如何在 iPhone 上使用 OpenAL 播放循环声音

发布于 2024-08-14 06:17:43 字数 3630 浏览 7 评论 0原文

我正在学习有关使用 OpenAL 播放声音的教程。现在一切正常,除了我无法让声音循环播放。我相信我已使用 AL_LOOPING 作为源。现在它只能播放一次,当它完成播放时,应用程序将被阻止(不响应我点击播放按钮)。关于代码有什么问题有什么想法吗?

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

I'm following a tutorial about playing sound with OpenAL. Now everything works fine except I can't make the sound looping. I believe that I've used AL_LOOPING for the source. Now it can only play once and when it finishes playing, the app will block(doesn't response to my tap on the play button). Any ideas about what's wrong with the code?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

岁月如刀 2024-08-21 06:17:43

您应该能够在 alBufferData() 调用之后立即释放 outData。它排除了它作为罪魁祸首,您可以尝试静态扩展并自己管理内存。它是这样的:

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

You should be able to release outData right after your alBufferData() call. It exclude it as the culprit, you can try the static extension and manage the memory yourself. It's something like:

alBufferDataStaticProcPtr alBufferDataStaticProc = (alBufferDataStaticProcPtr)alcGetProcAddress(0, (const ALCchar *)"alBufferDataStatic");
alBufferDataStaticProc(bufferID, bitChanFormat, audioData, audioDataSize, dataFormat.mSampleRate);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文