2009-04-30 104 views
3

我需要將聲音文件加載到基於Cocoa的OpenAL應用程序中。在Cocoa中加載OpenAL的.wav文件

進展:

  • 的OpenAL的效用函數alutLoadWAVFile已棄用; alut頭文件不再包含在Mac OS X SDK中。根據技術說明,實際的代碼仍然存在二進制兼容性。但是,如果我試圖爲該函數添加一個聲明,代碼將會編譯,但鏈接器將中止,抱怨找不到alutLoadWAVFile的符號。 (我正在鏈接到OpenAL.framework)。

  • 但是,Apple OpenAL示例代碼仍然使用此符號。當我清理示例代碼項目時,它編譯和鏈接就好了。然而,沒有可以找到的功能的聲明。 (方的問題:如何才能建立和鏈接,然後)

所以,我發現喬治·華納一些代碼在蘋果,含更換功能alutCreateBufferFromFile和alutLoadMemoryFromFile。雖然能夠直接從大多數任何類型的音頻文件創建OpenAL緩衝區,但代碼似乎只支持8位單聲道文件。 16位立體聲或單聲道44khz文件導致令人討厭的嘶嘶聲和剪輯。 (該文件是好的;的QuickTime播放這些就好了。)

因此,我的問題:可有人請點我的可可/碳一些.WAV加載代碼/幫助,適合與OpenAL的緩衝用?謝謝。

+0

更多的數據點:(1)「的grep -RF alutLoadWAVFile /系統/庫/框架/開發商/軟件開發工具包的/ usr /包括--include = '* H'。」不發出輸出並返回退出狀態1 (沒有結果)。 (2)項目沒有打開丟失原型的警告;我打開了它,並得到了四個警告,其中沒有一個是alutLoadWAVFile。 (3)修改build文件夾只會打開.o文件,最終的可執行文件和Xcode的索引文件。 先生,你發現了一個謎。 – 2009-04-30 07:29:17

回答

0

這可能是一個明顯的建議,但由於您沒有提及它:您是否按Apple's technote中的建議在http://www.openal.org/處嘗試過該庫?對於示例代碼如何鏈接和構建,它沒有找到原型(如果你打開-Wall,你會得到一個隱含的函數聲明警告),但OpenAL.framework - 至少在SDK中它們正在使用示例項目 - 事實上會導出_alutLoadWAVFile,您可以使用nm進行檢查。什麼是你得到的確切的鏈接錯誤,你使用的是什麼SDK?

+0

感謝您的幫助。 我沒有使用庫本身,因爲Apple的示例代碼沒有使用它。相反,示例代碼使用10.4 SDK,並鏈接到System/Library/Frameworks/OpenAL.framework。我也這樣做。 只有差異我可以看到項目之間是我的Xcode兼容性是3.1,他們是2.4。 所以,我註釋掉了我的行,而是使用了舊的OpenAL頭文件。我將alutLoadWAVFile恢復到我的代碼中,瞧!我現在有wav支持。 這是一個解決方法,但我會接受它! 乾杯。 – SirRatty 2009-04-30 23:27:54

5

我相信你已經解決了這個問題,但對於那些通過Google發現這個問題的人來說,這裏是一些幾乎沒有經過測試的WAV加載代碼。它的工作原理,但你最好仔細檢查內存泄漏,以及在使用真正的東西之前。

