실제 구현이 되고 있는 FmodIphoneSupprot.m파일을 살펴보자..
아래 코드들은 설명을 위해 적절히 수정을 하며 적는 코드라 동작을 완전히 보장은 못하다는 것을
명심해주시기 바란다. 구현 형태면에서 봐주셨으면 하는 바램이다..
헤더파일을 임포트하고 게임앱델리게이트 헤더를 임포트하고 있다.
게임앱델리게이트 사용을 위해 gameApp이라는 변수도 extern 선언을 해주고 있다.
#import "FmodIphoneSupport.h"
#import "GameAppDelegate.h"
extern GameAppDelegate *gameApp;
클래스 구현 시작 부분이다. FmodIphoneSupport의 구현임을 알린후
이 클래스 전반에 에러체크를 위해 사용할 ERRCHECK을 만들었다...이것은 Fmod에서 사용되는 API함수가 FMOD_RESULT
타입의 리턴값을 전해주는데 이값을 가지고 에러를 판단한다...이 함수는 Fmod api 다운 받아보면 포함된 예제 코드에 포함된 함수이다. 에러 발생시 에러내용을 디버깅 창에 출력하며 어플을 종료한다. 그 다음은 init함수를 재정의한다. 실제 Fmod초기화 부분은 initializeFMOD에서 해준다.
@implementation FmodIphoneSupport
void ERRCHECK(FMOD_RESULT result)
{
if (result != FMOD_OK)
{
fprintf(stderr, "FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
exit(-1);
}
}
- (id)init
{
if (self = [super init]) {
[self initializeFMOD];
}
return self;
}
초기화를 담당하는 함수다.. initFMOD 에서 실제 Fmod시스템에 대한 초기화를 해준다.
LoadGroups는 이전에 Fmod Designer에서 설정햇던 Group단위로 로딩을 해준다. 주의하여 보아야 할 부분은 bExternalAudioPlaying변수.. 이변수는 이미 아이팟으로 음악이 플레이중일때 처리를 위한 변수로 자세한 설명은 아래서 다시 하도록 하겠다. LoadGroups다음은 Fmod처리를 위한 update함수를 루프시키기 위해서 타이머 설정이 필요한데 타이머 설정을 해주고 있다. 그 다음은 bExternalAudioPlaying을 이용해서 이미 음악이 플레이중이면 음악을 계속해서 게임사운드와 같이 플레이할지 묻는 팝업창을 뛰우는 부분이다.
- (void)initializeFMOD
{
bool bExternalAudioPlaying = FALSE;
[self initFMOD:FMOD_IPHONE_SESSIONCATEGORY_AMBIENTSOUND externalAudioPlaying:&bExternalAudioPlaying];
[self LoadGroups];
timer = [NSTimer scheduledTimerWithTimeInterval:0.3 target:self selector:@selector(timerUpdate:) userInfo:nil repeats:YES];
if(bExternalAudioPlaying == TRUE)
{
[gameApp stopTimer];
UIAlertView *resultView = [[[UIAlertView alloc] initWithTitle:@" iPod music Settings" message:@"Your mp3 is playing. Do you want to continue playing your music?"
delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"cancel", nil] autorelease];
[resultView show];
}
}
Fmod사용을 위한 리소스들을 로딩하고 초기화하는 부분이다. EventSystem_Create로 이벤트시스템을 생성하고
FMOD_IPHONE_EXTRADRIVERDATA 구조체를 초기화하여 eventSystem->init의 인수로 넘기고 초기화를 마친다. 이때 init을 거치면서 bpExternalAudioPlaying의 주소가 가르키는 변수에는 이미 플레이중인 사운드가 있는지를 알수 있는 bool값이 셋팅되게 된다. eventSystem->load로 iPhoneGame.fev에 이벤트관련정보를 로딩한다.
- (void)initFMOD:(FMOD_IPHONE_SESSIONCATEGORY)sessionCategory externalAudioPlaying:(bool *)bpExternalAudioPlaying
{
FMOD_RESULT result = FMOD_OK;
char buffer[200] = {0};
result = FMOD::EventSystem_Create(&eventSystem);
ERRCHECK(result);
FMOD_IPHONE_EXTRADRIVERDATA driverdata;
memset(&driverdata, 0, sizeof(FMOD_IPHONE_EXTRADRIVERDATA));
driverdata.sessionCategory = sessionCategory;
if(bpExternalAudioPlaying)driverdata.otherAudioPlaying = bpExternalAudioPlaying;
result = eventSystem->init(FMOD_SIMULTANEOUS_PLAY_NUM, FMOD_INIT_NORMAL | FMOD_INIT_ENABLE_PROFILE, &driverdata, FMOD_EVENT_INIT_NORMAL);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/iPhoneGame.fev", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = eventSystem->load(buffer, NULL, NULL);
ERRCHECK(result);
}
LoadGroups에서 그룹객체를 얻어온다. freeFMOD에서는 eventSystem해제.
timerUpdate는 타이머를 통해서 루프를 돌게 해주는 함수이다. 이안에 eventSystem->update함수를 위치시키면 된다. dealloc은 객체소멸시 처리...
- (void)LoadGroups
{
FMOD_RESULT result = FMOD_OK;
if(eventSystem)
{
result = eventSystem->getGroup("iPhoneGame/BGM", false, &bgmGroup);
ERRCHECK(result);
result = eventSystem->getGroup("iPhoneGame/SE", false, &envGroup);
ERRCHECK(result);
}
}
- (void)freeFMOD
{
[timer invalidate];
if (eventSystem)
{
eventSystem->release();
eventSystem = NULL;
}
}
- (void)timerUpdate:(NSTimer *)timer
{
FMOD_RESULT result = FMOD_OK;
result = eventSystem->update();
ERRCHECK(result);
//메모리 쌓임을 방지하기 위해 일정 메모리 넘어가면 해제
if(memoryCurrent > FMOD_LIMIT_MEM_SIZE)
[self stopAllSE];
}
- (void)dealloc
{
[self freeFMOD];
[super dealloc];
}
- (FMOD::EventSystem *)getSystem
{
return eventSystem;
}
- (FMOD::EventGroup *)getSEGroup
{
return seGroup;
}
- (FMOD::EventGroup *)getBGMGroup
{
return bgmGroup;
}
- (FMOD::Event *)getBGMEvent
{
return bgmEvent;
}
그룹별 사운드볼륨 설정하고 설정값 얻어오는 함수들..
- (float)getBGMVolume
{
return bgmVolume;
}
- (void)setBGMVolume:(float) vol
{
bgmVolume = vol;
if(bgmEvent!=nil)bgmEvent->setVolume(bgmVolume);
}
- (float)getSEVolume
{
return seVolume;
}
- (void)setSEVolume:(float) vol
{
FMOD_RESULT result = FMOD_OK;
seVolume = vol;
}
- (void)playBGM:(int)bgmEventNum
{
if(bgmEventNum<0)
{
return;
}
FMOD_RESULT result = FMOD_OK;
result = bgmGroup->getEventByIndex(bgmEventNum, FMOD_EVENT_DEFAULT, &bgmEvent );
ERRCHECK(result);
if(bgmEvent)
{
result = bgmEvent->setVolume(bgmVolume);
ERRCHECK(result);
result = bgmEvent->start();
ERRCHECK(result);
}
}
- (void)stopBGM
{
FMOD_RESULT result = FMOD_OK;
//이 라인을 넣으면 사운드 데이타 해제
result = bgmGroup->freeEventData();
ERRCHECK(result);
}
- (void)playSE:(int)seEventNum
{
FMOD_RESULT result = FMOD_OK;
FMOD::Event *event;
if(seEventNum<0)
{
return;
}
result = seGroup->getEventByIndex(seEventNum, FMOD_EVENT_DEFAULT, &event );
ERRCHECK(result);
result = FMOD::Memory_GetStats(&memoryCurrent, &memoryMaximum);
ERRCHECK(result);
if(event)
{
result = event->setVolume(seVolume);
ERRCHECK(result);
result = event->start();
ERRCHECK(result);
}
}
- (void)stopAllSE
{
FMOD_RESULT result = FMOD_OK;
result = seGroup->freeEventData();
ERRCHECK(result);
}