Загрузить WAV-файл для OpenAL в Какао - PullRequest
3 голосов
/ 30 апреля 2009

Мне нужно загрузить звуковые файлы в приложение OpenAL на основе какао.

Прогресс:

  • Утилита OpenAL alutLoadWAVFile устарела; заголовок alut больше не включается в Mac OS X SDK. Согласно Техническим примечаниям, фактический код все еще там для двоичной совместимости. Однако, если я попытаюсь добавить объявление для функции, код скомпилируется, но компоновщик прервется, сообщив, что символ alutLoadWAVFile не найден. (Я ссылаюсь на OpenAL.framework).

  • Тем не менее, пример кода Apple OpenAL по-прежнему использует этот символ. Когда я очищаю пример кода проекта, он прекрасно компилируется и связывается. Все же нет объявления функции, которая будет найдена. (Дополнительный вопрос: как его построить и связать?)

Итак, я нашел некоторый код Джорджа Уорнера в Apple, содержащий функции замены для alutCreateBufferFromFile и alutLoadMemoryFromFile. Несмотря на то, что он способен создавать буфер OpenAL непосредственно из большинства аудио файлов любого типа, этот код поддерживает только 8-битные монофонические звуковые файлы. 16-битные стереофонические или монофонические файлы 44 кГц приводят к неприятным шипящим звукам и срезам. (С файлами все в порядке; Quicktime проигрывает их просто отлично.)

Таким образом, мой вопрос: может кто-нибудь указать мне какой-нибудь .wav код загрузки / справки для Какао / Углерода, подходящий для использования с буфером OpenAL? Thankyou.

Ответы [ 3 ]

5 голосов
/ 01 января 2011

Я уверен, что вы уже решили это, но для людей, которые находят это через 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;
}
1 голос
/ 08 июля 2009

Используйте функцию AudioFileReadBytes из Audio Services . Примеры можно найти в Finch Sound Engine , см. Категорию Sound + IO .

0 голосов
/ 30 апреля 2009

Это может быть очевидным предложением, но, поскольку вы не упомянули об этом: пробовали ли вы библиотеку на http://www.openal.org/, как предложено в Техническое замечание Apple ?

Что касается того, как пример кода связывает и собирает, то это не поиск прототипа (если вы включите -Wall, вы получите неявное предупреждение объявления функции), но OpenAL.framework - по крайней мере, в SDK они использование в примере проекта - фактически экспортирует _alutLoadWAVFile, который вы можете проверить с помощью nm. Какую именно ошибку вы получите, и какой SDK вы используете?

...