Mercurial > hg > easaier-soundaccess
view sv/filter/TimeStretchFilter.cpp @ 84:51a12971e10e
specify the number of channels of the source to the filters
author | lbajardsilogic |
---|---|
date | Fri, 22 Jun 2007 13:35:26 +0000 |
parents | 8ebc85f6ce4e |
children | 87495ac7710a |
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ /* Sound Access EASAIER client application. Silogic 2007. Laure Bajard. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See the file COPYING included with this distribution for more information. */ #include <math.h> #include <iostream> #include "TimeStretchFilter.h" #include "FFTReal.h" #include "DSP.h" #include "system/System.h" /*float *audioframe; float *prev_audioframe; float *window; float *processedframe; float *outbuffer; float *holdbuffer3; float *holdbuffer2; float *holdbuffer1; float *c_phase; ///CURRENT FRAME phases float *p_phase; ///PREVIOUS FRAME phases float *c_synthphase; float *p_synthphase; float *synthframe;*/ float *c_mags; ///CURRENT FRAME MAGNITUDES float *p_mags; ///PREVIOUS FRAME MAGNITUDES float *FFTframe; float hopfactor = 1; //need in DSP.cpp float lastfactor; int numpeaks; float *peak_locations; int currentposition = 1024+1;//= hop+1; // TimeStretchFilter::TimeStretchFilter() : Filter(), m_bypass(false), m_transcheck(false), m_peakcheck(false), m_framesize(4096), m_interpfactor(1) { m_hop = m_framesize/4; m_inputBuffer = (float *)calloc((m_framesize*2+1), sizeof(float)); /**********malloc***********/ FFTframe=(float *)calloc((m_framesize), sizeof(float)); //This block specifically sets up the buffers required to do a 75% overlap scheme audioframe=(float *)calloc((m_framesize), sizeof(float)); //The current frame prev_audioframe=(float *)calloc((m_framesize), sizeof(float)); window=(float *)calloc((m_framesize), sizeof(float)); //Window processedframe=(float *)calloc((m_framesize), sizeof(float)); //The current frame synthframe=(float *)calloc((m_framesize), sizeof(float)); outbuffer=(float *)calloc((m_framesize/4), sizeof(float)); //The current output segment which is 1/4 framesize for 75% overlap holdbuffer3=(float *)calloc((m_framesize*0.75), sizeof(float)); //The hold buffer for the previous frame segment holdbuffer2=(float *)calloc((m_framesize/2), sizeof(float)); //The fold buffer for the frame segment 2 frames ago holdbuffer1=(float *)calloc((m_framesize/4), sizeof(float)); c_mags=(float *)calloc((m_framesize/2), sizeof(float)); //The magnitude and phase arrays p_mags=(float *)calloc((m_framesize/2), sizeof(float)); c_phase=(float *)calloc((m_framesize/2), sizeof(float)); p_phase=(float *)calloc((m_framesize/2), sizeof(float)); c_synthphase=(float *)calloc((m_framesize/2), sizeof(float)); p_synthphase=(float *)calloc((m_framesize/2), sizeof(float)); peak_locations=(float *)calloc((m_framesize/2), sizeof(float)); hanning(window, m_framesize); /***************************/ } TimeStretchFilter::~TimeStretchFilter() { /**********de-alloc***********/ delete m_inputBuffer; delete FFTframe; delete audioframe; delete prev_audioframe; delete window; delete processedframe; delete synthframe; delete holdbuffer3; delete holdbuffer2; delete holdbuffer1; delete c_mags; delete p_mags; delete c_phase; delete p_phase; delete c_synthphase; delete p_synthphase; delete peak_locations; delete outbuffer; /***************************/ } TimeStretchFilter::PropertyList TimeStretchFilter::getProperties() const { PropertyList list; list.push_back("Time"); list.push_back("Pitch"); list.push_back("Bypass"); list.push_back("Transdetect"); list.push_back("Peaklock"); return list; } QString TimeStretchFilter::getPropertyLabel(const PropertyName &name) const { if (name == "Time") return tr("Time"); if (name == "Pitch") return tr("Pitch"); if (name == "Bypass") return tr("Bypass Processing"); if (name == "Transdetect") return tr("Transient Detection"); if (name == "Peaklock") return tr("Peak Locking"); return ""; } TimeStretchFilter::PropertyType TimeStretchFilter::getPropertyType(const PropertyName &name) const { if (name == "Time") return RangeProperty; if (name == "Pitch") return RangeProperty; if (name == "Bypass") return ToggleProperty; if (name == "Transdetect") return ToggleProperty; if (name == "Peaklock") return ToggleProperty; return InvalidProperty; } int TimeStretchFilter::getPropertyRangeAndValue(const PropertyName &name, int *min, int *max, int *deflt) const { //!!! factor this colour handling stuff out into a colour manager class int val = 0; if (name == "Time") { if (min) *min = -100; if (max) *max = 100; if (deflt) *deflt = 0; } if (name == "Pitch") { if (min) *min = -100; if (max) *max = 100; if (deflt) *deflt = 0; } if (name == "Bypass") { if (deflt) *deflt = 0; val = (m_bypass ? 1 : 0); } if (name == "Transdetect") { if (deflt) *deflt = 0; val = (m_transcheck ? 1 : 0); } if (name == "Peaklock") { if (deflt) *deflt = 0; val = (m_peakcheck ? 1 : 0); } return val; } QString TimeStretchFilter::getPropertyValueLabel(const PropertyName &name, int value) const { if (name == "Time") { if (value == -100) return tr("Slow"); if (value == 100) return tr("Fast"); } return tr("<unknown>"); } void TimeStretchFilter::setProperty(const PropertyName &name, int value) { if (name == "Time") { float tmaxfactor=2; if (value > 0){ hopfactor=1.0+((tmaxfactor-1)*(((float)value)/100)); } if (value < 0){ hopfactor=1.0/(1.0+((tmaxfactor-1)*(-((float)value)/100))); } if(value == 0){ hopfactor=1; } } else if (name == "Pitch") { float pmaxfactor=2; if (value > 0){ m_interpfactor=1.0+((pmaxfactor-1)*(((float)value)/100)); } if (value < 0){ m_interpfactor=1.0/(1.0+((pmaxfactor-1)*(-((float)value)/100))); } if(value == 0){ m_interpfactor=1; } } else if (name == "Bypass"){ m_bypass = (value > 0) ? true : false; } else if (name == "Transdetect"){ m_transcheck = (value > 0) ? true : false; } else if (name == "Peaklock"){ m_peakcheck = (value > 0) ? true : false; } } void TimeStretchFilter::putInput(float **input, size_t samples) { int dd; float sampdiff; float difratio; float interpsample; bool drum = 0; float drumthresh = 65; int transhold = 0; if (samples < floor(m_framesize*m_interpfactor + 1)) return; int channel = getSourceChannelCount(); for (int i=0; i<samples; i++){ if (channel > 1) m_inputBuffer[i] = (input[0][i] + input[1][i]) /2; else m_inputBuffer[i] = input[0][i]; } for (int i = 0; i<(m_framesize); i++) { //This block was specifically written to do resampling interpolation for crude pitch shifting //if it's not being used the audioframe line after the else should be used which is also used in bypass mode //At if (m_bypass == false) { dd = floor(double(i*m_interpfactor)); difratio = (double(i*m_interpfactor)) - floor(double(i*m_interpfactor)); // this block loads a frame as normal sampdiff=m_inputBuffer[dd+1]-m_inputBuffer[dd]; interpsample = (difratio*sampdiff)+m_inputBuffer[dd]; audioframe[i] = (interpsample)*window[i]; } else { audioframe[i] = (m_inputBuffer[i+1])*window[i]; processedframe[i] = (audioframe[i])*window[i]; } } FFTReal fft_object (m_framesize); if (m_bypass == false) { fft_object.do_fft (FFTframe,audioframe); cart2pol(FFTframe, c_mags, c_phase, m_framesize); //-------------------------------------------- fft_object.do_fft (FFTframe,prev_audioframe); cart2pol(FFTframe, p_mags, p_phase, m_framesize); drum=transient_detect(c_mags, c_mags, p_mags, p_mags, drumthresh, m_framesize); if (m_transcheck) { if (drum && transhold==0){ cur2last(c_phase, c_synthphase, p_synthphase, m_framesize); transhold=4; } else{ if(m_peakcheck){ rotatephases_peaklocked(c_phase, p_phase, c_synthphase, p_synthphase, m_framesize, m_interpfactor); } else{ rotatephases(c_phase, p_phase, c_synthphase, p_synthphase, m_framesize, m_interpfactor); } } } else { if(m_peakcheck){ rotatephases_peaklocked(c_phase, p_phase, c_synthphase, p_synthphase, m_framesize, m_interpfactor); } else{ rotatephases(c_phase, p_phase, c_synthphase, p_synthphase, m_framesize, m_interpfactor); } } if(transhold != 0){ transhold=transhold-1; } drum = 0; pol2cart(FFTframe, c_mags, c_synthphase, m_framesize); fft_object.do_ifft (FFTframe,processedframe); fft_object.rescale (processedframe); //VIP######## I have edited this function to do rewindowing also###### } for (int p = 0; p<(m_framesize); p++){ processedframe[p]=processedframe[p]*window[p]; } for (int j = 0; j<(m_framesize); j++) { //This block deals with the buffers for a 75% overlap scheme if (j < m_framesize/4){ outbuffer[j]=(processedframe[j]+holdbuffer1[j]+holdbuffer2[j]+holdbuffer3[j])*0.5; holdbuffer1[j]=holdbuffer2[j+(m_framesize/4)]; } if (j < m_framesize/2){ holdbuffer2[j]=holdbuffer3[j+(m_framesize/4)]; } if (j < m_framesize*0.75){ holdbuffer3[j]=processedframe[j+(m_framesize/4)]; } } for (int i = 0; i<(m_framesize); i++) { prev_audioframe[i] = audioframe[i]; } } void TimeStretchFilter::getOutput(float **output, size_t samples) { if (samples > m_framesize/4) return; int channel = getSourceChannelCount(); for (int i=0; i<samples; i++){ output[0][i] = outbuffer[i]; if (channel > 1) output[1][i] = outbuffer[i]; } } size_t TimeStretchFilter::getRequiredInputSamples(size_t outputSamplesNeeded) { // max (m_framesize, outputSamplesNeeded*2) size_t need = max( floor(m_framesize*m_interpfactor + 1), outputSamplesNeeded*2); return need; }