diff options
Diffstat (limited to 'src/chips')
| -rw-r--r-- | src/chips/dosbox/dbopl.cpp | 3561 | ||||
| -rw-r--r-- | src/chips/dosbox/dbopl.h | 517 | ||||
| -rw-r--r-- | src/chips/dosbox_opl3.cpp | 90 | ||||
| -rw-r--r-- | src/chips/dosbox_opl3.h | 21 | ||||
| -rw-r--r-- | src/chips/nuked/nukedopl3.c | 176 | ||||
| -rw-r--r-- | src/chips/nuked/nukedopl3.h | 2 | ||||
| -rw-r--r-- | src/chips/nuked/nukedopl3_174.c | 206 | ||||
| -rw-r--r-- | src/chips/nuked/nukedopl3_174.h | 2 | ||||
| -rw-r--r-- | src/chips/nuked_opl3.cpp | 62 | ||||
| -rw-r--r-- | src/chips/nuked_opl3.h | 21 | ||||
| -rw-r--r-- | src/chips/nuked_opl3_v174.cpp | 62 | ||||
| -rw-r--r-- | src/chips/nuked_opl3_v174.h | 21 | ||||
| -rw-r--r-- | src/chips/opl_chip_base.cpp | 52 | ||||
| -rw-r--r-- | src/chips/opl_chip_base.h | 81 | ||||
| -rw-r--r-- | src/chips/opl_chip_base.tcc | 216 | 
15 files changed, 2354 insertions, 2736 deletions
diff --git a/src/chips/dosbox/dbopl.cpp b/src/chips/dosbox/dbopl.cpp index 3e21772..7d78c5f 100644 --- a/src/chips/dosbox/dbopl.cpp +++ b/src/chips/dosbox/dbopl.cpp @@ -1,10 +1,5 @@ -//#ifdef ADLMIDI_USE_DOSBOX_OPL - -#ifdef __MINGW32__ -typedef struct vswprintf {} swprintf; -#endif  /* - *  Copyright (C) 2002-2010  The DOSBox Team + *  Copyright (C) 2002-2018  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 @@ -22,22 +17,21 @@ typedef struct vswprintf {} swprintf;   */  /* -    DOSBox implementation of a combined Yamaha YMF262 and Yamaha YM3812 emulator. -    Enabling the opl3 bit will switch the emulator to stereo opl3 output instead of regular mono opl2 -    Except for the table generation it's all integer math -    Can choose different types of generators, using muls and bigger tables, try different ones for slower platforms -    The generation was based on the MAME implementation but tried to have it use less memory and be faster in general -    MAME uses much bigger envelope tables and this will be the biggest cause of it sounding different at times - -    //TODO Don't delay first operator 1 sample in opl3 mode -    //TODO Maybe not use class method pointers but a regular function pointers with operator as first parameter -    //TODO Fix panning for the Percussion channels, would any opl3 player use it and actually really change it though? -    //TODO Check if having the same accuracy in all frequency multipliers sounds better or not - -    //DUNNO Keyon in 4op, switch to 2op without keyoff. +	DOSBox implementation of a combined Yamaha YMF262 and Yamaha YM3812 emulator. +	Enabling the opl3 bit will switch the emulator to stereo opl3 output instead of regular mono opl2 +	Except for the table generation it's all integer math +	Can choose different types of generators, using muls and bigger tables, try different ones for slower platforms +	The generation was based on the MAME implementation but tried to have it use less memory and be faster in general +	MAME uses much bigger envelope tables and this will be the biggest cause of it sounding different at times + +	//TODO Don't delay first operator 1 sample in opl3 mode +	//TODO Maybe not use class method pointers but a regular function pointers with operator as first parameter +	//TODO Fix panning for the Percussion channels, would any opl3 player use it and actually really change it though? +	//TODO Check if having the same accuracy in all frequency multipliers sounds better or not + +	//DUNNO Keyon in 4op, switch to 2op without keyoff.  */ -/* $Id: dbopl.cpp,v 1.10 2009-06-10 19:54:51 harekiet Exp $ */  #include <math.h> @@ -45,2001 +39,1580 @@ typedef struct vswprintf {} swprintf;  #include <string.h>  #include "dbopl.h" -#define DB_MAX(x, y) ((x) > (y) ? (x) : (y)) -#define DB_MIN(x, y) ((x) < (y) ? (x) : (y)) +#if defined(__GNUC__) && __GNUC__ > 3 +#define INLINE inline __attribute__((__always_inline__)) +#elif defined(_MSC_VER) +#define INLINE __forceinline +#else +#define INLINE inline +#endif -#define DBOPL_CLAMP(V, MIN, MAX) DB_MAX(DB_MIN(V, (MAX)), (MIN)) +#if defined(__GNUC__) +#if !defined(__clang__) +#define GCC_LIKELY(x) __builtin_expect(x, 1) +#define GCC_UNLIKELY(x) __builtin_expect(x, 0) +#else  // !defined(__clang__) +#if !defined (__c2__) && defined(__has_builtin) +#if __has_builtin(__builtin_expect) +#define GCC_LIKELY(x) __builtin_expect(x, 1) +#define GCC_UNLIKELY(x) __builtin_expect(x, 0) +#endif  // __has_builtin(__builtin_expect) +#endif  // !defined (__c2__) && defined(__has_builtin) +#endif  // !defined(__clang__) +#endif  // defined(__GNUC__) + +#if !defined(GCC_LIKELY) +#define GCC_LIKELY(x) (x) +#define GCC_UNLIKELY(x) (x) +#endif  #ifndef PI  #define PI 3.14159265358979323846  #endif -namespace DBOPL -{ +namespace DBOPL { -#define OPLRATE     ((double)(14318180.0 / 288.0)) +#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 +//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 +//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 ) ) +//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 +//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 +//Check some ranges +#if ENV_EXTRA > 3  #error Too many envelope bits -    #endif +#endif -    //How much to substract from the base value for the final attenuation -    static const Bit8u KslCreateTable[16] = -    { -        //0 will always be be lower than 7 * 8 -        64, 32, 24, 19, -        16, 12, 11, 10, -        8,  6,  5,  4, -        3,  2,  1,  0, -    }; +//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) -    }; +static const Bit8u FreqCreateTable[16] = { +	M(0.5), M(1 ), M(2 ), M(3 ), M(4 ), M(5 ), M(6 ), M(7 ), +	M(8  ), M(9 ), M(10), M(10), M(12), M(12), M(15), M(15) +};  #undef M -    //We're not including the highest attack rate, that gets a special value -    static const Bit8u AttackSamplesTable[13] = -    { -        69, 55, 46, 40, -        35, 29, 23, 20, -        19, 15, 11, 10, -        9 -    }; -    //On a real opl these values take 8 samples to reach and are based upon larger tables -    static const Bit8u EnvelopeIncreaseTable[13] = -    { -        4,  5,  6,  7, -        8, 10, 12, 14, -        16, 20, 24, 28, -        32, -    }; - -    #if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) -    static Bit16u ExpTable[ 256 ]; -    #endif - -    #if ( DBOPL_WAVE == WAVE_HANDLER ) -    //PI table used by WAVEHANDLER -    static Bit16u SinTable[ 512 ]; -    #endif - -    #if ( DBOPL_WAVE > WAVE_HANDLER ) -    //Layout of the waveform table in 512 entry intervals -    //With overlapping waves we reduce the table to half it's size - -    //  |    |//\\|____|WAV7|//__|/\  |____|/\/\| -    //  |\\//|    |    |WAV7|    |  \/|    |    | -    //  |06  |0126|17  |7   |3   |4   |4 5 |5   | - -    //6 is just 0 shifted and masked - -    static Bit16s WaveTable[ 8 * 512 ]; -    //Distance into WaveTable the wave starts -    static const Bit16u WaveBaseTable[8] = -    { -        0x000, 0x200, 0x200, 0x800, -        0xa00, 0xc00, 0x100, 0x400, - -    }; -    //Mask the counter with this -    static const Bit16u WaveMaskTable[8] = -    { -        1023, 1023, 511, 511, -        1023, 1023, 512, 1023, -    }; - -    //Where to start the counter on at keyon -    static const Bit16u WaveStartTable[8] = -    { -        512, 0, 0, 0, -        0, 512, 512, 256, -    }; -    #endif - -    #if ( DBOPL_WAVE == WAVE_TABLEMUL ) -    static Bit16u MulTable[ 384 ]; -    #endif - -    static Bit8u KslTable[ 8 * 16 ]; -    static Bit8u TremoloTable[ TREMOLO_TABLE ]; -    //Start of a channel behind the chip struct start -    static Bit16u ChanOffsetTable[32]; -    //Start of an operator behind the chip struct start -    static Bit16u OpOffsetTable[64]; - -    //The lower bits are the shift of the operator vibrato value -    //The highest bit is right shifted to generate -1 or 0 for negation -    //So taking the highest input value of 7 this gives 3, 7, 3, 0, -3, -7, -3, 0 -    static const Bit8s VibratoTable[ 8 ] = -    { -        1 - 0x00, 0 - 0x00, 1 - 0x00, 30 - 0x00, -        1 - 0x80, 0 - 0x80, 1 - 0x80, 30 - 0x80 -    }; - -    //Shift strength for the ksl value determined by ksl strength -    static const Bit8u KslShiftTable[4] = -    { -        31, 1, 2, 0 -    }; - -    //Generate a table index and table shift value using input value from a selected rate -    static void EnvelopeSelect(Bit8u val, Bit8u &index, Bit8u &shift) -    { -        if(val < 13 * 4)                     //Rate 0 - 12 -        { -            shift = 12 - (val >> 2); -            index = val & 3; -        } -        else if(val < 15 * 4)            //rate 13 - 14 -        { -            shift = 0; -            index = val - 12 * 4; -        } -        else                                //rate 15 and up -        { -            shift = 0; -            index = 12; -        } -    } - -    #if ( DBOPL_WAVE == WAVE_HANDLER ) -    /* -        Generate the different waveforms out of the sine/exponetial table using handlers -    */ -    static inline Bits MakeVolume(Bitu wave, Bitu volume) -    { -        Bitu total = wave + volume; -        Bitu index = total & 0xff; -        Bitu sig = ExpTable[ index ]; -        Bitu exp = total >> 8; -        #if 0 - -        //Check if we overflow the 31 shift limit -        if(exp >= 32) -            LOG_MSG("WTF %d %d", total, exp); - -        #endif -        return (sig >> exp); -    }; - -    static Bits DB_FASTCALL WaveForm0(Bitu i, Bitu volume) -    { -        Bits neg = 0 - ((i >> 9) & 1); //Create ~0 or 0 -        Bitu wave = SinTable[i & 511]; -        return (MakeVolume(wave, volume) ^ neg) - neg; -    } -    static Bits DB_FASTCALL WaveForm1(Bitu i, Bitu volume) -    { -        Bit32u wave = SinTable[i & 511]; -        wave |= (((i ^ 512) & 512) - 1) >> (32 - 12); -        return MakeVolume(wave, volume); -    } -    static Bits DB_FASTCALL WaveForm2(Bitu i, Bitu volume) -    { -        Bitu wave = SinTable[i & 511]; -        return MakeVolume(wave, volume); -    } -    static Bits DB_FASTCALL WaveForm3(Bitu i, Bitu volume) -    { -        Bitu wave = SinTable[i & 255]; -        wave |= (((i ^ 256) & 256) - 1) >> (32 - 12); -        return MakeVolume(wave, volume); -    } -    static Bits DB_FASTCALL WaveForm4(Bitu i, Bitu volume) -    { -        //Twice as fast -        i <<= 1; -        Bits neg = 0 - ((i >> 9) & 1); //Create ~0 or 0 -        Bitu wave = SinTable[i & 511]; -        wave |= (((i ^ 512) & 512) - 1) >> (32 - 12); -        return (MakeVolume(wave, volume) ^ neg) - neg; -    } -    static Bits DB_FASTCALL WaveForm5(Bitu i, Bitu volume) -    { -        //Twice as fast -        i <<= 1; -        Bitu wave = SinTable[i & 511]; -        wave |= (((i ^ 512) & 512) - 1) >> (32 - 12); -        return MakeVolume(wave, volume); -    } -    static Bits DB_FASTCALL WaveForm6(Bitu i, Bitu volume) -    { -        Bits neg = 0 - ((i >> 9) & 1); //Create ~0 or 0 -        return (MakeVolume(0, volume) ^ neg) - neg; -    } -    static Bits DB_FASTCALL WaveForm7(Bitu i, Bitu volume) -    { -        //Negative is reversed here -        Bits neg = ((i >> 9) & 1) - 1; -        Bitu wave = (i << 3); -        //When negative the volume also runs backwards -        wave = ((wave ^ neg) - neg) & 4095; -        return (MakeVolume(wave, volume) ^ neg) - neg; -    } - -    static const WaveHandler WaveHandlerTable[8] = -    { -        WaveForm0, WaveForm1, WaveForm2, WaveForm3, -        WaveForm4, WaveForm5, WaveForm6, WaveForm7 -    }; - -    #endif - -    /* -        Operator -    */ - -    //We zero out when rate == 0 -    inline void Operator::UpdateAttack(const Chip *chip) -    { -        Bit8u rate = reg60 >> 4; - -        if(rate) -        { -            Bit8u val = (rate << 2) + ksr; -            attackAdd = chip->attackRates[ val ]; -            rateZero &= ~(1 << ATTACK); -        } -        else -        { -            attackAdd = 0; -            rateZero |= (1 << ATTACK); -        } -    } -    inline void Operator::UpdateDecay(const Chip *chip) -    { -        Bit8u rate = reg60 & 0xf; - -        if(rate) -        { -            Bit8u val = (rate << 2) + ksr; -            decayAdd = chip->linearRates[ val ]; -            rateZero &= ~(1 << DECAY); -        } -        else -        { -            decayAdd = 0; -            rateZero |= (1 << DECAY); -        } -    } -    inline void Operator::UpdateRelease(const Chip *chip) -    { -        Bit8u rate = reg80 & 0xf; - -        if(rate) -        { -            Bit8u val = (rate << 2) + ksr; -            releaseAdd = chip->linearRates[ val ]; -            rateZero &= ~(1 << RELEASE); - -            if(!(reg20 & MASK_SUSTAIN)) -                rateZero &= ~(1 << SUSTAIN); -        } -        else -        { -            rateZero |= (1 << RELEASE); -            releaseAdd = 0; - -            if(!(reg20 & MASK_SUSTAIN)) -                rateZero |= (1 << SUSTAIN); -        } -    } - -    inline void Operator::UpdateAttenuation() -    { -        Bit8u kslBase = (Bit8u)((chanData >> SHIFT_KSLBASE) & 0xff); -        Bit32u tl = reg40 & 0x3f; -        Bit8u kslShift = KslShiftTable[ reg40 >> 6 ]; -        //Make sure the attenuation goes to the right bits -        totalLevel = tl << (ENV_BITS - 7);   //Total level goes 2 bits below max -        totalLevel += (kslBase << ENV_EXTRA) >> kslShift; -    } - -    void Operator::UpdateFrequency() -    { -        Bit32u freq = chanData & ((1 << 10) - 1); -        Bit32u block = (chanData >> 10) & 0xff; -        #ifdef WAVE_PRECISION -        block = 7 - block; -        waveAdd = (freq * freqMul) >> block; -        #else -        waveAdd = (freq << block) * freqMul; -        #endif - -        if(reg20 & MASK_VIBRATO) -        { -            vibStrength = (Bit8u)(freq >> 7); -            #ifdef WAVE_PRECISION -            vibrato = (vibStrength * freqMul) >> block; -            #else -            vibrato = (vibStrength << block) * freqMul; -            #endif -        } -        else -        { -            vibStrength = 0; -            vibrato = 0; -        } -    } - -    void Operator::UpdateRates(const Chip *chip) -    { -        //Mame seems to reverse this where enabling ksr actually lowers -        //the rate, but pdf manuals says otherwise? -        Bit8u newKsr = (Bit8u)((chanData >> SHIFT_KEYCODE) & 0xff); - -        if(!(reg20 & MASK_KSR)) -            newKsr >>= 2; - -        if(ksr == newKsr) -            return; - -        ksr = newKsr; -        UpdateAttack(chip); -        UpdateDecay(chip); -        UpdateRelease(chip); -    } - -    INLINE Bit32s Operator::RateForward(Bit32u add) -    { -        rateIndex += add; -        Bit32s ret = rateIndex >> RATE_SH; -        rateIndex = rateIndex & RATE_MASK; -        return ret; -    } - -    template< Operator::State yes> -    Bits Operator::TemplateVolume() -    { -        Bit32s vol = volume; -        Bit32s change; - -        switch(yes) -        { -        case OFF: -            return ENV_MAX; - -        case ATTACK: -            change = RateForward(attackAdd); - -            if(!change) -                return vol; - -            vol += ((~vol) * change) >> 3; - -            if(vol < ENV_MIN) -            { -                volume = ENV_MIN; -                rateIndex = 0; -                SetState(DECAY); -                return ENV_MIN; -            } - -            break; - -        case DECAY: -            vol += RateForward(decayAdd); - -            if(GCC_UNLIKELY(vol >= sustainLevel)) -            { -                //Check if we didn't overshoot max attenuation, then just go off -                if(GCC_UNLIKELY(vol >= ENV_MAX)) -                { -                    volume = ENV_MAX; -                    SetState(OFF); -                    return ENV_MAX; -                } - -                //Continue as sustain -                rateIndex = 0; -                SetState(SUSTAIN); -            } - -            break; - -        case SUSTAIN: -            if(reg20 & MASK_SUSTAIN) -                return vol; - -        //In sustain phase, but not sustaining, do regular release -        case RELEASE: -            vol += RateForward(releaseAdd);; - -            if(GCC_UNLIKELY(vol >= ENV_MAX)) -            { -                volume = ENV_MAX; -                SetState(OFF); -                return ENV_MAX; -            } - -            break; -        } - -        volume = vol; -        return vol; -    } - -    static const VolumeHandler VolumeHandlerTable[5] = -    { -        &Operator::TemplateVolume< Operator::OFF >, -        &Operator::TemplateVolume< Operator::RELEASE >, -        &Operator::TemplateVolume< Operator::SUSTAIN >, -        &Operator::TemplateVolume< Operator::DECAY >, -        &Operator::TemplateVolume< Operator::ATTACK > -    }; - -    INLINE Bitu Operator::ForwardVolume() -    { -        return currentLevel + (this->*volHandler)(); -    } - - -    INLINE Bitu Operator::ForwardWave() -    { -        waveIndex += waveCurrent; -        return waveIndex >> WAVE_SH; -    } - -    void Operator::Write20(const Chip *chip, Bit8u val) -    { -        Bit8u change = (reg20 ^ val); - -        if(!change) -            return; - -        reg20 = val; -        //Shift the tremolo bit over the entire register, saved a branch, YES! -        tremoloMask = (Bit8s)(val) >> 7; -        tremoloMask &= ~((1 << ENV_EXTRA) - 1); - -        //Update specific features based on changes -        if(change & MASK_KSR) -            UpdateRates(chip); - -        //With sustain enable the volume doesn't change -        if(reg20 & MASK_SUSTAIN || (!releaseAdd)) -            rateZero |= (1 << SUSTAIN); -        else -            rateZero &= ~(1 << SUSTAIN); - -        //Frequency multiplier or vibrato changed -        if(change & (0xf | MASK_VIBRATO)) -        { -            freqMul = chip->freqMul[ val & 0xf ]; -            UpdateFrequency(); -        } -    } - -    void Operator::Write40(const Chip * /*chip*/, Bit8u val) -    { -        if(!(reg40 ^ val)) -            return; - -        reg40 = val; -        UpdateAttenuation(); -    } - -    void Operator::Write60(const Chip *chip, Bit8u val) -    { -        Bit8u change = reg60 ^ val; -        reg60 = val; - -        if(change & 0x0f) -            UpdateDecay(chip); - -        if(change & 0xf0) -            UpdateAttack(chip); -    } - -    void Operator::Write80(const Chip *chip, Bit8u val) -    { -        Bit8u change = (reg80 ^ val); - -        if(!change) -            return; - -        reg80 = val; -        Bit8u sustain = val >> 4; -        //Turn 0xf into 0x1f -        sustain |= (sustain + 1) & 0x10; -        sustainLevel = sustain << (ENV_BITS - 5); - -        if(change & 0x0f) -            UpdateRelease(chip); -    } - -    void Operator::WriteE0(const Chip *chip, Bit8u val) -    { -        if(!(regE0 ^ val)) -            return; - -        //in opl3 mode you can always selet 7 waveforms regardless of waveformselect -        Bit8u waveForm = val & ((0x3 & chip->waveFormMask) | (0x7 & chip->opl3Active)); -        regE0 = val; -        #if ( DBOPL_WAVE == WAVE_HANDLER ) -        waveHandler = WaveHandlerTable[ waveForm ]; -        #else -        waveBase = WaveTable + WaveBaseTable[ waveForm ]; -        waveStart = WaveStartTable[ waveForm ] << WAVE_SH; -        waveMask = WaveMaskTable[ waveForm ]; -        #endif -    } - -    INLINE void Operator::SetState(Bit8u s) -    { -        state = s; -        volHandler = VolumeHandlerTable[ s ]; -    } - -    INLINE bool Operator::Silent() const -    { -        if(!ENV_SILENT(totalLevel + volume)) -            return false; - -        if(!(rateZero & (1 << state))) -            return false; - -        return true; -    } - -    INLINE void Operator::Prepare(const Chip *chip) -    { -        currentLevel = totalLevel + (chip->tremoloValue & tremoloMask); -        waveCurrent = waveAdd; - -        if(vibStrength >> chip->vibratoShift) -        { -            Bit32s add = vibrato >> chip->vibratoShift; -            //Sign extend over the shift value -            Bit32s neg = chip->vibratoSign; -            //Negate the add with -1 or 0 -            add = (add ^ neg) - neg; -            waveCurrent += add; -        } -    } - -    void Operator::KeyOn(Bit8u mask) -    { -        if(!keyOn) -        { -            //Restart the frequency generator -            #if ( DBOPL_WAVE > WAVE_HANDLER ) -            waveIndex = waveStart; -            #else -            waveIndex = 0; -            #endif -            rateIndex = 0; -            SetState(ATTACK); -        } - -        keyOn |= mask; -    } - -    void Operator::KeyOff(Bit8u mask) -    { -        keyOn &= ~mask; - -        if(!keyOn) -        { -            if(state != OFF) -                SetState(RELEASE); -        } -    } - -    INLINE Bits Operator::GetWave(Bitu index, Bitu vol) -    { -        #if ( DBOPL_WAVE == WAVE_HANDLER ) -        return waveHandler(index, vol << (3 - ENV_EXTRA)); -        #elif ( DBOPL_WAVE == WAVE_TABLEMUL ) -        return (waveBase[ index & waveMask ] * MulTable[ vol >> ENV_EXTRA ]) >> MUL_SH; -        #elif ( DBOPL_WAVE == WAVE_TABLELOG ) -        Bit32s wave = waveBase[ index & waveMask ]; -        Bit32u total = (wave & 0x7fff) + vol << (3 - ENV_EXTRA); -        Bit32s sig = ExpTable[ total & 0xff ]; -        Bit32u exp = total >> 8; -        Bit32s neg = wave >> 16; -        return ((sig ^ neg) - neg) >> exp; -        #else +//We're not including the highest attack rate, that gets a special value +static const Bit8u AttackSamplesTable[13] = { +	69, 55, 46, 40, +	35, 29, 23, 20, +	19, 15, 11, 10, +	9 +}; +//On a real opl these values take 8 samples to reach and are based upon larger tables +static const Bit8u EnvelopeIncreaseTable[13] = { +	4,  5,  6,  7, +	8, 10, 12, 14, +	16, 20, 24, 28, +	32, +}; + +#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) +static Bit16u ExpTable[ 256 ]; +#endif + +#if ( DBOPL_WAVE == WAVE_HANDLER ) +//PI table used by WAVEHANDLER +static Bit16u SinTable[ 512 ]; +#endif + +#if ( DBOPL_WAVE > WAVE_HANDLER ) +//Layout of the waveform table in 512 entry intervals +//With overlapping waves we reduce the table to half it's size + +//	|    |//\\|____|WAV7|//__|/\  |____|/\/\| +//	|\\//|    |    |WAV7|    |  \/|    |    | +//	|06  |0126|17  |7   |3   |4   |4 5 |5   | + +//6 is just 0 shifted and masked + +static Bit16s WaveTable[ 8 * 512 ]; +//Distance into WaveTable the wave starts +static const Bit16u WaveBaseTable[8] = { +	0x000, 0x200, 0x200, 0x800, +	0xa00, 0xc00, 0x100, 0x400, + +}; +//Mask the counter with this +static const Bit16u WaveMaskTable[8] = { +	1023, 1023, 511, 511, +	1023, 1023, 512, 1023, +}; + +//Where to start the counter on at keyon +static const Bit16u WaveStartTable[8] = { +	512, 0, 0, 0, +	0, 512, 512, 256, +}; +#endif + +#if ( DBOPL_WAVE == WAVE_TABLEMUL ) +static Bit16u MulTable[ 384 ]; +#endif + +static Bit8u KslTable[ 8 * 16 ]; +static Bit8u TremoloTable[ TREMOLO_TABLE ]; +//Start of a channel behind the chip struct start +static Bit16u ChanOffsetTable[32]; +//Start of an operator behind the chip struct start +static Bit16u OpOffsetTable[64]; + +//The lower bits are the shift of the operator vibrato value +//The highest bit is right shifted to generate -1 or 0 for negation +//So taking the highest input value of 7 this gives 3, 7, 3, 0, -3, -7, -3, 0 +static const Bit8s VibratoTable[ 8 ] = { +	1 - 0x00, 0 - 0x00, 1 - 0x00, 30 - 0x00, +	1 - 0x80, 0 - 0x80, 1 - 0x80, 30 - 0x80 +}; + +//Shift strength for the ksl value determined by ksl strength +static const Bit8u KslShiftTable[4] = { +	31,1,2,0 +}; + +//Generate a table index and table shift value using input value from a selected rate +static void EnvelopeSelect( Bit8u val, Bit8u& index, Bit8u& shift ) { +	if ( val < 13 * 4 ) {				//Rate 0 - 12 +		shift = 12 - ( val >> 2 ); +		index = val & 3; +	} else if ( val < 15 * 4 ) {		//rate 13 - 14 +		shift = 0; +		index = val - 12 * 4; +	} else {							//rate 15 and up +		shift = 0; +		index = 12; +	} +} + +#if ( DBOPL_WAVE == WAVE_HANDLER ) +/* +	Generate the different waveforms out of the sine/exponetial table using handlers +*/ +static inline Bits MakeVolume( Bitu wave, Bitu volume ) { +	Bitu total = wave + volume; +	Bitu index = total & 0xff; +	Bitu sig = ExpTable[ index ]; +	Bitu exp = total >> 8; +#if 0 +	//Check if we overflow the 31 shift limit +	if ( exp >= 32 ) { +		LOG_MSG( "WTF %d %d", total, exp ); +	} +#endif +	return (sig >> exp); +}; + +static Bits DB_FASTCALL WaveForm0( Bitu i, Bitu volume ) { +	Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 +	Bitu wave = SinTable[i & 511]; +	return (MakeVolume( wave, volume ) ^ neg) - neg; +} +static Bits DB_FASTCALL WaveForm1( Bitu i, Bitu volume ) { +	Bit32u wave = SinTable[i & 511]; +	wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); +	return MakeVolume( wave, volume ); +} +static Bits DB_FASTCALL WaveForm2( Bitu i, Bitu volume ) { +	Bitu wave = SinTable[i & 511]; +	return MakeVolume( wave, volume ); +} +static Bits DB_FASTCALL WaveForm3( Bitu i, Bitu volume ) { +	Bitu wave = SinTable[i & 255]; +	wave |= ( ( (i ^ 256 ) & 256) - 1) >> ( 32 - 12 ); +	return MakeVolume( wave, volume ); +} +static Bits DB_FASTCALL WaveForm4( Bitu i, Bitu volume ) { +	//Twice as fast +	i <<= 1; +	Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 +	Bitu wave = SinTable[i & 511]; +	wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); +	return (MakeVolume( wave, volume ) ^ neg) - neg; +} +static Bits DB_FASTCALL WaveForm5( Bitu i, Bitu volume ) { +	//Twice as fast +	i <<= 1; +	Bitu wave = SinTable[i & 511]; +	wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); +	return MakeVolume( wave, volume ); +} +static Bits DB_FASTCALL WaveForm6( Bitu i, Bitu volume ) { +	Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 +	return (MakeVolume( 0, volume ) ^ neg) - neg; +} +static Bits DB_FASTCALL WaveForm7( Bitu i, Bitu volume ) { +	//Negative is reversed here +	Bits neg = (( i >> 9) & 1) - 1; +	Bitu wave = (i << 3); +	//When negative the volume also runs backwards +	wave = ((wave ^ neg) - neg) & 4095; +	return (MakeVolume( wave, volume ) ^ neg) - neg; +} + +static const WaveHandler WaveHandlerTable[8] = { +	WaveForm0, WaveForm1, WaveForm2, WaveForm3, +	WaveForm4, WaveForm5, WaveForm6, WaveForm7 +}; + +#endif + +/* +	Operator +*/ + +//We zero out when rate == 0 +inline void Operator::UpdateAttack( const Chip* chip ) { +	Bit8u rate = reg60 >> 4; +	if ( rate ) { +		Bit8u val = (rate << 2) + ksr; +		attackAdd = chip->attackRates[ val ]; +		rateZero &= ~(1 << ATTACK); +	} else { +		attackAdd = 0; +		rateZero |= (1 << ATTACK); +	} +} +inline void Operator::UpdateDecay( const Chip* chip ) { +	Bit8u rate = reg60 & 0xf; +	if ( rate ) { +		Bit8u val = (rate << 2) + ksr; +		decayAdd = chip->linearRates[ val ]; +		rateZero &= ~(1 << DECAY); +	} else { +		decayAdd = 0; +		rateZero |= (1 << DECAY); +	} +} +inline void Operator::UpdateRelease( const Chip* chip ) { +	Bit8u rate = reg80 & 0xf; +	if ( rate ) { +		Bit8u val = (rate << 2) + ksr; +		releaseAdd = chip->linearRates[ val ]; +		rateZero &= ~(1 << RELEASE); +		if ( !(reg20 & MASK_SUSTAIN ) ) { +			rateZero &= ~( 1 << SUSTAIN ); +		} +	} else { +		rateZero |= (1 << RELEASE); +		releaseAdd = 0; +		if ( !(reg20 & MASK_SUSTAIN ) ) { +			rateZero |= ( 1 << SUSTAIN ); +		} +	} +} + +inline void Operator::UpdateAttenuation( ) { +	Bit8u kslBase = (Bit8u)((chanData >> SHIFT_KSLBASE) & 0xff); +	Bit32u tl = reg40 & 0x3f; +	Bit8u kslShift = KslShiftTable[ reg40 >> 6 ]; +	//Make sure the attenuation goes to the right bits +	totalLevel = tl << ( ENV_BITS - 7 );	//Total level goes 2 bits below max +	totalLevel += ( kslBase << ENV_EXTRA ) >> kslShift; +} + +void Operator::UpdateFrequency(  ) { +	Bit32u freq = chanData & (( 1 << 10 ) - 1); +	Bit32u block = (chanData >> 10) & 0xff; +#ifdef WAVE_PRECISION +	block = 7 - block; +	waveAdd = ( freq * freqMul ) >> block; +#else +	waveAdd = ( freq << block ) * freqMul; +#endif +	if ( reg20 & MASK_VIBRATO ) { +		vibStrength = (Bit8u)(freq >> 7); + +#ifdef WAVE_PRECISION +		vibrato = ( vibStrength * freqMul ) >> block; +#else +		vibrato = ( vibStrength << block ) * freqMul; +#endif +	} else { +		vibStrength = 0; +		vibrato = 0; +	} +} + +void Operator::UpdateRates( const Chip* chip ) { +	//Mame seems to reverse this where enabling ksr actually lowers +	//the rate, but pdf manuals says otherwise? +	Bit8u newKsr = (Bit8u)((chanData >> SHIFT_KEYCODE) & 0xff); +	if ( !( reg20 & MASK_KSR ) ) { +		newKsr >>= 2; +	} +	if ( ksr == newKsr ) +		return; +	ksr = newKsr; +	UpdateAttack( chip ); +	UpdateDecay( chip ); +	UpdateRelease( chip ); +} + +INLINE Bit32s Operator::RateForward( Bit32u add ) { +	rateIndex += add; +	Bit32s ret = rateIndex >> RATE_SH; +	rateIndex = rateIndex & RATE_MASK; +	return ret; +} + +template< Operator::State yes> +Bits Operator::TemplateVolume(  ) { +	Bit32s vol = volume; +	Bit32s change; +	switch ( yes ) { +	case OFF: +		return ENV_MAX; +	case ATTACK: +		change = RateForward( attackAdd ); +		if ( !change ) +			return vol; +		vol += ( (~vol) * change ) >> 3; +		if ( vol < ENV_MIN ) { +			volume = ENV_MIN; +			rateIndex = 0; +			SetState( DECAY ); +			return ENV_MIN; +		} +		break; +	case DECAY: +		vol += RateForward( decayAdd ); +		if ( GCC_UNLIKELY(vol >= sustainLevel) ) { +			//Check if we didn't overshoot max attenuation, then just go off +			if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { +				volume = ENV_MAX; +				SetState( OFF ); +				return ENV_MAX; +			} +			//Continue as sustain +			rateIndex = 0; +			SetState( SUSTAIN ); +		} +		break; +	case SUSTAIN: +		if ( reg20 & MASK_SUSTAIN ) { +			return vol; +		} +		//In sustain phase, but not sustaining, do regular release +	case RELEASE: +		vol += RateForward( releaseAdd );; +		if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { +			volume = ENV_MAX; +			SetState( OFF ); +			return ENV_MAX; +		} +		break; +	} +	volume = vol; +	return vol; +} + +static const VolumeHandler VolumeHandlerTable[5] = { +	&Operator::TemplateVolume< Operator::OFF >, +	&Operator::TemplateVolume< Operator::RELEASE >, +	&Operator::TemplateVolume< Operator::SUSTAIN >, +	&Operator::TemplateVolume< Operator::DECAY >, +	&Operator::TemplateVolume< Operator::ATTACK > +}; + +INLINE Bitu Operator::ForwardVolume() { +	return currentLevel + (this->*volHandler)(); +} + + +INLINE Bitu Operator::ForwardWave() { +	waveIndex += waveCurrent; +	return waveIndex >> WAVE_SH; +} + +void Operator::Write20( const Chip* chip, Bit8u val ) { +	Bit8u change = (reg20 ^ val ); +	if ( !change ) +		return; +	reg20 = val; +	//Shift the tremolo bit over the entire register, saved a branch, YES! +	tremoloMask = (Bit8s)(val) >> 7; +	tremoloMask &= ~(( 1 << ENV_EXTRA ) -1); +	//Update specific features based on changes +	if ( change & MASK_KSR ) { +		UpdateRates( chip ); +	} +	//With sustain enable the volume doesn't change +	if ( reg20 & MASK_SUSTAIN || ( !releaseAdd ) ) { +		rateZero |= ( 1 << SUSTAIN ); +	} else { +		rateZero &= ~( 1 << SUSTAIN ); +	} +	//Frequency multiplier or vibrato changed +	if ( change & (0xf | MASK_VIBRATO) ) { +		freqMul = chip->freqMul[ val & 0xf ]; +		UpdateFrequency(); +	} +} + +void Operator::Write40( const Chip* /*chip*/, Bit8u val ) { +	if (!(reg40 ^ val )) +		return; +	reg40 = val; +	UpdateAttenuation( ); +} + +void Operator::Write60( const Chip* chip, Bit8u val ) { +	Bit8u change = reg60 ^ val; +	reg60 = val; +	if ( change & 0x0f ) { +		UpdateDecay( chip ); +	} +	if ( change & 0xf0 ) { +		UpdateAttack( chip ); +	} +} + +void Operator::Write80( const Chip* chip, Bit8u val ) { +	Bit8u change = (reg80 ^ val ); +	if ( !change ) +		return; +	reg80 = val; +	Bit8u sustain = val >> 4; +	//Turn 0xf into 0x1f +	sustain |= ( sustain + 1) & 0x10; +	sustainLevel = sustain << ( ENV_BITS - 5 ); +	if ( change & 0x0f ) { +		UpdateRelease( chip ); +	} +} + +void Operator::WriteE0( const Chip* chip, Bit8u val ) { +	if ( !(regE0 ^ val) ) +		return; +	//in opl3 mode you can always selet 7 waveforms regardless of waveformselect +	Bit8u waveForm = val & ( ( 0x3 & chip->waveFormMask ) | (0x7 & chip->opl3Active ) ); +	regE0 = val; +#if ( DBOPL_WAVE == WAVE_HANDLER ) +	waveHandler = WaveHandlerTable[ waveForm ]; +#else +	waveBase = WaveTable + WaveBaseTable[ waveForm ]; +	waveStart = WaveStartTable[ waveForm ] << WAVE_SH; +	waveMask = WaveMaskTable[ waveForm ]; +#endif +} + +INLINE void Operator::SetState( Bit8u s ) { +	state = s; +	volHandler = VolumeHandlerTable[ s ]; +} + +INLINE bool Operator::Silent() const { +	if ( !ENV_SILENT( totalLevel + volume ) ) +		return false; +	if ( !(rateZero & ( 1 << state ) ) ) +		return false; +	return true; +} + +INLINE void Operator::Prepare( const Chip* chip )  { +	currentLevel = totalLevel + (chip->tremoloValue & tremoloMask); +	waveCurrent = waveAdd; +	if ( vibStrength >> chip->vibratoShift ) { +		Bit32s add = vibrato >> chip->vibratoShift; +		//Sign extend over the shift value +		Bit32s neg = chip->vibratoSign; +		//Negate the add with -1 or 0 +		add = ( add ^ neg ) - neg; +		waveCurrent += add; +	} +} + +void Operator::KeyOn( Bit8u mask ) { +	if ( !keyOn ) { +		//Restart the frequency generator +#if ( DBOPL_WAVE > WAVE_HANDLER ) +		waveIndex = waveStart; +#else +		waveIndex = 0; +#endif +		rateIndex = 0; +		SetState( ATTACK ); +	} +	keyOn |= mask; +} + +void Operator::KeyOff( Bit8u mask ) { +	keyOn &= ~mask; +	if ( !keyOn ) { +		if ( state != OFF ) { +			SetState( RELEASE ); +		} +	} +} + +INLINE Bits Operator::GetWave( Bitu index, Bitu vol ) { +#if ( DBOPL_WAVE == WAVE_HANDLER ) +	return waveHandler( index, vol << ( 3 - ENV_EXTRA ) ); +#elif ( DBOPL_WAVE == WAVE_TABLEMUL ) +	return (waveBase[ index & waveMask ] * MulTable[ vol >> ENV_EXTRA ]) >> MUL_SH; +#elif ( DBOPL_WAVE == WAVE_TABLELOG ) +	Bit32s wave = waveBase[ index & waveMask ]; +	Bit32u total = ( wave & 0x7fff ) + vol << ( 3 - ENV_EXTRA ); +	Bit32s sig = ExpTable[ total & 0xff ]; +	Bit32u exp = total >> 8; +	Bit32s neg = wave >> 16; +	return ((sig ^ neg) - neg) >> exp; +#else  #error "No valid wave routine" -        #endif -    } - -    Bits INLINE Operator::GetSample(Bits modulation) -    { -        Bitu vol = ForwardVolume(); - -        if(ENV_SILENT(vol)) -        { -            //Simply forward the wave -            waveIndex += waveCurrent; -            return 0; -        } -        else -        { -            Bitu index = ForwardWave(); -            index += modulation; -            return GetWave(index, vol); -        } -    } - -    Operator::Operator() -    { -        chanData = 0; -        freqMul = 0; -        waveIndex = 0; -        waveAdd = 0; -        waveCurrent = 0; -        keyOn = 0; -        ksr = 0; -        reg20 = 0; -        reg40 = 0; -        reg60 = 0; -        reg80 = 0; -        regE0 = 0; -        SetState(OFF); -        rateZero = (1 << OFF); -        sustainLevel = ENV_MAX; -        currentLevel = ENV_MAX; -        totalLevel = ENV_MAX; -        volume = ENV_MAX; -        releaseAdd = 0; -    } - -    /* -        Channel -    */ - -    Channel::Channel() -    { -        old[0] = old[1] = 0; -        chanData = 0; -        regB0 = 0; -        regC0 = 0; -        maskLeft = -1; -        maskRight = -1; -        feedback = 31; -        fourMask = 0; -        synthHandler = &Channel::BlockTemplate< sm2FM >; -    } - -    void Channel::SetChanData(const Chip *chip, Bit32u data) -    { -        Bit32u change = chanData ^ data; -        chanData = data; -        Op(0)->chanData = data; -        Op(1)->chanData = data; -        //Since a frequency update triggered this, always update frequency -        Op(0)->UpdateFrequency(); -        Op(1)->UpdateFrequency(); - -        if(change & (0xff << SHIFT_KSLBASE)) -        { -            Op(0)->UpdateAttenuation(); -            Op(1)->UpdateAttenuation(); -        } - -        if(change & (0xff << SHIFT_KEYCODE)) -        { -            Op(0)->UpdateRates(chip); -            Op(1)->UpdateRates(chip); -        } -    } - -    void Channel::UpdateFrequency(const Chip *chip, Bit8u fourOp) -    { -        //Extrace the frequency bits -        Bit32u data = chanData & 0xffff; -        Bit32u kslBase = KslTable[ data >> 6 ]; -        Bit32u keyCode = (data & 0x1c00) >> 9; - -        if(chip->reg08 & 0x40) -        { -            keyCode |= (data & 0x100) >> 8;  /* notesel == 1 */ -        } -        else -        { -            keyCode |= (data & 0x200) >> 9;  /* notesel == 0 */ -        } - -        //Add the keycode and ksl into the highest bits of chanData -        data |= (keyCode << SHIFT_KEYCODE) | (kslBase << SHIFT_KSLBASE); -        (this + 0)->SetChanData(chip, data); - -        if(fourOp & 0x3f) -            (this + 1)->SetChanData(chip, data); -    } - -    void Channel::WriteA0(const Chip *chip, Bit8u val) -    { -        Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask; - -        //Don't handle writes to silent fourop channels -        if(fourOp > 0x80) -            return; - -        Bit32u change = (chanData ^ val) & 0xff; - -        if(change) -        { -            chanData ^= change; -            UpdateFrequency(chip, fourOp); -        } -    } - -    void Channel::WriteB0(const Chip *chip, Bit8u val) -    { -        Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask; - -        //Don't handle writes to silent fourop channels -        if(fourOp > 0x80) -            return; - -        Bitu change = (chanData ^ (val << 8)) & 0x1f00; - -        if(change) -        { -            chanData ^= change; -            UpdateFrequency(chip, fourOp); -        } - -        //Check for a change in the keyon/off state -        if(!((val ^ regB0) & 0x20)) -            return; - -        regB0 = val; - -        if(val & 0x20) -        { -            Op(0)->KeyOn(0x1); -            Op(1)->KeyOn(0x1); - -            if(fourOp & 0x3f) -            { -                (this + 1)->Op(0)->KeyOn(1); -                (this + 1)->Op(1)->KeyOn(1); -            } -        } -        else -        { -            Op(0)->KeyOff(0x1); -            Op(1)->KeyOff(0x1); - -            if(fourOp & 0x3f) -            { -                (this + 1)->Op(0)->KeyOff(1); -                (this + 1)->Op(1)->KeyOff(1); -            } -        } -    } - -    void Channel::WriteC0(const Chip *chip, Bit8u val) -    { -        Bit8u change = val ^ regC0; - -        if(!change) -            return; - -        regC0 = val; -        feedback = (val >> 1) & 7; - -        if(feedback) -        { -            //We shift the input to the right 10 bit wave index value -            feedback = 9 - feedback; -        } -        else -            feedback = 31; - -        //Select the new synth mode -        if(chip->opl3Active) -        { -            //4-op mode enabled for this channel -            if((chip->reg104 & fourMask) & 0x3f) -            { -                Channel *chan0, *chan1; - -                //Check if it's the 2nd channel in a 4-op -                if(!(fourMask & 0x80)) -                { -                    chan0 = this; -                    chan1 = this + 1; -                } -                else -                { -                    chan0 = this - 1; -                    chan1 = this; -                } - -                Bit8u synth = ((chan0->regC0 & 1) << 0) | ((chan1->regC0 & 1) << 1); - -                switch(synth) -                { -                case 0: -                    chan0->synthHandler = &Channel::BlockTemplate< sm3FMFM >; -                    break; - -                case 1: -                    chan0->synthHandler = &Channel::BlockTemplate< sm3AMFM >; -                    break; - -                case 2: -                    chan0->synthHandler = &Channel::BlockTemplate< sm3FMAM >; -                    break; - -                case 3: -                    chan0->synthHandler = &Channel::BlockTemplate< sm3AMAM >; -                    break; -                } - -                //Disable updating percussion channels -            } -            else if((fourMask & 0x40) && (chip->regBD & 0x20)) -            { -                //Regular dual op, am or fm -            } -            else if(val & 1) -                synthHandler = &Channel::BlockTemplate< sm3AM >; -            else -                synthHandler = &Channel::BlockTemplate< sm3FM >; - -            maskLeft = (val & 0x10) ? -1 : 0; -            maskRight = (val & 0x20) ? -1 : 0; -            //opl2 active -        } -        else -        { -            //Disable updating percussion channels -            if((fourMask & 0x40) && (chip->regBD & 0x20)) -            { -                //Regular dual op, am or fm -            } -            else if(val & 1) -                synthHandler = &Channel::BlockTemplate< sm2AM >; -            else -                synthHandler = &Channel::BlockTemplate< sm2FM >; -        } -    } - -    void Channel::ResetC0(const Chip *chip) -    { -        Bit8u val = regC0; -        regC0 ^= 0xff; -        WriteC0(chip, val); -    } - -    template< bool opl3Mode> -    INLINE void Channel::GeneratePercussion(Chip *chip, Bit32s *output) -    { -        Channel *chan = this; -        //BassDrum -        Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback; -        old[0] = old[1]; -        old[1] = Op(0)->GetSample(mod); - -        //When bassdrum is in AM mode first operator is ignoed -        if(chan->regC0 & 1) -            mod = 0; -        else -            mod = old[0]; - -        Bit32s sample = Op(1)->GetSample(mod); -        //Precalculate stuff used by other outputs -        Bit32u noiseBit = chip->ForwardNoise() & 0x1; -        Bit32u c2 = Op(2)->ForwardWave(); -        Bit32u c5 = Op(5)->ForwardWave(); -        Bit32u phaseBit = (((c2 & 0x88) ^ ((c2 << 5) & 0x80)) | ((c5 ^ (c5 << 2)) & 0x20)) ? 0x02 : 0x00; -        //Hi-Hat -        Bit32u hhVol = Op(2)->ForwardVolume(); - -        if(!ENV_SILENT(hhVol)) -        { -            Bit32u hhIndex = (phaseBit << 8) | (0x34 << (phaseBit ^ (noiseBit << 1))); -            sample += Op(2)->GetWave(hhIndex, hhVol); -        } - -        //Snare Drum -        Bit32u sdVol = Op(3)->ForwardVolume(); - -        if(!ENV_SILENT(sdVol)) -        { -            Bit32u sdIndex = (0x100 + (c2 & 0x100)) ^ (noiseBit << 8); -            sample += Op(3)->GetWave(sdIndex, sdVol); -        } - -        //Tom-tom -        sample += Op(4)->GetSample(0); -        //Top-Cymbal -        Bit32u tcVol = Op(5)->ForwardVolume(); - -        if(!ENV_SILENT(tcVol)) -        { -            Bit32u tcIndex = (1 + phaseBit) << 8; -            sample += Op(5)->GetWave(tcIndex, tcVol); -        } - -        sample <<= 1; - -        if(opl3Mode) -        { -            output[0] += sample; -            output[1] += sample; -        } -        else -            output[0] += sample; -    } - -    template<SynthMode mode> -    Channel *Channel::BlockTemplate(Chip *chip, Bit32u samples, Bit32s *output) -    { -        switch(mode) -        { -        case sm2AM: -        case sm3AM: -            if(Op(0)->Silent() && Op(1)->Silent()) -            { -                old[0] = old[1] = 0; -                return (this + 1); -            } - -            break; - -        case sm2FM: -        case sm3FM: -            if(Op(1)->Silent()) -            { -                old[0] = old[1] = 0; -                return (this + 1); -            } - -            break; - -        case sm3FMFM: -            if(Op(3)->Silent()) -            { -                old[0] = old[1] = 0; -                return (this + 2); -            } - -            break; - -        case sm3AMFM: -            if(Op(0)->Silent() && Op(3)->Silent()) -            { -                old[0] = old[1] = 0; -                return (this + 2); -            } - -            break; - -        case sm3FMAM: -            if(Op(1)->Silent() && Op(3)->Silent()) -            { -                old[0] = old[1] = 0; -                return (this + 2); -            } - -            break; - -        case sm3AMAM: -            if(Op(0)->Silent() && Op(2)->Silent() && Op(3)->Silent()) -            { -                old[0] = old[1] = 0; -                return (this + 2); -            } - -            break; - -        default: -            break; -        } - -        //Init the operators with the the current vibrato and tremolo values -        Op(0)->Prepare(chip); -        Op(1)->Prepare(chip); - -        if(mode > sm4Start) -        { -            Op(2)->Prepare(chip); -            Op(3)->Prepare(chip); -        } - -        if(mode > sm6Start) -        { -            Op(4)->Prepare(chip); -            Op(5)->Prepare(chip); -        } - -        for(Bitu i = 0; i < samples; i++) -        { -            //Early out for percussion handlers -            if(mode == sm2Percussion) -            { -                GeneratePercussion<false>(chip, output + i); -                continue;   //Prevent some unitialized value bitching -            } -            else if(mode == sm3Percussion) -            { -                GeneratePercussion<true>(chip, output + i * 2); -                continue;   //Prevent some unitialized value bitching -            } - -            //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise -            Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback; -            old[0] = old[1]; -            old[1] = Op(0)->GetSample(mod); -            Bit32s sample; -            Bit32s out0 = old[0]; - -            if(mode == sm2AM || mode == sm3AM) -                sample = out0 + Op(1)->GetSample(0); -            else if(mode == sm2FM || mode == sm3FM) -                sample = Op(1)->GetSample(out0); -            else if(mode == sm3FMFM) -            { -                Bits next = Op(1)->GetSample(out0); -                next = Op(2)->GetSample(next); -                sample = Op(3)->GetSample(next); -            } -            else if(mode == sm3AMFM) -            { -                sample = out0; -                Bits next = Op(1)->GetSample(0); -                next = Op(2)->GetSample(next); -                sample += Op(3)->GetSample(next); -            } -            else if(mode == sm3FMAM) -            { -                sample = Op(1)->GetSample(out0); -                Bits next = Op(2)->GetSample(0); -                sample += Op(3)->GetSample(next); -            } -            else if(mode == sm3AMAM) -            { -                sample = out0; -                Bits next = Op(1)->GetSample(0); -                sample += Op(2)->GetSample(next); -                sample += Op(3)->GetSample(0); -            } - -            switch(mode) -            { -            case sm2AM: -            case sm2FM: -                output[ i ] += sample; -                break; - -            case sm3AM: -            case sm3FM: -            case sm3FMFM: -            case sm3AMFM: -            case sm3FMAM: -            case sm3AMAM: -                output[ i * 2 + 0 ] += sample & maskLeft; -                output[ i * 2 + 1 ] += sample & maskRight; -                break; - -            default: -                break; -            } -        } - -        switch(mode) -        { -        case sm2AM: -        case sm2FM: -        case sm3AM: -        case sm3FM: -            return (this + 1); - -        case sm3FMFM: -        case sm3AMFM: -        case sm3FMAM: -        case sm3AMAM: -            return(this + 2); - -        case sm2Percussion: -        case sm3Percussion: -            return(this + 3); -        } - -        return 0; -    } - -    /* -        Chip -    */ - -    Chip::Chip() -    { -        reg08 = 0; -        reg04 = 0; -        regBD = 0; -        reg104 = 0; -        opl3Active = 0; -        //Extra zeros! -        vibratoIndex = 0; -        tremoloIndex = 0; -        vibratoSign = 0; -        vibratoShift = 0; -        tremoloValue = 0; -        vibratoStrength = 0; -        tremoloStrength = 0; -        waveFormMask = 0; -        lfoCounter = 0; -        lfoAdd = 0; -        noiseCounter = 0; -        noiseAdd = 0; -        noiseValue = 0; -        memset(freqMul, 0, sizeof(Bit32u) * 16); -        memset(linearRates, 0, sizeof(Bit32u) * 76); -        memset(attackRates, 0, sizeof(Bit32u) * 76); -    } - -    INLINE Bit32u Chip::ForwardNoise() -    { -        noiseCounter += noiseAdd; -        Bitu count = noiseCounter >> LFO_SH; -        noiseCounter &= WAVE_MASK; - -        for(; count > 0; --count) -        { -            //Noise calculation from mame -            noiseValue ^= (0x800302) & (0 - (noiseValue & 1)); -            noiseValue >>= 1; -        } - -        return noiseValue; -    } - -    INLINE Bit32u Chip::ForwardLFO(Bit32u samples) -    { -        //Current vibrato value, runs 4x slower than tremolo -        vibratoSign = (VibratoTable[ vibratoIndex >> 2]) >> 7; -        vibratoShift = (VibratoTable[ vibratoIndex >> 2] & 7) + vibratoStrength; -        tremoloValue = TremoloTable[ tremoloIndex ] >> tremoloStrength; -        //Check hom many samples there can be done before the value changes -        Bit32u todo = LFO_MAX - lfoCounter; -        Bit32u count = (todo + lfoAdd - 1) / lfoAdd; - -        if(count > samples) -        { -            count = samples; -            lfoCounter += count * lfoAdd; -        } -        else -        { -            lfoCounter += count * lfoAdd; -            lfoCounter &= (LFO_MAX - 1); -            //Maximum of 7 vibrato value * 4 -            vibratoIndex = (vibratoIndex + 1) & 31; - -            //Clip tremolo to the the table size -            if(tremoloIndex + 1 < TREMOLO_TABLE) -                ++tremoloIndex; -            else -                tremoloIndex = 0; -        } - -        return count; -    } - - -    void Chip::WriteBD(Bit8u val) -    { -        Bit8u change = regBD ^ val; - -        if(!change) -            return; - -        regBD = val; -        //TODO could do this with shift and xor? -        vibratoStrength = (val & 0x40) ? 0x00 : 0x01; -        tremoloStrength = (val & 0x80) ? 0x00 : 0x02; - -        if(val & 0x20) -        { -            //Drum was just enabled, make sure channel 6 has the right synth -            if(change & 0x20) -            { -                if(opl3Active) -                    chan[6].synthHandler = &Channel::BlockTemplate< sm3Percussion >; -                else -                    chan[6].synthHandler = &Channel::BlockTemplate< sm2Percussion >; -            } - -            //Bass Drum -            if(val & 0x10) -            { -                chan[6].op[0].KeyOn(0x2); -                chan[6].op[1].KeyOn(0x2); -            } -            else -            { -                chan[6].op[0].KeyOff(0x2); -                chan[6].op[1].KeyOff(0x2); -            } - -            //Hi-Hat -            if(val & 0x1) -                chan[7].op[0].KeyOn(0x2); -            else -                chan[7].op[0].KeyOff(0x2); - -            //Snare -            if(val & 0x8) -                chan[7].op[1].KeyOn(0x2); -            else -                chan[7].op[1].KeyOff(0x2); - -            //Tom-Tom -            if(val & 0x4) -                chan[8].op[0].KeyOn(0x2); -            else -                chan[8].op[0].KeyOff(0x2); - -            //Top Cymbal -            if(val & 0x2) -                chan[8].op[1].KeyOn(0x2); -            else -                chan[8].op[1].KeyOff(0x2); - -            //Toggle keyoffs when we turn off the percussion -        } -        else if(change & 0x20) -        { -            //Trigger a reset to setup the original synth handler -            chan[6].ResetC0(this); -            chan[6].op[0].KeyOff(0x2); -            chan[6].op[1].KeyOff(0x2); -            chan[7].op[0].KeyOff(0x2); -            chan[7].op[1].KeyOff(0x2); -            chan[8].op[0].KeyOff(0x2); -            chan[8].op[1].KeyOff(0x2); -        } -    } - - -#define REGOP( _FUNC_ )                                                         \ -    index = ( ( reg >> 3) & 0x20 ) | ( reg & 0x1f );                                \ -    if ( OpOffsetTable[ index ] ) {                                                 \ -        Operator* regOp = (Operator*)( ((char *)this ) + OpOffsetTable[ index ] );  \ -        regOp->_FUNC_( this, val );                                                 \ -    } - -#define REGCHAN( _FUNC_ )                                                               \ -    index = ( ( reg >> 4) & 0x10 ) | ( reg & 0xf );                                     \ -    if ( ChanOffsetTable[ index ] ) {                                                   \ -        Channel* regChan = (Channel*)( ((char *)this ) + ChanOffsetTable[ index ] );    \ -        regChan->_FUNC_( this, val );                                                   \ -    } - -    void Chip::WriteReg(Bit32u reg, Bit8u val) -    { -        Bitu index = 0; - -        switch((reg & 0xf0) >> 4) -        { -        case 0x00 >> 4: -            if(reg == 0x01) -                waveFormMask = (val & 0x20) ? 0x7 : 0x0; -            else if(reg == 0x104) -            { -                //Only detect changes in lowest 6 bits -                if(!((reg104 ^ val) & 0x3f)) -                    return; - -                //Always keep the highest bit enabled, for checking > 0x80 -                reg104 = 0x80 | (val & 0x3f); -            } -            else if(reg == 0x105) -            { -                //MAME says the real opl3 doesn't reset anything on opl3 disable/enable till the next write in another register -                if(!((opl3Active ^ val) & 1)) -                    return; - -                opl3Active = (val & 1) ? 0xff : 0; - -                //Update the 0xc0 register for all channels to signal the switch to mono/stereo handlers -                for(int i = 0; i < 18; i++) -                    chan[i].ResetC0(this); -            } -            else if(reg == 0x08) -                reg08 = val; - -        case 0x10 >> 4: -            break; - -        case 0x20 >> 4: -        case 0x30 >> 4: -            REGOP(Write20); -            break; - -        case 0x40 >> 4: -        case 0x50 >> 4: -            REGOP(Write40); -            break; - -        case 0x60 >> 4: -        case 0x70 >> 4: -            REGOP(Write60); -            break; - -        case 0x80 >> 4: -        case 0x90 >> 4: -            REGOP(Write80); -            break; - -        case 0xa0 >> 4: -            REGCHAN(WriteA0); -            break; - -        case 0xb0 >> 4: -            if(reg == 0xbd) -                WriteBD(val); -            else -                REGCHAN(WriteB0); - -            break; - -        case 0xc0 >> 4: -            REGCHAN(WriteC0); - -        case 0xd0 >> 4: -            break; - -        case 0xe0 >> 4: -        case 0xf0 >> 4: -            REGOP(WriteE0); -            break; -        } -    } - - -    Bit32u Chip::WriteAddr(Bit32u port, Bit8u val) -    { -        switch(port & 3) -        { -        case 0: -            return val; - -        case 2: -            if(opl3Active || (val == 0x05)) -                return 0x100 | val; -            else -                return val; -        } - -        return 0; -    } - -    void Chip::GenerateBlock2(Bitu total, Bit32s *output) -    { -        while(total > 0) -        { -            Bit32u samples = ForwardLFO(total); -            memset(output, 0, sizeof(Bit32s) * samples); -            int count = 0; - -            for(Channel *ch = chan; ch < chan + 9;) -            { -                count++; -                ch = (ch->*(ch->synthHandler))(this, samples, output); -            } - -            total -= samples; -            output += samples; -        } -    } - -    void Chip::GenerateBlock3(Bitu total, Bit32s *output) -    { -        while(total > 0) -        { -            Bit32u samples = ForwardLFO((Bit32u)total); -            memset(output, 0, sizeof(Bit32s) * samples * 2); -            int count = 0; - -            for(Channel *ch = chan; ch < chan + 18;) -            { -                count++; -                ch = (ch->*(ch->synthHandler))(this, samples, output); -            } - -            total -= samples; -            output += samples * 2; -        } -    } - -    void Chip::GenerateBlock2_Mix(Bitu total, Bit32s *output) -    { -        while(total > 0) -        { -            Bit32u samples = ForwardLFO((Bit32u)total); -            int count = 0; -            for(Channel *ch = chan; ch < chan + 9;) -            { -                count++; -                ch = (ch->*(ch->synthHandler))(this, samples, output); -            } - -            total -= samples; -            output += samples; -        } -    } - -    void Chip::GenerateBlock3_Mix(Bitu total, Bit32s *output) -    { -        while(total > 0) -        { -            Bit32u samples = ForwardLFO(total); -            int count = 0; -            for(Channel *ch = chan; ch < chan + 18;) -            { -                count++; -                ch = (ch->*(ch->synthHandler))(this, samples, output); -            } -            total -= samples; -            output += samples * 2; -        } -    } - -    void Chip::Setup(Bit32u rate) -    { -        double original = OPLRATE; -        //  double original = rate; -        double scale = original / (double)rate; -        //Noise counter is run at the same precision as general waves -        noiseAdd = (Bit32u)(0.5 + scale * (1 << LFO_SH)); -        noiseCounter = 0; -        noiseValue = 1; //Make sure it triggers the noise xor the first time -        //The low frequency oscillation counter -        //Every time his overflows vibrato and tremoloindex are increased -        lfoAdd = (Bit32u)(0.5 + scale * (1 << LFO_SH)); -        lfoCounter = 0; -        vibratoIndex = 0; -        tremoloIndex = 0; -        //With higher octave this gets shifted up -        //-1 since the freqCreateTable = *2 -        #ifdef WAVE_PRECISION -        double freqScale = (1 << 7) * scale * (1 << (WAVE_SH - 1 - 10)); - -        for(int i = 0; i < 16; i++) -            freqMul[i] = (Bit32u)(0.5 + freqScale * FreqCreateTable[ i ]); - -        #else -        Bit32u freqScale = (Bit32u)(0.5 + scale * (1 << (WAVE_SH - 1 - 10))); - -        for(int i = 0; i < 16; i++) -            freqMul[i] = freqScale * FreqCreateTable[ i ]; - -        #endif - -        //-3 since the real envelope takes 8 steps to reach the single value we supply -        for(Bit8u i = 0; i < 76; i++) -        { -            Bit8u index, shift; -            EnvelopeSelect(i, index, shift); -            linearRates[i] = (Bit32u)(scale * (EnvelopeIncreaseTable[ index ] << (RATE_SH + ENV_EXTRA - shift - 3))); -        } - -        if(rate == 48000) -        { -            /* BISQWIT ADD: Use precalculated table for this common sample-rate. -             * Because the actual generation code, below, is MOLASSES SLOW on DOS. -             */ -            static const Bit32u precalculated_table[62] = -            { -                2152, 2700, 3228, 3712, 4304, 5399, 6456, 7424, 8608, 10799, 12912, 14849, 17216, 21598, -                25824, 29698, 34432, 43196, 51650, 59398, 68864, 86392, 103310, 118795, 137746, 172847, -                206619, 237693, 275559, 345774, 413238, 475500, 543030, 678787, 814545, 950302, 1086060, -                1357575, 1629090, 1900605, 2172120, 2715151, 3258181, 3801211, 4344241, 5430302, -                6516362, 7602423, 8688483, 10860604, 13032725, 15204846, 17376967, 21721209, 26065451, -                30409693, 34753934, 43442418, 52130902, 60819386, 69507869, 69507869 -            }; - -            for(Bit8u i = 0; i < 62; i++) -                attackRates[i] = precalculated_table[i]; -        } -        else if(rate == 44100) -        { -            static const Bit32u precalculated_table[62] = -            { -                2342, 2939, 3513, 4040, 4685, 5877, 7027, 8081, 9369, 11754, 14054, 16162, 18738, 23508, -                28108, 32325, 37478, 47018, 56219, 64649, 74965, 94044, 112448, 129292, 149929, 188132, -                224945, 258713, 300002, 376263, 449999, 517550, 591053, 738816, 886579, 1034343, 1182106, -                1477633, 1773159, 2068686, 2364213, 2955266, 3546319, 4137373, 4728426, 5910533, -                7092639, 8274746, 9456853, 11821066, 14185279, 16549492, 18913706, 23642132, 28370559, -                33098985, 37827412, 47284265, 56741118, 66197971, 75654824, 75654824 -            }; - -            for(Bit8u i = 0; i < 62; i++) -                attackRates[i] = precalculated_table[i]; -        } -        else if(rate == 22050) -        { -            static const Bit32u precalculated_table[62] = -            { -                4685, 5877, 7027, 8081, 9369, 11754, 14054, 16162, 18738, 23508, 28108, 32325, 37478, -                47018, 56219, 64649, 74965, 94044, 112448, 129292, 149929, 188132, 224945, 258713, 300002, -                376263, 449999, 517550, 591053, 738816, 886579, 1034343, 1182106, 1477633, 1773159, -                2068686, 2364213, 2955266, 3546319, 4137373, 4728426, 5910533, 7092639, 8274746, -                9456853, 11821066, 14185279, 16549492, 18913706, 23642132, 28370559, 33098985, -                37827412, 47284265, 56741118, 66197971, 75654824, 94568530, 113482236, 132395942, -                151309648, 151309648 -            }; - -            for(Bit8u i = 0; i < 62; i++) -                attackRates[i] = precalculated_table[i]; -        } -        //Generate the best matching attack rate -        else for(Bit8u i = 0; i < 62; i++) -            { -                Bit8u index, shift; -                EnvelopeSelect(i, index, shift); -                //Original amount of samples the attack would take -                Bit32s original = (Bit32u)((AttackSamplesTable[ index ] << shift) / scale); -                Bit32s guessAdd = (Bit32u)(scale * (EnvelopeIncreaseTable[ index ] << (RATE_SH - shift - 3))); -                Bit32s bestAdd = guessAdd; -                Bit32u bestDiff = 1 << 30; - -                for(Bit32u passes = 0; passes < 16; passes ++) -                { -                    Bit32s volume = ENV_MAX; -                    Bit32s samples = 0; -                    Bit32u count = 0; - -                    while(volume > 0 && samples < original * 2) -                    { -                        count += guessAdd; -                        Bit32s change = count >> RATE_SH; -                        count &= RATE_MASK; - -                        if(GCC_UNLIKELY(change))      // less than 1 % -                            volume += (~volume * change) >> 3; - -                        samples++; -                    } - -                    Bit32s diff = original - samples; -                    Bit32u lDiff = labs(diff); - -                    //Init last on first pass -                    if(lDiff < bestDiff) -                    { -                        bestDiff = lDiff; -                        bestAdd = guessAdd; - -                        if(!bestDiff) -                            break; -                    } - -                    //Below our target -                    if(diff < 0) -                    { -                        //Better than the last time -                        Bit32s mul = ((original - diff) << 12) / original; -                        guessAdd = ((guessAdd * mul) >> 12); -                        guessAdd++; -                    } -                    else if(diff > 0) -                    { -                        Bit32s mul = ((original - diff) << 12) / original; -                        guessAdd = (guessAdd * mul) >> 12; -                        guessAdd--; -                    } -                } - -                attackRates[i] = bestAdd; -            } - -        /*fprintf(stderr, "attack rate table: "); -        for ( Bit8u i = 0; i < 62; i++ ) -            fprintf(stderr, ",%u", attackRates[i]); -        fprintf(stderr, "\n");*/ - -        for(Bit8u i = 62; i < 76; i++) -        { -            //This should provide instant volume maximizing -            attackRates[i] = 8 << RATE_SH; -        } - -        //Setup the channels with the correct four op flags -        //Channels are accessed through a table so they appear linear here -        chan[ 0].fourMask = 0x00 | (1 << 0); -        chan[ 1].fourMask = 0x80 | (1 << 0); -        chan[ 2].fourMask = 0x00 | (1 << 1); -        chan[ 3].fourMask = 0x80 | (1 << 1); -        chan[ 4].fourMask = 0x00 | (1 << 2); -        chan[ 5].fourMask = 0x80 | (1 << 2); -        chan[ 9].fourMask = 0x00 | (1 << 3); -        chan[10].fourMask = 0x80 | (1 << 3); -        chan[11].fourMask = 0x00 | (1 << 4); -        chan[12].fourMask = 0x80 | (1 << 4); -        chan[13].fourMask = 0x00 | (1 << 5); -        chan[14].fourMask = 0x80 | (1 << 5); -        //mark the percussion channels -        chan[ 6].fourMask = 0x40; -        chan[ 7].fourMask = 0x40; -        chan[ 8].fourMask = 0x40; -        //Clear Everything in opl3 mode -        WriteReg(0x105, 0x1); - -        for(int i = 0; i < 512; i++) -        { -            if(i == 0x105) -                continue; - -            WriteReg(i, 0xff); -            WriteReg(i, 0x0); -        } - -        WriteReg(0x105, 0x0); - -        //Clear everything in opl2 mode -        for(int i = 0; i < 255; i++) -        { -            WriteReg(i, 0xff); -            WriteReg(i, 0x0); -        } -    } - -    static bool doneTables = false; -    void InitTables(void) -    { -        if(doneTables) -            return; - -        doneTables = true; -        #if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) - -        //Exponential volume table, same as the real adlib -        for(int i = 0; i < 256; i++) -        { -            //Save them in reverse -            ExpTable[i] = (int)(0.5 + (pow(2.0, (255 - i) * (1.0 / 256)) - 1) * 1024); -            ExpTable[i] += 1024; //or remove the -1 oh well :) -            //Preshift to the left once so the final volume can shift to the right -            ExpTable[i] *= 2; -        } - -        #endif -        #if ( DBOPL_WAVE == WAVE_HANDLER ) - -        //Add 0.5 for the trunc rounding of the integer cast -        //Do a PI sinetable instead of the original 0.5 PI -        for(int i = 0; i < 512; i++) -            SinTable[i] = (Bit16s)(0.5 - log10(sin((i + 0.5) * (PI / 512.0))) / log10(2.0) * 256); - -        #endif -        #if ( DBOPL_WAVE == WAVE_TABLEMUL ) - -        //Multiplication based tables -        for(int i = 0; i < 384; i++) -        { -            int s = i * 8; -            //TODO maybe keep some of the precision errors of the original table? -            double val = (0.5 + (pow(2.0, -1.0 + (255 - s) * (1.0 / 256))) * (1 << MUL_SH)); -            MulTable[i] = (Bit16u)(val); -        } - -        //Sine Wave Base -        for(int i = 0; i < 512; i++) -        { -            WaveTable[ 0x0200 + i ] = (Bit16s)(sin((i + 0.5) * (PI / 512.0)) * 4084); -            WaveTable[ 0x0000 + i ] = -WaveTable[ 0x200 + i ]; -        } - -        //Exponential wave -        for(int i = 0; i < 256; i++) -        { -            WaveTable[ 0x700 + i ] = (Bit16s)(0.5 + (pow(2.0, -1.0 + (255 - i * 8) * (1.0 / 256))) * 4085); -            WaveTable[ 0x6ff - i ] = -WaveTable[ 0x700 + i ]; -        } - -        #endif -        #if ( DBOPL_WAVE == WAVE_TABLELOG ) - -        //Sine Wave Base -        for(int i = 0; i < 512; i++) -        { -            WaveTable[ 0x0200 + i ] = (Bit16s)(0.5 - log10(sin((i + 0.5) * (PI / 512.0))) / log10(2.0) * 256); -            WaveTable[ 0x0000 + i ] = ((Bit16s)0x8000) | WaveTable[ 0x200 + i]; -        } - -        //Exponential wave -        for(int i = 0; i < 256; i++) -        { -            WaveTable[ 0x700 + i ] = i * 8; -            WaveTable[ 0x6ff - i ] = ((Bit16s)0x8000) | i * 8; -        } - -        #endif -        //  |    |//\\|____|WAV7|//__|/\  |____|/\/\| -        //  |\\//|    |    |WAV7|    |  \/|    |    | -        //  |06  |0126|27  |7   |3   |4   |4 5 |5   | -        #if (( DBOPL_WAVE == WAVE_TABLELOG ) || ( DBOPL_WAVE == WAVE_TABLEMUL )) - -        for(int i = 0; i < 256; i++) -        { -            //Fill silence gaps -            WaveTable[ 0x400 + i ] = WaveTable[0]; -            WaveTable[ 0x500 + i ] = WaveTable[0]; -            WaveTable[ 0x900 + i ] = WaveTable[0]; -            WaveTable[ 0xc00 + i ] = WaveTable[0]; -            WaveTable[ 0xd00 + i ] = WaveTable[0]; -            //Replicate sines in other pieces -            WaveTable[ 0x800 + i ] = WaveTable[ 0x200 + i ]; -            //double speed sines -            WaveTable[ 0xa00 + i ] = WaveTable[ 0x200 + i * 2 ]; -            WaveTable[ 0xb00 + i ] = WaveTable[ 0x000 + i * 2 ]; -            WaveTable[ 0xe00 + i ] = WaveTable[ 0x200 + i * 2 ]; -            WaveTable[ 0xf00 + i ] = WaveTable[ 0x200 + i * 2 ]; -        } - -        #endif - -        //Create the ksl table -        for(int oct = 0; oct < 8; oct++) -        { -            int base = oct * 8; - -            for(int i = 0; i < 16; i++) -            { -                int val = base - KslCreateTable[i]; - -                if(val < 0) -                    val = 0; - -                //*4 for the final range to match attenuation range -                KslTable[ oct * 16 + i ] = val * 4; -            } -        } - -        //Create the Tremolo table, just increase and decrease a triangle wave -        for(Bit8u i = 0; i < TREMOLO_TABLE / 2; i++) -        { -            Bit8u val = i << ENV_EXTRA; -            TremoloTable[i] = val; -            TremoloTable[TREMOLO_TABLE - 1 - i] = val; -        } - -        //Create a table with offsets of the channels from the start of the chip -        DBOPL::Chip *chip = 0; - -        for(Bitu i = 0; i < 32; i++) -        { -            Bitu index = i & 0xf; - -            if(index >= 9) -            { -                ChanOffsetTable[i] = 0; -                continue; -            } - -            //Make sure the four op channels follow eachother -            if(index < 6) -                index = (index % 3) * 2 + (index / 3); - -            //Add back the bits for highest ones -            if(i >= 16) -                index += 9; - -            intptr_t blah = reinterpret_cast<intptr_t>(&(chip->chan[ index ])); -            ChanOffsetTable[i] = static_cast<Bit16u>(blah); -        } - -        //Same for operators -        for(Bitu i = 0; i < 64; i++) -        { -            if(i % 8 >= 6 || ((i / 8) % 4 == 3)) -            { -                OpOffsetTable[i] = 0; -                continue; -            } - -            Bitu chNum = (i / 8) * 3 + (i % 8) % 3; - -            //Make sure we use 16 and up for the 2nd range to match the chanoffset gap -            if(chNum >= 12) -                chNum += 16 - 12; - -            Bitu opNum = (i % 8) / 3; -            DBOPL::Channel *chan = NULL; -            intptr_t blah = reinterpret_cast<intptr_t>(&(chan->op[opNum])); -            OpOffsetTable[i] = static_cast<Bit16u>((intptr_t)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(void(*AddSamples_m32)(Bitu, Bit32s *), -                           void(*AddSamples_s32)(Bitu, Bit32s *), -                           Bitu samples) -    { -        Bit32s buffer[ 512 * 2 ]; - -        if(GCC_UNLIKELY(samples > 512)) -            samples = 512; - -        if(!chip.opl3Active) -        { -            chip.GenerateBlock2(samples, buffer); -            AddSamples_m32(samples, buffer); -        } -        else -        { -            chip.GenerateBlock3(samples, buffer); -            AddSamples_s32(samples, buffer); -        } -    } - -    void Handler::GenerateArr(Bit32s *out, Bitu *samples) -    { -        if(GCC_UNLIKELY(*samples > 512)) -            *samples = 512; - -        if(!chip.opl3Active) -            chip.GenerateBlock2(*samples, out); -        else -            chip.GenerateBlock3(*samples, out); -    } - -    void Handler::GenerateArr(Bit32s *out, ssize_t *samples) -    { -        if(GCC_UNLIKELY(*samples > 512)) -            *samples = 512; - -        if(!chip.opl3Active) -            chip.GenerateBlock2(static_cast<Bitu>(*samples), out); -        else -            chip.GenerateBlock3(static_cast<Bitu>(*samples), out); -    } - -    void Handler::GenerateArr(Bit16s *out, ssize_t *samples) -    { -        Bit32s out32[1024]; -        if(GCC_UNLIKELY(*samples > 512)) -            *samples = 512; -        memset(out32, 0, sizeof(Bit32s) * 1024); -        if(!chip.opl3Active) -            chip.GenerateBlock2(static_cast<Bitu>(*samples), out32); -        else -            chip.GenerateBlock3(static_cast<Bitu>(*samples), out32); -        ssize_t sz = *samples * 2; -        for(ssize_t i = 0; i < sz; i++) -            out[i] = static_cast<Bit16s>(DBOPL_CLAMP(out32[i], static_cast<ssize_t>(INT16_MIN), static_cast<ssize_t>(INT16_MAX))); -    } - -    void Handler::GenerateArrMix(Bit32s *out, ssize_t *samples) -    { -        if(GCC_UNLIKELY(*samples > 512)) -            *samples = 512; -        if(!chip.opl3Active) -            chip.GenerateBlock2_Mix(static_cast<Bitu>(*samples), out); -        else -            chip.GenerateBlock3_Mix(static_cast<Bitu>(*samples), out); -    } - -    void Handler::GenerateArrMix(Bit16s *out, ssize_t *samples) -    { -        Bit32s out32[1024]; -        if(GCC_UNLIKELY(*samples > 512)) -            *samples = 512; -        memset(out32, 0, sizeof(Bit32s) * 1024); -        if(!chip.opl3Active) -            chip.GenerateBlock2(static_cast<Bitu>(*samples), out32); -        else -            chip.GenerateBlock3(static_cast<Bitu>(*samples), out32); -        ssize_t sz = *samples * 2; -        for(ssize_t i = 0; i < sz; i++) -            out[i] += static_cast<Bit16s>(DBOPL_CLAMP(out32[i], static_cast<ssize_t>(INT16_MIN), static_cast<ssize_t>(INT16_MAX))); -    } - - -    void Handler::Init(Bitu rate) -    { -        InitTables(); -        chip.Setup((Bit32u)rate); -    } - - -}       //Namespace DBOPL - -//#endif //ADLMIDI_USE_DOSBOX_OPL +#endif +} + +Bits INLINE Operator::GetSample( Bits modulation ) { +	Bitu vol = ForwardVolume(); +	if ( ENV_SILENT( vol ) ) { +		//Simply forward the wave +		waveIndex += waveCurrent; +		return 0; +	} else { +		Bitu index = ForwardWave(); +		index += modulation; +		return GetWave( index, vol ); +	} +} + +Operator::Operator() { +	chanData = 0; +	freqMul = 0; +	waveIndex = 0; +	waveAdd = 0; +	waveCurrent = 0; +	keyOn = 0; +	ksr = 0; +	reg20 = 0; +	reg40 = 0; +	reg60 = 0; +	reg80 = 0; +	regE0 = 0; +	SetState( OFF ); +	rateZero = (1 << OFF); +	sustainLevel = ENV_MAX; +	currentLevel = ENV_MAX; +	totalLevel = ENV_MAX; +	volume = ENV_MAX; +	releaseAdd = 0; +} + +/* +	Channel +*/ + +Channel::Channel() { +	old[0] = old[1] = 0; +	chanData = 0; +	regB0 = 0; +	regC0 = 0; +	maskLeft = -1; +	maskRight = -1; +	feedback = 31; +	fourMask = 0; +	synthHandler = &Channel::BlockTemplate< sm2FM >; +} + +void Channel::SetChanData( const Chip* chip, Bit32u data ) { +	Bit32u change = chanData ^ data; +	chanData = data; +	Op( 0 )->chanData = data; +	Op( 1 )->chanData = data; +	//Since a frequency update triggered this, always update frequency +	Op( 0 )->UpdateFrequency(); +	Op( 1 )->UpdateFrequency(); +	if ( change & ( 0xff << SHIFT_KSLBASE ) ) { +		Op( 0 )->UpdateAttenuation(); +		Op( 1 )->UpdateAttenuation(); +	} +	if ( change & ( 0xff << SHIFT_KEYCODE ) ) { +		Op( 0 )->UpdateRates( chip ); +		Op( 1 )->UpdateRates( chip ); +	} +} + +void Channel::UpdateFrequency( const Chip* chip, Bit8u fourOp ) { +	//Extrace the frequency bits +	Bit32u data = chanData & 0xffff; +	Bit32u kslBase = KslTable[ data >> 6 ]; +	Bit32u keyCode = ( data & 0x1c00) >> 9; +	if ( chip->reg08 & 0x40 ) { +		keyCode |= ( data & 0x100)>>8;	/* notesel == 1 */ +	} else { +		keyCode |= ( data & 0x200)>>9;	/* notesel == 0 */ +	} +	//Add the keycode and ksl into the highest bits of chanData +	data |= (keyCode << SHIFT_KEYCODE) | ( kslBase << SHIFT_KSLBASE ); +	( this + 0 )->SetChanData( chip, data ); +	if ( fourOp & 0x3f ) { +		( this + 1 )->SetChanData( chip, data ); +	} +} + +void Channel::WriteA0( const Chip* chip, Bit8u val ) { +	Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask; +	//Don't handle writes to silent fourop channels +	if ( fourOp > 0x80 ) +		return; +	Bit32u change = (chanData ^ val ) & 0xff; +	if ( change ) { +		chanData ^= change; +		UpdateFrequency( chip, fourOp ); +	} +} + +void Channel::WriteB0( const Chip* chip, Bit8u val ) { +	Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask; +	//Don't handle writes to silent fourop channels +	if ( fourOp > 0x80 ) +		return; +	Bitu change = (chanData ^ ( val << 8 ) ) & 0x1f00; +	if ( change ) { +		chanData ^= change; +		UpdateFrequency( chip, fourOp ); +	} +	//Check for a change in the keyon/off state +	if ( !(( val ^ regB0) & 0x20)) +		return; +	regB0 = val; +	if ( val & 0x20 ) { +		Op(0)->KeyOn( 0x1 ); +		Op(1)->KeyOn( 0x1 ); +		if ( fourOp & 0x3f ) { +			( this + 1 )->Op(0)->KeyOn( 1 ); +			( this + 1 )->Op(1)->KeyOn( 1 ); +		} +	} else { +		Op(0)->KeyOff( 0x1 ); +		Op(1)->KeyOff( 0x1 ); +		if ( fourOp & 0x3f ) { +			( this + 1 )->Op(0)->KeyOff( 1 ); +			( this + 1 )->Op(1)->KeyOff( 1 ); +		} +	} +} + +void Channel::WriteC0(const Chip* chip, Bit8u val) { +	Bit8u change = val ^ regC0; +	if (!change) +		return; +	regC0 = val; +	feedback = (regC0 >> 1) & 7; +	if (feedback) { +		//We shift the input to the right 10 bit wave index value +		feedback = 9 - feedback; +	} +	else { +		feedback = 31; +	} +	UpdateSynth(chip); +} + +void Channel::UpdateSynth( const Chip* chip ) { +	//Select the new synth mode +	if ( chip->opl3Active ) { +		//4-op mode enabled for this channel +		if ( (chip->reg104 & fourMask) & 0x3f ) { +			Channel* chan0, *chan1; +			//Check if it's the 2nd channel in a 4-op +			if ( !(fourMask & 0x80 ) ) { +				chan0 = this; +				chan1 = this + 1; +			} else { +				chan0 = this - 1; +				chan1 = this; +			} + +			Bit8u synth = ( (chan0->regC0 & 1) << 0 )| (( chan1->regC0 & 1) << 1 ); +			switch ( synth ) { +			case 0: +				chan0->synthHandler = &Channel::BlockTemplate< sm3FMFM >; +				break; +			case 1: +				chan0->synthHandler = &Channel::BlockTemplate< sm3AMFM >; +				break; +			case 2: +				chan0->synthHandler = &Channel::BlockTemplate< sm3FMAM >; +				break; +			case 3: +				chan0->synthHandler = &Channel::BlockTemplate< sm3AMAM >; +				break; +			} +		//Disable updating percussion channels +		} else if ((fourMask & 0x40) && ( chip->regBD & 0x20) ) { + +		//Regular dual op, am or fm +		} else if (regC0 & 1 ) { +			synthHandler = &Channel::BlockTemplate< sm3AM >; +		} else { +			synthHandler = &Channel::BlockTemplate< sm3FM >; +		} +		maskLeft = (regC0 & 0x10 ) ? -1 : 0; +		maskRight = (regC0 & 0x20 ) ? -1 : 0; +	//opl2 active +	} else { +		//Disable updating percussion channels +		if ( (fourMask & 0x40) && ( chip->regBD & 0x20 ) ) { + +		//Regular dual op, am or fm +		} else if (regC0 & 1 ) { +			synthHandler = &Channel::BlockTemplate< sm2AM >; +		} else { +			synthHandler = &Channel::BlockTemplate< sm2FM >; +		} +	} +} + +template< bool opl3Mode> +INLINE void Channel::GeneratePercussion( Chip* chip, Bit32s* output ) { +	Channel* chan = this; + +	//BassDrum +	Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback; +	old[0] = old[1]; +	old[1] = static_cast<Bit32u>(Op(0)->GetSample( mod )); + +	//When bassdrum is in AM mode first operator is ignoed +	if ( chan->regC0 & 1 ) { +		mod = 0; +	} else { +		mod = old[0]; +	} +	Bit32s sample = static_cast<Bit32u>(Op(1)->GetSample( mod )); + + +	//Precalculate stuff used by other outputs +	Bit32u noiseBit = chip->ForwardNoise() & 0x1; +	Bit32u c2 = static_cast<Bit32u>(Op(2)->ForwardWave()); +	Bit32u c5 = static_cast<Bit32u>(Op(5)->ForwardWave()); +	Bit32u phaseBit = (((c2 & 0x88) ^ ((c2<<5) & 0x80)) | ((c5 ^ (c5<<2)) & 0x20)) ? 0x02 : 0x00; + +	//Hi-Hat +	Bit32u hhVol = static_cast<Bit32u>(Op(2)->ForwardVolume()); +	if ( !ENV_SILENT( hhVol ) ) { +		Bit32u hhIndex = (phaseBit<<8) | (0x34 << ( phaseBit ^ (noiseBit << 1 ))); +		sample += static_cast<Bit32u>(Op(2)->GetWave( hhIndex, hhVol )); +	} +	//Snare Drum +	Bit32u sdVol = static_cast<Bit32u>(Op(3)->ForwardVolume()); +	if ( !ENV_SILENT( sdVol ) ) { +		Bit32u sdIndex = ( 0x100 + (c2 & 0x100) ) ^ ( noiseBit << 8 ); +		sample += static_cast<Bit32u>(Op(3)->GetWave( sdIndex, sdVol )); +	} +	//Tom-tom +	sample += static_cast<Bit32u>(Op(4)->GetSample( 0 )); + +	//Top-Cymbal +	Bit32u tcVol = static_cast<Bit32u>(Op(5)->ForwardVolume()); +	if ( !ENV_SILENT( tcVol ) ) { +		Bit32u tcIndex = (1 + phaseBit) << 8; +		sample += static_cast<Bit32u>(Op(5)->GetWave( tcIndex, tcVol )); +	} +	sample <<= 1; +	if ( opl3Mode ) { +		output[0] += sample; +		output[1] += sample; +	} else { +		output[0] += sample; +	} +} + +template<SynthMode mode> +Channel* Channel::BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ) { +	switch( mode ) { +	case sm2AM: +	case sm3AM: +		if ( Op(0)->Silent() && Op(1)->Silent() ) { +			old[0] = old[1] = 0; +			return (this + 1); +		} +		break; +	case sm2FM: +	case sm3FM: +		if ( Op(1)->Silent() ) { +			old[0] = old[1] = 0; +			return (this + 1); +		} +		break; +	case sm3FMFM: +		if ( Op(3)->Silent() ) { +			old[0] = old[1] = 0; +			return (this + 2); +		} +		break; +	case sm3AMFM: +		if ( Op(0)->Silent() && Op(3)->Silent() ) { +			old[0] = old[1] = 0; +			return (this + 2); +		} +		break; +	case sm3FMAM: +		if ( Op(1)->Silent() && Op(3)->Silent() ) { +			old[0] = old[1] = 0; +			return (this + 2); +		} +		break; +	case sm3AMAM: +		if ( Op(0)->Silent() && Op(2)->Silent() && Op(3)->Silent() ) { +			old[0] = old[1] = 0; +			return (this + 2); +		} +		break; +	default: +		break; +	} +	//Init the operators with the the current vibrato and tremolo values +	Op( 0 )->Prepare( chip ); +	Op( 1 )->Prepare( chip ); +	if ( mode > sm4Start ) { +		Op( 2 )->Prepare( chip ); +		Op( 3 )->Prepare( chip ); +	} +	if ( mode > sm6Start ) { +		Op( 4 )->Prepare( chip ); +		Op( 5 )->Prepare( chip ); +	} +	for ( Bitu i = 0; i < samples; i++ ) { +		//Early out for percussion handlers +		if ( mode == sm2Percussion ) { +			GeneratePercussion<false>( chip, output + i ); +			continue;	//Prevent some unitialized value bitching +		} else if ( mode == sm3Percussion ) { +			GeneratePercussion<true>( chip, output + i * 2 ); +			continue;	//Prevent some unitialized value bitching +		} + +		//Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise +		Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback; +		old[0] = old[1]; +		old[1] = static_cast<Bit32u>(Op(0)->GetSample( mod )); +		Bit32s sample; +		Bit32s out0 = old[0]; +		if ( mode == sm2AM || mode == sm3AM ) { +			sample = static_cast<Bit32u>(out0 + Op(1)->GetSample( 0 )); +		} else if ( mode == sm2FM || mode == sm3FM ) { +			sample = static_cast<Bit32u>(Op(1)->GetSample( out0 )); +		} else if ( mode == sm3FMFM ) { +			Bits next = Op(1)->GetSample( out0 ); +			next = Op(2)->GetSample( next ); +			sample = static_cast<Bit32u>(Op(3)->GetSample( next )); +		} else if ( mode == sm3AMFM ) { +			sample = out0; +			Bits next = Op(1)->GetSample( 0 ); +			next = Op(2)->GetSample( next ); +			sample += static_cast<Bit32u>(Op(3)->GetSample( next )); +		} else if ( mode == sm3FMAM ) { +			sample = static_cast<Bit32u>(Op(1)->GetSample( out0 )); +			Bits next = Op(2)->GetSample( 0 ); +			sample += static_cast<Bit32u>(Op(3)->GetSample( next )); +		} else if ( mode == sm3AMAM ) { +			sample = out0; +			Bits next = Op(1)->GetSample( 0 ); +			sample += static_cast<Bit32u>(Op(2)->GetSample( next )); +			sample += static_cast<Bit32u>(Op(3)->GetSample( 0 )); +		} +		switch( mode ) { +		case sm2AM: +		case sm2FM: +			output[ i ] += sample; +			break; +		case sm3AM: +		case sm3FM: +		case sm3FMFM: +		case sm3AMFM: +		case sm3FMAM: +		case sm3AMAM: +			output[ i * 2 + 0 ] += sample & maskLeft; +			output[ i * 2 + 1 ] += sample & maskRight; +			break; +		default: +			break; +		} +	} +	switch( mode ) { +	case sm2AM: +	case sm2FM: +	case sm3AM: +	case sm3FM: +		return ( this + 1 ); +	case sm3FMFM: +	case sm3AMFM: +	case sm3FMAM: +	case sm3AMAM: +		return( this + 2 ); +	case sm2Percussion: +	case sm3Percussion: +		return( this + 3 ); +	} +	return 0; +} + +/* +	Chip +*/ + +Chip::Chip() { +	reg08 = 0; +	reg04 = 0; +	regBD = 0; +	reg104 = 0; +	opl3Active = 0; +} + +INLINE Bit32u Chip::ForwardNoise() { +	noiseCounter += noiseAdd; +	Bitu count = noiseCounter >> LFO_SH; +	noiseCounter &= WAVE_MASK; +	for ( ; count > 0; --count ) { +		//Noise calculation from mame +		noiseValue ^= ( 0x800302 ) & ( 0 - (noiseValue & 1 ) ); +		noiseValue >>= 1; +	} +	return noiseValue; +} + +INLINE Bit32u Chip::ForwardLFO( Bit32u samples ) { +	//Current vibrato value, runs 4x slower than tremolo +	vibratoSign = ( VibratoTable[ vibratoIndex >> 2] ) >> 7; +	vibratoShift = ( VibratoTable[ vibratoIndex >> 2] & 7) + vibratoStrength; +	tremoloValue = TremoloTable[ tremoloIndex ] >> tremoloStrength; + +	//Check hom many samples there can be done before the value changes +	Bit32u todo = LFO_MAX - lfoCounter; +	Bit32u count = (todo + lfoAdd - 1) / lfoAdd; +	if ( count > samples ) { +		count = samples; +		lfoCounter += count * lfoAdd; +	} else { +		lfoCounter += count * lfoAdd; +		lfoCounter &= (LFO_MAX - 1); +		//Maximum of 7 vibrato value * 4 +		vibratoIndex = ( vibratoIndex + 1 ) & 31; +		//Clip tremolo to the the table size +		if ( tremoloIndex + 1 < TREMOLO_TABLE  ) +			++tremoloIndex; +		else +			tremoloIndex = 0; +	} +	return count; +} + + +void Chip::WriteBD( Bit8u val ) { +	Bit8u change = regBD ^ val; +	if ( !change ) +		return; +	regBD = val; +	//TODO could do this with shift and xor? +	vibratoStrength = (val & 0x40) ? 0x00 : 0x01; +	tremoloStrength = (val & 0x80) ? 0x00 : 0x02; +	if ( val & 0x20 ) { +		//Drum was just enabled, make sure channel 6 has the right synth +		if ( change & 0x20 ) { +			if ( opl3Active ) { +				chan[6].synthHandler = &Channel::BlockTemplate< sm3Percussion >; +			} else { +				chan[6].synthHandler = &Channel::BlockTemplate< sm2Percussion >; +			} +		} +		//Bass Drum +		if ( val & 0x10 ) { +			chan[6].op[0].KeyOn( 0x2 ); +			chan[6].op[1].KeyOn( 0x2 ); +		} else { +			chan[6].op[0].KeyOff( 0x2 ); +			chan[6].op[1].KeyOff( 0x2 ); +		} +		//Hi-Hat +		if ( val & 0x1 ) { +			chan[7].op[0].KeyOn( 0x2 ); +		} else { +			chan[7].op[0].KeyOff( 0x2 ); +		} +		//Snare +		if ( val & 0x8 ) { +			chan[7].op[1].KeyOn( 0x2 ); +		} else { +			chan[7].op[1].KeyOff( 0x2 ); +		} +		//Tom-Tom +		if ( val & 0x4 ) { +			chan[8].op[0].KeyOn( 0x2 ); +		} else { +			chan[8].op[0].KeyOff( 0x2 ); +		} +		//Top Cymbal +		if ( val & 0x2 ) { +			chan[8].op[1].KeyOn( 0x2 ); +		} else { +			chan[8].op[1].KeyOff( 0x2 ); +		} +	//Toggle keyoffs when we turn off the percussion +	} else if ( change & 0x20 ) { +		//Trigger a reset to setup the original synth handler +		//This makes it call +		chan[6].UpdateSynth( this ); +		chan[6].op[0].KeyOff( 0x2 ); +		chan[6].op[1].KeyOff( 0x2 ); +		chan[7].op[0].KeyOff( 0x2 ); +		chan[7].op[1].KeyOff( 0x2 ); +		chan[8].op[0].KeyOff( 0x2 ); +		chan[8].op[1].KeyOff( 0x2 ); +	} +} + + +#define REGOP( _FUNC_ )															\ +	index = ( ( reg >> 3) & 0x20 ) | ( reg & 0x1f );								\ +	if ( OpOffsetTable[ index ] ) {													\ +		Operator* regOp = (Operator*)( ((char *)this ) + OpOffsetTable[ index ] );	\ +		regOp->_FUNC_( this, val );													\ +	} + +#define REGCHAN( _FUNC_ )																\ +	index = ( ( reg >> 4) & 0x10 ) | ( reg & 0xf );										\ +	if ( ChanOffsetTable[ index ] ) {													\ +		Channel* regChan = (Channel*)( ((char *)this ) + ChanOffsetTable[ index ] );	\ +		regChan->_FUNC_( this, val );													\ +	} + +//Update the 0xc0 register for all channels to signal the switch to mono/stereo handlers +void Chip::UpdateSynths() { +	for (int i = 0; i < 18; i++) { +		chan[i].UpdateSynth(this); +	} +} + + +void Chip::WriteReg( Bit32u reg, Bit8u val ) { +	Bitu index; +	switch ( (reg & 0xf0) >> 4 ) { +	case 0x00 >> 4: +		if ( reg == 0x01 ) { +			waveFormMask = ( val & 0x20 ) ? 0x7 : 0x0; +		} else if ( reg == 0x104 ) { +			//Only detect changes in lowest 6 bits +			if ( !((reg104 ^ val) & 0x3f) ) +				return; +			//Always keep the highest bit enabled, for checking > 0x80 +			reg104 = 0x80 | ( val & 0x3f ); +			//Switch synths when changing the 4op combinations +			UpdateSynths(); +		} else if ( reg == 0x105 ) { +			//MAME says the real opl3 doesn't reset anything on opl3 disable/enable till the next write in another register +			if ( !((opl3Active ^ val) & 1 ) ) +				return; +			opl3Active = ( val & 1 ) ? 0xff : 0; +			//Just tupdate the synths now that opl3 most have been enabled +			//This isn't how the real card handles it but need to switch to stereo generating handlers +			UpdateSynths(); +		} else if ( reg == 0x08 ) { +			reg08 = val; +		} +	case 0x10 >> 4: +		break; +	case 0x20 >> 4: +	case 0x30 >> 4: +		REGOP( Write20 ); +		break; +	case 0x40 >> 4: +	case 0x50 >> 4: +		REGOP( Write40 ); +		break; +	case 0x60 >> 4: +	case 0x70 >> 4: +		REGOP( Write60 ); +		break; +	case 0x80 >> 4: +	case 0x90 >> 4: +		REGOP( Write80 ); +		break; +	case 0xa0 >> 4: +		REGCHAN( WriteA0 ); +		break; +	case 0xb0 >> 4: +		if ( reg == 0xbd ) { +			WriteBD( val ); +		} else { +			REGCHAN( WriteB0 ); +		} +		break; +	case 0xc0 >> 4: +		REGCHAN( WriteC0 ); +	case 0xd0 >> 4: +		break; +	case 0xe0 >> 4: +	case 0xf0 >> 4: +		REGOP( WriteE0 ); +		break; +	} +} + + +Bit32u Chip::WriteAddr( Bit32u port, Bit8u val ) { +	switch ( port & 3 ) { +	case 0: +		return val; +	case 2: +		if ( opl3Active || (val == 0x05) ) +			return 0x100 | val; +		else +			return val; +	} +	return 0; +} + +void Chip::GenerateBlock2( Bitu total, Bit32s* output ) { +	while ( total > 0 ) { +		Bit32u samples = ForwardLFO( static_cast<Bit32u>(total) ); +		memset(output, 0, sizeof(Bit32s) * samples); +//		int count = 0; +		for( Channel* ch = chan; ch < chan + 9; ) { +//			count++; +			ch = (ch->*(ch->synthHandler))( this, samples, output ); +		} +		total -= samples; +		output += samples; +	} +} + +void Chip::GenerateBlock2_Mix( Bitu total, Bit32s* output ) { +	while ( total > 0 ) { +		Bit32u samples = ForwardLFO( static_cast<Bit32u>(total) ); +//		int count = 0; +		for( Channel* ch = chan; ch < chan + 9; ) { +//			count++; +			ch = (ch->*(ch->synthHandler))( this, samples, output ); +		} +		total -= samples; +		output += samples; +	} +} + +void Chip::GenerateBlock3( Bitu total, Bit32s* output  ) { +	while ( total > 0 ) { +		Bit32u samples = ForwardLFO( static_cast<Bit32u>(total) ); +		memset(output, 0, sizeof(Bit32s) * samples *2); +//		int count = 0; +		for( Channel* ch = chan; ch < chan + 18; ) { +//			count++; +			ch = (ch->*(ch->synthHandler))( this, samples, output ); +		} +		total -= samples; +		output += samples * 2; +	} +} + +void Chip::GenerateBlock3_Mix( Bitu total, Bit32s* output  ) { +	while ( total > 0 ) { +		Bit32u samples = ForwardLFO( static_cast<Bit32u>(total) ); +//		int count = 0; +		for( Channel* ch = chan; ch < chan + 18; ) { +//			count++; +			ch = (ch->*(ch->synthHandler))( this, samples, output ); +		} +		total -= samples; +		output += samples * 2; +	} +} + +void Chip::Setup( Bit32u rate ) { +	double original = OPLRATE; +//	double original = rate; +	double scale = original / (double)rate; + +	//Noise counter is run at the same precision as general waves +	noiseAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); +	noiseCounter = 0; +	noiseValue = 1;	//Make sure it triggers the noise xor the first time +	//The low frequency oscillation counter +	//Every time his overflows vibrato and tremoloindex are increased +	lfoAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); +	lfoCounter = 0; +	vibratoIndex = 0; +	tremoloIndex = 0; + +	//With higher octave this gets shifted up +	//-1 since the freqCreateTable = *2 +#ifdef WAVE_PRECISION +	double freqScale = ( 1 << 7 ) * scale * ( 1 << ( WAVE_SH - 1 - 10)); +	for ( int i = 0; i < 16; i++ ) { +		freqMul[i] = (Bit32u)( 0.5 + freqScale * FreqCreateTable[ i ] ); +	} +#else +	Bit32u freqScale = (Bit32u)( 0.5 + scale * ( 1 << ( WAVE_SH - 1 - 10))); +	for ( int i = 0; i < 16; i++ ) { +		freqMul[i] = freqScale * FreqCreateTable[ i ]; +	} +#endif + +	//-3 since the real envelope takes 8 steps to reach the single value we supply +	for ( Bit8u i = 0; i < 76; i++ ) { +		Bit8u index, shift; +		EnvelopeSelect( i, index, shift ); +		linearRates[i] = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH + ENV_EXTRA - shift - 3 ))); +	} +//	Bit32s attackDiffs[62]; +	//Generate the best matching attack rate +	for ( Bit8u i = 0; i < 62; i++ ) { +		Bit8u index, shift; +		EnvelopeSelect( i, index, shift ); +		//Original amount of samples the attack would take +		Bit32s original = (Bit32u)( (AttackSamplesTable[ index ] << shift) / scale); + +		Bit32s guessAdd = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH - shift - 3 ))); +		Bit32s bestAdd = guessAdd; +		Bit32u bestDiff = 1 << 30; +		for( Bit32u passes = 0; passes < 16; passes ++ ) { +			Bit32s volume = ENV_MAX; +			Bit32s samples = 0; +			Bit32u count = 0; +			while ( volume > 0 && samples < original * 2 ) { +				count += guessAdd; +				Bit32s change = count >> RATE_SH; +				count &= RATE_MASK; +				if ( GCC_UNLIKELY(change) ) { // less than 1 % +					volume += ( ~volume * change ) >> 3; +				} +				samples++; + +			} +			Bit32s diff = original - samples; +			Bit32u lDiff = labs( diff ); +			//Init last on first pass +			if ( lDiff < bestDiff ) { +				bestDiff = lDiff; +				bestAdd = guessAdd; +				//We hit an exactly matching sample count +				if ( !bestDiff ) +					break; +			} +			//Linear correction factor, not exactly perfect but seems to work +			double correct = (original - diff) / (double)original; +			guessAdd = (Bit32u)(guessAdd * correct); +			//Below our target +			if ( diff < 0 ) { +				//Always add one here for rounding, an overshoot will get corrected by another pass decreasing +				guessAdd++; +			} +		} +		attackRates[i] = bestAdd; +		//Keep track of the diffs for some debugging +//		attackDiffs[i] = bestDiff; +	} +	for ( Bit8u i = 62; i < 76; i++ ) { +		//This should provide instant volume maximizing +		attackRates[i] = 8 << RATE_SH; +	} +	//Setup the channels with the correct four op flags +	//Channels are accessed through a table so they appear linear here +	chan[ 0].fourMask = 0x00 | ( 1 << 0 ); +	chan[ 1].fourMask = 0x80 | ( 1 << 0 ); +	chan[ 2].fourMask = 0x00 | ( 1 << 1 ); +	chan[ 3].fourMask = 0x80 | ( 1 << 1 ); +	chan[ 4].fourMask = 0x00 | ( 1 << 2 ); +	chan[ 5].fourMask = 0x80 | ( 1 << 2 ); + +	chan[ 9].fourMask = 0x00 | ( 1 << 3 ); +	chan[10].fourMask = 0x80 | ( 1 << 3 ); +	chan[11].fourMask = 0x00 | ( 1 << 4 ); +	chan[12].fourMask = 0x80 | ( 1 << 4 ); +	chan[13].fourMask = 0x00 | ( 1 << 5 ); +	chan[14].fourMask = 0x80 | ( 1 << 5 ); + +	//mark the percussion channels +	chan[ 6].fourMask = 0x40; +	chan[ 7].fourMask = 0x40; +	chan[ 8].fourMask = 0x40; + +	//Clear Everything in opl3 mode +	WriteReg( 0x105, 0x1 ); +	for ( int i = 0; i < 512; i++ ) { +		if ( i == 0x105 ) +			continue; +		WriteReg( i, 0xff ); +		WriteReg( i, 0x0 ); +	} +	WriteReg( 0x105, 0x0 ); +	//Clear everything in opl2 mode +	for ( int i = 0; i < 255; i++ ) { +		WriteReg( i, 0xff ); +		WriteReg( i, 0x0 ); +	} +} + +static bool doneTables = false; +void InitTables( void ) { +	if ( doneTables ) +		return; +	doneTables = true; +#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) +	//Exponential volume table, same as the real adlib +	for ( int i = 0; i < 256; i++ ) { +		//Save them in reverse +		ExpTable[i] = (int)( 0.5 + ( pow(2.0, ( 255 - i) * ( 1.0 /256 ) )-1) * 1024 ); +		ExpTable[i] += 1024; //or remove the -1 oh well :) +		//Preshift to the left once so the final volume can shift to the right +		ExpTable[i] *= 2; +	} +#endif +#if ( DBOPL_WAVE == WAVE_HANDLER ) +	//Add 0.5 for the trunc rounding of the integer cast +	//Do a PI sinetable instead of the original 0.5 PI +	for ( int i = 0; i < 512; i++ ) { +		SinTable[i] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 ); +	} +#endif +#if ( DBOPL_WAVE == WAVE_TABLEMUL ) +	//Multiplication based tables +	for ( int i = 0; i < 384; i++ ) { +		int s = i * 8; +		//TODO maybe keep some of the precision errors of the original table? +		double val = ( 0.5 + ( pow(2.0, -1.0 + ( 255 - s) * ( 1.0 /256 ) )) * ( 1 << MUL_SH )); +		MulTable[i] = (Bit16u)(val); +	} + +	//Sine Wave Base +	for ( int i = 0; i < 512; i++ ) { +		WaveTable[ 0x0200 + i ] = (Bit16s)(sin( (i + 0.5) * (PI / 512.0) ) * 4084); +		WaveTable[ 0x0000 + i ] = -WaveTable[ 0x200 + i ]; +	} +	//Exponential wave +	for ( int i = 0; i < 256; i++ ) { +		WaveTable[ 0x700 + i ] = (Bit16s)( 0.5 + ( pow(2.0, -1.0 + ( 255 - i * 8) * ( 1.0 /256 ) ) ) * 4085 ); +		WaveTable[ 0x6ff - i ] = -WaveTable[ 0x700 + i ]; +	} +#endif +#if ( DBOPL_WAVE == WAVE_TABLELOG ) +	//Sine Wave Base +	for ( int i = 0; i < 512; i++ ) { +		WaveTable[ 0x0200 + i ] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 ); +		WaveTable[ 0x0000 + i ] = ((Bit16s)0x8000) | WaveTable[ 0x200 + i]; +	} +	//Exponential wave +	for ( int i = 0; i < 256; i++ ) { +		WaveTable[ 0x700 + i ] = i * 8; +		WaveTable[ 0x6ff - i ] = ((Bit16s)0x8000) | i * 8; +	} +#endif + +	//	|    |//\\|____|WAV7|//__|/\  |____|/\/\| +	//	|\\//|    |    |WAV7|    |  \/|    |    | +	//	|06  |0126|27  |7   |3   |4   |4 5 |5   | + +#if (( DBOPL_WAVE == WAVE_TABLELOG ) || ( DBOPL_WAVE == WAVE_TABLEMUL )) +	for ( int i = 0; i < 256; i++ ) { +		//Fill silence gaps +		WaveTable[ 0x400 + i ] = WaveTable[0]; +		WaveTable[ 0x500 + i ] = WaveTable[0]; +		WaveTable[ 0x900 + i ] = WaveTable[0]; +		WaveTable[ 0xc00 + i ] = WaveTable[0]; +		WaveTable[ 0xd00 + i ] = WaveTable[0]; +		//Replicate sines in other pieces +		WaveTable[ 0x800 + i ] = WaveTable[ 0x200 + i ]; +		//double speed sines +		WaveTable[ 0xa00 + i ] = WaveTable[ 0x200 + i * 2 ]; +		WaveTable[ 0xb00 + i ] = WaveTable[ 0x000 + i * 2 ]; +		WaveTable[ 0xe00 + i ] = WaveTable[ 0x200 + i * 2 ]; +		WaveTable[ 0xf00 + i ] = WaveTable[ 0x200 + i * 2 ]; +	} +#endif + +	//Create the ksl table +	for ( int oct = 0; oct < 8; oct++ ) { +		int base = oct * 8; +		for ( int i = 0; i < 16; i++ ) { +			int val = base - KslCreateTable[i]; +			if ( val < 0 ) +				val = 0; +			//*4 for the final range to match attenuation range +			KslTable[ oct * 16 + i ] = val * 4; +		} +	} +	//Create the Tremolo table, just increase and decrease a triangle wave +	for ( Bit8u i = 0; i < TREMOLO_TABLE / 2; i++ ) { +		Bit8u val = i << ENV_EXTRA; +		TremoloTable[i] = val; +		TremoloTable[TREMOLO_TABLE - 1 - i] = val; +	} +	//Create a table with offsets of the channels from the start of the chip +	DBOPL::Chip* chip = 0; +	for ( Bitu i = 0; i < 32; i++ ) { +		Bitu index = i & 0xf; +		if ( index >= 9 ) { +			ChanOffsetTable[i] = 0; +			continue; +		} +		//Make sure the four op channels follow eachother +		if ( index < 6 ) { +			index = (index % 3) * 2 + ( index / 3 ); +		} +		//Add back the bits for highest ones +		if ( i >= 16 ) +			index += 9; +		Bitu blah = reinterpret_cast<Bitu>( &(chip->chan[ index ]) ); +		ChanOffsetTable[i] = static_cast<Bit16u>(blah); +	} +	//Same for operators +	for ( Bitu i = 0; i < 64; i++ ) { +		if ( i % 8 >= 6 || ( (i / 8) % 4 == 3 ) ) { +			OpOffsetTable[i] = 0; +			continue; +		} +		Bitu chNum = (i / 8) * 3 + (i % 8) % 3; +		//Make sure we use 16 and up for the 2nd range to match the chanoffset gap +		if ( chNum >= 12 ) +			chNum += 16 - 12; +		Bitu opNum = ( i % 8 ) / 3; +		DBOPL::Channel* chan = 0; +		Bitu blah = reinterpret_cast<Bitu>( &(chan->op[opNum]) ); +		OpOffsetTable[i] = static_cast<Bit16u>(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 ); +} + +#define DB_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define DB_MIN(x, y) ((x) < (y) ? (x) : (y)) + +#define DBOPL_CLAMP(V, MIN, MAX) DB_MAX(DB_MIN(V, (MAX)), (MIN)) + +void Handler::GenerateArr(Bit32s *out, Bitu *samples) +{ +	if(GCC_UNLIKELY(*samples > 512)) +		*samples = 512; +	if(!chip.opl3Active) +		chip.GenerateBlock2(*samples, out); +	else +		chip.GenerateBlock3(*samples, out); +} + +void Handler::GenerateArr(Bit16s *out, Bitu *samples) +{ +	Bit32s out32[1024]; +	if(GCC_UNLIKELY(*samples > 512)) +		*samples = 512; +	memset(out32, 0, sizeof(Bit32s) * 1024); +	if(!chip.opl3Active) +		chip.GenerateBlock2(*samples, out32); +	else +		chip.GenerateBlock3(*samples, out32); +	Bitu sz = *samples * 2; +	for(Bitu i = 0; i < sz; i++) +		out[i] = static_cast<Bit16s>(DBOPL_CLAMP(out32[i], INT16_MIN, INT16_MAX)); +} + +void Handler::GenerateArrMix(Bit32s *out, Bitu *samples) +{ +	if(GCC_UNLIKELY(*samples > 512)) +		*samples = 512; +	if(!chip.opl3Active) +		chip.GenerateBlock2_Mix(*samples, out); +	else +		chip.GenerateBlock3_Mix(*samples, out); +} + +void Handler::GenerateArrMix(Bit16s *out, Bitu *samples) +{ +	Bit32s out32[1024]; +	if(GCC_UNLIKELY(*samples > 512)) +		*samples = 512; +	memset(out32, 0, sizeof(Bit32s) * 1024); +	if(!chip.opl3Active) +		chip.GenerateBlock2(*samples, out32); +	else +		chip.GenerateBlock3(*samples, out32); +	Bitu sz = *samples * 2; +	for(Bitu i = 0; i < sz; i++) +		out[i] += static_cast<Bit16s>(DBOPL_CLAMP(out32[i], INT16_MIN, INT16_MAX)); +} + +void Handler::Init( Bitu rate ) { +	InitTables(); +	chip.Setup( static_cast<Bit32u>(rate) ); +} + + +}		//Namespace DBOPL diff --git a/src/chips/dosbox/dbopl.h b/src/chips/dosbox/dbopl.h index 13c606f..73c0aa9 100644 --- a/src/chips/dosbox/dbopl.h +++ b/src/chips/dosbox/dbopl.h @@ -1,5 +1,5 @@  /* - *  Copyright (C) 2002-2010  The DOSBox Team + *  Copyright (C) 2002-2018  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 @@ -16,28 +16,28 @@   *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.   */ - -/* BEGIN MIDIPLAY GLUE */ +#include <inttypes.h>  #include <stdint.h> -#include <stdlib.h>  #include <sys/types.h> -typedef unsigned long Bitu; -typedef   signed long Bits; -typedef unsigned Bit32u; -typedef int      Bit32s; -typedef unsigned short Bit16u; -typedef signed   short Bit16s; -typedef unsigned char Bit8u; -typedef signed   char Bit8s; -#define INLINE inline -#ifdef _MSC_VER -#define GCC_UNLIKELY(x) (!!(x) == 0) -#define GCC_LIKELY(x)   (!!(x) == 1) + +#if defined(__GNUC__) && defined(__i386__) +#define DB_FASTCALL __attribute__((fastcall)) +#elif defined(_MSC_VER) +#define DB_FASTCALL __fastcall  #else -#define GCC_UNLIKELY(x) __builtin_expect((x),0) -#define GCC_LIKELY(x)   __builtin_expect((x),1) +#define DB_FASTCALL  #endif -/* END MIDIPLAY GLUE */ + +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;  //Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume  #define WAVE_HANDLER    10 @@ -49,267 +49,236 @@ typedef signed   char Bit8s;  //Select the type of wave generator routine  #define DBOPL_WAVE WAVE_TABLEMUL -#ifdef _WIN32 -#   ifdef _MSC_VER -#       ifdef _WIN64 -typedef __int64 ssize_t; -#       else -typedef __int32 ssize_t; -#       endif -#   else -#       ifdef _WIN64 -typedef int64_t ssize_t; -#       else -typedef int32_t ssize_t; -#       endif -#   endif -#endif - -namespace DBOPL -{ +namespace DBOPL { -    struct Chip; -    struct Operator; -    struct Channel; +struct Chip; +struct Operator; +struct Channel;  #if (DBOPL_WAVE == WAVE_HANDLER) -    typedef Bits(DB_FASTCALL *WaveHandler)(Bitu i, Bitu volume); +typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume );  #endif -    typedef Bits(DBOPL::Operator::*VolumeHandler)(); -    typedef Channel *(DBOPL::Channel::*SynthHandler)(Chip *chip, Bit32u samples, Bit32s *output); - -    //Different synth modes that can generate blocks of data -    typedef enum -    { -        sm2AM, -        sm2FM, -        sm3AM, -        sm3FM, -        sm4Start, -        sm3FMFM, -        sm3AMFM, -        sm3FMAM, -        sm3AMAM, -        sm6Start, -        sm2Percussion, -        sm3Percussion -    } SynthMode; - -    //Shifts for the values contained in chandata variable -    enum -    { -        SHIFT_KSLBASE = 16, -        SHIFT_KEYCODE = 24 -    }; - -    struct Operator -    { -        public: -            //Masks for operator 20 values -            enum -            { -                MASK_KSR = 0x10, -                MASK_SUSTAIN = 0x20, -                MASK_VIBRATO = 0x40, -                MASK_TREMOLO = 0x80 -            }; - -            typedef enum -            { -                OFF, -                RELEASE, -                SUSTAIN, -                DECAY, -                ATTACK -            } State; - -            VolumeHandler volHandler; +typedef Bits ( DBOPL::Operator::*VolumeHandler) ( ); +typedef Channel* ( DBOPL::Channel::*SynthHandler) ( Chip* chip, Bit32u samples, Bit32s* output ); + +//Different synth modes that can generate blocks of data +typedef enum { +	sm2AM, +	sm2FM, +	sm3AM, +	sm3FM, +	sm4Start, +	sm3FMFM, +	sm3AMFM, +	sm3FMAM, +	sm3AMAM, +	sm6Start, +	sm2Percussion, +	sm3Percussion, +} SynthMode; + +//Shifts for the values contained in chandata variable +enum { +	SHIFT_KSLBASE = 16, +	SHIFT_KEYCODE = 24, +}; + +struct Operator { +public: +	//Masks for operator 20 values +	enum { +		MASK_KSR = 0x10, +		MASK_SUSTAIN = 0x20, +		MASK_VIBRATO = 0x40, +		MASK_TREMOLO = 0x80, +	}; + +	typedef enum { +		OFF, +		RELEASE, +		SUSTAIN, +		DECAY, +		ATTACK, +	} State; + +	VolumeHandler volHandler;  #if (DBOPL_WAVE == WAVE_HANDLER) -            WaveHandler waveHandler;    //Routine that generate a wave +	WaveHandler waveHandler;	//Routine that generate a wave  #else -            Bit16s *waveBase; -            Bit32u waveMask; -            Bit32u waveStart; +	Bit16s* waveBase; +	Bit32u waveMask; +	Bit32u waveStart;  #endif -            Bit32u waveIndex;           //WAVE_BITS shifted counter of the frequency index -            Bit32u waveAdd;             //The base frequency without vibrato -            Bit32u waveCurrent;         //waveAdd + vibratao - -            Bit32u chanData;            //Frequency/octave and derived data coming from whatever channel controls this -            Bit32u freqMul;             //Scale channel frequency with this, TODO maybe remove? -            Bit32u vibrato;             //Scaled up vibrato strength -            Bit32s sustainLevel;        //When stopping at sustain level stop here -            Bit32s totalLevel;          //totalLevel is added to every generated volume -            Bit32u currentLevel;        //totalLevel + tremolo -            Bit32s volume;              //The currently active volume - -            Bit32u attackAdd;           //Timers for the different states of the envelope -            Bit32u decayAdd; -            Bit32u releaseAdd; -            Bit32u rateIndex;           //Current position of the evenlope - -            Bit8u rateZero;             //Bits for the different states of the envelope having no changes -            Bit8u keyOn;                //Bitmask of different values that can generate keyon -            //Registers, also used to check for changes -            Bit8u reg20, reg40, reg60, reg80, regE0; -            //Active part of the envelope we're in -            Bit8u state; -            //0xff when tremolo is enabled -            Bit8u tremoloMask; -            //Strength of the vibrato -            Bit8u vibStrength; -            //Keep track of the calculated KSR so we can check for changes -            Bit8u ksr; -        private: -            void SetState(Bit8u s); -            void UpdateAttack(const Chip *chip); -            void UpdateRelease(const Chip *chip); -            void UpdateDecay(const Chip *chip); -        public: -            void UpdateAttenuation(); -            void UpdateRates(const Chip *chip); -            void UpdateFrequency(); - -            void Write20(const Chip *chip, Bit8u val); -            void Write40(const Chip *chip, Bit8u val); -            void Write60(const Chip *chip, Bit8u val); -            void Write80(const Chip *chip, Bit8u val); -            void WriteE0(const Chip *chip, Bit8u val); - -            bool Silent() const; -            void Prepare(const Chip *chip); - -            void KeyOn(Bit8u mask); -            void KeyOff(Bit8u mask); - -            template< State state> -            Bits TemplateVolume(); - -            Bit32s RateForward(Bit32u add); -            Bitu ForwardWave(); -            Bitu ForwardVolume(); - -            Bits GetSample(Bits modulation); -            Bits GetWave(Bitu index, Bitu vol); -        public: -            Operator(); -            char ____padding[5]; -    }; - -    struct Channel -    { -        Operator op[2]; -        inline Operator *Op(Bitu index) -        { -            return &((this + (index >> 1))->op[ index & 1 ]); -        } -        SynthHandler synthHandler; -        Bit32u chanData;        //Frequency/octave and derived values -        Bit32s old[2];          //Old data for feedback - -        Bit8u feedback;         //Feedback shift -        Bit8u regB0;            //Register values to check for changes -        Bit8u regC0; -        //This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel -        Bit8u fourMask; -        Bit8s maskLeft;     //Sign extended values for both channel's panning -        Bit8s maskRight; - -        //Forward the channel data to the operators of the channel -        void SetChanData(const Chip *chip, Bit32u data); -        //Change in the chandata, check for new values and if we have to forward to operators -        void UpdateFrequency(const Chip *chip, Bit8u fourOp); -        void WriteA0(const Chip *chip, Bit8u val); -        void WriteB0(const Chip *chip, Bit8u val); -        void WriteC0(const Chip *chip, Bit8u val); -        void ResetC0(const Chip *chip); - -        //call this for the first channel -        template< bool opl3Mode > -        void GeneratePercussion(Chip *chip, Bit32s *output); - -        //Generate blocks of data in specific modes -        template<SynthMode mode> -        Channel *BlockTemplate(Chip *chip, Bit32u samples, Bit32s *output); -        Channel(); -        char ____padding[6]; -    }; - -    struct Chip -    { -        //This is used as the base counter for vibrato and tremolo -        Bit32u lfoCounter; -        Bit32u lfoAdd; - - -        Bit32u noiseCounter; -        Bit32u noiseAdd; -        Bit32u noiseValue; - -        //Frequency scales for the different multiplications -        Bit32u freqMul[16]; -        //Rates for decay and release for rate of this chip -        Bit32u linearRates[76]; -        //Best match attack rates for the rate of this chip -        Bit32u attackRates[76]; - -        //18 channels with 2 operators each -        Channel chan[18]; - -        Bit8u reg104; -        Bit8u reg08; -        Bit8u reg04; -        Bit8u regBD; -        Bit8u vibratoIndex; -        Bit8u tremoloIndex; -        Bit8s vibratoSign; -        Bit8u vibratoShift; -        Bit8u tremoloValue; -        Bit8u vibratoStrength; -        Bit8u tremoloStrength; -        //Mask for allowed wave forms -        Bit8u waveFormMask; -        //0 or -1 when enabled -        Bit8s opl3Active; - -        //Return the maximum amount of samples before and LFO change -        Bit32u ForwardLFO(Bit32u samples); -        Bit32u ForwardNoise(); - -        void WriteBD(Bit8u val); -        void WriteReg(Bit32u reg, Bit8u val); - -        Bit32u WriteAddr(Bit32u port, Bit8u val); - -        void GenerateBlock2(Bitu samples, Bit32s *output); -        void GenerateBlock3(Bitu samples, Bit32s *output); - -        void GenerateBlock2_Mix(Bitu samples, Bit32s *output); -        void GenerateBlock3_Mix(Bitu samples, Bit32s *output); - -        void Generate(Bit32u samples); -        void Setup(Bit32u r); - -        Chip(); -    }; - -    struct Handler -    { -        DBOPL::Chip chip; -        Bit32u WriteAddr(Bit32u port, Bit8u val); -        void WriteReg(Bit32u addr, Bit8u val); -        void Generate(void(*AddSamples_m32)(Bitu, Bit32s *), -                      void(*AddSamples_s32)(Bitu, Bit32s *), -                      Bitu samples); -        void GenerateArr(Bit32s *out, Bitu *samples); -        void GenerateArr(Bit32s *out, ssize_t *samples); -        void GenerateArr(Bit16s *out, ssize_t *samples); -        void GenerateArrMix(Bit32s *out, ssize_t *samples); -        void GenerateArrMix(Bit16s *out, ssize_t *samples); -        void Init(Bitu rate); -    }; - - -}       //Namespace +	Bit32u waveIndex;			//WAVE_BITS shifted counter of the frequency index +	Bit32u waveAdd;				//The base frequency without vibrato +	Bit32u waveCurrent;			//waveAdd + vibratao + +	Bit32u chanData;			//Frequency/octave and derived data coming from whatever channel controls this +	Bit32u freqMul;				//Scale channel frequency with this, TODO maybe remove? +	Bit32u vibrato;				//Scaled up vibrato strength +	Bit32s sustainLevel;		//When stopping at sustain level stop here +	Bit32s totalLevel;			//totalLevel is added to every generated volume +	Bit32u currentLevel;		//totalLevel + tremolo +	Bit32s volume;				//The currently active volume + +	Bit32u attackAdd;			//Timers for the different states of the envelope +	Bit32u decayAdd; +	Bit32u releaseAdd; +	Bit32u rateIndex;			//Current position of the evenlope + +	Bit8u rateZero;				//Bits for the different states of the envelope having no changes +	Bit8u keyOn;				//Bitmask of different values that can generate keyon +	//Registers, also used to check for changes +	Bit8u reg20, reg40, reg60, reg80, regE0; +	//Active part of the envelope we're in +	Bit8u state; +	//0xff when tremolo is enabled +	Bit8u tremoloMask; +	//Strength of the vibrato +	Bit8u vibStrength; +	//Keep track of the calculated KSR so we can check for changes +	Bit8u ksr; +private: +	void SetState( Bit8u s ); +	void UpdateAttack( const Chip* chip ); +	void UpdateRelease( const Chip* chip ); +	void UpdateDecay( const Chip* chip ); +public: +	void UpdateAttenuation(); +	void UpdateRates( const Chip* chip ); +	void UpdateFrequency( ); + +	void Write20( const Chip* chip, Bit8u val ); +	void Write40( const Chip* chip, Bit8u val ); +	void Write60( const Chip* chip, Bit8u val ); +	void Write80( const Chip* chip, Bit8u val ); +	void WriteE0( const Chip* chip, Bit8u val ); + +	bool Silent() const; +	void Prepare( const Chip* chip ); + +	void KeyOn( Bit8u mask); +	void KeyOff( Bit8u mask); + +	template< State state> +	Bits TemplateVolume( ); + +	Bit32s RateForward( Bit32u add ); +	Bitu ForwardWave(); +	Bitu ForwardVolume(); + +	Bits GetSample( Bits modulation ); +	Bits GetWave( Bitu index, Bitu vol ); +public: +	Operator(); +}; + +struct Channel { +	Operator op[2]; +	inline Operator* Op( Bitu index ) { +		return &( ( this + (index >> 1) )->op[ index & 1 ]); +	} +	SynthHandler synthHandler; +	Bit32u chanData;		//Frequency/octave and derived values +	Bit32s old[2];			//Old data for feedback + +	Bit8u feedback;			//Feedback shift +	Bit8u regB0;			//Register values to check for changes +	Bit8u regC0; +	//This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel +	Bit8u fourMask; +	Bit8s maskLeft;		//Sign extended values for both channel's panning +	Bit8s maskRight; + +	//Forward the channel data to the operators of the channel +	void SetChanData( const Chip* chip, Bit32u data ); +	//Change in the chandata, check for new values and if we have to forward to operators +	void UpdateFrequency( const Chip* chip, Bit8u fourOp ); +	void UpdateSynth(const Chip* chip); +	void WriteA0( const Chip* chip, Bit8u val ); +	void WriteB0( const Chip* chip, Bit8u val ); +	void WriteC0( const Chip* chip, Bit8u val ); + +	//call this for the first channel +	template< bool opl3Mode > +	void GeneratePercussion( Chip* chip, Bit32s* output ); + +	//Generate blocks of data in specific modes +	template<SynthMode mode> +	Channel* BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ); +	Channel(); +}; + +struct Chip { +	//This is used as the base counter for vibrato and tremolo +	Bit32u lfoCounter; +	Bit32u lfoAdd; + + +	Bit32u noiseCounter; +	Bit32u noiseAdd; +	Bit32u noiseValue; + +	//Frequency scales for the different multiplications +	Bit32u freqMul[16]; +	//Rates for decay and release for rate of this chip +	Bit32u linearRates[76]; +	//Best match attack rates for the rate of this chip +	Bit32u attackRates[76]; + +	//18 channels with 2 operators each +	Channel chan[18]; + +	Bit8u reg104; +	Bit8u reg08; +	Bit8u reg04; +	Bit8u regBD; +	Bit8u vibratoIndex; +	Bit8u tremoloIndex; +	Bit8s vibratoSign; +	Bit8u vibratoShift; +	Bit8u tremoloValue; +	Bit8u vibratoStrength; +	Bit8u tremoloStrength; +	//Mask for allowed wave forms +	Bit8u waveFormMask; +	//0 or -1 when enabled +	Bit8s opl3Active; + +	//Return the maximum amount of samples before and LFO change +	Bit32u ForwardLFO( Bit32u samples ); +	Bit32u ForwardNoise(); + +	void WriteBD( Bit8u val ); +	void WriteReg(Bit32u reg, Bit8u val ); + +	Bit32u WriteAddr( Bit32u port, Bit8u val ); + +	void GenerateBlock2( Bitu samples, Bit32s* output ); +	void GenerateBlock2_Mix( Bitu samples, Bit32s* output ); +	void GenerateBlock3( Bitu samples, Bit32s* output ); +	void GenerateBlock3_Mix( Bitu samples, Bit32s* output ); + +	//Update the synth handlers in all channels +	void UpdateSynths(); +	void Generate( Bit32u samples ); +	void Setup( Bit32u r ); + +	Chip(); +}; + +struct Handler { +	DBOPL::Chip chip; +	Bit32u WriteAddr( Bit32u port, Bit8u val ); +	void WriteReg( Bit32u addr, Bit8u val ); +	void GenerateArr(Bit32s *out, Bitu *samples); +	void GenerateArr(Bit16s *out, Bitu *samples); +	void GenerateArrMix(Bit32s *out, Bitu *samples); +	void GenerateArrMix(Bit16s *out, Bitu *samples); +	void Init( Bitu rate ); +}; + + +}		//Namespace diff --git a/src/chips/dosbox_opl3.cpp b/src/chips/dosbox_opl3.cpp index e748b85..af4cb08 100644 --- a/src/chips/dosbox_opl3.cpp +++ b/src/chips/dosbox_opl3.cpp @@ -1,22 +1,16 @@  #include "dosbox_opl3.h"  #include "dosbox/dbopl.h" +#include <new>  #include <cstdlib>  #include <assert.h>  DosBoxOPL3::DosBoxOPL3() : -    OPLChipBase(), -    m_chip(NULL) +    OPLChipBaseBufferedT(), +    m_chip(new DBOPL::Handler)  {      reset();  } -DosBoxOPL3::DosBoxOPL3(const DosBoxOPL3 &c) : -    OPLChipBase(c), -    m_chip(NULL) -{ -    setRate(c.m_rate); -} -  DosBoxOPL3::~DosBoxOPL3()  {      DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip); @@ -25,23 +19,20 @@ DosBoxOPL3::~DosBoxOPL3()  void DosBoxOPL3::setRate(uint32_t rate)  { -    OPLChipBase::setRate(rate); -    reset(); +    OPLChipBaseBufferedT::setRate(rate); +    DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip); +    chip_r->~Handler(); +    new(chip_r) DBOPL::Handler; +    chip_r->Init(49716);  }  void DosBoxOPL3::reset()  { +    OPLChipBaseBufferedT::reset();      DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip); -    if(m_chip && chip_r) -        delete chip_r; -    m_chip = new DBOPL::Handler; -    chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip); -    chip_r->Init(m_rate); -} - -void DosBoxOPL3::reset(uint32_t rate) -{ -    setRate(rate); +    chip_r->~Handler(); +    new(chip_r) DBOPL::Handler; +    chip_r->Init(49716);  }  void DosBoxOPL3::writeReg(uint16_t addr, uint8_t data) @@ -50,63 +41,14 @@ void DosBoxOPL3::writeReg(uint16_t addr, uint8_t data)      chip_r->WriteReg(static_cast<Bit32u>(addr), data);  } -int DosBoxOPL3::generate(int16_t *output, size_t frames) -{ -    DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip); -    ssize_t left = (ssize_t)frames; -    while(left > 0) -    { -        ssize_t frames_i = left; -        chip_r->GenerateArr(output, &frames_i); -        output += (frames_i * 2); -        left -= frames_i; -    } -    return (int)frames; -} - -int DosBoxOPL3::generateAndMix(int16_t *output, size_t frames) -{ -    DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip); -    ssize_t left = (ssize_t)frames; -    while(left > 0) -    { -        ssize_t frames_i = left; -        chip_r->GenerateArrMix(output, &frames_i); -        output += (frames_i * 2); -        left -= frames_i; -    } -    return (int)frames; -} - -int DosBoxOPL3::generate32(int32_t *output, size_t frames) -{ -    DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip); -    ssize_t left = (ssize_t)frames; -    while(left > 0) -    { -        ssize_t frames_i = left; -        chip_r->GenerateArr(output, &frames_i); -        output += (frames_i * 2); -        left -= frames_i; -    } -    return (int)frames; -} - -int DosBoxOPL3::generateAndMix32(int32_t *output, size_t frames) +void DosBoxOPL3::nativeGenerateN(int16_t *output, size_t frames)  {      DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip); -    ssize_t left = (ssize_t)frames; -    while(left > 0) -    { -        ssize_t frames_i = left; -        chip_r->GenerateArrMix(output, &frames_i); -        output += (frames_i * 2); -        left -= frames_i; -    } -    return (int)frames; +    Bitu frames_i = frames; +    chip_r->GenerateArr(output, &frames_i);  }  const char *DosBoxOPL3::emulatorName()  { -    return "DosBox 0.74 OPL3"; +    return "DosBox 0.74-r4111 OPL3";  } diff --git a/src/chips/dosbox_opl3.h b/src/chips/dosbox_opl3.h index 422e2d1..f4c68da 100644 --- a/src/chips/dosbox_opl3.h +++ b/src/chips/dosbox_opl3.h @@ -3,23 +3,20 @@  #include "opl_chip_base.h" -class DosBoxOPL3 final : public OPLChipBase +class DosBoxOPL3 final : public OPLChipBaseBufferedT<DosBoxOPL3>  {      void *m_chip;  public:      DosBoxOPL3(); -    DosBoxOPL3(const DosBoxOPL3 &c); -    virtual ~DosBoxOPL3() override; +    ~DosBoxOPL3() override; -    virtual void setRate(uint32_t rate) override; -    virtual void reset() override; -    virtual void reset(uint32_t rate) override; -    virtual void writeReg(uint16_t addr, uint8_t data) override; -    virtual int generate(int16_t *output, size_t frames) override; -    virtual int generateAndMix(int16_t *output, size_t frames) override; -    virtual int generate32(int32_t *output, size_t frames) override; -    virtual int generateAndMix32(int32_t *output, size_t frames) override; -    virtual const char *emulatorName() override; +    void setRate(uint32_t rate) override; +    void reset() override; +    void writeReg(uint16_t addr, uint8_t data) override; +    void nativePreGenerate() override {} +    void nativePostGenerate() override {} +    void nativeGenerateN(int16_t *output, size_t frames) override; +    const char *emulatorName() override;  };  #endif // DOSBOX_OPL3_H diff --git a/src/chips/nuked/nukedopl3.c b/src/chips/nuked/nukedopl3.c index eadb6b9..87d3212 100644 --- a/src/chips/nuked/nukedopl3.c +++ b/src/chips/nuked/nukedopl3.c @@ -697,18 +697,18 @@ static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data)          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[0] = &channel6->slotz[1]->out; +        channel6->out[1] = &channel6->slotz[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; +        channel7->out[0] = &channel7->slotz[0]->out; +        channel7->out[1] = &channel7->slotz[0]->out; +        channel7->out[2] = &channel7->slotz[1]->out; +        channel7->out[3] = &channel7->slotz[1]->out; +        channel8->out[0] = &channel8->slotz[0]->out; +        channel8->out[1] = &channel8->slotz[0]->out; +        channel8->out[2] = &channel8->slotz[1]->out; +        channel8->out[3] = &channel8->slotz[1]->out;          for (chnum = 6; chnum < 9; chnum++)          {              chip->channel[chnum].chtype = ch_drum; @@ -719,49 +719,49 @@ static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data)          /* hh */          if (chip->rhy & 0x01)          { -            OPL3_EnvelopeKeyOn(channel7->slots[0], egk_drum); +            OPL3_EnvelopeKeyOn(channel7->slotz[0], egk_drum);          }          else          { -            OPL3_EnvelopeKeyOff(channel7->slots[0], egk_drum); +            OPL3_EnvelopeKeyOff(channel7->slotz[0], egk_drum);          }          /* tc */          if (chip->rhy & 0x02)          { -            OPL3_EnvelopeKeyOn(channel8->slots[1], egk_drum); +            OPL3_EnvelopeKeyOn(channel8->slotz[1], egk_drum);          }          else          { -            OPL3_EnvelopeKeyOff(channel8->slots[1], egk_drum); +            OPL3_EnvelopeKeyOff(channel8->slotz[1], egk_drum);          }          /* tom */          if (chip->rhy & 0x04)          { -            OPL3_EnvelopeKeyOn(channel8->slots[0], egk_drum); +            OPL3_EnvelopeKeyOn(channel8->slotz[0], egk_drum);          }          else          { -            OPL3_EnvelopeKeyOff(channel8->slots[0], egk_drum); +            OPL3_EnvelopeKeyOff(channel8->slotz[0], egk_drum);          }          /* sd */          if (chip->rhy & 0x08)          { -            OPL3_EnvelopeKeyOn(channel7->slots[1], egk_drum); +            OPL3_EnvelopeKeyOn(channel7->slotz[1], egk_drum);          }          else          { -            OPL3_EnvelopeKeyOff(channel7->slots[1], egk_drum); +            OPL3_EnvelopeKeyOff(channel7->slotz[1], egk_drum);          }          /* bd */          if (chip->rhy & 0x10)          { -            OPL3_EnvelopeKeyOn(channel6->slots[0], egk_drum); -            OPL3_EnvelopeKeyOn(channel6->slots[1], egk_drum); +            OPL3_EnvelopeKeyOn(channel6->slotz[0], egk_drum); +            OPL3_EnvelopeKeyOn(channel6->slotz[1], egk_drum);          }          else          { -            OPL3_EnvelopeKeyOff(channel6->slots[0], egk_drum); -            OPL3_EnvelopeKeyOff(channel6->slots[1], egk_drum); +            OPL3_EnvelopeKeyOff(channel6->slotz[0], egk_drum); +            OPL3_EnvelopeKeyOff(channel6->slotz[1], egk_drum);          }      }      else @@ -770,8 +770,8 @@ static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data)          {              chip->channel[chnum].chtype = ch_2op;              OPL3_ChannelSetupAlg(&chip->channel[chnum]); -            OPL3_EnvelopeKeyOff(chip->channel[chnum].slots[0], egk_drum); -            OPL3_EnvelopeKeyOff(chip->channel[chnum].slots[1], egk_drum); +            OPL3_EnvelopeKeyOff(chip->channel[chnum].slotz[0], egk_drum); +            OPL3_EnvelopeKeyOff(chip->channel[chnum].slotz[1], egk_drum);          }      }  } @@ -785,14 +785,14 @@ static void OPL3_ChannelWriteA0(opl3_channel *channel, Bit8u data)      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_EnvelopeUpdateKSL(channel->slotz[0]); +    OPL3_EnvelopeUpdateKSL(channel->slotz[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_EnvelopeUpdateKSL(channel->pair->slotz[0]); +        OPL3_EnvelopeUpdateKSL(channel->pair->slotz[1]);      }  } @@ -806,15 +806,15 @@ static void OPL3_ChannelWriteB0(opl3_channel *channel, Bit8u data)      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_EnvelopeUpdateKSL(channel->slotz[0]); +    OPL3_EnvelopeUpdateKSL(channel->slotz[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_EnvelopeUpdateKSL(channel->pair->slotz[0]); +        OPL3_EnvelopeUpdateKSL(channel->pair->slotz[1]);      }  } @@ -824,19 +824,19 @@ static void OPL3_ChannelSetupAlg(opl3_channel *channel)      {          if (channel->ch_num == 7 || channel->ch_num == 8)          { -            channel->slots[0]->mod = &channel->chip->zeromod; -            channel->slots[1]->mod = &channel->chip->zeromod; +            channel->slotz[0]->mod = &channel->chip->zeromod; +            channel->slotz[1]->mod = &channel->chip->zeromod;              return;          }          switch (channel->alg & 0x01)          {          case 0x00: -            channel->slots[0]->mod = &channel->slots[0]->fbmod; -            channel->slots[1]->mod = &channel->slots[0]->out; +            channel->slotz[0]->mod = &channel->slotz[0]->fbmod; +            channel->slotz[1]->mod = &channel->slotz[0]->out;              break;          case 0x01: -            channel->slots[0]->mod = &channel->slots[0]->fbmod; -            channel->slots[1]->mod = &channel->chip->zeromod; +            channel->slotz[0]->mod = &channel->slotz[0]->fbmod; +            channel->slotz[1]->mod = &channel->chip->zeromod;              break;          }          return; @@ -854,43 +854,43 @@ static void OPL3_ChannelSetupAlg(opl3_channel *channel)          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->pair->slotz[0]->mod = &channel->pair->slotz[0]->fbmod; +            channel->pair->slotz[1]->mod = &channel->pair->slotz[0]->out; +            channel->slotz[0]->mod = &channel->pair->slotz[1]->out; +            channel->slotz[1]->mod = &channel->slotz[0]->out; +            channel->out[0] = &channel->slotz[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->pair->slotz[0]->mod = &channel->pair->slotz[0]->fbmod; +            channel->pair->slotz[1]->mod = &channel->pair->slotz[0]->out; +            channel->slotz[0]->mod = &channel->chip->zeromod; +            channel->slotz[1]->mod = &channel->slotz[0]->out; +            channel->out[0] = &channel->pair->slotz[1]->out; +            channel->out[1] = &channel->slotz[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->pair->slotz[0]->mod = &channel->pair->slotz[0]->fbmod; +            channel->pair->slotz[1]->mod = &channel->chip->zeromod; +            channel->slotz[0]->mod = &channel->pair->slotz[1]->out; +            channel->slotz[1]->mod = &channel->slotz[0]->out; +            channel->out[0] = &channel->pair->slotz[0]->out; +            channel->out[1] = &channel->slotz[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->pair->slotz[0]->mod = &channel->pair->slotz[0]->fbmod; +            channel->pair->slotz[1]->mod = &channel->chip->zeromod; +            channel->slotz[0]->mod = &channel->pair->slotz[1]->out; +            channel->slotz[1]->mod = &channel->chip->zeromod; +            channel->out[0] = &channel->pair->slotz[0]->out; +            channel->out[1] = &channel->slotz[0]->out; +            channel->out[2] = &channel->slotz[1]->out;              channel->out[3] = &channel->chip->zeromod;              break;          } @@ -900,18 +900,18 @@ static void OPL3_ChannelSetupAlg(opl3_channel *channel)          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->slotz[0]->mod = &channel->slotz[0]->fbmod; +            channel->slotz[1]->mod = &channel->slotz[0]->out; +            channel->out[0] = &channel->slotz[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->slotz[0]->mod = &channel->slotz[0]->fbmod; +            channel->slotz[1]->mod = &channel->chip->zeromod; +            channel->out[0] = &channel->slotz[0]->out; +            channel->out[1] = &channel->slotz[1]->out;              channel->out[2] = &channel->chip->zeromod;              channel->out[3] = &channel->chip->zeromod;              break; @@ -964,21 +964,21 @@ static void OPL3_ChannelKeyOn(opl3_channel *channel)      {          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); +            OPL3_EnvelopeKeyOn(channel->slotz[0], egk_norm); +            OPL3_EnvelopeKeyOn(channel->slotz[1], egk_norm); +            OPL3_EnvelopeKeyOn(channel->pair->slotz[0], egk_norm); +            OPL3_EnvelopeKeyOn(channel->pair->slotz[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); +            OPL3_EnvelopeKeyOn(channel->slotz[0], egk_norm); +            OPL3_EnvelopeKeyOn(channel->slotz[1], egk_norm);          }      }      else      { -        OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); -        OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); +        OPL3_EnvelopeKeyOn(channel->slotz[0], egk_norm); +        OPL3_EnvelopeKeyOn(channel->slotz[1], egk_norm);      }  } @@ -988,21 +988,21 @@ static void OPL3_ChannelKeyOff(opl3_channel *channel)      {          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); +            OPL3_EnvelopeKeyOff(channel->slotz[0], egk_norm); +            OPL3_EnvelopeKeyOff(channel->slotz[1], egk_norm); +            OPL3_EnvelopeKeyOff(channel->pair->slotz[0], egk_norm); +            OPL3_EnvelopeKeyOff(channel->pair->slotz[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); +            OPL3_EnvelopeKeyOff(channel->slotz[0], egk_norm); +            OPL3_EnvelopeKeyOff(channel->slotz[1], egk_norm);          }      }      else      { -        OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); -        OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); +        OPL3_EnvelopeKeyOff(channel->slotz[0], egk_norm); +        OPL3_EnvelopeKeyOff(channel->slotz[1], egk_norm);      }  } @@ -1147,7 +1147,7 @@ void OPL3_Generate(opl3_chip *chip, Bit16s *buf)      if (chip->eg_timerrem || chip->eg_state)      { -        if (chip->eg_timer == 0xfffffffff) +        if (chip->eg_timer == (uint64_t)0xfffffffffU)          {              chip->eg_timer = 0;              chip->eg_timerrem = 1; @@ -1209,8 +1209,8 @@ void OPL3_Reset(opl3_chip *chip, Bit32u samplerate)      }      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->channel[channum].slotz[0] = &chip->slot[ch_slot[channum]]; +        chip->channel[channum].slotz[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) diff --git a/src/chips/nuked/nukedopl3.h b/src/chips/nuked/nukedopl3.h index ce748b1..d57cf5f 100644 --- a/src/chips/nuked/nukedopl3.h +++ b/src/chips/nuked/nukedopl3.h @@ -86,7 +86,7 @@ struct _opl3_slot {  };  struct _opl3_channel { -    opl3_slot *slots[2]; +    opl3_slot *slotz[2];/*Don't use "slots" keyword to avoid conflict with Qt applications*/      opl3_channel *pair;      opl3_chip *chip;      Bit16s *out[4]; diff --git a/src/chips/nuked/nukedopl3_174.c b/src/chips/nuked/nukedopl3_174.c index 401089c..99eab16 100644 --- a/src/chips/nuked/nukedopl3_174.c +++ b/src/chips/nuked/nukedopl3_174.c @@ -638,18 +638,18 @@ static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data)          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[0] = &channel6->slotz[1]->out; +        channel6->out[1] = &channel6->slotz[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; +        channel7->out[0] = &channel7->slotz[0]->out; +        channel7->out[1] = &channel7->slotz[0]->out; +        channel7->out[2] = &channel7->slotz[1]->out; +        channel7->out[3] = &channel7->slotz[1]->out; +        channel8->out[0] = &channel8->slotz[0]->out; +        channel8->out[1] = &channel8->slotz[0]->out; +        channel8->out[2] = &channel8->slotz[1]->out; +        channel8->out[3] = &channel8->slotz[1]->out;          for (chnum = 6; chnum < 9; chnum++)          {              chip->channel[chnum].chtype = ch_drum; @@ -658,49 +658,49 @@ static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data)          /*hh*/          if (chip->rhy & 0x01)          { -            OPL3_EnvelopeKeyOn(channel7->slots[0], egk_drum); +            OPL3_EnvelopeKeyOn(channel7->slotz[0], egk_drum);          }          else          { -            OPL3_EnvelopeKeyOff(channel7->slots[0], egk_drum); +            OPL3_EnvelopeKeyOff(channel7->slotz[0], egk_drum);          }          /*tc*/          if (chip->rhy & 0x02)          { -            OPL3_EnvelopeKeyOn(channel8->slots[1], egk_drum); +            OPL3_EnvelopeKeyOn(channel8->slotz[1], egk_drum);          }          else          { -            OPL3_EnvelopeKeyOff(channel8->slots[1], egk_drum); +            OPL3_EnvelopeKeyOff(channel8->slotz[1], egk_drum);          }          /*tom*/          if (chip->rhy & 0x04)          { -            OPL3_EnvelopeKeyOn(channel8->slots[0], egk_drum); +            OPL3_EnvelopeKeyOn(channel8->slotz[0], egk_drum);          }          else          { -            OPL3_EnvelopeKeyOff(channel8->slots[0], egk_drum); +            OPL3_EnvelopeKeyOff(channel8->slotz[0], egk_drum);          }          /*sd*/          if (chip->rhy & 0x08)          { -            OPL3_EnvelopeKeyOn(channel7->slots[1], egk_drum); +            OPL3_EnvelopeKeyOn(channel7->slotz[1], egk_drum);          }          else          { -            OPL3_EnvelopeKeyOff(channel7->slots[1], egk_drum); +            OPL3_EnvelopeKeyOff(channel7->slotz[1], egk_drum);          }          /*bd*/          if (chip->rhy & 0x10)          { -            OPL3_EnvelopeKeyOn(channel6->slots[0], egk_drum); -            OPL3_EnvelopeKeyOn(channel6->slots[1], egk_drum); +            OPL3_EnvelopeKeyOn(channel6->slotz[0], egk_drum); +            OPL3_EnvelopeKeyOn(channel6->slotz[1], egk_drum);          }          else          { -            OPL3_EnvelopeKeyOff(channel6->slots[0], egk_drum); -            OPL3_EnvelopeKeyOff(channel6->slots[1], egk_drum); +            OPL3_EnvelopeKeyOff(channel6->slotz[0], egk_drum); +            OPL3_EnvelopeKeyOff(channel6->slotz[1], egk_drum);          }      }      else @@ -709,8 +709,8 @@ static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data)          {              chip->channel[chnum].chtype = ch_2op;              OPL3_ChannelSetupAlg(&chip->channel[chnum]); -            OPL3_EnvelopeKeyOff(chip->channel[chnum].slots[0], egk_drum); -            OPL3_EnvelopeKeyOff(chip->channel[chnum].slots[1], egk_drum); +            OPL3_EnvelopeKeyOff(chip->channel[chnum].slotz[0], egk_drum); +            OPL3_EnvelopeKeyOff(chip->channel[chnum].slotz[1], egk_drum);          }      }  } @@ -724,18 +724,18 @@ static void OPL3_ChannelWriteA0(opl3_channel *channel, Bit8u data)      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]); +    OPL3_EnvelopeUpdateKSL(channel->slotz[0]); +    OPL3_EnvelopeUpdateKSL(channel->slotz[1]); +    OPL3_EnvelopeUpdateRate(channel->slotz[0]); +    OPL3_EnvelopeUpdateRate(channel->slotz[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]); +        OPL3_EnvelopeUpdateKSL(channel->pair->slotz[0]); +        OPL3_EnvelopeUpdateKSL(channel->pair->slotz[1]); +        OPL3_EnvelopeUpdateRate(channel->pair->slotz[0]); +        OPL3_EnvelopeUpdateRate(channel->pair->slotz[1]);      }  } @@ -749,19 +749,19 @@ static void OPL3_ChannelWriteB0(opl3_channel *channel, Bit8u data)      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]); +    OPL3_EnvelopeUpdateKSL(channel->slotz[0]); +    OPL3_EnvelopeUpdateKSL(channel->slotz[1]); +    OPL3_EnvelopeUpdateRate(channel->slotz[0]); +    OPL3_EnvelopeUpdateRate(channel->slotz[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]); +        OPL3_EnvelopeUpdateKSL(channel->pair->slotz[0]); +        OPL3_EnvelopeUpdateKSL(channel->pair->slotz[1]); +        OPL3_EnvelopeUpdateRate(channel->pair->slotz[0]); +        OPL3_EnvelopeUpdateRate(channel->pair->slotz[1]);      }  } @@ -772,12 +772,12 @@ static void OPL3_ChannelSetupAlg(opl3_channel *channel)          switch (channel->alg & 0x01)          {          case 0x00: -            channel->slots[0]->mod = &channel->slots[0]->fbmod; -            channel->slots[1]->mod = &channel->slots[0]->out; +            channel->slotz[0]->mod = &channel->slotz[0]->fbmod; +            channel->slotz[1]->mod = &channel->slotz[0]->out;              break;          case 0x01: -            channel->slots[0]->mod = &channel->slots[0]->fbmod; -            channel->slots[1]->mod = &channel->chip->zeromod; +            channel->slotz[0]->mod = &channel->slotz[0]->fbmod; +            channel->slotz[1]->mod = &channel->chip->zeromod;              break;          }          return; @@ -795,43 +795,43 @@ static void OPL3_ChannelSetupAlg(opl3_channel *channel)          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->pair->slotz[0]->mod = &channel->pair->slotz[0]->fbmod; +            channel->pair->slotz[1]->mod = &channel->pair->slotz[0]->out; +            channel->slotz[0]->mod = &channel->pair->slotz[1]->out; +            channel->slotz[1]->mod = &channel->slotz[0]->out; +            channel->out[0] = &channel->slotz[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->pair->slotz[0]->mod = &channel->pair->slotz[0]->fbmod; +            channel->pair->slotz[1]->mod = &channel->pair->slotz[0]->out; +            channel->slotz[0]->mod = &channel->chip->zeromod; +            channel->slotz[1]->mod = &channel->slotz[0]->out; +            channel->out[0] = &channel->pair->slotz[1]->out; +            channel->out[1] = &channel->slotz[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->pair->slotz[0]->mod = &channel->pair->slotz[0]->fbmod; +            channel->pair->slotz[1]->mod = &channel->chip->zeromod; +            channel->slotz[0]->mod = &channel->pair->slotz[1]->out; +            channel->slotz[1]->mod = &channel->slotz[0]->out; +            channel->out[0] = &channel->pair->slotz[0]->out; +            channel->out[1] = &channel->slotz[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->pair->slotz[0]->mod = &channel->pair->slotz[0]->fbmod; +            channel->pair->slotz[1]->mod = &channel->chip->zeromod; +            channel->slotz[0]->mod = &channel->pair->slotz[1]->out; +            channel->slotz[1]->mod = &channel->chip->zeromod; +            channel->out[0] = &channel->pair->slotz[0]->out; +            channel->out[1] = &channel->slotz[0]->out; +            channel->out[2] = &channel->slotz[1]->out;              channel->out[3] = &channel->chip->zeromod;              break;          } @@ -841,18 +841,18 @@ static void OPL3_ChannelSetupAlg(opl3_channel *channel)          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->slotz[0]->mod = &channel->slotz[0]->fbmod; +            channel->slotz[1]->mod = &channel->slotz[0]->out; +            channel->out[0] = &channel->slotz[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->slotz[0]->mod = &channel->slotz[0]->fbmod; +            channel->slotz[1]->mod = &channel->chip->zeromod; +            channel->out[0] = &channel->slotz[0]->out; +            channel->out[1] = &channel->slotz[1]->out;              channel->out[2] = &channel->chip->zeromod;              channel->out[3] = &channel->chip->zeromod;              break; @@ -905,21 +905,21 @@ static void OPL3_ChannelKeyOn(opl3_channel *channel)      {          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); +            OPL3_EnvelopeKeyOn(channel->slotz[0], egk_norm); +            OPL3_EnvelopeKeyOn(channel->slotz[1], egk_norm); +            OPL3_EnvelopeKeyOn(channel->pair->slotz[0], egk_norm); +            OPL3_EnvelopeKeyOn(channel->pair->slotz[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); +            OPL3_EnvelopeKeyOn(channel->slotz[0], egk_norm); +            OPL3_EnvelopeKeyOn(channel->slotz[1], egk_norm);          }      }      else      { -        OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); -        OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); +        OPL3_EnvelopeKeyOn(channel->slotz[0], egk_norm); +        OPL3_EnvelopeKeyOn(channel->slotz[1], egk_norm);      }  } @@ -929,21 +929,21 @@ static void OPL3_ChannelKeyOff(opl3_channel *channel)      {          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); +            OPL3_EnvelopeKeyOff(channel->slotz[0], egk_norm); +            OPL3_EnvelopeKeyOff(channel->slotz[1], egk_norm); +            OPL3_EnvelopeKeyOff(channel->pair->slotz[0], egk_norm); +            OPL3_EnvelopeKeyOff(channel->pair->slotz[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); +            OPL3_EnvelopeKeyOff(channel->slotz[0], egk_norm); +            OPL3_EnvelopeKeyOff(channel->slotz[1], egk_norm);          }      }      else      { -        OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); -        OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); +        OPL3_EnvelopeKeyOff(channel->slotz[0], egk_norm); +        OPL3_EnvelopeKeyOff(channel->slotz[1], egk_norm);      }  } @@ -997,9 +997,9 @@ static void OPL3_GenerateRhythm1(opl3_chip *chip)      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; +    OPL3_SlotGenerate(channel6->slotz[0]); +    phase14 = (channel7->slotz[0]->pg_phase >> 9) & 0x3ff; +    phase17 = (channel8->slotz[1]->pg_phase >> 9) & 0x3ff;      phase = 0x00;      /*hh tc phase bit*/      phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) @@ -1007,9 +1007,9 @@ static void OPL3_GenerateRhythm1(opl3_chip *chip)      /*hh*/      phase = (phasebit << 9)            | (0x34 << ((phasebit ^ (chip->noise & 0x01)) << 1)); -    OPL3_SlotGeneratePhase(channel7->slots[0], phase); +    OPL3_SlotGeneratePhase(channel7->slotz[0], phase);      /*tt*/ -    OPL3_SlotGenerateZM(channel8->slots[0]); +    OPL3_SlotGenerateZM(channel8->slotz[0]);  }  static void OPL3_GenerateRhythm2(opl3_chip *chip) @@ -1025,19 +1025,19 @@ static void OPL3_GenerateRhythm2(opl3_chip *chip)      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; +    OPL3_SlotGenerate(channel6->slotz[1]); +    phase14 = (channel7->slotz[0]->pg_phase >> 9) & 0x3ff; +    phase17 = (channel8->slotz[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); +    OPL3_SlotGeneratePhase(channel7->slotz[1], phase);      /*tc*/      phase = 0x100 | (phasebit << 9); -    OPL3_SlotGeneratePhase(channel8->slots[1], phase); +    OPL3_SlotGeneratePhase(channel8->slotz[1], phase);  }  void OPL3v17_Generate(opl3_chip *chip, Bit16s *buf) @@ -1202,8 +1202,8 @@ void OPL3v17_Reset(opl3_chip *chip, Bit32u samplerate)      }      for (channum = 0; channum < 18; channum++)      { -        chip->channel[channum].slots[0] = &chip->chipslot[ch_slot[channum]]; -        chip->channel[channum].slots[1] = &chip->chipslot[ch_slot[channum] + 3]; +        chip->channel[channum].slotz[0] = &chip->chipslot[ch_slot[channum]]; +        chip->channel[channum].slotz[1] = &chip->chipslot[ch_slot[channum] + 3];          chip->chipslot[ch_slot[channum]].channel = &chip->channel[channum];          chip->chipslot[ch_slot[channum] + 3].channel = &chip->channel[channum];          if ((channum % 9) < 3) diff --git a/src/chips/nuked/nukedopl3_174.h b/src/chips/nuked/nukedopl3_174.h index 43e4a6e..240802f 100644 --- a/src/chips/nuked/nukedopl3_174.h +++ b/src/chips/nuked/nukedopl3_174.h @@ -91,7 +91,7 @@ struct _opl3_slot {  };  struct _opl3_channel { -    opl3_slot *slots[2]; +    opl3_slot *slotz[2];/*Don't use "slots" keyword to avoid conflict with Qt applications*/      opl3_channel *pair;      opl3_chip *chip;      Bit16s *out[4]; diff --git a/src/chips/nuked_opl3.cpp b/src/chips/nuked_opl3.cpp index 70fc525..48e5c17 100644 --- a/src/chips/nuked_opl3.cpp +++ b/src/chips/nuked_opl3.cpp @@ -3,18 +3,10 @@  #include <cstring>  NukedOPL3::NukedOPL3() : -    OPLChipBase() +    OPLChipBaseT()  {      m_chip = new opl3_chip; -    reset(m_rate); -} - -NukedOPL3::NukedOPL3(const NukedOPL3 &c): -    OPLChipBase(c) -{ -    m_chip = new opl3_chip; -    std::memset(m_chip, 0, sizeof(opl3_chip)); -    reset(c.m_rate); +    setRate(m_rate);  }  NukedOPL3::~NukedOPL3() @@ -25,7 +17,7 @@ NukedOPL3::~NukedOPL3()  void NukedOPL3::setRate(uint32_t rate)  { -    OPLChipBase::setRate(rate); +    OPLChipBaseT::setRate(rate);      opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);      std::memset(chip_r, 0, sizeof(opl3_chip));      OPL3_Reset(chip_r, rate); @@ -33,12 +25,10 @@ void NukedOPL3::setRate(uint32_t rate)  void NukedOPL3::reset()  { -    setRate(m_rate); -} - -void NukedOPL3::reset(uint32_t rate) -{ -    setRate(rate); +    OPLChipBaseT::reset(); +    opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); +    std::memset(chip_r, 0, sizeof(opl3_chip)); +    OPL3_Reset(chip_r, m_rate);  }  void NukedOPL3::writeReg(uint16_t addr, uint8_t data) @@ -47,44 +37,10 @@ void NukedOPL3::writeReg(uint16_t addr, uint8_t data)      OPL3_WriteRegBuffered(chip_r, addr, data);  } -int NukedOPL3::generate(int16_t *output, size_t frames) -{ -    opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); -    OPL3_GenerateStream(chip_r, output, (Bit32u)frames); -    return (int)frames; -} - -int NukedOPL3::generateAndMix(int16_t *output, size_t frames) -{ -    opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); -    OPL3_GenerateStreamMix(chip_r, output, (Bit32u)frames); -    return (int)frames; -} - -int NukedOPL3::generate32(int32_t *output, size_t frames) -{ -    opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); -    for(size_t i = 0; i < frames; ++i) { -        int16_t frame[2]; -        OPL3_GenerateResampled(chip_r, frame); -        output[0] = (int32_t)frame[0]; -        output[1] = (int32_t)frame[1]; -        output += 2; -    } -    return (int)frames; -} - -int NukedOPL3::generateAndMix32(int32_t *output, size_t frames) +void NukedOPL3::nativeGenerate(int16_t *frame)  {      opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); -    for(size_t i = 0; i < frames; ++i) { -        int16_t frame[2]; -        OPL3_GenerateResampled(chip_r, frame); -        output[0] += (int32_t)frame[0]; -        output[1] += (int32_t)frame[1]; -        output += 2; -    } -    return (int)frames; +    OPL3_Generate(chip_r, frame);  }  const char *NukedOPL3::emulatorName() diff --git a/src/chips/nuked_opl3.h b/src/chips/nuked_opl3.h index ceb1dfd..25d9ed5 100644 --- a/src/chips/nuked_opl3.h +++ b/src/chips/nuked_opl3.h @@ -3,23 +3,20 @@  #include "opl_chip_base.h" -class NukedOPL3 final : public OPLChipBase +class NukedOPL3 final : public OPLChipBaseT<NukedOPL3>  {      void *m_chip;  public:      NukedOPL3(); -    NukedOPL3(const NukedOPL3 &c); -    virtual ~NukedOPL3() override; +    ~NukedOPL3() override; -    virtual void setRate(uint32_t rate) override; -    virtual void reset() override; -    virtual void reset(uint32_t rate) override; -    virtual void writeReg(uint16_t addr, uint8_t data) override; -    virtual int generate(int16_t *output, size_t frames) override; -    virtual int generateAndMix(int16_t *output, size_t frames) override; -    virtual int generate32(int32_t *output, size_t frames) override; -    virtual int generateAndMix32(int32_t *output, size_t frames) override; -    virtual const char *emulatorName() override; +    void setRate(uint32_t rate) override; +    void reset() override; +    void writeReg(uint16_t addr, uint8_t data) override; +    void nativePreGenerate() override {} +    void nativePostGenerate() override {} +    void nativeGenerate(int16_t *frame) override; +    const char *emulatorName() override;  };  #endif // NUKED_OPL3_H diff --git a/src/chips/nuked_opl3_v174.cpp b/src/chips/nuked_opl3_v174.cpp index 0dcf925..e24b2e7 100644 --- a/src/chips/nuked_opl3_v174.cpp +++ b/src/chips/nuked_opl3_v174.cpp @@ -3,18 +3,10 @@  #include <cstring>  NukedOPL3v174::NukedOPL3v174() : -    OPLChipBase() +    OPLChipBaseT()  {      m_chip = new opl3_chip; -    reset(m_rate); -} - -NukedOPL3v174::NukedOPL3v174(const NukedOPL3v174 &c): -    OPLChipBase(c) -{ -    m_chip = new opl3_chip; -    std::memset(m_chip, 0, sizeof(opl3_chip)); -    reset(c.m_rate); +    setRate(m_rate);  }  NukedOPL3v174::~NukedOPL3v174() @@ -25,7 +17,7 @@ NukedOPL3v174::~NukedOPL3v174()  void NukedOPL3v174::setRate(uint32_t rate)  { -    OPLChipBase::setRate(rate); +    OPLChipBaseT::setRate(rate);      opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);      std::memset(chip_r, 0, sizeof(opl3_chip));      OPL3v17_Reset(chip_r, rate); @@ -33,12 +25,10 @@ void NukedOPL3v174::setRate(uint32_t rate)  void NukedOPL3v174::reset()  { -    setRate(m_rate); -} - -void NukedOPL3v174::reset(uint32_t rate) -{ -    setRate(rate); +    OPLChipBaseT::reset(); +    opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); +    std::memset(chip_r, 0, sizeof(opl3_chip)); +    OPL3v17_Reset(chip_r, m_rate);  }  void NukedOPL3v174::writeReg(uint16_t addr, uint8_t data) @@ -47,44 +37,10 @@ void NukedOPL3v174::writeReg(uint16_t addr, uint8_t data)      OPL3v17_WriteReg(chip_r, addr, data);  } -int NukedOPL3v174::generate(int16_t *output, size_t frames) -{ -    opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); -    OPL3v17_GenerateStream(chip_r, output, (Bit32u)frames); -    return (int)frames; -} - -int NukedOPL3v174::generateAndMix(int16_t *output, size_t frames) -{ -    opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); -    OPL3v17_GenerateStreamMix(chip_r, output, (Bit32u)frames); -    return (int)frames; -} - -int NukedOPL3v174::generate32(int32_t *output, size_t frames) -{ -    opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); -    for(size_t i = 0; i < frames; ++i) { -        int16_t frame[2]; -        OPL3v17_GenerateResampled(chip_r, frame); -        output[0] = (int32_t)frame[0]; -        output[1] = (int32_t)frame[1]; -        output += 2; -    } -    return (int)frames; -} - -int NukedOPL3v174::generateAndMix32(int32_t *output, size_t frames) +void NukedOPL3v174::nativeGenerate(int16_t *frame)  {      opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip); -    for(size_t i = 0; i < frames; ++i) { -        int16_t frame[2]; -        OPL3v17_GenerateResampled(chip_r, frame); -        output[0] += (int32_t)frame[0]; -        output[1] += (int32_t)frame[1]; -        output += 2; -    } -    return (int)frames; +    OPL3v17_Generate(chip_r, frame);  }  const char *NukedOPL3v174::emulatorName() diff --git a/src/chips/nuked_opl3_v174.h b/src/chips/nuked_opl3_v174.h index acbdcca..b9c5ba6 100644 --- a/src/chips/nuked_opl3_v174.h +++ b/src/chips/nuked_opl3_v174.h @@ -3,23 +3,20 @@  #include "opl_chip_base.h" -class NukedOPL3v174 final : public OPLChipBase +class NukedOPL3v174 final : public OPLChipBaseT<NukedOPL3v174>  {      void *m_chip;  public:      NukedOPL3v174(); -    NukedOPL3v174(const NukedOPL3v174 &c); -    virtual ~NukedOPL3v174() override; +    ~NukedOPL3v174() override; -    virtual void setRate(uint32_t rate) override; -    virtual void reset() override; -    virtual void reset(uint32_t rate) override; -    virtual void writeReg(uint16_t addr, uint8_t data) override; -    virtual int generate(int16_t *output, size_t frames) override; -    virtual int generateAndMix(int16_t *output, size_t frames) override; -    virtual int generate32(int32_t *output, size_t frames) override; -    virtual int generateAndMix32(int32_t *output, size_t frames) override; -    virtual const char *emulatorName() override; +    void setRate(uint32_t rate) override; +    void reset() override; +    void writeReg(uint16_t addr, uint8_t data) override; +    void nativePreGenerate() override {} +    void nativePostGenerate() override {} +    void nativeGenerate(int16_t *frame) override; +    const char *emulatorName() override;  };  #endif // NUKED_OPL3174_H diff --git a/src/chips/opl_chip_base.cpp b/src/chips/opl_chip_base.cpp deleted file mode 100644 index 670a998..0000000 --- a/src/chips/opl_chip_base.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "opl_chip_base.h" - -OPLChipBase::OPLChipBase() : -    m_rate(44100) -{} - -OPLChipBase::OPLChipBase(const OPLChipBase &c): -    m_rate(c.m_rate) -{} - -OPLChipBase::~OPLChipBase() -{} - -void OPLChipBase::setRate(uint32_t rate) -{ -    m_rate = rate; -} - -void OPLChipBase::reset(uint32_t rate) -{ -    setRate(rate); -} - -int OPLChipBase::generate32(int32_t *output, size_t frames) -{ -    enum { maxFramesAtOnce = 256 }; -    int16_t temp[2 * maxFramesAtOnce]; -    for(size_t left = frames; left > 0;) { -        size_t count = (left < static_cast<size_t>(maxFramesAtOnce)) ? left : static_cast<size_t>(maxFramesAtOnce); -        generate(temp, count); -        for(size_t i = 0; i < 2 * count; ++i) -            output[i] = temp[i]; -        left -= count; -        output += 2 * count; -    } -    return (int)frames; -} - -int OPLChipBase::generateAndMix32(int32_t *output, size_t frames) -{ -    enum { maxFramesAtOnce = 256 }; -    int16_t temp[2 * maxFramesAtOnce]; -    for(size_t left = frames; left > 0;) { -        size_t count = (left < static_cast<size_t>(maxFramesAtOnce)) ? left : static_cast<size_t>(maxFramesAtOnce); -        generate(temp, count); -        for(size_t i = 0; i < 2 * count; ++i) -            output[i] += temp[i]; -        left -= count; -        output += 2 * count; -    } -    return (int)frames; -} diff --git a/src/chips/opl_chip_base.h b/src/chips/opl_chip_base.h index fb9b9e9..5721a81 100644 --- a/src/chips/opl_chip_base.h +++ b/src/chips/opl_chip_base.h @@ -9,24 +9,91 @@  #define override  #endif +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) +class VResampler; +#endif +  class OPLChipBase  {  protected:      uint32_t m_rate;  public:      OPLChipBase(); -    OPLChipBase(const OPLChipBase &c);      virtual ~OPLChipBase(); -    virtual void setRate(uint32_t rate); +    virtual void setRate(uint32_t rate) = 0;      virtual void reset() = 0; -    virtual void reset(uint32_t rate);      virtual void writeReg(uint16_t addr, uint8_t data) = 0; -    virtual int generate(int16_t *output, size_t frames) = 0; -    virtual int generateAndMix(int16_t *output, size_t frames) = 0; -    virtual int generate32(int32_t *output, size_t frames); -    virtual int generateAndMix32(int32_t *output, size_t frames); + +    virtual void nativePreGenerate() = 0; +    virtual void nativePostGenerate() = 0; +    virtual void nativeGenerate(int16_t *frame) = 0; + +    virtual void generate(int16_t *output, size_t frames) = 0; +    virtual void generateAndMix(int16_t *output, size_t frames) = 0; +    virtual void generate32(int32_t *output, size_t frames) = 0; +    virtual void generateAndMix32(int32_t *output, size_t frames) = 0; +      virtual const char* emulatorName() = 0; +private: +    OPLChipBase(const OPLChipBase &c); +    OPLChipBase &operator=(const OPLChipBase &c); +}; + +// A base class providing F-bounded generic and efficient implementations, +// supporting resampling of chip outputs +template <class T> +class OPLChipBaseT : public OPLChipBase +{ +public: +    OPLChipBaseT(); +    virtual ~OPLChipBaseT(); + +    virtual void setRate(uint32_t rate) override; +    virtual void reset() override; +    void generate(int16_t *output, size_t frames) override; +    void generateAndMix(int16_t *output, size_t frames) override; +    void generate32(int32_t *output, size_t frames) override; +    void generateAndMix32(int32_t *output, size_t frames) override; +private: +    void setupResampler(uint32_t rate); +    void resetResampler(); +    void resampledGenerate(int32_t *output); +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) +    VResampler *m_resampler; +#else +    int32_t m_oldsamples[2]; +    int32_t m_samples[2]; +    int32_t m_samplecnt; +    int32_t m_rateratio; +    enum { rsm_frac = 10 }; +#endif +    // amplitude scale factors in and out of resampler, varying for chips; +    // values are OK to "redefine", the static polymorphism will accept it. +    enum { resamplerPreAmplify = 1, resamplerPostAttenuate = 1 }; +}; + +// A base class which provides frame-by-frame interfaces on emulations which +// don't have a routine for it. It produces outputs in fixed size buffers. +// Fast register updates will suffer some latency because of buffering. +template <class T, unsigned Buffer = 256> +class OPLChipBaseBufferedT : public OPLChipBaseT<T> +{ +public: +    OPLChipBaseBufferedT() +        : OPLChipBaseT<T>(), m_bufferIndex(0) {} +    virtual ~OPLChipBaseBufferedT() +        {} +public: +    void reset() override; +    void nativeGenerate(int16_t *frame) override; +protected: +    virtual void nativeGenerateN(int16_t *output, size_t frames) = 0; +private: +    unsigned m_bufferIndex; +    int16_t m_buffer[2 * Buffer];  }; +#include "opl_chip_base.tcc" +  #endif // ONP_CHIP_BASE_H diff --git a/src/chips/opl_chip_base.tcc b/src/chips/opl_chip_base.tcc new file mode 100644 index 0000000..58145bc --- /dev/null +++ b/src/chips/opl_chip_base.tcc @@ -0,0 +1,216 @@ +#include "opl_chip_base.h" +#include <cmath> + +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) +#include <zita-resampler/vresampler.h> +#endif + +/* OPLChipBase */ + +inline OPLChipBase::OPLChipBase() : +    m_rate(44100) +{ +} + +inline OPLChipBase::~OPLChipBase() +{ +} + +/* OPLChipBaseT */ + +template <class T> +OPLChipBaseT<T>::OPLChipBaseT() +    : OPLChipBase() +{ +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) +    m_resampler = new VResampler; +#endif +    setupResampler(m_rate); +} + +template <class T> +OPLChipBaseT<T>::~OPLChipBaseT() +{ +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) +    delete m_resampler; +#endif +} + +template <class T> +void OPLChipBaseT<T>::setRate(uint32_t rate) +{ +    uint32_t oldRate = m_rate; +    m_rate = rate; +    if(rate != oldRate) +        setupResampler(rate); +    else +        resetResampler(); +} + +template <class T> +void OPLChipBaseT<T>::reset() +{ +    resetResampler(); +} + +template <class T> +void OPLChipBaseT<T>::generate(int16_t *output, size_t frames) +{ +    static_cast<T *>(this)->nativePreGenerate(); +    for(size_t i = 0; i < frames; ++i) +    { +        int32_t frame[2]; +        static_cast<T *>(this)->resampledGenerate(frame); +        for (unsigned c = 0; c < 2; ++c) { +            int32_t temp = frame[c]; +            temp = (temp > -32768) ? temp : -32768; +            temp = (temp < 32767) ? temp : 32767; +            output[c] = (int16_t)temp; +        } +        output += 2; +    } +    static_cast<T *>(this)->nativePostGenerate(); +} + +template <class T> +void OPLChipBaseT<T>::generateAndMix(int16_t *output, size_t frames) +{ +    static_cast<T *>(this)->nativePreGenerate(); +    for(size_t i = 0; i < frames; ++i) +    { +        int32_t frame[2]; +        static_cast<T *>(this)->resampledGenerate(frame); +        for (unsigned c = 0; c < 2; ++c) { +            int32_t temp = (int32_t)output[c] + frame[c]; +            temp = (temp > -32768) ? temp : -32768; +            temp = (temp < 32767) ? temp : 32767; +            output[c] = (int16_t)temp; +        } +        output += 2; +    } +    static_cast<T *>(this)->nativePostGenerate(); +} + +template <class T> +void OPLChipBaseT<T>::generate32(int32_t *output, size_t frames) +{ +    static_cast<T *>(this)->nativePreGenerate(); +    for(size_t i = 0; i < frames; ++i) +    { +        static_cast<T *>(this)->resampledGenerate(output); +        output += 2; +    } +    static_cast<T *>(this)->nativePostGenerate(); +} + +template <class T> +void OPLChipBaseT<T>::generateAndMix32(int32_t *output, size_t frames) +{ +    static_cast<T *>(this)->nativePreGenerate(); +    for(size_t i = 0; i < frames; ++i) +    { +        int32_t frame[2]; +        static_cast<T *>(this)->resampledGenerate(frame); +        output[0] += frame[0]; +        output[1] += frame[1]; +        output += 2; +    } +    static_cast<T *>(this)->nativePostGenerate(); +} + +template <class T> +void OPLChipBaseT<T>::setupResampler(uint32_t rate) +{ +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) +    m_resampler->setup(rate * (1.0 / 49716), 2, 48); +#else +    m_oldsamples[0] = m_oldsamples[1] = 0; +    m_samples[0] = m_samples[1] = 0; +    m_samplecnt = 0; +    m_rateratio = (int32_t)((rate << rsm_frac) / 49716); +#endif +} + +template <class T> +void OPLChipBaseT<T>::resetResampler() +{ +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) +    m_resampler->reset(); +#else +    m_oldsamples[0] = m_oldsamples[1] = 0; +    m_samples[0] = m_samples[1] = 0; +    m_samplecnt = 0; +#endif +} + +#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) +template <class T> +void OPLChipBaseT<T>::resampledGenerate(int32_t *output) +{ +    VResampler *rsm = m_resampler; +    float scale = (float)T::resamplerPreAmplify / +        (float)T::resamplerPostAttenuate; +    float f_in[2]; +    float f_out[2]; +    rsm->inp_count = 0; +    rsm->inp_data = f_in; +    rsm->out_count = 1; +    rsm->out_data = f_out; +    while(rsm->process(), rsm->out_count != 0) +    { +        int16_t in[2]; +        static_cast<T *>(this)->nativeGenerate(in); +        f_in[0] = scale * (float)in[0]; +        f_in[1] = scale * (float)in[1]; +        rsm->inp_count = 1; +        rsm->inp_data = f_in; +        rsm->out_count = 1; +        rsm->out_data = f_out; +    } +    output[0] = std::lround(f_out[0]); +    output[1] = std::lround(f_out[1]); +} +#else +template <class T> +void OPLChipBaseT<T>::resampledGenerate(int32_t *output) +{ +    int32_t samplecnt = m_samplecnt; +    const int32_t rateratio = m_rateratio; +    while(samplecnt >= rateratio) +    { +        m_oldsamples[0] = m_samples[0]; +        m_oldsamples[1] = m_samples[1]; +        int16_t buffer[2]; +        static_cast<T *>(this)->nativeGenerate(buffer); +        m_samples[0] = buffer[0] * T::resamplerPreAmplify; +        m_samples[1] = buffer[1] * T::resamplerPreAmplify; +        samplecnt -= rateratio; +    } +    output[0] = (int32_t)(((m_oldsamples[0] * (rateratio - samplecnt) +                            + m_samples[0] * samplecnt) / rateratio)/T::resamplerPostAttenuate); +    output[1] = (int32_t)(((m_oldsamples[1] * (rateratio - samplecnt) +                            + m_samples[1] * samplecnt) / rateratio)/T::resamplerPostAttenuate); +    m_samplecnt = samplecnt + (1 << rsm_frac); +} +#endif + +/* OPLChipBaseBufferedT */ + +template <class T, unsigned Buffer> +void OPLChipBaseBufferedT<T, Buffer>::reset() +{ +    OPLChipBaseT<T>::reset(); +    m_bufferIndex = 0; +} + +template <class T, unsigned Buffer> +void OPLChipBaseBufferedT<T, Buffer>::nativeGenerate(int16_t *frame) +{ +    unsigned bufferIndex = m_bufferIndex; +    if(bufferIndex == 0) +        static_cast<T *>(this)->nativeGenerateN(m_buffer, Buffer); +    frame[0] = m_buffer[2 * bufferIndex]; +    frame[1] = m_buffer[2 * bufferIndex + 1]; +    bufferIndex = (bufferIndex + 1 < Buffer) ? (bufferIndex + 1) : 0; +    m_bufferIndex = bufferIndex; +}  |