[修正]IOS中使用SoundTouch库实现变声

 之前写过一片文章“ IOS中使用SoundTouch库实现变声”。
最后有很多朋友在博客上说发出来的代码在模拟器上运行可以,不能在真机上运行,前段时间一直也很忙,没时间翻代码出来查看,望谅解。
今天抽空检查了一下问题的根源,并且在IPhone 4(ios5.0.1)上测试通过,下面更新一些代码。

同样是Apple官方的SpeakHere,要下载代码的,请查看上一篇文章。

void AQRecorder::StartRecord(CFStringRef inRecordFile) 
{ 
    mSoundTouch.setSampleRate(44100);//mRecordFormat.mSampleRate 
    mSoundTouch.setChannels(1);//mRecordFormat.mChannelsPerFrame 
    mSoundTouch.setTempoChange(1.0); 
    mSoundTouch.setPitchSemiTones(9); 
    mSoundTouch.setRateChange(-0.7); 
 
    mSoundTouch.setSetting(SETTING_SEQUENCE_MS, 40); 
    mSoundTouch.setSetting(SETTING_SEEKWINDOW_MS, 16); 
    mSoundTouch.setSetting(SETTING_OVERLAP_MS, 8); 
     
    //Only use one of the following two options 
    //  mSoundTouch.setSetting(SETTING_USE_QUICKSEEK, 0); 
    //  mSoundTouch.setSetting(SETTING_USE_AA_FILTER, !(0)); 
    //  mSoundTouch.setSetting(SETTING_AA_FILTER_LENGTH, 32); 

红色的两行很重要,需要指明采样率和声道。如果需要使用后面注释两个变量,需要在SetupAudioFormat方法执行之后才可以,否则无效,原因大家都懂的。
将麦克风捕捉的声音回调函数按照一下代码更新。

// ____________________________________________________________________________________ 
// AudioQueue callback function, called when an input buffers has been filled. 
void AQRecorder::MyInputBufferHandler(  void *                              inUserData, 
                                        AudioQueueRef                       inAQ, 
                                        AudioQueueBufferRef                 inBuffer, 
                                        const AudioTimeStamp *              inStartTime, 
                                        UInt32                              inNumPackets, 
                                        const AudioStreamPacketDescription* inPacketDesc) 
{ 
     
    AQRecorder *aqr = (AQRecorder *)inUserData; 
    try { 
        if (inNumPackets > 0) { 
            UInt32 audioDataByteSize = inBuffer->mAudioDataByteSize; 
            CAStreamBasicDescription queueFormat = aqr->DataFormat(); 
            SoundTouch *soundTouch = aqr->GetSoundTouch(); 
 
            uint nSamples = audioDataByteSize/queueFormat.mBytesPerPacket; 
            soundTouch->putSamples((const SAMPLETYPE *)inBuffer->mAudioData,nSamples); 
             
            SAMPLETYPE *samples = (SAMPLETYPE *)malloc(audioDataByteSize); 
            UInt32 numSamples; 
            do { 
                memset(samples, 0, audioDataByteSize); 
                numSamples = soundTouch->receiveSamples((SAMPLETYPE *)samples, nSamples); 
                // write packets to file 
                XThrowIfError(AudioFileWritePackets(aqr->mRecordFile, 
                                                    FALSE, 
                                                    numSamples*queueFormat.mBytesPerPacket, 
                                                    NULL, 
                                                    aqr->mRecordPacket, 
                                                    &numSamples, 
                                                    samples), 
                              "AudioFileWritePackets failed"); 
                aqr->mRecordPacket += numSamples; 
            } while (numSamples!=0); 
            free(samples); 
        } 
         
        // if we're not stopping, re-enqueue the buffe so that it gets filled again 
        if (aqr->IsRunning()) 
            XThrowIfError(AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL), "AudioQueueEnqueueBuffer failed"); 
    } catch (CAXException e) { 
        char buf[256]; 
        fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf)); 
    } 
} 
原因大家自己应该能看明白。
之前是在xcode 3.x上写的代码,刚开始有朋友反馈时,我以为是版本问题产生的,结果不是。
本次更新的代码是我在xcode4.2和iphone4上测试无误的,如果还有问题的,可以仔细看看前后两篇文章。不要吧参数设置错误了。
ps:QQ经常不在线,有问题上微博:http://weibo.com/yarin

你可能感兴趣的:(移动开发,程序语言)