之前写过一片文章“IOS中使用SoundTouch库实现变声”。

最后有很多朋友在博客上说发出来的代码在模拟器上运行可以,不能在真机上运行,前段时间一直也很忙,没时间翻代码出来查看,望谅解。

今天抽空检查了一下问题的根源,并且在IPhone 4(ios5.0.1)上测试通过,下面更新一些代码。

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

  1. void AQRecorder::StartRecord(CFStringRef inRecordFile) 
  2. mSoundTouch.setSampleRate(44100);//mRecordFormat.mSampleRate 
  3.     mSoundTouch.setChannels(1);//mRecordFormat.mChannelsPerFrame 
  4.     mSoundTouch.setTempoChange(1.0); 
  5.     mSoundTouch.setPitchSemiTones(9); 
  6.     mSoundTouch.setRateChange(-0.7); 
  7.  
  8.     mSoundTouch.setSetting(SETTING_SEQUENCE_MS, 40); 
  9.     mSoundTouch.setSetting(SETTING_SEEKWINDOW_MS, 16); 
  10.     mSoundTouch.setSetting(SETTING_OVERLAP_MS, 8); 
  11.      
  12.     //Only use one of the following two options 
  13.     //  mSoundTouch.setSetting(SETTING_USE_QUICKSEEK, 0); 
  14.     //  mSoundTouch.setSetting(SETTING_USE_AA_FILTER, !(0)); 
  15.     //  mSoundTouch.setSetting(SETTING_AA_FILTER_LENGTH, 32); 

红色的两行很重要,需要指明采样率和声道。如果需要使用后面注释两个变量,需要在SetupAudioFormat方法执行之后才可以,否则无效,原因大家都懂的。

将麦克风捕捉的声音回调函数按照一下代码更新。

  1. // ____________________________________________________________________________________ 
  2. // AudioQueue callback function, called when an input buffers has been filled. 
  3. void AQRecorder::MyInputBufferHandler(  void *                              inUserData, 
  4.                                         AudioQueueRef                       inAQ, 
  5.                                         AudioQueueBufferRef                 inBuffer, 
  6.                                         const AudioTimeStamp *              inStartTime, 
  7.                                         UInt32                              inNumPackets, 
  8.                                         const AudioStreamPacketDescription* inPacketDesc) 
  9.      
  10.     AQRecorder *aqr = (AQRecorder *)inUserData; 
  11.     try { 
  12.         if (inNumPackets > 0) { 
  13.             UInt32 audioDataByteSize = inBuffer->mAudioDataByteSize; 
  14.             CAStreamBasicDescription queueFormat = aqr->DataFormat(); 
  15.             SoundTouch *soundTouch = aqr->GetSoundTouch(); 
  16.  
  17.             uint nSamples = audioDataByteSize/queueFormat.mBytesPerPacket; 
  18.             soundTouch->putSamples((const SAMPLETYPE *)inBuffer->mAudioData,nSamples); 
  19.              
  20.             SAMPLETYPE *samples = (SAMPLETYPE *)malloc(audioDataByteSize); 
  21.             UInt32 numSamples; 
  22.             do { 
  23.                 memset(samples, 0, audioDataByteSize); 
  24.                 numSamples = soundTouch->receiveSamples((SAMPLETYPE *)samples, nSamples); 
  25.                 // write packets to file 
  26.                 XThrowIfError(AudioFileWritePackets(aqr->mRecordFile, 
  27.                                                     FALSE, 
  28.                                                     numSamples*queueFormat.mBytesPerPacket, 
  29.                                                     NULL, 
  30.                                                     aqr->mRecordPacket, 
  31.                                                     &numSamples, 
  32.                                                     samples), 
  33.                               "AudioFileWritePackets failed"); 
  34.                 aqr->mRecordPacket += numSamples; 
  35.             } while (numSamples!=0); 
  36.             free(samples); 
  37.         } 
  38.          
  39.         // if we're not stopping, re-enqueue the buffe so that it gets filled again 
  40.         if (aqr->IsRunning()) 
  41.             XThrowIfError(AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL), "AudioQueueEnqueueBuffer failed"); 
  42.     } catch (CAXException e) { 
  43.         char buf[256]; 
  44.         fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf)); 
  45.     } 

原因大家自己应该能看明白。

之前是在xcode 3.x上写的代码,刚开始有朋友反馈时,我以为是版本问题产生的,结果不是。

本次更新的代码是我在xcode4.2和iphone4上测试无误的,如果还有问题的,可以仔细看看前后两篇文章。不要吧参数设置错误了。

ps:QQ经常不在线,有问题上微博:http://weibo.com/yarin