1 /* 2 * Copyright (C) 2002 - David W. Durham 3 * 4 * This file is part of ReZound, an audio editing application. 5 * 6 * ReZound is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published 8 * by the Free Software Foundation; either version 2 of the License, 9 * or (at your option) any later version. 10 * 11 * ReZound is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 */ 20 21 #ifndef __DSP_PitchChanger_H__ 22 #define __DSP_PitchChanger_H__ 23 24 #include "../../config/common.h" 25 26 #ifdef HAVE_LIBSOUNDTOUCH 27 28 /* NOTE: 29 * - The template is called TPitchChanger which used the libSoundTouch library. And 30 * this is not to be confused with the preexisting TSoundStretcher template which 31 * changes the rate (speed and pitch). 32 */ 33 34 35 #include <TAutoBuffer.h> 36 37 #include "../CSound_defs.h" 38 39 #include <soundtouch/SoundTouch.h> 40 using namespace soundtouch; 41 42 template<class src_type> class TPitchChanger 43 { 44 public: 45 /* 46 * src is the data to read 47 * srcOffset is the first sample that this class will look at 48 * length is the length of samples beyond the srcOffset that should be read and is the number of output samples 49 * deltaSemitones is the how much + or - to change the pitch 50 * frameSize can be passed if the src is actually interlaced data of more than 1 channel of audio 51 * frameOffset should be passed when frameSize is given other than one to say which channel in the interlaced data should be processed 52 */ 53 TPitchChanger(const src_type &_src,const sample_pos_t _srcOffset,const sample_pos_t _length,const float _deltaSemitones,unsigned srcSampleRate,unsigned _frameSize=1,unsigned _frameOffset=0) : src(_src)54 src(_src), 55 srcOffset(_srcOffset), 56 length(_length), 57 deltaSemitones(_deltaSemitones), 58 frameSize(_frameSize), 59 frameOffset(_frameOffset), 60 61 pos(0), 62 srcEnd(srcOffset+length), 63 flushed(false), 64 65 outputBuffer(1024), 66 outputBufferOffset(0), 67 outputBufferSize(0), 68 69 inputBuffer(outputBuffer.getSize()) 70 { 71 if(frameSize==0) 72 throw(runtime_error(string(__func__)+" -- frameSize is 0")); 73 if(frameOffset>=frameSize) 74 throw(runtime_error(string(__func__)+" -- frameOffset is >= frameSize: "+istring(frameOffset)+">="+istring(frameSize))); 75 76 changer.setChannels(1); // ??? need to have a way of allowing more than one channel so that phase across channels is preserved 77 changer.setSampleRate(srcSampleRate); 78 changer.setPitchSemiTones(deltaSemitones); 79 } 80 ~TPitchChanger()81 virtual ~TPitchChanger() 82 { 83 } 84 getSample()85 const sample_t getSample() 86 { 87 if(outputBufferOffset<outputBufferSize) 88 // data available to read 89 return convert_sample<soundtouch::SAMPLETYPE,sample_t>(outputBuffer[outputBufferOffset++]); 90 else if(changer.numSamples() > 0) 91 { // read more data from changer 92 outputBufferSize=changer.receiveSamples(outputBuffer,outputBuffer.getSize()); 93 outputBufferOffset=0; 94 } 95 else /*if(changer.numSamples() <= 0)*/ 96 { // write more data to changer 97 if(pos<srcEnd) 98 { 99 const size_t chunkSize=min((sample_pos_t)inputBuffer.getSize(),srcEnd-pos); 100 size_t t; 101 // unfortunately I'm having to make a copy into inputBuffer before giving it to changer 102 for(t=0;t<chunkSize;t++) 103 inputBuffer[t]=convert_sample<sample_t,soundtouch::SAMPLETYPE>(src[((pos++)*frameSize)+frameOffset]); 104 changer.putSamples(inputBuffer,t); 105 } 106 else 107 { // no input to give to changer 108 if(!flushed) 109 { 110 changer.flush(); 111 flushed=true; 112 } 113 else 114 return 0; 115 } 116 } 117 118 // recur 119 return getSample(); 120 } 121 122 // algorithm tuning (libSoundTouch specific.. see SoundTouch.h) setSetting(uint settingId,uint value)123 bool setSetting(uint settingId,uint value) 124 { 125 return changer.setSetting(settingId,value); 126 } 127 128 private: 129 const src_type src; 130 const sample_pos_t srcOffset; 131 const sample_pos_t length; 132 const float deltaSemitones; 133 const sample_pos_t frameSize; 134 const sample_pos_t frameOffset; 135 136 sample_pos_t pos; 137 sample_pos_t srcEnd; 138 bool flushed; 139 140 TAutoBuffer<soundtouch::SAMPLETYPE> outputBuffer; 141 size_t outputBufferOffset; 142 size_t outputBufferSize; 143 144 TAutoBuffer<soundtouch::SAMPLETYPE> inputBuffer; 145 146 SoundTouch changer; 147 }; 148 149 #endif // HAVE_LIBSOUNDTOUCH 150 151 #endif 152