Load .wav file for OpenAL in Cocoa

拜拜、爱过 提交于 2019-12-06 00:29:12

I'm sure you've solved this already, but for people who find this via Google, here's some barely tested WAV loading code. It works but you'd better double check for memory leaks and whatnot before using for something real.

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;
}
zoul

Use the AudioFileReadBytes function from Audio Services. Examples can be found in the Finch sound engine, see the Sound+IO category.

This may be an obvious suggestion, but since you didn't mention it: have you tried the library at http://www.openal.org/ as suggested in Apple's technote?

As for how the sample code links and builds, it's not finding a prototype (if you turn on -Wall, you'll get an implicit function declaration warning), but OpenAL.framework--at least in the SDK they are using in the sample project--does in fact export _alutLoadWAVFile, which you can check with nm. What's the exact link error you get, and what SDK are you using?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!