![]() |
Mixxx
|
00001 /*************************************************************************** 00002 engineflanger.cpp - description 00003 ------------------- 00004 copyright : (C) 2002 by Tue and Ken Haste Andersen 00005 email : 00006 ***************************************************************************/ 00007 00008 /*************************************************************************** 00009 * * 00010 * This program is free software; you can redistribute it and/or modify * 00011 * it under the terms of the GNU General Public License as published by * 00012 * the Free Software Foundation; either version 2 of the License, or * 00013 * (at your option) any later version. * 00014 * * 00015 ***************************************************************************/ 00016 00017 #include <QtDebug> 00018 00019 #include "controlpushbutton.h" 00020 #include "controlpotmeter.h" 00021 #include "engineflanger.h" 00022 #include "mathstuff.h" 00023 #include "sampleutil.h" 00024 00025 00026 /*---------------------------------------------------------------- 00027 A flanger effect. 00028 The flanger is controlled by the following variables: 00029 average_delay_length - The average length of the delay, which is modulated by the LFO. 00030 LFOperiod - the period of LFO given in samples. 00031 LFOamplitude - the amplitude of the modulation of the delay length. 00032 depth - the depth of the flanger, controlled by a ControlPotmeter. 00033 ----------------------------------------------------------------*/ 00034 EngineFlanger::EngineFlanger(const char * group) 00035 { 00036 // Init. buffers: 00037 delay_buffer = SampleUtil::alloc(max_delay + 1); 00038 SampleUtil::applyGain(delay_buffer, 0.0f, max_delay+1); 00039 00040 // Init. potmeters 00041 00042 // rryan 6/2010 This is gross. The flanger was originally written as this 00043 // hack that hard-coded the two channels, and while pulling it apart, I have 00044 // to keep these global [Flanger]-group controls, except there is one 00045 // EngineFlanger per deck, so create these controls if they don't exist, 00046 // otherwise look them up. 00047 00048 potmeterDepth = ControlObject::getControl(ConfigKey("[Flanger]", "lfoDepth")); 00049 potmeterDelay = ControlObject::getControl(ConfigKey("[Flanger]", "lfoDelay")); 00050 potmeterLFOperiod = ControlObject::getControl(ConfigKey("[Flanger]", "lfoPeriod")); 00051 00052 if (potmeterDepth == NULL) 00053 potmeterDepth = new ControlPotmeter(ConfigKey("[Flanger]", "lfoDepth"), 0., 1.); 00054 if (potmeterDelay == NULL) 00055 potmeterDelay = new ControlPotmeter(ConfigKey("[Flanger]", "lfoDelay"), 50., 10000.); 00056 if (potmeterLFOperiod == NULL) 00057 potmeterLFOperiod = new ControlPotmeter(ConfigKey("[Flanger]", "lfoPeriod"), 50000., 2000000.); 00058 00059 // Create an enable key on a per-deck basis. 00060 flangerEnable = new ControlPushButton(ConfigKey(group, "flanger")); 00061 flangerEnable->setToggleButton(true); 00062 00063 // Fixed values of controls: 00064 LFOamplitude = 240; 00065 average_delay_length = 250; 00066 00067 // Set initial values for vars 00068 delay_pos=0; 00069 time = 0; 00070 } 00071 00072 EngineFlanger::~EngineFlanger() 00073 { 00074 // Don't delete the controls anymore since we don't know if we created them. 00075 // delete potmeterDepth; 00076 // delete potmeterDelay; 00077 // delete potmeterLFOperiod; 00078 00079 delete flangerEnable; 00080 00081 SampleUtil::free(delay_buffer); 00082 } 00083 00084 void EngineFlanger::process(const CSAMPLE * pIn, const CSAMPLE * pOut, const int iBufferSize) 00085 { 00086 CSAMPLE * pOutput = (CSAMPLE *)pOut; 00087 CSAMPLE delayed_sample,prev,next; 00088 FLOAT_TYPE frac; 00089 00090 if (flangerEnable->get() == 0.0f) { 00091 // SampleUtil handles shortcuts when aliased, and gains of 1.0, etc. 00092 return SampleUtil::copyWithGain(pOutput, pIn, 1.0f, iBufferSize); 00093 } 00094 00095 for (int i=0; i<iBufferSize; ++i) 00096 { 00097 // put sample into delay buffer: 00098 delay_buffer[delay_pos] = pIn[i]; 00099 delay_pos++; 00100 if (delay_pos >= max_delay) 00101 delay_pos=0; 00102 00103 // Update the LFO to find the current delay: 00104 time++; 00105 if (time==potmeterLFOperiod->get()) time=0; 00106 delay = average_delay_length + LFOamplitude *sin( two_pi * ((FLOAT_TYPE) time)/((FLOAT_TYPE) potmeterLFOperiod->get()) ); 00107 00108 // Make a linear interpolation to find the delayed sample: 00109 prev = delay_buffer[(delay_pos-(int)delay+max_delay-1) % max_delay]; 00110 next = delay_buffer[(delay_pos-(int)delay+max_delay) % max_delay]; 00111 frac = delay - floor(delay); 00112 delayed_sample = prev + frac*(next-prev); 00113 00114 // Take the sample from the delay buffer and mix it with the source buffer: 00115 pOutput[i] = pIn[i] + potmeterDepth->get()*delayed_sample; 00116 } 00117 }