static bool LoadWAVFile(const char* filename, ALenum* format, ALvoid** data, ALsizei* size, ALsizei* freq, Float64* estimatedDurationOut) 
{ 
    CFStringRef filenameStr = CFStringCreateWithCString(NULL, filename, kCFStringEncodingUTF8); 
    CFURLRef url = CFURLCreateWithFileSystemPath(NULL, filenameStr, kCFURLPOSIXPathStyle, false); 
    CFRelease(filenameStr); 

    AudioFileID audioFile; 
    OSStatus error = AudioFileOpenURL(url, kAudioFileReadPermission, kAudioFileWAVEType, &audioFile); 
    CFRelease(url); 

    if (error != noErr) 
    { 
     fprintf(stderr, "Error opening audio file. %d\n", error); 
     return false; 
    } 

    AudioStreamBasicDescription basicDescription; 
    UInt32 propertySize = sizeof(basicDescription); 
    error = AudioFileGetProperty(audioFile, kAudioFilePropertyDataFormat, &propertySize, &basicDescription); 

    if (error != noErr) 
    { 
     fprintf(stderr, "Error reading audio file basic description. %d\n", error); 
     AudioFileClose(audioFile); 
     return false; 
    } 

    if (basicDescription.mFormatID != kAudioFormatLinearPCM) 
    { 
     // Need PCM for Open AL. WAVs are (I believe) by definition PCM, so this check isn't necessary. It's just here 
     // in case I ever use this with another audio format. 
     fprintf(stderr, "Audio file is not linear-PCM. %d\n", basicDescription.mFormatID); 
     AudioFileClose(audioFile); 
     return false; 
    } 

    UInt64 audioDataByteCount = 0; 
    propertySize = sizeof(audioDataByteCount); 
    error = AudioFileGetProperty(audioFile, kAudioFilePropertyAudioDataByteCount, &propertySize, &audioDataByteCount); 
    if (error != noErr) 
    { 
     fprintf(stderr, "Error reading audio file byte count. %d\n", error); 
     AudioFileClose(audioFile); 
     return false; 
    } 

    Float64 estimatedDuration = 0; 
    propertySize = sizeof(estimatedDuration); 
    error = AudioFileGetProperty(audioFile, kAudioFilePropertyEstimatedDuration, &propertySize, &estimatedDuration); 
    if (error != noErr) 
    { 
     fprintf(stderr, "Error reading estimated duration of audio file. %d\n", error); 
     AudioFileClose(audioFile); 
     return false; 
    } 

    ALenum alFormat = 0; 

    if (basicDescription.mChannelsPerFrame == 1) 
    { 
     if (basicDescription.mBitsPerChannel == 8) 
      alFormat = AL_FORMAT_MONO8; 
     else if (basicDescription.mBitsPerChannel == 16) 
      alFormat = AL_FORMAT_MONO16; 
     else 
     { 
      fprintf(stderr, "Expected 8 or 16 bits for the mono channel but got %d\n", basicDescription.mBitsPerChannel); 
      AudioFileClose(audioFile); 
      return false; 
     } 

    } 
    else if (basicDescription.mChannelsPerFrame == 2) 
    { 
     if (basicDescription.mBitsPerChannel == 8) 
      alFormat = AL_FORMAT_STEREO8; 
     else if (basicDescription.mBitsPerChannel == 16) 
      alFormat = AL_FORMAT_STEREO16; 
     else 
     { 
      fprintf(stderr, "Expected 8 or 16 bits per channel but got %d\n", basicDescription.mBitsPerChannel); 
      AudioFileClose(audioFile); 
      return false; 
     } 
    } 
    else 
    { 
     fprintf(stderr, "Expected 1 or 2 channels in audio file but got %d\n", basicDescription.mChannelsPerFrame); 
     AudioFileClose(audioFile); 
     return false; 
    } 

    UInt32 numBytesToRead = audioDataByteCount; 
    void* buffer = malloc(numBytesToRead); 

    if (buffer == NULL) 
    { 
     fprintf(stderr, "Error allocating buffer for audio data of size %u\n", numBytesToRead); 
     return false; 
    } 

    error = AudioFileReadBytes(audioFile, false, 0, &numBytesToRead, buffer); 
    AudioFileClose(audioFile); 

    if (error != noErr) 
    { 
     fprintf(stderr, "Error reading audio bytes. %d\n", error); 
     free(buffer); 
     return false; 
    } 

    if (numBytesToRead != audioDataByteCount) 
    { 
     fprintf(stderr, "Tried to read %lld bytes from the audio file but only got %d bytes\n", audioDataByteCount, numBytesToRead); 
     free(buffer); 
     return false; 
    } 

    *freq = basicDescription.mSampleRate; 
    *size = audioDataByteCount; 
    *format = alFormat; 
    *data = buffer; 
    *estimatedDurationOut = estimatedDuration; 

    return true; 
}