diff --git a/msvc/libopl.vcproj b/msvc/libopl.vcproj index b0480b6c..316847c0 100644 --- a/msvc/libopl.vcproj +++ b/msvc/libopl.vcproj @@ -158,10 +158,6 @@ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > - - @@ -194,6 +190,10 @@ RelativePath="..\opl\opl_win32.c" > + + + + -#include -#include -//#include "dosbox.h" -#include "dbopl.h" - - -#define GCC_UNLIKELY(x) x - -#define TRUE 1 -#define FALSE 0 - -#ifndef PI -#define PI 3.14159265358979323846 -#endif - -#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 - -static inline void Operator__SetState(Operator *self, Bit8u s ); -static inline Bit32u Chip__ForwardNoise(Chip *self); - -// C++'s template<> sure is useful sometimes. - -static Channel* Channel__BlockTemplate(Channel *self, Chip* chip, - Bit32u samples, Bit32s* output, - SynthMode mode ); -#define BLOCK_TEMPLATE(mode) \ - static Channel* Channel__BlockTemplate_ ## mode(Channel *self, Chip* chip, \ - Bit32u samples, Bit32s* output) \ - { \ - return Channel__BlockTemplate(self, chip, samples, output, mode); \ - } - -BLOCK_TEMPLATE(sm2AM) -BLOCK_TEMPLATE(sm2FM) -BLOCK_TEMPLATE(sm3AM) -BLOCK_TEMPLATE(sm3FM) -BLOCK_TEMPLATE(sm3FMFM) -BLOCK_TEMPLATE(sm3AMFM) -BLOCK_TEMPLATE(sm3FMAM) -BLOCK_TEMPLATE(sm3AMAM) -BLOCK_TEMPLATE(sm2Percussion) -BLOCK_TEMPLATE(sm3Percussion) - -//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 -static inline void Operator__UpdateAttack(Operator *self, const Chip* chip ) { - Bit8u rate = self->reg60 >> 4; - if ( rate ) { - Bit8u val = (rate << 2) + self->ksr; - self->attackAdd = chip->attackRates[ val ]; - self->rateZero &= ~(1 << ATTACK); - } else { - self->attackAdd = 0; - self->rateZero |= (1 << ATTACK); - } -} -static inline void Operator__UpdateDecay(Operator *self, const Chip* chip ) { - Bit8u rate = self->reg60 & 0xf; - if ( rate ) { - Bit8u val = (rate << 2) + self->ksr; - self->decayAdd = chip->linearRates[ val ]; - self->rateZero &= ~(1 << DECAY); - } else { - self->decayAdd = 0; - self->rateZero |= (1 << DECAY); - } -} -static inline void Operator__UpdateRelease(Operator *self, const Chip* chip ) { - Bit8u rate = self->reg80 & 0xf; - if ( rate ) { - Bit8u val = (rate << 2) + self->ksr; - self->releaseAdd = chip->linearRates[ val ]; - self->rateZero &= ~(1 << RELEASE); - if ( !(self->reg20 & MASK_SUSTAIN ) ) { - self->rateZero &= ~( 1 << SUSTAIN ); - } - } else { - self->rateZero |= (1 << RELEASE); - self->releaseAdd = 0; - if ( !(self->reg20 & MASK_SUSTAIN ) ) { - self->rateZero |= ( 1 << SUSTAIN ); - } - } -} - -static inline void Operator__UpdateAttenuation(Operator *self) { - Bit8u kslBase = (Bit8u)((self->chanData >> SHIFT_KSLBASE) & 0xff); - Bit32u tl = self->reg40 & 0x3f; - Bit8u kslShift = KslShiftTable[ self->reg40 >> 6 ]; - //Make sure the attenuation goes to the right bits - self->totalLevel = tl << ( ENV_BITS - 7 ); //Total level goes 2 bits below max - self->totalLevel += ( kslBase << ENV_EXTRA ) >> kslShift; -} - -static void Operator__UpdateFrequency(Operator *self) { - Bit32u freq = self->chanData & (( 1 << 10 ) - 1); - Bit32u block = (self->chanData >> 10) & 0xff; -#ifdef WAVE_PRECISION - block = 7 - block; - self->waveAdd = ( freq * self->freqMul ) >> block; -#else - self->waveAdd = ( freq << block ) * self->freqMul; -#endif - if ( self->reg20 & MASK_VIBRATO ) { - self->vibStrength = (Bit8u)(freq >> 7); - -#ifdef WAVE_PRECISION - self->vibrato = ( self->vibStrength * self->freqMul ) >> block; -#else - self->vibrato = ( self->vibStrength << block ) * self->freqMul; -#endif - } else { - self->vibStrength = 0; - self->vibrato = 0; - } -} - -static void Operator__UpdateRates(Operator *self, const Chip* chip ) { - //Mame seems to reverse this where enabling ksr actually lowers - //the rate, but pdf manuals says otherwise? - Bit8u newKsr = (Bit8u)((self->chanData >> SHIFT_KEYCODE) & 0xff); - if ( !( self->reg20 & MASK_KSR ) ) { - newKsr >>= 2; - } - if ( self->ksr == newKsr ) - return; - self->ksr = newKsr; - Operator__UpdateAttack( self, chip ); - Operator__UpdateDecay( self, chip ); - Operator__UpdateRelease( self, chip ); -} - -static inline Bit32s Operator__RateForward(Operator *self, Bit32u add ) { - Bit32s ret; // haleyjd: GNUisms out! - self->rateIndex += add; - ret = self->rateIndex >> RATE_SH; - self->rateIndex = self->rateIndex & RATE_MASK; - return ret; -} - -static Bits Operator__TemplateVolume(Operator *self, OperatorState yes) { - Bit32s vol = self->volume; - Bit32s change; - switch ( yes ) { - case OFF: - return ENV_MAX; - case ATTACK: - change = Operator__RateForward( self, self->attackAdd ); - if ( !change ) - return vol; - vol += ( (~vol) * change ) >> 3; - if ( vol < ENV_MIN ) { - self->volume = ENV_MIN; - self->rateIndex = 0; - Operator__SetState( self, DECAY ); - return ENV_MIN; - } - break; - case DECAY: - vol += Operator__RateForward( self, self->decayAdd ); - if ( GCC_UNLIKELY(vol >= self->sustainLevel) ) { - //Check if we didn't overshoot max attenuation, then just go off - if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { - self->volume = ENV_MAX; - Operator__SetState( self, OFF ); - return ENV_MAX; - } - //Continue as sustain - self->rateIndex = 0; - Operator__SetState( self, SUSTAIN ); - } - break; - case SUSTAIN: - if ( self->reg20 & MASK_SUSTAIN ) { - return vol; - } - //In sustain phase, but not sustaining, do regular release - case RELEASE: - vol += Operator__RateForward( self, self->releaseAdd );; - if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { - self->volume = ENV_MAX; - Operator__SetState( self, OFF ); - return ENV_MAX; - } - break; - } - self->volume = vol; - return vol; -} - -#define TEMPLATE_VOLUME(mode) \ - static Bits Operator__TemplateVolume ## mode(Operator *self) \ - { \ - return Operator__TemplateVolume(self, mode); \ - } - -TEMPLATE_VOLUME(OFF) -TEMPLATE_VOLUME(RELEASE) -TEMPLATE_VOLUME(SUSTAIN) -TEMPLATE_VOLUME(ATTACK) -TEMPLATE_VOLUME(DECAY) - -static const VolumeHandler VolumeHandlerTable[5] = { - &Operator__TemplateVolumeOFF, - &Operator__TemplateVolumeRELEASE, - &Operator__TemplateVolumeSUSTAIN, - &Operator__TemplateVolumeDECAY, - &Operator__TemplateVolumeATTACK, -}; - -static inline Bitu Operator__ForwardVolume(Operator *self) { - return self->currentLevel + (self->volHandler)(self); -} - - -static inline Bitu Operator__ForwardWave(Operator *self) { - self->waveIndex += self->waveCurrent; - return self->waveIndex >> WAVE_SH; -} - -static void Operator__Write20(Operator *self, const Chip* chip, Bit8u val ) { - Bit8u change = (self->reg20 ^ val ); - if ( !change ) - return; - self->reg20 = val; - //Shift the tremolo bit over the entire register, saved a branch, YES! - self->tremoloMask = (Bit8s)(val) >> 7; - self->tremoloMask &= ~(( 1 << ENV_EXTRA ) -1); - //Update specific features based on changes - if ( change & MASK_KSR ) { - Operator__UpdateRates( self, chip ); - } - //With sustain enable the volume doesn't change - if ( self->reg20 & MASK_SUSTAIN || ( !self->releaseAdd ) ) { - self->rateZero |= ( 1 << SUSTAIN ); - } else { - self->rateZero &= ~( 1 << SUSTAIN ); - } - //Frequency multiplier or vibrato changed - if ( change & (0xf | MASK_VIBRATO) ) { - self->freqMul = chip->freqMul[ val & 0xf ]; - Operator__UpdateFrequency(self); - } -} - -static void Operator__Write40(Operator *self, const Chip *chip, Bit8u val ) { - if (!(self->reg40 ^ val )) - return; - self->reg40 = val; - Operator__UpdateAttenuation( self ); -} - -static void Operator__Write60(Operator *self, const Chip* chip, Bit8u val ) { - Bit8u change = self->reg60 ^ val; - self->reg60 = val; - if ( change & 0x0f ) { - Operator__UpdateDecay( self, chip ); - } - if ( change & 0xf0 ) { - Operator__UpdateAttack( self, chip ); - } -} - -static void Operator__Write80(Operator *self, const Chip* chip, Bit8u val ) { - Bit8u change = (self->reg80 ^ val ); - Bit8u sustain; // haleyjd 09/09/10: GNUisms out! - if ( !change ) - return; - self->reg80 = val; - sustain = val >> 4; - //Turn 0xf into 0x1f - sustain |= ( sustain + 1) & 0x10; - self->sustainLevel = sustain << ( ENV_BITS - 5 ); - if ( change & 0x0f ) { - Operator__UpdateRelease( self, chip ); - } -} - -static void Operator__WriteE0(Operator *self, const Chip* chip, Bit8u val ) { - Bit8u waveForm; // haleyjd 09/09/10: GNUisms out! - if ( !(self->regE0 ^ val) ) - return; - //in opl3 mode you can always selet 7 waveforms regardless of waveformselect - waveForm = val & ( ( 0x3 & chip->waveFormMask ) | (0x7 & chip->opl3Active ) ); - self->regE0 = val; -#if( DBOPL_WAVE == WAVE_HANDLER ) - self->waveHandler = WaveHandlerTable[ waveForm ]; -#else - self->waveBase = WaveTable + WaveBaseTable[ waveForm ]; - self->waveStart = WaveStartTable[ waveForm ] << WAVE_SH; - self->waveMask = WaveMaskTable[ waveForm ]; -#endif -} - -static inline void Operator__SetState(Operator *self, Bit8u s ) { - self->state = s; - self->volHandler = VolumeHandlerTable[ s ]; -} - -static inline int Operator__Silent(Operator *self) { - if ( !ENV_SILENT( self->totalLevel + self->volume ) ) - return FALSE; - if ( !(self->rateZero & ( 1 << self->state ) ) ) - return FALSE; - return TRUE; -} - -static inline void Operator__Prepare(Operator *self, const Chip* chip ) { - self->currentLevel = self->totalLevel + (chip->tremoloValue & self->tremoloMask); - self->waveCurrent = self->waveAdd; - if ( self->vibStrength >> chip->vibratoShift ) { - Bit32s add = self->vibrato >> chip->vibratoShift; - //Sign extend over the shift value - Bit32s neg = chip->vibratoSign; - //Negate the add with -1 or 0 - add = ( add ^ neg ) - neg; - self->waveCurrent += add; - } -} - -static void Operator__KeyOn(Operator *self, Bit8u mask ) { - if ( !self->keyOn ) { - //Restart the frequency generator -#if( DBOPL_WAVE > WAVE_HANDLER ) - self->waveIndex = self->waveStart; -#else - self->waveIndex = 0; -#endif - self->rateIndex = 0; - Operator__SetState( self, ATTACK ); - } - self->keyOn |= mask; -} - -static void Operator__KeyOff(Operator *self, Bit8u mask ) { - self->keyOn &= ~mask; - if ( !self->keyOn ) { - if ( self->state != OFF ) { - Operator__SetState( self, RELEASE ); - } - } -} - -static inline Bits Operator__GetWave(Operator *self, Bitu index, Bitu vol ) { -#if( DBOPL_WAVE == WAVE_HANDLER ) - return self->waveHandler( index, vol << ( 3 - ENV_EXTRA ) ); -#elif( DBOPL_WAVE == WAVE_TABLEMUL ) - return(self->waveBase[ index & self->waveMask ] * MulTable[ vol >> ENV_EXTRA ]) >> MUL_SH; -#elif( DBOPL_WAVE == WAVE_TABLELOG ) - Bit32s wave = self->waveBase[ index & self->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 -} - -static inline Bits Operator__GetSample(Operator *self, Bits modulation ) { - Bitu vol = Operator__ForwardVolume(self); - if ( ENV_SILENT( vol ) ) { - //Simply forward the wave - self->waveIndex += self->waveCurrent; - return 0; - } else { - Bitu index = Operator__ForwardWave(self); - index += modulation; - return Operator__GetWave( self, index, vol ); - } -} - -static void Operator__Operator(Operator *self) { - self->chanData = 0; - self->freqMul = 0; - self->waveIndex = 0; - self->waveAdd = 0; - self->waveCurrent = 0; - self->keyOn = 0; - self->ksr = 0; - self->reg20 = 0; - self->reg40 = 0; - self->reg60 = 0; - self->reg80 = 0; - self->regE0 = 0; - Operator__SetState( self, OFF ); - self->rateZero = (1 << OFF); - self->sustainLevel = ENV_MAX; - self->currentLevel = ENV_MAX; - self->totalLevel = ENV_MAX; - self->volume = ENV_MAX; - self->releaseAdd = 0; -} - -/* - Channel -*/ - -static void Channel__Channel(Channel *self) { - Operator__Operator(&self->op[0]); - Operator__Operator(&self->op[1]); - self->old[0] = self->old[1] = 0; - self->chanData = 0; - self->regB0 = 0; - self->regC0 = 0; - self->maskLeft = -1; - self->maskRight = -1; - self->feedback = 31; - self->fourMask = 0; - self->synthHandler = Channel__BlockTemplate_sm2FM; -}; - -static inline Operator* Channel__Op( Channel *self, Bitu index ) { - return &( ( self + (index >> 1) )->op[ index & 1 ]); -} - -static void Channel__SetChanData(Channel *self, const Chip* chip, Bit32u data ) { - Bit32u change = self->chanData ^ data; - self->chanData = data; - Channel__Op( self, 0 )->chanData = data; - Channel__Op( self, 1 )->chanData = data; - //Since a frequency update triggered this, always update frequency - Operator__UpdateFrequency(Channel__Op( self, 0 )); - Operator__UpdateFrequency(Channel__Op( self, 1 )); - if ( change & ( 0xff << SHIFT_KSLBASE ) ) { - Operator__UpdateAttenuation(Channel__Op( self, 0 )); - Operator__UpdateAttenuation(Channel__Op( self, 1 )); - } - if ( change & ( 0xff << SHIFT_KEYCODE ) ) { - Operator__UpdateRates(Channel__Op( self, 0 ), chip); - Operator__UpdateRates(Channel__Op( self, 1 ), chip); - } -} - -static void Channel__UpdateFrequency(Channel *self, const Chip* chip, Bit8u fourOp ) { - //Extrace the frequency bits - Bit32u data = self->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 ); - Channel__SetChanData( self + 0, chip, data ); - if ( fourOp & 0x3f ) { - Channel__SetChanData( self + 1, chip, data ); - } -} - -static void Channel__WriteA0(Channel *self, const Chip* chip, Bit8u val ) { - Bit8u fourOp = chip->reg104 & chip->opl3Active & self->fourMask; - Bit32u change; // haleyjd 09/09/10: GNUisms out! - //Don't handle writes to silent fourop channels - if ( fourOp > 0x80 ) - return; - change = (self->chanData ^ val ) & 0xff; - if ( change ) { - self->chanData ^= change; - Channel__UpdateFrequency( self, chip, fourOp ); - } -} - -static void Channel__WriteB0(Channel *self, const Chip* chip, Bit8u val ) { - Bit8u fourOp = chip->reg104 & chip->opl3Active & self->fourMask; - Bitu change; // haleyjd 09/09/10: GNUisms out! - //Don't handle writes to silent fourop channels - if ( fourOp > 0x80 ) - return; - change = (self->chanData ^ ( val << 8 ) ) & 0x1f00; - if ( change ) { - self->chanData ^= change; - Channel__UpdateFrequency( self, chip, fourOp ); - } - //Check for a change in the keyon/off state - if ( !(( val ^ self->regB0) & 0x20)) - return; - self->regB0 = val; - if ( val & 0x20 ) { - Operator__KeyOn( Channel__Op(self, 0), 0x1 ); - Operator__KeyOn( Channel__Op(self, 1), 0x1 ); - if ( fourOp & 0x3f ) { - Operator__KeyOn( Channel__Op(self + 1, 0), 1 ); - Operator__KeyOn( Channel__Op(self + 1, 1), 1 ); - } - } else { - Operator__KeyOff( Channel__Op(self, 0), 0x1 ); - Operator__KeyOff( Channel__Op(self, 1), 0x1 ); - if ( fourOp & 0x3f ) { - Operator__KeyOff( Channel__Op(self + 1, 0), 1 ); - Operator__KeyOff( Channel__Op(self + 1, 1), 1 ); - } - } -} - -static void Channel__WriteC0(Channel *self, const Chip* chip, Bit8u val ) { - Bit8u change = val ^ self->regC0; - if ( !change ) - return; - self->regC0 = val; - self->feedback = ( val >> 1 ) & 7; - if ( self->feedback ) { - //We shift the input to the right 10 bit wave index value - self->feedback = 9 - self->feedback; - } else { - self->feedback = 31; - } - //Select the new synth mode - if ( chip->opl3Active ) { - //4-op mode enabled for this channel - if ( (chip->reg104 & self->fourMask) & 0x3f ) { - Channel* chan0, *chan1; - Bit8u synth; // haleyjd 09/09/10: GNUisms out! - //Check if it's the 2nd channel in a 4-op - if ( !(self->fourMask & 0x80 ) ) { - chan0 = self; - chan1 = self + 1; - } else { - chan0 = self - 1; - chan1 = self; - } - - 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 ((self->fourMask & 0x40) && ( chip->regBD & 0x20) ) { - - //Regular dual op, am or fm - } else if ( val & 1 ) { - self->synthHandler = Channel__BlockTemplate_sm3AM; - } else { - self->synthHandler = Channel__BlockTemplate_sm3FM; - } - self->maskLeft = ( val & 0x10 ) ? -1 : 0; - self->maskRight = ( val & 0x20 ) ? -1 : 0; - //opl2 active - } else { - //Disable updating percussion channels - if ( (self->fourMask & 0x40) && ( chip->regBD & 0x20 ) ) { - - //Regular dual op, am or fm - } else if ( val & 1 ) { - self->synthHandler = Channel__BlockTemplate_sm2AM; - } else { - self->synthHandler = Channel__BlockTemplate_sm2FM; - } - } -} - -static void Channel__ResetC0(Channel *self, const Chip* chip ) { - Bit8u val = self->regC0; - self->regC0 ^= 0xff; - Channel__WriteC0( self, chip, val ); -}; - -static inline void Channel__GeneratePercussion(Channel *self, Chip* chip, - Bit32s* output, int opl3Mode ) { - Channel* chan = self; - - //BassDrum - Bit32s mod = (Bit32u)((self->old[0] + self->old[1])) >> self->feedback; - Bit32s sample; // haleyjd 09/09/10 - Bit32u noiseBit; - Bit32u c2; - Bit32u c5; - Bit32u phaseBit; - Bit32u hhVol; - Bit32u sdVol; - Bit32u tcVol; - - self->old[0] = self->old[1]; - self->old[1] = Operator__GetSample( Channel__Op(self, 0), mod ); - - //When bassdrum is in AM mode first operator is ignoed - if ( chan->regC0 & 1 ) { - mod = 0; - } else { - mod = self->old[0]; - } - sample = Operator__GetSample( Channel__Op(self, 1), mod ); - - //Precalculate stuff used by other outputs - noiseBit = Chip__ForwardNoise(chip) & 0x1; - c2 = Operator__ForwardWave(Channel__Op(self, 2)); - c5 = Operator__ForwardWave(Channel__Op(self, 5)); - phaseBit = (((c2 & 0x88) ^ ((c2<<5) & 0x80)) | ((c5 ^ (c5<<2)) & 0x20)) ? 0x02 : 0x00; - - //Hi-Hat - hhVol = Operator__ForwardVolume(Channel__Op(self, 2)); - if ( !ENV_SILENT( hhVol ) ) { - Bit32u hhIndex = (phaseBit<<8) | (0x34 << ( phaseBit ^ (noiseBit << 1 ))); - sample += Operator__GetWave( Channel__Op(self, 2), hhIndex, hhVol ); - } - //Snare Drum - sdVol = Operator__ForwardVolume( Channel__Op(self, 3) ); - if ( !ENV_SILENT( sdVol ) ) { - Bit32u sdIndex = ( 0x100 + (c2 & 0x100) ) ^ ( noiseBit << 8 ); - sample += Operator__GetWave( Channel__Op(self, 3), sdIndex, sdVol ); - } - //Tom-tom - sample += Operator__GetSample( Channel__Op(self, 4), 0 ); - - //Top-Cymbal - tcVol = Operator__ForwardVolume(Channel__Op(self, 5)); - if ( !ENV_SILENT( tcVol ) ) { - Bit32u tcIndex = (1 + phaseBit) << 8; - sample += Operator__GetWave( Channel__Op(self, 5), tcIndex, tcVol ); - } - sample <<= 1; - if ( opl3Mode ) { - output[0] += sample; - output[1] += sample; - } else { - output[0] += sample; - } -} - -Channel* Channel__BlockTemplate(Channel *self, Chip* chip, - Bit32u samples, Bit32s* output, - SynthMode mode ) { - Bitu i; - - switch( mode ) { - case sm2AM: - case sm3AM: - if ( Operator__Silent(Channel__Op(self, 0)) - && Operator__Silent(Channel__Op(self, 1))) { - self->old[0] = self->old[1] = 0; - return(self + 1); - } - break; - case sm2FM: - case sm3FM: - if ( Operator__Silent(Channel__Op(self, 1))) { - self->old[0] = self->old[1] = 0; - return (self + 1); - } - break; - case sm3FMFM: - if ( Operator__Silent(Channel__Op(self, 3))) { - self->old[0] = self->old[1] = 0; - return (self + 2); - } - break; - case sm3AMFM: - if ( Operator__Silent( Channel__Op(self, 0) ) - && Operator__Silent( Channel__Op(self, 3) )) { - self->old[0] = self->old[1] = 0; - return (self + 2); - } - break; - case sm3FMAM: - if ( Operator__Silent( Channel__Op(self, 1)) - && Operator__Silent( Channel__Op(self, 3))) { - self->old[0] = self->old[1] = 0; - return (self + 2); - } - break; - case sm3AMAM: - if ( Operator__Silent( Channel__Op(self, 0) ) - && Operator__Silent( Channel__Op(self, 2) ) - && Operator__Silent( Channel__Op(self, 3) )) { - self->old[0] = self->old[1] = 0; - return (self + 2); - } - break; - - default: - abort(); - } - //Init the operators with the the current vibrato and tremolo values - Operator__Prepare( Channel__Op( self, 0 ), chip ); - Operator__Prepare( Channel__Op( self, 1 ), chip ); - if ( mode > sm4Start ) { - Operator__Prepare( Channel__Op( self, 2 ), chip ); - Operator__Prepare( Channel__Op( self, 3 ), chip ); - } - if ( mode > sm6Start ) { - Operator__Prepare( Channel__Op( self, 4 ), chip ); - Operator__Prepare( Channel__Op( self, 5 ), chip ); - } - for ( i = 0; i < samples; i++ ) { - Bit32s mod; // haleyjd 09/09/10: GNUisms out! - Bit32s sample; - Bit32s out0; - - //Early out for percussion handlers - if ( mode == sm2Percussion ) { - Channel__GeneratePercussion( self, chip, output + i, FALSE ); - continue; //Prevent some unitialized value bitching - } else if ( mode == sm3Percussion ) { - Channel__GeneratePercussion( self, chip, output + i * 2, TRUE ); - continue; //Prevent some unitialized value bitching - } - - //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise - mod = (Bit32u)((self->old[0] + self->old[1])) >> self->feedback; - self->old[0] = self->old[1]; - self->old[1] = Operator__GetSample( Channel__Op(self, 0), mod ); - sample = 0; - out0 = self->old[0]; - if ( mode == sm2AM || mode == sm3AM ) { - sample = out0 + Operator__GetSample( Channel__Op(self, 1), 0 ); - } else if ( mode == sm2FM || mode == sm3FM ) { - sample = Operator__GetSample( Channel__Op(self, 1), out0 ); - } else if ( mode == sm3FMFM ) { - Bits next = Operator__GetSample( Channel__Op(self, 1), out0 ); - next = Operator__GetSample( Channel__Op(self, 2), next ); - sample = Operator__GetSample( Channel__Op(self, 3), next ); - } else if ( mode == sm3AMFM ) { - Bits next; // haleyjd 09/09/10: GNUisms out! - sample = out0; - next = Operator__GetSample( Channel__Op(self, 1), 0 ); - next = Operator__GetSample( Channel__Op(self, 2), next ); - sample += Operator__GetSample( Channel__Op(self, 3), next ); - } else if ( mode == sm3FMAM ) { - Bits next; // haleyjd 09/09/10: GNUisms out! - sample = Operator__GetSample( Channel__Op(self, 1), out0 ); - next = Operator__GetSample( Channel__Op(self, 2), 0 ); - sample += Operator__GetSample( Channel__Op(self, 3), next ); - } else if ( mode == sm3AMAM ) { - Bits next; // haleyjd 09/09/10: GNUisms out! - sample = out0; - next = Operator__GetSample( Channel__Op(self, 1), 0 ); - sample += Operator__GetSample( Channel__Op(self, 2), next ); - sample += Operator__GetSample( Channel__Op(self, 3), 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 & self->maskLeft; - output[ i * 2 + 1 ] += sample & self->maskRight; - break; - default: - abort(); - } - } - switch( mode ) { - case sm2AM: - case sm2FM: - case sm3AM: - case sm3FM: - return ( self + 1 ); - case sm3FMFM: - case sm3AMFM: - case sm3FMAM: - case sm3AMAM: - return ( self + 2 ); - case sm2Percussion: - case sm3Percussion: - return( self + 3 ); - default: - abort(); - } - return 0; -} - -/* - Chip -*/ - -void Chip__Chip(Chip *self) { - int i; - - for (i=0; i<18; ++i) { - Channel__Channel(&self->chan[i]); - } - - self->reg08 = 0; - self->reg04 = 0; - self->regBD = 0; - self->reg104 = 0; - self->opl3Active = 0; -} - -static inline Bit32u Chip__ForwardNoise(Chip *self) { - Bitu count; - self->noiseCounter += self->noiseAdd; - count = self->noiseCounter >> LFO_SH; - self->noiseCounter &= WAVE_MASK; - for ( ; count > 0; --count ) { - //Noise calculation from mame - self->noiseValue ^= ( 0x800302 ) & ( 0 - (self->noiseValue & 1 ) ); - self->noiseValue >>= 1; - } - return self->noiseValue; -} - -static inline Bit32u Chip__ForwardLFO(Chip *self, Bit32u samples ) { - Bit32u todo; // haleyjd 09/09/10: GNUisms out!!!!!! - Bit32u count; - - //Current vibrato value, runs 4x slower than tremolo - self->vibratoSign = ( VibratoTable[ self->vibratoIndex >> 2] ) >> 7; - self->vibratoShift = ( VibratoTable[ self->vibratoIndex >> 2] & 7) + self->vibratoStrength; - self->tremoloValue = TremoloTable[ self->tremoloIndex ] >> self->tremoloStrength; - - //Check hom many samples there can be done before the value changes - todo = LFO_MAX - self->lfoCounter; - count = (todo + self->lfoAdd - 1) / self->lfoAdd; - if ( count > samples ) { - count = samples; - self->lfoCounter += count * self->lfoAdd; - } else { - self->lfoCounter += count * self->lfoAdd; - self->lfoCounter &= (LFO_MAX - 1); - //Maximum of 7 vibrato value * 4 - self->vibratoIndex = ( self->vibratoIndex + 1 ) & 31; - //Clip tremolo to the the table size - if ( self->tremoloIndex + 1 < TREMOLO_TABLE ) - ++self->tremoloIndex; - else - self->tremoloIndex = 0; - } - return count; -} - - -static void Chip__WriteBD(Chip *self, Bit8u val ) { - Bit8u change = self->regBD ^ val; - if ( !change ) - return; - self->regBD = val; - //TODO could do this with shift and xor? - self->vibratoStrength = (val & 0x40) ? 0x00 : 0x01; - self->tremoloStrength = (val & 0x80) ? 0x00 : 0x02; - if ( val & 0x20 ) { - //Drum was just enabled, make sure channel 6 has the right synth - if ( change & 0x20 ) { - if ( self->opl3Active ) { - self->chan[6].synthHandler - = Channel__BlockTemplate_sm3Percussion; - } else { - self->chan[6].synthHandler - = Channel__BlockTemplate_sm2Percussion; - } - } - //Bass Drum - if ( val & 0x10 ) { - Operator__KeyOn( &self->chan[6].op[0], 0x2 ); - Operator__KeyOn( &self->chan[6].op[1], 0x2 ); - } else { - Operator__KeyOff( &self->chan[6].op[0], 0x2 ); - Operator__KeyOff( &self->chan[6].op[1], 0x2 ); - } - //Hi-Hat - if ( val & 0x1 ) { - Operator__KeyOn( &self->chan[7].op[0], 0x2 ); - } else { - Operator__KeyOff( &self->chan[7].op[0], 0x2 ); - } - //Snare - if ( val & 0x8 ) { - Operator__KeyOn( &self->chan[7].op[1], 0x2 ); - } else { - Operator__KeyOff( &self->chan[7].op[1], 0x2 ); - } - //Tom-Tom - if ( val & 0x4 ) { - Operator__KeyOn( &self->chan[8].op[0], 0x2 ); - } else { - Operator__KeyOff( &self->chan[8].op[0], 0x2 ); - } - //Top Cymbal - if ( val & 0x2 ) { - Operator__KeyOn( &self->chan[8].op[1], 0x2 ); - } else { - Operator__KeyOff( &self->chan[8].op[1], 0x2 ); - } - //Toggle keyoffs when we turn off the percussion - } else if ( change & 0x20 ) { - //Trigger a reset to setup the original synth handler - Channel__ResetC0( &self->chan[6], self ); - Operator__KeyOff( &self->chan[6].op[0], 0x2 ); - Operator__KeyOff( &self->chan[6].op[1], 0x2 ); - Operator__KeyOff( &self->chan[7].op[0], 0x2 ); - Operator__KeyOff( &self->chan[7].op[1], 0x2 ); - Operator__KeyOff( &self->chan[8].op[0], 0x2 ); - Operator__KeyOff( &self->chan[8].op[1], 0x2 ); - } -} - - -#define REGOP( _FUNC_ ) \ - index = ( ( reg >> 3) & 0x20 ) | ( reg & 0x1f ); \ - if ( OpOffsetTable[ index ] ) { \ - Operator* regOp = (Operator*)( ((char *)self ) + OpOffsetTable[ index ] ); \ - Operator__ ## _FUNC_ (regOp, self, val); \ - } - -#define REGCHAN( _FUNC_ ) \ - index = ( ( reg >> 4) & 0x10 ) | ( reg & 0xf ); \ - if ( ChanOffsetTable[ index ] ) { \ - Channel* regChan = (Channel*)( ((char *)self ) + ChanOffsetTable[ index ] ); \ - Channel__ ## _FUNC_ (regChan, self, val); \ - } - -void Chip__WriteReg(Chip *self, Bit32u reg, Bit8u val ) { - Bitu index; - switch ( (reg & 0xf0) >> 4 ) { - case 0x00 >> 4: - if ( reg == 0x01 ) { - self->waveFormMask = ( val & 0x20 ) ? 0x7 : 0x0; - } else if ( reg == 0x104 ) { - //Only detect changes in lowest 6 bits - if ( !((self->reg104 ^ val) & 0x3f) ) - return; - //Always keep the highest bit enabled, for checking > 0x80 - self->reg104 = 0x80 | ( val & 0x3f ); - } else if ( reg == 0x105 ) { - int i; - - //MAME says the real opl3 doesn't reset anything on opl3 disable/enable till the next write in another register - if ( !((self->opl3Active ^ val) & 1 ) ) - return; - self->opl3Active = ( val & 1 ) ? 0xff : 0; - //Update the 0xc0 register for all channels to signal the switch to mono/stereo handlers - for ( i = 0; i < 18;i++ ) { - Channel__ResetC0( &self->chan[i], self ); - } - } else if ( reg == 0x08 ) { - self->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 ) { - Chip__WriteBD( self, 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(Chip *self, Bit32u port, Bit8u val ) { - switch ( port & 3 ) { - case 0: - return val; - case 2: - if ( self->opl3Active || (val == 0x05) ) - return 0x100 | val; - else - return val; - } - return 0; -} - -void Chip__GenerateBlock2(Chip *self, Bitu total, Bit32s* output ) { - while ( total > 0 ) { - Channel *ch; - int count; - - Bit32u samples = Chip__ForwardLFO( self, total ); - memset(output, 0, sizeof(Bit32s) * samples); - count = 0; - for ( ch = self->chan; ch < self->chan + 9; ) { - count++; - ch = (ch->synthHandler)( ch, self, samples, output ); - } - total -= samples; - output += samples; - } -} - -void Chip__GenerateBlock3(Chip *self, Bitu total, Bit32s* output ) { - while ( total > 0 ) { - int count; - Channel *ch; - - Bit32u samples = Chip__ForwardLFO( self, total ); - memset(output, 0, sizeof(Bit32s) * samples *2); - count = 0; - for ( ch = self->chan; ch < self->chan + 18; ) { - count++; - ch = (ch->synthHandler)( ch, self, samples, output ); - } - total -= samples; - output += samples * 2; - } -} - -void Chip__Setup(Chip *self, Bit32u rate ) { - double original = OPLRATE; - Bit32u i; - Bit32u freqScale; // haleyjd 09/09/10: GNUisms out! -// double original = rate; - double scale = original / (double)rate; - - //Noise counter is run at the same precision as general waves - self->noiseAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); - self->noiseCounter = 0; - self->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 - self->lfoAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); - self->lfoCounter = 0; - self->vibratoIndex = 0; - self->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 ( i = 0; i < 16; i++ ) { - self->freqMul[i] = (Bit32u)( 0.5 + freqScale * FreqCreateTable[ i ] ); - } -#else - freqScale = (Bit32u)( 0.5 + scale * ( 1 << ( WAVE_SH - 1 - 10))); - for ( i = 0; i < 16; i++ ) { - self->freqMul[i] = freqScale * FreqCreateTable[ i ]; - } -#endif - - //-3 since the real envelope takes 8 steps to reach the single value we supply - for ( i = 0; i < 76; i++ ) { - Bit8u index, shift; - EnvelopeSelect( i, &index, &shift ); - self->linearRates[i] = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH + ENV_EXTRA - shift - 3 ))); - } - //Generate the best matching attack rate - for ( i = 0; i < 62; i++ ) { - Bit8u index, shift; - Bit32s original; // haleyjd 09/09/10: GNUisms out! - Bit32s guessAdd; - Bit32s bestAdd; - Bit32u bestDiff; - Bit32u passes; - EnvelopeSelect( i, &index, &shift ); - //Original amount of samples the attack would take - original = (Bit32u)( (AttackSamplesTable[ index ] << shift) / scale); - - guessAdd = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH - shift - 3 ))); - bestAdd = guessAdd; - bestDiff = 1 << 30; - - for ( passes = 0; passes < 16; passes ++ ) { - Bit32s volume = ENV_MAX; - Bit32s samples = 0; - Bit32u count = 0; - Bit32s diff; - Bit32u lDiff; - while ( volume > 0 && samples < original * 2 ) { - Bit32s change; // haleyjd 09/09/10 - count += guessAdd; - change = count >> RATE_SH; - count &= RATE_MASK; - if ( GCC_UNLIKELY(change) ) { // less than 1 % - volume += ( ~volume * change ) >> 3; - } - samples++; - - } - diff = original - samples; - 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--; - } - } - self->attackRates[i] = bestAdd; - } - for ( i = 62; i < 76; i++ ) { - //This should provide instant volume maximizing - self->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 - self->chan[ 0].fourMask = 0x00 | ( 1 << 0 ); - self->chan[ 1].fourMask = 0x80 | ( 1 << 0 ); - self->chan[ 2].fourMask = 0x00 | ( 1 << 1 ); - self->chan[ 3].fourMask = 0x80 | ( 1 << 1 ); - self->chan[ 4].fourMask = 0x00 | ( 1 << 2 ); - self->chan[ 5].fourMask = 0x80 | ( 1 << 2 ); - - self->chan[ 9].fourMask = 0x00 | ( 1 << 3 ); - self->chan[10].fourMask = 0x80 | ( 1 << 3 ); - self->chan[11].fourMask = 0x00 | ( 1 << 4 ); - self->chan[12].fourMask = 0x80 | ( 1 << 4 ); - self->chan[13].fourMask = 0x00 | ( 1 << 5 ); - self->chan[14].fourMask = 0x80 | ( 1 << 5 ); - - //mark the percussion channels - self->chan[ 6].fourMask = 0x40; - self->chan[ 7].fourMask = 0x40; - self->chan[ 8].fourMask = 0x40; - - //Clear Everything in opl3 mode - Chip__WriteReg( self, 0x105, 0x1 ); - for ( i = 0; i < 512; i++ ) { - if ( i == 0x105 ) - continue; - Chip__WriteReg( self, i, 0xff ); - Chip__WriteReg( self, i, 0x0 ); - } - Chip__WriteReg( self, 0x105, 0x0 ); - //Clear everything in opl2 mode - for ( i = 0; i < 255; i++ ) { - Chip__WriteReg( self, i, 0xff ); - Chip__WriteReg( self, i, 0x0 ); - } -} - -static int doneTables = FALSE; -void DBOPL_InitTables( void ) { - int i, oct; - - if ( doneTables ) - return; - doneTables = TRUE; -#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) - //Exponential volume table, same as the real adlib - for ( 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 ( 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 ( 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 ( 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 ( 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 ( 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 ( 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 ( 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 ( oct = 0; oct < 8; oct++ ) { - int base = oct * 8; - for ( 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 ( 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 - { // haleyjd 09/09/10: Driving me #$%^@ insane - Chip *chip = NULL; - for ( i = 0; i < 32; i++ ) { - Bitu index = i & 0xf; - Bitu blah; // haleyjd 09/09/10 - 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; - blah = (Bitu) ( &(chip->chan[ index ]) ); - ChanOffsetTable[i] = blah; - } - //Same for operators - for ( i = 0; i < 64; i++ ) { - Bitu chNum; // haleyjd 09/09/10 - Bitu opNum; - Bitu blah; - Channel* chan = NULL; - if ( i % 8 >= 6 || ( (i / 8) % 4 == 3 ) ) { - OpOffsetTable[i] = 0; - continue; - } - 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; - opNum = ( i % 8 ) / 3; - blah = (Bitu) ( &(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 - } -} - -/* - -Bit32u Handler::WriteAddr( Bit32u port, Bit8u val ) { - return chip.WriteAddr( port, val ); - -} -void Handler::WriteReg( Bit32u addr, Bit8u val ) { - chip.WriteReg( addr, val ); -} - -void Handler::Generate( MixerChannel* chan, Bitu samples ) { - Bit32s buffer[ 512 * 2 ]; - if ( GCC_UNLIKELY(samples > 512) ) - samples = 512; - if ( !chip.opl3Active ) { - chip.GenerateBlock2( samples, buffer ); - chan->AddSamples_m32( samples, buffer ); - } else { - chip.GenerateBlock3( samples, buffer ); - chan->AddSamples_s32( samples, buffer ); - } -} - -void Handler::Init( Bitu rate ) { - InitTables(); - chip.Setup( rate ); -} -*/ - diff --git a/opl/dbopl.h b/opl/dbopl.h deleted file mode 100644 index a8b857b3..00000000 --- a/opl/dbopl.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * 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. - */ - -#include - -//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 - -typedef struct _Chip Chip; -typedef struct _Operator Operator; -typedef struct _Channel Channel; - -typedef uintptr_t Bitu; -typedef intptr_t Bits; -typedef uint32_t Bit32u; -typedef int32_t Bit32s; -typedef uint16_t Bit16u; -typedef int16_t Bit16s; -typedef uint8_t Bit8u; -typedef int8_t Bit8s; - -#if (DBOPL_WAVE == WAVE_HANDLER) -typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume ); -#endif - -#define DB_FASTCALL - -typedef Bits (*VolumeHandler)(Operator *self); -typedef Channel* (*SynthHandler)(Channel *self, 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, -}; - -//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, -} OperatorState; - -struct _Operator { - 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; -}; - -struct _Channel { - Operator op[2]; - 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; - -}; - -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; - -}; - -/* -struct Handler : public Adlib::Handler { - DBOPL::Chip chip; - virtual Bit32u WriteAddr( Bit32u port, Bit8u val ); - virtual void WriteReg( Bit32u addr, Bit8u val ); - virtual void Generate( MixerChannel* chan, Bitu samples ); - virtual void Init( Bitu rate ); -}; -*/ - - -void Chip__Setup(Chip *self, Bit32u rate ); -void DBOPL_InitTables( void ); -void Chip__Chip(Chip *self); -void Chip__WriteReg(Chip *self, Bit32u reg, Bit8u val ); -void Chip__GenerateBlock2(Chip *self, Bitu total, Bit32s* output ); -void Chip__GenerateBlock3(Chip *self, Bitu total, Bit32s* output ); - -// haleyjd 09/09/10: Not standard C. -#ifdef _MSC_VER -#define inline __inline -#endif diff --git a/opl/opl3.c b/opl/opl3.c new file mode 100644 index 00000000..81ef0f6a --- /dev/null +++ b/opl/opl3.c @@ -0,0 +1,1430 @@ +// +// Copyright (C) 2013-2016 Alexey Khokholov (Nuke.YKT) +// +// 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. +// +// +// Nuked OPL3 emulator. +// Thanks: +// MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): +// Feedback and Rhythm part calculation information. +// forums.submarine.org.uk(carbon14, opl3): +// Tremolo and phase generator calculation information. +// OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): +// OPL2 ROMs. +// +// version: 1.7 +// +// Changelog: +// +// v1.1: +// Vibrato's sign fix. +// v1.2: +// Operator key fix. +// Corrected 4-operator mode. +// Corrected rhythm mode. +// Some small fixes. +// v1.2.1: +// Small envelope generator fix. +// Removed EX_Get function(not used) +// v1.3: +// Complete rewrite. +// v1.4: +// New envelope and waveform generator. +// Some small fixes. +// v1.4.1: +// Envelope generator rate calculation fix. +// v1.4.2: +// Version for ZDoom. +// v1.5: +// Optimizations. +// v1.6: +// Improved emulation output. +// v1.6.1: +// Simple YMF289(OPL3-L) emulation. +// v1.7: +// Version for Chocolate Doom. +// + +#include +#include +#include +#include "opl3.h" + +#define RSM_FRAC 10 + +// Channel types + +enum { + ch_2op = 0, + ch_4op = 1, + ch_4op2 = 2, + ch_drum = 3 +}; + +// Envelope key types + +enum { + egk_norm = 0x01, + egk_drum = 0x02 +}; + + +// +// logsin table +// + +static const Bit16u logsinrom[256] = { + 0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, + 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365, + 0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd, + 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261, + 0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f, + 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd, + 0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195, + 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166, + 0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c, + 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118, + 0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8, + 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db, + 0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1, + 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9, + 0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094, + 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081, + 0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070, + 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060, + 0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052, + 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045, + 0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039, + 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f, + 0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026, + 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e, + 0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017, + 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011, + 0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c, + 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007, + 0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004, + 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002, + 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 +}; + +// +// exp table +// + +static const Bit16u exprom[256] = { + 0x000, 0x003, 0x006, 0x008, 0x00b, 0x00e, 0x011, 0x014, + 0x016, 0x019, 0x01c, 0x01f, 0x022, 0x025, 0x028, 0x02a, + 0x02d, 0x030, 0x033, 0x036, 0x039, 0x03c, 0x03f, 0x042, + 0x045, 0x048, 0x04b, 0x04e, 0x051, 0x054, 0x057, 0x05a, + 0x05d, 0x060, 0x063, 0x066, 0x069, 0x06c, 0x06f, 0x072, + 0x075, 0x078, 0x07b, 0x07e, 0x082, 0x085, 0x088, 0x08b, + 0x08e, 0x091, 0x094, 0x098, 0x09b, 0x09e, 0x0a1, 0x0a4, + 0x0a8, 0x0ab, 0x0ae, 0x0b1, 0x0b5, 0x0b8, 0x0bb, 0x0be, + 0x0c2, 0x0c5, 0x0c8, 0x0cc, 0x0cf, 0x0d2, 0x0d6, 0x0d9, + 0x0dc, 0x0e0, 0x0e3, 0x0e7, 0x0ea, 0x0ed, 0x0f1, 0x0f4, + 0x0f8, 0x0fb, 0x0ff, 0x102, 0x106, 0x109, 0x10c, 0x110, + 0x114, 0x117, 0x11b, 0x11e, 0x122, 0x125, 0x129, 0x12c, + 0x130, 0x134, 0x137, 0x13b, 0x13e, 0x142, 0x146, 0x149, + 0x14d, 0x151, 0x154, 0x158, 0x15c, 0x160, 0x163, 0x167, + 0x16b, 0x16f, 0x172, 0x176, 0x17a, 0x17e, 0x181, 0x185, + 0x189, 0x18d, 0x191, 0x195, 0x199, 0x19c, 0x1a0, 0x1a4, + 0x1a8, 0x1ac, 0x1b0, 0x1b4, 0x1b8, 0x1bc, 0x1c0, 0x1c4, + 0x1c8, 0x1cc, 0x1d0, 0x1d4, 0x1d8, 0x1dc, 0x1e0, 0x1e4, + 0x1e8, 0x1ec, 0x1f0, 0x1f5, 0x1f9, 0x1fd, 0x201, 0x205, + 0x209, 0x20e, 0x212, 0x216, 0x21a, 0x21e, 0x223, 0x227, + 0x22b, 0x230, 0x234, 0x238, 0x23c, 0x241, 0x245, 0x249, + 0x24e, 0x252, 0x257, 0x25b, 0x25f, 0x264, 0x268, 0x26d, + 0x271, 0x276, 0x27a, 0x27f, 0x283, 0x288, 0x28c, 0x291, + 0x295, 0x29a, 0x29e, 0x2a3, 0x2a8, 0x2ac, 0x2b1, 0x2b5, + 0x2ba, 0x2bf, 0x2c4, 0x2c8, 0x2cd, 0x2d2, 0x2d6, 0x2db, + 0x2e0, 0x2e5, 0x2e9, 0x2ee, 0x2f3, 0x2f8, 0x2fd, 0x302, + 0x306, 0x30b, 0x310, 0x315, 0x31a, 0x31f, 0x324, 0x329, + 0x32e, 0x333, 0x338, 0x33d, 0x342, 0x347, 0x34c, 0x351, + 0x356, 0x35b, 0x360, 0x365, 0x36a, 0x370, 0x375, 0x37a, + 0x37f, 0x384, 0x38a, 0x38f, 0x394, 0x399, 0x39f, 0x3a4, + 0x3a9, 0x3ae, 0x3b4, 0x3b9, 0x3bf, 0x3c4, 0x3c9, 0x3cf, + 0x3d4, 0x3da, 0x3df, 0x3e4, 0x3ea, 0x3ef, 0x3f5, 0x3fa +}; + +// +// freq mult table multiplied by 2 +// +// 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 +// + +static const Bit8u mt[16] = { + 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 +}; + +// +// ksl table +// + +static const Bit8u kslrom[16] = { + 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64 +}; + +static const Bit8u kslshift[4] = { + 8, 1, 2, 0 +}; + +// +// envelope generator constants +// + +static const Bit8u eg_incstep[3][4][8] = { + { + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + { 0, 1, 0, 1, 0, 1, 0, 1 }, + { 0, 1, 0, 1, 1, 1, 0, 1 }, + { 0, 1, 1, 1, 0, 1, 1, 1 }, + { 0, 1, 1, 1, 1, 1, 1, 1 } + }, + { + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 2, 2, 1, 1, 1, 1, 1, 1 }, + { 2, 2, 1, 1, 2, 2, 1, 1 }, + { 2, 2, 2, 2, 2, 2, 1, 1 } + } +}; + +static const Bit8u eg_incdesc[16] = { + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2 +}; + +static const Bit8s eg_incsh[16] = { + 0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -1, -2 +}; + +// +// address decoding +// + +static const Bit8s ad_slot[0x20] = { + 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1, + 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +static const Bit8u ch_slot[18] = { + 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 +}; + +// +// Envelope generator +// + +typedef Bit16s(*envelope_sinfunc)(Bit16u phase, Bit16u envelope); +typedef void(*envelope_genfunc)(opl3_slot *slott); + +static Bit16s OPL3_EnvelopeCalcExp(Bit32u level) +{ + if (level > 0x1fff) + { + level = 0x1fff; + } + return ((exprom[(level & 0xff) ^ 0xff] | 0x400) << 1) >> (level >> 8); +} + +static Bit16s OPL3_EnvelopeCalcSin0(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + Bit16u neg = 0; + phase &= 0x3ff; + if (phase & 0x200) + { + neg = ~0; + } + if (phase & 0x100) + { + out = logsinrom[(phase & 0xff) ^ 0xff]; + } + else + { + out = logsinrom[phase & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; +} + +static Bit16s OPL3_EnvelopeCalcSin1(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + phase &= 0x3ff; + if (phase & 0x200) + { + out = 0x1000; + } + else if (phase & 0x100) + { + out = logsinrom[(phase & 0xff) ^ 0xff]; + } + else + { + out = logsinrom[phase & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)); +} + +static Bit16s OPL3_EnvelopeCalcSin2(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + phase &= 0x3ff; + if (phase & 0x100) + { + out = logsinrom[(phase & 0xff) ^ 0xff]; + } + else + { + out = logsinrom[phase & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)); +} + +static Bit16s OPL3_EnvelopeCalcSin3(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + phase &= 0x3ff; + if (phase & 0x100) + { + out = 0x1000; + } + else + { + out = logsinrom[phase & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)); +} + +static Bit16s OPL3_EnvelopeCalcSin4(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + Bit16u neg = 0; + phase &= 0x3ff; + if ((phase & 0x300) == 0x100) + { + neg = ~0; + } + if (phase & 0x200) + { + out = 0x1000; + } + else if (phase & 0x80) + { + out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; + } + else + { + out = logsinrom[(phase << 1) & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; +} + +static Bit16s OPL3_EnvelopeCalcSin5(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + phase &= 0x3ff; + if (phase & 0x200) + { + out = 0x1000; + } + else if (phase & 0x80) + { + out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; + } + else + { + out = logsinrom[(phase << 1) & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)); +} + +static Bit16s OPL3_EnvelopeCalcSin6(Bit16u phase, Bit16u envelope) +{ + Bit16u neg = 0; + phase &= 0x3ff; + if (phase & 0x200) + { + neg = ~0; + } + return OPL3_EnvelopeCalcExp(envelope << 3) ^ neg; +} + +static Bit16s OPL3_EnvelopeCalcSin7(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + Bit16u neg = 0; + phase &= 0x3ff; + if (phase & 0x200) + { + neg = ~0; + phase = (phase & 0x1ff) ^ 0x1ff; + } + out = phase << 3; + return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; +} + +static const envelope_sinfunc envelope_sin[8] = { + OPL3_EnvelopeCalcSin0, + OPL3_EnvelopeCalcSin1, + OPL3_EnvelopeCalcSin2, + OPL3_EnvelopeCalcSin3, + OPL3_EnvelopeCalcSin4, + OPL3_EnvelopeCalcSin5, + OPL3_EnvelopeCalcSin6, + OPL3_EnvelopeCalcSin7 +}; + +void OPL3_EnvelopeGenOff(opl3_slot *slot); +void OPL3_EnvelopeGenAttack(opl3_slot *slot); +void OPL3_EnvelopeGenDecay(opl3_slot *slot); +void OPL3_EnvelopeGenSustain(opl3_slot *slot); +void OPL3_EnvelopeGenRelease(opl3_slot *slot); + +envelope_genfunc envelope_gen[5] = { + OPL3_EnvelopeGenOff, + OPL3_EnvelopeGenAttack, + OPL3_EnvelopeGenDecay, + OPL3_EnvelopeGenSustain, + OPL3_EnvelopeGenRelease +}; + +enum envelope_gen_num +{ + envelope_gen_num_off = 0, + envelope_gen_num_attack = 1, + envelope_gen_num_decay = 2, + envelope_gen_num_sustain = 3, + envelope_gen_num_release = 4 +}; + +static Bit8u OPL3_EnvelopeCalcRate(opl3_slot *slot, Bit8u reg_rate) +{ + Bit8u rate; + if (reg_rate == 0x00) + { + return 0x00; + } + rate = (reg_rate << 2) + + (slot->reg_ksr ? slot->channel->ksv : (slot->channel->ksv >> 2)); + if (rate > 0x3c) + { + rate = 0x3c; + } + return rate; +} + +static void OPL3_EnvelopeUpdateKSL(opl3_slot *slot) +{ + Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2) + - ((0x08 - slot->channel->block) << 5); + if (ksl < 0) + { + ksl = 0; + } + slot->eg_ksl = (Bit8u)ksl; +} + +static void OPL3_EnvelopeUpdateRate(opl3_slot *slot) +{ + switch (slot->eg_gen) + { + case envelope_gen_num_off: + case envelope_gen_num_attack: + slot->eg_rate = OPL3_EnvelopeCalcRate(slot, slot->reg_ar); + break; + case envelope_gen_num_decay: + slot->eg_rate = OPL3_EnvelopeCalcRate(slot, slot->reg_dr); + break; + case envelope_gen_num_sustain: + case envelope_gen_num_release: + slot->eg_rate = OPL3_EnvelopeCalcRate(slot, slot->reg_rr); + break; + } +} + +static void OPL3_EnvelopeGenOff(opl3_slot *slot) +{ + slot->eg_rout = 0x1ff; +} + +static void OPL3_EnvelopeGenAttack(opl3_slot *slot) +{ + if (slot->eg_rout == 0x00) + { + slot->eg_gen = envelope_gen_num_decay; + OPL3_EnvelopeUpdateRate(slot); + return; + } + slot->eg_rout += ((~slot->eg_rout) * slot->eg_inc) >> 3; + if (slot->eg_rout < 0x00) + { + slot->eg_rout = 0x00; + } +} + +static void OPL3_EnvelopeGenDecay(opl3_slot *slot) +{ + if (slot->eg_rout >= slot->reg_sl << 4) + { + slot->eg_gen = envelope_gen_num_sustain; + OPL3_EnvelopeUpdateRate(slot); + return; + } + slot->eg_rout += slot->eg_inc; +} + +static void OPL3_EnvelopeGenSustain(opl3_slot *slot) +{ + if (!slot->reg_type) + { + OPL3_EnvelopeGenRelease(slot); + } +} + +static void OPL3_EnvelopeGenRelease(opl3_slot *slot) +{ + if (slot->eg_rout >= 0x1ff) + { + slot->eg_gen = envelope_gen_num_off; + slot->eg_rout = 0x1ff; + OPL3_EnvelopeUpdateRate(slot); + return; + } + slot->eg_rout += slot->eg_inc; +} + +static void OPL3_EnvelopeCalc(opl3_slot *slot) +{ + Bit8u rate_h, rate_l; + Bit8u inc = 0; + rate_h = slot->eg_rate >> 2; + rate_l = slot->eg_rate & 3; + if (eg_incsh[rate_h] > 0) + { + if ((slot->chip->timer & ((1 << eg_incsh[rate_h]) - 1)) == 0) + { + inc = eg_incstep[eg_incdesc[rate_h]][rate_l] + [((slot->chip->timer)>> eg_incsh[rate_h]) & 0x07]; + } + } + else + { + inc = eg_incstep[eg_incdesc[rate_h]][rate_l] + [slot->chip->timer & 0x07] << (-eg_incsh[rate_h]); + } + slot->eg_inc = inc; + slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) + + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; + envelope_gen[slot->eg_gen](slot); +} + +static void OPL3_EnvelopeKeyOn(opl3_slot *slot, Bit8u type) +{ + if (!slot->key) + { + slot->eg_gen = envelope_gen_num_attack; + if ((slot->eg_rate >> 2) != 0x0f) + { + slot->eg_gen = envelope_gen_num_attack; + } + else + { + slot->eg_gen = envelope_gen_num_decay; + slot->eg_rout = 0x00; + } + OPL3_EnvelopeUpdateRate(slot); + slot->pg_phase = 0x00; + } + slot->key |= type; +} + +static void OPL3_EnvelopeKeyOff(opl3_slot *slot, Bit8u type) +{ + if (slot->key) + { + slot->key &= (~type); + if (!slot->key) + { + slot->eg_gen = envelope_gen_num_release; + OPL3_EnvelopeUpdateRate(slot); + } + } +} + +// +// Phase Generator +// + +static void OPL3_PhaseGenerate(opl3_slot *slot) +{ + Bit16u f_num; + Bit32u basefreq; + + f_num = slot->channel->f_num; + if (slot->reg_vib) + { + Bit8s range; + Bit8u vibpos; + + range = (f_num >> 7) & 7; + vibpos = slot->chip->vibpos; + + if (!(vibpos & 3)) + { + range = 0; + } + else if (vibpos & 1) + { + range >>= 1; + } + range >>= slot->chip->vibshift; + + if (vibpos & 4) + { + range = -range; + } + f_num += range; + } + basefreq = (f_num << slot->channel->block) >> 1; + slot->pg_phase += (basefreq * mt[slot->reg_mult]) >> 1; +} + +// +// Noise Generator +// + +static void OPL3_NoiseGenerate(opl3_chip *chip) +{ + if (chip->noise & 0x01) + { + chip->noise ^= 0x800302; + } + chip->noise >>= 1; +} + +// +// Slot +// + +static void OPL3_SlotWrite20(opl3_slot *slot, Bit8u data) +{ + if ((data >> 7) & 0x01) + { + slot->trem = &slot->chip->tremolo; + } + else + { + slot->trem = (Bit8u*)&slot->chip->zeromod; + } + slot->reg_vib = (data >> 6) & 0x01; + slot->reg_type = (data >> 5) & 0x01; + slot->reg_ksr = (data >> 4) & 0x01; + slot->reg_mult = data & 0x0f; + OPL3_EnvelopeUpdateRate(slot); +} + +static void OPL3_SlotWrite40(opl3_slot *slot, Bit8u data) +{ + slot->reg_ksl = (data >> 6) & 0x03; + slot->reg_tl = data & 0x3f; + OPL3_EnvelopeUpdateKSL(slot); +} + +static void OPL3_SlotWrite60(opl3_slot *slot, Bit8u data) +{ + slot->reg_ar = (data >> 4) & 0x0f; + slot->reg_dr = data & 0x0f; + OPL3_EnvelopeUpdateRate(slot); +} + +static void OPL3_SlotWrite80(opl3_slot *slot, Bit8u data) +{ + slot->reg_sl = (data >> 4) & 0x0f; + if (slot->reg_sl == 0x0f) + { + slot->reg_sl = 0x1f; + } + slot->reg_rr = data & 0x0f; + OPL3_EnvelopeUpdateRate(slot); +} + +static void OPL3_SlotWriteE0(opl3_slot *slot, Bit8u data) +{ + slot->reg_wf = data & 0x07; + if (slot->chip->newm == 0x00) + { + slot->reg_wf &= 0x03; + } +} + +static void OPL3_SlotGeneratePhase(opl3_slot *slot, Bit16u phase) +{ + slot->out = envelope_sin[slot->reg_wf](phase, slot->eg_out); +} + +static void OPL3_SlotGenerate(opl3_slot *slot) +{ + OPL3_SlotGeneratePhase(slot, (Bit16u)(slot->pg_phase >> 9) + *slot->mod); +} + +static void OPL3_SlotGenerateZM(opl3_slot *slot) +{ + OPL3_SlotGeneratePhase(slot, 0); +} + +static void OPL3_SlotCalcFB(opl3_slot *slot) +{ + if (slot->channel->fb != 0x00) + { + slot->fbmod = (slot->prout + slot->out) >> (0x09 - slot->channel->fb); + } + else + { + slot->fbmod = 0; + } + slot->prout = slot->out; +} + +// +// Channel +// + +void OPL3_ChannelSetupAlg(opl3_channel *channel); + +static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data) +{ + opl3_channel *channel6; + opl3_channel *channel7; + opl3_channel *channel8; + Bit8u chnum; + + chip->rhy = data & 0x3f; + if (chip->rhy & 0x20) + { + channel6 = &chip->channel[6]; + channel7 = &chip->channel[7]; + channel8 = &chip->channel[8]; + channel6->out[0] = &channel6->slots[1]->out; + channel6->out[1] = &channel6->slots[1]->out; + channel6->out[2] = &chip->zeromod; + channel6->out[3] = &chip->zeromod; + channel7->out[0] = &channel7->slots[0]->out; + channel7->out[1] = &channel7->slots[0]->out; + channel7->out[2] = &channel7->slots[1]->out; + channel7->out[3] = &channel7->slots[1]->out; + channel8->out[0] = &channel8->slots[0]->out; + channel8->out[1] = &channel8->slots[0]->out; + channel8->out[2] = &channel8->slots[1]->out; + channel8->out[3] = &channel8->slots[1]->out; + for (chnum = 6; chnum < 9; chnum++) + { + chip->channel[chnum].chtype = ch_drum; + } + OPL3_ChannelSetupAlg(channel6); + //hh + if (chip->rhy & 0x01) + { + OPL3_EnvelopeKeyOn(channel7->slots[0], egk_drum); + } + else + { + OPL3_EnvelopeKeyOff(channel7->slots[0], egk_drum); + } + //tc + if (chip->rhy & 0x02) + { + OPL3_EnvelopeKeyOn(channel8->slots[1], egk_drum); + } + else + { + OPL3_EnvelopeKeyOff(channel8->slots[1], egk_drum); + } + //tom + if (chip->rhy & 0x04) + { + OPL3_EnvelopeKeyOn(channel8->slots[0], egk_drum); + } + else + { + OPL3_EnvelopeKeyOff(channel8->slots[0], egk_drum); + } + //sd + if (chip->rhy & 0x08) + { + OPL3_EnvelopeKeyOn(channel7->slots[1], egk_drum); + } + else + { + OPL3_EnvelopeKeyOff(channel7->slots[1], egk_drum); + } + //bd + if (chip->rhy & 0x10) + { + OPL3_EnvelopeKeyOn(channel6->slots[0], egk_drum); + OPL3_EnvelopeKeyOn(channel6->slots[1], egk_drum); + } + else + { + OPL3_EnvelopeKeyOff(channel6->slots[0], egk_drum); + OPL3_EnvelopeKeyOff(channel6->slots[1], egk_drum); + } + } + else + { + for (chnum = 6; chnum < 9; chnum++) + { + chip->channel[chnum].chtype = ch_2op; + OPL3_ChannelSetupAlg(&chip->channel[chnum]); + } + } +} + +static void OPL3_ChannelWriteA0(opl3_channel *channel, Bit8u data) +{ + if (channel->chip->newm && channel->chtype == ch_4op2) + { + return; + } + channel->f_num = (channel->f_num & 0x300) | data; + channel->ksv = (channel->block << 1) + | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); + OPL3_EnvelopeUpdateKSL(channel->slots[0]); + OPL3_EnvelopeUpdateKSL(channel->slots[1]); + OPL3_EnvelopeUpdateRate(channel->slots[0]); + OPL3_EnvelopeUpdateRate(channel->slots[1]); + if (channel->chip->newm && channel->chtype == ch_4op) + { + channel->pair->f_num = channel->f_num; + channel->pair->ksv = channel->ksv; + OPL3_EnvelopeUpdateKSL(channel->pair->slots[0]); + OPL3_EnvelopeUpdateKSL(channel->pair->slots[1]); + OPL3_EnvelopeUpdateRate(channel->pair->slots[0]); + OPL3_EnvelopeUpdateRate(channel->pair->slots[1]); + } +} + +static void OPL3_ChannelWriteB0(opl3_channel *channel, Bit8u data) +{ + if (channel->chip->newm && channel->chtype == ch_4op2) + { + return; + } + channel->f_num = (channel->f_num & 0xff) | ((data & 0x03) << 8); + channel->block = (data >> 2) & 0x07; + channel->ksv = (channel->block << 1) + | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); + OPL3_EnvelopeUpdateKSL(channel->slots[0]); + OPL3_EnvelopeUpdateKSL(channel->slots[1]); + OPL3_EnvelopeUpdateRate(channel->slots[0]); + OPL3_EnvelopeUpdateRate(channel->slots[1]); + if (channel->chip->newm && channel->chtype == ch_4op) + { + channel->pair->f_num = channel->f_num; + channel->pair->block = channel->block; + channel->pair->ksv = channel->ksv; + OPL3_EnvelopeUpdateKSL(channel->pair->slots[0]); + OPL3_EnvelopeUpdateKSL(channel->pair->slots[1]); + OPL3_EnvelopeUpdateRate(channel->pair->slots[0]); + OPL3_EnvelopeUpdateRate(channel->pair->slots[1]); + } +} + +static void OPL3_ChannelSetupAlg(opl3_channel *channel) +{ + if (channel->chtype == ch_drum) + { + switch (channel->alg & 0x01) + { + case 0x00: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->slots[0]->out; + break; + case 0x01: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->chip->zeromod; + break; + } + return; + } + if (channel->alg & 0x08) + { + return; + } + if (channel->alg & 0x04) + { + channel->pair->out[0] = &channel->chip->zeromod; + channel->pair->out[1] = &channel->chip->zeromod; + channel->pair->out[2] = &channel->chip->zeromod; + channel->pair->out[3] = &channel->chip->zeromod; + switch (channel->alg & 0x03) + { + case 0x00: + channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; + channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; + channel->slots[0]->mod = &channel->pair->slots[1]->out; + channel->slots[1]->mod = &channel->slots[0]->out; + channel->out[0] = &channel->slots[1]->out; + channel->out[1] = &channel->chip->zeromod; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; + break; + case 0x01: + channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; + channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; + channel->slots[0]->mod = &channel->chip->zeromod; + channel->slots[1]->mod = &channel->slots[0]->out; + channel->out[0] = &channel->pair->slots[1]->out; + channel->out[1] = &channel->slots[1]->out; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; + break; + case 0x02: + channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; + channel->pair->slots[1]->mod = &channel->chip->zeromod; + channel->slots[0]->mod = &channel->pair->slots[1]->out; + channel->slots[1]->mod = &channel->slots[0]->out; + channel->out[0] = &channel->pair->slots[0]->out; + channel->out[1] = &channel->slots[1]->out; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; + break; + case 0x03: + channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; + channel->pair->slots[1]->mod = &channel->chip->zeromod; + channel->slots[0]->mod = &channel->pair->slots[1]->out; + channel->slots[1]->mod = &channel->chip->zeromod; + channel->out[0] = &channel->pair->slots[0]->out; + channel->out[1] = &channel->slots[0]->out; + channel->out[2] = &channel->slots[1]->out; + channel->out[3] = &channel->chip->zeromod; + break; + } + } + else + { + switch (channel->alg & 0x01) + { + case 0x00: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->slots[0]->out; + channel->out[0] = &channel->slots[1]->out; + channel->out[1] = &channel->chip->zeromod; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; + break; + case 0x01: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->chip->zeromod; + channel->out[0] = &channel->slots[0]->out; + channel->out[1] = &channel->slots[1]->out; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; + break; + } + } +} + +static void OPL3_ChannelWriteC0(opl3_channel *channel, Bit8u data) +{ + channel->fb = (data & 0x0e) >> 1; + channel->con = data & 0x01; + channel->alg = channel->con; + if (channel->chip->newm) + { + if (channel->chtype == ch_4op) + { + channel->pair->alg = 0x04 | (channel->con << 1) | (channel->pair->con); + channel->alg = 0x08; + OPL3_ChannelSetupAlg(channel->pair); + } + else if (channel->chtype == ch_4op2) + { + channel->alg = 0x04 | (channel->pair->con << 1) | (channel->con); + channel->pair->alg = 0x08; + OPL3_ChannelSetupAlg(channel); + } + else + { + OPL3_ChannelSetupAlg(channel); + } + } + else + { + OPL3_ChannelSetupAlg(channel); + } + if (channel->chip->newm) + { + channel->cha = ((data >> 4) & 0x01) ? ~0 : 0; + channel->chb = ((data >> 5) & 0x01) ? ~0 : 0; + } + else + { + channel->cha = channel->chb = ~0; + } +} + +static void OPL3_ChannelKeyOn(opl3_channel *channel) +{ + if (channel->chip->newm) + { + if (channel->chtype == ch_4op) + { + OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); + OPL3_EnvelopeKeyOn(channel->pair->slots[0], egk_norm); + OPL3_EnvelopeKeyOn(channel->pair->slots[1], egk_norm); + } + else if (channel->chtype == ch_2op || channel->chtype == ch_drum) + { + OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); + } + } + else + { + OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); + } +} + +static void OPL3_ChannelKeyOff(opl3_channel *channel) +{ + if (channel->chip->newm) + { + if (channel->chtype == ch_4op) + { + OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); + OPL3_EnvelopeKeyOff(channel->pair->slots[0], egk_norm); + OPL3_EnvelopeKeyOff(channel->pair->slots[1], egk_norm); + } + else if (channel->chtype == ch_2op || channel->chtype == ch_drum) + { + OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); + } + } + else + { + OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); + } +} + +static void OPL3_ChannelSet4Op(opl3_chip *chip, Bit8u data) +{ + Bit8u bit; + Bit8u chnum; + for (bit = 0; bit < 6; bit++) + { + chnum = bit; + if (bit >= 3) + { + chnum += 9 - 3; + } + if ((data >> bit) & 0x01) + { + chip->channel[chnum].chtype = ch_4op; + chip->channel[chnum + 3].chtype = ch_4op2; + } + else + { + chip->channel[chnum].chtype = ch_2op; + chip->channel[chnum + 3].chtype = ch_2op; + } + } +} + +static Bit16s OPL3_ClipSample(Bit32s sample) +{ + if (sample > 32767) + { + sample = 32767; + } + else if (sample < -32768) + { + sample = -32768; + } + return (Bit16s)sample; +} + +static void OPL3_GenerateRhythm1(opl3_chip *chip) +{ + opl3_channel *channel6; + opl3_channel *channel7; + opl3_channel *channel8; + Bit16u phase14; + Bit16u phase17; + Bit16u phase; + Bit16u phasebit; + + channel6 = &chip->channel[6]; + channel7 = &chip->channel[7]; + channel8 = &chip->channel[8]; + OPL3_SlotGenerate(channel6->slots[0]); + phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; + phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; + phase = 0x00; + //hh tc phase bit + phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) + | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; + //hh + phase = (phasebit << 9) + | (0x34 << ((phasebit ^ (chip->noise & 0x01) << 1))); + OPL3_SlotGeneratePhase(channel7->slots[0], phase); + //tt + OPL3_SlotGenerateZM(channel8->slots[0]); +} + +static void OPL3_GenerateRhythm2(opl3_chip *chip) +{ + opl3_channel *channel6; + opl3_channel *channel7; + opl3_channel *channel8; + Bit16u phase14; + Bit16u phase17; + Bit16u phase; + Bit16u phasebit; + + channel6 = &chip->channel[6]; + channel7 = &chip->channel[7]; + channel8 = &chip->channel[8]; + OPL3_SlotGenerate(channel6->slots[1]); + phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; + phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; + phase = 0x00; + //hh tc phase bit + phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) + | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; + //sd + phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8); + OPL3_SlotGeneratePhase(channel7->slots[1], phase); + //tc + phase = 0x100 | (phasebit << 9); + OPL3_SlotGeneratePhase(channel8->slots[1], phase); +} + +void OPL3_Generate(opl3_chip *chip, Bit16s *buf) +{ + Bit8u ii; + Bit8u jj; + Bit16s accm; + + buf[1] = OPL3_ClipSample(chip->mixbuff[1]); + + for (ii = 0; ii < 12; ii++) + { + OPL3_SlotCalcFB(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); + OPL3_EnvelopeCalc(&chip->slot[ii]); + OPL3_SlotGenerate(&chip->slot[ii]); + } + + for (ii = 12; ii < 15; ii++) + { + OPL3_SlotCalcFB(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); + OPL3_EnvelopeCalc(&chip->slot[ii]); + } + + if (chip->rhy & 0x20) + { + OPL3_GenerateRhythm1(chip); + } + else + { + OPL3_SlotGenerate(&chip->slot[12]); + OPL3_SlotGenerate(&chip->slot[13]); + OPL3_SlotGenerate(&chip->slot[14]); + } + + chip->mixbuff[0] = 0; + for (ii = 0; ii < 18; ii++) + { + accm = 0; + for (jj = 0; jj < 4; jj++) + { + accm += *chip->channel[ii].out[jj]; + } + chip->mixbuff[0] += (Bit16s)(accm & chip->channel[ii].cha); + } + + for (ii = 15; ii < 18; ii++) + { + OPL3_SlotCalcFB(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); + OPL3_EnvelopeCalc(&chip->slot[ii]); + } + + if (chip->rhy & 0x20) + { + OPL3_GenerateRhythm2(chip); + } + else + { + OPL3_SlotGenerate(&chip->slot[15]); + OPL3_SlotGenerate(&chip->slot[16]); + OPL3_SlotGenerate(&chip->slot[17]); + } + + buf[0] = OPL3_ClipSample(chip->mixbuff[0]); + + for (ii = 18; ii < 33; ii++) + { + OPL3_SlotCalcFB(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); + OPL3_EnvelopeCalc(&chip->slot[ii]); + OPL3_SlotGenerate(&chip->slot[ii]); + } + + chip->mixbuff[1] = 0; + for (ii = 0; ii < 18; ii++) + { + accm = 0; + for (jj = 0; jj < 4; jj++) + { + accm += *chip->channel[ii].out[jj]; + } + chip->mixbuff[1] += (Bit16s)(accm & chip->channel[ii].chb); + } + + for (ii = 33; ii < 36; ii++) + { + OPL3_SlotCalcFB(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); + OPL3_EnvelopeCalc(&chip->slot[ii]); + OPL3_SlotGenerate(&chip->slot[ii]); + } + + OPL3_NoiseGenerate(chip); + + if ((chip->timer & 0x3f) == 0x3f) + { + chip->tremolopos = (chip->tremolopos + 1) % 210; + if (chip->tremolopos < 105) + { + chip->tremolo = chip->tremolopos >> chip->tremoloshift; + } + else + { + chip->tremolo = (210 - chip->tremolopos) >> chip->tremoloshift; + } + } + + if ((chip->timer & 0x3ff) == 0x3ff) + { + chip->vibpos = (chip->vibpos + 1) & 7; + } + + chip->timer++; + + while (chip->writebuf_cur != chip->writebuf_last + && chip->writebuf[chip->writebuf_cur].time <= chip->writebuf_samplecnt) + { + OPL3_WriteReg(chip, chip->writebuf[chip->writebuf_cur].reg, + chip->writebuf[chip->writebuf_cur].data); + chip->writebuf_cur = (chip->writebuf_cur + 1) % OPL_WRITEBUF_SIZE; + } + chip->writebuf_samplecnt++; +} + +void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf) +{ + while (chip->samplecnt >= chip->rateratio) + { + chip->oldsamples[0] = chip->samples[0]; + chip->oldsamples[1] = chip->samples[1]; + OPL3_Generate(chip, chip->samples); + chip->samplecnt -= chip->rateratio; + } + buf[0] = (Bit16s)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) + + chip->samples[0] * chip->samplecnt) / chip->rateratio); + buf[1] = (Bit16s)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) + + chip->samples[1] * chip->samplecnt) / chip->rateratio); + chip->samplecnt += 1 << RSM_FRAC; +} + +void OPL3_Reset(opl3_chip *chip, Bit32u samplerate) +{ + Bit8u slotnum; + Bit8u channum; + + memset(chip, 0, sizeof(opl3_chip)); + for (slotnum = 0; slotnum < 36; slotnum++) + { + chip->slot[slotnum].chip = chip; + chip->slot[slotnum].mod = &chip->zeromod; + chip->slot[slotnum].eg_rout = 0x1ff; + chip->slot[slotnum].eg_out = 0x1ff; + chip->slot[slotnum].eg_gen = envelope_gen_num_off; + chip->slot[slotnum].trem = (Bit8u*)&chip->zeromod; + } + for (channum = 0; channum < 18; channum++) + { + chip->channel[channum].slots[0] = &chip->slot[ch_slot[channum]]; + chip->channel[channum].slots[1] = &chip->slot[ch_slot[channum] + 3]; + chip->slot[ch_slot[channum]].channel = &chip->channel[channum]; + chip->slot[ch_slot[channum] + 3].channel = &chip->channel[channum]; + if ((channum % 9) < 3) + { + chip->channel[channum].pair = &chip->channel[channum + 3]; + } + else if ((channum % 9) < 6) + { + chip->channel[channum].pair = &chip->channel[channum - 3]; + } + chip->channel[channum].chip = chip; + chip->channel[channum].out[0] = &chip->zeromod; + chip->channel[channum].out[1] = &chip->zeromod; + chip->channel[channum].out[2] = &chip->zeromod; + chip->channel[channum].out[3] = &chip->zeromod; + chip->channel[channum].chtype = ch_2op; + chip->channel[channum].cha = ~0; + chip->channel[channum].chb = ~0; + OPL3_ChannelSetupAlg(&chip->channel[channum]); + } + chip->noise = 0x306600; + chip->rateratio = (samplerate << RSM_FRAC) / 49716; +} + +void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v) +{ + Bit8u high = (reg >> 8) & 0x01; + Bit8u regm = reg & 0xff; + switch (regm & 0xf0) + { + case 0x00: + if (high) + { + switch (regm & 0x0f) + { + case 0x04: + OPL3_ChannelSet4Op(chip, v); + break; + case 0x05: + chip->newm = v & 0x01; + break; + } + } + else + { + switch (regm & 0x0f) + { + case 0x08: + chip->nts = (v >> 6) & 0x01; + break; + } + } + break; + case 0x20: + case 0x30: + if (ad_slot[regm & 0x1f] >= 0) + { + OPL3_SlotWrite20(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); + } + break; + case 0x40: + case 0x50: + if (ad_slot[regm & 0x1f] >= 0) + { + OPL3_SlotWrite40(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); + } + break; + case 0x60: + case 0x70: + if (ad_slot[regm & 0x1f] >= 0) + { + OPL3_SlotWrite60(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); + } + break; + case 0x80: + case 0x90: + if (ad_slot[regm & 0x1f] >= 0) + { + OPL3_SlotWrite80(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); + } + break; + case 0xe0: + case 0xf0: + if (ad_slot[regm & 0x1f] >= 0) + { + OPL3_SlotWriteE0(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); + } + break; + case 0xa0: + if ((regm & 0x0f) < 9) + { + OPL3_ChannelWriteA0(&chip->channel[9 * high + (regm & 0x0f)], v); + } + break; + case 0xb0: + if (regm == 0xbd && !high) + { + chip->tremoloshift = (((v >> 7) ^ 1) << 1) + 2; + chip->vibshift = ((v >> 6) & 0x01) ^ 1; + OPL3_ChannelUpdateRhythm(chip, v); + } + else if ((regm & 0x0f) < 9) + { + OPL3_ChannelWriteB0(&chip->channel[9 * high + (regm & 0x0f)], v); + if (v & 0x20) + { + OPL3_ChannelKeyOn(&chip->channel[9 * high + (regm & 0x0f)]); + } + else + { + OPL3_ChannelKeyOff(&chip->channel[9 * high + (regm & 0x0f)]); + } + } + break; + case 0xc0: + if ((regm & 0x0f) < 9) + { + OPL3_ChannelWriteC0(&chip->channel[9 * high + (regm & 0x0f)], v); + } + break; + } +} + +void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v) +{ + Bit64u time1, time2; + chip->writebuf[chip->writebuf_last % OPL_WRITEBUF_SIZE].reg = reg; + chip->writebuf[chip->writebuf_last % OPL_WRITEBUF_SIZE].data = v; + time1 = chip->writebuf_lasttime + OPL_WRITEBUF_DELAY; + time2 = chip->writebuf_samplecnt; + + if (time1 < time2) + { + time1 = time2; + } + + chip->writebuf[chip->writebuf_last % OPL_WRITEBUF_SIZE].time = time1; + chip->writebuf_lasttime = time1; + chip->writebuf_last = (chip->writebuf_last + 1) % OPL_WRITEBUF_SIZE; +} + +void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples) +{ + Bit32u i; + + for(i = 0; i < numsamples; i++) + { + OPL3_GenerateResampled(chip, sndptr); + sndptr += 2; + } +} diff --git a/opl/opl3.h b/opl/opl3.h new file mode 100644 index 00000000..7d2ace42 --- /dev/null +++ b/opl/opl3.h @@ -0,0 +1,135 @@ +// +// Copyright (C) 2013-2016 Alexey Khokholov (Nuke.YKT) +// +// 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. +// +// +// Nuked OPL3 emulator. +// Thanks: +// MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): +// Feedback and Rhythm part calculation information. +// forums.submarine.org.uk(carbon14, opl3): +// Tremolo and phase generator calculation information. +// OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): +// OPL2 ROMs. +// +// version: 1.7 +// + +#ifndef OPL_OPL3_H +#define OPL_OPL3_H + +#include + +#define OPL_WRITEBUF_SIZE 1024 +#define OPL_WRITEBUF_DELAY 2 + +typedef uintptr_t Bitu; +typedef intptr_t Bits; +typedef uint64_t Bit64u; +typedef int64_t Bit64s; +typedef uint32_t Bit32u; +typedef int32_t Bit32s; +typedef uint16_t Bit16u; +typedef int16_t Bit16s; +typedef uint8_t Bit8u; +typedef int8_t Bit8s; + +typedef struct _opl3_slot opl3_slot; +typedef struct _opl3_channel opl3_channel; +typedef struct _opl3_chip opl3_chip; + +struct _opl3_slot { + opl3_channel *channel; + opl3_chip *chip; + Bit16s out; + Bit16s fbmod; + Bit16s *mod; + Bit16s prout; + Bit16s eg_rout; + Bit16s eg_out; + Bit8u eg_inc; + Bit8u eg_gen; + Bit8u eg_rate; + Bit8u eg_ksl; + Bit8u *trem; + Bit8u reg_vib; + Bit8u reg_type; + Bit8u reg_ksr; + Bit8u reg_mult; + Bit8u reg_ksl; + Bit8u reg_tl; + Bit8u reg_ar; + Bit8u reg_dr; + Bit8u reg_sl; + Bit8u reg_rr; + Bit8u reg_wf; + Bit8u key; + Bit32u pg_phase; + Bit32u timer; +}; + +struct _opl3_channel { + opl3_slot *slots[2]; + opl3_channel *pair; + opl3_chip *chip; + Bit16s *out[4]; + Bit8u chtype; + Bit16u f_num; + Bit8u block; + Bit8u fb; + Bit8u con; + Bit8u alg; + Bit8u ksv; + Bit16u cha, chb; +}; + +typedef struct _opl3_writebuf { + Bit64u time; + Bit16u reg; + Bit8u data; +} opl3_writebuf; + +struct _opl3_chip { + opl3_channel channel[18]; + opl3_slot slot[36]; + Bit16u timer; + Bit8u newm; + Bit8u nts; + Bit8u rhy; + Bit8u vibpos; + Bit8u vibshift; + Bit8u tremolo; + Bit8u tremolopos; + Bit8u tremoloshift; + Bit32u noise; + Bit16s zeromod; + Bit32s mixbuff[2]; + //OPL3L + Bit32s rateratio; + Bit32s samplecnt; + Bit16s oldsamples[2]; + Bit16s samples[2]; + + Bit64u writebuf_samplecnt; + Bit32u writebuf_cur; + Bit32u writebuf_last; + Bit64u writebuf_lasttime; + opl3_writebuf writebuf[OPL_WRITEBUF_SIZE]; +}; + +void OPL3_Generate(opl3_chip *chip, Bit16s *buf); +void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf); +void OPL3_Reset(opl3_chip *chip, Bit32u samplerate); +void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v); +void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v); +void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples); +#endif diff --git a/opl/opl_sdl.c b/opl/opl_sdl.c index 54164f34..370e6b87 100644 --- a/opl/opl_sdl.c +++ b/opl/opl_sdl.c @@ -25,7 +25,7 @@ #include "SDL.h" #include "SDL_mixer.h" -#include "dbopl.h" +#include "opl3.h" #include "opl.h" #include "opl_internal.h" @@ -70,7 +70,7 @@ static uint64_t pause_offset; // OPL software emulator structure. -static Chip opl_chip; +static opl3_chip opl_chip; static int opl_opl3mode; // Temporary mixing buffer used by the mixing callback. @@ -165,30 +165,7 @@ static void FillBuffer(int16_t *buffer, unsigned int nsamples) assert(nsamples < mixing_freq); - if (opl_opl3mode) - { - Chip__GenerateBlock3(&opl_chip, nsamples, mix_buffer); - - // Mix into the destination buffer, doubling up into stereo. - - for (i=0; i