2009-12-09 204 views
4

我正在學習關於使用OpenAL播放聲音的教程。現在一切正常,除了我不能讓聲音循環。我相信我已經使用AL_LOOPING作爲源代碼。現在它只能播放一次,當它完成播放時,該應用程序將阻止(不響應我點擊播放按鈕)。關於代碼有什麼問題的任何想法?如何在iPhone上使用OpenAL播放循環聲音

// start up openAL 
// init device and context 
-(void)initOpenAL 
{ 
    // Initialization 
    mDevice = alcOpenDevice(NULL); // select the "preferred device" 
    if (mDevice) { 
     // use the device to make a context 
     mContext = alcCreateContext(mDevice, NULL); 
     // set my context to the currently active one 
     alcMakeContextCurrent(mContext); 
    } 
} 


// open the audio file 
// returns a big audio ID struct 
-(AudioFileID)openAudioFile:(NSString*)filePath 
{ 
    AudioFileID outAFID; 
    // use the NSURl instead of a cfurlref cuz it is easier 
    NSURL * afUrl = [NSURL fileURLWithPath:filePath]; 

    // do some platform specific stuff.. 
#if TARGET_OS_IPHONE 
    OSStatus result = AudioFileOpenURL((CFURLRef)afUrl, kAudioFileReadPermission, 0, &outAFID); 
#else 
    OSStatus result = AudioFileOpenURL((CFURLRef)afUrl, fsRdPerm, 0, &outAFID); 
#endif 
    if (result != 0) NSLog(@"cannot openf file: %@",filePath); 
    return outAFID; 
} 


// find the audio portion of the file 
// return the size in bytes 
-(UInt32)audioFileSize:(AudioFileID)fileDescriptor 
{ 
    UInt64 outDataSize = 0; 
    UInt32 thePropSize = sizeof(UInt64); 
    OSStatus result = AudioFileGetProperty(fileDescriptor, kAudioFilePropertyAudioDataByteCount, &thePropSize, &outDataSize); 
    if(result != 0) NSLog(@"cannot find file size"); 
    return (UInt32)outDataSize; 
} 

- (void)stopSound 
{ 
    alSourceStop(sourceID); 
} 

-(void)cleanUpOpenAL:(id)sender 
{ 
    // delete the sources 
    alDeleteSources(1, &sourceID); 

    // delete the buffers 
    alDeleteBuffers(1, &bufferID); 

    // destroy the context 
    alcDestroyContext(mContext); 

    // close the device 
    alcCloseDevice(mDevice); 
} 

-(IBAction)play:(id)sender 
{ 
    alSourcePlay(sourceID); 
} 


#pragma mark - 
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. 
- (void)viewDidLoad { 
    [super viewDidLoad]; 

    [self initOpenAL]; 
    // get the full path of the file 
    NSString* fileName = [[NSBundle mainBundle] pathForResource:@"sound" ofType:@"caf"]; 
    // first, open the file 
    AudioFileID fileID = [self openAudioFile:fileName]; 

    // find out how big the actual audio data is 
    UInt32 fileSize = [self audioFileSize:fileID]; 

    // this is where the audio data will live for the moment 
    unsigned char * outData = malloc(fileSize); 

    // this where we actually get the bytes from the file and put them 
    // into the data buffer 
    OSStatus result = noErr; 
    result = AudioFileReadBytes(fileID, false, 0, &fileSize, outData); 
    AudioFileClose(fileID); //close the file 

    if (result != 0) NSLog(@"cannot load effect: %@", fileName); 

    //NSUInteger bufferID;    // buffer is defined in head file 
    // grab a buffer ID from openAL 
    alGenBuffers(1, &bufferID); 

    // jam the audio data into the new buffer 
    alBufferData(bufferID, AL_FORMAT_STEREO16, outData, fileSize, 8000); 


    //NSUInteger sourceID;    // source is defined in head file 

    // grab a source ID from openAL 
    alGenSources(1, &sourceID); 

    // attach the buffer to the source 
    alSourcei(sourceID, AL_BUFFER, bufferID); 
    // set some basic source prefs 
    alSourcef(sourceID, AL_PITCH, 1.0f); 
    alSourcef(sourceID, AL_GAIN, 1.0f); 
    alSourcei(sourceID, AL_LOOPING, AL_TRUE); 

    // clean up the buffer 
    if (outData) 
    { 
     free(outData); 
     outData = NULL; 
    } 
} 
+0

我在我以前的項目之一使用了類似的代碼,它工作正常。在播放聲音之後,你能否介紹一些關於你的應用行爲的細節?它完全阻止了用戶界面,還是在點擊按鈕之後沒有發生任何事情? – Morion 2009-12-09 13:44:53

+0

當我點擊播放按鈕時,什麼都沒有發生(按鈕不是藍色的)。幾秒鐘後(超過10秒鐘),顯示藍色並全部被阻擋。我必須按主頁按鈕關閉應用程序。 – 2009-12-09 13:48:49

+0

是因爲我在viewDidLoad中釋放了「outData」?也許我應該將outData定義爲私有變量,並且不要在這裏釋放它。 – 2009-12-09 13:53:10

回答

0

你應該能夠在你的alBufferData()調用之後立即釋放outData。它將它排除爲罪魁禍首,您可以嘗試靜態擴展並自己管理內存。它是這樣的:

alBufferDataStaticProcPtr alBufferDataStaticProc = (alBufferDataStaticProcPtr)alcGetProcAddress(0, (const ALCchar *)"alBufferDataStatic"); 
alBufferDataStaticProc(bufferID, bitChanFormat, audioData, audioDataSize, dataFormat.mSampleRate); 
+0

謝謝。我發現我正在給聲音分配一個錯誤的格式。 alBufferDataStaticProc方法可以讓我免除這個錯誤。這真是一個好方法。 – 2009-12-11 01:21:14