diff options
author | Filippos Karapetis | 2014-07-07 22:33:12 +0300 |
---|---|---|
committer | Filippos Karapetis | 2014-07-08 00:02:18 +0300 |
commit | 8c5f67568f1a320134d73c2efe41ff57dfdc1fdd (patch) | |
tree | 0e938c157af6a7b285e14e5f1cd7108f64fe90bb /audio/softsynth/mt32/BReverbModel.cpp | |
parent | 10c7986a36d0fadfc2373c8b8728855dcf8a4cad (diff) | |
download | scummvm-rg350-8c5f67568f1a320134d73c2efe41ff57dfdc1fdd.tar.gz scummvm-rg350-8c5f67568f1a320134d73c2efe41ff57dfdc1fdd.tar.bz2 scummvm-rg350-8c5f67568f1a320134d73c2efe41ff57dfdc1fdd.zip |
MT32: Update to munt 1.4.0
This syncs with munt commit 175446af43
Diffstat (limited to 'audio/softsynth/mt32/BReverbModel.cpp')
-rw-r--r-- | audio/softsynth/mt32/BReverbModel.cpp | 312 |
1 files changed, 209 insertions, 103 deletions
diff --git a/audio/softsynth/mt32/BReverbModel.cpp b/audio/softsynth/mt32/BReverbModel.cpp index 38cc592c95..37b3e9670d 100644 --- a/audio/softsynth/mt32/BReverbModel.cpp +++ b/audio/softsynth/mt32/BReverbModel.cpp @@ -34,70 +34,143 @@ static const Bit32u PROCESS_DELAY = 1; static const Bit32u MODE_3_ADDITIONAL_DELAY = 1; static const Bit32u MODE_3_FEEDBACK_DELAY = 1; -// Default reverb settings for modes 0-2. These correspond to CM-32L / LAPC-I "new" reverb settings. MT-32 reverb is a bit different. +// Default reverb settings for "new" reverb model implemented in CM-32L / LAPC-I. // Found by tracing reverb RAM data lines (thanks go to Lord_Nightmare & balrog). +const BReverbSettings &BReverbModel::getCM32L_LAPCSettings(const ReverbMode mode) { + static const Bit32u MODE_0_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_0_ALLPASSES[] = {994, 729, 78}; + static const Bit32u MODE_0_NUMBER_OF_COMBS = 4; // Well, actually there are 3 comb filters, but the entrance LPF + delay can be processed via a hacked comb. + static const Bit32u MODE_0_COMBS[] = {705 + PROCESS_DELAY, 2349, 2839, 3632}; + static const Bit32u MODE_0_OUTL[] = {2349, 141, 1960}; + static const Bit32u MODE_0_OUTR[] = {1174, 1570, 145}; + static const Bit32u MODE_0_COMB_FACTOR[] = {0xA0, 0x60, 0x60, 0x60}; + static const Bit32u MODE_0_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; + static const Bit32u MODE_0_DRY_AMP[] = {0xA0, 0xA0, 0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xD0}; + static const Bit32u MODE_0_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0}; + static const Bit32u MODE_0_LPF_AMP = 0x60; + + static const Bit32u MODE_1_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_1_ALLPASSES[] = {1324, 809, 176}; + static const Bit32u MODE_1_NUMBER_OF_COMBS = 4; // Same as for mode 0 above + static const Bit32u MODE_1_COMBS[] = {961 + PROCESS_DELAY, 2619, 3545, 4519}; + static const Bit32u MODE_1_OUTL[] = {2618, 1760, 4518}; + static const Bit32u MODE_1_OUTR[] = {1300, 3532, 2274}; + static const Bit32u MODE_1_COMB_FACTOR[] = {0x80, 0x60, 0x60, 0x60}; + static const Bit32u MODE_1_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; + static const Bit32u MODE_1_DRY_AMP[] = {0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xE0}; + static const Bit32u MODE_1_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0}; + static const Bit32u MODE_1_LPF_AMP = 0x60; + + static const Bit32u MODE_2_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_2_ALLPASSES[] = {969, 644, 157}; + static const Bit32u MODE_2_NUMBER_OF_COMBS = 4; // Same as for mode 0 above + static const Bit32u MODE_2_COMBS[] = {116 + PROCESS_DELAY, 2259, 2839, 3539}; + static const Bit32u MODE_2_OUTL[] = {2259, 718, 1769}; + static const Bit32u MODE_2_OUTR[] = {1136, 2128, 1}; + static const Bit32u MODE_2_COMB_FACTOR[] = {0, 0x20, 0x20, 0x20}; + static const Bit32u MODE_2_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0, + 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0, + 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0}; + static const Bit32u MODE_2_DRY_AMP[] = {0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xB0, 0xC0, 0xE0}; + static const Bit32u MODE_2_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0}; + static const Bit32u MODE_2_LPF_AMP = 0x80; + + static const Bit32u MODE_3_NUMBER_OF_ALLPASSES = 0; + static const Bit32u MODE_3_NUMBER_OF_COMBS = 1; + static const Bit32u MODE_3_DELAY[] = {16000 + MODE_3_FEEDBACK_DELAY + PROCESS_DELAY + MODE_3_ADDITIONAL_DELAY}; + static const Bit32u MODE_3_OUTL[] = {400, 624, 960, 1488, 2256, 3472, 5280, 8000}; + static const Bit32u MODE_3_OUTR[] = {800, 1248, 1920, 2976, 4512, 6944, 10560, 16000}; + static const Bit32u MODE_3_COMB_FACTOR[] = {0x68}; + static const Bit32u MODE_3_COMB_FEEDBACK[] = {0x68, 0x60}; + static const Bit32u MODE_3_DRY_AMP[] = {0x20, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x20, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50}; + static const Bit32u MODE_3_WET_AMP[] = {0x18, 0x18, 0x28, 0x40, 0x60, 0x80, 0xA8, 0xF8}; + + static const BReverbSettings REVERB_MODE_0_SETTINGS = {MODE_0_NUMBER_OF_ALLPASSES, MODE_0_ALLPASSES, MODE_0_NUMBER_OF_COMBS, MODE_0_COMBS, MODE_0_OUTL, MODE_0_OUTR, MODE_0_COMB_FACTOR, MODE_0_COMB_FEEDBACK, MODE_0_DRY_AMP, MODE_0_WET_AMP, MODE_0_LPF_AMP}; + static const BReverbSettings REVERB_MODE_1_SETTINGS = {MODE_1_NUMBER_OF_ALLPASSES, MODE_1_ALLPASSES, MODE_1_NUMBER_OF_COMBS, MODE_1_COMBS, MODE_1_OUTL, MODE_1_OUTR, MODE_1_COMB_FACTOR, MODE_1_COMB_FEEDBACK, MODE_1_DRY_AMP, MODE_1_WET_AMP, MODE_1_LPF_AMP}; + static const BReverbSettings REVERB_MODE_2_SETTINGS = {MODE_2_NUMBER_OF_ALLPASSES, MODE_2_ALLPASSES, MODE_2_NUMBER_OF_COMBS, MODE_2_COMBS, MODE_2_OUTL, MODE_2_OUTR, MODE_2_COMB_FACTOR, MODE_2_COMB_FEEDBACK, MODE_2_DRY_AMP, MODE_2_WET_AMP, MODE_2_LPF_AMP}; + static const BReverbSettings REVERB_MODE_3_SETTINGS = {MODE_3_NUMBER_OF_ALLPASSES, NULL, MODE_3_NUMBER_OF_COMBS, MODE_3_DELAY, MODE_3_OUTL, MODE_3_OUTR, MODE_3_COMB_FACTOR, MODE_3_COMB_FEEDBACK, MODE_3_DRY_AMP, MODE_3_WET_AMP, 0}; + + static const BReverbSettings * const REVERB_SETTINGS[] = {&REVERB_MODE_0_SETTINGS, &REVERB_MODE_1_SETTINGS, &REVERB_MODE_2_SETTINGS, &REVERB_MODE_3_SETTINGS}; + + return *REVERB_SETTINGS[mode]; +} -static const Bit32u MODE_0_NUMBER_OF_ALLPASSES = 3; -static const Bit32u MODE_0_ALLPASSES[] = {994, 729, 78}; -static const Bit32u MODE_0_NUMBER_OF_COMBS = 4; // Well, actually there are 3 comb filters, but the entrance LPF + delay can be processed via a hacked comb. -static const Bit32u MODE_0_COMBS[] = {705 + PROCESS_DELAY, 2349, 2839, 3632}; -static const Bit32u MODE_0_OUTL[] = {2349, 141, 1960}; -static const Bit32u MODE_0_OUTR[] = {1174, 1570, 145}; -static const Bit32u MODE_0_COMB_FACTOR[] = {0xA0, 0x60, 0x60, 0x60}; -static const Bit32u MODE_0_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, - 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, - 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; -static const Bit32u MODE_0_DRY_AMP[] = {0xA0, 0xA0, 0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xD0}; -static const Bit32u MODE_0_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0}; -static const Bit32u MODE_0_LPF_AMP = 0x60; - -static const Bit32u MODE_1_NUMBER_OF_ALLPASSES = 3; -static const Bit32u MODE_1_ALLPASSES[] = {1324, 809, 176}; -static const Bit32u MODE_1_NUMBER_OF_COMBS = 4; // Same as for mode 0 above -static const Bit32u MODE_1_COMBS[] = {961 + PROCESS_DELAY, 2619, 3545, 4519}; -static const Bit32u MODE_1_OUTL[] = {2618, 1760, 4518}; -static const Bit32u MODE_1_OUTR[] = {1300, 3532, 2274}; -static const Bit32u MODE_1_COMB_FACTOR[] = {0x80, 0x60, 0x60, 0x60}; -static const Bit32u MODE_1_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, - 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, - 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; -static const Bit32u MODE_1_DRY_AMP[] = {0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xE0}; -static const Bit32u MODE_1_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0}; -static const Bit32u MODE_1_LPF_AMP = 0x60; - -static const Bit32u MODE_2_NUMBER_OF_ALLPASSES = 3; -static const Bit32u MODE_2_ALLPASSES[] = {969, 644, 157}; -static const Bit32u MODE_2_NUMBER_OF_COMBS = 4; // Same as for mode 0 above -static const Bit32u MODE_2_COMBS[] = {116 + PROCESS_DELAY, 2259, 2839, 3539}; -static const Bit32u MODE_2_OUTL[] = {2259, 718, 1769}; -static const Bit32u MODE_2_OUTR[] = {1136, 2128, 1}; -static const Bit32u MODE_2_COMB_FACTOR[] = {0, 0x20, 0x20, 0x20}; -static const Bit32u MODE_2_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0, - 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0, - 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0}; -static const Bit32u MODE_2_DRY_AMP[] = {0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xB0, 0xC0, 0xE0}; -static const Bit32u MODE_2_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0}; -static const Bit32u MODE_2_LPF_AMP = 0x80; - -static const Bit32u MODE_3_NUMBER_OF_ALLPASSES = 0; -static const Bit32u MODE_3_NUMBER_OF_COMBS = 1; -static const Bit32u MODE_3_DELAY[] = {16000 + MODE_3_FEEDBACK_DELAY + PROCESS_DELAY + MODE_3_ADDITIONAL_DELAY}; -static const Bit32u MODE_3_OUTL[] = {400, 624, 960, 1488, 2256, 3472, 5280, 8000}; -static const Bit32u MODE_3_OUTR[] = {800, 1248, 1920, 2976, 4512, 6944, 10560, 16000}; -static const Bit32u MODE_3_COMB_FACTOR[] = {0x68}; -static const Bit32u MODE_3_COMB_FEEDBACK[] = {0x68, 0x60}; -static const Bit32u MODE_3_DRY_AMP[] = {0x20, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50}; -static const Bit32u MODE_3_WET_AMP[] = {0x18, 0x18, 0x28, 0x40, 0x60, 0x80, 0xA8, 0xF8}; - -static const BReverbSettings REVERB_MODE_0_SETTINGS = {MODE_0_NUMBER_OF_ALLPASSES, MODE_0_ALLPASSES, MODE_0_NUMBER_OF_COMBS, MODE_0_COMBS, MODE_0_OUTL, MODE_0_OUTR, MODE_0_COMB_FACTOR, MODE_0_COMB_FEEDBACK, MODE_0_DRY_AMP, MODE_0_WET_AMP, MODE_0_LPF_AMP}; -static const BReverbSettings REVERB_MODE_1_SETTINGS = {MODE_1_NUMBER_OF_ALLPASSES, MODE_1_ALLPASSES, MODE_1_NUMBER_OF_COMBS, MODE_1_COMBS, MODE_1_OUTL, MODE_1_OUTR, MODE_1_COMB_FACTOR, MODE_1_COMB_FEEDBACK, MODE_1_DRY_AMP, MODE_1_WET_AMP, MODE_1_LPF_AMP}; -static const BReverbSettings REVERB_MODE_2_SETTINGS = {MODE_2_NUMBER_OF_ALLPASSES, MODE_2_ALLPASSES, MODE_2_NUMBER_OF_COMBS, MODE_2_COMBS, MODE_2_OUTL, MODE_2_OUTR, MODE_2_COMB_FACTOR, MODE_2_COMB_FEEDBACK, MODE_2_DRY_AMP, MODE_2_WET_AMP, MODE_2_LPF_AMP}; -static const BReverbSettings REVERB_MODE_3_SETTINGS = {MODE_3_NUMBER_OF_ALLPASSES, NULL, MODE_3_NUMBER_OF_COMBS, MODE_3_DELAY, MODE_3_OUTL, MODE_3_OUTR, MODE_3_COMB_FACTOR, MODE_3_COMB_FEEDBACK, MODE_3_DRY_AMP, MODE_3_WET_AMP, 0}; - -static const BReverbSettings * const REVERB_SETTINGS[] = {&REVERB_MODE_0_SETTINGS, &REVERB_MODE_1_SETTINGS, &REVERB_MODE_2_SETTINGS, &REVERB_MODE_3_SETTINGS}; +// Default reverb settings for "old" reverb model implemented in MT-32. +// Found by tracing reverb RAM data lines (thanks go to Lord_Nightmare & balrog). +const BReverbSettings &BReverbModel::getMT32Settings(const ReverbMode mode) { + static const Bit32u MODE_0_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_0_ALLPASSES[] = {994, 729, 78}; + static const Bit32u MODE_0_NUMBER_OF_COMBS = 4; // Same as above in the new model implementation + static const Bit32u MODE_0_COMBS[] = {575 + PROCESS_DELAY, 2040, 2752, 3629}; + static const Bit32u MODE_0_OUTL[] = {2040, 687, 1814}; + static const Bit32u MODE_0_OUTR[] = {1019, 2072, 1}; + static const Bit32u MODE_0_COMB_FACTOR[] = {0xB0, 0x60, 0x60, 0x60}; + static const Bit32u MODE_0_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; + static const Bit32u MODE_0_DRY_AMP[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; + static const Bit32u MODE_0_WET_AMP[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x70, 0xA0, 0xE0}; + static const Bit32u MODE_0_LPF_AMP = 0x80; + + static const Bit32u MODE_1_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_1_ALLPASSES[] = {1324, 809, 176}; + static const Bit32u MODE_1_NUMBER_OF_COMBS = 4; // Same as above in the new model implementation + static const Bit32u MODE_1_COMBS[] = {961 + PROCESS_DELAY, 2619, 3545, 4519}; + static const Bit32u MODE_1_OUTL[] = {2618, 1760, 4518}; + static const Bit32u MODE_1_OUTR[] = {1300, 3532, 2274}; + static const Bit32u MODE_1_COMB_FACTOR[] = {0x90, 0x60, 0x60, 0x60}; + static const Bit32u MODE_1_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; + static const Bit32u MODE_1_DRY_AMP[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; + static const Bit32u MODE_1_WET_AMP[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x70, 0xA0, 0xE0}; + static const Bit32u MODE_1_LPF_AMP = 0x80; + + static const Bit32u MODE_2_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_2_ALLPASSES[] = {969, 644, 157}; + static const Bit32u MODE_2_NUMBER_OF_COMBS = 4; // Same as above in the new model implementation + static const Bit32u MODE_2_COMBS[] = {116 + PROCESS_DELAY, 2259, 2839, 3539}; + static const Bit32u MODE_2_OUTL[] = {2259, 718, 1769}; + static const Bit32u MODE_2_OUTR[] = {1136, 2128, 1}; + static const Bit32u MODE_2_COMB_FACTOR[] = {0, 0x60, 0x60, 0x60}; + static const Bit32u MODE_2_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; + static const Bit32u MODE_2_DRY_AMP[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; + static const Bit32u MODE_2_WET_AMP[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x70, 0xA0, 0xE0}; + static const Bit32u MODE_2_LPF_AMP = 0x80; + + static const Bit32u MODE_3_NUMBER_OF_ALLPASSES = 0; + static const Bit32u MODE_3_NUMBER_OF_COMBS = 1; + static const Bit32u MODE_3_DELAY[] = {16000 + MODE_3_FEEDBACK_DELAY + PROCESS_DELAY + MODE_3_ADDITIONAL_DELAY}; + static const Bit32u MODE_3_OUTL[] = {400, 624, 960, 1488, 2256, 3472, 5280, 8000}; + static const Bit32u MODE_3_OUTR[] = {800, 1248, 1920, 2976, 4512, 6944, 10560, 16000}; + static const Bit32u MODE_3_COMB_FACTOR[] = {0x68}; + static const Bit32u MODE_3_COMB_FEEDBACK[] = {0x68, 0x60}; + static const Bit32u MODE_3_DRY_AMP[] = {0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x10, 0x20, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10}; + static const Bit32u MODE_3_WET_AMP[] = {0x08, 0x18, 0x28, 0x40, 0x60, 0x80, 0xA8, 0xF8}; + + static const BReverbSettings REVERB_MODE_0_SETTINGS = {MODE_0_NUMBER_OF_ALLPASSES, MODE_0_ALLPASSES, MODE_0_NUMBER_OF_COMBS, MODE_0_COMBS, MODE_0_OUTL, MODE_0_OUTR, MODE_0_COMB_FACTOR, MODE_0_COMB_FEEDBACK, MODE_0_DRY_AMP, MODE_0_WET_AMP, MODE_0_LPF_AMP}; + static const BReverbSettings REVERB_MODE_1_SETTINGS = {MODE_1_NUMBER_OF_ALLPASSES, MODE_1_ALLPASSES, MODE_1_NUMBER_OF_COMBS, MODE_1_COMBS, MODE_1_OUTL, MODE_1_OUTR, MODE_1_COMB_FACTOR, MODE_1_COMB_FEEDBACK, MODE_1_DRY_AMP, MODE_1_WET_AMP, MODE_1_LPF_AMP}; + static const BReverbSettings REVERB_MODE_2_SETTINGS = {MODE_2_NUMBER_OF_ALLPASSES, MODE_2_ALLPASSES, MODE_2_NUMBER_OF_COMBS, MODE_2_COMBS, MODE_2_OUTL, MODE_2_OUTR, MODE_2_COMB_FACTOR, MODE_2_COMB_FEEDBACK, MODE_2_DRY_AMP, MODE_2_WET_AMP, MODE_2_LPF_AMP}; + static const BReverbSettings REVERB_MODE_3_SETTINGS = {MODE_3_NUMBER_OF_ALLPASSES, NULL, MODE_3_NUMBER_OF_COMBS, MODE_3_DELAY, MODE_3_OUTL, MODE_3_OUTR, MODE_3_COMB_FACTOR, MODE_3_COMB_FEEDBACK, MODE_3_DRY_AMP, MODE_3_WET_AMP, 0}; + + static const BReverbSettings * const REVERB_SETTINGS[] = {&REVERB_MODE_0_SETTINGS, &REVERB_MODE_1_SETTINGS, &REVERB_MODE_2_SETTINGS, &REVERB_MODE_3_SETTINGS}; + + return *REVERB_SETTINGS[mode]; +} // This algorithm tries to emulate exactly Boss multiplication operation (at least this is what we see on reverb RAM data lines). // Also LA32 is suspected to use the similar one to perform PCM interpolation and ring modulation. @@ -153,14 +226,7 @@ bool RingBuffer::isEmpty() const { } void RingBuffer::mute() { -#if MT32EMU_USE_FLOAT_SAMPLES - Sample *buf = buffer; - for (Bit32u i = 0; i < size; i++) { - *buf++ = 0; - } -#else - memset(buffer, 0, size * sizeof(Sample)); -#endif + Synth::muteSampleBuffer(buffer, size); } AllpassFilter::AllpassFilter(const Bit32u useSize) : RingBuffer(useSize) {} @@ -195,10 +261,10 @@ void CombFilter::process(const Sample in) { const Sample last = buffer[index]; // prepare input + feedback - const Sample filterIn = in + weirdMul(next(), feedbackFactor, 0xF0 /* Maybe 0x80 ? */); + const Sample filterIn = in + weirdMul(next(), feedbackFactor, 0xF0); // store input + feedback processed by a low-pass filter - buffer[index] = weirdMul(last, filterFactor, 0x40) - filterIn; + buffer[index] = weirdMul(last, filterFactor, 0xC0) - filterIn; } Sample CombFilter::getOutputAt(const Bit32u outIndex) const { @@ -256,8 +322,10 @@ void TapDelayCombFilter::setOutputPositions(const Bit32u useOutL, const Bit32u u outR = useOutR; } -BReverbModel::BReverbModel(const ReverbMode mode) - : allpasses(NULL), combs(NULL), currentSettings(*REVERB_SETTINGS[mode]), tapDelayMode(mode == REVERB_MODE_TAP_DELAY) {} +BReverbModel::BReverbModel(const ReverbMode mode, const bool mt32CompatibleModel) : + allpasses(NULL), combs(NULL), + currentSettings(mt32CompatibleModel ? getMT32Settings(mode) : getCM32L_LAPCSettings(mode)), + tapDelayMode(mode == REVERB_MODE_TAP_DELAY) {} BReverbModel::~BReverbModel() { close(); @@ -334,12 +402,21 @@ void BReverbModel::setParameters(Bit8u time, Bit8u level) { if (time == 0 && level == 0) { dryAmp = wetLevel = 0; } else { - dryAmp = currentSettings.dryAmps[level]; + if (tapDelayMode && ((time == 0) || (time == 1 && level == 1))) { + // Looks like MT-32 implementation has some minor quirks in this mode: + // for odd level values, the output level changes sometimes depending on the time value which doesn't seem right. + dryAmp = currentSettings.dryAmps[level + 8]; + } else { + dryAmp = currentSettings.dryAmps[level]; + } wetLevel = currentSettings.wetLevels[level]; } } bool BReverbModel::isActive() const { + if (combs == NULL) { + return false; + } for (Bit32u i = 0; i < currentSettings.numberOfAllpasses; i++) { if (!allpasses[i]->isEmpty()) return true; } @@ -349,14 +426,34 @@ bool BReverbModel::isActive() const { return false; } +bool BReverbModel::isMT32Compatible(const ReverbMode mode) const { + return ¤tSettings == &getMT32Settings(mode); +} + void BReverbModel::process(const Sample *inLeft, const Sample *inRight, Sample *outLeft, Sample *outRight, unsigned long numSamples) { + if (combs == NULL) { + Synth::muteSampleBuffer(outLeft, numSamples); + Synth::muteSampleBuffer(outRight, numSamples); + return; + } + Sample dry; - while (numSamples > 0) { + while ((numSamples--) > 0) { if (tapDelayMode) { - dry = *inLeft + *inRight; +#if MT32EMU_USE_FLOAT_SAMPLES + dry = (*(inLeft++) * 0.5f) + (*(inRight++) * 0.5f); +#else + dry = (*(inLeft++) >> 1) + (*(inRight++) >> 1); +#endif } else { - dry = *inLeft / 2 + *inRight / 2; +#if MT32EMU_USE_FLOAT_SAMPLES + dry = (*(inLeft++) * 0.25f) + (*(inRight++) * 0.25f); +#elif MT32EMU_BOSS_REVERB_PRECISE_MODE + dry = (*(inLeft++) >> 1) / 2 + (*(inRight++) >> 1) / 2; +#else + dry = (*(inLeft++) >> 2) + (*(inRight++) >> 2); +#endif } // Looks like dryAmp doesn't change in MT-32 but it does in CM-32L / LAPC-I @@ -365,8 +462,12 @@ void BReverbModel::process(const Sample *inLeft, const Sample *inRight, Sample * if (tapDelayMode) { TapDelayCombFilter *comb = static_cast<TapDelayCombFilter *> (*combs); comb->process(dry); - *outLeft = weirdMul(comb->getLeftOutput(), wetLevel, 0xFF); - *outRight = weirdMul(comb->getRightOutput(), wetLevel, 0xFF); + if (outLeft != NULL) { + *(outLeft++) = weirdMul(comb->getLeftOutput(), wetLevel, 0xFF); + } + if (outRight != NULL) { + *(outRight++) = weirdMul(comb->getRightOutput(), wetLevel, 0xFF); + } } else { // If the output position is equal to the comb size, get it now in order not to loose it Sample link = combs[0]->getOutputAt(currentSettings.combSizes[0] - 1); @@ -389,33 +490,38 @@ void BReverbModel::process(const Sample *inLeft, const Sample *inRight, Sample * combs[2]->process(link); combs[3]->process(link); - Sample outL2 = combs[2]->getOutputAt(currentSettings.outLPositions[1]); - Sample outL3 = combs[3]->getOutputAt(currentSettings.outLPositions[2]); - Sample outR1 = combs[1]->getOutputAt(currentSettings.outRPositions[0]); - Sample outR2 = combs[2]->getOutputAt(currentSettings.outRPositions[1]); - Sample outR3 = combs[3]->getOutputAt(currentSettings.outRPositions[2]); - + if (outLeft != NULL) { + Sample outL2 = combs[2]->getOutputAt(currentSettings.outLPositions[1]); + Sample outL3 = combs[3]->getOutputAt(currentSettings.outLPositions[2]); #if MT32EMU_USE_FLOAT_SAMPLES - *outLeft = 1.5f * (outL1 + outL2) + outL3; - *outRight = 1.5f * (outR1 + outR2) + outR3; + Sample outSample = 1.5f * (outL1 + outL2) + outL3; +#elif MT32EMU_BOSS_REVERB_PRECISE_MODE + /* NOTE: + * Thanks to Mok for discovering, the adder in BOSS reverb chip is found to perform addition with saturation to avoid integer overflow. + * Analysing of the algorithm suggests that the overflow is most probable when the combs output is added below. + * So, despite this isn't actually accurate, we only add the check here for performance reasons. + */ + Sample outSample = Synth::clipBit16s(Synth::clipBit16s(Synth::clipBit16s(Synth::clipBit16s((Bit32s)outL1 + Bit32s(outL1 >> 1)) + (Bit32s)outL2) + Bit32s(outL2 >> 1)) + (Bit32s)outL3); #else - outL1 += outL1 >> 1; - outL2 += outL2 >> 1; - *outLeft = outL1 + outL2 + outL3; - - outR1 += outR1 >> 1; - outR2 += outR2 >> 1; - *outRight = outR1 + outR2 + outR3; + Sample outSample = Synth::clipBit16s((Bit32s)outL1 + Bit32s(outL1 >> 1) + (Bit32s)outL2 + Bit32s(outL2 >> 1) + (Bit32s)outL3); +#endif + *(outLeft++) = weirdMul(outSample, wetLevel, 0xFF); + } + if (outRight != NULL) { + Sample outR1 = combs[1]->getOutputAt(currentSettings.outRPositions[0]); + Sample outR2 = combs[2]->getOutputAt(currentSettings.outRPositions[1]); + Sample outR3 = combs[3]->getOutputAt(currentSettings.outRPositions[2]); +#if MT32EMU_USE_FLOAT_SAMPLES + Sample outSample = 1.5f * (outR1 + outR2) + outR3; +#elif MT32EMU_BOSS_REVERB_PRECISE_MODE + // See the note above for the left channel output. + Sample outSample = Synth::clipBit16s(Synth::clipBit16s(Synth::clipBit16s(Synth::clipBit16s((Bit32s)outR1 + Bit32s(outR1 >> 1)) + (Bit32s)outR2) + Bit32s(outR2 >> 1)) + (Bit32s)outR3); +#else + Sample outSample = Synth::clipBit16s((Bit32s)outR1 + Bit32s(outR1 >> 1) + (Bit32s)outR2 + Bit32s(outR2 >> 1) + (Bit32s)outR3); #endif - *outLeft = weirdMul(*outLeft, wetLevel, 0xFF); - *outRight = weirdMul(*outRight, wetLevel, 0xFF); + *(outRight++) = weirdMul(outSample, wetLevel, 0xFF); + } } - - numSamples--; - inLeft++; - inRight++; - outLeft++; - outRight++; } } |