- 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);
- // ____________________________________________________________________________________
- // 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));
- }
- }
这个简单的歌声合成程序,我称它为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 }