1 #ifndef _WDL_SIMPLEPITCHSHIFT_H_
2 #define _WDL_SIMPLEPITCHSHIFT_H_
7 #ifndef WDL_SIMPLEPITCHSHIFT_SAMPLETYPE
8 #define WDL_SIMPLEPITCHSHIFT_SAMPLETYPE double
12 #ifdef WDL_SIMPLEPITCHSHIFT_PARENTCLASS
13 class WDL_SimplePitchShifter
: public WDL_SIMPLEPITCHSHIFT_PARENTCLASS
15 class WDL_SimplePitchShifter
19 WDL_SimplePitchShifter()
29 ~WDL_SimplePitchShifter() { }
39 m_rsbuf
.Resize(0,false);
40 m_psbuf
.Resize(0,false);
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
)
76 #ifdef WDL_SIMPLEPITCHSHIFT_EXTRA_INTERFACE
77 WDL_SIMPLEPITCHSHIFT_EXTRA_INTERFACE
81 void PitchShiftBlock(WDL_SIMPLEPITCHSHIFT_SAMPLETYPE
*inputs
, WDL_SIMPLEPITCHSHIFT_SAMPLETYPE
*outputs
, int nch
, int length
, double pitch
, int bsize
, int olsize
, double srate
);
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
;
91 WDL_TypedBuf
<WDL_SIMPLEPITCHSHIFT_SAMPLETYPE
> m_inbuf
;
92 WDL_TypedBuf
<WDL_SIMPLEPITCHSHIFT_SAMPLETYPE
> m_rsbuf
;
104 #ifdef WDL_SIMPLEPITCHSHIFT_IMPLEMENT
105 void WDL_SimplePitchShifter::BufferDone(int input_filled
)
107 // perform pitch shifting
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);
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
);
134 int needclear
=m_rsbuf
.GetSize()<m_last_nch
;
136 WDL_SIMPLEPITCHSHIFT_SAMPLETYPE
*bufi
=m_rsbuf
.Resize((input_filled
+1)*m_last_nch
,false);
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
;
155 int outlen
= (int) (input_filled
*itempo
-fp
) + 128; // upper bound on possible sample count
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
));
177 for (a
= 0; a
< nch
; a
++)
179 *bufo
++ = bufi
[idx
+a
]*(1.0-rdpos
)+bufi
[idx
+nch
+a
]*rdpos
;
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
)
194 if (!GetSizes(q
,&ws
,&os
)) return NULL
;
195 static char buf
[128];
196 sprintf(buf
,"%dms window, %dms fade",ws
,os
);
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]))];
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
);
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();
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
;
246 int ipos1
=(int)pspos
;
247 double frac0
=pspos
-ipos1
;
253 if (ipos2
>= bsizench
) ipos2
=0;
256 for(a
=0;a
<nch
;a
++) outputs
[a
]=(psbuf
[ipos1
+a
]*(1-frac0
)+psbuf
[ipos2
+a
]*frac0
);
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
;
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
;
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
;
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
));
303 if (++writepos
>= bsize
) writeposnch
= writepos
=0;
309 m_pswritepos
=writepos
;