Make duplicate script compatible with Python 3
[wdl/wdl-ol.git] / WDL / simple_pitchshift.h
blob592f8a25da6f097ea8ee79d595d242703358f2b8
1 #ifndef _WDL_SIMPLEPITCHSHIFT_H_
2 #define _WDL_SIMPLEPITCHSHIFT_H_
5 #include "queue.h"
7 #ifndef WDL_SIMPLEPITCHSHIFT_SAMPLETYPE
8 #define WDL_SIMPLEPITCHSHIFT_SAMPLETYPE double
9 #endif
12 #ifdef WDL_SIMPLEPITCHSHIFT_PARENTCLASS
13 class WDL_SimplePitchShifter : public WDL_SIMPLEPITCHSHIFT_PARENTCLASS
14 #else
15 class WDL_SimplePitchShifter
16 #endif
18 public:
19 WDL_SimplePitchShifter()
21 m_last_nch=1;
22 m_srate=44100.0;
23 m_last_tempo=1.0;
24 m_last_shift=1.0;
25 m_qual=0;
27 Reset();
29 ~WDL_SimplePitchShifter() { }
31 void Reset()
33 m_hadinput=0;
34 m_pspos=0.0;
35 m_pswritepos=0;
36 m_latpos=0;
37 m_tempo_fracpos=0.0;
38 m_queue.Clear();
39 m_rsbuf.Resize(0,false);
40 m_psbuf.Resize(0,false);
43 bool IsReset()
45 return !m_queue.Available() && !m_hadinput;
50 void set_srate(double srate) { m_srate=srate; }
51 void set_nch(int nch) { if (m_last_nch!=nch) { m_queue.Clear(); m_last_nch=nch; m_tempo_fracpos=0.0; } }
52 void set_shift(double shift) { m_last_shift=shift; }
53 void set_tempo(double tempo) { m_last_tempo=tempo; }
54 void set_formant_shift(double shift)
58 WDL_SIMPLEPITCHSHIFT_SAMPLETYPE *GetBuffer(int size)
60 return m_inbuf.Resize(size*m_last_nch);
62 void BufferDone(int input_filled);
63 void FlushSamples() {}
65 static const char *enumQual(int q);
66 static bool GetSizes(int qv, int *ws, int *os);
68 int GetSamples(int requested_output, WDL_SIMPLEPITCHSHIFT_SAMPLETYPE *buffer);
71 void SetQualityParameter(int parm)
73 m_qual=parm;
76 #ifdef WDL_SIMPLEPITCHSHIFT_EXTRA_INTERFACE
77 WDL_SIMPLEPITCHSHIFT_EXTRA_INTERFACE
78 #endif
80 private:
81 void PitchShiftBlock(WDL_SIMPLEPITCHSHIFT_SAMPLETYPE *inputs, WDL_SIMPLEPITCHSHIFT_SAMPLETYPE *outputs, int nch, int length, double pitch, int bsize, int olsize, double srate);
84 private:
85 double m_pspos WDL_FIXALIGN;
86 double m_tempo_fracpos;
87 double m_srate,m_last_tempo,m_last_shift;
89 WDL_TypedBuf<WDL_SIMPLEPITCHSHIFT_SAMPLETYPE> m_psbuf;
90 WDL_Queue m_queue;
91 WDL_TypedBuf<WDL_SIMPLEPITCHSHIFT_SAMPLETYPE> m_inbuf;
92 WDL_TypedBuf<WDL_SIMPLEPITCHSHIFT_SAMPLETYPE> m_rsbuf;
94 int m_pswritepos;
95 int m_last_nch;
96 int m_qual;
97 int m_hadinput;
99 int m_latpos;
104 #ifdef WDL_SIMPLEPITCHSHIFT_IMPLEMENT
105 void WDL_SimplePitchShifter::BufferDone(int input_filled)
107 // perform pitch shifting
108 if (input_filled>0)
110 m_hadinput=1;
111 int ws,os;
112 GetSizes(m_qual,&ws,&os);
114 int bsize=(int) (ws * 0.001 * m_srate);
115 if (bsize<16) bsize=16;
116 else if (bsize>128*1024)bsize=128*1024;
118 int olsize=(int) (os * 0.001 * m_srate);
119 if (olsize > bsize/2) olsize=bsize/2;
120 if (olsize<1)olsize=1;
121 if (m_psbuf.GetSize() != bsize*m_last_nch)
123 memset(m_psbuf.Resize(bsize*m_last_nch,false),0,sizeof(WDL_SIMPLEPITCHSHIFT_SAMPLETYPE)*bsize*m_last_nch);
124 m_pspos=(double) (bsize/2);
125 m_pswritepos=0;
128 if (fabs(m_last_tempo-1.0)<0.0000000001)
130 PitchShiftBlock(m_inbuf.Get(),(WDL_SIMPLEPITCHSHIFT_SAMPLETYPE *)m_queue.Add(NULL,input_filled*m_last_nch*sizeof(WDL_SIMPLEPITCHSHIFT_SAMPLETYPE)),m_last_nch,input_filled,m_last_shift,bsize,olsize,m_srate);
132 else
134 int needclear=m_rsbuf.GetSize()<m_last_nch;
136 WDL_SIMPLEPITCHSHIFT_SAMPLETYPE *bufi=m_rsbuf.Resize((input_filled+1)*m_last_nch,false);
137 if (needclear)
138 memset(bufi,0,m_last_nch*sizeof(WDL_SIMPLEPITCHSHIFT_SAMPLETYPE));
140 double tempo=m_last_tempo;
141 double itempo=1.0/tempo;
142 PitchShiftBlock(m_inbuf.Get(),bufi+m_last_nch,m_last_nch,input_filled,m_last_shift*itempo,bsize,olsize,m_srate);
144 double fp=m_tempo_fracpos;
147 if (m_latpos < bsize/2)
149 int a = bsize/2-m_latpos;
150 if (a > input_filled) a=input_filled;
151 m_latpos+=a;
152 fp += a;
155 int outlen = (int) (input_filled*itempo-fp) + 128; // upper bound on possible sample count
156 if (outlen<0)
158 outlen=0;
161 WDL_SIMPLEPITCHSHIFT_SAMPLETYPE *bufo = (WDL_SIMPLEPITCHSHIFT_SAMPLETYPE *)m_queue.Add(NULL,outlen*m_last_nch*sizeof(WDL_SIMPLEPITCHSHIFT_SAMPLETYPE));
162 // resample bufi to bufo
163 int i,nch=m_last_nch;
164 for (i = 0; i < outlen; i ++)
166 double rdpos=floor(fp);
167 int idx=((int)rdpos);
168 if (idx>=input_filled)
170 // un-add any missing samples
171 m_queue.Add(NULL,(i-outlen)*m_last_nch*sizeof(WDL_SIMPLEPITCHSHIFT_SAMPLETYPE));
172 break;
174 rdpos = (fp-rdpos);
175 int a;
176 idx*=nch;
177 for (a = 0; a < nch; a ++)
179 *bufo++ = bufi[idx+a]*(1.0-rdpos)+bufi[idx+nch+a]*rdpos;
181 fp += tempo;
184 memcpy(bufi,bufi+m_last_nch*input_filled,m_last_nch*sizeof(WDL_SIMPLEPITCHSHIFT_SAMPLETYPE)); // save last sample for interpolation later
186 m_tempo_fracpos=fp-floor(fp);
191 const char *WDL_SimplePitchShifter::enumQual(int q)
193 int ws,os;
194 if (!GetSizes(q,&ws,&os)) return NULL;
195 static char buf[128];
196 sprintf(buf,"%dms window, %dms fade",ws,os);
197 return buf;
200 bool WDL_SimplePitchShifter::GetSizes(int qv, int *ws, int *os)
202 int windows[]={50,75,100,150,225,300,40,30,20,10,5,3};
203 int divs[]={2,3,5,7};
205 int wd=qv/(sizeof(divs)/sizeof(divs[0]));
206 if (wd >= sizeof(windows)/sizeof(windows[0])) wd=-1;
208 *ws=windows[wd>=0?wd:0];
209 *os = *ws / divs[qv%(sizeof(divs)/sizeof(divs[0]))];
210 if (*os<1) *os=1;
212 return wd>=0;
215 int WDL_SimplePitchShifter::GetSamples(int requested_output, WDL_SIMPLEPITCHSHIFT_SAMPLETYPE *buffer)
217 if (!m_last_nch||requested_output<1) return 0;
219 int l=m_queue.Available()/sizeof(WDL_SIMPLEPITCHSHIFT_SAMPLETYPE)/m_last_nch;
221 if (requested_output>l) requested_output=l;
222 int sz=requested_output*sizeof(WDL_SIMPLEPITCHSHIFT_SAMPLETYPE)*m_last_nch;
223 memcpy(buffer,m_queue.Get(),sz);
224 m_queue.Advance(sz);
225 m_queue.Compact();
226 return requested_output;
229 void WDL_SimplePitchShifter::PitchShiftBlock(WDL_SIMPLEPITCHSHIFT_SAMPLETYPE *inputs, WDL_SIMPLEPITCHSHIFT_SAMPLETYPE *outputs, int nch, int length, double pitch, int bsize, int olsize, double srate)
231 double iolsize=1.0/olsize;
233 WDL_SIMPLEPITCHSHIFT_SAMPLETYPE *psbuf=m_psbuf.Get();
235 double dpi=pitch;
237 double pspos=m_pspos;
238 int writepos=m_pswritepos;
239 int writeposnch = writepos*nch;
240 int bsizench = bsize*nch;
241 int olsizench = olsize*nch;
243 int i=length;
244 while (i--)
246 int ipos1=(int)pspos;
247 double frac0=pspos-ipos1;
249 ipos1*=nch;
251 int ipos2=ipos1+nch;
253 if (ipos2 >= bsizench) ipos2=0;
255 int a;
256 for(a=0;a<nch;a++) outputs[a]=(psbuf[ipos1+a]*(1-frac0)+psbuf[ipos2+a]*frac0);
258 double tv=pspos;
259 if (dpi >= 1.0)
261 if (tv > writepos) tv-=bsize;
263 if (tv >= writepos-olsize && tv < writepos)
265 double tfrac=(writepos-tv)*iolsize;
266 int tmp=ipos1+olsizench;
267 if (tmp>=bsizench) tmp-=bsizench;
268 int tmp2=tmp+nch;
269 if (tmp2 >= bsizench) tmp2=0;
271 for(a=0;a<nch;a++) outputs[a]= outputs[a]*tfrac + (1-tfrac)*(psbuf[tmp+a]*(1-frac0)+psbuf[tmp2+a]*frac0);
273 if (tv+pitch >= writepos) pspos+=olsize;
277 else
279 if (tv<writepos) tv+=bsize;
281 if (tv >= writepos && tv < writepos+olsize)
283 double tfrac=(tv-writepos)*iolsize;
284 int tmp=ipos1+olsizench;
285 if (tmp>=bsizench) tmp -= bsizench;
286 int tmp2= tmp+nch;
287 if (tmp2 >= bsizench) tmp2=0;
288 for(a=0;a<nch;a++) outputs[a] = outputs[a]*tfrac + (1-tfrac)*(psbuf[tmp+a]*(1-frac0)+psbuf[tmp2+a]*frac0);
290 // this is wrong, but blehhh?
291 if (tv+pitch < writepos+1) pspos += olsize;
292 // if (tv+pitch >= writepos+olsize) pspos += olsize;
297 if ((pspos+=pitch) >= bsize) pspos -= bsize;
300 memcpy(psbuf+writeposnch,inputs,nch*sizeof(WDL_SIMPLEPITCHSHIFT_SAMPLETYPE));
302 writeposnch += nch;
303 if (++writepos >= bsize) writeposnch = writepos=0;
305 inputs += nch;
306 outputs += nch;
307 } // sample loop
308 m_pspos=pspos;
309 m_pswritepos=writepos;
312 #endif
314 #endif