annotate sv/filter/TimeStretchFilter.cpp @ 97:486e44e12a5d

this version use only one servlet. Data is provide by stream capacity.
author benoitrigolleau
date Tue, 10 Jul 2007 16:01:13 +0000
parents 87495ac7710a
children d94ee3e8dfe1
rev   line source
lbajardsilogic@79 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
lbajardsilogic@79 2
lbajardsilogic@79 3 /* Sound Access
lbajardsilogic@79 4 EASAIER client application.
lbajardsilogic@79 5 Silogic 2007. Laure Bajard.
lbajardsilogic@79 6
lbajardsilogic@79 7 This program is free software; you can redistribute it and/or
lbajardsilogic@79 8 modify it under the terms of the GNU General Public License as
lbajardsilogic@79 9 published by the Free Software Foundation; either version 2 of the
lbajardsilogic@79 10 License, or (at your option) any later version. See the file
lbajardsilogic@79 11 COPYING included with this distribution for more information.
lbajardsilogic@79 12 */
lbajardsilogic@79 13
lbajardsilogic@79 14 #include <math.h>
lbajardsilogic@82 15 #include <iostream>
lbajardsilogic@79 16
lbajardsilogic@79 17 #include "TimeStretchFilter.h"
lbajardsilogic@79 18
lbajardsilogic@79 19 #include "FFTReal.h"
lbajardsilogic@79 20 #include "DSP.h"
lbajardsilogic@79 21
lbajardsilogic@82 22 #include "system/System.h"
lbajardsilogic@82 23
lbajardsilogic@82 24 /*float *audioframe;
lbajardsilogic@79 25 float *prev_audioframe;
lbajardsilogic@79 26 float *window;
lbajardsilogic@79 27 float *processedframe;
lbajardsilogic@79 28 float *outbuffer;
lbajardsilogic@79 29 float *holdbuffer3;
lbajardsilogic@79 30 float *holdbuffer2;
lbajardsilogic@79 31 float *holdbuffer1;
lbajardsilogic@79 32
lbajardsilogic@79 33 float *c_phase; ///CURRENT FRAME phases
lbajardsilogic@79 34 float *p_phase; ///PREVIOUS FRAME phases
lbajardsilogic@79 35 float *c_synthphase;
lbajardsilogic@79 36 float *p_synthphase;
lbajardsilogic@82 37 float *synthframe;*/
lbajardsilogic@82 38
lbajardsilogic@82 39 float *c_mags; ///CURRENT FRAME MAGNITUDES
lbajardsilogic@82 40 float *p_mags; ///PREVIOUS FRAME MAGNITUDES
lbajardsilogic@79 41
lbajardsilogic@79 42 float *FFTframe;
lbajardsilogic@79 43
lbajardsilogic@79 44 float hopfactor = 1;
lbajardsilogic@82 45
lbajardsilogic@82 46 //need in DSP.cpp
lbajardsilogic@79 47 float lastfactor;
lbajardsilogic@79 48
lbajardsilogic@79 49 int numpeaks;
lbajardsilogic@79 50 float *peak_locations;
lbajardsilogic@82 51 int currentposition = 1024+1;//= hop+1;
lbajardsilogic@82 52 //
lbajardsilogic@79 53
lbajardsilogic@82 54 TimeStretchFilter::TimeStretchFilter() : Filter(),
lbajardsilogic@82 55 m_bypass(false),
lbajardsilogic@82 56 m_transcheck(false),
lbajardsilogic@82 57 m_peakcheck(false),
lbajardsilogic@82 58 m_framesize(4096),
lbajardsilogic@82 59 m_interpfactor(1)
lbajardsilogic@79 60 {
lbajardsilogic@82 61 m_hop = m_framesize/4;
lbajardsilogic@79 62
lbajardsilogic@82 63 m_inputBuffer = (float *)calloc((m_framesize*2+1), sizeof(float));
lbajardsilogic@82 64
lbajardsilogic@79 65 /**********malloc***********/
lbajardsilogic@82 66 FFTframe=(float *)calloc((m_framesize), sizeof(float));
lbajardsilogic@79 67
lbajardsilogic@79 68 //This block specifically sets up the buffers required to do a 75% overlap scheme
lbajardsilogic@82 69 audioframe=(float *)calloc((m_framesize), sizeof(float)); //The current frame
lbajardsilogic@82 70 prev_audioframe=(float *)calloc((m_framesize), sizeof(float));
lbajardsilogic@82 71 window=(float *)calloc((m_framesize), sizeof(float)); //Window
lbajardsilogic@82 72 processedframe=(float *)calloc((m_framesize), sizeof(float)); //The current frame
lbajardsilogic@82 73 synthframe=(float *)calloc((m_framesize), sizeof(float));
lbajardsilogic@82 74 outbuffer=(float *)calloc((m_framesize/4), sizeof(float)); //The current output segment which is 1/4 framesize for 75% overlap
lbajardsilogic@79 75
lbajardsilogic@82 76 holdbuffer3=(float *)calloc((m_framesize*0.75), sizeof(float)); //The hold buffer for the previous frame segment
lbajardsilogic@82 77 holdbuffer2=(float *)calloc((m_framesize/2), sizeof(float)); //The fold buffer for the frame segment 2 frames ago
lbajardsilogic@82 78 holdbuffer1=(float *)calloc((m_framesize/4), sizeof(float));
lbajardsilogic@79 79
lbajardsilogic@82 80 c_mags=(float *)calloc((m_framesize/2), sizeof(float)); //The magnitude and phase arrays
lbajardsilogic@82 81 p_mags=(float *)calloc((m_framesize/2), sizeof(float));
lbajardsilogic@82 82 c_phase=(float *)calloc((m_framesize/2), sizeof(float));
lbajardsilogic@82 83 p_phase=(float *)calloc((m_framesize/2), sizeof(float));
lbajardsilogic@82 84 c_synthphase=(float *)calloc((m_framesize/2), sizeof(float));
lbajardsilogic@82 85 p_synthphase=(float *)calloc((m_framesize/2), sizeof(float));
lbajardsilogic@79 86
lbajardsilogic@82 87 peak_locations=(float *)calloc((m_framesize/2), sizeof(float));
lbajardsilogic@79 88
lbajardsilogic@82 89 hanning(window, m_framesize);
lbajardsilogic@82 90
lbajardsilogic@79 91 /***************************/
lbajardsilogic@79 92 }
lbajardsilogic@79 93
lbajardsilogic@79 94 TimeStretchFilter::~TimeStretchFilter()
lbajardsilogic@79 95 {
lbajardsilogic@79 96 /**********de-alloc***********/
lbajardsilogic@82 97 delete m_inputBuffer;
lbajardsilogic@82 98 delete FFTframe;
lbajardsilogic@79 99
lbajardsilogic@79 100 delete audioframe;
lbajardsilogic@79 101 delete prev_audioframe;
lbajardsilogic@79 102 delete window;
lbajardsilogic@79 103 delete processedframe;
lbajardsilogic@79 104 delete synthframe;
lbajardsilogic@79 105
lbajardsilogic@79 106 delete holdbuffer3;
lbajardsilogic@79 107 delete holdbuffer2;
lbajardsilogic@79 108 delete holdbuffer1;
lbajardsilogic@79 109
lbajardsilogic@79 110 delete c_mags;
lbajardsilogic@79 111 delete p_mags;
lbajardsilogic@79 112 delete c_phase;
lbajardsilogic@79 113 delete p_phase;
lbajardsilogic@79 114 delete c_synthphase;
lbajardsilogic@79 115 delete p_synthphase;
lbajardsilogic@79 116
lbajardsilogic@79 117 delete peak_locations;
lbajardsilogic@79 118
lbajardsilogic@82 119 delete outbuffer;
lbajardsilogic@79 120
lbajardsilogic@79 121 /***************************/
lbajardsilogic@79 122 }
lbajardsilogic@79 123
lbajardsilogic@79 124 TimeStretchFilter::PropertyList TimeStretchFilter::getProperties() const
lbajardsilogic@79 125 {
lbajardsilogic@79 126 PropertyList list;
lbajardsilogic@90 127 //list.push_back("Time");
lbajardsilogic@79 128 list.push_back("Pitch");
lbajardsilogic@79 129 list.push_back("Bypass");
lbajardsilogic@79 130 list.push_back("Transdetect");
lbajardsilogic@79 131 list.push_back("Peaklock");
lbajardsilogic@79 132 return list;
lbajardsilogic@79 133 }
lbajardsilogic@79 134
lbajardsilogic@79 135 QString TimeStretchFilter::getPropertyLabel(const PropertyName &name) const
lbajardsilogic@79 136 {
lbajardsilogic@79 137 if (name == "Time") return tr("Time");
lbajardsilogic@79 138 if (name == "Pitch") return tr("Pitch");
lbajardsilogic@79 139 if (name == "Bypass") return tr("Bypass Processing");
lbajardsilogic@79 140 if (name == "Transdetect") return tr("Transient Detection");
lbajardsilogic@79 141 if (name == "Peaklock") return tr("Peak Locking");
lbajardsilogic@79 142 return "";
lbajardsilogic@79 143 }
lbajardsilogic@79 144
lbajardsilogic@79 145 TimeStretchFilter::PropertyType TimeStretchFilter::getPropertyType(const PropertyName &name) const
lbajardsilogic@79 146 {
lbajardsilogic@79 147 if (name == "Time") return RangeProperty;
lbajardsilogic@79 148 if (name == "Pitch") return RangeProperty;
lbajardsilogic@79 149 if (name == "Bypass") return ToggleProperty;
lbajardsilogic@79 150 if (name == "Transdetect") return ToggleProperty;
lbajardsilogic@79 151 if (name == "Peaklock") return ToggleProperty;
lbajardsilogic@79 152 return InvalidProperty;
lbajardsilogic@79 153 }
lbajardsilogic@79 154
lbajardsilogic@79 155 int TimeStretchFilter::getPropertyRangeAndValue(const PropertyName &name,
lbajardsilogic@79 156 int *min, int *max, int *deflt) const
lbajardsilogic@79 157 {
lbajardsilogic@79 158 //!!! factor this colour handling stuff out into a colour manager class
lbajardsilogic@79 159 int val = 0;
lbajardsilogic@79 160
lbajardsilogic@79 161 if (name == "Time") {
lbajardsilogic@79 162 if (min) *min = -100;
lbajardsilogic@79 163 if (max) *max = 100;
lbajardsilogic@79 164 if (deflt) *deflt = 0;
lbajardsilogic@79 165 }
lbajardsilogic@79 166
lbajardsilogic@79 167 if (name == "Pitch") {
lbajardsilogic@79 168 if (min) *min = -100;
lbajardsilogic@79 169 if (max) *max = 100;
lbajardsilogic@79 170 if (deflt) *deflt = 0;
lbajardsilogic@82 171 }
lbajardsilogic@79 172
lbajardsilogic@82 173 if (name == "Bypass") {
lbajardsilogic@82 174 if (deflt) *deflt = 0;
lbajardsilogic@82 175 val = (m_bypass ? 1 : 0);
lbajardsilogic@82 176 }
lbajardsilogic@82 177
lbajardsilogic@82 178 if (name == "Transdetect") {
lbajardsilogic@82 179 if (deflt) *deflt = 0;
lbajardsilogic@82 180 val = (m_transcheck ? 1 : 0);
lbajardsilogic@82 181 }
lbajardsilogic@82 182
lbajardsilogic@82 183 if (name == "Peaklock") {
lbajardsilogic@82 184 if (deflt) *deflt = 0;
lbajardsilogic@82 185 val = (m_peakcheck ? 1 : 0);
lbajardsilogic@82 186 }
lbajardsilogic@79 187
lbajardsilogic@79 188 return val;
lbajardsilogic@79 189 }
lbajardsilogic@79 190
lbajardsilogic@79 191 QString TimeStretchFilter::getPropertyValueLabel(const PropertyName &name,
lbajardsilogic@79 192 int value) const
lbajardsilogic@79 193 {
lbajardsilogic@79 194 if (name == "Time") {
lbajardsilogic@79 195 if (value == -100)
lbajardsilogic@79 196 return tr("Slow");
lbajardsilogic@79 197 if (value == 100)
lbajardsilogic@79 198 return tr("Fast");
lbajardsilogic@79 199 }
lbajardsilogic@79 200 return tr("<unknown>");
lbajardsilogic@79 201 }
lbajardsilogic@79 202
lbajardsilogic@79 203 void TimeStretchFilter::setProperty(const PropertyName &name, int value)
lbajardsilogic@79 204 {
lbajardsilogic@79 205 if (name == "Time") {
lbajardsilogic@82 206 float tmaxfactor=2;
lbajardsilogic@79 207 if (value > 0){
lbajardsilogic@82 208 hopfactor=1.0+((tmaxfactor-1)*(((float)value)/100));
lbajardsilogic@79 209 }
lbajardsilogic@79 210 if (value < 0){
lbajardsilogic@82 211 hopfactor=1.0/(1.0+((tmaxfactor-1)*(-((float)value)/100)));
lbajardsilogic@79 212 }
lbajardsilogic@79 213 if(value == 0){
lbajardsilogic@79 214 hopfactor=1;
lbajardsilogic@79 215 }
lbajardsilogic@79 216 } else if (name == "Pitch") {
lbajardsilogic@82 217 float pmaxfactor=2;
lbajardsilogic@79 218 if (value > 0){
lbajardsilogic@82 219 m_interpfactor=1.0+((pmaxfactor-1)*(((float)value)/100));
lbajardsilogic@79 220 }
lbajardsilogic@79 221 if (value < 0){
lbajardsilogic@82 222 m_interpfactor=1.0/(1.0+((pmaxfactor-1)*(-((float)value)/100)));
lbajardsilogic@79 223 }
lbajardsilogic@79 224 if(value == 0){
lbajardsilogic@82 225 m_interpfactor=1;
lbajardsilogic@79 226 }
lbajardsilogic@79 227 } else if (name == "Bypass"){
lbajardsilogic@79 228 m_bypass = (value > 0) ? true : false;
lbajardsilogic@79 229 } else if (name == "Transdetect"){
lbajardsilogic@79 230 m_transcheck = (value > 0) ? true : false;
lbajardsilogic@79 231 } else if (name == "Peaklock"){
lbajardsilogic@79 232 m_peakcheck = (value > 0) ? true : false;
lbajardsilogic@79 233 }
lbajardsilogic@79 234
lbajardsilogic@79 235 }
lbajardsilogic@79 236
lbajardsilogic@79 237 void TimeStretchFilter::putInput(float **input, size_t samples)
lbajardsilogic@82 238 {
lbajardsilogic@82 239 int dd;
lbajardsilogic@82 240 float sampdiff;
lbajardsilogic@82 241 float difratio;
lbajardsilogic@82 242 float interpsample;
lbajardsilogic@82 243
lbajardsilogic@82 244 bool drum = 0;
lbajardsilogic@82 245 float drumthresh = 65;
lbajardsilogic@82 246 int transhold = 0;
lbajardsilogic@82 247
lbajardsilogic@82 248 if (samples < floor(m_framesize*m_interpfactor + 1))
lbajardsilogic@82 249 return;
lbajardsilogic@82 250
lbajardsilogic@84 251 int channel = getSourceChannelCount();
lbajardsilogic@82 252
lbajardsilogic@82 253 for (int i=0; i<samples; i++){
lbajardsilogic@82 254 if (channel > 1)
lbajardsilogic@82 255 m_inputBuffer[i] = (input[0][i] + input[1][i]) /2;
lbajardsilogic@82 256 else
lbajardsilogic@82 257 m_inputBuffer[i] = input[0][i];
lbajardsilogic@79 258 }
lbajardsilogic@82 259
lbajardsilogic@82 260 for (int i = 0; i<(m_framesize); i++)
lbajardsilogic@79 261 {
lbajardsilogic@79 262
lbajardsilogic@79 263 //This block was specifically written to do resampling interpolation for crude pitch shifting
lbajardsilogic@79 264 //if it's not being used the audioframe line after the else should be used which is also used in bypass mode
lbajardsilogic@79 265 //At
lbajardsilogic@79 266
lbajardsilogic@79 267 if (m_bypass == false) {
lbajardsilogic@82 268 dd = floor(double(i*m_interpfactor));
lbajardsilogic@82 269 difratio = (double(i*m_interpfactor)) - floor(double(i*m_interpfactor));
lbajardsilogic@82 270
lbajardsilogic@79 271 // this block loads a frame as normal
lbajardsilogic@82 272 sampdiff=m_inputBuffer[dd+1]-m_inputBuffer[dd];
lbajardsilogic@82 273 interpsample = (difratio*sampdiff)+m_inputBuffer[dd];
lbajardsilogic@82 274 audioframe[i] = (interpsample)*window[i];
lbajardsilogic@79 275 }
lbajardsilogic@79 276 else {
lbajardsilogic@82 277 audioframe[i] = (m_inputBuffer[i+1])*window[i];
lbajardsilogic@79 278 processedframe[i] = (audioframe[i])*window[i];
lbajardsilogic@79 279 }
lbajardsilogic@79 280 }
lbajardsilogic@79 281
lbajardsilogic@82 282 FFTReal fft_object (m_framesize);
lbajardsilogic@79 283
lbajardsilogic@79 284 if (m_bypass == false)
lbajardsilogic@79 285 {
lbajardsilogic@79 286 fft_object.do_fft (FFTframe,audioframe);
lbajardsilogic@79 287
lbajardsilogic@82 288 cart2pol(FFTframe, c_mags, c_phase, m_framesize);
lbajardsilogic@79 289
lbajardsilogic@79 290 //--------------------------------------------
lbajardsilogic@79 291
lbajardsilogic@79 292 fft_object.do_fft (FFTframe,prev_audioframe);
lbajardsilogic@79 293
lbajardsilogic@82 294 cart2pol(FFTframe, p_mags, p_phase, m_framesize);
lbajardsilogic@79 295
lbajardsilogic@82 296 drum=transient_detect(c_mags, c_mags, p_mags, p_mags, drumthresh, m_framesize);
lbajardsilogic@79 297
lbajardsilogic@79 298
lbajardsilogic@79 299 if (m_transcheck)
lbajardsilogic@79 300 {
lbajardsilogic@79 301
lbajardsilogic@79 302 if (drum && transhold==0){
lbajardsilogic@82 303 cur2last(c_phase, c_synthphase, p_synthphase, m_framesize);
lbajardsilogic@79 304 transhold=4;
lbajardsilogic@79 305 }
lbajardsilogic@79 306 else{
lbajardsilogic@79 307 if(m_peakcheck){
lbajardsilogic@82 308 rotatephases_peaklocked(c_phase, p_phase, c_synthphase, p_synthphase, m_framesize, m_interpfactor);
lbajardsilogic@79 309 }
lbajardsilogic@79 310 else{
lbajardsilogic@82 311 rotatephases(c_phase, p_phase, c_synthphase, p_synthphase, m_framesize, m_interpfactor);
lbajardsilogic@79 312 }
lbajardsilogic@79 313 }
lbajardsilogic@79 314 }
lbajardsilogic@79 315 else
lbajardsilogic@79 316 {
lbajardsilogic@79 317 if(m_peakcheck){
lbajardsilogic@82 318 rotatephases_peaklocked(c_phase, p_phase, c_synthphase, p_synthphase, m_framesize, m_interpfactor);
lbajardsilogic@79 319 }
lbajardsilogic@79 320 else{
lbajardsilogic@82 321 rotatephases(c_phase, p_phase, c_synthphase, p_synthphase, m_framesize, m_interpfactor);
lbajardsilogic@79 322 }
lbajardsilogic@79 323 }
lbajardsilogic@79 324
lbajardsilogic@79 325 if(transhold != 0){
lbajardsilogic@79 326 transhold=transhold-1;
lbajardsilogic@79 327 }
lbajardsilogic@79 328
lbajardsilogic@79 329 drum = 0;
lbajardsilogic@79 330
lbajardsilogic@82 331 pol2cart(FFTframe, c_mags, c_synthphase, m_framesize);
lbajardsilogic@79 332
lbajardsilogic@79 333 fft_object.do_ifft (FFTframe,processedframe);
lbajardsilogic@79 334 fft_object.rescale (processedframe); //VIP######## I have edited this function to do rewindowing also######
lbajardsilogic@79 335 }
lbajardsilogic@79 336
lbajardsilogic@82 337 for (int p = 0; p<(m_framesize); p++){
lbajardsilogic@79 338 processedframe[p]=processedframe[p]*window[p];
lbajardsilogic@79 339 }
lbajardsilogic@79 340
lbajardsilogic@82 341 for (int j = 0; j<(m_framesize); j++)
lbajardsilogic@79 342 {
lbajardsilogic@79 343 //This block deals with the buffers for a 75% overlap scheme
lbajardsilogic@79 344
lbajardsilogic@82 345 if (j < m_framesize/4){
lbajardsilogic@79 346 outbuffer[j]=(processedframe[j]+holdbuffer1[j]+holdbuffer2[j]+holdbuffer3[j])*0.5;
lbajardsilogic@82 347 holdbuffer1[j]=holdbuffer2[j+(m_framesize/4)];
lbajardsilogic@79 348 }
lbajardsilogic@79 349
lbajardsilogic@82 350 if (j < m_framesize/2){
lbajardsilogic@82 351 holdbuffer2[j]=holdbuffer3[j+(m_framesize/4)];
lbajardsilogic@79 352 }
lbajardsilogic@79 353
lbajardsilogic@82 354 if (j < m_framesize*0.75){
lbajardsilogic@82 355 holdbuffer3[j]=processedframe[j+(m_framesize/4)];
lbajardsilogic@79 356 }
lbajardsilogic@79 357 }
lbajardsilogic@82 358
lbajardsilogic@82 359 for (int i = 0; i<(m_framesize); i++)
lbajardsilogic@82 360 {
lbajardsilogic@82 361 prev_audioframe[i] = audioframe[i];
lbajardsilogic@82 362 }
lbajardsilogic@79 363 }
lbajardsilogic@79 364
lbajardsilogic@79 365 void TimeStretchFilter::getOutput(float **output, size_t samples)
lbajardsilogic@79 366 {
lbajardsilogic@82 367 if (samples > m_framesize/4)
lbajardsilogic@82 368 return;
lbajardsilogic@82 369
lbajardsilogic@84 370 int channel = getSourceChannelCount();
lbajardsilogic@82 371
lbajardsilogic@82 372 for (int i=0; i<samples; i++){
lbajardsilogic@82 373 output[0][i] = outbuffer[i];
lbajardsilogic@82 374 if (channel > 1)
lbajardsilogic@82 375 output[1][i] = outbuffer[i];
lbajardsilogic@82 376 }
lbajardsilogic@82 377 }
lbajardsilogic@82 378
lbajardsilogic@82 379 size_t TimeStretchFilter::getRequiredInputSamples(size_t outputSamplesNeeded)
lbajardsilogic@82 380 {
lbajardsilogic@82 381 // max (m_framesize, outputSamplesNeeded*2)
lbajardsilogic@82 382 size_t need = max( floor(m_framesize*m_interpfactor + 1), outputSamplesNeeded*2);
lbajardsilogic@79 383
lbajardsilogic@82 384 return need;
lbajardsilogic@79 385 }