DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/mt32/freeverb/revmodel.cpp
00001 // Reverb model implementation
00002 //
00003 // Written by Jezar at Dreampoint, June 2000
00004 // Modifications by Jerome Fisher, 2009, 2011
00005 // http://www.dreampoint.co.uk
00006 // This code is public domain
00007 
00008 #include "revmodel.h"
00009 
00010 revmodel::revmodel(float scaletuning)
00011 {
00012         int i;
00013         int bufsize;
00014 
00015         // Allocate buffers for the components
00016         for (i = 0; i < numcombs; i++) {
00017                 bufsize = int(scaletuning * combtuning[i]);
00018                 combL[i].setbuffer(new float[bufsize], bufsize);
00019                 bufsize += int(scaletuning * stereospread);
00020                 combR[i].setbuffer(new float[bufsize], bufsize);
00021         }
00022         for (i = 0; i < numallpasses; i++) {
00023                 bufsize = int(scaletuning * allpasstuning[i]);
00024                 allpassL[i].setbuffer(new float[bufsize], bufsize);
00025                 allpassL[i].setfeedback(0.5f);
00026                 bufsize += int(scaletuning * stereospread);
00027                 allpassR[i].setbuffer(new float[bufsize], bufsize);
00028                 allpassR[i].setfeedback(0.5f);
00029         }
00030 
00031         // Set default values
00032         dry = initialdry;
00033         wet = initialwet*scalewet;
00034         damp = initialdamp*scaledamp;
00035         roomsize = (initialroom*scaleroom) + offsetroom;
00036         width = initialwidth;
00037         mode = initialmode;
00038     filtval = 0;
00039         update();
00040 
00041         // Buffer will be full of rubbish - so we MUST mute them
00042         mute();
00043 }
00044 
00045 revmodel::~revmodel()
00046 {
00047         int i;
00048 
00049         for (i = 0; i < numcombs; i++) {
00050                 combL[i].deletebuffer();
00051                 combR[i].deletebuffer();
00052         }
00053         for (i = 0; i < numallpasses; i++) {
00054                 allpassL[i].deletebuffer();
00055                 allpassR[i].deletebuffer();
00056         }
00057 }
00058 
00059 void revmodel::mute()
00060 {
00061         int i;
00062 
00063         if (getmode() >= freezemode)
00064                 return;
00065 
00066         for (i=0;i<numcombs;i++)
00067         {
00068                 combL[i].mute();
00069                 combR[i].mute();
00070         }
00071         for (i=0;i<numallpasses;i++)
00072         {
00073                 allpassL[i].mute();
00074                 allpassR[i].mute();
00075         }
00076 
00077         // Init LPF history
00078         filtprev1 = 0;
00079         filtprev2 = 0;
00080 }
00081 
00082 void revmodel::process(const float *inputL, const float *inputR, float *outputL, float *outputR, long numsamples)
00083 {
00084         while (numsamples-- > 0)
00085         {
00086                 int i;
00087 
00088                 float outL = 0;
00089                 float outR = 0;
00090                 float input = (*inputL + *inputR) * gain;
00091 
00092                 // Implementation of 2-stage IIR single-pole low-pass filter
00093                 // found at the entrance of reverb processing on real devices
00094                 filtprev1 += (input - filtprev1) * filtval;
00095                 filtprev2 += (filtprev1 - filtprev2) * filtval;
00096                 input = filtprev2;
00097 
00098                 int s = -1;
00099                 // Accumulate comb filters in parallel
00100                 for (i=0; i<numcombs; i++)
00101                 {
00102                         outL += s * combL[i].process(input);
00103                         outR += s * combR[i].process(input);
00104                         s = -s;
00105                 }
00106 
00107                 // Feed through allpasses in series
00108                 for (i=0; i<numallpasses; i++)
00109                 {
00110                         outL = allpassL[i].process(outL);
00111                         outR = allpassR[i].process(outR);
00112                 }
00113 
00114                 // Calculate output REPLACING anything already there
00115                 *outputL = outL*wet1 + outR*wet2;
00116                 *outputR = outR*wet1 + outL*wet2;
00117                 
00118                 inputL++;
00119                 inputR++;
00120                 outputL++;
00121                 outputR++;
00122         }
00123 }
00124 
00125 void revmodel::update()
00126 {
00127 // Recalculate internal values after parameter change
00128 
00129         int i;
00130 
00131         wet1 = wet*(width/2 + 0.5f);
00132         wet2 = wet*((1-width)/2);
00133 
00134         if (mode >= freezemode)
00135         {
00136                 roomsize1 = 1;
00137                 damp1 = 0;
00138                 gain = muted;
00139         }
00140         else
00141         {
00142                 roomsize1 = roomsize;
00143                 damp1 = damp;
00144                 gain = fixedgain;
00145         }
00146 
00147         for (i=0; i<numcombs; i++)
00148         {
00149                 combL[i].setfeedback(roomsize1);
00150                 combR[i].setfeedback(roomsize1);
00151         }
00152 
00153         for (i=0; i<numcombs; i++)
00154         {
00155                 combL[i].setdamp(damp1);
00156                 combR[i].setdamp(damp1);
00157         }
00158 }
00159 
00160 // The following get/set functions are not inlined, because
00161 // speed is never an issue when calling them, and also
00162 // because as you develop the reverb model, you may
00163 // wish to take dynamic action when they are called.
00164 
00165 void revmodel::setroomsize(float value)
00166 {
00167         roomsize = (value*scaleroom) + offsetroom;
00168         update();
00169 }
00170 
00171 float revmodel::getroomsize()
00172 {
00173         return (roomsize-offsetroom)/scaleroom;
00174 }
00175 
00176 void revmodel::setdamp(float value)
00177 {
00178         damp = value*scaledamp;
00179         update();
00180 }
00181 
00182 float revmodel::getdamp()
00183 {
00184         return damp/scaledamp;
00185 }
00186 
00187 void revmodel::setwet(float value)
00188 {
00189         wet = value*scalewet;
00190         update();
00191 }
00192 
00193 float revmodel::getwet()
00194 {
00195         return wet/scalewet;
00196 }
00197 
00198 void revmodel::setdry(float value)
00199 {
00200         dry = value*scaledry;
00201 }
00202 
00203 float revmodel::getdry()
00204 {
00205         return dry/scaledry;
00206 }
00207 
00208 void revmodel::setwidth(float value)
00209 {
00210         width = value;
00211         update();
00212 }
00213 
00214 float revmodel::getwidth()
00215 {
00216         return width;
00217 }
00218 
00219 void revmodel::setmode(float value)
00220 {
00221         mode = value;
00222         update();
00223 }
00224 
00225 float revmodel::getmode()
00226 {
00227         if (mode >= freezemode)
00228                 return 1;
00229         else
00230                 return 0;
00231 }
00232 
00233 void revmodel::setfiltval(float value)
00234 {
00235         filtval = value;
00236 }
00237 
00238 
00239 void revmodel::saveState( std::ostream &stream )
00240 {
00241         stream.write(reinterpret_cast<const char*>(&gain), sizeof(gain) );
00242         stream.write(reinterpret_cast<const char*>(&roomsize), sizeof(roomsize) );
00243         stream.write(reinterpret_cast<const char*>(&roomsize1), sizeof(roomsize1) );
00244         stream.write(reinterpret_cast<const char*>(&damp), sizeof(damp) );
00245         stream.write(reinterpret_cast<const char*>(&damp1), sizeof(damp1) );
00246         stream.write(reinterpret_cast<const char*>(&wet), sizeof(wet) );
00247         stream.write(reinterpret_cast<const char*>(&wet1), sizeof(wet1) );
00248         stream.write(reinterpret_cast<const char*>(&wet2), sizeof(wet2) );
00249         stream.write(reinterpret_cast<const char*>(&dry), sizeof(dry) );
00250         stream.write(reinterpret_cast<const char*>(&width), sizeof(width) );
00251         stream.write(reinterpret_cast<const char*>(&mode), sizeof(mode) );
00252         stream.write(reinterpret_cast<const char*>(&filtval), sizeof(filtval) );
00253         stream.write(reinterpret_cast<const char*>(&filtprev1), sizeof(filtprev1) );
00254         stream.write(reinterpret_cast<const char*>(&filtprev2), sizeof(filtprev2) );
00255 
00256 
00257         for( int lcv=0; lcv<numcombs; lcv++ ) {
00258                 combL[lcv].saveState(stream);
00259                 combR[lcv].saveState(stream);
00260         }
00261 
00262         for( int lcv=0; lcv<numallpasses; lcv++ ) {
00263                 allpassL[lcv].saveState(stream);
00264                 allpassR[lcv].saveState(stream);
00265         }
00266 }
00267 
00268 
00269 void revmodel::loadState( std::istream &stream )
00270 {
00271         stream.read(reinterpret_cast<char*>(&gain), sizeof(gain) );
00272         stream.read(reinterpret_cast<char*>(&roomsize), sizeof(roomsize) );
00273         stream.read(reinterpret_cast<char*>(&roomsize1), sizeof(roomsize1) );
00274         stream.read(reinterpret_cast<char*>(&damp), sizeof(damp) );
00275         stream.read(reinterpret_cast<char*>(&damp1), sizeof(damp1) );
00276         stream.read(reinterpret_cast<char*>(&wet), sizeof(wet) );
00277         stream.read(reinterpret_cast<char*>(&wet1), sizeof(wet1) );
00278         stream.read(reinterpret_cast<char*>(&wet2), sizeof(wet2) );
00279         stream.read(reinterpret_cast<char*>(&dry), sizeof(dry) );
00280         stream.read(reinterpret_cast<char*>(&width), sizeof(width) );
00281         stream.read(reinterpret_cast<char*>(&mode), sizeof(mode) );
00282         stream.read(reinterpret_cast<char*>(&filtval), sizeof(filtval) );
00283         stream.read(reinterpret_cast<char*>(&filtprev1), sizeof(filtprev1) );
00284         stream.read(reinterpret_cast<char*>(&filtprev2), sizeof(filtprev2) );
00285 
00286 
00287         for( int lcv=0; lcv<numcombs; lcv++ ) {
00288                 combL[lcv].loadState(stream);
00289                 combR[lcv].loadState(stream);
00290         }
00291 
00292         for( int lcv=0; lcv<numallpasses; lcv++ ) {
00293                 allpassL[lcv].loadState(stream);
00294                 allpassR[lcv].loadState(stream);
00295         }
00296 }