IOS中使用SoundTouch库实现变声

IOS中使用SoundTouch库实现变声
  
  
  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.     } 


      这个简单的歌声合成程序,我称它为FA♂乐器好了,因为音源是FA(滑稽

 http://files.cnblogs.com/files/CodeMIRACLE/fa.zip

  开发环境是win10 CodeBlock+Mingw32,直接把源代码添加到工程里。source\SouthStretch文件夹里面有个WavFile.cpp提供了一系列对WAV文件操作的函数,很方便,直接加进工程里使用。

  程序的设计参考了官方SouthStretch的实现。编译的时候这个库的SSE和MMX优化会报编译错误,我就把那些优化的代码都注释掉了。

  SoundTouch的使用十分简单

复制代码
  1  #include <stdexcept>
  2  #include <stdio.h>
  3  #include <string.h>
  4  #include <time.h>
  5  #include<cstdlib>
  6  #include "WavFile.h"
  7  #include "SoundTouch.h"
  8  #include "BPMDetect.h"
  9  #include<iostream>
 10  #include<algorithm>
 11  #include "STTypes.h"
 12  #include <vector>
 13  #include <sstream>
 14  #include <map>
 15  #include <windows.h>
 16  using namespace soundtouch;
 17  using namespace std;
 18  #define BUFF_SIZE           6720
 19  map<string,int> tonemap;
 20  template<class T>
 21  string tostring(T& x)
 22  {
 23      stringstream ss;
 24      ss<<x;
 25      return ss.str();
 26  }
 27  void InitToneMap()
 28  {
 29      string keys[]={"C","C#","D","D#","E","F","F#","G","G#","A","A#","B"};
 30      for(int i=0;i<=10;i++)
 31      {
 32          for(int j=0;j<12;j++)
 33             tonemap[keys[j]+tostring(i)]=i*12+j-82;
 34      }
 35  }
 36  void WriteVoidSample(WavOutFile* wavout,SoundTouch* pSoundTouch,int num,int channels,double tempo)
 37  {
 38          short *sampleBuffer=new short[num];
 39          memset(sampleBuffer,0,sizeof(short)*num);
 40          pSoundTouch->setTempo(tempo);
 41          pSoundTouch->putSamples(sampleBuffer,num/channels);
 42          pSoundTouch->receiveSamples(sampleBuffer,num);
 43          wavout->write(sampleBuffer,num);
 44          delete []sampleBuffer;
 45  }
 46  void WriteProcessSample(WavInFile* wavin,WavOutFile* wavout,SoundTouch* pSoundTouch,int tone,double tempo)
 47  {
 48          int nSamples;
 49          int nChannels;
 50          int buffSizeSamples;
 51          short *sampleBuffer=new short[BUFF_SIZE];
 52          pSoundTouch->setPitchSemiTones(tone);
 53          pSoundTouch->setTempo(tempo);
 54          while(!wavin->eof())
 55          {
 56              int num;
 57              num = wavin->read(sampleBuffer, BUFF_SIZE);
 58              nSamples = num / (int)wavin->getNumChannels();
 59              nChannels = (int)wavin->getNumChannels();
 60              buffSizeSamples = BUFF_SIZE / nChannels;
 61              pSoundTouch->putSamples(sampleBuffer, nSamples);
 62              do
 63              {
 64                  nSamples = pSoundTouch->receiveSamples(sampleBuffer,buffSizeSamples);
 65                  wavout->write(sampleBuffer, nSamples * nChannels);
 66              } while (nSamples != 0);
 67          }
 68          wavin->rewind();
 69          pSoundTouch->clear();
 70          delete []sampleBuffer;
 71  }
 72  int main()
 73  {
 74      FILE* fp=fopen("tone.txt","r");
 75      if(fp)
 76      {
 77          WavInFile *wavin;
 78          WavOutFile *wavout;
 79          SoundTouch *pSoundTouch;
 80          wavin = new WavInFile("fa.wav");
 81          pSoundTouch = new SoundTouch;
 82          pSoundTouch->setSampleRate(wavin->getSampleRate());
 83          pSoundTouch->setChannels(wavin->getNumChannels());
 84          wavout = new WavOutFile("out.wav",wavin->getSampleRate(),wavin->getNumBits(),wavin->getNumChannels());
 85          InitToneMap();
 86          char tone[4];
 87          double meter;
 88          while(~fscanf(fp,"%s%lf",tone,&meter))
 89          {
 90                  if(tone[0]!='0')
 91                      WriteProcessSample(wavin,wavout,pSoundTouch,tonemap[tone],1/meter);
 92                  else
 93                      WriteVoidSample(wavout,pSoundTouch,wavin->getDataSizeInBytes(),wavin->getNumChannels(),1/meter);
 94          }
 95          delete wavin;
 96          delete wavout;
 97          delete pSoundTouch;
 98          PlaySound("out.wav",NULL,SND_SYNC);
 99      }
100  }
复制代码

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值