diff --git a/src/hardware/dbopl.cpp b/src/hardware/dbopl.cpp index d0786565..c077d939 100644 --- a/src/hardware/dbopl.cpp +++ b/src/hardware/dbopl.cpp @@ -26,7 +26,7 @@ //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 rhytm channels, would any opl3 player use it and actually really change it though? + //TODO Fix panning for the Percussion channels, would any opl3 player use it and actually really change it though? //TODO don't use variables in work structure for tremolo and vibrato but give the variables as parameters to GetSample //TODO Since the vibrato takes 1024 samples it's easier to run the emulator in same vibrato chunks, vibrato would be costfree @@ -49,6 +49,8 @@ namespace DBOPL { #define MAX_SAMPLES 256 #define OPLRATE ((double)(14318180.0 / 288.0)) +//Shift the final volume up at the end +#define POST_VOLSHIFT (1) //Only need 4 valid bits at the top for vibrato #define VIBRATO_SH ( 32 - 4 ) @@ -65,13 +67,12 @@ namespace DBOPL { //Maximum amount of attenuation bits //Envelope goes to 511, 9 bits -//Final envelope should get shifted up 3 bits, we already do that for some generation modes #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 ( 12 ) +#define ENV_BITS ( 9 ) #endif //Limits of the envelope with those bits and when the envelope goes silent #define ENV_MIN 0 @@ -577,7 +578,7 @@ INLINE Bits Operator::GetWave( Bitu index, Bitu vol ) { 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; + Bit32u total = ( wave & 0x7fff ) + vol << ( 3 - ENV_EXTRA ); Bit32s sig = ExpTable[ total & 0xff ]; Bit32u exp = total >> 8; Bit32s neg = wave >> 16; @@ -601,15 +602,19 @@ Bits INLINE Operator::GetSample( Bits modulation ) { } Operator::Operator() { + chanData = 0; freqMul = 0; waveIndex = 0; waveAdd = 0; keyOn = 0; ksr = 0; - chanData = 0; + reg20 = 0; + reg40 = 0; + reg60 = 0; + reg80 = 0; + regE0 = 0; SetState( OFF ); rateZero = (1 << OFF); - sustainLevel = ENV_MAX; activeLevel = ENV_MAX; totalLevel = ENV_MAX; @@ -620,8 +625,9 @@ Operator::Operator() { */ Channel::Channel() { - //Frequency init + old[0] = old[1] = 0; chanData = 0; + regB0 = 0; regC0 = 0; maskLeft = -1; maskRight = -1; @@ -750,7 +756,7 @@ void Channel::WriteC0( const Chip* chip, Bit8u val ) { chan0->synthHandler = &Channel::BlockTemplate< sm3AMAM >; break; } - //Disable updating rhytm channels + //Disable updating percussion channels } else if ((fourMask & 0x40) && ( chip->regBD & 0x20) ) { //Regular dual op, am or fm @@ -763,7 +769,7 @@ void Channel::WriteC0( const Chip* chip, Bit8u val ) { maskRight = ( val & 0x20 ) ? -1 : 0; //opl2 active } else { - //Disable updating rhytm channels + //Disable updating percussion channels if ( (fourMask & 0x40) && ( chip->regBD & 0x20 ) ) { //Regular dual op, am or fm @@ -782,7 +788,7 @@ void Channel::ResetC0( const Chip* chip ) { }; template< bool opl3Mode> -void Channel::GenerateRhytm( Bit32s* output ) { +void Channel::GeneratePercussion( Bit32s* output ) { Channel* chan = this; //BassDrum @@ -891,12 +897,12 @@ Channel* Channel::BlockTemplate( ) { Work.vibrato = Work.vibTable[i]; Work.tremolo = Work.tremTable[i]; - //Early out for rhytm handlers - if ( mode == sm2Rhytm ) { - GenerateRhytm( Work.output + i ); + //Early out for percussion handlers + if ( mode == sm2Percussion ) { + GeneratePercussion( Work.output + i ); continue; //Prevent some unitialized value bitching - } else if ( mode == sm3Rhytm ) { - GenerateRhytm( Work.output + i * 2 ); + } else if ( mode == sm3Percussion ) { + GeneratePercussion( Work.output + i * 2 ); continue; //Prevent some unitialized value bitching } @@ -956,8 +962,8 @@ Channel* Channel::BlockTemplate( ) { case sm3FMAM: case sm3AMAM: return( this + 2 ); - case sm2Rhytm: - case sm3Rhytm: + case sm2Percussion: + case sm3Percussion: return( this + 3 ); } return 0; @@ -968,6 +974,9 @@ Channel* Channel::BlockTemplate( ) { */ Chip::Chip() { + reg08 = 0; + reg04 = 0; + regBD = 0; reg104 = 0; opl3Active = 0; } @@ -1001,9 +1010,9 @@ void Chip::WriteBD( Bit8u val ) { //Drum was just enabled, make sure channel 6 has the right synth if ( change & 0x20 ) { if ( opl3Active ) { - chan[6].synthHandler = &Channel::BlockTemplate< sm3Rhytm >; + chan[6].synthHandler = &Channel::BlockTemplate< sm3Percussion >; } else { - chan[6].synthHandler = &Channel::BlockTemplate< sm2Rhytm >; + chan[6].synthHandler = &Channel::BlockTemplate< sm2Percussion >; } } //Bass Drum @@ -1038,7 +1047,7 @@ void Chip::WriteBD( Bit8u val ) { } else { chan[8].op[1].KeyOff( 0x2 ); } - //Toggle keyoffs when we turn off the rhytm + //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 ); @@ -1155,6 +1164,9 @@ void Chip::GenerateBlock2( Bitu samples ) { count++; ch = (ch->*(ch->synthHandler))(); } + for ( Bitu i = 0; i < Work.samples; i++ ) { + Work.output[i] <<= POST_VOLSHIFT; + } } void Chip::GenerateBlock3( Bitu samples ) { @@ -1170,6 +1182,11 @@ void Chip::GenerateBlock3( Bitu samples ) { count++; ch = (ch->*(ch->synthHandler))(); } + for ( Bitu i = 0; i < Work.samples; i++ ) { + Work.output[i*2 + 0] <<= POST_VOLSHIFT; + Work.output[i*2 + 1] <<= POST_VOLSHIFT; + } + } void Chip::Setup( Bit32u rate ) { @@ -1263,7 +1280,7 @@ void Chip::Setup( Bit32u rate ) { chan[13].fourMask = 0x00 | ( 1 << 5 ); chan[14].fourMask = 0x80 | ( 1 << 5 ); - //mark the rhythm channels + //mark the percussion channels chan[ 6].fourMask = 0x40; chan[ 7].fourMask = 0x40; chan[ 8].fourMask = 0x40; diff --git a/src/hardware/dbopl.h b/src/hardware/dbopl.h index f42a330d..9232404f 100644 --- a/src/hardware/dbopl.h +++ b/src/hardware/dbopl.h @@ -27,7 +27,7 @@ #define WAVE_TABLEMUL 12 //Select the type of wave generator routine -#define DBOPL_WAVE WAVE_HANDLER +#define DBOPL_WAVE WAVE_TABLEMUL //Enable vibrato in the output #define DBOPL_VIBRATO //Enable tremolo in the output @@ -51,14 +51,14 @@ typedef enum { smNone, sm2AM, sm2FM, - sm2Rhytm, + sm2Percussion, sm3AM, sm3FM, sm3FMFM, sm3AMFM, sm3FMAM, sm3AMAM, - sm3Rhytm, + sm3Percussion, } SynthMode; //Shifts for the values contained in chandata variable @@ -121,14 +121,12 @@ public: 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: - //is the operator silent? void UpdateAttenuation(); void UpdateRates( const Chip* chip ); void UpdateFrequency( ); @@ -168,7 +166,7 @@ struct Channel { Bit8u feedback; //Feedback shift Bit8u regB0; //Register values to check for changes Bit8u regC0; - //This should correspond with reg104, bit 6 indicates a rhytm channel, bit 7 indicates a silent channel + //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; @@ -184,12 +182,11 @@ struct Channel { //call this for the first channel template< bool opl3Mode > - void GenerateRhytm( Bit32s* output ); + void GeneratePercussion( Bit32s* output ); //Generate blocks of data in specific modes template Channel* BlockTemplate( ); - void BlockRhytm( ); Channel(); };