使用SoundTouch库写一个歌声合成程序

  以前在学习WAV文件格式的时候发现了一个叫SoundTouch的开源小众库,提供WAV音频的变调和变速功能。这几天忽然想起来这个库,无聊的我就写了一个简单的歌声合成程序。功能和质量都比不上专业的音频合成软件,而且我也不想再做下去了......

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

 https://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  }

 

posted @ 2016-05-21 15:16  CodeMIRACLE  阅读(2546)  评论(1编辑  收藏  举报