DOSBox-X
|
00001 /* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher 00002 * Copyright (C) 2011, 2012, 2013 Dean Beeler, Jerome Fisher, Sergey V. Mikayev 00003 * 00004 * This program is free software: you can redistribute it and/or modify 00005 * it under the terms of the GNU Lesser General Public License as published by 00006 * the Free Software Foundation, either version 2.1 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public License 00015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 */ 00017 00018 #include "mt32emu.h" 00019 00020 #if MT32EMU_USE_REVERBMODEL == 1 00021 00022 #include "AReverbModel.h" 00023 00024 // Analysing of state of reverb RAM address lines gives exact sizes of the buffers of filters used. This also indicates that 00025 // the reverb model implemented in the real devices consists of three series allpass filters preceded by a non-feedback comb (or a delay with a LPF) 00026 // and followed by three parallel comb filters 00027 00028 namespace MT32Emu { 00029 00030 // Because LA-32 chip makes it's output available to process by the Boss chip with a significant delay, 00031 // the Boss chip puts to the buffer the LA32 dry output when it is ready and performs processing of the _previously_ latched data. 00032 // Of course, the right way would be to use a dedicated variable for this, but our reverb model is way higher level, 00033 // so we can simply increase the input buffer size. 00034 static const Bit32u PROCESS_DELAY = 1; 00035 00036 // Default reverb settings for modes 0-2. These correspond to CM-32L / LAPC-I "new" reverb settings. MT-32 reverb is a bit different. 00037 // Found by tracing reverb RAM data lines (thanks go to Lord_Nightmare & balrog). 00038 00039 static const Bit32u NUM_ALLPASSES = 3; 00040 static const Bit32u NUM_COMBS = 4; // Well, actually there are 3 comb filters, but the entrance LPF + delay can be perfectly processed via a comb here. 00041 00042 static const Bit32u MODE_0_ALLPASSES[] = {994, 729, 78}; 00043 static const Bit32u MODE_0_COMBS[] = {705 + PROCESS_DELAY, 2349, 2839, 3632}; 00044 static const Bit32u MODE_0_OUTL[] = {2349, 141, 1960}; 00045 static const Bit32u MODE_0_OUTR[] = {1174, 1570, 145}; 00046 static const Bit32u MODE_0_COMB_FACTOR[] = {0x3C, 0x60, 0x60, 0x60}; 00047 static const Bit32u MODE_0_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00048 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, 00049 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, 00050 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; 00051 static const Bit32u MODE_0_LEVELS[] = {10*1, 10*3, 10*5, 10*7, 11*9, 11*12, 11*15, 13*15}; 00052 static const Bit32u MODE_0_LPF_AMP = 6; 00053 00054 static const Bit32u MODE_1_ALLPASSES[] = {1324, 809, 176}; 00055 static const Bit32u MODE_1_COMBS[] = {961 + PROCESS_DELAY, 2619, 3545, 4519}; 00056 static const Bit32u MODE_1_OUTL[] = {2618, 1760, 4518}; 00057 static const Bit32u MODE_1_OUTR[] = {1300, 3532, 2274}; 00058 static const Bit32u MODE_1_COMB_FACTOR[] = {0x30, 0x60, 0x60, 0x60}; 00059 static const Bit32u MODE_1_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00060 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, 00061 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, 00062 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; 00063 static const Bit32u MODE_1_LEVELS[] = {10*1, 10*3, 11*5, 11*7, 11*9, 11*12, 11*15, 14*15}; 00064 static const Bit32u MODE_1_LPF_AMP = 6; 00065 00066 static const Bit32u MODE_2_ALLPASSES[] = {969, 644, 157}; 00067 static const Bit32u MODE_2_COMBS[] = {116 + PROCESS_DELAY, 2259, 2839, 3539}; 00068 static const Bit32u MODE_2_OUTL[] = {2259, 718, 1769}; 00069 static const Bit32u MODE_2_OUTR[] = {1136, 2128, 1}; 00070 static const Bit32u MODE_2_COMB_FACTOR[] = {0, 0x20, 0x20, 0x20}; 00071 static const Bit32u MODE_2_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00072 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0, 00073 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0, 00074 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0}; 00075 static const Bit32u MODE_2_LEVELS[] = {10*1, 10*3, 11*5, 11*7, 11*9, 11*12, 12*15, 14*15}; 00076 static const Bit32u MODE_2_LPF_AMP = 8; 00077 00078 static const AReverbSettings REVERB_MODE_0_SETTINGS = {MODE_0_ALLPASSES, MODE_0_COMBS, MODE_0_OUTL, MODE_0_OUTR, MODE_0_COMB_FACTOR, MODE_0_COMB_FEEDBACK, MODE_0_LEVELS, MODE_0_LPF_AMP}; 00079 static const AReverbSettings REVERB_MODE_1_SETTINGS = {MODE_1_ALLPASSES, MODE_1_COMBS, MODE_1_OUTL, MODE_1_OUTR, MODE_1_COMB_FACTOR, MODE_1_COMB_FEEDBACK, MODE_1_LEVELS, MODE_1_LPF_AMP}; 00080 static const AReverbSettings REVERB_MODE_2_SETTINGS = {MODE_2_ALLPASSES, MODE_2_COMBS, MODE_2_OUTL, MODE_2_OUTR, MODE_2_COMB_FACTOR, MODE_2_COMB_FEEDBACK, MODE_2_LEVELS, MODE_2_LPF_AMP}; 00081 00082 static const AReverbSettings * const REVERB_SETTINGS[] = {&REVERB_MODE_0_SETTINGS, &REVERB_MODE_1_SETTINGS, &REVERB_MODE_2_SETTINGS, &REVERB_MODE_0_SETTINGS}; 00083 00084 RingBuffer::RingBuffer(const Bit32u newsize) : size(newsize), index(0) { 00085 buffer = new float[size]; 00086 } 00087 00088 RingBuffer::~RingBuffer() { 00089 delete[] buffer; 00090 buffer = NULL; 00091 } 00092 00093 float RingBuffer::next() { 00094 if (++index >= size) { 00095 index = 0; 00096 } 00097 return buffer[index]; 00098 } 00099 00100 bool RingBuffer::isEmpty() const { 00101 if (buffer == NULL) return true; 00102 00103 float *buf = buffer; 00104 float max = 0.001f; 00105 for (Bit32u i = 0; i < size; i++) { 00106 if ((*buf < -max) || (*buf > max)) return false; 00107 buf++; 00108 } 00109 return true; 00110 } 00111 00112 void RingBuffer::mute() { 00113 float *buf = buffer; 00114 for (Bit32u i = 0; i < size; i++) { 00115 *buf++ = 0; 00116 } 00117 } 00118 00119 AllpassFilter::AllpassFilter(const Bit32u useSize) : RingBuffer(useSize) {} 00120 00121 float AllpassFilter::process(const float in) { 00122 // This model corresponds to the allpass filter implementation of the real CM-32L device 00123 // found from sample analysis 00124 00125 const float bufferOut = next(); 00126 00127 // store input - feedback / 2 00128 buffer[index] = in - 0.5f * bufferOut; 00129 00130 // return buffer output + feedforward / 2 00131 return bufferOut + 0.5f * buffer[index]; 00132 } 00133 00134 CombFilter::CombFilter(const Bit32u useSize) : RingBuffer(useSize), feedbackFactor(0.0F), filterFactor(0.0F) {} 00135 00136 void CombFilter::process(const float in) { 00137 // This model corresponds to the comb filter implementation of the real CM-32L device 00138 // found from sample analysis 00139 00140 // the previously stored value 00141 float last = buffer[index]; 00142 00143 // prepare input + feedback 00144 float filterIn = in + next() * feedbackFactor; 00145 00146 // store input + feedback processed by a low-pass filter 00147 buffer[index] = filterFactor * last - filterIn; 00148 } 00149 00150 float CombFilter::getOutputAt(const Bit32u outIndex) const { 00151 return buffer[(size + index - outIndex) % size]; 00152 } 00153 00154 void CombFilter::setFeedbackFactor(const float useFeedbackFactor) { 00155 feedbackFactor = useFeedbackFactor; 00156 } 00157 00158 void CombFilter::setFilterFactor(const float useFilterFactor) { 00159 filterFactor = useFilterFactor; 00160 } 00161 00162 AReverbModel::AReverbModel(const ReverbMode mode) : allpasses(NULL), combs(NULL), currentSettings(*REVERB_SETTINGS[mode]), lpfAmp(0.0F), wetLevel(0.0F) {} 00163 00164 AReverbModel::~AReverbModel() { 00165 AReverbModel::close(); 00166 } 00167 00168 void AReverbModel::open() { 00169 allpasses = new AllpassFilter*[NUM_ALLPASSES]; 00170 for (Bit32u i = 0; i < NUM_ALLPASSES; i++) { 00171 allpasses[i] = new AllpassFilter(currentSettings.allpassSizes[i]); 00172 } 00173 combs = new CombFilter*[NUM_COMBS]; 00174 for (Bit32u i = 0; i < NUM_COMBS; i++) { 00175 combs[i] = new CombFilter(currentSettings.combSizes[i]); 00176 combs[i]->setFilterFactor(currentSettings.filterFactor[i] / 256.0f); 00177 } 00178 lpfAmp = currentSettings.lpfAmp / 16.0f; 00179 mute(); 00180 } 00181 00182 void AReverbModel::close() { 00183 if (allpasses != NULL) { 00184 for (Bit32u i = 0; i < NUM_ALLPASSES; i++) { 00185 if (allpasses[i] != NULL) { 00186 delete allpasses[i]; 00187 allpasses[i] = NULL; 00188 } 00189 } 00190 delete[] allpasses; 00191 allpasses = NULL; 00192 } 00193 if (combs != NULL) { 00194 for (Bit32u i = 0; i < NUM_COMBS; i++) { 00195 if (combs[i] != NULL) { 00196 delete combs[i]; 00197 combs[i] = NULL; 00198 } 00199 } 00200 delete[] combs; 00201 combs = NULL; 00202 } 00203 } 00204 00205 void AReverbModel::mute() { 00206 if (allpasses == NULL || combs == NULL) return; 00207 for (Bit32u i = 0; i < NUM_ALLPASSES; i++) { 00208 allpasses[i]->mute(); 00209 } 00210 for (Bit32u i = 0; i < NUM_COMBS; i++) { 00211 combs[i]->mute(); 00212 } 00213 } 00214 00215 void AReverbModel::setParameters(Bit8u time, Bit8u level) { 00216 // FIXME: wetLevel definitely needs ramping when changed 00217 // Although, most games don't set reverb level during MIDI playback 00218 if (combs == NULL) return; 00219 level &= 7; 00220 time &= 7; 00221 for (Bit32u i = 0; i < NUM_COMBS; i++) { 00222 combs[i]->setFeedbackFactor(currentSettings.decayTimes[(i << 3) + time] / 256.0f); 00223 } 00224 wetLevel = (level == 0 && time == 0) ? 0.0f : 0.5f * lpfAmp * currentSettings.wetLevels[level] / 256.0f; 00225 } 00226 00227 bool AReverbModel::isActive() const { 00228 for (Bit32u i = 0; i < NUM_ALLPASSES; i++) { 00229 if (!allpasses[i]->isEmpty()) return true; 00230 } 00231 for (Bit32u i = 0; i < NUM_COMBS; i++) { 00232 if (!combs[i]->isEmpty()) return true; 00233 } 00234 return false; 00235 } 00236 00237 void AReverbModel::process(const float *inLeft, const float *inRight, float *outLeft, float *outRight, unsigned long numSamples) { 00238 for (unsigned long i = 0; i < numSamples; i++) { 00239 float dry = wetLevel * (*inLeft + *inRight); 00240 00241 // Get the last stored sample before processing in order not to loose it 00242 float link = combs[0]->getOutputAt(currentSettings.combSizes[0] - 1); 00243 00244 combs[0]->process(-dry); 00245 00246 link = allpasses[0]->process(link); 00247 link = allpasses[1]->process(link); 00248 link = allpasses[2]->process(link); 00249 00250 // If the output position is equal to the comb size, get it now in order not to loose it 00251 float outL1 = 1.5f * combs[1]->getOutputAt(currentSettings.outLPositions[0] - 1); 00252 00253 combs[1]->process(link); 00254 combs[2]->process(link); 00255 combs[3]->process(link); 00256 00257 link = outL1 + 1.5f * combs[2]->getOutputAt(currentSettings.outLPositions[1]); 00258 link += combs[3]->getOutputAt(currentSettings.outLPositions[2]); 00259 *outLeft = link; 00260 00261 link = 1.5f * combs[1]->getOutputAt(currentSettings.outRPositions[0]); 00262 link += 1.5f * combs[2]->getOutputAt(currentSettings.outRPositions[1]); 00263 link += combs[3]->getOutputAt(currentSettings.outRPositions[2]); 00264 *outRight = link; 00265 00266 inLeft++; 00267 inRight++; 00268 outLeft++; 00269 outRight++; 00270 } 00271 } 00272 00273 } 00274 00275 #endif