aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Schickel2010-03-08 00:33:36 +0000
committerJohannes Schickel2010-03-08 00:33:36 +0000
commitf7b1faedc251348692942b7cffbabea6959b7827 (patch)
tree51a046c0878644b85ba13b42b4e04b6bf3b9bc9d
parent4dafbcd924b8c9a21461341e85eda4acf6b25e14 (diff)
downloadscummvm-rg350-f7b1faedc251348692942b7cffbabea6959b7827.tar.gz
scummvm-rg350-f7b1faedc251348692942b7cffbabea6959b7827.tar.bz2
scummvm-rg350-f7b1faedc251348692942b7cffbabea6959b7827.zip
Switch to the other DOSBox OPL emulator as suggested by the DOSBox developers.
svn-id: r48179
-rw-r--r--sound/module.mk1
-rw-r--r--sound/softsynth/opl/dbopl.cpp1511
-rw-r--r--sound/softsynth/opl/dbopl.h281
-rw-r--r--sound/softsynth/opl/dosbox.cpp108
-rw-r--r--sound/softsynth/opl/dosbox.h18
-rw-r--r--sound/softsynth/opl/opl_impl.h1463
-rw-r--r--sound/softsynth/opl/opl_inc.h203
7 files changed, 1836 insertions, 1749 deletions
diff --git a/sound/module.mk b/sound/module.mk
index 10cf090325..df593d8e1f 100644
--- a/sound/module.mk
+++ b/sound/module.mk
@@ -32,6 +32,7 @@ MODULE_OBJS := \
mods/soundfx.o \
mods/tfmx.o \
softsynth/adlib.o \
+ softsynth/opl/dbopl.o \
softsynth/opl/dosbox.o \
softsynth/opl/mame.o \
softsynth/ym2612.o \
diff --git a/sound/softsynth/opl/dbopl.cpp b/sound/softsynth/opl/dbopl.cpp
new file mode 100644
index 0000000000..3e0ef7bfb1
--- /dev/null
+++ b/sound/softsynth/opl/dbopl.cpp
@@ -0,0 +1,1511 @@
+/*
+ * Copyright (C) 2002-2010 The DOSBox Team
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ DOSBox implementation of a combined Yamaha YMF262 and Yamaha YM3812 emulator.
+ Enabling the opl3 bit will switch the emulator to stereo opl3 output instead of regular mono opl2
+ Except for the table generation it's all integer math
+ Can choose different types of generators, using muls and bigger tables, try different ones for slower platforms
+ The generation was based on the MAME implementation but tried to have it use less memory and be faster in general
+ MAME uses much bigger envelope tables and this will be the biggest cause of it sounding different at times
+
+ //TODO Don't delay first operator 1 sample in opl3 mode
+ //TODO Maybe not use class method pointers but a regular function pointers with operator as first parameter
+ //TODO Fix panning for the Percussion channels, would any opl3 player use it and actually really change it though?
+ //TODO Check if having the same accuracy in all frequency multipliers sounds better or not
+
+ //DUNNO Keyon in 4op, switch to 2op without keyoff.
+*/
+
+/* $Id: dbopl.cpp,v 1.10 2009-06-10 19:54:51 harekiet Exp $ */
+
+
+#include "dbopl.h"
+
+#ifndef DISABLE_DOSBOX_OPL
+
+namespace OPL {
+namespace DOSBox {
+
+#ifndef PI
+#define PI 3.14159265358979323846
+#endif
+
+namespace DBOPL {
+
+#define OPLRATE ((double)(14318180.0 / 288.0))
+#define TREMOLO_TABLE 52
+
+//Try to use most precision for frequencies
+//Else try to keep different waves in synch
+//#define WAVE_PRECISION 1
+#ifndef WAVE_PRECISION
+//Wave bits available in the top of the 32bit range
+//Original adlib uses 10.10, we use 10.22
+#define WAVE_BITS 10
+#else
+//Need some extra bits at the top to have room for octaves and frequency multiplier
+//We support to 8 times lower rate
+//128 * 15 * 8 = 15350, 2^13.9, so need 14 bits
+#define WAVE_BITS 14
+#endif
+#define WAVE_SH ( 32 - WAVE_BITS )
+#define WAVE_MASK ( ( 1 << WAVE_SH ) - 1 )
+
+//Use the same accuracy as the waves
+#define LFO_SH ( WAVE_SH - 10 )
+//LFO is controlled by our tremolo 256 sample limit
+#define LFO_MAX ( 256 << ( LFO_SH ) )
+
+
+//Maximum amount of attenuation bits
+//Envelope goes to 511, 9 bits
+#if (DBOPL_WAVE == WAVE_TABLEMUL )
+//Uses the value directly
+#define ENV_BITS ( 9 )
+#else
+//Add 3 bits here for more accuracy and would have to be shifted up either way
+#define ENV_BITS ( 9 )
+#endif
+//Limits of the envelope with those bits and when the envelope goes silent
+#define ENV_MIN 0
+#define ENV_EXTRA ( ENV_BITS - 9 )
+#define ENV_MAX ( 511 << ENV_EXTRA )
+#define ENV_LIMIT ( ( 12 * 256) >> ( 3 - ENV_EXTRA ) )
+#define ENV_SILENT( _X_ ) ( (_X_) >= ENV_LIMIT )
+
+//Attack/decay/release rate counter shift
+#define RATE_SH 24
+#define RATE_MASK ( ( 1 << RATE_SH ) - 1 )
+//Has to fit within 16bit lookuptable
+#define MUL_SH 16
+
+//Check some ranges
+#if ENV_EXTRA > 3
+#error Too many envelope bits
+#endif
+
+
+//How much to substract from the base value for the final attenuation
+static const Bit8u KslCreateTable[16] = {
+ //0 will always be be lower than 7 * 8
+ 64, 32, 24, 19,
+ 16, 12, 11, 10,
+ 8, 6, 5, 4,
+ 3, 2, 1, 0,
+};
+
+#define M(_X_) ((Bit8u)( (_X_) * 2))
+static const Bit8u FreqCreateTable[16] = {
+ M(0.5), M(1 ), M(2 ), M(3 ), M(4 ), M(5 ), M(6 ), M(7 ),
+ M(8 ), M(9 ), M(10), M(10), M(12), M(12), M(15), M(15)
+};
+#undef M
+
+//We're not including the highest attack rate, that gets a special value
+static const Bit8u AttackSamplesTable[13] = {
+ 69, 55, 46, 40,
+ 35, 29, 23, 20,
+ 19, 15, 11, 10,
+ 9
+};
+//On a real opl these values take 8 samples to reach and are based upon larger tables
+static const Bit8u EnvelopeIncreaseTable[13] = {
+ 4, 5, 6, 7,
+ 8, 10, 12, 14,
+ 16, 20, 24, 28,
+ 32,
+};
+
+#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG )
+static Bit16u ExpTable[ 256 ];
+#endif
+
+#if ( DBOPL_WAVE == WAVE_HANDLER )
+//PI table used by WAVEHANDLER
+static Bit16u SinTable[ 512 ];
+#endif
+
+#if ( DBOPL_WAVE > WAVE_HANDLER )
+//Layout of the waveform table in 512 entry intervals
+//With overlapping waves we reduce the table to half it's size
+
+// | |//\\|____|WAV7|//__|/\ |____|/\/\|
+// |\\//| | |WAV7| | \/| | |
+// |06 |0126|17 |7 |3 |4 |4 5 |5 |
+
+//6 is just 0 shifted and masked
+
+static Bit16s WaveTable[ 8 * 512 ];
+//Distance into WaveTable the wave starts
+static const Bit16u WaveBaseTable[8] = {
+ 0x000, 0x200, 0x200, 0x800,
+ 0xa00, 0xc00, 0x100, 0x400,
+
+};
+//Mask the counter with this
+static const Bit16u WaveMaskTable[8] = {
+ 1023, 1023, 511, 511,
+ 1023, 1023, 512, 1023,
+};
+
+//Where to start the counter on at keyon
+static const Bit16u WaveStartTable[8] = {
+ 512, 0, 0, 0,
+ 0, 512, 512, 256,
+};
+#endif
+
+#if ( DBOPL_WAVE == WAVE_TABLEMUL )
+static Bit16u MulTable[ 384 ];
+#endif
+
+static Bit8u KslTable[ 8 * 16 ];
+static Bit8u TremoloTable[ TREMOLO_TABLE ];
+//Start of a channel behind the chip struct start
+static Bit16u ChanOffsetTable[32];
+//Start of an operator behind the chip struct start
+static Bit16u OpOffsetTable[64];
+
+//The lower bits are the shift of the operator vibrato value
+//The highest bit is right shifted to generate -1 or 0 for negation
+//So taking the highest input value of 7 this gives 3, 7, 3, 0, -3, -7, -3, 0
+static const Bit8s VibratoTable[ 8 ] = {
+ 1 - 0x00, 0 - 0x00, 1 - 0x00, 30 - 0x00,
+ 1 - 0x80, 0 - 0x80, 1 - 0x80, 30 - 0x80
+};
+
+//Shift strength for the ksl value determined by ksl strength
+static const Bit8u KslShiftTable[4] = {
+ 31,1,2,0
+};
+
+//Generate a table index and table shift value using input value from a selected rate
+static void EnvelopeSelect( Bit8u val, Bit8u& index, Bit8u& shift ) {
+ if ( val < 13 * 4 ) { //Rate 0 - 12
+ shift = 12 - ( val >> 2 );
+ index = val & 3;
+ } else if ( val < 15 * 4 ) { //rate 13 - 14
+ shift = 0;
+ index = val - 12 * 4;
+ } else { //rate 15 and up
+ shift = 0;
+ index = 12;
+ }
+}
+
+#if ( DBOPL_WAVE == WAVE_HANDLER )
+/*
+ Generate the different waveforms out of the sine/exponetial table using handlers
+*/
+static inline Bits MakeVolume( Bitu wave, Bitu volume ) {
+ Bitu total = wave + volume;
+ Bitu index = total & 0xff;
+ Bitu sig = ExpTable[ index ];
+ Bitu exp = total >> 8;
+#if 0
+ //Check if we overflow the 31 shift limit
+ if ( exp >= 32 ) {
+ LOG_MSG( "WTF %d %d", total, exp );
+ }
+#endif
+ return (sig >> exp);
+};
+
+static Bits DB_FASTCALL WaveForm0( Bitu i, Bitu volume ) {
+ Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0
+ Bitu wave = SinTable[i & 511];
+ return (MakeVolume( wave, volume ) ^ neg) - neg;
+}
+static Bits DB_FASTCALL WaveForm1( Bitu i, Bitu volume ) {
+ Bit32u wave = SinTable[i & 511];
+ wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 );
+ return MakeVolume( wave, volume );
+}
+static Bits DB_FASTCALL WaveForm2( Bitu i, Bitu volume ) {
+ Bitu wave = SinTable[i & 511];
+ return MakeVolume( wave, volume );
+}
+static Bits DB_FASTCALL WaveForm3( Bitu i, Bitu volume ) {
+ Bitu wave = SinTable[i & 255];
+ wave |= ( ( (i ^ 256 ) & 256) - 1) >> ( 32 - 12 );
+ return MakeVolume( wave, volume );
+}
+static Bits DB_FASTCALL WaveForm4( Bitu i, Bitu volume ) {
+ //Twice as fast
+ i <<= 1;
+ Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0
+ Bitu wave = SinTable[i & 511];
+ wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 );
+ return (MakeVolume( wave, volume ) ^ neg) - neg;
+}
+static Bits DB_FASTCALL WaveForm5( Bitu i, Bitu volume ) {
+ //Twice as fast
+ i <<= 1;
+ Bitu wave = SinTable[i & 511];
+ wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 );
+ return MakeVolume( wave, volume );
+}
+static Bits DB_FASTCALL WaveForm6( Bitu i, Bitu volume ) {
+ Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0
+ return (MakeVolume( 0, volume ) ^ neg) - neg;
+}
+static Bits DB_FASTCALL WaveForm7( Bitu i, Bitu volume ) {
+ //Negative is reversed here
+ Bits neg = (( i >> 9) & 1) - 1;
+ Bitu wave = (i << 3);
+ //When negative the volume also runs backwards
+ wave = ((wave ^ neg) - neg) & 4095;
+ return (MakeVolume( wave, volume ) ^ neg) - neg;
+}
+
+static const WaveHandler WaveHandlerTable[8] = {
+ WaveForm0, WaveForm1, WaveForm2, WaveForm3,
+ WaveForm4, WaveForm5, WaveForm6, WaveForm7
+};
+
+#endif
+
+/*
+ Operator
+*/
+
+//We zero out when rate == 0
+inline void Operator::UpdateAttack( const Chip* chip ) {
+ Bit8u rate = reg60 >> 4;
+ if ( rate ) {
+ Bit8u val = (rate << 2) + ksr;
+ attackAdd = chip->attackRates[ val ];
+ rateZero &= ~(1 << ATTACK);
+ } else {
+ attackAdd = 0;
+ rateZero |= (1 << ATTACK);
+ }
+}
+inline void Operator::UpdateDecay( const Chip* chip ) {
+ Bit8u rate = reg60 & 0xf;
+ if ( rate ) {
+ Bit8u val = (rate << 2) + ksr;
+ decayAdd = chip->linearRates[ val ];
+ rateZero &= ~(1 << DECAY);
+ } else {
+ decayAdd = 0;
+ rateZero |= (1 << DECAY);
+ }
+}
+inline void Operator::UpdateRelease( const Chip* chip ) {
+ Bit8u rate = reg80 & 0xf;
+ if ( rate ) {
+ Bit8u val = (rate << 2) + ksr;
+ releaseAdd = chip->linearRates[ val ];
+ rateZero &= ~(1 << RELEASE);
+ if ( !(reg20 & MASK_SUSTAIN ) ) {
+ rateZero &= ~( 1 << SUSTAIN );
+ }
+ } else {
+ rateZero |= (1 << RELEASE);
+ releaseAdd = 0;
+ if ( !(reg20 & MASK_SUSTAIN ) ) {
+ rateZero |= ( 1 << SUSTAIN );
+ }
+ }
+}
+
+inline void Operator::UpdateAttenuation( ) {
+ Bit8u kslBase = (Bit8u)((chanData >> SHIFT_KSLBASE) & 0xff);
+ Bit32u tl = reg40 & 0x3f;
+ Bit8u kslShift = KslShiftTable[ reg40 >> 6 ];
+ //Make sure the attenuation goes to the right bits
+ totalLevel = tl << ( ENV_BITS - 7 ); //Total level goes 2 bits below max
+ totalLevel += ( kslBase << ENV_EXTRA ) >> kslShift;
+}
+
+void Operator::UpdateFrequency( ) {
+ Bit32u freq = chanData & (( 1 << 10 ) - 1);
+ Bit32u block = (chanData >> 10) & 0xff;
+#ifdef WAVE_PRECISION
+ block = 7 - block;
+ waveAdd = ( freq * freqMul ) >> block;
+#else
+ waveAdd = ( freq << block ) * freqMul;
+#endif
+ if ( reg20 & MASK_VIBRATO ) {
+ vibStrength = (Bit8u)(freq >> 7);
+
+#ifdef WAVE_PRECISION
+ vibrato = ( vibStrength * freqMul ) >> block;
+#else
+ vibrato = ( vibStrength << block ) * freqMul;
+#endif
+ } else {
+ vibStrength = 0;
+ vibrato = 0;
+ }
+}
+
+void Operator::UpdateRates( const Chip* chip ) {
+ //Mame seems to reverse this where enabling ksr actually lowers
+ //the rate, but pdf manuals says otherwise?
+ Bit8u newKsr = (Bit8u)((chanData >> SHIFT_KEYCODE) & 0xff);
+ if ( !( reg20 & MASK_KSR ) ) {
+ newKsr >>= 2;
+ }
+ if ( ksr == newKsr )
+ return;
+ ksr = newKsr;
+ UpdateAttack( chip );
+ UpdateDecay( chip );
+ UpdateRelease( chip );
+}
+
+INLINE Bit32s Operator::RateForward( Bit32u add ) {
+ rateIndex += add;
+ Bit32s ret = rateIndex >> RATE_SH;
+ rateIndex = rateIndex & RATE_MASK;
+ return ret;
+}
+
+template< Operator::State yes>
+Bits Operator::TemplateVolume( ) {
+ Bit32s vol = volume;
+ Bit32s change;
+ switch ( yes ) {
+ case OFF:
+ return ENV_MAX;
+ case ATTACK:
+ change = RateForward( attackAdd );
+ if ( !change )
+ return vol;
+ vol += ( (~vol) * change ) >> 3;
+ if ( vol < ENV_MIN ) {
+ volume = ENV_MIN;
+ rateIndex = 0;
+ SetState( DECAY );
+ return ENV_MIN;
+ }
+ break;
+ case DECAY:
+ vol += RateForward( decayAdd );
+ if ( GCC_UNLIKELY(vol >= sustainLevel) ) {
+ //Check if we didn't overshoot max attenuation, then just go off
+ if ( GCC_UNLIKELY(vol >= ENV_MAX) ) {
+ volume = ENV_MAX;
+ SetState( OFF );
+ return ENV_MAX;
+ }
+ //Continue as sustain
+ rateIndex = 0;
+ SetState( SUSTAIN );
+ }
+ break;
+ case SUSTAIN:
+ if ( reg20 & MASK_SUSTAIN ) {
+ return vol;
+ }
+ //In sustain phase, but not sustaining, do regular release
+ case RELEASE:
+ vol += RateForward( releaseAdd );;
+ if ( GCC_UNLIKELY(vol >= ENV_MAX) ) {
+ volume = ENV_MAX;
+ SetState( OFF );
+ return ENV_MAX;
+ }
+ break;
+ }
+ volume = vol;
+ return vol;
+}
+
+static const VolumeHandler VolumeHandlerTable[5] = {
+ &Operator::TemplateVolume< Operator::OFF >,
+ &Operator::TemplateVolume< Operator::RELEASE >,
+ &Operator::TemplateVolume< Operator::SUSTAIN >,
+ &Operator::TemplateVolume< Operator::DECAY >,
+ &Operator::TemplateVolume< Operator::ATTACK >
+};
+
+INLINE Bitu Operator::ForwardVolume() {
+ return currentLevel + (this->*volHandler)();
+}
+
+
+INLINE Bitu Operator::ForwardWave() {
+ waveIndex += waveCurrent;
+ return waveIndex >> WAVE_SH;
+}
+
+void Operator::Write20( const Chip* chip, Bit8u val ) {
+ Bit8u change = (reg20 ^ val );
+ if ( !change )
+ return;
+ reg20 = val;
+ //Shift the tremolo bit over the entire register, saved a branch, YES!
+ tremoloMask = (Bit8s)(val) >> 7;
+ tremoloMask &= ~(( 1 << ENV_EXTRA ) -1);
+ //Update specific features based on changes
+ if ( change & MASK_KSR ) {
+ UpdateRates( chip );
+ }
+ //With sustain enable the volume doesn't change
+ if ( reg20 & MASK_SUSTAIN || ( !releaseAdd ) ) {
+ rateZero |= ( 1 << SUSTAIN );
+ } else {
+ rateZero &= ~( 1 << SUSTAIN );
+ }
+ //Frequency multiplier or vibrato changed
+ if ( change & (0xf | MASK_VIBRATO) ) {
+ freqMul = chip->freqMul[ val & 0xf ];
+ UpdateFrequency();
+ }
+}
+
+void Operator::Write40( const Chip* /*chip*/, Bit8u val ) {
+ if (!(reg40 ^ val ))
+ return;
+ reg40 = val;
+ UpdateAttenuation( );
+}
+
+void Operator::Write60( const Chip* chip, Bit8u val ) {
+ Bit8u change = reg60 ^ val;
+ reg60 = val;
+ if ( change & 0x0f ) {
+ UpdateDecay( chip );
+ }
+ if ( change & 0xf0 ) {
+ UpdateAttack( chip );
+ }
+}
+
+void Operator::Write80( const Chip* chip, Bit8u val ) {
+ Bit8u change = (reg80 ^ val );
+ if ( !change )
+ return;
+ reg80 = val;
+ Bit8u sustain = val >> 4;
+ //Turn 0xf into 0x1f
+ sustain |= ( sustain + 1) & 0x10;
+ sustainLevel = sustain << ( ENV_BITS - 5 );
+ if ( change & 0x0f ) {
+ UpdateRelease( chip );
+ }
+}
+
+void Operator::WriteE0( const Chip* chip, Bit8u val ) {
+ if ( !(regE0 ^ val) )
+ return;
+ //in opl3 mode you can always selet 7 waveforms regardless of waveformselect
+ Bit8u waveForm = val & ( ( 0x3 & chip->waveFormMask ) | (0x7 & chip->opl3Active ) );
+ regE0 = val;
+#if ( DBOPL_WAVE == WAVE_HANDLER )
+ waveHandler = WaveHandlerTable[ waveForm ];
+#else
+ waveBase = WaveTable + WaveBaseTable[ waveForm ];
+ waveStart = WaveStartTable[ waveForm ] << WAVE_SH;
+ waveMask = WaveMaskTable[ waveForm ];
+#endif
+}
+
+INLINE void Operator::SetState( Bit8u s ) {
+ state = s;
+ volHandler = VolumeHandlerTable[ s ];
+}
+
+INLINE bool Operator::Silent() const {
+ if ( !ENV_SILENT( totalLevel + volume ) )
+ return false;
+ if ( !(rateZero & ( 1 << state ) ) )
+ return false;
+ return true;
+}
+
+INLINE void Operator::Prepare( const Chip* chip ) {
+ currentLevel = totalLevel + (chip->tremoloValue & tremoloMask);
+ waveCurrent = waveAdd;
+ if ( vibStrength >> chip->vibratoShift ) {
+ Bit32s add = vibrato >> chip->vibratoShift;
+ //Sign extend over the shift value
+ Bit32s neg = chip->vibratoSign;
+ //Negate the add with -1 or 0
+ add = ( add ^ neg ) - neg;
+ waveCurrent += add;
+ }
+}
+
+void Operator::KeyOn( Bit8u mask ) {
+ if ( !keyOn ) {
+ //Restart the frequency generator
+#if ( DBOPL_WAVE > WAVE_HANDLER )
+ waveIndex = waveStart;
+#else
+ waveIndex = 0;
+#endif
+ rateIndex = 0;
+ SetState( ATTACK );
+ }
+ keyOn |= mask;
+}
+
+void Operator::KeyOff( Bit8u mask ) {
+ keyOn &= ~mask;
+ if ( !keyOn ) {
+ if ( state != OFF ) {
+ SetState( RELEASE );
+ }
+ }
+}
+
+INLINE Bits Operator::GetWave( Bitu index, Bitu vol ) {
+#if ( DBOPL_WAVE == WAVE_HANDLER )
+ return waveHandler( index, vol << ( 3 - ENV_EXTRA ) );
+#elif ( DBOPL_WAVE == WAVE_TABLEMUL )
+ return (waveBase[ index & waveMask ] * MulTable[ vol >> ENV_EXTRA ]) >> MUL_SH;
+#elif ( DBOPL_WAVE == WAVE_TABLELOG )
+ Bit32s wave = waveBase[ index & waveMask ];
+ Bit32u total = ( wave & 0x7fff ) + vol << ( 3 - ENV_EXTRA );
+ Bit32s sig = ExpTable[ total & 0xff ];
+ Bit32u exp = total >> 8;
+ Bit32s neg = wave >> 16;
+ return ((sig ^ neg) - neg) >> exp;
+#else
+#error "No valid wave routine"
+#endif
+}
+
+Bits INLINE Operator::GetSample( Bits modulation ) {
+ Bitu vol = ForwardVolume();
+ if ( ENV_SILENT( vol ) ) {
+ //Simply forward the wave
+ waveIndex += waveCurrent;
+ return 0;
+ } else {
+ Bitu index = ForwardWave();
+ index += modulation;
+ return GetWave( index, vol );
+ }
+}
+
+Operator::Operator() {
+ chanData = 0;
+ freqMul = 0;
+ waveIndex = 0;
+ waveAdd = 0;
+ waveCurrent = 0;
+ keyOn = 0;
+ ksr = 0;
+ reg20 = 0;
+ reg40 = 0;
+ reg60 = 0;
+ reg80 = 0;
+ regE0 = 0;
+ SetState( OFF );
+ rateZero = (1 << OFF);
+ sustainLevel = ENV_MAX;
+ currentLevel = ENV_MAX;
+ totalLevel = ENV_MAX;
+ volume = ENV_MAX;
+}
+
+/*
+ Channel
+*/
+
+Channel::Channel() {
+ old[0] = old[1] = 0;
+ chanData = 0;
+ regB0 = 0;
+ regC0 = 0;
+ maskLeft = -1;
+ maskRight = -1;
+ feedback = 31;
+ fourMask = 0;
+ synthHandler = &Channel::BlockTemplate< sm2FM >;
+}
+
+void Channel::SetChanData( const Chip* chip, Bit32u data ) {
+ Bit32u change = chanData ^ data;
+ chanData = data;
+ Op( 0 )->chanData = data;
+ Op( 1 )->chanData = data;
+ //Since a frequency update triggered this, always update frequency
+ Op( 0 )->UpdateFrequency();
+ Op( 1 )->UpdateFrequency();
+ if ( change & ( 0xff << SHIFT_KSLBASE ) ) {
+ Op( 0 )->UpdateAttenuation();
+ Op( 1 )->UpdateAttenuation();
+ }
+ if ( change & ( 0xff << SHIFT_KEYCODE ) ) {
+ Op( 0 )->UpdateRates( chip );
+ Op( 1 )->UpdateRates( chip );
+ }
+}
+
+void Channel::UpdateFrequency( const Chip* chip, Bit8u fourOp ) {
+ //Extrace the frequency bits
+ Bit32u data = chanData & 0xffff;
+ Bit32u kslBase = KslTable[ data >> 6 ];
+ Bit32u keyCode = ( data & 0x1c00) >> 9;
+ if ( chip->reg08 & 0x40 ) {
+ keyCode |= ( data & 0x100)>>8; /* notesel == 1 */
+ } else {
+ keyCode |= ( data & 0x200)>>9; /* notesel == 0 */
+ }
+ //Add the keycode and ksl into the highest bits of chanData
+ data |= (keyCode << SHIFT_KEYCODE) | ( kslBase << SHIFT_KSLBASE );
+ ( this + 0 )->SetChanData( chip, data );
+ if ( fourOp & 0x3f ) {
+ ( this + 1 )->SetChanData( chip, data );
+ }
+}
+
+void Channel::WriteA0( const Chip* chip, Bit8u val ) {
+ Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask;
+ //Don't handle writes to silent fourop channels
+ if ( fourOp > 0x80 )
+ return;
+ Bit32u change = (chanData ^ val ) & 0xff;
+ if ( change ) {
+ chanData ^= change;
+ UpdateFrequency( chip, fourOp );
+ }
+}
+
+void Channel::WriteB0( const Chip* chip, Bit8u val ) {
+ Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask;
+ //Don't handle writes to silent fourop channels
+ if ( fourOp > 0x80 )
+ return;
+ Bitu change = (chanData ^ ( val << 8 ) ) & 0x1f00;
+ if ( change ) {
+ chanData ^= change;
+ UpdateFrequency( chip, fourOp );
+ }
+ //Check for a change in the keyon/off state
+ if ( !(( val ^ regB0) & 0x20))
+ return;
+ regB0 = val;
+ if ( val & 0x20 ) {
+ Op(0)->KeyOn( 0x1 );
+ Op(1)->KeyOn( 0x1 );
+ if ( fourOp & 0x3f ) {
+ ( this + 1 )->Op(0)->KeyOn( 1 );
+ ( this + 1 )->Op(1)->KeyOn( 1 );
+ }
+ } else {
+ Op(0)->KeyOff( 0x1 );
+ Op(1)->KeyOff( 0x1 );
+ if ( fourOp & 0x3f ) {
+ ( this + 1 )->Op(0)->KeyOff( 1 );
+ ( this + 1 )->Op(1)->KeyOff( 1 );
+ }
+ }
+}
+
+void Channel::WriteC0( const Chip* chip, Bit8u val ) {
+ Bit8u change = val ^ regC0;
+ if ( !change )
+ return;
+ regC0 = val;
+ feedback = ( val >> 1 ) & 7;
+ if ( feedback ) {
+ //We shift the input to the right 10 bit wave index value
+ feedback = 9 - feedback;
+ } else {
+ feedback = 31;
+ }
+ //Select the new synth mode
+ if ( chip->opl3Active ) {
+ //4-op mode enabled for this channel
+ if ( (chip->reg104 & fourMask) & 0x3f ) {
+ Channel* chan0, *chan1;
+ //Check if it's the 2nd channel in a 4-op
+ if ( !(fourMask & 0x80 ) ) {
+ chan0 = this;
+ chan1 = this + 1;
+ } else {
+ chan0 = this - 1;
+ chan1 = this;
+ }
+
+ Bit8u synth = ( (chan0->regC0 & 1) << 0 )| (( chan1->regC0 & 1) << 1 );
+ switch ( synth ) {
+ case 0:
+ chan0->synthHandler = &Channel::BlockTemplate< sm3FMFM >;
+ break;
+ case 1:
+ chan0->synthHandler = &Channel::BlockTemplate< sm3AMFM >;
+ break;
+ case 2:
+ chan0->synthHandler = &Channel::BlockTemplate< sm3FMAM >;
+ break;
+ case 3:
+ chan0->synthHandler = &Channel::BlockTemplate< sm3AMAM >;
+ break;
+ }
+ //Disable updating percussion channels
+ } else if ((fourMask & 0x40) && ( chip->regBD & 0x20) ) {
+
+ //Regular dual op, am or fm
+ } else if ( val & 1 ) {
+ synthHandler = &Channel::BlockTemplate< sm3AM >;
+ } else {
+ synthHandler = &Channel::BlockTemplate< sm3FM >;
+ }
+ maskLeft = ( val & 0x10 ) ? -1 : 0;
+ maskRight = ( val & 0x20 ) ? -1 : 0;
+ //opl2 active
+ } else {
+ //Disable updating percussion channels
+ if ( (fourMask & 0x40) && ( chip->regBD & 0x20 ) ) {
+
+ //Regular dual op, am or fm
+ } else if ( val & 1 ) {
+ synthHandler = &Channel::BlockTemplate< sm2AM >;
+ } else {
+ synthHandler = &Channel::BlockTemplate< sm2FM >;
+ }
+ }
+}
+
+void Channel::ResetC0( const Chip* chip ) {
+ Bit8u val = regC0;
+ regC0 ^= 0xff;
+ WriteC0( chip, val );
+}
+
+template< bool opl3Mode>
+INLINE void Channel::GeneratePercussion( Chip* chip, Bit32s* output ) {
+ Channel* chan = this;
+
+ //BassDrum
+ Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback;
+ old[0] = old[1];
+ old[1] = Op(0)->GetSample( mod );
+
+ //When bassdrum is in AM mode first operator is ignoed
+ if ( chan->regC0 & 1 ) {
+ mod = 0;
+ } else {
+ mod = old[0];
+ }
+ Bit32s sample = Op(1)->GetSample( mod );
+
+
+ //Precalculate stuff used by other outputs
+ Bit32u noiseBit = chip->ForwardNoise() & 0x1;
+ Bit32u c2 = Op(2)->ForwardWave();
+ Bit32u c5 = Op(5)->ForwardWave();
+ Bit32u phaseBit = (((c2 & 0x88) ^ ((c2<<5) & 0x80)) | ((c5 ^ (c5<<2)) & 0x20)) ? 0x02 : 0x00;
+
+ //Hi-Hat
+ Bit32u hhVol = Op(2)->ForwardVolume();
+ if ( !ENV_SILENT( hhVol ) ) {
+ Bit32u hhIndex = (phaseBit<<8) | (0x34 << ( phaseBit ^ (noiseBit << 1 )));
+ sample += Op(2)->GetWave( hhIndex, hhVol );
+ }
+ //Snare Drum
+ Bit32u sdVol = Op(3)->ForwardVolume();
+ if ( !ENV_SILENT( sdVol ) ) {
+ Bit32u sdIndex = ( 0x100 + (c2 & 0x100) ) ^ ( noiseBit << 8 );
+ sample += Op(3)->GetWave( sdIndex, sdVol );
+ }
+ //Tom-tom
+ sample += Op(4)->GetSample( 0 );
+
+ //Top-Cymbal
+ Bit32u tcVol = Op(5)->ForwardVolume();
+ if ( !ENV_SILENT( tcVol ) ) {
+ Bit32u tcIndex = (1 + phaseBit) << 8;
+ sample += Op(5)->GetWave( tcIndex, tcVol );
+ }
+ sample <<= 1;
+ if ( opl3Mode ) {
+ output[0] += sample;
+ output[1] += sample;
+ } else {
+ output[0] += sample;
+ }
+}
+
+template<SynthMode mode>
+Channel* Channel::BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ) {
+ switch( mode ) {
+ case sm2AM:
+ case sm3AM:
+ if ( Op(0)->Silent() && Op(1)->Silent() ) {
+ old[0] = old[1] = 0;
+ return (this + 1);
+ }
+ break;
+ case sm2FM:
+ case sm3FM:
+ if ( Op(1)->Silent() ) {
+ old[0] = old[1] = 0;
+ return (this + 1);
+ }
+ break;
+ case sm3FMFM:
+ if ( Op(3)->Silent() ) {
+ old[0] = old[1] = 0;
+ return (this + 2);
+ }
+ break;
+ case sm3AMFM:
+ if ( Op(0)->Silent() && Op(3)->Silent() ) {
+ old[0] = old[1] = 0;
+ return (this + 2);
+ }
+ break;
+ case sm3FMAM:
+ if ( Op(1)->Silent() && Op(3)->Silent() ) {
+ old[0] = old[1] = 0;
+ return (this + 2);
+ }
+ break;
+ case sm3AMAM:
+ if ( Op(0)->Silent() && Op(2)->Silent() && Op(3)->Silent() ) {
+ old[0] = old[1] = 0;
+ return (this + 2);
+ }
+ break;
+ case sm2Percussion:
+ // This case was not handled in the DOSBox code either
+ // thus we leave this blank.
+ // TODO: Consider checking this.
+ break;
+ case sm3Percussion:
+ // This case was not handled in the DOSBox code either
+ // thus we leave this blank.
+ // TODO: Consider checking this.
+ break;
+ }
+ //Init the operators with the the current vibrato and tremolo values
+ Op( 0 )->Prepare( chip );
+ Op( 1 )->Prepare( chip );
+ if ( mode > sm4Start ) {
+ Op( 2 )->Prepare( chip );
+ Op( 3 )->Prepare( chip );
+ }
+ if ( mode > sm6Start ) {
+ Op( 4 )->Prepare( chip );
+ Op( 5 )->Prepare( chip );
+ }
+ for ( Bitu i = 0; i < samples; i++ ) {
+ //Early out for percussion handlers
+ if ( mode == sm2Percussion ) {
+ GeneratePercussion<false>( chip, output + i );
+ continue; //Prevent some unitialized value bitching
+ } else if ( mode == sm3Percussion ) {
+ GeneratePercussion<true>( chip, output + i * 2 );
+ continue; //Prevent some unitialized value bitching
+ }
+
+ //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise
+ Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback;
+ old[0] = old[1];
+ old[1] = Op(0)->GetSample( mod );
+ Bit32s sample;
+ Bit32s out0 = old[0];
+ if ( mode == sm2AM || mode == sm3AM ) {
+ sample = out0 + Op(1)->GetSample( 0 );
+ } else if ( mode == sm2FM || mode == sm3FM ) {
+ sample = Op(1)->GetSample( out0 );
+ } else if ( mode == sm3FMFM ) {
+ Bits next = Op(1)->GetSample( out0 );
+ next = Op(2)->GetSample( next );
+ sample = Op(3)->GetSample( next );
+ } else if ( mode == sm3AMFM ) {
+ sample = out0;
+ Bits next = Op(1)->GetSample( 0 );
+ next = Op(2)->GetSample( next );
+ sample += Op(3)->GetSample( next );
+ } else if ( mode == sm3FMAM ) {
+ sample = Op(1)->GetSample( out0 );
+ Bits next = Op(2)->GetSample( 0 );
+ sample += Op(3)->GetSample( next );
+ } else if ( mode == sm3AMAM ) {
+ sample = out0;
+ Bits next = Op(1)->GetSample( 0 );
+ sample += Op(2)->GetSample( next );
+ sample += Op(3)->GetSample( 0 );
+ }
+ switch( mode ) {
+ case sm2AM:
+ case sm2FM:
+ output[ i ] += sample;
+ break;
+ case sm3AM:
+ case sm3FM:
+ case sm3FMFM:
+ case sm3AMFM:
+ case sm3FMAM:
+ case sm3AMAM:
+ output[ i * 2 + 0 ] += sample & maskLeft;
+ output[ i * 2 + 1 ] += sample & maskRight;
+ break;
+ case sm2Percussion:
+ // This case was not handled in the DOSBox code either
+ // thus we leave this blank.
+ // TODO: Consider checking this.
+ break;
+ case sm3Percussion:
+ // This case was not handled in the DOSBox code either
+ // thus we leave this blank.
+ // TODO: Consider checking this.
+ break;
+ }
+ }
+ switch( mode ) {
+ case sm2AM:
+ case sm2FM:
+ case sm3AM:
+ case sm3FM:
+ return ( this + 1 );
+ case sm3FMFM:
+ case sm3AMFM:
+ case sm3FMAM:
+ case sm3AMAM:
+ return( this + 2 );
+ case sm2Percussion:
+ case sm3Percussion:
+ return( this + 3 );
+ }
+ return 0;
+}
+
+/*
+ Chip
+*/
+
+Chip::Chip() {
+ reg08 = 0;
+ reg04 = 0;
+ regBD = 0;
+ reg104 = 0;
+ opl3Active = 0;
+}
+
+INLINE Bit32u Chip::ForwardNoise() {
+ noiseCounter += noiseAdd;
+ Bitu count = noiseCounter >> LFO_SH;
+ noiseCounter &= WAVE_MASK;
+ for ( ; count > 0; --count ) {
+ //Noise calculation from mame
+ noiseValue ^= ( 0x800302 ) & ( 0 - (noiseValue & 1 ) );
+ noiseValue >>= 1;
+ }
+ return noiseValue;
+}
+
+INLINE Bit32u Chip::ForwardLFO( Bit32u samples ) {
+ //Current vibrato value, runs 4x slower than tremolo
+ vibratoSign = ( VibratoTable[ vibratoIndex >> 2] ) >> 7;
+ vibratoShift = ( VibratoTable[ vibratoIndex >> 2] & 7) + vibratoStrength;
+ tremoloValue = TremoloTable[ tremoloIndex ] >> tremoloStrength;
+
+ //Check hom many samples there can be done before the value changes
+ Bit32u todo = LFO_MAX - lfoCounter;
+ Bit32u count = (todo + lfoAdd - 1) / lfoAdd;
+ if ( count > samples ) {
+ count = samples;
+ lfoCounter += count * lfoAdd;
+ } else {
+ lfoCounter += count * lfoAdd;
+ lfoCounter &= (LFO_MAX - 1);
+ //Maximum of 7 vibrato value * 4
+ vibratoIndex = ( vibratoIndex + 1 ) & 31;
+ //Clip tremolo to the the table size
+ if ( tremoloIndex + 1 < TREMOLO_TABLE )
+ ++tremoloIndex;
+ else
+ tremoloIndex = 0;
+ }
+ return count;
+}
+
+
+void Chip::WriteBD( Bit8u val ) {
+ Bit8u change = regBD ^ val;
+ if ( !change )
+ return;
+ regBD = val;
+ //TODO could do this with shift and xor?
+ vibratoStrength = (val & 0x40) ? 0x00 : 0x01;
+ tremoloStrength = (val & 0x80) ? 0x00 : 0x02;
+ if ( val & 0x20 ) {
+ //Drum was just enabled, make sure channel 6 has the right synth
+ if ( change & 0x20 ) {
+ if ( opl3Active ) {
+ chan[6].synthHandler = &Channel::BlockTemplate< sm3Percussion >;
+ } else {
+ chan[6].synthHandler = &Channel::BlockTemplate< sm2Percussion >;
+ }
+ }
+ //Bass Drum
+ if ( val & 0x10 ) {
+ chan[6].op[0].KeyOn( 0x2 );
+ chan[6].op[1].KeyOn( 0x2 );
+ } else {
+ chan[6].op[0].KeyOff( 0x2 );
+ chan[6].op[1].KeyOff( 0x2 );
+ }
+ //Hi-Hat
+ if ( val & 0x1 ) {
+ chan[7].op[0].KeyOn( 0x2 );
+ } else {
+ chan[7].op[0].KeyOff( 0x2 );
+ }
+ //Snare
+ if ( val & 0x8 ) {
+ chan[7].op[1].KeyOn( 0x2 );
+ } else {
+ chan[7].op[1].KeyOff( 0x2 );
+ }
+ //Tom-Tom
+ if ( val & 0x4 ) {
+ chan[8].op[0].KeyOn( 0x2 );
+ } else {
+ chan[8].op[0].KeyOff( 0x2 );
+ }
+ //Top Cymbal
+ if ( val & 0x2 ) {
+ chan[8].op[1].KeyOn( 0x2 );
+ } else {
+ chan[8].op[1].KeyOff( 0x2 );
+ }
+ //Toggle keyoffs when we turn off the percussion
+ } else if ( change & 0x20 ) {
+ //Trigger a reset to setup the original synth handler
+ chan[6].ResetC0( this );
+ chan[6].op[0].KeyOff( 0x2 );
+ chan[6].op[1].KeyOff( 0x2 );
+ chan[7].op[0].KeyOff( 0x2 );
+ chan[7].op[1].KeyOff( 0x2 );
+ chan[8].op[0].KeyOff( 0x2 );
+ chan[8].op[1].KeyOff( 0x2 );
+ }
+}
+
+
+#define REGOP( _FUNC_ ) \
+ index = ( ( reg >> 3) & 0x20 ) | ( reg & 0x1f ); \
+ if ( OpOffsetTable[ index ] ) { \
+ Operator* regOp = (Operator*)( ((char *)this ) + OpOffsetTable[ index ] ); \
+ regOp->_FUNC_( this, val ); \
+ }
+
+#define REGCHAN( _FUNC_ ) \
+ index = ( ( reg >> 4) & 0x10 ) | ( reg & 0xf ); \
+ if ( ChanOffsetTable[ index ] ) { \
+ Channel* regChan = (Channel*)( ((char *)this ) + ChanOffsetTable[ index ] ); \
+ regChan->_FUNC_( this, val ); \
+ }
+
+void Chip::WriteReg( Bit32u reg, Bit8u val ) {
+ Bitu index;
+ switch ( (reg & 0xf0) >> 4 ) {
+ case 0x00 >> 4:
+ if ( reg == 0x01 ) {
+ waveFormMask = ( val & 0x20 ) ? 0x7 : 0x0;
+ } else if ( reg == 0x104 ) {
+ //Only detect changes in lowest 6 bits
+ if ( !((reg104 ^ val) & 0x3f) )
+ return;
+ //Always keep the highest bit enabled, for checking > 0x80
+ reg104 = 0x80 | ( val & 0x3f );
+ } else if ( reg == 0x105 ) {
+ //MAME says the real opl3 doesn't reset anything on opl3 disable/enable till the next write in another register
+ if ( !((opl3Active ^ val) & 1 ) )
+ return;
+ opl3Active = ( val & 1 ) ? 0xff : 0;
+ //Update the 0xc0 register for all channels to signal the switch to mono/stereo handlers
+ for ( int i = 0; i < 18;i++ ) {
+ chan[i].ResetC0( this );
+ }
+ } else if ( reg == 0x08 ) {
+ reg08 = val;
+ }
+ case 0x10 >> 4:
+ break;
+ case 0x20 >> 4:
+ case 0x30 >> 4:
+ REGOP( Write20 );
+ break;
+ case 0x40 >> 4:
+ case 0x50 >> 4:
+ REGOP( Write40 );
+ break;
+ case 0x60 >> 4:
+ case 0x70 >> 4:
+ REGOP( Write60 );
+ break;
+ case 0x80 >> 4:
+ case 0x90 >> 4:
+ REGOP( Write80 );
+ break;
+ case 0xa0 >> 4:
+ REGCHAN( WriteA0 );
+ break;
+ case 0xb0 >> 4:
+ if ( reg == 0xbd ) {
+ WriteBD( val );
+ } else {
+ REGCHAN( WriteB0 );
+ }
+ break;
+ case 0xc0 >> 4:
+ REGCHAN( WriteC0 );
+ case 0xd0 >> 4:
+ break;
+ case 0xe0 >> 4:
+ case 0xf0 >> 4:
+ REGOP( WriteE0 );
+ break;
+ }
+}
+
+
+Bit32u Chip::WriteAddr( Bit32u port, Bit8u val ) {
+ switch ( port & 3 ) {
+ case 0:
+ return val;
+ case 2:
+ if ( opl3Active || (val == 0x05) )
+ return 0x100 | val;
+ else
+ return val;
+ }
+ return 0;
+}
+
+void Chip::GenerateBlock2( Bitu total, Bit32s* output ) {
+ while ( total > 0 ) {
+ Bit32u samples = ForwardLFO( total );
+ for ( Bitu i = 0; i < samples; i++ ) {
+ output[i] = 0;
+ }
+ int count = 0;
+ for( Channel* ch = chan; ch < chan + 9; ) {
+ count++;
+ ch = (ch->*(ch->synthHandler))( this, samples, output );
+ }
+ total -= samples;
+ output += samples;
+ }
+}
+
+void Chip::GenerateBlock3( Bitu total, Bit32s* output ) {
+ while ( total > 0 ) {
+ Bit32u samples = ForwardLFO( total );
+ for ( Bitu i = 0; i < samples; i++ ) {
+ output[i * 2 + 0 ] = 0;
+ output[i * 2 + 1 ] = 0;
+ }
+ int count = 0;
+ for( Channel* ch = chan; ch < chan + 18; ) {
+ count++;
+ ch = (ch->*(ch->synthHandler))( this, samples, output );
+ }
+ total -= samples;
+ output += samples * 2;
+ }
+}
+
+void Chip::Setup( Bit32u rate ) {
+ double scale = OPLRATE / (double)rate;
+
+ //Noise counter is run at the same precision as general waves
+ noiseAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) );
+ noiseCounter = 0;
+ noiseValue = 1; //Make sure it triggers the noise xor the first time
+ //The low frequency oscillation counter
+ //Every time his overflows vibrato and tremoloindex are increased
+ lfoAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) );
+ lfoCounter = 0;
+ vibratoIndex = 0;
+ tremoloIndex = 0;
+
+ //With higher octave this gets shifted up
+ //-1 since the freqCreateTable = *2
+#ifdef WAVE_PRECISION
+ double freqScale = ( 1 << 7 ) * scale * ( 1 << ( WAVE_SH - 1 - 10));
+ for ( int i = 0; i < 16; i++ ) {
+ freqMul[i] = (Bit32u)( 0.5 + freqScale * FreqCreateTable[ i ] );
+ }
+#else
+ Bit32u freqScale = (Bit32u)( 0.5 + scale * ( 1 << ( WAVE_SH - 1 - 10)));
+ for ( int i = 0; i < 16; i++ ) {
+ freqMul[i] = freqScale * FreqCreateTable[ i ];
+ }
+#endif
+
+ //-3 since the real envelope takes 8 steps to reach the single value we supply
+ for ( Bit8u i = 0; i < 76; i++ ) {
+ Bit8u index, shift;
+ EnvelopeSelect( i, index, shift );
+ linearRates[i] = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH + ENV_EXTRA - shift - 3 )));
+ }
+ //Generate the best matching attack rate
+ for ( Bit8u i = 0; i < 62; i++ ) {
+ Bit8u index, shift;
+ EnvelopeSelect( i, index, shift );
+ //Original amount of samples the attack would take
+ Bit32s original = (Bit32u)( (AttackSamplesTable[ index ] << shift) / scale);
+
+ Bit32s guessAdd = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH - shift - 3 )));
+ Bit32s bestAdd = guessAdd;
+ Bit32u bestDiff = 1 << 30;
+ for( Bit32u passes = 0; passes < 16; passes ++ ) {
+ Bit32s volume = ENV_MAX;
+ Bit32s samples = 0;
+ Bit32u count = 0;
+ while ( volume > 0 && samples < original * 2 ) {
+ count += guessAdd;
+ Bit32s change = count >> RATE_SH;
+ count &= RATE_MASK;
+ if ( GCC_UNLIKELY(change) ) { // less than 1 %
+ volume += ( ~volume * change ) >> 3;
+ }
+ samples++;
+
+ }
+ Bit32s diff = original - samples;
+ Bit32u lDiff = labs( diff );
+ //Init last on first pass
+ if ( lDiff < bestDiff ) {
+ bestDiff = lDiff;
+ bestAdd = guessAdd;
+ if ( !bestDiff )
+ break;
+ }
+ //Below our target
+ if ( diff < 0 ) {
+ //Better than the last time
+ Bit32s mul = ((original - diff) << 12) / original;
+ guessAdd = ((guessAdd * mul) >> 12);
+ guessAdd++;
+ } else if ( diff > 0 ) {
+ Bit32s mul = ((original - diff) << 12) / original;
+ guessAdd = (guessAdd * mul) >> 12;
+ guessAdd--;
+ }
+ }
+ attackRates[i] = bestAdd;
+ }
+ for ( Bit8u i = 62; i < 76; i++ ) {
+ //This should provide instant volume maximizing
+ attackRates[i] = 8 << RATE_SH;
+ }
+ //Setup the channels with the correct four op flags
+ //Channels are accessed through a table so they appear linear here
+ chan[ 0].fourMask = 0x00 | ( 1 << 0 );
+ chan[ 1].fourMask = 0x80 | ( 1 << 0 );
+ chan[ 2].fourMask = 0x00 | ( 1 << 1 );
+ chan[ 3].fourMask = 0x80 | ( 1 << 1 );
+ chan[ 4].fourMask = 0x00 | ( 1 << 2 );
+ chan[ 5].fourMask = 0x80 | ( 1 << 2 );
+
+ chan[ 9].fourMask = 0x00 | ( 1 << 3 );
+ chan[10].fourMask = 0x80 | ( 1 << 3 );
+ chan[11].fourMask = 0x00 | ( 1 << 4 );
+ chan[12].fourMask = 0x80 | ( 1 << 4 );
+ chan[13].fourMask = 0x00 | ( 1 << 5 );
+ chan[14].fourMask = 0x80 | ( 1 << 5 );
+
+ //mark the percussion channels
+ chan[ 6].fourMask = 0x40;
+ chan[ 7].fourMask = 0x40;
+ chan[ 8].fourMask = 0x40;
+
+ //Clear Everything in opl3 mode
+ WriteReg( 0x105, 0x1 );
+ for ( int i = 0; i < 512; i++ ) {
+ if ( i == 0x105 )
+ continue;
+ WriteReg( i, 0xff );
+ WriteReg( i, 0x0 );
+ }
+ WriteReg( 0x105, 0x0 );
+ //Clear everything in opl2 mode
+ for ( int i = 0; i < 255; i++ ) {
+ WriteReg( i, 0xff );
+ WriteReg( i, 0x0 );
+ }
+}
+
+static bool doneTables = false;
+void InitTables( void ) {
+ if ( doneTables )
+ return;
+ doneTables = true;
+#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG )
+ //Exponential volume table, same as the real adlib
+ for ( int i = 0; i < 256; i++ ) {
+ //Save them in reverse
+ ExpTable[i] = (int)( 0.5 + ( pow(2.0, ( 255 - i) * ( 1.0 /256 ) )-1) * 1024 );
+ ExpTable[i] += 1024; //or remove the -1 oh well :)
+ //Preshift to the left once so the final volume can shift to the right
+ ExpTable[i] *= 2;
+ }
+#endif
+#if ( DBOPL_WAVE == WAVE_HANDLER )
+ //Add 0.5 for the trunc rounding of the integer cast
+ //Do a PI sinetable instead of the original 0.5 PI
+ for ( int i = 0; i < 512; i++ ) {
+ SinTable[i] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 );
+ }
+#endif
+#if ( DBOPL_WAVE == WAVE_TABLEMUL )
+ //Multiplication based tables
+ for ( int i = 0; i < 384; i++ ) {
+ int s = i * 8;
+ //TODO maybe keep some of the precision errors of the original table?
+ double val = ( 0.5 + ( pow(2.0, -1.0 + ( 255 - s) * ( 1.0 /256 ) )) * ( 1 << MUL_SH ));
+ MulTable[i] = (Bit16u)(val);
+ }
+
+ //Sine Wave Base
+ for ( int i = 0; i < 512; i++ ) {
+ WaveTable[ 0x0200 + i ] = (Bit16s)(sin( (i + 0.5) * (PI / 512.0) ) * 4084);
+ WaveTable[ 0x0000 + i ] = -WaveTable[ 0x200 + i ];
+ }
+ //Exponential wave
+ for ( int i = 0; i < 256; i++ ) {
+ WaveTable[ 0x700 + i ] = (Bit16s)( 0.5 + ( pow(2.0, -1.0 + ( 255 - i * 8) * ( 1.0 /256 ) ) ) * 4085 );
+ WaveTable[ 0x6ff - i ] = -WaveTable[ 0x700 + i ];
+ }
+#endif
+#if ( DBOPL_WAVE == WAVE_TABLELOG )
+ //Sine Wave Base
+ for ( int i = 0; i < 512; i++ ) {
+ WaveTable[ 0x0200 + i ] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 );
+ WaveTable[ 0x0000 + i ] = ((Bit16s)0x8000) | WaveTable[ 0x200 + i];
+ }
+ //Exponential wave
+ for ( int i = 0; i < 256; i++ ) {
+ WaveTable[ 0x700 + i ] = i * 8;
+ WaveTable[ 0x6ff - i ] = ((Bit16s)0x8000) | i * 8;
+ }
+#endif
+
+ // | |//\\|____|WAV7|//__|/\ |____|/\/\|
+ // |\\//| | |WAV7| | \/| | |
+ // |06 |0126|27 |7 |3 |4 |4 5 |5 |
+
+#if (( DBOPL_WAVE == WAVE_TABLELOG ) || ( DBOPL_WAVE == WAVE_TABLEMUL ))
+ for ( int i = 0; i < 256; i++ ) {
+ //Fill silence gaps
+ WaveTable[ 0x400 + i ] = WaveTable[0];
+ WaveTable[ 0x500 + i ] = WaveTable[0];
+ WaveTable[ 0x900 + i ] = WaveTable[0];
+ WaveTable[ 0xc00 + i ] = WaveTable[0];
+ WaveTable[ 0xd00 + i ] = WaveTable[0];
+ //Replicate sines in other pieces
+ WaveTable[ 0x800 + i ] = WaveTable[ 0x200 + i ];
+ //double speed sines
+ WaveTable[ 0xa00 + i ] = WaveTable[ 0x200 + i * 2 ];
+ WaveTable[ 0xb00 + i ] = WaveTable[ 0x000 + i * 2 ];
+ WaveTable[ 0xe00 + i ] = WaveTable[ 0x200 + i * 2 ];
+ WaveTable[ 0xf00 + i ] = WaveTable[ 0x200 + i * 2 ];
+ }
+#endif
+
+ //Create the ksl table
+ for ( int oct = 0; oct < 8; oct++ ) {
+ int base = oct * 8;
+ for ( int i = 0; i < 16; i++ ) {
+ int val = base - KslCreateTable[i];
+ if ( val < 0 )
+ val = 0;
+ //*4 for the final range to match attenuation range
+ KslTable[ oct * 16 + i ] = val * 4;
+ }
+ }
+ //Create the Tremolo table, just increase and decrease a triangle wave
+ for ( Bit8u i = 0; i < TREMOLO_TABLE / 2; i++ ) {
+ Bit8u val = i << ENV_EXTRA;
+ TremoloTable[i] = val;
+ TremoloTable[TREMOLO_TABLE - 1 - i] = val;
+ }
+ //Create a table with offsets of the channels from the start of the chip
+ DBOPL::Chip* chip = 0;
+ for ( Bitu i = 0; i < 32; i++ ) {
+ Bitu index = i & 0xf;
+ if ( index >= 9 ) {
+ ChanOffsetTable[i] = 0;
+ continue;
+ }
+ //Make sure the four op channels follow eachother
+ if ( index < 6 ) {
+ index = (index % 3) * 2 + ( index / 3 );
+ }
+ //Add back the bits for highest ones
+ if ( i >= 16 )
+ index += 9;
+ Bitu blah = reinterpret_cast<long>( &(chip->chan[ index ]) );
+ ChanOffsetTable[i] = blah;
+ }
+ //Same for operators
+ for ( Bitu i = 0; i < 64; i++ ) {
+ if ( i % 8 >= 6 || ( (i / 8) % 4 == 3 ) ) {
+ OpOffsetTable[i] = 0;
+ continue;
+ }
+ Bitu chNum = (i / 8) * 3 + (i % 8) % 3;
+ //Make sure we use 16 and up for the 2nd range to match the chanoffset gap
+ if ( chNum >= 12 )
+ chNum += 16 - 12;
+ Bitu opNum = ( i % 8 ) / 3;
+ DBOPL::Channel* chan = 0;
+ Bitu blah = reinterpret_cast<long>( &(chan->op[opNum]) );
+ OpOffsetTable[i] = ChanOffsetTable[ chNum ] + blah;
+ }
+#if 0
+ //Stupid checks if table's are correct
+ for ( Bitu i = 0; i < 18; i++ ) {
+ Bit32u find = (Bit16u)( &(chip->chan[ i ]) );
+ for ( Bitu c = 0; c < 32; c++ ) {
+ if ( ChanOffsetTable[c] == find ) {
+ find = 0;
+ break;
+ }
+ }
+ if ( find ) {
+ find = find;
+ }
+ }
+ for ( Bitu i = 0; i < 36; i++ ) {
+ Bit32u find = (Bit16u)( &(chip->chan[ i / 2 ].op[i % 2]) );
+ for ( Bitu c = 0; c < 64; c++ ) {
+ if ( OpOffsetTable[c] == find ) {
+ find = 0;
+ break;
+ }
+ }
+ if ( find ) {
+ find = find;
+ }
+ }
+#endif
+}
+
+} //Namespace DBOPL
+} // End of namespace DOSBox
+} // End of namespace OPL
+
+#endif // !DISABLE_DOSBOX_OPL
diff --git a/sound/softsynth/opl/dbopl.h b/sound/softsynth/opl/dbopl.h
new file mode 100644
index 0000000000..b595f3edf9
--- /dev/null
+++ b/sound/softsynth/opl/dbopl.h
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2002-2010 The DOSBox Team
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef SOUND_SOFTSYNTH_OPL_DBOPL_H
+#define SOUND_SOFTSYNTH_OPL_DBOPL_H
+
+#include "common/scummsys.h"
+
+#ifndef DISABLE_DOSBOX_OPL
+
+namespace OPL {
+namespace DOSBox {
+
+//Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume
+#define WAVE_HANDLER 10
+//Use a logarithmic wavetable with an exponential table for volume
+#define WAVE_TABLELOG 11
+//Use a linear wavetable with a multiply table for volume
+#define WAVE_TABLEMUL 12
+
+//Select the type of wave generator routine
+#define DBOPL_WAVE WAVE_TABLEMUL
+
+namespace DBOPL {
+
+// Type aliases for the DBOPL code
+typedef int Bits;
+typedef uint Bitu;
+
+typedef int8 Bit8s;
+typedef uint8 Bit8u;
+
+typedef int16 Bit16s;
+typedef uint16 Bit16u;
+
+typedef int32 Bit32s;
+typedef uint32 Bit32u;
+
+#define DB_FASTCALL
+#define GCC_UNLIKELY(x) (x)
+#define INLINE inline
+// -------------------------------
+
+struct Chip;
+struct Operator;
+struct Channel;
+
+#if (DBOPL_WAVE == WAVE_HANDLER)
+typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume );
+#endif
+
+typedef Bits ( DBOPL::Operator::*VolumeHandler) ( );
+typedef Channel* ( DBOPL::Channel::*SynthHandler) ( Chip* chip, Bit32u samples, Bit32s* output );
+
+//Different synth modes that can generate blocks of data
+typedef enum {
+ sm2AM,
+ sm2FM,
+ sm3AM,
+ sm3FM,
+ sm4Start,
+ sm3FMFM,
+ sm3AMFM,
+ sm3FMAM,
+ sm3AMAM,
+ sm6Start,
+ sm2Percussion,
+ sm3Percussion
+} SynthMode;
+
+//Shifts for the values contained in chandata variable
+enum {
+ SHIFT_KSLBASE = 16,
+ SHIFT_KEYCODE = 24
+};
+
+struct Operator {
+public:
+ //Masks for operator 20 values
+ enum {
+ MASK_KSR = 0x10,
+ MASK_SUSTAIN = 0x20,
+ MASK_VIBRATO = 0x40,
+ MASK_TREMOLO = 0x80
+ };
+
+ typedef enum {
+ OFF,
+ RELEASE,
+ SUSTAIN,
+ DECAY,
+ ATTACK
+ } State;
+
+ VolumeHandler volHandler;
+
+#if (DBOPL_WAVE == WAVE_HANDLER)
+ WaveHandler waveHandler; //Routine that generate a wave
+#else
+ Bit16s* waveBase;
+ Bit32u waveMask;
+ Bit32u waveStart;
+#endif
+ Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index
+ Bit32u waveAdd; //The base frequency without vibrato
+ Bit32u waveCurrent; //waveAdd + vibratao
+
+ Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this
+ Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove?
+ Bit32u vibrato; //Scaled up vibrato strength
+ Bit32s sustainLevel; //When stopping at sustain level stop here
+ Bit32s totalLevel; //totalLevel is added to every generated volume
+ Bit32u currentLevel; //totalLevel + tremolo
+ Bit32s volume; //The currently active volume
+
+ Bit32u attackAdd; //Timers for the different states of the envelope
+ Bit32u decayAdd;
+ Bit32u releaseAdd;
+ Bit32u rateIndex; //Current position of the evenlope
+
+ Bit8u rateZero; //Bits for the different states of the envelope having no changes
+ Bit8u keyOn; //Bitmask of different values that can generate keyon
+ //Registers, also used to check for changes
+ Bit8u reg20, reg40, reg60, reg80, regE0;
+ //Active part of the envelope we're in
+ Bit8u state;
+ //0xff when tremolo is enabled
+ Bit8u tremoloMask;
+ //Strength of the vibrato
+ Bit8u vibStrength;
+ //Keep track of the calculated KSR so we can check for changes
+ Bit8u ksr;
+private:
+ void SetState( Bit8u s );
+ void UpdateAttack( const Chip* chip );
+ void UpdateRelease( const Chip* chip );
+ void UpdateDecay( const Chip* chip );
+public:
+ void UpdateAttenuation();
+ void UpdateRates( const Chip* chip );
+ void UpdateFrequency( );
+
+ void Write20( const Chip* chip, Bit8u val );
+ void Write40( const Chip* chip, Bit8u val );
+ void Write60( const Chip* chip, Bit8u val );
+ void Write80( const Chip* chip, Bit8u val );
+ void WriteE0( const Chip* chip, Bit8u val );
+
+ bool Silent() const;
+ void Prepare( const Chip* chip );
+
+ void KeyOn( Bit8u mask);
+ void KeyOff( Bit8u mask);
+
+ template< State state>
+ Bits TemplateVolume( );
+
+ Bit32s RateForward( Bit32u add );
+ Bitu ForwardWave();
+ Bitu ForwardVolume();
+
+ Bits GetSample( Bits modulation );
+ Bits GetWave( Bitu index, Bitu vol );
+public:
+ Operator();
+};
+
+struct Channel {
+ Operator op[2];
+ inline Operator* Op( Bitu index ) {
+ return &( ( this + (index >> 1) )->op[ index & 1 ]);
+ }
+ SynthHandler synthHandler;
+ Bit32u chanData; //Frequency/octave and derived values
+ Bit32s old[2]; //Old data for feedback
+
+ Bit8u feedback; //Feedback shift
+ Bit8u regB0; //Register values to check for changes
+ Bit8u regC0;
+ //This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel
+ Bit8u fourMask;
+ Bit8s maskLeft; //Sign extended values for both channel's panning
+ Bit8s maskRight;
+
+ //Forward the channel data to the operators of the channel
+ void SetChanData( const Chip* chip, Bit32u data );
+ //Change in the chandata, check for new values and if we have to forward to operators
+ void UpdateFrequency( const Chip* chip, Bit8u fourOp );
+ void WriteA0( const Chip* chip, Bit8u val );
+ void WriteB0( const Chip* chip, Bit8u val );
+ void WriteC0( const Chip* chip, Bit8u val );
+ void ResetC0( const Chip* chip );
+
+ //call this for the first channel
+ template< bool opl3Mode >
+ void GeneratePercussion( Chip* chip, Bit32s* output );
+
+ //Generate blocks of data in specific modes
+ template<SynthMode mode>
+ Channel* BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output );
+ Channel();
+};
+
+struct Chip {
+ //This is used as the base counter for vibrato and tremolo
+ Bit32u lfoCounter;
+ Bit32u lfoAdd;
+
+
+ Bit32u noiseCounter;
+ Bit32u noiseAdd;
+ Bit32u noiseValue;
+
+ //Frequency scales for the different multiplications
+ Bit32u freqMul[16];
+ //Rates for decay and release for rate of this chip
+ Bit32u linearRates[76];
+ //Best match attack rates for the rate of this chip
+ Bit32u attackRates[76];
+
+ //18 channels with 2 operators each
+ Channel chan[18];
+
+ Bit8u reg104;
+ Bit8u reg08;
+ Bit8u reg04;
+ Bit8u regBD;
+ Bit8u vibratoIndex;
+ Bit8u tremoloIndex;
+ Bit8s vibratoSign;
+ Bit8u vibratoShift;
+ Bit8u tremoloValue;
+ Bit8u vibratoStrength;
+ Bit8u tremoloStrength;
+ //Mask for allowed wave forms
+ Bit8u waveFormMask;
+ //0 or -1 when enabled
+ Bit8s opl3Active;
+
+ //Return the maximum amount of samples before and LFO change
+ Bit32u ForwardLFO( Bit32u samples );
+ Bit32u ForwardNoise();
+
+ void WriteBD( Bit8u val );
+ void WriteReg(Bit32u reg, Bit8u val );
+
+ Bit32u WriteAddr( Bit32u port, Bit8u val );
+
+ void GenerateBlock2( Bitu samples, Bit32s* output );
+ void GenerateBlock3( Bitu samples, Bit32s* output );
+
+ void Generate( Bit32u samples );
+ void Setup( Bit32u r );
+
+ Chip();
+};
+
+void InitTables();
+
+} //Namespace
+} // End of namespace DOSBox
+} // End of namespace OPL
+
+#endif // !DISABLE_DOSBOX_OPL
+
+#endif
diff --git a/sound/softsynth/opl/dosbox.cpp b/sound/softsynth/opl/dosbox.cpp
index 9b3cab57c6..7de66af9f5 100644
--- a/sound/softsynth/opl/dosbox.cpp
+++ b/sound/softsynth/opl/dosbox.cpp
@@ -144,53 +144,7 @@ uint8 Chip::read() {
return ret;
}
-namespace OPL2 {
-#include "opl_impl.h"
-
-struct Handler : public DOSBox::Handler {
- void writeReg(uint32 reg, uint8 val) {
- adlib_write(reg, val);
- }
-
- uint32 writeAddr(uint32 port, uint8 val) {
- return val;
- }
-
- void generate(int16 *chan, uint samples) {
- adlib_getsample(chan, samples);
- }
-
- void init(uint rate) {
- adlib_init(rate);
- }
-};
-} // End of namespace OPL2
-
-namespace OPL3 {
-#define OPLTYPE_IS_OPL3
-#include "opl_impl.h"
-
-struct Handler : public DOSBox::Handler {
- void writeReg(uint32 reg, uint8 val) {
- adlib_write(reg, val);
- }
-
- uint32 writeAddr(uint32 port, uint8 val) {
- adlib_write_index(port, val);
- return opl_index;
- }
-
- void generate(int16 *chan, uint samples) {
- adlib_getsample(chan, samples);
- }
-
- void init(uint rate) {
- adlib_init(rate);
- }
-};
-} // End of namespace OPL3
-
-OPL::OPL(Config::OplType type) : _type(type), _rate(0), _handler(0) {
+OPL::OPL(Config::OplType type) : _type(type), _rate(0), _emulator(0) {
}
OPL::~OPL() {
@@ -198,8 +152,8 @@ OPL::~OPL() {
}
void OPL::free() {
- delete _handler;
- _handler = 0;
+ delete _emulator;
+ _emulator = 0;
}
bool OPL::init(int rate) {
@@ -208,25 +162,16 @@ bool OPL::init(int rate) {
memset(&_reg, 0, sizeof(_reg));
memset(_chip, 0, sizeof(_chip));
- switch (_type) {
- case Config::kOpl2:
- _handler = new OPL2::Handler();
- break;
-
- case Config::kDualOpl2:
- case Config::kOpl3:
- _handler = new OPL3::Handler();
- break;
-
- default:
+ _emulator = new DBOPL::Chip();
+ if (!_emulator)
return false;
- }
- _handler->init(rate);
+ DBOPL::InitTables();
+ _emulator->Setup(rate);
if (_type == Config::kDualOpl2) {
// Setup opl3 mode in the hander
- _handler->writeReg(0x105, 1);
+ _emulator->WriteReg(0x105, 1);
}
_rate = rate;
@@ -243,7 +188,7 @@ void OPL::write(int port, int val) {
case Config::kOpl2:
case Config::kOpl3:
if (!_chip[0].write(_reg.normal, val))
- _handler->writeReg(_reg.normal, val);
+ _emulator->WriteReg(_reg.normal, val);
break;
case Config::kDualOpl2:
// Not a 0x??8 port, then write to a specific port
@@ -262,10 +207,10 @@ void OPL::write(int port, int val) {
// Make sure to clip them in the right range
switch (_type) {
case Config::kOpl2:
- _reg.normal = _handler->writeAddr(port, val) & 0xff;
+ _reg.normal = _emulator->WriteAddr(port, val) & 0xff;
break;
case Config::kOpl3:
- _reg.normal = _handler->writeAddr(port, val) & 0x1ff;
+ _reg.normal = _emulator->WriteAddr(port, val) & 0x1ff;
break;
case Config::kDualOpl2:
// Not a 0x?88 port, when write to a specific side
@@ -344,7 +289,7 @@ void OPL::dualWrite(uint8 index, uint8 reg, uint8 val) {
}
uint32 fullReg = reg + (index ? 0x100 : 0);
- _handler->writeReg(fullReg, val);
+ _emulator->WriteReg(fullReg, val);
}
void OPL::readBuffer(int16 *buffer, int length) {
@@ -353,7 +298,34 @@ void OPL::readBuffer(int16 *buffer, int length) {
if (_type != Config::kOpl2)
length >>= 1;
- _handler->generate(buffer, length);
+ const uint bufferLength = 512;
+ int32 tempBuffer[bufferLength * 2];
+
+ if (_emulator->opl3Active) {
+ while (length > 0) {
+ const uint readSamples = MIN<uint>(length, bufferLength);
+
+ _emulator->GenerateBlock3(readSamples, tempBuffer);
+
+ for (uint i = 0; i < (readSamples << 1); ++i)
+ buffer[i] = tempBuffer[i];
+
+ buffer += (readSamples << 1);
+ length -= readSamples;
+ }
+ } else {
+ while (length > 0) {
+ const uint readSamples = MIN<uint>(length, bufferLength << 1);
+
+ _emulator->GenerateBlock2(readSamples, tempBuffer);
+
+ for (uint i = 0; i < readSamples; ++i)
+ buffer[i] = tempBuffer[i];
+
+ buffer += readSamples;
+ length -= readSamples;
+ }
+ }
}
} // End of namespace DOSBox
diff --git a/sound/softsynth/opl/dosbox.h b/sound/softsynth/opl/dosbox.h
index 4e27e3088a..4018678806 100644
--- a/sound/softsynth/opl/dosbox.h
+++ b/sound/softsynth/opl/dosbox.h
@@ -36,6 +36,8 @@
#include "sound/fmopl.h"
+#include "dbopl.h"
+
namespace OPL {
namespace DOSBox {
@@ -69,26 +71,12 @@ struct Chip {
uint8 read();
};
-class Handler {
-public:
- virtual ~Handler() {}
-
- // Write an address to a chip, returns the address the chip sets
- virtual uint32 writeAddr(uint32 port, uint8 val) = 0;
- // Write to a specific register in the chip
- virtual void writeReg(uint32 addr, uint8 val) = 0;
- // Generate a certain amount of samples
- virtual void generate(int16 *chan, uint samples) = 0;
- // Initialize at a specific sample rate and mode
- virtual void init(uint rate) = 0;
-};
-
class OPL : public ::OPL::OPL {
private:
Config::OplType _type;
uint _rate;
- Handler *_handler;
+ DBOPL::Chip *_emulator;
Chip _chip[2];
union {
uint16 normal;
diff --git a/sound/softsynth/opl/opl_impl.h b/sound/softsynth/opl/opl_impl.h
deleted file mode 100644
index 0df8b5f884..0000000000
--- a/sound/softsynth/opl/opl_impl.h
+++ /dev/null
@@ -1,1463 +0,0 @@
-/*
- * Copyright (C) 2002-2009 The DOSBox Team
- * OPL2/OPL3 emulation library
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-
-/*
- * Originally based on ADLIBEMU.C, an AdLib/OPL2 emulation library by Ken Silverman
- * Copyright (C) 1998-2001 Ken Silverman
- * Ken Silverman's official web site: "http://www.advsys.net/ken"
- */
-
-#include "opl_inc.h"
-
-
-static fltype recipsamp; // inverse of sampling rate
-static Bit16s wavtable[WAVEPREC*3]; // wave form table
-
-// vibrato/tremolo tables
-static Bit32s vib_table[VIBTAB_SIZE];
-static Bit32s trem_table[TREMTAB_SIZE*2];
-
-static Bit32s vibval_const[BLOCKBUF_SIZE];
-static Bit32s tremval_const[BLOCKBUF_SIZE];
-
-// vibrato value tables (used per-operator)
-static Bit32s vibval_var1[BLOCKBUF_SIZE];
-static Bit32s vibval_var2[BLOCKBUF_SIZE];
-
-// vibrato/trmolo value table pointers
-static Bit32s *vibval1, *vibval2, *vibval3, *vibval4;
-static Bit32s *tremval1, *tremval2, *tremval3, *tremval4;
-
-
-// key scale level lookup table
-static const fltype kslmul[4] = {
- 0.0, 0.5, 0.25, 1.0 // -> 0, 3, 1.5, 6 dB/oct
-};
-
-// frequency multiplicator lookup table
-static const fltype frqmul_tab[16] = {
- 0.5,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15
-};
-// calculated frequency multiplication values (depend on sampling rate)
-static fltype frqmul[16];
-
-// key scale levels
-static Bit8u kslev[8][16];
-
-// map a channel number to the register offset of the modulator (=register base)
-static const Bit8u modulatorbase[9] = {
- 0,1,2,
- 8,9,10,
- 16,17,18
-};
-
-// map a register base to a modulator operator number or operator number
-#if defined(OPLTYPE_IS_OPL3)
-static const Bit8u regbase2modop[44] = {
- 0,1,2,0,1,2,0,0,3,4,5,3,4,5,0,0,6,7,8,6,7,8, // first set
- 18,19,20,18,19,20,0,0,21,22,23,21,22,23,0,0,24,25,26,24,25,26 // second set
-};
-static const Bit8u regbase2op[44] = {
- 0,1,2,9,10,11,0,0,3,4,5,12,13,14,0,0,6,7,8,15,16,17, // first set
- 18,19,20,27,28,29,0,0,21,22,23,30,31,32,0,0,24,25,26,33,34,35 // second set
-};
-#else
-static const Bit8u regbase2modop[22] = {
- 0,1,2,0,1,2,0,0,3,4,5,3,4,5,0,0,6,7,8,6,7,8
-};
-static const Bit8u regbase2op[22] = {
- 0,1,2,9,10,11,0,0,3,4,5,12,13,14,0,0,6,7,8,15,16,17
-};
-#endif
-
-
-// start of the waveform
-static Bit32u waveform[8] = {
- WAVEPREC,
- WAVEPREC>>1,
- WAVEPREC,
- (WAVEPREC*3)>>2,
- 0,
- 0,
- (WAVEPREC*5)>>2,
- WAVEPREC<<1
-};
-
-// length of the waveform as mask
-static Bit32u wavemask[8] = {
- WAVEPREC-1,
- WAVEPREC-1,
- (WAVEPREC>>1)-1,
- (WAVEPREC>>1)-1,
- WAVEPREC-1,
- ((WAVEPREC*3)>>2)-1,
- WAVEPREC>>1,
- WAVEPREC-1
-};
-
-// where the first entry resides
-static Bit32u wavestart[8] = {
- 0,
- WAVEPREC>>1,
- 0,
- WAVEPREC>>2,
- 0,
- 0,
- 0,
- WAVEPREC>>3
-};
-
-// envelope generator function constants
-static fltype attackconst[4] = {
- (fltype)(1/2.82624),
- (fltype)(1/2.25280),
- (fltype)(1/1.88416),
- (fltype)(1/1.59744)
-};
-static fltype decrelconst[4] = {
- (fltype)(1/39.28064),
- (fltype)(1/31.41608),
- (fltype)(1/26.17344),
- (fltype)(1/22.44608)
-};
-
-
-void operator_advance(op_type* op_pt, Bit32s vib) {
- op_pt->wfpos = op_pt->tcount; // waveform position
-
- // advance waveform time
- op_pt->tcount += op_pt->tinc;
- op_pt->tcount += (Bit32s)(op_pt->tinc)*vib/FIXEDPT;
-
- op_pt->generator_pos += generator_add;
-}
-
-void operator_advance_drums(op_type* op_pt1, Bit32s vib1, op_type* op_pt2, Bit32s vib2, op_type* op_pt3, Bit32s vib3) {
- Bit32u c1 = op_pt1->tcount/FIXEDPT;
- Bit32u c3 = op_pt3->tcount/FIXEDPT;
- Bit32u phasebit = (((c1 & 0x88) ^ ((c1<<5) & 0x80)) | ((c3 ^ (c3<<2)) & 0x20)) ? 0x02 : 0x00;
-
- Bit32u noisebit = rand()&1;
-
- Bit32u snare_phase_bit = (((Bitu)((op_pt1->tcount/FIXEDPT) / 0x100))&1);
-
- //Hihat
- Bit32u inttm = (phasebit<<8) | (0x34<<(phasebit ^ (noisebit<<1)));
- op_pt1->wfpos = inttm*FIXEDPT; // waveform position
- // advance waveform time
- op_pt1->tcount += op_pt1->tinc;
- op_pt1->tcount += (Bit32s)(op_pt1->tinc)*vib1/FIXEDPT;
- op_pt1->generator_pos += generator_add;
-
- //Snare
- inttm = ((1+snare_phase_bit) ^ noisebit)<<8;
- op_pt2->wfpos = inttm*FIXEDPT; // waveform position
- // advance waveform time
- op_pt2->tcount += op_pt2->tinc;
- op_pt2->tcount += (Bit32s)(op_pt2->tinc)*vib2/FIXEDPT;
- op_pt2->generator_pos += generator_add;
-
- //Cymbal
- inttm = (1+phasebit)<<8;
- op_pt3->wfpos = inttm*FIXEDPT; // waveform position
- // advance waveform time
- op_pt3->tcount += op_pt3->tinc;
- op_pt3->tcount += (Bit32s)(op_pt3->tinc)*vib3/FIXEDPT;
- op_pt3->generator_pos += generator_add;
-}
-
-
-// output level is sustained, mode changes only when operator is turned off (->release)
-// or when the keep-sustained bit is turned off (->sustain_nokeep)
-void operator_output(op_type* op_pt, Bit32s modulator, Bit32s trem) {
- if (op_pt->op_state != OF_TYPE_OFF) {
- op_pt->lastcval = op_pt->cval;
- Bit32u i = (Bit32u)((op_pt->wfpos+modulator)/FIXEDPT);
-
- // wform: -16384 to 16383 (0x4000)
- // trem : 32768 to 65535 (0x10000)
- // step_amp: 0.0 to 1.0
- // vol : 1/2^14 to 1/2^29 (/0x4000; /1../0x8000)
-
- op_pt->cval = (Bit32s)(op_pt->step_amp*op_pt->vol*op_pt->cur_wform[i&op_pt->cur_wmask]*trem/16.0);
- }
-}
-
-
-// no action, operator is off
-void operator_off(op_type* /*op_pt*/) {
-}
-
-// output level is sustained, mode changes only when operator is turned off (->release)
-// or when the keep-sustained bit is turned off (->sustain_nokeep)
-void operator_sustain(op_type* op_pt) {
- Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples
- for (Bit32u ct=0; ct<num_steps_add; ct++) {
- op_pt->cur_env_step++;
- }
- op_pt->generator_pos -= num_steps_add*FIXEDPT;
-}
-
-// operator in release mode, if output level reaches zero the operator is turned off
-void operator_release(op_type* op_pt) {
- // ??? boundary?
- if (op_pt->amp > 0.00000001) {
- // release phase
- op_pt->amp *= op_pt->releasemul;
- }
-
- Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples
- for (Bit32u ct=0; ct<num_steps_add; ct++) {
- op_pt->cur_env_step++; // sample counter
- if ((op_pt->cur_env_step & op_pt->env_step_r)==0) {
- if (op_pt->amp <= 0.00000001) {
- // release phase finished, turn off this operator
- op_pt->amp = 0.0;
- if (op_pt->op_state == OF_TYPE_REL) {
- op_pt->op_state = OF_TYPE_OFF;
- }
- }
- op_pt->step_amp = op_pt->amp;
- }
- }
- op_pt->generator_pos -= num_steps_add*FIXEDPT;
-}
-
-// operator in decay mode, if sustain level is reached the output level is either
-// kept (sustain level keep enabled) or the operator is switched into release mode
-void operator_decay(op_type* op_pt) {
- if (op_pt->amp > op_pt->sustain_level) {
- // decay phase
- op_pt->amp *= op_pt->decaymul;
- }
-
- Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples
- for (Bit32u ct=0; ct<num_steps_add; ct++) {
- op_pt->cur_env_step++;
- if ((op_pt->cur_env_step & op_pt->env_step_d)==0) {
- if (op_pt->amp <= op_pt->sustain_level) {
- // decay phase finished, sustain level reached
- if (op_pt->sus_keep) {
- // keep sustain level (until turned off)
- op_pt->op_state = OF_TYPE_SUS;
- op_pt->amp = op_pt->sustain_level;
- } else {
- // next: release phase
- op_pt->op_state = OF_TYPE_SUS_NOKEEP;
- }
- }
- op_pt->step_amp = op_pt->amp;
- }
- }
- op_pt->generator_pos -= num_steps_add*FIXEDPT;
-}
-
-// operator in attack mode, if full output level is reached,
-// the operator is switched into decay mode
-void operator_attack(op_type* op_pt) {
- op_pt->amp = ((op_pt->a3*op_pt->amp + op_pt->a2)*op_pt->amp + op_pt->a1)*op_pt->amp + op_pt->a0;
-
- Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples
- for (Bit32u ct=0; ct<num_steps_add; ct++) {
- op_pt->cur_env_step++; // next sample
- if ((op_pt->cur_env_step & op_pt->env_step_a)==0) { // check if next step already reached
- if (op_pt->amp > 1.0) {
- // attack phase finished, next: decay
- op_pt->op_state = OF_TYPE_DEC;
- op_pt->amp = 1.0;
- op_pt->step_amp = 1.0;
- }
- op_pt->step_skip_pos_a <<= 1;
- if (op_pt->step_skip_pos_a==0) op_pt->step_skip_pos_a = 1;
- if (op_pt->step_skip_pos_a & op_pt->env_step_skip_a) { // check if required to skip next step
- op_pt->step_amp = op_pt->amp;
- }
- }
- }
- op_pt->generator_pos -= num_steps_add*FIXEDPT;
-}
-
-
-typedef void (*optype_fptr)(op_type*);
-
-optype_fptr opfuncs[6] = {
- operator_attack,
- operator_decay,
- operator_release,
- operator_sustain, // sustain phase (keeping level)
- operator_release, // sustain_nokeep phase (release-style)
- operator_off
-};
-
-void change_attackrate(Bitu regbase, op_type* op_pt) {
- Bits attackrate = adlibreg[ARC_ATTR_DECR+regbase]>>4;
- if (attackrate) {
- fltype f = (fltype)(pow(FL2,(fltype)attackrate+(op_pt->toff>>2)-1)*attackconst[op_pt->toff&3]*recipsamp);
- // attack rate coefficients
- op_pt->a0 = (fltype)(0.0377*f);
- op_pt->a1 = (fltype)(10.73*f+1);
- op_pt->a2 = (fltype)(-17.57*f);
- op_pt->a3 = (fltype)(7.42*f);
-
- Bits step_skip = attackrate*4 + op_pt->toff;
- Bits steps = step_skip >> 2;
- op_pt->env_step_a = (1<<(steps<=12?12-steps:0))-1;
-
- Bits step_num = (step_skip<=48)?(4-(step_skip&3)):0;
- static Bit8u step_skip_mask[5] = {0xff, 0xfe, 0xee, 0xba, 0xaa};
- op_pt->env_step_skip_a = step_skip_mask[step_num];
-
-#if defined(OPLTYPE_IS_OPL3)
- if (step_skip>=60) {
-#else
- if (step_skip>=62) {
-#endif
- op_pt->a0 = (fltype)(2.0); // something that triggers an immediate transition to amp:=1.0
- op_pt->a1 = (fltype)(0.0);
- op_pt->a2 = (fltype)(0.0);
- op_pt->a3 = (fltype)(0.0);
- }
- } else {
- // attack disabled
- op_pt->a0 = 0.0;
- op_pt->a1 = 1.0;
- op_pt->a2 = 0.0;
- op_pt->a3 = 0.0;
- op_pt->env_step_a = 0;
- op_pt->env_step_skip_a = 0;
- }
-}
-
-void change_decayrate(Bitu regbase, op_type* op_pt) {
- Bits decayrate = adlibreg[ARC_ATTR_DECR+regbase]&15;
- // decaymul should be 1.0 when decayrate==0
- if (decayrate) {
- fltype f = (fltype)(-7.4493*decrelconst[op_pt->toff&3]*recipsamp);
- op_pt->decaymul = (fltype)(pow(FL2,f*pow(FL2,(fltype)(decayrate+(op_pt->toff>>2)))));
- Bits steps = (decayrate*4 + op_pt->toff) >> 2;
- op_pt->env_step_d = (1<<(steps<=12?12-steps:0))-1;
- } else {
- op_pt->decaymul = 1.0;
- op_pt->env_step_d = 0;
- }
-}
-
-void change_releaserate(Bitu regbase, op_type* op_pt) {
- Bits releaserate = adlibreg[ARC_SUSL_RELR+regbase]&15;
- // releasemul should be 1.0 when releaserate==0
- if (releaserate) {
- fltype f = (fltype)(-7.4493*decrelconst[op_pt->toff&3]*recipsamp);
- op_pt->releasemul = (fltype)(pow(FL2,f*pow(FL2,(fltype)(releaserate+(op_pt->toff>>2)))));
- Bits steps = (releaserate*4 + op_pt->toff) >> 2;
- op_pt->env_step_r = (1<<(steps<=12?12-steps:0))-1;
- } else {
- op_pt->releasemul = 1.0;
- op_pt->env_step_r = 0;
- }
-}
-
-void change_sustainlevel(Bitu regbase, op_type* op_pt) {
- Bits sustainlevel = adlibreg[ARC_SUSL_RELR+regbase]>>4;
- // sustainlevel should be 0.0 when sustainlevel==15 (max)
- if (sustainlevel<15) {
- op_pt->sustain_level = (fltype)(pow(FL2,(fltype)sustainlevel * (-FL05)));
- } else {
- op_pt->sustain_level = 0.0;
- }
-}
-
-void change_waveform(Bitu regbase, op_type* op_pt) {
-#if defined(OPLTYPE_IS_OPL3)
- if (regbase>=ARC_SECONDSET) regbase -= (ARC_SECONDSET-22); // second set starts at 22
-#endif
- // waveform selection
- op_pt->cur_wmask = wavemask[wave_sel[regbase]];
- op_pt->cur_wform = &wavtable[waveform[wave_sel[regbase]]];
- // (might need to be adapted to waveform type here...)
-}
-
-void change_keepsustain(Bitu regbase, op_type* op_pt) {
- op_pt->sus_keep = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x20)>0;
- if (op_pt->op_state==OF_TYPE_SUS) {
- if (!op_pt->sus_keep) op_pt->op_state = OF_TYPE_SUS_NOKEEP;
- } else if (op_pt->op_state==OF_TYPE_SUS_NOKEEP) {
- if (op_pt->sus_keep) op_pt->op_state = OF_TYPE_SUS;
- }
-}
-
-// enable/disable vibrato/tremolo LFO effects
-void change_vibrato(Bitu regbase, op_type* op_pt) {
- op_pt->vibrato = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x40)!=0;
- op_pt->tremolo = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x80)!=0;
-}
-
-// change amount of self-feedback
-void change_feedback(Bitu chanbase, op_type* op_pt) {
- Bits feedback = adlibreg[ARC_FEEDBACK+chanbase]&14;
- if (feedback) op_pt->mfbi = (Bit32s)(pow(FL2,(fltype)((feedback>>1)+8)));
- else op_pt->mfbi = 0;
-}
-
-void change_frequency(Bitu chanbase, Bitu regbase, op_type* op_pt) {
- // frequency
- Bit32u frn = ((((Bit32u)adlibreg[ARC_KON_BNUM+chanbase])&3)<<8) + (Bit32u)adlibreg[ARC_FREQ_NUM+chanbase];
- // block number/octave
- Bit32u oct = ((((Bit32u)adlibreg[ARC_KON_BNUM+chanbase])>>2)&7);
- op_pt->freq_high = (Bit32s)((frn>>7)&7);
-
- // keysplit
- Bit32u note_sel = (adlibreg[8]>>6)&1;
- op_pt->toff = ((frn>>9)&(note_sel^1)) | ((frn>>8)&note_sel);
- op_pt->toff += (oct<<1);
-
- // envelope scaling (KSR)
- if (!(adlibreg[ARC_TVS_KSR_MUL+regbase]&0x10)) op_pt->toff >>= 2;
-
- // 20+a0+b0:
- op_pt->tinc = (Bit32u)((((fltype)(frn<<oct))*frqmul[adlibreg[ARC_TVS_KSR_MUL+regbase]&15]));
- // 40+a0+b0:
- fltype vol_in = (fltype)((fltype)(adlibreg[ARC_KSL_OUTLEV+regbase]&63) +
- kslmul[adlibreg[ARC_KSL_OUTLEV+regbase]>>6]*kslev[oct][frn>>6]);
- op_pt->vol = (fltype)(pow(FL2,(fltype)(vol_in * -0.125 - 14)));
-
- // operator frequency changed, care about features that depend on it
- change_attackrate(regbase,op_pt);
- change_decayrate(regbase,op_pt);
- change_releaserate(regbase,op_pt);
-}
-
-void enable_operator(Bitu regbase, op_type* op_pt, Bit32u act_type) {
- // check if this is really an off-on transition
- if (op_pt->act_state == OP_ACT_OFF) {
- Bits wselbase = regbase;
- if (wselbase>=ARC_SECONDSET) wselbase -= (ARC_SECONDSET-22); // second set starts at 22
-
- op_pt->tcount = wavestart[wave_sel[wselbase]]*FIXEDPT;
-
- // start with attack mode
- op_pt->op_state = OF_TYPE_ATT;
- op_pt->act_state |= act_type;
- }
-}
-
-void disable_operator(op_type* op_pt, Bit32u act_type) {
- // check if this is really an on-off transition
- if (op_pt->act_state != OP_ACT_OFF) {
- op_pt->act_state &= (~act_type);
- if (op_pt->act_state == OP_ACT_OFF) {
- if (op_pt->op_state != OF_TYPE_OFF) op_pt->op_state = OF_TYPE_REL;
- }
- }
-}
-
-void adlib_init(Bit32u samplerate) {
- Bits i, j, oct;
-
- int_samplerate = samplerate;
-
- generator_add = (Bit32u)(INTFREQU*FIXEDPT/int_samplerate);
-
-
- memset((void *)adlibreg,0,sizeof(adlibreg));
- memset((void *)op,0,sizeof(op_type)*MAXOPERATORS);
- memset((void *)wave_sel,0,sizeof(wave_sel));
-
- for (i=0;i<MAXOPERATORS;i++) {
- op[i].op_state = OF_TYPE_OFF;
- op[i].act_state = OP_ACT_OFF;
- op[i].amp = 0.0;
- op[i].step_amp = 0.0;
- op[i].vol = 0.0;
- op[i].tcount = 0;
- op[i].tinc = 0;
- op[i].toff = 0;
- op[i].cur_wmask = wavemask[0];
- op[i].cur_wform = &wavtable[waveform[0]];
- op[i].freq_high = 0;
-
- op[i].generator_pos = 0;
- op[i].cur_env_step = 0;
- op[i].env_step_a = 0;
- op[i].env_step_d = 0;
- op[i].env_step_r = 0;
- op[i].step_skip_pos_a = 0;
- op[i].env_step_skip_a = 0;
-
-#if defined(OPLTYPE_IS_OPL3)
- op[i].is_4op = false;
- op[i].is_4op_attached = false;
- op[i].left_pan = 1;
- op[i].right_pan = 1;
-#endif
- }
-
- recipsamp = 1.0 / (fltype)int_samplerate;
- for (i=15;i>=0;i--) {
- frqmul[i] = (fltype)(frqmul_tab[i]*INTFREQU/(fltype)WAVEPREC*(fltype)FIXEDPT*recipsamp);
- }
-
- status = 0;
- opl_index = 0;
-
-
- // create vibrato table
- vib_table[0] = 8;
- vib_table[1] = 4;
- vib_table[2] = 0;
- vib_table[3] = -4;
- for (i=4; i<VIBTAB_SIZE; i++) vib_table[i] = vib_table[i-4]*-1;
-
- // vibrato at ~6.1 ?? (opl3 docs say 6.1, opl4 docs say 6.0, y8950 docs say 6.4)
- vibtab_add = static_cast<Bit32u>(VIBTAB_SIZE*FIXEDPT_LFO/8192*INTFREQU/int_samplerate);
- vibtab_pos = 0;
-
- for (i=0; i<BLOCKBUF_SIZE; i++) vibval_const[i] = 0;
-
-
- // create tremolo table
- Bit32s trem_table_int[TREMTAB_SIZE];
- for (i=0; i<14; i++) trem_table_int[i] = i-13; // upwards (13 to 26 -> -0.5/6 to 0)
- for (i=14; i<41; i++) trem_table_int[i] = -i+14; // downwards (26 to 0 -> 0 to -1/6)
- for (i=41; i<53; i++) trem_table_int[i] = i-40-26; // upwards (1 to 12 -> -1/6 to -0.5/6)
-
- for (i=0; i<TREMTAB_SIZE; i++) {
- // 0.0 .. -26/26*4.8/6 == [0.0 .. -0.8], 4/53 steps == [1 .. 0.57]
- fltype trem_val1=(fltype)(((fltype)trem_table_int[i])*4.8/26.0/6.0); // 4.8db
- fltype trem_val2=(fltype)((fltype)((Bit32s)(trem_table_int[i]/4))*1.2/6.0/6.0); // 1.2db (larger stepping)
-
- trem_table[i] = (Bit32s)(pow(FL2,trem_val1)*FIXEDPT);
- trem_table[TREMTAB_SIZE+i] = (Bit32s)(pow(FL2,trem_val2)*FIXEDPT);
- }
-
- // tremolo at 3.7hz
- tremtab_add = (Bit32u)((fltype)TREMTAB_SIZE * TREM_FREQ * FIXEDPT_LFO / (fltype)int_samplerate);
- tremtab_pos = 0;
-
- for (i=0; i<BLOCKBUF_SIZE; i++) tremval_const[i] = FIXEDPT;
-
-
- static Bitu initfirstime = 0;
- if (!initfirstime) {
- initfirstime = 1;
-
- // create waveform tables
- for (i=0;i<(WAVEPREC>>1);i++) {
- wavtable[(i<<1) +WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<1) )*PI*2/WAVEPREC));
- wavtable[(i<<1)+1+WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<1)+1)*PI*2/WAVEPREC));
- wavtable[i] = wavtable[(i<<1) +WAVEPREC];
- // alternative: (zero-less)
-/* wavtable[(i<<1) +WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<2)+1)*PI/WAVEPREC));
- wavtable[(i<<1)+1+WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<2)+3)*PI/WAVEPREC));
- wavtable[i] = wavtable[(i<<1)-1+WAVEPREC]; */
- }
- for (i=0;i<(WAVEPREC>>3);i++) {
- wavtable[i+(WAVEPREC<<1)] = wavtable[i+(WAVEPREC>>3)]-16384;
- wavtable[i+((WAVEPREC*17)>>3)] = wavtable[i+(WAVEPREC>>2)]+16384;
- }
-
- // key scale level table verified ([table in book]*8/3)
- kslev[7][0] = 0; kslev[7][1] = 24; kslev[7][2] = 32; kslev[7][3] = 37;
- kslev[7][4] = 40; kslev[7][5] = 43; kslev[7][6] = 45; kslev[7][7] = 47;
- kslev[7][8] = 48;
- for (i=9;i<16;i++) kslev[7][i] = (Bit8u)(i+41);
- for (j=6;j>=0;j--) {
- for (i=0;i<16;i++) {
- oct = (Bits)kslev[j+1][i]-8;
- if (oct < 0) oct = 0;
- kslev[j][i] = (Bit8u)oct;
- }
- }
- }
-
-}
-
-
-
-void adlib_write(Bitu idx, Bit8u val) {
- Bit32u second_set = idx&0x100;
- adlibreg[idx] = val;
-
- switch (idx&0xf0) {
- case ARC_CONTROL:
- // here we check for the second set registers, too:
- switch (idx) {
- case 0x02: // timer1 counter
- case 0x03: // timer2 counter
- break;
- case 0x04:
- // IRQ reset, timer mask/start
- if (val&0x80) {
- // clear IRQ bits in status register
- status &= ~0x60;
- } else {
- status = 0;
- }
- break;
-#if defined(OPLTYPE_IS_OPL3)
- case 0x04|ARC_SECONDSET:
- // 4op enable/disable switches for each possible channel
- op[0].is_4op = (val&1)>0;
- op[3].is_4op_attached = op[0].is_4op;
- op[1].is_4op = (val&2)>0;
- op[4].is_4op_attached = op[1].is_4op;
- op[2].is_4op = (val&4)>0;
- op[5].is_4op_attached = op[2].is_4op;
- op[18].is_4op = (val&8)>0;
- op[21].is_4op_attached = op[18].is_4op;
- op[19].is_4op = (val&16)>0;
- op[22].is_4op_attached = op[19].is_4op;
- op[20].is_4op = (val&32)>0;
- op[23].is_4op_attached = op[20].is_4op;
- break;
- case 0x05|ARC_SECONDSET:
- break;
-#endif
- case 0x08:
- // CSW, note select
- break;
- default:
- break;
- }
- break;
- case ARC_TVS_KSR_MUL:
- case ARC_TVS_KSR_MUL+0x10: {
- // tremolo/vibrato/sustain keeping enabled; key scale rate; frequency multiplication
- int num = idx&7;
- Bitu base = (idx-ARC_TVS_KSR_MUL)&0xff;
- if ((num<6) && (base<22)) {
-#if defined(OPLTYPE_IS_OPL3)
- Bitu modop = regbase2modop[second_set?(base+22):base];
-#else
- Bitu modop = regbase2modop[base];
-#endif
- Bitu regbase = base+second_set;
- Bitu chanbase = second_set?(modop-18+ARC_SECONDSET):modop;
-
- // change tremolo/vibrato and sustain keeping of this operator
- op_type* op_ptr = &op[modop+((num<3) ? 0 : 9)];
- change_keepsustain(regbase,op_ptr);
- change_vibrato(regbase,op_ptr);
-
- // change frequency calculations of this operator as
- // key scale rate and frequency multiplicator can be changed
-#if defined(OPLTYPE_IS_OPL3)
- if ((adlibreg[0x105]&1) && (op[modop].is_4op_attached)) {
- // operator uses frequency of channel
- change_frequency(chanbase-3,regbase,op_ptr);
- } else {
- change_frequency(chanbase,regbase,op_ptr);
- }
-#else
- change_frequency(chanbase,base,op_ptr);
-#endif
- }
- }
- break;
- case ARC_KSL_OUTLEV:
- case ARC_KSL_OUTLEV+0x10: {
- // key scale level; output rate
- int num = idx&7;
- Bitu base = (idx-ARC_KSL_OUTLEV)&0xff;
- if ((num<6) && (base<22)) {
-#if defined(OPLTYPE_IS_OPL3)
- Bitu modop = regbase2modop[second_set?(base+22):base];
-#else
- Bitu modop = regbase2modop[base];
-#endif
- Bitu chanbase = second_set?(modop-18+ARC_SECONDSET):modop;
-
- // change frequency calculations of this operator as
- // key scale level and output rate can be changed
- op_type* op_ptr = &op[modop+((num<3) ? 0 : 9)];
-#if defined(OPLTYPE_IS_OPL3)
- Bitu regbase = base+second_set;
- if ((adlibreg[0x105]&1) && (op[modop].is_4op_attached)) {
- // operator uses frequency of channel
- change_frequency(chanbase-3,regbase,op_ptr);
- } else {
- change_frequency(chanbase,regbase,op_ptr);
- }
-#else
- change_frequency(chanbase,base,op_ptr);
-#endif
- }
- }
- break;
- case ARC_ATTR_DECR:
- case ARC_ATTR_DECR+0x10: {
- // attack/decay rates
- int num = idx&7;
- Bitu base = (idx-ARC_ATTR_DECR)&0xff;
- if ((num<6) && (base<22)) {
- Bitu regbase = base+second_set;
-
- // change attack rate and decay rate of this operator
- op_type* op_ptr = &op[regbase2op[second_set?(base+22):base]];
- change_attackrate(regbase,op_ptr);
- change_decayrate(regbase,op_ptr);
- }
- }
- break;
- case ARC_SUSL_RELR:
- case ARC_SUSL_RELR+0x10: {
- // sustain level; release rate
- int num = idx&7;
- Bitu base = (idx-ARC_SUSL_RELR)&0xff;
- if ((num<6) && (base<22)) {
- Bitu regbase = base+second_set;
-
- // change sustain level and release rate of this operator
- op_type* op_ptr = &op[regbase2op[second_set?(base+22):base]];
- change_releaserate(regbase,op_ptr);
- change_sustainlevel(regbase,op_ptr);
- }
- }
- break;
- case ARC_FREQ_NUM: {
- // 0xa0-0xa8 low8 frequency
- Bitu base = (idx-ARC_FREQ_NUM)&0xff;
- if (base<9) {
- Bits opbase = second_set?(base+18):base;
-#if defined(OPLTYPE_IS_OPL3)
- if ((adlibreg[0x105]&1) && op[opbase].is_4op_attached) break;
-#endif
- // regbase of modulator:
- Bits modbase = modulatorbase[base]+second_set;
-
- Bitu chanbase = base+second_set;
-
- change_frequency(chanbase,modbase,&op[opbase]);
- change_frequency(chanbase,modbase+3,&op[opbase+9]);
-#if defined(OPLTYPE_IS_OPL3)
- // for 4op channels all four operators are modified to the frequency of the channel
- if ((adlibreg[0x105]&1) && op[second_set?(base+18):base].is_4op) {
- change_frequency(chanbase,modbase+8,&op[opbase+3]);
- change_frequency(chanbase,modbase+3+8,&op[opbase+3+9]);
- }
-#endif
- }
- }
- break;
- case ARC_KON_BNUM: {
- if (idx == ARC_PERC_MODE) {
-#if defined(OPLTYPE_IS_OPL3)
- if (second_set) return;
-#endif
-
- if ((val&0x30) == 0x30) { // BassDrum active
- enable_operator(16,&op[6],OP_ACT_PERC);
- change_frequency(6,16,&op[6]);
- enable_operator(16+3,&op[6+9],OP_ACT_PERC);
- change_frequency(6,16+3,&op[6+9]);
- } else {
- disable_operator(&op[6],OP_ACT_PERC);
- disable_operator(&op[6+9],OP_ACT_PERC);
- }
- if ((val&0x28) == 0x28) { // Snare active
- enable_operator(17+3,&op[16],OP_ACT_PERC);
- change_frequency(7,17+3,&op[16]);
- } else {
- disable_operator(&op[16],OP_ACT_PERC);
- }
- if ((val&0x24) == 0x24) { // TomTom active
- enable_operator(18,&op[8],OP_ACT_PERC);
- change_frequency(8,18,&op[8]);
- } else {
- disable_operator(&op[8],OP_ACT_PERC);
- }
- if ((val&0x22) == 0x22) { // Cymbal active
- enable_operator(18+3,&op[8+9],OP_ACT_PERC);
- change_frequency(8,18+3,&op[8+9]);
- } else {
- disable_operator(&op[8+9],OP_ACT_PERC);
- }
- if ((val&0x21) == 0x21) { // Hihat active
- enable_operator(17,&op[7],OP_ACT_PERC);
- change_frequency(7,17,&op[7]);
- } else {
- disable_operator(&op[7],OP_ACT_PERC);
- }
-
- break;
- }
- // regular 0xb0-0xb8
- Bitu base = (idx-ARC_KON_BNUM)&0xff;
- if (base<9) {
- Bits opbase = second_set?(base+18):base;
-#if defined(OPLTYPE_IS_OPL3)
- if ((adlibreg[0x105]&1) && op[opbase].is_4op_attached) break;
-#endif
- // regbase of modulator:
- Bits modbase = modulatorbase[base]+second_set;
-
- if (val&32) {
- // operator switched on
- enable_operator(modbase,&op[opbase],OP_ACT_NORMAL); // modulator (if 2op)
- enable_operator(modbase+3,&op[opbase+9],OP_ACT_NORMAL); // carrier (if 2op)
-#if defined(OPLTYPE_IS_OPL3)
- // for 4op channels all four operators are switched on
- if ((adlibreg[0x105]&1) && op[opbase].is_4op) {
- // turn on chan+3 operators as well
- enable_operator(modbase+8,&op[opbase+3],OP_ACT_NORMAL);
- enable_operator(modbase+3+8,&op[opbase+3+9],OP_ACT_NORMAL);
- }
-#endif
- } else {
- // operator switched off
- disable_operator(&op[opbase],OP_ACT_NORMAL);
- disable_operator(&op[opbase+9],OP_ACT_NORMAL);
-#if defined(OPLTYPE_IS_OPL3)
- // for 4op channels all four operators are switched off
- if ((adlibreg[0x105]&1) && op[opbase].is_4op) {
- // turn off chan+3 operators as well
- disable_operator(&op[opbase+3],OP_ACT_NORMAL);
- disable_operator(&op[opbase+3+9],OP_ACT_NORMAL);
- }
-#endif
- }
-
- Bitu chanbase = base+second_set;
-
- // change frequency calculations of modulator and carrier (2op) as
- // the frequency of the channel has changed
- change_frequency(chanbase,modbase,&op[opbase]);
- change_frequency(chanbase,modbase+3,&op[opbase+9]);
-#if defined(OPLTYPE_IS_OPL3)
- // for 4op channels all four operators are modified to the frequency of the channel
- if ((adlibreg[0x105]&1) && op[second_set?(base+18):base].is_4op) {
- // change frequency calculations of chan+3 operators as well
- change_frequency(chanbase,modbase+8,&op[opbase+3]);
- change_frequency(chanbase,modbase+3+8,&op[opbase+3+9]);
- }
-#endif
- }
- }
- break;
- case ARC_FEEDBACK: {
- // 0xc0-0xc8 feedback/modulation type (AM/FM)
- Bitu base = (idx-ARC_FEEDBACK)&0xff;
- if (base<9) {
- Bits opbase = second_set?(base+18):base;
- Bitu chanbase = base+second_set;
- change_feedback(chanbase,&op[opbase]);
-#if defined(OPLTYPE_IS_OPL3)
- // OPL3 panning
- op[opbase].left_pan = ((val&0x10)>>4);
- op[opbase].right_pan = ((val&0x20)>>5);
-#endif
- }
- }
- break;
- case ARC_WAVE_SEL:
- case ARC_WAVE_SEL+0x10: {
- int num = idx&7;
- Bitu base = (idx-ARC_WAVE_SEL)&0xff;
- if ((num<6) && (base<22)) {
-#if defined(OPLTYPE_IS_OPL3)
- Bits wselbase = second_set?(base+22):base; // for easier mapping onto wave_sel[]
- // change waveform
- if (adlibreg[0x105]&1) wave_sel[wselbase] = val&7; // opl3 mode enabled, all waveforms accessible
- else wave_sel[wselbase] = val&3;
- op_type* op_ptr = &op[regbase2modop[wselbase]+((num<3) ? 0 : 9)];
- change_waveform(wselbase,op_ptr);
-#else
- if (adlibreg[0x01]&0x20) {
- // wave selection enabled, change waveform
- wave_sel[base] = val&3;
- op_type* op_ptr = &op[regbase2modop[base]+((num<3) ? 0 : 9)];
- change_waveform(base,op_ptr);
- }
-#endif
- }
- }
- break;
- default:
- break;
- }
-}
-
-
-Bitu adlib_reg_read(Bitu port) {
-#if defined(OPLTYPE_IS_OPL3)
- // opl3-detection routines require ret&6 to be zero
- if ((port&1)==0) {
- return status;
- }
- return 0x00;
-#else
- // opl2-detection routines require ret&6 to be 6
- if ((port&1)==0) {
- return status|6;
- }
- return 0xff;
-#endif
-}
-
-void adlib_write_index(Bitu port, Bit8u val) {
- opl_index = val;
-#if defined(OPLTYPE_IS_OPL3)
- if ((port&3)!=0) {
- // possibly second set
- if (((adlibreg[0x105]&1)!=0) || (opl_index==5)) opl_index |= ARC_SECONDSET;
- }
-#endif
-}
-
-static inline void clipit16(Bit32s ival, Bit16s* outval) {
- if (ival<32768) {
- if (ival>-32769) {
- *outval=(Bit16s)ival;
- } else {
- *outval = -32768;
- }
- } else {
- *outval = 32767;
- }
-}
-
-
-
-// be careful with this
-// uses cptr and chanval, outputs into outbufl(/outbufr)
-// for opl3 check if opl3-mode is enabled (which uses stereo panning)
-#undef CHANVAL_OUT
-#if defined(OPLTYPE_IS_OPL3)
-#define CHANVAL_OUT \
- if (adlibreg[0x105]&1) { \
- outbufl[i] += chanval*cptr[0].left_pan; \
- outbufr[i] += chanval*cptr[0].right_pan; \
- } else { \
- outbufl[i] += chanval; \
- }
-#else
-#define CHANVAL_OUT \
- outbufl[i] += chanval;
-#endif
-
-void adlib_getsample(Bit16s* sndptr, Bits numsamples) {
- Bits i, endsamples;
- op_type* cptr;
-
- Bit32s outbufl[BLOCKBUF_SIZE];
-#if defined(OPLTYPE_IS_OPL3)
- // second output buffer (right channel for opl3 stereo)
- Bit32s outbufr[BLOCKBUF_SIZE];
-#endif
-
- // vibrato/tremolo lookup tables (global, to possibly be used by all operators)
- Bit32s vib_lut[BLOCKBUF_SIZE];
- Bit32s trem_lut[BLOCKBUF_SIZE];
-
- Bits samples_to_process = numsamples;
-
- for (Bits cursmp=0; cursmp<samples_to_process; cursmp+=endsamples) {
- endsamples = samples_to_process-cursmp;
- if (endsamples>BLOCKBUF_SIZE) endsamples = BLOCKBUF_SIZE;
-
- memset((void*)&outbufl,0,endsamples*sizeof(Bit32s));
-#if defined(OPLTYPE_IS_OPL3)
- // clear second output buffer (opl3 stereo)
- if (adlibreg[0x105]&1) memset((void*)&outbufr,0,endsamples*sizeof(Bit32s));
-#endif
-
- // calculate vibrato/tremolo lookup tables
- Bit32s vib_tshift = ((adlibreg[ARC_PERC_MODE]&0x40)==0) ? 1 : 0; // 14cents/7cents switching
- for (i=0;i<endsamples;i++) {
- // cycle through vibrato table
- vibtab_pos += vibtab_add;
- if (vibtab_pos/FIXEDPT_LFO>=VIBTAB_SIZE) vibtab_pos-=VIBTAB_SIZE*FIXEDPT_LFO;
- vib_lut[i] = vib_table[vibtab_pos/FIXEDPT_LFO]>>vib_tshift; // 14cents (14/100 of a semitone) or 7cents
-
- // cycle through tremolo table
- tremtab_pos += tremtab_add;
- if (tremtab_pos/FIXEDPT_LFO>=TREMTAB_SIZE) tremtab_pos-=TREMTAB_SIZE*FIXEDPT_LFO;
- if (adlibreg[ARC_PERC_MODE]&0x80) trem_lut[i] = trem_table[tremtab_pos/FIXEDPT_LFO];
- else trem_lut[i] = trem_table[TREMTAB_SIZE+tremtab_pos/FIXEDPT_LFO];
- }
-
- if (adlibreg[ARC_PERC_MODE]&0x20) {
- //BassDrum
- cptr = &op[6];
- if (adlibreg[ARC_FEEDBACK+6]&1) {
- // additive synthesis
- if (cptr[9].op_state != OF_TYPE_OFF) {
- if (cptr[9].vibrato) {
- vibval1 = vibval_var1;
- for (i=0;i<endsamples;i++)
- vibval1[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval1 = vibval_const;
- if (cptr[9].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
- else tremval1 = tremval_const;
-
- // calculate channel output
- for (i=0;i<endsamples;i++) {
- operator_advance(&cptr[9],vibval1[i]);
- opfuncs[cptr[9].op_state](&cptr[9]);
- operator_output(&cptr[9],0,tremval1[i]);
-
- Bit32s chanval = cptr[9].cval*2;
- CHANVAL_OUT
- }
- }
- } else {
- // frequency modulation
- if ((cptr[9].op_state != OF_TYPE_OFF) || (cptr[0].op_state != OF_TYPE_OFF)) {
- if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) {
- vibval1 = vibval_var1;
- for (i=0;i<endsamples;i++)
- vibval1[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval1 = vibval_const;
- if ((cptr[9].vibrato) && (cptr[9].op_state != OF_TYPE_OFF)) {
- vibval2 = vibval_var2;
- for (i=0;i<endsamples;i++)
- vibval2[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval2 = vibval_const;
- if (cptr[0].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
- else tremval1 = tremval_const;
- if (cptr[9].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
- else tremval2 = tremval_const;
-
- // calculate channel output
- for (i=0;i<endsamples;i++) {
- operator_advance(&cptr[0],vibval1[i]);
- opfuncs[cptr[0].op_state](&cptr[0]);
- operator_output(&cptr[0],(cptr[0].lastcval+cptr[0].cval)*cptr[0].mfbi/2,tremval1[i]);
-
- operator_advance(&cptr[9],vibval2[i]);
- opfuncs[cptr[9].op_state](&cptr[9]);
- operator_output(&cptr[9],cptr[0].cval*FIXEDPT,tremval2[i]);
-
- Bit32s chanval = cptr[9].cval*2;
- CHANVAL_OUT
- }
- }
- }
-
- //TomTom (j=8)
- if (op[8].op_state != OF_TYPE_OFF) {
- cptr = &op[8];
- if (cptr[0].vibrato) {
- vibval3 = vibval_var1;
- for (i=0;i<endsamples;i++)
- vibval3[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval3 = vibval_const;
-
- if (cptr[0].tremolo) tremval3 = trem_lut; // tremolo enabled, use table
- else tremval3 = tremval_const;
-
- // calculate channel output
- for (i=0;i<endsamples;i++) {
- operator_advance(&cptr[0],vibval3[i]);
- opfuncs[cptr[0].op_state](&cptr[0]); //TomTom
- operator_output(&cptr[0],0,tremval3[i]);
- Bit32s chanval = cptr[0].cval*2;
- CHANVAL_OUT
- }
- }
-
- //Snare/Hihat (j=7), Cymbal (j=8)
- if ((op[7].op_state != OF_TYPE_OFF) || (op[16].op_state != OF_TYPE_OFF) ||
- (op[17].op_state != OF_TYPE_OFF)) {
- cptr = &op[7];
- if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) {
- vibval1 = vibval_var1;
- for (i=0;i<endsamples;i++)
- vibval1[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval1 = vibval_const;
- if ((cptr[9].vibrato) && (cptr[9].op_state == OF_TYPE_OFF)) {
- vibval2 = vibval_var2;
- for (i=0;i<endsamples;i++)
- vibval2[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval2 = vibval_const;
-
- if (cptr[0].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
- else tremval1 = tremval_const;
- if (cptr[9].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
- else tremval2 = tremval_const;
-
- cptr = &op[8];
- if ((cptr[9].vibrato) && (cptr[9].op_state == OF_TYPE_OFF)) {
- vibval4 = vibval_var2;
- for (i=0;i<endsamples;i++)
- vibval4[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval4 = vibval_const;
-
- if (cptr[9].tremolo) tremval4 = trem_lut; // tremolo enabled, use table
- else tremval4 = tremval_const;
-
- // calculate channel output
- for (i=0;i<endsamples;i++) {
- operator_advance_drums(&op[7],vibval1[i],&op[7+9],vibval2[i],&op[8+9],vibval4[i]);
-
- opfuncs[op[7].op_state](&op[7]); //Hihat
- operator_output(&op[7],0,tremval1[i]);
-
- opfuncs[op[7+9].op_state](&op[7+9]); //Snare
- operator_output(&op[7+9],0,tremval2[i]);
-
- opfuncs[op[8+9].op_state](&op[8+9]); //Cymbal
- operator_output(&op[8+9],0,tremval4[i]);
-
- Bit32s chanval = (op[7].cval + op[7+9].cval + op[8+9].cval)*2;
- CHANVAL_OUT
- }
- }
- }
-
- Bitu max_channel = NUM_CHANNELS;
-#if defined(OPLTYPE_IS_OPL3)
- if ((adlibreg[0x105]&1)==0) max_channel = NUM_CHANNELS/2;
-#endif
- for (Bits cur_ch=max_channel-1; cur_ch>=0; cur_ch--) {
- // skip drum/percussion operators
- if ((adlibreg[ARC_PERC_MODE]&0x20) && (cur_ch >= 6) && (cur_ch < 9)) continue;
-
- Bitu k = cur_ch;
-#if defined(OPLTYPE_IS_OPL3)
- if (cur_ch < 9) {
- cptr = &op[cur_ch];
- } else {
- cptr = &op[cur_ch+9]; // second set is operator18-operator35
- k += (-9+256); // second set uses registers 0x100 onwards
- }
- // check if this operator is part of a 4-op
- if ((adlibreg[0x105]&1) && cptr->is_4op_attached) continue;
-#else
- cptr = &op[cur_ch];
-#endif
-
- // check for FM/AM
- if (adlibreg[ARC_FEEDBACK+k]&1) {
-#if defined(OPLTYPE_IS_OPL3)
- if ((adlibreg[0x105]&1) && cptr->is_4op) {
- if (adlibreg[ARC_FEEDBACK+k+3]&1) {
- // AM-AM-style synthesis (op1[fb] + (op2 * op3) + op4)
- if (cptr[0].op_state != OF_TYPE_OFF) {
- if (cptr[0].vibrato) {
- vibval1 = vibval_var1;
- for (i=0;i<endsamples;i++)
- vibval1[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval1 = vibval_const;
- if (cptr[0].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
- else tremval1 = tremval_const;
-
- // calculate channel output
- for (i=0;i<endsamples;i++) {
- operator_advance(&cptr[0],vibval1[i]);
- opfuncs[cptr[0].op_state](&cptr[0]);
- operator_output(&cptr[0],(cptr[0].lastcval+cptr[0].cval)*cptr[0].mfbi/2,tremval1[i]);
-
- Bit32s chanval = cptr[0].cval;
- CHANVAL_OUT
- }
- }
-
- if ((cptr[3].op_state != OF_TYPE_OFF) || (cptr[9].op_state != OF_TYPE_OFF)) {
- if ((cptr[9].vibrato) && (cptr[9].op_state != OF_TYPE_OFF)) {
- vibval1 = vibval_var1;
- for (i=0;i<endsamples;i++)
- vibval1[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval1 = vibval_const;
- if (cptr[9].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
- else tremval1 = tremval_const;
- if (cptr[3].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
- else tremval2 = tremval_const;
-
- // calculate channel output
- for (i=0;i<endsamples;i++) {
- operator_advance(&cptr[9],vibval1[i]);
- opfuncs[cptr[9].op_state](&cptr[9]);
- operator_output(&cptr[9],0,tremval1[i]);
-
- operator_advance(&cptr[3],0);
- opfuncs[cptr[3].op_state](&cptr[3]);
- operator_output(&cptr[3],cptr[9].cval*FIXEDPT,tremval2[i]);
-
- Bit32s chanval = cptr[3].cval;
- CHANVAL_OUT
- }
- }
-
- if (cptr[3+9].op_state != OF_TYPE_OFF) {
- if (cptr[3+9].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
- else tremval1 = tremval_const;
-
- // calculate channel output
- for (i=0;i<endsamples;i++) {
- operator_advance(&cptr[3+9],0);
- opfuncs[cptr[3+9].op_state](&cptr[3+9]);
- operator_output(&cptr[3+9],0,tremval1[i]);
-
- Bit32s chanval = cptr[3+9].cval;
- CHANVAL_OUT
- }
- }
- } else {
- // AM-FM-style synthesis (op1[fb] + (op2 * op3 * op4))
- if (cptr[0].op_state != OF_TYPE_OFF) {
- if (cptr[0].vibrato) {
- vibval1 = vibval_var1;
- for (i=0;i<endsamples;i++)
- vibval1[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval1 = vibval_const;
- if (cptr[0].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
- else tremval1 = tremval_const;
-
- // calculate channel output
- for (i=0;i<endsamples;i++) {
- operator_advance(&cptr[0],vibval1[i]);
- opfuncs[cptr[0].op_state](&cptr[0]);
- operator_output(&cptr[0],(cptr[0].lastcval+cptr[0].cval)*cptr[0].mfbi/2,tremval1[i]);
-
- Bit32s chanval = cptr[0].cval;
- CHANVAL_OUT
- }
- }
-
- if ((cptr[9].op_state != OF_TYPE_OFF) || (cptr[3].op_state != OF_TYPE_OFF) || (cptr[3+9].op_state != OF_TYPE_OFF)) {
- if ((cptr[9].vibrato) && (cptr[9].op_state != OF_TYPE_OFF)) {
- vibval1 = vibval_var1;
- for (i=0;i<endsamples;i++)
- vibval1[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval1 = vibval_const;
- if (cptr[9].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
- else tremval1 = tremval_const;
- if (cptr[3].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
- else tremval2 = tremval_const;
- if (cptr[3+9].tremolo) tremval3 = trem_lut; // tremolo enabled, use table
- else tremval3 = tremval_const;
-
- // calculate channel output
- for (i=0;i<endsamples;i++) {
- operator_advance(&cptr[9],vibval1[i]);
- opfuncs[cptr[9].op_state](&cptr[9]);
- operator_output(&cptr[9],0,tremval1[i]);
-
- operator_advance(&cptr[3],0);
- opfuncs[cptr[3].op_state](&cptr[3]);
- operator_output(&cptr[3],cptr[9].cval*FIXEDPT,tremval2[i]);
-
- operator_advance(&cptr[3+9],0);
- opfuncs[cptr[3+9].op_state](&cptr[3+9]);
- operator_output(&cptr[3+9],cptr[3].cval*FIXEDPT,tremval3[i]);
-
- Bit32s chanval = cptr[3+9].cval;
- CHANVAL_OUT
- }
- }
- }
- continue;
- }
-#endif
- // 2op additive synthesis
- if ((cptr[9].op_state == OF_TYPE_OFF) && (cptr[0].op_state == OF_TYPE_OFF)) continue;
- if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) {
- vibval1 = vibval_var1;
- for (i=0;i<endsamples;i++)
- vibval1[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval1 = vibval_const;
- if ((cptr[9].vibrato) && (cptr[9].op_state != OF_TYPE_OFF)) {
- vibval2 = vibval_var2;
- for (i=0;i<endsamples;i++)
- vibval2[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval2 = vibval_const;
- if (cptr[0].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
- else tremval1 = tremval_const;
- if (cptr[9].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
- else tremval2 = tremval_const;
-
- // calculate channel output
- for (i=0;i<endsamples;i++) {
- // carrier1
- operator_advance(&cptr[0],vibval1[i]);
- opfuncs[cptr[0].op_state](&cptr[0]);
- operator_output(&cptr[0],(cptr[0].lastcval+cptr[0].cval)*cptr[0].mfbi/2,tremval1[i]);
-
- // carrier2
- operator_advance(&cptr[9],vibval2[i]);
- opfuncs[cptr[9].op_state](&cptr[9]);
- operator_output(&cptr[9],0,tremval2[i]);
-
- Bit32s chanval = cptr[9].cval + cptr[0].cval;
- CHANVAL_OUT
- }
- } else {
-#if defined(OPLTYPE_IS_OPL3)
- if ((adlibreg[0x105]&1) && cptr->is_4op) {
- if (adlibreg[ARC_FEEDBACK+k+3]&1) {
- // FM-AM-style synthesis ((op1[fb] * op2) + (op3 * op4))
- if ((cptr[0].op_state != OF_TYPE_OFF) || (cptr[9].op_state != OF_TYPE_OFF)) {
- if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) {
- vibval1 = vibval_var1;
- for (i=0;i<endsamples;i++)
- vibval1[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval1 = vibval_const;
- if ((cptr[9].vibrato) && (cptr[9].op_state != OF_TYPE_OFF)) {
- vibval2 = vibval_var2;
- for (i=0;i<endsamples;i++)
- vibval2[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval2 = vibval_const;
- if (cptr[0].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
- else tremval1 = tremval_const;
- if (cptr[9].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
- else tremval2 = tremval_const;
-
- // calculate channel output
- for (i=0;i<endsamples;i++) {
- operator_advance(&cptr[0],vibval1[i]);
- opfuncs[cptr[0].op_state](&cptr[0]);
- operator_output(&cptr[0],(cptr[0].lastcval+cptr[0].cval)*cptr[0].mfbi/2,tremval1[i]);
-
- operator_advance(&cptr[9],vibval2[i]);
- opfuncs[cptr[9].op_state](&cptr[9]);
- operator_output(&cptr[9],cptr[0].cval*FIXEDPT,tremval2[i]);
-
- Bit32s chanval = cptr[9].cval;
- CHANVAL_OUT
- }
- }
-
- if ((cptr[3].op_state != OF_TYPE_OFF) || (cptr[3+9].op_state != OF_TYPE_OFF)) {
- if (cptr[3].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
- else tremval1 = tremval_const;
- if (cptr[3+9].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
- else tremval2 = tremval_const;
-
- // calculate channel output
- for (i=0;i<endsamples;i++) {
- operator_advance(&cptr[3],0);
- opfuncs[cptr[3].op_state](&cptr[3]);
- operator_output(&cptr[3],0,tremval1[i]);
-
- operator_advance(&cptr[3+9],0);
- opfuncs[cptr[3+9].op_state](&cptr[3+9]);
- operator_output(&cptr[3+9],cptr[3].cval*FIXEDPT,tremval2[i]);
-
- Bit32s chanval = cptr[3+9].cval;
- CHANVAL_OUT
- }
- }
-
- } else {
- // FM-FM-style synthesis (op1[fb] * op2 * op3 * op4)
- if ((cptr[0].op_state != OF_TYPE_OFF) || (cptr[9].op_state != OF_TYPE_OFF) ||
- (cptr[3].op_state != OF_TYPE_OFF) || (cptr[3+9].op_state != OF_TYPE_OFF)) {
- if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) {
- vibval1 = vibval_var1;
- for (i=0;i<endsamples;i++)
- vibval1[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval1 = vibval_const;
- if ((cptr[9].vibrato) && (cptr[9].op_state != OF_TYPE_OFF)) {
- vibval2 = vibval_var2;
- for (i=0;i<endsamples;i++)
- vibval2[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval2 = vibval_const;
- if (cptr[0].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
- else tremval1 = tremval_const;
- if (cptr[9].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
- else tremval2 = tremval_const;
- if (cptr[3].tremolo) tremval3 = trem_lut; // tremolo enabled, use table
- else tremval3 = tremval_const;
- if (cptr[3+9].tremolo) tremval4 = trem_lut; // tremolo enabled, use table
- else tremval4 = tremval_const;
-
- // calculate channel output
- for (i=0;i<endsamples;i++) {
- operator_advance(&cptr[0],vibval1[i]);
- opfuncs[cptr[0].op_state](&cptr[0]);
- operator_output(&cptr[0],(cptr[0].lastcval+cptr[0].cval)*cptr[0].mfbi/2,tremval1[i]);
-
- operator_advance(&cptr[9],vibval2[i]);
- opfuncs[cptr[9].op_state](&cptr[9]);
- operator_output(&cptr[9],cptr[0].cval*FIXEDPT,tremval2[i]);
-
- operator_advance(&cptr[3],0);
- opfuncs[cptr[3].op_state](&cptr[3]);
- operator_output(&cptr[3],cptr[9].cval*FIXEDPT,tremval3[i]);
-
- operator_advance(&cptr[3+9],0);
- opfuncs[cptr[3+9].op_state](&cptr[3+9]);
- operator_output(&cptr[3+9],cptr[3].cval*FIXEDPT,tremval4[i]);
-
- Bit32s chanval = cptr[3+9].cval;
- CHANVAL_OUT
- }
- }
- }
- continue;
- }
-#endif
- // 2op frequency modulation
- if ((cptr[9].op_state == OF_TYPE_OFF) && (cptr[0].op_state == OF_TYPE_OFF)) continue;
- if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) {
- vibval1 = vibval_var1;
- for (i=0;i<endsamples;i++)
- vibval1[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval1 = vibval_const;
- if ((cptr[9].vibrato) && (cptr[9].op_state != OF_TYPE_OFF)) {
- vibval2 = vibval_var2;
- for (i=0;i<endsamples;i++)
- vibval2[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
- } else vibval2 = vibval_const;
- if (cptr[0].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
- else tremval1 = tremval_const;
- if (cptr[9].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
- else tremval2 = tremval_const;
-
- // calculate channel output
- for (i=0;i<endsamples;i++) {
- // modulator
- operator_advance(&cptr[0],vibval1[i]);
- opfuncs[cptr[0].op_state](&cptr[0]);
- operator_output(&cptr[0],(cptr[0].lastcval+cptr[0].cval)*cptr[0].mfbi/2,tremval1[i]);
-
- // carrier
- operator_advance(&cptr[9],vibval2[i]);
- opfuncs[cptr[9].op_state](&cptr[9]);
- operator_output(&cptr[9],cptr[0].cval*FIXEDPT,tremval2[i]);
-
- Bit32s chanval = cptr[9].cval;
- CHANVAL_OUT
- }
- }
- }
-
-#if defined(OPLTYPE_IS_OPL3)
- if (adlibreg[0x105]&1) {
- // convert to 16bit samples (stereo)
- for (i=0;i<endsamples;i++) {
- clipit16(outbufl[i] * 2,sndptr++);
- clipit16(outbufr[i] * 2,sndptr++);
- }
- } else {
- // convert to 16bit samples (mono)
- for (i=0;i<endsamples;i++) {
- clipit16(outbufl[i] * 2,sndptr++);
- clipit16(outbufl[i] * 2,sndptr++);
- }
- }
-#else
- // convert to 16bit samples
- for (i=0;i<endsamples;i++)
- clipit16(outbufl[i] * 2,sndptr++);
-#endif
-
- }
-}
diff --git a/sound/softsynth/opl/opl_inc.h b/sound/softsynth/opl/opl_inc.h
deleted file mode 100644
index bdf7e84547..0000000000
--- a/sound/softsynth/opl/opl_inc.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2002-2009 The DOSBox Team
- * OPL2/OPL3 emulation library
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-
-/*
- * Originally based on ADLIBEMU.C, an AdLib/OPL2 emulation library by Ken Silverman
- * Copyright (C) 1998-2001 Ken Silverman
- * Ken Silverman's official web site: "http://www.advsys.net/ken"
- */
-
-#define fltype double
-
-/*
- define Bits, Bitu, Bit32s, Bit32u, Bit16s, Bit16u, Bit8s, Bit8u here
-*/
-
-#define Bitu uint
-#define Bits int
-#define Bit32u uint32
-#define Bit32s int32
-#define Bit16u uint16
-#define Bit16s int16
-#define Bit8u uint8
-#define Bit8s int8
-
-
-/*
- define attribution that inlines/forces inlining of a function (optional)
-*/
-#define OPL_INLINE INLINE
-
-
-#undef NUM_CHANNELS
-#if defined(OPLTYPE_IS_OPL3)
-#define NUM_CHANNELS 18
-#else
-#define NUM_CHANNELS 9
-#endif
-
-#define MAXOPERATORS (NUM_CHANNELS*2)
-
-
-#define FL05 ((fltype)0.5)
-#define FL2 ((fltype)2.0)
-
-#ifdef PI
-#undef PI
-#endif
-
-#define PI ((fltype)3.1415926535897932384626433832795)
-
-
-#define FIXEDPT 0x10000 // fixed-point calculations using 16+16
-#define FIXEDPT_LFO 0x1000000 // fixed-point calculations using 8+24
-
-#define WAVEPREC 1024 // waveform precision (10 bits)
-
-#define INTFREQU ((fltype)(14318180.0 / 288.0)) // clocking of the chip
-
-
-#define OF_TYPE_ATT 0
-#define OF_TYPE_DEC 1
-#define OF_TYPE_REL 2
-#define OF_TYPE_SUS 3
-#define OF_TYPE_SUS_NOKEEP 4
-#define OF_TYPE_OFF 5
-
-#define ARC_CONTROL 0x00
-#define ARC_TVS_KSR_MUL 0x20
-#define ARC_KSL_OUTLEV 0x40
-#define ARC_ATTR_DECR 0x60
-#define ARC_SUSL_RELR 0x80
-#define ARC_FREQ_NUM 0xa0
-#define ARC_KON_BNUM 0xb0
-#define ARC_PERC_MODE 0xbd
-#define ARC_FEEDBACK 0xc0
-#define ARC_WAVE_SEL 0xe0
-
-#define ARC_SECONDSET 0x100 // second operator set for OPL3
-
-
-#define OP_ACT_OFF 0x00
-#define OP_ACT_NORMAL 0x01 // regular channel activated (bitmasked)
-#define OP_ACT_PERC 0x02 // percussion channel activated (bitmasked)
-
-#define BLOCKBUF_SIZE 512
-
-
-// vibrato constants
-#define VIBTAB_SIZE 8
-#define VIBFAC 70/50000 // no braces, integer mul/div
-
-// tremolo constants and table
-#define TREMTAB_SIZE 53
-#define TREM_FREQ ((fltype)(3.7)) // tremolo at 3.7hz
-
-
-/* operator struct definition
- For OPL2 all 9 channels consist of two operators each, carrier and modulator.
- Channel x has operators x as modulator and operators (9+x) as carrier.
- For OPL3 all 18 channels consist either of two operators (2op mode) or four
- operators (4op mode) which is determined through register4 of the second
- adlib register set.
- Only the channels 0,1,2 (first set) and 9,10,11 (second set) can act as
- 4op channels. The two additional operators for a channel y come from the
- 2op channel y+3 so the operatorss y, (9+y), y+3, (9+y)+3 make up a 4op
- channel.
-*/
-typedef struct operator_struct {
- Bit32s cval, lastcval; // current output/last output (used for feedback)
- Bit32u tcount, wfpos, tinc; // time (position in waveform) and time increment
- fltype amp, step_amp; // and amplification (envelope)
- fltype vol; // volume
- fltype sustain_level; // sustain level
- Bit32s mfbi; // feedback amount
- fltype a0, a1, a2, a3; // attack rate function coefficients
- fltype decaymul, releasemul; // decay/release rate functions
- Bit32u op_state; // current state of operator (attack/decay/sustain/release/off)
- Bit32u toff;
- Bit32s freq_high; // highest three bits of the frequency, used for vibrato calculations
- Bit16s* cur_wform; // start of selected waveform
- Bit32u cur_wmask; // mask for selected waveform
- Bit32u act_state; // activity state (regular, percussion)
- bool sus_keep; // keep sustain level when decay finished
- bool vibrato,tremolo; // vibrato/tremolo enable bits
-
- // variables used to provide non-continuous envelopes
- Bit32u generator_pos; // for non-standard sample rates we need to determine how many samples have passed
- Bits cur_env_step; // current (standardized) sample position
- Bits env_step_a,env_step_d,env_step_r; // number of std samples of one step (for attack/decay/release mode)
- Bit8u step_skip_pos_a; // position of 8-cyclic step skipping (always 2^x to check against mask)
- Bits env_step_skip_a; // bitmask that determines if a step is skipped (respective bit is zero then)
-
-#if defined(OPLTYPE_IS_OPL3)
- bool is_4op,is_4op_attached; // base of a 4op channel/part of a 4op channel
- Bit32s left_pan,right_pan; // opl3 stereo panning amount
-#endif
-} op_type;
-
-// per-chip variables
-Bitu chip_num;
-op_type op[MAXOPERATORS];
-
-Bits int_samplerate;
-
-Bit8u status;
-Bit32u opl_index;
-#if defined(OPLTYPE_IS_OPL3)
-Bit8u adlibreg[512]; // adlib register set (including second set)
-Bit8u wave_sel[44]; // waveform selection
-#else
-Bit8u adlibreg[256]; // adlib register set
-Bit8u wave_sel[22]; // waveform selection
-#endif
-
-
-// vibrato/tremolo increment/counter
-Bit32u vibtab_pos;
-Bit32u vibtab_add;
-Bit32u tremtab_pos;
-Bit32u tremtab_add;
-
-
-// enable an operator
-void enable_operator(Bitu regbase, op_type* op_pt);
-
-// functions to change parameters of an operator
-void change_frequency(Bitu chanbase, Bitu regbase, op_type* op_pt);
-
-void change_attackrate(Bitu regbase, op_type* op_pt);
-void change_decayrate(Bitu regbase, op_type* op_pt);
-void change_releaserate(Bitu regbase, op_type* op_pt);
-void change_sustainlevel(Bitu regbase, op_type* op_pt);
-void change_waveform(Bitu regbase, op_type* op_pt);
-void change_keepsustain(Bitu regbase, op_type* op_pt);
-void change_vibrato(Bitu regbase, op_type* op_pt);
-void change_feedback(Bitu chanbase, op_type* op_pt);
-
-// general functions
-void adlib_init(Bit32u samplerate);
-void adlib_write(Bitu idx, Bit8u val);
-void adlib_getsample(Bit16s* sndptr, Bits numsamples);
-
-Bitu adlib_reg_read(Bitu port);
-void adlib_write_index(Bitu port, Bit8u val);
-
-static Bit32u generator_add; // should be a chip parameter