ref: 36f721637c5e5ac85671eb438ab9e6831933138c
parent: 77a480fcbf908bd39192b64af00487b6831a2d7b
parent: e3954613bd4365cac43dd6f7b89ef73e82c56936
author: Simon Howard <[email protected]>
date: Sun Feb 28 08:27:56 EST 2016
Merge remote-tracking branch 'origin/master' into sdl2-branch
--- a/msvc/libopl.vcproj
+++ b/msvc/libopl.vcproj
@@ -159,10 +159,6 @@
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
- RelativePath="..\opl\dbopl.c"
- >
- </File>
- <File
RelativePath="..\opl\ioperm_sys.c"
>
</File>
@@ -194,6 +190,10 @@
RelativePath="..\opl\opl_win32.c"
>
</File>
+ <File
+ RelativePath="..\opl\opl3.c"
+ >
+ </File>
</Filter>
<Filter
Name="Header Files"
@@ -222,6 +222,10 @@
</File>
<File
RelativePath="..\opl\opl_timer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\opl\opl3.h"
>
</File>
</Filter>
--- a/opl/Makefile.am
+++ b/opl/Makefile.am
@@ -15,5 +15,5 @@
opl_timer.c opl_timer.h \
opl_win32.c \
ioperm_sys.c ioperm_sys.h \
- dbopl.c dbopl.h
+ opl3.c opl3.h
--- a/opl/dbopl.c
+++ /dev/null
@@ -1,1638 +1,0 @@
-/*
- * Copyright (C) 2002-2010 The DOSBox Team
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-//
-// Chocolate Doom-related discussion:
-//
-// This is the DosBox OPL emulator code (src/hardware/dbopl.cpp) r3635,
-// converted to C. The bulk of the work was done using the minus-minus
-// script in the Chocolate Doom SVN repository, then the result tweaked
-// by hand until working.
-//
-
-
-/*
- 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>
-#include <stdlib.h>
-#include <string.h>
-//#include "dosbox.h"
-#include "dbopl.h"
-
-
-#define GCC_UNLIKELY(x) x
-
-#define TRUE 1
-#define FALSE 0
-
-#ifndef PI
-#define PI 3.14159265358979323846
-#endif
-
-#define OPLRATE ((double)(14318180.0 / 288.0))
-#define TREMOLO_TABLE 52
-
-//Try to use most precision for frequencies
-//Else try to keep different waves in synch
-//#define WAVE_PRECISION 1
-#ifndef WAVE_PRECISION
-//Wave bits available in the top of the 32bit range
-//Original adlib uses 10.10, we use 10.22
-#define WAVE_BITS 10
-#else
-//Need some extra bits at the top to have room for octaves and frequency multiplier
-//We support to 8 times lower rate
-//128 * 15 * 8 = 15350, 2^13.9, so need 14 bits
-#define WAVE_BITS 14
-#endif
-#define WAVE_SH ( 32 - WAVE_BITS )
-#define WAVE_MASK ( ( 1 << WAVE_SH ) - 1 )
-
-//Use the same accuracy as the waves
-#define LFO_SH ( WAVE_SH - 10 )
-//LFO is controlled by our tremolo 256 sample limit
-#define LFO_MAX ( 256 << ( LFO_SH ) )
-
-
-//Maximum amount of attenuation bits
-//Envelope goes to 511, 9 bits
-#if (DBOPL_WAVE == WAVE_TABLEMUL )
-//Uses the value directly
-#define ENV_BITS ( 9 )
-#else
-//Add 3 bits here for more accuracy and would have to be shifted up either way
-#define ENV_BITS ( 9 )
-#endif
-//Limits of the envelope with those bits and when the envelope goes silent
-#define ENV_MIN 0
-#define ENV_EXTRA ( ENV_BITS - 9 )
-#define ENV_MAX ( 511 << ENV_EXTRA )
-#define ENV_LIMIT ( ( 12 * 256) >> ( 3 - ENV_EXTRA ) )
-#define ENV_SILENT( _X_ ) ( (_X_) >= ENV_LIMIT )
-
-//Attack/decay/release rate counter shift
-#define RATE_SH 24
-#define RATE_MASK ( ( 1 << RATE_SH ) - 1 )
-//Has to fit within 16bit lookuptable
-#define MUL_SH 16
-
-//Check some ranges
-#if ENV_EXTRA > 3
-#error Too many envelope bits
-#endif
-
-static inline void Operator__SetState(Operator *self, Bit8u s );
-static inline Bit32u Chip__ForwardNoise(Chip *self);
-
-// C++'s template<> sure is useful sometimes.
-
-static Channel* Channel__BlockTemplate(Channel *self, Chip* chip,
- Bit32u samples, Bit32s* output,
- SynthMode mode );
-#define BLOCK_TEMPLATE(mode) \
- static Channel* Channel__BlockTemplate_ ## mode(Channel *self, Chip* chip, \
- Bit32u samples, Bit32s* output) \
- { \
- return Channel__BlockTemplate(self, chip, samples, output, mode); \
- }
-
-BLOCK_TEMPLATE(sm2AM)
-BLOCK_TEMPLATE(sm2FM)
-BLOCK_TEMPLATE(sm3AM)
-BLOCK_TEMPLATE(sm3FM)
-BLOCK_TEMPLATE(sm3FMFM)
-BLOCK_TEMPLATE(sm3AMFM)
-BLOCK_TEMPLATE(sm3FMAM)
-BLOCK_TEMPLATE(sm3AMAM)
-BLOCK_TEMPLATE(sm2Percussion)
-BLOCK_TEMPLATE(sm3Percussion)
-
-//How much to substract from the base value for the final attenuation
-static const Bit8u KslCreateTable[16] = {
- //0 will always be be lower than 7 * 8
- 64, 32, 24, 19,
- 16, 12, 11, 10,
- 8, 6, 5, 4,
- 3, 2, 1, 0,
-};
-
-#define M(_X_) ((Bit8u)( (_X_) * 2))
-static const Bit8u FreqCreateTable[16] = {
- M(0.5), M(1 ), M(2 ), M(3 ), M(4 ), M(5 ), M(6 ), M(7 ),
- M(8 ), M(9 ), M(10), M(10), M(12), M(12), M(15), M(15)
-};
-#undef M
-
-//We're not including the highest attack rate, that gets a special value
-static const Bit8u AttackSamplesTable[13] = {
- 69, 55, 46, 40,
- 35, 29, 23, 20,
- 19, 15, 11, 10,
- 9
-};
-//On a real opl these values take 8 samples to reach and are based upon larger tables
-static const Bit8u EnvelopeIncreaseTable[13] = {
- 4, 5, 6, 7,
- 8, 10, 12, 14,
- 16, 20, 24, 28,
- 32,
-};
-
-#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG )
-static Bit16u ExpTable[ 256 ];
-#endif
-
-#if ( DBOPL_WAVE == WAVE_HANDLER )
-//PI table used by WAVEHANDLER
-static Bit16u SinTable[ 512 ];
-#endif
-
-#if ( DBOPL_WAVE > WAVE_HANDLER )
-//Layout of the waveform table in 512 entry intervals
-//With overlapping waves we reduce the table to half it's size
-
-// | |//\\|____|WAV7|//__|/\ |____|/\/\|
-// |\\//| | |WAV7| | \/| | |
-// |06 |0126|17 |7 |3 |4 |4 5 |5 |
-
-//6 is just 0 shifted and masked
-
-static Bit16s WaveTable[ 8 * 512 ];
-//Distance into WaveTable the wave starts
-static const Bit16u WaveBaseTable[8] = {
- 0x000, 0x200, 0x200, 0x800,
- 0xa00, 0xc00, 0x100, 0x400,
-
-};
-//Mask the counter with this
-static const Bit16u WaveMaskTable[8] = {
- 1023, 1023, 511, 511,
- 1023, 1023, 512, 1023,
-};
-
-//Where to start the counter on at keyon
-static const Bit16u WaveStartTable[8] = {
- 512, 0, 0, 0,
- 0, 512, 512, 256,
-};
-#endif
-
-#if ( DBOPL_WAVE == WAVE_TABLEMUL )
-static Bit16u MulTable[ 384 ];
-#endif
-
-static Bit8u KslTable[ 8 * 16 ];
-static Bit8u TremoloTable[ TREMOLO_TABLE ];
-//Start of a channel behind the chip struct start
-static Bit16u ChanOffsetTable[32];
-//Start of an operator behind the chip struct start
-static Bit16u OpOffsetTable[64];
-
-//The lower bits are the shift of the operator vibrato value
-//The highest bit is right shifted to generate -1 or 0 for negation
-//So taking the highest input value of 7 this gives 3, 7, 3, 0, -3, -7, -3, 0
-static const Bit8s VibratoTable[ 8 ] = {
- 1 - 0x00, 0 - 0x00, 1 - 0x00, 30 - 0x00,
- 1 - 0x80, 0 - 0x80, 1 - 0x80, 30 - 0x80
-};
-
-//Shift strength for the ksl value determined by ksl strength
-static const Bit8u KslShiftTable[4] = {
- 31,1,2,0
-};
-
-//Generate a table index and table shift value using input value from a selected rate
-static void EnvelopeSelect( Bit8u val, Bit8u *index, Bit8u *shift ) {
- if ( val < 13 * 4 ) { //Rate 0 - 12
- *shift = 12 - ( val >> 2 );
- *index = val & 3;
- } else if ( val < 15 * 4 ) { //rate 13 - 14
- *shift = 0;
- *index = val - 12 * 4;
- } else { //rate 15 and up
- *shift = 0;
- *index = 12;
- }
-}
-
-#if ( DBOPL_WAVE == WAVE_HANDLER )
-/*
- Generate the different waveforms out of the sine/exponetial table using handlers
-*/
-static inline Bits MakeVolume( Bitu wave, Bitu volume ) {
- Bitu total = wave + volume;
- Bitu index = total & 0xff;
- Bitu sig = ExpTable[ index ];
- Bitu exp = total >> 8;
-#if 0
- //Check if we overflow the 31 shift limit
- if ( exp >= 32 ) {
- LOG_MSG( "WTF %d %d", total, exp );
- }
-#endif
- return (sig >> exp);
-};
-
-static Bits DB_FASTCALL WaveForm0( Bitu i, Bitu volume ) {
- Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0
- Bitu wave = SinTable[i & 511];
- return (MakeVolume( wave, volume ) ^ neg) - neg;
-}
-static Bits DB_FASTCALL WaveForm1( Bitu i, Bitu volume ) {
- Bit32u wave = SinTable[i & 511];
- wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 );
- return MakeVolume( wave, volume );
-}
-static Bits DB_FASTCALL WaveForm2( Bitu i, Bitu volume ) {
- Bitu wave = SinTable[i & 511];
- return MakeVolume( wave, volume );
-}
-static Bits DB_FASTCALL WaveForm3( Bitu i, Bitu volume ) {
- Bitu wave = SinTable[i & 255];
- wave |= ( ( (i ^ 256 ) & 256) - 1) >> ( 32 - 12 );
- return MakeVolume( wave, volume );
-}
-static Bits DB_FASTCALL WaveForm4( Bitu i, Bitu volume ) {
- //Twice as fast
- i <<= 1;
- Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0
- Bitu wave = SinTable[i & 511];
- wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 );
- return (MakeVolume( wave, volume ) ^ neg) - neg;
-}
-static Bits DB_FASTCALL WaveForm5( Bitu i, Bitu volume ) {
- //Twice as fast
- i <<= 1;
- Bitu wave = SinTable[i & 511];
- wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 );
- return MakeVolume( wave, volume );
-}
-static Bits DB_FASTCALL WaveForm6( Bitu i, Bitu volume ) {
- Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0
- return (MakeVolume( 0, volume ) ^ neg) - neg;
-}
-static Bits DB_FASTCALL WaveForm7( Bitu i, Bitu volume ) {
- //Negative is reversed here
- Bits neg = (( i >> 9) & 1) - 1;
- Bitu wave = (i << 3);
- //When negative the volume also runs backwards
- wave = ((wave ^ neg) - neg) & 4095;
- return (MakeVolume( wave, volume ) ^ neg) - neg;
-}
-
-static const WaveHandler WaveHandlerTable[8] = {
- WaveForm0, WaveForm1, WaveForm2, WaveForm3,
- WaveForm4, WaveForm5, WaveForm6, WaveForm7
-};
-
-#endif
-
-/*
- Operator
-*/
-
-//We zero out when rate == 0
-static inline void Operator__UpdateAttack(Operator *self, const Chip* chip ) {
- Bit8u rate = self->reg60 >> 4;
- if ( rate ) {
- Bit8u val = (rate << 2) + self->ksr;
- self->attackAdd = chip->attackRates[ val ];
- self->rateZero &= ~(1 << ATTACK);
- } else {
- self->attackAdd = 0;
- self->rateZero |= (1 << ATTACK);
- }
-}
-static inline void Operator__UpdateDecay(Operator *self, const Chip* chip ) {
- Bit8u rate = self->reg60 & 0xf;
- if ( rate ) {
- Bit8u val = (rate << 2) + self->ksr;
- self->decayAdd = chip->linearRates[ val ];
- self->rateZero &= ~(1 << DECAY);
- } else {
- self->decayAdd = 0;
- self->rateZero |= (1 << DECAY);
- }
-}
-static inline void Operator__UpdateRelease(Operator *self, const Chip* chip ) {
- Bit8u rate = self->reg80 & 0xf;
- if ( rate ) {
- Bit8u val = (rate << 2) + self->ksr;
- self->releaseAdd = chip->linearRates[ val ];
- self->rateZero &= ~(1 << RELEASE);
- if ( !(self->reg20 & MASK_SUSTAIN ) ) {
- self->rateZero &= ~( 1 << SUSTAIN );
- }
- } else {
- self->rateZero |= (1 << RELEASE);
- self->releaseAdd = 0;
- if ( !(self->reg20 & MASK_SUSTAIN ) ) {
- self->rateZero |= ( 1 << SUSTAIN );
- }
- }
-}
-
-static inline void Operator__UpdateAttenuation(Operator *self) {
- Bit8u kslBase = (Bit8u)((self->chanData >> SHIFT_KSLBASE) & 0xff);
- Bit32u tl = self->reg40 & 0x3f;
- Bit8u kslShift = KslShiftTable[ self->reg40 >> 6 ];
- //Make sure the attenuation goes to the right bits
- self->totalLevel = tl << ( ENV_BITS - 7 ); //Total level goes 2 bits below max
- self->totalLevel += ( kslBase << ENV_EXTRA ) >> kslShift;
-}
-
-static void Operator__UpdateFrequency(Operator *self) {
- Bit32u freq = self->chanData & (( 1 << 10 ) - 1);
- Bit32u block = (self->chanData >> 10) & 0xff;
-#ifdef WAVE_PRECISION
- block = 7 - block;
- self->waveAdd = ( freq * self->freqMul ) >> block;
-#else
- self->waveAdd = ( freq << block ) * self->freqMul;
-#endif
- if ( self->reg20 & MASK_VIBRATO ) {
- self->vibStrength = (Bit8u)(freq >> 7);
-
-#ifdef WAVE_PRECISION
- self->vibrato = ( self->vibStrength * self->freqMul ) >> block;
-#else
- self->vibrato = ( self->vibStrength << block ) * self->freqMul;
-#endif
- } else {
- self->vibStrength = 0;
- self->vibrato = 0;
- }
-}
-
-static void Operator__UpdateRates(Operator *self, const Chip* chip ) {
- //Mame seems to reverse this where enabling ksr actually lowers
- //the rate, but pdf manuals says otherwise?
- Bit8u newKsr = (Bit8u)((self->chanData >> SHIFT_KEYCODE) & 0xff);
- if ( !( self->reg20 & MASK_KSR ) ) {
- newKsr >>= 2;
- }
- if ( self->ksr == newKsr )
- return;
- self->ksr = newKsr;
- Operator__UpdateAttack( self, chip );
- Operator__UpdateDecay( self, chip );
- Operator__UpdateRelease( self, chip );
-}
-
-static inline Bit32s Operator__RateForward(Operator *self, Bit32u add ) {
- Bit32s ret; // haleyjd: GNUisms out!
- self->rateIndex += add;
- ret = self->rateIndex >> RATE_SH;
- self->rateIndex = self->rateIndex & RATE_MASK;
- return ret;
-}
-
-static Bits Operator__TemplateVolume(Operator *self, OperatorState yes) {
- Bit32s vol = self->volume;
- Bit32s change;
- switch ( yes ) {
- case OFF:
- return ENV_MAX;
- case ATTACK:
- change = Operator__RateForward( self, self->attackAdd );
- if ( !change )
- return vol;
- vol += ( (~vol) * change ) >> 3;
- if ( vol < ENV_MIN ) {
- self->volume = ENV_MIN;
- self->rateIndex = 0;
- Operator__SetState( self, DECAY );
- return ENV_MIN;
- }
- break;
- case DECAY:
- vol += Operator__RateForward( self, self->decayAdd );
- if ( GCC_UNLIKELY(vol >= self->sustainLevel) ) {
- //Check if we didn't overshoot max attenuation, then just go off
- if ( GCC_UNLIKELY(vol >= ENV_MAX) ) {
- self->volume = ENV_MAX;
- Operator__SetState( self, OFF );
- return ENV_MAX;
- }
- //Continue as sustain
- self->rateIndex = 0;
- Operator__SetState( self, SUSTAIN );
- }
- break;
- case SUSTAIN:
- if ( self->reg20 & MASK_SUSTAIN ) {
- return vol;
- }
- //In sustain phase, but not sustaining, do regular release
- case RELEASE:
- vol += Operator__RateForward( self, self->releaseAdd );;
- if ( GCC_UNLIKELY(vol >= ENV_MAX) ) {
- self->volume = ENV_MAX;
- Operator__SetState( self, OFF );
- return ENV_MAX;
- }
- break;
- }
- self->volume = vol;
- return vol;
-}
-
-#define TEMPLATE_VOLUME(mode) \
- static Bits Operator__TemplateVolume ## mode(Operator *self) \
- { \
- return Operator__TemplateVolume(self, mode); \
- }
-
-TEMPLATE_VOLUME(OFF)
-TEMPLATE_VOLUME(RELEASE)
-TEMPLATE_VOLUME(SUSTAIN)
-TEMPLATE_VOLUME(ATTACK)
-TEMPLATE_VOLUME(DECAY)
-
-static const VolumeHandler VolumeHandlerTable[5] = {
- &Operator__TemplateVolumeOFF,
- &Operator__TemplateVolumeRELEASE,
- &Operator__TemplateVolumeSUSTAIN,
- &Operator__TemplateVolumeDECAY,
- &Operator__TemplateVolumeATTACK,
-};
-
-static inline Bitu Operator__ForwardVolume(Operator *self) {
- return self->currentLevel + (self->volHandler)(self);
-}
-
-
-static inline Bitu Operator__ForwardWave(Operator *self) {
- self->waveIndex += self->waveCurrent;
- return self->waveIndex >> WAVE_SH;
-}
-
-static void Operator__Write20(Operator *self, const Chip* chip, Bit8u val ) {
- Bit8u change = (self->reg20 ^ val );
- if ( !change )
- return;
- self->reg20 = val;
- //Shift the tremolo bit over the entire register, saved a branch, YES!
- self->tremoloMask = (Bit8s)(val) >> 7;
- self->tremoloMask &= ~(( 1 << ENV_EXTRA ) -1);
- //Update specific features based on changes
- if ( change & MASK_KSR ) {
- Operator__UpdateRates( self, chip );
- }
- //With sustain enable the volume doesn't change
- if ( self->reg20 & MASK_SUSTAIN || ( !self->releaseAdd ) ) {
- self->rateZero |= ( 1 << SUSTAIN );
- } else {
- self->rateZero &= ~( 1 << SUSTAIN );
- }
- //Frequency multiplier or vibrato changed
- if ( change & (0xf | MASK_VIBRATO) ) {
- self->freqMul = chip->freqMul[ val & 0xf ];
- Operator__UpdateFrequency(self);
- }
-}
-
-static void Operator__Write40(Operator *self, const Chip *chip, Bit8u val ) {
- if (!(self->reg40 ^ val ))
- return;
- self->reg40 = val;
- Operator__UpdateAttenuation( self );
-}
-
-static void Operator__Write60(Operator *self, const Chip* chip, Bit8u val ) {
- Bit8u change = self->reg60 ^ val;
- self->reg60 = val;
- if ( change & 0x0f ) {
- Operator__UpdateDecay( self, chip );
- }
- if ( change & 0xf0 ) {
- Operator__UpdateAttack( self, chip );
- }
-}
-
-static void Operator__Write80(Operator *self, const Chip* chip, Bit8u val ) {
- Bit8u change = (self->reg80 ^ val );
- Bit8u sustain; // haleyjd 09/09/10: GNUisms out!
- if ( !change )
- return;
- self->reg80 = val;
- sustain = val >> 4;
- //Turn 0xf into 0x1f
- sustain |= ( sustain + 1) & 0x10;
- self->sustainLevel = sustain << ( ENV_BITS - 5 );
- if ( change & 0x0f ) {
- Operator__UpdateRelease( self, chip );
- }
-}
-
-static void Operator__WriteE0(Operator *self, const Chip* chip, Bit8u val ) {
- Bit8u waveForm; // haleyjd 09/09/10: GNUisms out!
- if ( !(self->regE0 ^ val) )
- return;
- //in opl3 mode you can always selet 7 waveforms regardless of waveformselect
- waveForm = val & ( ( 0x3 & chip->waveFormMask ) | (0x7 & chip->opl3Active ) );
- self->regE0 = val;
-#if( DBOPL_WAVE == WAVE_HANDLER )
- self->waveHandler = WaveHandlerTable[ waveForm ];
-#else
- self->waveBase = WaveTable + WaveBaseTable[ waveForm ];
- self->waveStart = WaveStartTable[ waveForm ] << WAVE_SH;
- self->waveMask = WaveMaskTable[ waveForm ];
-#endif
-}
-
-static inline void Operator__SetState(Operator *self, Bit8u s ) {
- self->state = s;
- self->volHandler = VolumeHandlerTable[ s ];
-}
-
-static inline int Operator__Silent(Operator *self) {
- if ( !ENV_SILENT( self->totalLevel + self->volume ) )
- return FALSE;
- if ( !(self->rateZero & ( 1 << self->state ) ) )
- return FALSE;
- return TRUE;
-}
-
-static inline void Operator__Prepare(Operator *self, const Chip* chip ) {
- self->currentLevel = self->totalLevel + (chip->tremoloValue & self->tremoloMask);
- self->waveCurrent = self->waveAdd;
- if ( self->vibStrength >> chip->vibratoShift ) {
- Bit32s add = self->vibrato >> chip->vibratoShift;
- //Sign extend over the shift value
- Bit32s neg = chip->vibratoSign;
- //Negate the add with -1 or 0
- add = ( add ^ neg ) - neg;
- self->waveCurrent += add;
- }
-}
-
-static void Operator__KeyOn(Operator *self, Bit8u mask ) {
- if ( !self->keyOn ) {
- //Restart the frequency generator
-#if( DBOPL_WAVE > WAVE_HANDLER )
- self->waveIndex = self->waveStart;
-#else
- self->waveIndex = 0;
-#endif
- self->rateIndex = 0;
- Operator__SetState( self, ATTACK );
- }
- self->keyOn |= mask;
-}
-
-static void Operator__KeyOff(Operator *self, Bit8u mask ) {
- self->keyOn &= ~mask;
- if ( !self->keyOn ) {
- if ( self->state != OFF ) {
- Operator__SetState( self, RELEASE );
- }
- }
-}
-
-static inline Bits Operator__GetWave(Operator *self, Bitu index, Bitu vol ) {
-#if( DBOPL_WAVE == WAVE_HANDLER )
- return self->waveHandler( index, vol << ( 3 - ENV_EXTRA ) );
-#elif( DBOPL_WAVE == WAVE_TABLEMUL )
- return(self->waveBase[ index & self->waveMask ] * MulTable[ vol >> ENV_EXTRA ]) >> MUL_SH;
-#elif( DBOPL_WAVE == WAVE_TABLELOG )
- Bit32s wave = self->waveBase[ index & self->waveMask ];
- Bit32u total = ( wave & 0x7fff ) + vol << ( 3 - ENV_EXTRA );
- Bit32s sig = ExpTable[ total & 0xff ];
- Bit32u exp = total >> 8;
- Bit32s neg = wave >> 16;
- return((sig ^ neg) - neg) >> exp;
-#else
-#error "No valid wave routine"
-#endif
-}
-
-static inline Bits Operator__GetSample(Operator *self, Bits modulation ) {
- Bitu vol = Operator__ForwardVolume(self);
- if ( ENV_SILENT( vol ) ) {
- //Simply forward the wave
- self->waveIndex += self->waveCurrent;
- return 0;
- } else {
- Bitu index = Operator__ForwardWave(self);
- index += modulation;
- return Operator__GetWave( self, index, vol );
- }
-}
-
-static void Operator__Operator(Operator *self) {
- self->chanData = 0;
- self->freqMul = 0;
- self->waveIndex = 0;
- self->waveAdd = 0;
- self->waveCurrent = 0;
- self->keyOn = 0;
- self->ksr = 0;
- self->reg20 = 0;
- self->reg40 = 0;
- self->reg60 = 0;
- self->reg80 = 0;
- self->regE0 = 0;
- Operator__SetState( self, OFF );
- self->rateZero = (1 << OFF);
- self->sustainLevel = ENV_MAX;
- self->currentLevel = ENV_MAX;
- self->totalLevel = ENV_MAX;
- self->volume = ENV_MAX;
- self->releaseAdd = 0;
-}
-
-/*
- Channel
-*/
-
-static void Channel__Channel(Channel *self) {
- Operator__Operator(&self->op[0]);
- Operator__Operator(&self->op[1]);
- self->old[0] = self->old[1] = 0;
- self->chanData = 0;
- self->regB0 = 0;
- self->regC0 = 0;
- self->maskLeft = -1;
- self->maskRight = -1;
- self->feedback = 31;
- self->fourMask = 0;
- self->synthHandler = Channel__BlockTemplate_sm2FM;
-};
-
-static inline Operator* Channel__Op( Channel *self, Bitu index ) {
- return &( ( self + (index >> 1) )->op[ index & 1 ]);
-}
-
-static void Channel__SetChanData(Channel *self, const Chip* chip, Bit32u data ) {
- Bit32u change = self->chanData ^ data;
- self->chanData = data;
- Channel__Op( self, 0 )->chanData = data;
- Channel__Op( self, 1 )->chanData = data;
- //Since a frequency update triggered this, always update frequency
- Operator__UpdateFrequency(Channel__Op( self, 0 ));
- Operator__UpdateFrequency(Channel__Op( self, 1 ));
- if ( change & ( 0xff << SHIFT_KSLBASE ) ) {
- Operator__UpdateAttenuation(Channel__Op( self, 0 ));
- Operator__UpdateAttenuation(Channel__Op( self, 1 ));
- }
- if ( change & ( 0xff << SHIFT_KEYCODE ) ) {
- Operator__UpdateRates(Channel__Op( self, 0 ), chip);
- Operator__UpdateRates(Channel__Op( self, 1 ), chip);
- }
-}
-
-static void Channel__UpdateFrequency(Channel *self, const Chip* chip, Bit8u fourOp ) {
- //Extrace the frequency bits
- Bit32u data = self->chanData & 0xffff;
- Bit32u kslBase = KslTable[ data >> 6 ];
- Bit32u keyCode = ( data & 0x1c00) >> 9;
- if ( chip->reg08 & 0x40 ) {
- keyCode |= ( data & 0x100)>>8; /* notesel == 1 */
- } else {
- keyCode |= ( data & 0x200)>>9; /* notesel == 0 */
- }
- //Add the keycode and ksl into the highest bits of chanData
- data |= (keyCode << SHIFT_KEYCODE) | ( kslBase << SHIFT_KSLBASE );
- Channel__SetChanData( self + 0, chip, data );
- if ( fourOp & 0x3f ) {
- Channel__SetChanData( self + 1, chip, data );
- }
-}
-
-static void Channel__WriteA0(Channel *self, const Chip* chip, Bit8u val ) {
- Bit8u fourOp = chip->reg104 & chip->opl3Active & self->fourMask;
- Bit32u change; // haleyjd 09/09/10: GNUisms out!
- //Don't handle writes to silent fourop channels
- if ( fourOp > 0x80 )
- return;
- change = (self->chanData ^ val ) & 0xff;
- if ( change ) {
- self->chanData ^= change;
- Channel__UpdateFrequency( self, chip, fourOp );
- }
-}
-
-static void Channel__WriteB0(Channel *self, const Chip* chip, Bit8u val ) {
- Bit8u fourOp = chip->reg104 & chip->opl3Active & self->fourMask;
- Bitu change; // haleyjd 09/09/10: GNUisms out!
- //Don't handle writes to silent fourop channels
- if ( fourOp > 0x80 )
- return;
- change = (self->chanData ^ ( val << 8 ) ) & 0x1f00;
- if ( change ) {
- self->chanData ^= change;
- Channel__UpdateFrequency( self, chip, fourOp );
- }
- //Check for a change in the keyon/off state
- if ( !(( val ^ self->regB0) & 0x20))
- return;
- self->regB0 = val;
- if ( val & 0x20 ) {
- Operator__KeyOn( Channel__Op(self, 0), 0x1 );
- Operator__KeyOn( Channel__Op(self, 1), 0x1 );
- if ( fourOp & 0x3f ) {
- Operator__KeyOn( Channel__Op(self + 1, 0), 1 );
- Operator__KeyOn( Channel__Op(self + 1, 1), 1 );
- }
- } else {
- Operator__KeyOff( Channel__Op(self, 0), 0x1 );
- Operator__KeyOff( Channel__Op(self, 1), 0x1 );
- if ( fourOp & 0x3f ) {
- Operator__KeyOff( Channel__Op(self + 1, 0), 1 );
- Operator__KeyOff( Channel__Op(self + 1, 1), 1 );
- }
- }
-}
-
-static void Channel__WriteC0(Channel *self, const Chip* chip, Bit8u val ) {
- Bit8u change = val ^ self->regC0;
- if ( !change )
- return;
- self->regC0 = val;
- self->feedback = ( val >> 1 ) & 7;
- if ( self->feedback ) {
- //We shift the input to the right 10 bit wave index value
- self->feedback = 9 - self->feedback;
- } else {
- self->feedback = 31;
- }
- //Select the new synth mode
- if ( chip->opl3Active ) {
- //4-op mode enabled for this channel
- if ( (chip->reg104 & self->fourMask) & 0x3f ) {
- Channel* chan0, *chan1;
- Bit8u synth; // haleyjd 09/09/10: GNUisms out!
- //Check if it's the 2nd channel in a 4-op
- if ( !(self->fourMask & 0x80 ) ) {
- chan0 = self;
- chan1 = self + 1;
- } else {
- chan0 = self - 1;
- chan1 = self;
- }
-
- synth = ( (chan0->regC0 & 1) << 0 )| (( chan1->regC0 & 1) << 1 );
- switch ( synth ) {
- case 0:
- chan0->synthHandler = Channel__BlockTemplate_sm3FMFM;
- break;
- case 1:
- chan0->synthHandler = Channel__BlockTemplate_sm3AMFM;
- break;
- case 2:
- chan0->synthHandler = Channel__BlockTemplate_sm3FMAM ;
- break;
- case 3:
- chan0->synthHandler = Channel__BlockTemplate_sm3AMAM ;
- break;
- }
- //Disable updating percussion channels
- } else if ((self->fourMask & 0x40) && ( chip->regBD & 0x20) ) {
-
- //Regular dual op, am or fm
- } else if ( val & 1 ) {
- self->synthHandler = Channel__BlockTemplate_sm3AM;
- } else {
- self->synthHandler = Channel__BlockTemplate_sm3FM;
- }
- self->maskLeft = ( val & 0x10 ) ? -1 : 0;
- self->maskRight = ( val & 0x20 ) ? -1 : 0;
- //opl2 active
- } else {
- //Disable updating percussion channels
- if ( (self->fourMask & 0x40) && ( chip->regBD & 0x20 ) ) {
-
- //Regular dual op, am or fm
- } else if ( val & 1 ) {
- self->synthHandler = Channel__BlockTemplate_sm2AM;
- } else {
- self->synthHandler = Channel__BlockTemplate_sm2FM;
- }
- }
-}
-
-static void Channel__ResetC0(Channel *self, const Chip* chip ) {
- Bit8u val = self->regC0;
- self->regC0 ^= 0xff;
- Channel__WriteC0( self, chip, val );
-};
-
-static inline void Channel__GeneratePercussion(Channel *self, Chip* chip,
- Bit32s* output, int opl3Mode ) {
- Channel* chan = self;
-
- //BassDrum
- Bit32s mod = (Bit32u)((self->old[0] + self->old[1])) >> self->feedback;
- Bit32s sample; // haleyjd 09/09/10
- Bit32u noiseBit;
- Bit32u c2;
- Bit32u c5;
- Bit32u phaseBit;
- Bit32u hhVol;
- Bit32u sdVol;
- Bit32u tcVol;
-
- self->old[0] = self->old[1];
- self->old[1] = Operator__GetSample( Channel__Op(self, 0), mod );
-
- //When bassdrum is in AM mode first operator is ignoed
- if ( chan->regC0 & 1 ) {
- mod = 0;
- } else {
- mod = self->old[0];
- }
- sample = Operator__GetSample( Channel__Op(self, 1), mod );
-
- //Precalculate stuff used by other outputs
- noiseBit = Chip__ForwardNoise(chip) & 0x1;
- c2 = Operator__ForwardWave(Channel__Op(self, 2));
- c5 = Operator__ForwardWave(Channel__Op(self, 5));
- phaseBit = (((c2 & 0x88) ^ ((c2<<5) & 0x80)) | ((c5 ^ (c5<<2)) & 0x20)) ? 0x02 : 0x00;
-
- //Hi-Hat
- hhVol = Operator__ForwardVolume(Channel__Op(self, 2));
- if ( !ENV_SILENT( hhVol ) ) {
- Bit32u hhIndex = (phaseBit<<8) | (0x34 << ( phaseBit ^ (noiseBit << 1 )));
- sample += Operator__GetWave( Channel__Op(self, 2), hhIndex, hhVol );
- }
- //Snare Drum
- sdVol = Operator__ForwardVolume( Channel__Op(self, 3) );
- if ( !ENV_SILENT( sdVol ) ) {
- Bit32u sdIndex = ( 0x100 + (c2 & 0x100) ) ^ ( noiseBit << 8 );
- sample += Operator__GetWave( Channel__Op(self, 3), sdIndex, sdVol );
- }
- //Tom-tom
- sample += Operator__GetSample( Channel__Op(self, 4), 0 );
-
- //Top-Cymbal
- tcVol = Operator__ForwardVolume(Channel__Op(self, 5));
- if ( !ENV_SILENT( tcVol ) ) {
- Bit32u tcIndex = (1 + phaseBit) << 8;
- sample += Operator__GetWave( Channel__Op(self, 5), tcIndex, tcVol );
- }
- sample <<= 1;
- if ( opl3Mode ) {
- output[0] += sample;
- output[1] += sample;
- } else {
- output[0] += sample;
- }
-}
-
-Channel* Channel__BlockTemplate(Channel *self, Chip* chip,
- Bit32u samples, Bit32s* output,
- SynthMode mode ) {
- Bitu i;
-
- switch( mode ) {
- case sm2AM:
- case sm3AM:
- if ( Operator__Silent(Channel__Op(self, 0))
- && Operator__Silent(Channel__Op(self, 1))) {
- self->old[0] = self->old[1] = 0;
- return(self + 1);
- }
- break;
- case sm2FM:
- case sm3FM:
- if ( Operator__Silent(Channel__Op(self, 1))) {
- self->old[0] = self->old[1] = 0;
- return (self + 1);
- }
- break;
- case sm3FMFM:
- if ( Operator__Silent(Channel__Op(self, 3))) {
- self->old[0] = self->old[1] = 0;
- return (self + 2);
- }
- break;
- case sm3AMFM:
- if ( Operator__Silent( Channel__Op(self, 0) )
- && Operator__Silent( Channel__Op(self, 3) )) {
- self->old[0] = self->old[1] = 0;
- return (self + 2);
- }
- break;
- case sm3FMAM:
- if ( Operator__Silent( Channel__Op(self, 1))
- && Operator__Silent( Channel__Op(self, 3))) {
- self->old[0] = self->old[1] = 0;
- return (self + 2);
- }
- break;
- case sm3AMAM:
- if ( Operator__Silent( Channel__Op(self, 0) )
- && Operator__Silent( Channel__Op(self, 2) )
- && Operator__Silent( Channel__Op(self, 3) )) {
- self->old[0] = self->old[1] = 0;
- return (self + 2);
- }
- break;
-
- default:
- abort();
- }
- //Init the operators with the the current vibrato and tremolo values
- Operator__Prepare( Channel__Op( self, 0 ), chip );
- Operator__Prepare( Channel__Op( self, 1 ), chip );
- if ( mode > sm4Start ) {
- Operator__Prepare( Channel__Op( self, 2 ), chip );
- Operator__Prepare( Channel__Op( self, 3 ), chip );
- }
- if ( mode > sm6Start ) {
- Operator__Prepare( Channel__Op( self, 4 ), chip );
- Operator__Prepare( Channel__Op( self, 5 ), chip );
- }
- for ( i = 0; i < samples; i++ ) {
- Bit32s mod; // haleyjd 09/09/10: GNUisms out!
- Bit32s sample;
- Bit32s out0;
-
- //Early out for percussion handlers
- if ( mode == sm2Percussion ) {
- Channel__GeneratePercussion( self, chip, output + i, FALSE );
- continue; //Prevent some unitialized value bitching
- } else if ( mode == sm3Percussion ) {
- Channel__GeneratePercussion( self, chip, output + i * 2, TRUE );
- continue; //Prevent some unitialized value bitching
- }
-
- //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise
- mod = (Bit32u)((self->old[0] + self->old[1])) >> self->feedback;
- self->old[0] = self->old[1];
- self->old[1] = Operator__GetSample( Channel__Op(self, 0), mod );
- sample = 0;
- out0 = self->old[0];
- if ( mode == sm2AM || mode == sm3AM ) {
- sample = out0 + Operator__GetSample( Channel__Op(self, 1), 0 );
- } else if ( mode == sm2FM || mode == sm3FM ) {
- sample = Operator__GetSample( Channel__Op(self, 1), out0 );
- } else if ( mode == sm3FMFM ) {
- Bits next = Operator__GetSample( Channel__Op(self, 1), out0 );
- next = Operator__GetSample( Channel__Op(self, 2), next );
- sample = Operator__GetSample( Channel__Op(self, 3), next );
- } else if ( mode == sm3AMFM ) {
- Bits next; // haleyjd 09/09/10: GNUisms out!
- sample = out0;
- next = Operator__GetSample( Channel__Op(self, 1), 0 );
- next = Operator__GetSample( Channel__Op(self, 2), next );
- sample += Operator__GetSample( Channel__Op(self, 3), next );
- } else if ( mode == sm3FMAM ) {
- Bits next; // haleyjd 09/09/10: GNUisms out!
- sample = Operator__GetSample( Channel__Op(self, 1), out0 );
- next = Operator__GetSample( Channel__Op(self, 2), 0 );
- sample += Operator__GetSample( Channel__Op(self, 3), next );
- } else if ( mode == sm3AMAM ) {
- Bits next; // haleyjd 09/09/10: GNUisms out!
- sample = out0;
- next = Operator__GetSample( Channel__Op(self, 1), 0 );
- sample += Operator__GetSample( Channel__Op(self, 2), next );
- sample += Operator__GetSample( Channel__Op(self, 3), 0 );
- }
- switch( mode ) {
- case sm2AM:
- case sm2FM:
- output[ i ] += sample;
- break;
- case sm3AM:
- case sm3FM:
- case sm3FMFM:
- case sm3AMFM:
- case sm3FMAM:
- case sm3AMAM:
- output[ i * 2 + 0 ] += sample & self->maskLeft;
- output[ i * 2 + 1 ] += sample & self->maskRight;
- break;
- default:
- abort();
- }
- }
- switch( mode ) {
- case sm2AM:
- case sm2FM:
- case sm3AM:
- case sm3FM:
- return ( self + 1 );
- case sm3FMFM:
- case sm3AMFM:
- case sm3FMAM:
- case sm3AMAM:
- return ( self + 2 );
- case sm2Percussion:
- case sm3Percussion:
- return( self + 3 );
- default:
- abort();
- }
- return 0;
-}
-
-/*
- Chip
-*/
-
-void Chip__Chip(Chip *self) {
- int i;
-
- for (i=0; i<18; ++i) {
- Channel__Channel(&self->chan[i]);
- }
-
- self->reg08 = 0;
- self->reg04 = 0;
- self->regBD = 0;
- self->reg104 = 0;
- self->opl3Active = 0;
-}
-
-static inline Bit32u Chip__ForwardNoise(Chip *self) {
- Bitu count;
- self->noiseCounter += self->noiseAdd;
- count = self->noiseCounter >> LFO_SH;
- self->noiseCounter &= WAVE_MASK;
- for ( ; count > 0; --count ) {
- //Noise calculation from mame
- self->noiseValue ^= ( 0x800302 ) & ( 0 - (self->noiseValue & 1 ) );
- self->noiseValue >>= 1;
- }
- return self->noiseValue;
-}
-
-static inline Bit32u Chip__ForwardLFO(Chip *self, Bit32u samples ) {
- Bit32u todo; // haleyjd 09/09/10: GNUisms out!!!!!!
- Bit32u count;
-
- //Current vibrato value, runs 4x slower than tremolo
- self->vibratoSign = ( VibratoTable[ self->vibratoIndex >> 2] ) >> 7;
- self->vibratoShift = ( VibratoTable[ self->vibratoIndex >> 2] & 7) + self->vibratoStrength;
- self->tremoloValue = TremoloTable[ self->tremoloIndex ] >> self->tremoloStrength;
-
- //Check hom many samples there can be done before the value changes
- todo = LFO_MAX - self->lfoCounter;
- count = (todo + self->lfoAdd - 1) / self->lfoAdd;
- if ( count > samples ) {
- count = samples;
- self->lfoCounter += count * self->lfoAdd;
- } else {
- self->lfoCounter += count * self->lfoAdd;
- self->lfoCounter &= (LFO_MAX - 1);
- //Maximum of 7 vibrato value * 4
- self->vibratoIndex = ( self->vibratoIndex + 1 ) & 31;
- //Clip tremolo to the the table size
- if ( self->tremoloIndex + 1 < TREMOLO_TABLE )
- ++self->tremoloIndex;
- else
- self->tremoloIndex = 0;
- }
- return count;
-}
-
-
-static void Chip__WriteBD(Chip *self, Bit8u val ) {
- Bit8u change = self->regBD ^ val;
- if ( !change )
- return;
- self->regBD = val;
- //TODO could do this with shift and xor?
- self->vibratoStrength = (val & 0x40) ? 0x00 : 0x01;
- self->tremoloStrength = (val & 0x80) ? 0x00 : 0x02;
- if ( val & 0x20 ) {
- //Drum was just enabled, make sure channel 6 has the right synth
- if ( change & 0x20 ) {
- if ( self->opl3Active ) {
- self->chan[6].synthHandler
- = Channel__BlockTemplate_sm3Percussion;
- } else {
- self->chan[6].synthHandler
- = Channel__BlockTemplate_sm2Percussion;
- }
- }
- //Bass Drum
- if ( val & 0x10 ) {
- Operator__KeyOn( &self->chan[6].op[0], 0x2 );
- Operator__KeyOn( &self->chan[6].op[1], 0x2 );
- } else {
- Operator__KeyOff( &self->chan[6].op[0], 0x2 );
- Operator__KeyOff( &self->chan[6].op[1], 0x2 );
- }
- //Hi-Hat
- if ( val & 0x1 ) {
- Operator__KeyOn( &self->chan[7].op[0], 0x2 );
- } else {
- Operator__KeyOff( &self->chan[7].op[0], 0x2 );
- }
- //Snare
- if ( val & 0x8 ) {
- Operator__KeyOn( &self->chan[7].op[1], 0x2 );
- } else {
- Operator__KeyOff( &self->chan[7].op[1], 0x2 );
- }
- //Tom-Tom
- if ( val & 0x4 ) {
- Operator__KeyOn( &self->chan[8].op[0], 0x2 );
- } else {
- Operator__KeyOff( &self->chan[8].op[0], 0x2 );
- }
- //Top Cymbal
- if ( val & 0x2 ) {
- Operator__KeyOn( &self->chan[8].op[1], 0x2 );
- } else {
- Operator__KeyOff( &self->chan[8].op[1], 0x2 );
- }
- //Toggle keyoffs when we turn off the percussion
- } else if ( change & 0x20 ) {
- //Trigger a reset to setup the original synth handler
- Channel__ResetC0( &self->chan[6], self );
- Operator__KeyOff( &self->chan[6].op[0], 0x2 );
- Operator__KeyOff( &self->chan[6].op[1], 0x2 );
- Operator__KeyOff( &self->chan[7].op[0], 0x2 );
- Operator__KeyOff( &self->chan[7].op[1], 0x2 );
- Operator__KeyOff( &self->chan[8].op[0], 0x2 );
- Operator__KeyOff( &self->chan[8].op[1], 0x2 );
- }
-}
-
-
-#define REGOP( _FUNC_ ) \
- index = ( ( reg >> 3) & 0x20 ) | ( reg & 0x1f ); \
- if ( OpOffsetTable[ index ] ) { \
- Operator* regOp = (Operator*)( ((char *)self ) + OpOffsetTable[ index ] ); \
- Operator__ ## _FUNC_ (regOp, self, val); \
- }
-
-#define REGCHAN( _FUNC_ ) \
- index = ( ( reg >> 4) & 0x10 ) | ( reg & 0xf ); \
- if ( ChanOffsetTable[ index ] ) { \
- Channel* regChan = (Channel*)( ((char *)self ) + ChanOffsetTable[ index ] ); \
- Channel__ ## _FUNC_ (regChan, self, val); \
- }
-
-void Chip__WriteReg(Chip *self, Bit32u reg, Bit8u val ) {
- Bitu index;
- switch ( (reg & 0xf0) >> 4 ) {
- case 0x00 >> 4:
- if ( reg == 0x01 ) {
- self->waveFormMask = ( val & 0x20 ) ? 0x7 : 0x0;
- } else if ( reg == 0x104 ) {
- //Only detect changes in lowest 6 bits
- if ( !((self->reg104 ^ val) & 0x3f) )
- return;
- //Always keep the highest bit enabled, for checking > 0x80
- self->reg104 = 0x80 | ( val & 0x3f );
- } else if ( reg == 0x105 ) {
- int i;
-
- //MAME says the real opl3 doesn't reset anything on opl3 disable/enable till the next write in another register
- if ( !((self->opl3Active ^ val) & 1 ) )
- return;
- self->opl3Active = ( val & 1 ) ? 0xff : 0;
- //Update the 0xc0 register for all channels to signal the switch to mono/stereo handlers
- for ( i = 0; i < 18;i++ ) {
- Channel__ResetC0( &self->chan[i], self );
- }
- } else if ( reg == 0x08 ) {
- self->reg08 = val;
- }
- case 0x10 >> 4:
- break;
- case 0x20 >> 4:
- case 0x30 >> 4:
- REGOP( Write20 );
- break;
- case 0x40 >> 4:
- case 0x50 >> 4:
- REGOP( Write40 );
- break;
- case 0x60 >> 4:
- case 0x70 >> 4:
- REGOP( Write60 );
- break;
- case 0x80 >> 4:
- case 0x90 >> 4:
- REGOP( Write80 );
- break;
- case 0xa0 >> 4:
- REGCHAN( WriteA0 );
- break;
- case 0xb0 >> 4:
- if ( reg == 0xbd ) {
- Chip__WriteBD( self, val );
- } else {
- REGCHAN( WriteB0 );
- }
- break;
- case 0xc0 >> 4:
- REGCHAN( WriteC0 );
- case 0xd0 >> 4:
- break;
- case 0xe0 >> 4:
- case 0xf0 >> 4:
- REGOP( WriteE0 );
- break;
- }
-}
-
-Bit32u Chip__WriteAddr(Chip *self, Bit32u port, Bit8u val ) {
- switch ( port & 3 ) {
- case 0:
- return val;
- case 2:
- if ( self->opl3Active || (val == 0x05) )
- return 0x100 | val;
- else
- return val;
- }
- return 0;
-}
-
-void Chip__GenerateBlock2(Chip *self, Bitu total, Bit32s* output ) {
- while ( total > 0 ) {
- Channel *ch;
- int count;
-
- Bit32u samples = Chip__ForwardLFO( self, total );
- memset(output, 0, sizeof(Bit32s) * samples);
- count = 0;
- for ( ch = self->chan; ch < self->chan + 9; ) {
- count++;
- ch = (ch->synthHandler)( ch, self, samples, output );
- }
- total -= samples;
- output += samples;
- }
-}
-
-void Chip__GenerateBlock3(Chip *self, Bitu total, Bit32s* output ) {
- while ( total > 0 ) {
- int count;
- Channel *ch;
-
- Bit32u samples = Chip__ForwardLFO( self, total );
- memset(output, 0, sizeof(Bit32s) * samples *2);
- count = 0;
- for ( ch = self->chan; ch < self->chan + 18; ) {
- count++;
- ch = (ch->synthHandler)( ch, self, samples, output );
- }
- total -= samples;
- output += samples * 2;
- }
-}
-
-void Chip__Setup(Chip *self, Bit32u rate ) {
- double original = OPLRATE;
- Bit32u i;
- Bit32u freqScale; // haleyjd 09/09/10: GNUisms out!
-// double original = rate;
- double scale = original / (double)rate;
-
- //Noise counter is run at the same precision as general waves
- self->noiseAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) );
- self->noiseCounter = 0;
- self->noiseValue = 1; //Make sure it triggers the noise xor the first time
- //The low frequency oscillation counter
- //Every time his overflows vibrato and tremoloindex are increased
- self->lfoAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) );
- self->lfoCounter = 0;
- self->vibratoIndex = 0;
- self->tremoloIndex = 0;
-
- //With higher octave this gets shifted up
- //-1 since the freqCreateTable = *2
-#ifdef WAVE_PRECISION
- double freqScale = ( 1 << 7 ) * scale * ( 1 << ( WAVE_SH - 1 - 10));
- for ( i = 0; i < 16; i++ ) {
- self->freqMul[i] = (Bit32u)( 0.5 + freqScale * FreqCreateTable[ i ] );
- }
-#else
- freqScale = (Bit32u)( 0.5 + scale * ( 1 << ( WAVE_SH - 1 - 10)));
- for ( i = 0; i < 16; i++ ) {
- self->freqMul[i] = freqScale * FreqCreateTable[ i ];
- }
-#endif
-
- //-3 since the real envelope takes 8 steps to reach the single value we supply
- for ( i = 0; i < 76; i++ ) {
- Bit8u index, shift;
- EnvelopeSelect( i, &index, &shift );
- self->linearRates[i] = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH + ENV_EXTRA - shift - 3 )));
- }
- //Generate the best matching attack rate
- for ( i = 0; i < 62; i++ ) {
- Bit8u index, shift;
- Bit32s original; // haleyjd 09/09/10: GNUisms out!
- Bit32s guessAdd;
- Bit32s bestAdd;
- Bit32u bestDiff;
- Bit32u passes;
- EnvelopeSelect( i, &index, &shift );
- //Original amount of samples the attack would take
- original = (Bit32u)( (AttackSamplesTable[ index ] << shift) / scale);
-
- guessAdd = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH - shift - 3 )));
- bestAdd = guessAdd;
- bestDiff = 1 << 30;
-
- for ( passes = 0; passes < 16; passes ++ ) {
- Bit32s volume = ENV_MAX;
- Bit32s samples = 0;
- Bit32u count = 0;
- Bit32s diff;
- Bit32u lDiff;
- while ( volume > 0 && samples < original * 2 ) {
- Bit32s change; // haleyjd 09/09/10
- count += guessAdd;
- change = count >> RATE_SH;
- count &= RATE_MASK;
- if ( GCC_UNLIKELY(change) ) { // less than 1 %
- volume += ( ~volume * change ) >> 3;
- }
- samples++;
-
- }
- diff = original - samples;
- lDiff = labs( diff );
- //Init last on first pass
- if ( lDiff < bestDiff ) {
- bestDiff = lDiff;
- bestAdd = guessAdd;
- if ( !bestDiff )
- break;
- }
- //Below our target
- if ( diff < 0 ) {
- //Better than the last time
- Bit32s mul = ((original - diff) << 12) / original;
- guessAdd = ((guessAdd * mul) >> 12);
- guessAdd++;
- } else if ( diff > 0 ) {
- Bit32s mul = ((original - diff) << 12) / original;
- guessAdd = (guessAdd * mul) >> 12;
- guessAdd--;
- }
- }
- self->attackRates[i] = bestAdd;
- }
- for ( i = 62; i < 76; i++ ) {
- //This should provide instant volume maximizing
- self->attackRates[i] = 8 << RATE_SH;
- }
- //Setup the channels with the correct four op flags
- //Channels are accessed through a table so they appear linear here
- self->chan[ 0].fourMask = 0x00 | ( 1 << 0 );
- self->chan[ 1].fourMask = 0x80 | ( 1 << 0 );
- self->chan[ 2].fourMask = 0x00 | ( 1 << 1 );
- self->chan[ 3].fourMask = 0x80 | ( 1 << 1 );
- self->chan[ 4].fourMask = 0x00 | ( 1 << 2 );
- self->chan[ 5].fourMask = 0x80 | ( 1 << 2 );
-
- self->chan[ 9].fourMask = 0x00 | ( 1 << 3 );
- self->chan[10].fourMask = 0x80 | ( 1 << 3 );
- self->chan[11].fourMask = 0x00 | ( 1 << 4 );
- self->chan[12].fourMask = 0x80 | ( 1 << 4 );
- self->chan[13].fourMask = 0x00 | ( 1 << 5 );
- self->chan[14].fourMask = 0x80 | ( 1 << 5 );
-
- //mark the percussion channels
- self->chan[ 6].fourMask = 0x40;
- self->chan[ 7].fourMask = 0x40;
- self->chan[ 8].fourMask = 0x40;
-
- //Clear Everything in opl3 mode
- Chip__WriteReg( self, 0x105, 0x1 );
- for ( i = 0; i < 512; i++ ) {
- if ( i == 0x105 )
- continue;
- Chip__WriteReg( self, i, 0xff );
- Chip__WriteReg( self, i, 0x0 );
- }
- Chip__WriteReg( self, 0x105, 0x0 );
- //Clear everything in opl2 mode
- for ( i = 0; i < 255; i++ ) {
- Chip__WriteReg( self, i, 0xff );
- Chip__WriteReg( self, i, 0x0 );
- }
-}
-
-static int doneTables = FALSE;
-void DBOPL_InitTables( void ) {
- int i, oct;
-
- if ( doneTables )
- return;
- doneTables = TRUE;
-#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG )
- //Exponential volume table, same as the real adlib
- for ( i = 0; i < 256; i++ ) {
- //Save them in reverse
- ExpTable[i] = (int)( 0.5 + ( pow(2.0, ( 255 - i) * ( 1.0 /256 ) )-1) * 1024 );
- ExpTable[i] += 1024; //or remove the -1 oh well :)
- //Preshift to the left once so the final volume can shift to the right
- ExpTable[i] *= 2;
- }
-#endif
-#if ( DBOPL_WAVE == WAVE_HANDLER )
- //Add 0.5 for the trunc rounding of the integer cast
- //Do a PI sinetable instead of the original 0.5 PI
- for ( i = 0; i < 512; i++ ) {
- SinTable[i] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 );
- }
-#endif
-#if ( DBOPL_WAVE == WAVE_TABLEMUL )
- //Multiplication based tables
- for ( i = 0; i < 384; i++ ) {
- int s = i * 8;
- //TODO maybe keep some of the precision errors of the original table?
- double val = ( 0.5 + ( pow(2.0, -1.0 + ( 255 - s) * ( 1.0 /256 ) )) * ( 1 << MUL_SH ));
- MulTable[i] = (Bit16u)(val);
- }
-
- //Sine Wave Base
- for ( i = 0; i < 512; i++ ) {
- WaveTable[ 0x0200 + i ] = (Bit16s)(sin( (i + 0.5) * (PI / 512.0) ) * 4084);
- WaveTable[ 0x0000 + i ] = -WaveTable[ 0x200 + i ];
- }
- //Exponential wave
- for ( i = 0; i < 256; i++ ) {
- WaveTable[ 0x700 + i ] = (Bit16s)( 0.5 + ( pow(2.0, -1.0 + ( 255 - i * 8) * ( 1.0 /256 ) ) ) * 4085 );
- WaveTable[ 0x6ff - i ] = -WaveTable[ 0x700 + i ];
- }
-#endif
-#if ( DBOPL_WAVE == WAVE_TABLELOG )
- //Sine Wave Base
- for ( i = 0; i < 512; i++ ) {
- WaveTable[ 0x0200 + i ] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 );
- WaveTable[ 0x0000 + i ] = ((Bit16s)0x8000) | WaveTable[ 0x200 + i];
- }
- //Exponential wave
- for ( i = 0; i < 256; i++ ) {
- WaveTable[ 0x700 + i ] = i * 8;
- WaveTable[ 0x6ff - i ] = ((Bit16s)0x8000) | i * 8;
- }
-#endif
-
- // | |//\\|____|WAV7|//__|/\ |____|/\/\|
- // |\\//| | |WAV7| | \/| | |
- // |06 |0126|27 |7 |3 |4 |4 5 |5 |
-
-#if (( DBOPL_WAVE == WAVE_TABLELOG ) || ( DBOPL_WAVE == WAVE_TABLEMUL ))
- for ( i = 0; i < 256; i++ ) {
- //Fill silence gaps
- WaveTable[ 0x400 + i ] = WaveTable[0];
- WaveTable[ 0x500 + i ] = WaveTable[0];
- WaveTable[ 0x900 + i ] = WaveTable[0];
- WaveTable[ 0xc00 + i ] = WaveTable[0];
- WaveTable[ 0xd00 + i ] = WaveTable[0];
- //Replicate sines in other pieces
- WaveTable[ 0x800 + i ] = WaveTable[ 0x200 + i ];
- //double speed sines
- WaveTable[ 0xa00 + i ] = WaveTable[ 0x200 + i * 2 ];
- WaveTable[ 0xb00 + i ] = WaveTable[ 0x000 + i * 2 ];
- WaveTable[ 0xe00 + i ] = WaveTable[ 0x200 + i * 2 ];
- WaveTable[ 0xf00 + i ] = WaveTable[ 0x200 + i * 2 ];
- }
-#endif
-
- //Create the ksl table
- for ( oct = 0; oct < 8; oct++ ) {
- int base = oct * 8;
- for ( i = 0; i < 16; i++ ) {
- int val = base - KslCreateTable[i];
- if ( val < 0 )
- val = 0;
- //*4 for the final range to match attenuation range
- KslTable[ oct * 16 + i ] = val * 4;
- }
- }
- //Create the Tremolo table, just increase and decrease a triangle wave
- for ( i = 0; i < TREMOLO_TABLE / 2; i++ ) {
- Bit8u val = i << ENV_EXTRA;
- TremoloTable[i] = val;
- TremoloTable[TREMOLO_TABLE - 1 - i] = val;
- }
- //Create a table with offsets of the channels from the start of the chip
- { // haleyjd 09/09/10: Driving me #$%^@ insane
- Chip *chip = NULL;
- for ( i = 0; i < 32; i++ ) {
- Bitu index = i & 0xf;
- Bitu blah; // haleyjd 09/09/10
- if ( index >= 9 ) {
- ChanOffsetTable[i] = 0;
- continue;
- }
- //Make sure the four op channels follow eachother
- if ( index < 6 ) {
- index = (index % 3) * 2 + ( index / 3 );
- }
- //Add back the bits for highest ones
- if ( i >= 16 )
- index += 9;
- blah = (Bitu) ( &(chip->chan[ index ]) );
- ChanOffsetTable[i] = blah;
- }
- //Same for operators
- for ( i = 0; i < 64; i++ ) {
- Bitu chNum; // haleyjd 09/09/10
- Bitu opNum;
- Bitu blah;
- Channel* chan = NULL;
- if ( i % 8 >= 6 || ( (i / 8) % 4 == 3 ) ) {
- OpOffsetTable[i] = 0;
- continue;
- }
- chNum = (i / 8) * 3 + (i % 8) % 3;
- //Make sure we use 16 and up for the 2nd range to match the chanoffset gap
- if ( chNum >= 12 )
- chNum += 16 - 12;
- opNum = ( i % 8 ) / 3;
- blah = (Bitu) ( &(chan->op[opNum]) );
- OpOffsetTable[i] = ChanOffsetTable[ chNum ] + blah;
- }
-#if 0
- //Stupid checks if table's are correct
- for ( Bitu i = 0; i < 18; i++ ) {
- Bit32u find = (Bit16u)( &(chip->chan[ i ]) );
- for ( Bitu c = 0; c < 32; c++ ) {
- if ( ChanOffsetTable[c] == find ) {
- find = 0;
- break;
- }
- }
- if ( find ) {
- find = find;
- }
- }
- for ( Bitu i = 0; i < 36; i++ ) {
- Bit32u find = (Bit16u)( &(chip->chan[ i / 2 ].op[i % 2]) );
- for ( Bitu c = 0; c < 64; c++ ) {
- if ( OpOffsetTable[c] == find ) {
- find = 0;
- break;
- }
- }
- if ( find ) {
- find = find;
- }
- }
-#endif
- }
-}
-
-/*
-
-Bit32u Handler::WriteAddr( Bit32u port, Bit8u val ) {
- return chip.WriteAddr( port, val );
-
-}
-void Handler::WriteReg( Bit32u addr, Bit8u val ) {
- chip.WriteReg( addr, val );
-}
-
-void Handler::Generate( MixerChannel* chan, Bitu samples ) {
- Bit32s buffer[ 512 * 2 ];
- if ( GCC_UNLIKELY(samples > 512) )
- samples = 512;
- if ( !chip.opl3Active ) {
- chip.GenerateBlock2( samples, buffer );
- chan->AddSamples_m32( samples, buffer );
- } else {
- chip.GenerateBlock3( samples, buffer );
- chan->AddSamples_s32( samples, buffer );
- }
-}
-
-void Handler::Init( Bitu rate ) {
- InitTables();
- chip.Setup( rate );
-}
-*/
-
--- a/opl/dbopl.h
+++ /dev/null
@@ -1,203 +1,0 @@
-/*
- * Copyright (C) 2002-2010 The DOSBox Team
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <inttypes.h>
-
-//Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume
-#define WAVE_HANDLER 10
-//Use a logarithmic wavetable with an exponential table for volume
-#define WAVE_TABLELOG 11
-//Use a linear wavetable with a multiply table for volume
-#define WAVE_TABLEMUL 12
-
-//Select the type of wave generator routine
-#define DBOPL_WAVE WAVE_TABLEMUL
-
-typedef struct _Chip Chip;
-typedef struct _Operator Operator;
-typedef struct _Channel Channel;
-
-typedef uintptr_t Bitu;
-typedef intptr_t Bits;
-typedef uint32_t Bit32u;
-typedef int32_t Bit32s;
-typedef uint16_t Bit16u;
-typedef int16_t Bit16s;
-typedef uint8_t Bit8u;
-typedef int8_t Bit8s;
-
-#if (DBOPL_WAVE == WAVE_HANDLER)
-typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume );
-#endif
-
-#define DB_FASTCALL
-
-typedef Bits (*VolumeHandler)(Operator *self);
-typedef Channel* (*SynthHandler)(Channel *self, Chip* chip, Bit32u samples, Bit32s* output );
-
-//Different synth modes that can generate blocks of data
-typedef enum {
- sm2AM,
- sm2FM,
- sm3AM,
- sm3FM,
- sm4Start,
- sm3FMFM,
- sm3AMFM,
- sm3FMAM,
- sm3AMAM,
- sm6Start,
- sm2Percussion,
- sm3Percussion,
-} SynthMode;
-
-//Shifts for the values contained in chandata variable
-enum {
- SHIFT_KSLBASE = 16,
- SHIFT_KEYCODE = 24,
-};
-
-//Masks for operator 20 values
-enum {
- MASK_KSR = 0x10,
- MASK_SUSTAIN = 0x20,
- MASK_VIBRATO = 0x40,
- MASK_TREMOLO = 0x80,
-};
-
-typedef enum {
- OFF,
- RELEASE,
- SUSTAIN,
- DECAY,
- ATTACK,
-} OperatorState;
-
-struct _Operator {
- VolumeHandler volHandler;
-
-#if (DBOPL_WAVE == WAVE_HANDLER)
- WaveHandler waveHandler; //Routine that generate a wave
-#else
- Bit16s* waveBase;
- Bit32u waveMask;
- Bit32u waveStart;
-#endif
- Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index
- Bit32u waveAdd; //The base frequency without vibrato
- Bit32u waveCurrent; //waveAdd + vibratao
-
- Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this
- Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove?
- Bit32u vibrato; //Scaled up vibrato strength
- Bit32s sustainLevel; //When stopping at sustain level stop here
- Bit32s totalLevel; //totalLevel is added to every generated volume
- Bit32u currentLevel; //totalLevel + tremolo
- Bit32s volume; //The currently active volume
-
- Bit32u attackAdd; //Timers for the different states of the envelope
- Bit32u decayAdd;
- Bit32u releaseAdd;
- Bit32u rateIndex; //Current position of the evenlope
-
- Bit8u rateZero; //Bits for the different states of the envelope having no changes
- Bit8u keyOn; //Bitmask of different values that can generate keyon
- //Registers, also used to check for changes
- Bit8u reg20, reg40, reg60, reg80, regE0;
- //Active part of the envelope we're in
- Bit8u state;
- //0xff when tremolo is enabled
- Bit8u tremoloMask;
- //Strength of the vibrato
- Bit8u vibStrength;
- //Keep track of the calculated KSR so we can check for changes
- Bit8u ksr;
-};
-
-struct _Channel {
- Operator op[2];
- SynthHandler synthHandler;
- Bit32u chanData; //Frequency/octave and derived values
- Bit32s old[2]; //Old data for feedback
-
- Bit8u feedback; //Feedback shift
- Bit8u regB0; //Register values to check for changes
- Bit8u regC0;
- //This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel
- Bit8u fourMask;
- Bit8s maskLeft; //Sign extended values for both channel's panning
- Bit8s maskRight;
-
-};
-
-struct _Chip {
- //This is used as the base counter for vibrato and tremolo
- Bit32u lfoCounter;
- Bit32u lfoAdd;
-
-
- Bit32u noiseCounter;
- Bit32u noiseAdd;
- Bit32u noiseValue;
-
- //Frequency scales for the different multiplications
- Bit32u freqMul[16];
- //Rates for decay and release for rate of this chip
- Bit32u linearRates[76];
- //Best match attack rates for the rate of this chip
- Bit32u attackRates[76];
-
- //18 channels with 2 operators each
- Channel chan[18];
-
- Bit8u reg104;
- Bit8u reg08;
- Bit8u reg04;
- Bit8u regBD;
- Bit8u vibratoIndex;
- Bit8u tremoloIndex;
- Bit8s vibratoSign;
- Bit8u vibratoShift;
- Bit8u tremoloValue;
- Bit8u vibratoStrength;
- Bit8u tremoloStrength;
- //Mask for allowed wave forms
- Bit8u waveFormMask;
- //0 or -1 when enabled
- Bit8s opl3Active;
-
-};
-
-/*
-struct Handler : public Adlib::Handler {
- DBOPL::Chip chip;
- virtual Bit32u WriteAddr( Bit32u port, Bit8u val );
- virtual void WriteReg( Bit32u addr, Bit8u val );
- virtual void Generate( MixerChannel* chan, Bitu samples );
- virtual void Init( Bitu rate );
-};
-*/
-
-
-void Chip__Setup(Chip *self, Bit32u rate );
-void DBOPL_InitTables( void );
-void Chip__Chip(Chip *self);
-void Chip__WriteReg(Chip *self, Bit32u reg, Bit8u val );
-void Chip__GenerateBlock2(Chip *self, Bitu total, Bit32s* output );
-void Chip__GenerateBlock3(Chip *self, Bitu total, Bit32s* output );
-
-// haleyjd 09/09/10: Not standard C.
-#ifdef _MSC_VER
-#define inline __inline
-#endif
--- /dev/null
+++ b/opl/opl3.c
@@ -1,0 +1,1430 @@
+//
+// Copyright (C) 2013-2016 Alexey Khokholov (Nuke.YKT)
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+//
+// Nuked OPL3 emulator.
+// Thanks:
+// MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh):
+// Feedback and Rhythm part calculation information.
+// forums.submarine.org.uk(carbon14, opl3):
+// Tremolo and phase generator calculation information.
+// OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
+// OPL2 ROMs.
+//
+// version: 1.7
+//
+// Changelog:
+//
+// v1.1:
+// Vibrato's sign fix.
+// v1.2:
+// Operator key fix.
+// Corrected 4-operator mode.
+// Corrected rhythm mode.
+// Some small fixes.
+// v1.2.1:
+// Small envelope generator fix.
+// Removed EX_Get function(not used)
+// v1.3:
+// Complete rewrite.
+// v1.4:
+// New envelope and waveform generator.
+// Some small fixes.
+// v1.4.1:
+// Envelope generator rate calculation fix.
+// v1.4.2:
+// Version for ZDoom.
+// v1.5:
+// Optimizations.
+// v1.6:
+// Improved emulation output.
+// v1.6.1:
+// Simple YMF289(OPL3-L) emulation.
+// v1.7:
+// Version for Chocolate Doom.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "opl3.h"
+
+#define RSM_FRAC 10
+
+// Channel types
+
+enum {
+ ch_2op = 0,
+ ch_4op = 1,
+ ch_4op2 = 2,
+ ch_drum = 3
+};
+
+// Envelope key types
+
+enum {
+ egk_norm = 0x01,
+ egk_drum = 0x02
+};
+
+
+//
+// logsin table
+//
+
+static const Bit16u logsinrom[256] = {
+ 0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471,
+ 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365,
+ 0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd,
+ 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261,
+ 0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f,
+ 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd,
+ 0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195,
+ 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166,
+ 0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c,
+ 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118,
+ 0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8,
+ 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db,
+ 0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1,
+ 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9,
+ 0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094,
+ 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081,
+ 0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070,
+ 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060,
+ 0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052,
+ 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045,
+ 0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039,
+ 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f,
+ 0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026,
+ 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e,
+ 0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017,
+ 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011,
+ 0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c,
+ 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007,
+ 0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004,
+ 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002,
+ 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001,
+ 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000
+};
+
+//
+// exp table
+//
+
+static const Bit16u exprom[256] = {
+ 0x000, 0x003, 0x006, 0x008, 0x00b, 0x00e, 0x011, 0x014,
+ 0x016, 0x019, 0x01c, 0x01f, 0x022, 0x025, 0x028, 0x02a,
+ 0x02d, 0x030, 0x033, 0x036, 0x039, 0x03c, 0x03f, 0x042,
+ 0x045, 0x048, 0x04b, 0x04e, 0x051, 0x054, 0x057, 0x05a,
+ 0x05d, 0x060, 0x063, 0x066, 0x069, 0x06c, 0x06f, 0x072,
+ 0x075, 0x078, 0x07b, 0x07e, 0x082, 0x085, 0x088, 0x08b,
+ 0x08e, 0x091, 0x094, 0x098, 0x09b, 0x09e, 0x0a1, 0x0a4,
+ 0x0a8, 0x0ab, 0x0ae, 0x0b1, 0x0b5, 0x0b8, 0x0bb, 0x0be,
+ 0x0c2, 0x0c5, 0x0c8, 0x0cc, 0x0cf, 0x0d2, 0x0d6, 0x0d9,
+ 0x0dc, 0x0e0, 0x0e3, 0x0e7, 0x0ea, 0x0ed, 0x0f1, 0x0f4,
+ 0x0f8, 0x0fb, 0x0ff, 0x102, 0x106, 0x109, 0x10c, 0x110,
+ 0x114, 0x117, 0x11b, 0x11e, 0x122, 0x125, 0x129, 0x12c,
+ 0x130, 0x134, 0x137, 0x13b, 0x13e, 0x142, 0x146, 0x149,
+ 0x14d, 0x151, 0x154, 0x158, 0x15c, 0x160, 0x163, 0x167,
+ 0x16b, 0x16f, 0x172, 0x176, 0x17a, 0x17e, 0x181, 0x185,
+ 0x189, 0x18d, 0x191, 0x195, 0x199, 0x19c, 0x1a0, 0x1a4,
+ 0x1a8, 0x1ac, 0x1b0, 0x1b4, 0x1b8, 0x1bc, 0x1c0, 0x1c4,
+ 0x1c8, 0x1cc, 0x1d0, 0x1d4, 0x1d8, 0x1dc, 0x1e0, 0x1e4,
+ 0x1e8, 0x1ec, 0x1f0, 0x1f5, 0x1f9, 0x1fd, 0x201, 0x205,
+ 0x209, 0x20e, 0x212, 0x216, 0x21a, 0x21e, 0x223, 0x227,
+ 0x22b, 0x230, 0x234, 0x238, 0x23c, 0x241, 0x245, 0x249,
+ 0x24e, 0x252, 0x257, 0x25b, 0x25f, 0x264, 0x268, 0x26d,
+ 0x271, 0x276, 0x27a, 0x27f, 0x283, 0x288, 0x28c, 0x291,
+ 0x295, 0x29a, 0x29e, 0x2a3, 0x2a8, 0x2ac, 0x2b1, 0x2b5,
+ 0x2ba, 0x2bf, 0x2c4, 0x2c8, 0x2cd, 0x2d2, 0x2d6, 0x2db,
+ 0x2e0, 0x2e5, 0x2e9, 0x2ee, 0x2f3, 0x2f8, 0x2fd, 0x302,
+ 0x306, 0x30b, 0x310, 0x315, 0x31a, 0x31f, 0x324, 0x329,
+ 0x32e, 0x333, 0x338, 0x33d, 0x342, 0x347, 0x34c, 0x351,
+ 0x356, 0x35b, 0x360, 0x365, 0x36a, 0x370, 0x375, 0x37a,
+ 0x37f, 0x384, 0x38a, 0x38f, 0x394, 0x399, 0x39f, 0x3a4,
+ 0x3a9, 0x3ae, 0x3b4, 0x3b9, 0x3bf, 0x3c4, 0x3c9, 0x3cf,
+ 0x3d4, 0x3da, 0x3df, 0x3e4, 0x3ea, 0x3ef, 0x3f5, 0x3fa
+};
+
+//
+// freq mult table multiplied by 2
+//
+// 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15
+//
+
+static const Bit8u mt[16] = {
+ 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30
+};
+
+//
+// ksl table
+//
+
+static const Bit8u kslrom[16] = {
+ 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64
+};
+
+static const Bit8u kslshift[4] = {
+ 8, 1, 2, 0
+};
+
+//
+// envelope generator constants
+//
+
+static const Bit8u eg_incstep[3][4][8] = {
+ {
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ {
+ { 0, 1, 0, 1, 0, 1, 0, 1 },
+ { 0, 1, 0, 1, 1, 1, 0, 1 },
+ { 0, 1, 1, 1, 0, 1, 1, 1 },
+ { 0, 1, 1, 1, 1, 1, 1, 1 }
+ },
+ {
+ { 1, 1, 1, 1, 1, 1, 1, 1 },
+ { 2, 2, 1, 1, 1, 1, 1, 1 },
+ { 2, 2, 1, 1, 2, 2, 1, 1 },
+ { 2, 2, 2, 2, 2, 2, 1, 1 }
+ }
+};
+
+static const Bit8u eg_incdesc[16] = {
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2
+};
+
+static const Bit8s eg_incsh[16] = {
+ 0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -1, -2
+};
+
+//
+// address decoding
+//
+
+static const Bit8s ad_slot[0x20] = {
+ 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1,
+ 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+static const Bit8u ch_slot[18] = {
+ 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32
+};
+
+//
+// Envelope generator
+//
+
+typedef Bit16s(*envelope_sinfunc)(Bit16u phase, Bit16u envelope);
+typedef void(*envelope_genfunc)(opl3_slot *slott);
+
+static Bit16s OPL3_EnvelopeCalcExp(Bit32u level)
+{
+ if (level > 0x1fff)
+ {
+ level = 0x1fff;
+ }
+ return ((exprom[(level & 0xff) ^ 0xff] | 0x400) << 1) >> (level >> 8);
+}
+
+static Bit16s OPL3_EnvelopeCalcSin0(Bit16u phase, Bit16u envelope)
+{
+ Bit16u out = 0;
+ Bit16u neg = 0;
+ phase &= 0x3ff;
+ if (phase & 0x200)
+ {
+ neg = ~0;
+ }
+ if (phase & 0x100)
+ {
+ out = logsinrom[(phase & 0xff) ^ 0xff];
+ }
+ else
+ {
+ out = logsinrom[phase & 0xff];
+ }
+ return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg;
+}
+
+static Bit16s OPL3_EnvelopeCalcSin1(Bit16u phase, Bit16u envelope)
+{
+ Bit16u out = 0;
+ phase &= 0x3ff;
+ if (phase & 0x200)
+ {
+ out = 0x1000;
+ }
+ else if (phase & 0x100)
+ {
+ out = logsinrom[(phase & 0xff) ^ 0xff];
+ }
+ else
+ {
+ out = logsinrom[phase & 0xff];
+ }
+ return OPL3_EnvelopeCalcExp(out + (envelope << 3));
+}
+
+static Bit16s OPL3_EnvelopeCalcSin2(Bit16u phase, Bit16u envelope)
+{
+ Bit16u out = 0;
+ phase &= 0x3ff;
+ if (phase & 0x100)
+ {
+ out = logsinrom[(phase & 0xff) ^ 0xff];
+ }
+ else
+ {
+ out = logsinrom[phase & 0xff];
+ }
+ return OPL3_EnvelopeCalcExp(out + (envelope << 3));
+}
+
+static Bit16s OPL3_EnvelopeCalcSin3(Bit16u phase, Bit16u envelope)
+{
+ Bit16u out = 0;
+ phase &= 0x3ff;
+ if (phase & 0x100)
+ {
+ out = 0x1000;
+ }
+ else
+ {
+ out = logsinrom[phase & 0xff];
+ }
+ return OPL3_EnvelopeCalcExp(out + (envelope << 3));
+}
+
+static Bit16s OPL3_EnvelopeCalcSin4(Bit16u phase, Bit16u envelope)
+{
+ Bit16u out = 0;
+ Bit16u neg = 0;
+ phase &= 0x3ff;
+ if ((phase & 0x300) == 0x100)
+ {
+ neg = ~0;
+ }
+ if (phase & 0x200)
+ {
+ out = 0x1000;
+ }
+ else if (phase & 0x80)
+ {
+ out = logsinrom[((phase ^ 0xff) << 1) & 0xff];
+ }
+ else
+ {
+ out = logsinrom[(phase << 1) & 0xff];
+ }
+ return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg;
+}
+
+static Bit16s OPL3_EnvelopeCalcSin5(Bit16u phase, Bit16u envelope)
+{
+ Bit16u out = 0;
+ phase &= 0x3ff;
+ if (phase & 0x200)
+ {
+ out = 0x1000;
+ }
+ else if (phase & 0x80)
+ {
+ out = logsinrom[((phase ^ 0xff) << 1) & 0xff];
+ }
+ else
+ {
+ out = logsinrom[(phase << 1) & 0xff];
+ }
+ return OPL3_EnvelopeCalcExp(out + (envelope << 3));
+}
+
+static Bit16s OPL3_EnvelopeCalcSin6(Bit16u phase, Bit16u envelope)
+{
+ Bit16u neg = 0;
+ phase &= 0x3ff;
+ if (phase & 0x200)
+ {
+ neg = ~0;
+ }
+ return OPL3_EnvelopeCalcExp(envelope << 3) ^ neg;
+}
+
+static Bit16s OPL3_EnvelopeCalcSin7(Bit16u phase, Bit16u envelope)
+{
+ Bit16u out = 0;
+ Bit16u neg = 0;
+ phase &= 0x3ff;
+ if (phase & 0x200)
+ {
+ neg = ~0;
+ phase = (phase & 0x1ff) ^ 0x1ff;
+ }
+ out = phase << 3;
+ return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg;
+}
+
+static const envelope_sinfunc envelope_sin[8] = {
+ OPL3_EnvelopeCalcSin0,
+ OPL3_EnvelopeCalcSin1,
+ OPL3_EnvelopeCalcSin2,
+ OPL3_EnvelopeCalcSin3,
+ OPL3_EnvelopeCalcSin4,
+ OPL3_EnvelopeCalcSin5,
+ OPL3_EnvelopeCalcSin6,
+ OPL3_EnvelopeCalcSin7
+};
+
+static void OPL3_EnvelopeGenOff(opl3_slot *slot);
+static void OPL3_EnvelopeGenAttack(opl3_slot *slot);
+static void OPL3_EnvelopeGenDecay(opl3_slot *slot);
+static void OPL3_EnvelopeGenSustain(opl3_slot *slot);
+static void OPL3_EnvelopeGenRelease(opl3_slot *slot);
+
+envelope_genfunc envelope_gen[5] = {
+ OPL3_EnvelopeGenOff,
+ OPL3_EnvelopeGenAttack,
+ OPL3_EnvelopeGenDecay,
+ OPL3_EnvelopeGenSustain,
+ OPL3_EnvelopeGenRelease
+};
+
+enum envelope_gen_num
+{
+ envelope_gen_num_off = 0,
+ envelope_gen_num_attack = 1,
+ envelope_gen_num_decay = 2,
+ envelope_gen_num_sustain = 3,
+ envelope_gen_num_release = 4
+};
+
+static Bit8u OPL3_EnvelopeCalcRate(opl3_slot *slot, Bit8u reg_rate)
+{
+ Bit8u rate;
+ if (reg_rate == 0x00)
+ {
+ return 0x00;
+ }
+ rate = (reg_rate << 2)
+ + (slot->reg_ksr ? slot->channel->ksv : (slot->channel->ksv >> 2));
+ if (rate > 0x3c)
+ {
+ rate = 0x3c;
+ }
+ return rate;
+}
+
+static void OPL3_EnvelopeUpdateKSL(opl3_slot *slot)
+{
+ Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2)
+ - ((0x08 - slot->channel->block) << 5);
+ if (ksl < 0)
+ {
+ ksl = 0;
+ }
+ slot->eg_ksl = (Bit8u)ksl;
+}
+
+static void OPL3_EnvelopeUpdateRate(opl3_slot *slot)
+{
+ switch (slot->eg_gen)
+ {
+ case envelope_gen_num_off:
+ case envelope_gen_num_attack:
+ slot->eg_rate = OPL3_EnvelopeCalcRate(slot, slot->reg_ar);
+ break;
+ case envelope_gen_num_decay:
+ slot->eg_rate = OPL3_EnvelopeCalcRate(slot, slot->reg_dr);
+ break;
+ case envelope_gen_num_sustain:
+ case envelope_gen_num_release:
+ slot->eg_rate = OPL3_EnvelopeCalcRate(slot, slot->reg_rr);
+ break;
+ }
+}
+
+static void OPL3_EnvelopeGenOff(opl3_slot *slot)
+{
+ slot->eg_rout = 0x1ff;
+}
+
+static void OPL3_EnvelopeGenAttack(opl3_slot *slot)
+{
+ if (slot->eg_rout == 0x00)
+ {
+ slot->eg_gen = envelope_gen_num_decay;
+ OPL3_EnvelopeUpdateRate(slot);
+ return;
+ }
+ slot->eg_rout += ((~slot->eg_rout) * slot->eg_inc) >> 3;
+ if (slot->eg_rout < 0x00)
+ {
+ slot->eg_rout = 0x00;
+ }
+}
+
+static void OPL3_EnvelopeGenDecay(opl3_slot *slot)
+{
+ if (slot->eg_rout >= slot->reg_sl << 4)
+ {
+ slot->eg_gen = envelope_gen_num_sustain;
+ OPL3_EnvelopeUpdateRate(slot);
+ return;
+ }
+ slot->eg_rout += slot->eg_inc;
+}
+
+static void OPL3_EnvelopeGenSustain(opl3_slot *slot)
+{
+ if (!slot->reg_type)
+ {
+ OPL3_EnvelopeGenRelease(slot);
+ }
+}
+
+static void OPL3_EnvelopeGenRelease(opl3_slot *slot)
+{
+ if (slot->eg_rout >= 0x1ff)
+ {
+ slot->eg_gen = envelope_gen_num_off;
+ slot->eg_rout = 0x1ff;
+ OPL3_EnvelopeUpdateRate(slot);
+ return;
+ }
+ slot->eg_rout += slot->eg_inc;
+}
+
+static void OPL3_EnvelopeCalc(opl3_slot *slot)
+{
+ Bit8u rate_h, rate_l;
+ Bit8u inc = 0;
+ rate_h = slot->eg_rate >> 2;
+ rate_l = slot->eg_rate & 3;
+ if (eg_incsh[rate_h] > 0)
+ {
+ if ((slot->chip->timer & ((1 << eg_incsh[rate_h]) - 1)) == 0)
+ {
+ inc = eg_incstep[eg_incdesc[rate_h]][rate_l]
+ [((slot->chip->timer)>> eg_incsh[rate_h]) & 0x07];
+ }
+ }
+ else
+ {
+ inc = eg_incstep[eg_incdesc[rate_h]][rate_l]
+ [slot->chip->timer & 0x07] << (-eg_incsh[rate_h]);
+ }
+ slot->eg_inc = inc;
+ slot->eg_out = slot->eg_rout + (slot->reg_tl << 2)
+ + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem;
+ envelope_gen[slot->eg_gen](slot);
+}
+
+static void OPL3_EnvelopeKeyOn(opl3_slot *slot, Bit8u type)
+{
+ if (!slot->key)
+ {
+ slot->eg_gen = envelope_gen_num_attack;
+ if ((slot->eg_rate >> 2) != 0x0f)
+ {
+ slot->eg_gen = envelope_gen_num_attack;
+ }
+ else
+ {
+ slot->eg_gen = envelope_gen_num_decay;
+ slot->eg_rout = 0x00;
+ }
+ OPL3_EnvelopeUpdateRate(slot);
+ slot->pg_phase = 0x00;
+ }
+ slot->key |= type;
+}
+
+static void OPL3_EnvelopeKeyOff(opl3_slot *slot, Bit8u type)
+{
+ if (slot->key)
+ {
+ slot->key &= (~type);
+ if (!slot->key)
+ {
+ slot->eg_gen = envelope_gen_num_release;
+ OPL3_EnvelopeUpdateRate(slot);
+ }
+ }
+}
+
+//
+// Phase Generator
+//
+
+static void OPL3_PhaseGenerate(opl3_slot *slot)
+{
+ Bit16u f_num;
+ Bit32u basefreq;
+
+ f_num = slot->channel->f_num;
+ if (slot->reg_vib)
+ {
+ Bit8s range;
+ Bit8u vibpos;
+
+ range = (f_num >> 7) & 7;
+ vibpos = slot->chip->vibpos;
+
+ if (!(vibpos & 3))
+ {
+ range = 0;
+ }
+ else if (vibpos & 1)
+ {
+ range >>= 1;
+ }
+ range >>= slot->chip->vibshift;
+
+ if (vibpos & 4)
+ {
+ range = -range;
+ }
+ f_num += range;
+ }
+ basefreq = (f_num << slot->channel->block) >> 1;
+ slot->pg_phase += (basefreq * mt[slot->reg_mult]) >> 1;
+}
+
+//
+// Noise Generator
+//
+
+static void OPL3_NoiseGenerate(opl3_chip *chip)
+{
+ if (chip->noise & 0x01)
+ {
+ chip->noise ^= 0x800302;
+ }
+ chip->noise >>= 1;
+}
+
+//
+// Slot
+//
+
+static void OPL3_SlotWrite20(opl3_slot *slot, Bit8u data)
+{
+ if ((data >> 7) & 0x01)
+ {
+ slot->trem = &slot->chip->tremolo;
+ }
+ else
+ {
+ slot->trem = (Bit8u*)&slot->chip->zeromod;
+ }
+ slot->reg_vib = (data >> 6) & 0x01;
+ slot->reg_type = (data >> 5) & 0x01;
+ slot->reg_ksr = (data >> 4) & 0x01;
+ slot->reg_mult = data & 0x0f;
+ OPL3_EnvelopeUpdateRate(slot);
+}
+
+static void OPL3_SlotWrite40(opl3_slot *slot, Bit8u data)
+{
+ slot->reg_ksl = (data >> 6) & 0x03;
+ slot->reg_tl = data & 0x3f;
+ OPL3_EnvelopeUpdateKSL(slot);
+}
+
+static void OPL3_SlotWrite60(opl3_slot *slot, Bit8u data)
+{
+ slot->reg_ar = (data >> 4) & 0x0f;
+ slot->reg_dr = data & 0x0f;
+ OPL3_EnvelopeUpdateRate(slot);
+}
+
+static void OPL3_SlotWrite80(opl3_slot *slot, Bit8u data)
+{
+ slot->reg_sl = (data >> 4) & 0x0f;
+ if (slot->reg_sl == 0x0f)
+ {
+ slot->reg_sl = 0x1f;
+ }
+ slot->reg_rr = data & 0x0f;
+ OPL3_EnvelopeUpdateRate(slot);
+}
+
+static void OPL3_SlotWriteE0(opl3_slot *slot, Bit8u data)
+{
+ slot->reg_wf = data & 0x07;
+ if (slot->chip->newm == 0x00)
+ {
+ slot->reg_wf &= 0x03;
+ }
+}
+
+static void OPL3_SlotGeneratePhase(opl3_slot *slot, Bit16u phase)
+{
+ slot->out = envelope_sin[slot->reg_wf](phase, slot->eg_out);
+}
+
+static void OPL3_SlotGenerate(opl3_slot *slot)
+{
+ OPL3_SlotGeneratePhase(slot, (Bit16u)(slot->pg_phase >> 9) + *slot->mod);
+}
+
+static void OPL3_SlotGenerateZM(opl3_slot *slot)
+{
+ OPL3_SlotGeneratePhase(slot, 0);
+}
+
+static void OPL3_SlotCalcFB(opl3_slot *slot)
+{
+ if (slot->channel->fb != 0x00)
+ {
+ slot->fbmod = (slot->prout + slot->out) >> (0x09 - slot->channel->fb);
+ }
+ else
+ {
+ slot->fbmod = 0;
+ }
+ slot->prout = slot->out;
+}
+
+//
+// Channel
+//
+
+static void OPL3_ChannelSetupAlg(opl3_channel *channel);
+
+static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data)
+{
+ opl3_channel *channel6;
+ opl3_channel *channel7;
+ opl3_channel *channel8;
+ Bit8u chnum;
+
+ chip->rhy = data & 0x3f;
+ if (chip->rhy & 0x20)
+ {
+ channel6 = &chip->channel[6];
+ channel7 = &chip->channel[7];
+ channel8 = &chip->channel[8];
+ channel6->out[0] = &channel6->slots[1]->out;
+ channel6->out[1] = &channel6->slots[1]->out;
+ channel6->out[2] = &chip->zeromod;
+ channel6->out[3] = &chip->zeromod;
+ channel7->out[0] = &channel7->slots[0]->out;
+ channel7->out[1] = &channel7->slots[0]->out;
+ channel7->out[2] = &channel7->slots[1]->out;
+ channel7->out[3] = &channel7->slots[1]->out;
+ channel8->out[0] = &channel8->slots[0]->out;
+ channel8->out[1] = &channel8->slots[0]->out;
+ channel8->out[2] = &channel8->slots[1]->out;
+ channel8->out[3] = &channel8->slots[1]->out;
+ for (chnum = 6; chnum < 9; chnum++)
+ {
+ chip->channel[chnum].chtype = ch_drum;
+ }
+ OPL3_ChannelSetupAlg(channel6);
+ //hh
+ if (chip->rhy & 0x01)
+ {
+ OPL3_EnvelopeKeyOn(channel7->slots[0], egk_drum);
+ }
+ else
+ {
+ OPL3_EnvelopeKeyOff(channel7->slots[0], egk_drum);
+ }
+ //tc
+ if (chip->rhy & 0x02)
+ {
+ OPL3_EnvelopeKeyOn(channel8->slots[1], egk_drum);
+ }
+ else
+ {
+ OPL3_EnvelopeKeyOff(channel8->slots[1], egk_drum);
+ }
+ //tom
+ if (chip->rhy & 0x04)
+ {
+ OPL3_EnvelopeKeyOn(channel8->slots[0], egk_drum);
+ }
+ else
+ {
+ OPL3_EnvelopeKeyOff(channel8->slots[0], egk_drum);
+ }
+ //sd
+ if (chip->rhy & 0x08)
+ {
+ OPL3_EnvelopeKeyOn(channel7->slots[1], egk_drum);
+ }
+ else
+ {
+ OPL3_EnvelopeKeyOff(channel7->slots[1], egk_drum);
+ }
+ //bd
+ if (chip->rhy & 0x10)
+ {
+ OPL3_EnvelopeKeyOn(channel6->slots[0], egk_drum);
+ OPL3_EnvelopeKeyOn(channel6->slots[1], egk_drum);
+ }
+ else
+ {
+ OPL3_EnvelopeKeyOff(channel6->slots[0], egk_drum);
+ OPL3_EnvelopeKeyOff(channel6->slots[1], egk_drum);
+ }
+ }
+ else
+ {
+ for (chnum = 6; chnum < 9; chnum++)
+ {
+ chip->channel[chnum].chtype = ch_2op;
+ OPL3_ChannelSetupAlg(&chip->channel[chnum]);
+ }
+ }
+}
+
+static void OPL3_ChannelWriteA0(opl3_channel *channel, Bit8u data)
+{
+ if (channel->chip->newm && channel->chtype == ch_4op2)
+ {
+ return;
+ }
+ channel->f_num = (channel->f_num & 0x300) | data;
+ channel->ksv = (channel->block << 1)
+ | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01);
+ OPL3_EnvelopeUpdateKSL(channel->slots[0]);
+ OPL3_EnvelopeUpdateKSL(channel->slots[1]);
+ OPL3_EnvelopeUpdateRate(channel->slots[0]);
+ OPL3_EnvelopeUpdateRate(channel->slots[1]);
+ if (channel->chip->newm && channel->chtype == ch_4op)
+ {
+ channel->pair->f_num = channel->f_num;
+ channel->pair->ksv = channel->ksv;
+ OPL3_EnvelopeUpdateKSL(channel->pair->slots[0]);
+ OPL3_EnvelopeUpdateKSL(channel->pair->slots[1]);
+ OPL3_EnvelopeUpdateRate(channel->pair->slots[0]);
+ OPL3_EnvelopeUpdateRate(channel->pair->slots[1]);
+ }
+}
+
+static void OPL3_ChannelWriteB0(opl3_channel *channel, Bit8u data)
+{
+ if (channel->chip->newm && channel->chtype == ch_4op2)
+ {
+ return;
+ }
+ channel->f_num = (channel->f_num & 0xff) | ((data & 0x03) << 8);
+ channel->block = (data >> 2) & 0x07;
+ channel->ksv = (channel->block << 1)
+ | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01);
+ OPL3_EnvelopeUpdateKSL(channel->slots[0]);
+ OPL3_EnvelopeUpdateKSL(channel->slots[1]);
+ OPL3_EnvelopeUpdateRate(channel->slots[0]);
+ OPL3_EnvelopeUpdateRate(channel->slots[1]);
+ if (channel->chip->newm && channel->chtype == ch_4op)
+ {
+ channel->pair->f_num = channel->f_num;
+ channel->pair->block = channel->block;
+ channel->pair->ksv = channel->ksv;
+ OPL3_EnvelopeUpdateKSL(channel->pair->slots[0]);
+ OPL3_EnvelopeUpdateKSL(channel->pair->slots[1]);
+ OPL3_EnvelopeUpdateRate(channel->pair->slots[0]);
+ OPL3_EnvelopeUpdateRate(channel->pair->slots[1]);
+ }
+}
+
+static void OPL3_ChannelSetupAlg(opl3_channel *channel)
+{
+ if (channel->chtype == ch_drum)
+ {
+ switch (channel->alg & 0x01)
+ {
+ case 0x00:
+ channel->slots[0]->mod = &channel->slots[0]->fbmod;
+ channel->slots[1]->mod = &channel->slots[0]->out;
+ break;
+ case 0x01:
+ channel->slots[0]->mod = &channel->slots[0]->fbmod;
+ channel->slots[1]->mod = &channel->chip->zeromod;
+ break;
+ }
+ return;
+ }
+ if (channel->alg & 0x08)
+ {
+ return;
+ }
+ if (channel->alg & 0x04)
+ {
+ channel->pair->out[0] = &channel->chip->zeromod;
+ channel->pair->out[1] = &channel->chip->zeromod;
+ channel->pair->out[2] = &channel->chip->zeromod;
+ channel->pair->out[3] = &channel->chip->zeromod;
+ switch (channel->alg & 0x03)
+ {
+ case 0x00:
+ channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod;
+ channel->pair->slots[1]->mod = &channel->pair->slots[0]->out;
+ channel->slots[0]->mod = &channel->pair->slots[1]->out;
+ channel->slots[1]->mod = &channel->slots[0]->out;
+ channel->out[0] = &channel->slots[1]->out;
+ channel->out[1] = &channel->chip->zeromod;
+ channel->out[2] = &channel->chip->zeromod;
+ channel->out[3] = &channel->chip->zeromod;
+ break;
+ case 0x01:
+ channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod;
+ channel->pair->slots[1]->mod = &channel->pair->slots[0]->out;
+ channel->slots[0]->mod = &channel->chip->zeromod;
+ channel->slots[1]->mod = &channel->slots[0]->out;
+ channel->out[0] = &channel->pair->slots[1]->out;
+ channel->out[1] = &channel->slots[1]->out;
+ channel->out[2] = &channel->chip->zeromod;
+ channel->out[3] = &channel->chip->zeromod;
+ break;
+ case 0x02:
+ channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod;
+ channel->pair->slots[1]->mod = &channel->chip->zeromod;
+ channel->slots[0]->mod = &channel->pair->slots[1]->out;
+ channel->slots[1]->mod = &channel->slots[0]->out;
+ channel->out[0] = &channel->pair->slots[0]->out;
+ channel->out[1] = &channel->slots[1]->out;
+ channel->out[2] = &channel->chip->zeromod;
+ channel->out[3] = &channel->chip->zeromod;
+ break;
+ case 0x03:
+ channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod;
+ channel->pair->slots[1]->mod = &channel->chip->zeromod;
+ channel->slots[0]->mod = &channel->pair->slots[1]->out;
+ channel->slots[1]->mod = &channel->chip->zeromod;
+ channel->out[0] = &channel->pair->slots[0]->out;
+ channel->out[1] = &channel->slots[0]->out;
+ channel->out[2] = &channel->slots[1]->out;
+ channel->out[3] = &channel->chip->zeromod;
+ break;
+ }
+ }
+ else
+ {
+ switch (channel->alg & 0x01)
+ {
+ case 0x00:
+ channel->slots[0]->mod = &channel->slots[0]->fbmod;
+ channel->slots[1]->mod = &channel->slots[0]->out;
+ channel->out[0] = &channel->slots[1]->out;
+ channel->out[1] = &channel->chip->zeromod;
+ channel->out[2] = &channel->chip->zeromod;
+ channel->out[3] = &channel->chip->zeromod;
+ break;
+ case 0x01:
+ channel->slots[0]->mod = &channel->slots[0]->fbmod;
+ channel->slots[1]->mod = &channel->chip->zeromod;
+ channel->out[0] = &channel->slots[0]->out;
+ channel->out[1] = &channel->slots[1]->out;
+ channel->out[2] = &channel->chip->zeromod;
+ channel->out[3] = &channel->chip->zeromod;
+ break;
+ }
+ }
+}
+
+static void OPL3_ChannelWriteC0(opl3_channel *channel, Bit8u data)
+{
+ channel->fb = (data & 0x0e) >> 1;
+ channel->con = data & 0x01;
+ channel->alg = channel->con;
+ if (channel->chip->newm)
+ {
+ if (channel->chtype == ch_4op)
+ {
+ channel->pair->alg = 0x04 | (channel->con << 1) | (channel->pair->con);
+ channel->alg = 0x08;
+ OPL3_ChannelSetupAlg(channel->pair);
+ }
+ else if (channel->chtype == ch_4op2)
+ {
+ channel->alg = 0x04 | (channel->pair->con << 1) | (channel->con);
+ channel->pair->alg = 0x08;
+ OPL3_ChannelSetupAlg(channel);
+ }
+ else
+ {
+ OPL3_ChannelSetupAlg(channel);
+ }
+ }
+ else
+ {
+ OPL3_ChannelSetupAlg(channel);
+ }
+ if (channel->chip->newm)
+ {
+ channel->cha = ((data >> 4) & 0x01) ? ~0 : 0;
+ channel->chb = ((data >> 5) & 0x01) ? ~0 : 0;
+ }
+ else
+ {
+ channel->cha = channel->chb = ~0;
+ }
+}
+
+static void OPL3_ChannelKeyOn(opl3_channel *channel)
+{
+ if (channel->chip->newm)
+ {
+ if (channel->chtype == ch_4op)
+ {
+ OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm);
+ OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm);
+ OPL3_EnvelopeKeyOn(channel->pair->slots[0], egk_norm);
+ OPL3_EnvelopeKeyOn(channel->pair->slots[1], egk_norm);
+ }
+ else if (channel->chtype == ch_2op || channel->chtype == ch_drum)
+ {
+ OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm);
+ OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm);
+ }
+ }
+ else
+ {
+ OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm);
+ OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm);
+ }
+}
+
+static void OPL3_ChannelKeyOff(opl3_channel *channel)
+{
+ if (channel->chip->newm)
+ {
+ if (channel->chtype == ch_4op)
+ {
+ OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm);
+ OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm);
+ OPL3_EnvelopeKeyOff(channel->pair->slots[0], egk_norm);
+ OPL3_EnvelopeKeyOff(channel->pair->slots[1], egk_norm);
+ }
+ else if (channel->chtype == ch_2op || channel->chtype == ch_drum)
+ {
+ OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm);
+ OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm);
+ }
+ }
+ else
+ {
+ OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm);
+ OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm);
+ }
+}
+
+static void OPL3_ChannelSet4Op(opl3_chip *chip, Bit8u data)
+{
+ Bit8u bit;
+ Bit8u chnum;
+ for (bit = 0; bit < 6; bit++)
+ {
+ chnum = bit;
+ if (bit >= 3)
+ {
+ chnum += 9 - 3;
+ }
+ if ((data >> bit) & 0x01)
+ {
+ chip->channel[chnum].chtype = ch_4op;
+ chip->channel[chnum + 3].chtype = ch_4op2;
+ }
+ else
+ {
+ chip->channel[chnum].chtype = ch_2op;
+ chip->channel[chnum + 3].chtype = ch_2op;
+ }
+ }
+}
+
+static Bit16s OPL3_ClipSample(Bit32s sample)
+{
+ if (sample > 32767)
+ {
+ sample = 32767;
+ }
+ else if (sample < -32768)
+ {
+ sample = -32768;
+ }
+ return (Bit16s)sample;
+}
+
+static void OPL3_GenerateRhythm1(opl3_chip *chip)
+{
+ opl3_channel *channel6;
+ opl3_channel *channel7;
+ opl3_channel *channel8;
+ Bit16u phase14;
+ Bit16u phase17;
+ Bit16u phase;
+ Bit16u phasebit;
+
+ channel6 = &chip->channel[6];
+ channel7 = &chip->channel[7];
+ channel8 = &chip->channel[8];
+ OPL3_SlotGenerate(channel6->slots[0]);
+ phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff;
+ phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff;
+ phase = 0x00;
+ //hh tc phase bit
+ phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04)
+ | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00;
+ //hh
+ phase = (phasebit << 9)
+ | (0x34 << ((phasebit ^ (chip->noise & 0x01) << 1)));
+ OPL3_SlotGeneratePhase(channel7->slots[0], phase);
+ //tt
+ OPL3_SlotGenerateZM(channel8->slots[0]);
+}
+
+static void OPL3_GenerateRhythm2(opl3_chip *chip)
+{
+ opl3_channel *channel6;
+ opl3_channel *channel7;
+ opl3_channel *channel8;
+ Bit16u phase14;
+ Bit16u phase17;
+ Bit16u phase;
+ Bit16u phasebit;
+
+ channel6 = &chip->channel[6];
+ channel7 = &chip->channel[7];
+ channel8 = &chip->channel[8];
+ OPL3_SlotGenerate(channel6->slots[1]);
+ phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff;
+ phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff;
+ phase = 0x00;
+ //hh tc phase bit
+ phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04)
+ | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00;
+ //sd
+ phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8);
+ OPL3_SlotGeneratePhase(channel7->slots[1], phase);
+ //tc
+ phase = 0x100 | (phasebit << 9);
+ OPL3_SlotGeneratePhase(channel8->slots[1], phase);
+}
+
+void OPL3_Generate(opl3_chip *chip, Bit16s *buf)
+{
+ Bit8u ii;
+ Bit8u jj;
+ Bit16s accm;
+
+ buf[1] = OPL3_ClipSample(chip->mixbuff[1]);
+
+ for (ii = 0; ii < 12; ii++)
+ {
+ OPL3_SlotCalcFB(&chip->slot[ii]);
+ OPL3_PhaseGenerate(&chip->slot[ii]);
+ OPL3_EnvelopeCalc(&chip->slot[ii]);
+ OPL3_SlotGenerate(&chip->slot[ii]);
+ }
+
+ for (ii = 12; ii < 15; ii++)
+ {
+ OPL3_SlotCalcFB(&chip->slot[ii]);
+ OPL3_PhaseGenerate(&chip->slot[ii]);
+ OPL3_EnvelopeCalc(&chip->slot[ii]);
+ }
+
+ if (chip->rhy & 0x20)
+ {
+ OPL3_GenerateRhythm1(chip);
+ }
+ else
+ {
+ OPL3_SlotGenerate(&chip->slot[12]);
+ OPL3_SlotGenerate(&chip->slot[13]);
+ OPL3_SlotGenerate(&chip->slot[14]);
+ }
+
+ chip->mixbuff[0] = 0;
+ for (ii = 0; ii < 18; ii++)
+ {
+ accm = 0;
+ for (jj = 0; jj < 4; jj++)
+ {
+ accm += *chip->channel[ii].out[jj];
+ }
+ chip->mixbuff[0] += (Bit16s)(accm & chip->channel[ii].cha);
+ }
+
+ for (ii = 15; ii < 18; ii++)
+ {
+ OPL3_SlotCalcFB(&chip->slot[ii]);
+ OPL3_PhaseGenerate(&chip->slot[ii]);
+ OPL3_EnvelopeCalc(&chip->slot[ii]);
+ }
+
+ if (chip->rhy & 0x20)
+ {
+ OPL3_GenerateRhythm2(chip);
+ }
+ else
+ {
+ OPL3_SlotGenerate(&chip->slot[15]);
+ OPL3_SlotGenerate(&chip->slot[16]);
+ OPL3_SlotGenerate(&chip->slot[17]);
+ }
+
+ buf[0] = OPL3_ClipSample(chip->mixbuff[0]);
+
+ for (ii = 18; ii < 33; ii++)
+ {
+ OPL3_SlotCalcFB(&chip->slot[ii]);
+ OPL3_PhaseGenerate(&chip->slot[ii]);
+ OPL3_EnvelopeCalc(&chip->slot[ii]);
+ OPL3_SlotGenerate(&chip->slot[ii]);
+ }
+
+ chip->mixbuff[1] = 0;
+ for (ii = 0; ii < 18; ii++)
+ {
+ accm = 0;
+ for (jj = 0; jj < 4; jj++)
+ {
+ accm += *chip->channel[ii].out[jj];
+ }
+ chip->mixbuff[1] += (Bit16s)(accm & chip->channel[ii].chb);
+ }
+
+ for (ii = 33; ii < 36; ii++)
+ {
+ OPL3_SlotCalcFB(&chip->slot[ii]);
+ OPL3_PhaseGenerate(&chip->slot[ii]);
+ OPL3_EnvelopeCalc(&chip->slot[ii]);
+ OPL3_SlotGenerate(&chip->slot[ii]);
+ }
+
+ OPL3_NoiseGenerate(chip);
+
+ if ((chip->timer & 0x3f) == 0x3f)
+ {
+ chip->tremolopos = (chip->tremolopos + 1) % 210;
+ if (chip->tremolopos < 105)
+ {
+ chip->tremolo = chip->tremolopos >> chip->tremoloshift;
+ }
+ else
+ {
+ chip->tremolo = (210 - chip->tremolopos) >> chip->tremoloshift;
+ }
+ }
+
+ if ((chip->timer & 0x3ff) == 0x3ff)
+ {
+ chip->vibpos = (chip->vibpos + 1) & 7;
+ }
+
+ chip->timer++;
+
+ while (chip->writebuf_cur != chip->writebuf_last
+ && chip->writebuf[chip->writebuf_cur].time <= chip->writebuf_samplecnt)
+ {
+ OPL3_WriteReg(chip, chip->writebuf[chip->writebuf_cur].reg,
+ chip->writebuf[chip->writebuf_cur].data);
+ chip->writebuf_cur = (chip->writebuf_cur + 1) % OPL_WRITEBUF_SIZE;
+ }
+ chip->writebuf_samplecnt++;
+}
+
+void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf)
+{
+ while (chip->samplecnt >= chip->rateratio)
+ {
+ chip->oldsamples[0] = chip->samples[0];
+ chip->oldsamples[1] = chip->samples[1];
+ OPL3_Generate(chip, chip->samples);
+ chip->samplecnt -= chip->rateratio;
+ }
+ buf[0] = (Bit16s)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt)
+ + chip->samples[0] * chip->samplecnt) / chip->rateratio);
+ buf[1] = (Bit16s)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt)
+ + chip->samples[1] * chip->samplecnt) / chip->rateratio);
+ chip->samplecnt += 1 << RSM_FRAC;
+}
+
+void OPL3_Reset(opl3_chip *chip, Bit32u samplerate)
+{
+ Bit8u slotnum;
+ Bit8u channum;
+
+ memset(chip, 0, sizeof(opl3_chip));
+ for (slotnum = 0; slotnum < 36; slotnum++)
+ {
+ chip->slot[slotnum].chip = chip;
+ chip->slot[slotnum].mod = &chip->zeromod;
+ chip->slot[slotnum].eg_rout = 0x1ff;
+ chip->slot[slotnum].eg_out = 0x1ff;
+ chip->slot[slotnum].eg_gen = envelope_gen_num_off;
+ chip->slot[slotnum].trem = (Bit8u*)&chip->zeromod;
+ }
+ for (channum = 0; channum < 18; channum++)
+ {
+ chip->channel[channum].slots[0] = &chip->slot[ch_slot[channum]];
+ chip->channel[channum].slots[1] = &chip->slot[ch_slot[channum] + 3];
+ chip->slot[ch_slot[channum]].channel = &chip->channel[channum];
+ chip->slot[ch_slot[channum] + 3].channel = &chip->channel[channum];
+ if ((channum % 9) < 3)
+ {
+ chip->channel[channum].pair = &chip->channel[channum + 3];
+ }
+ else if ((channum % 9) < 6)
+ {
+ chip->channel[channum].pair = &chip->channel[channum - 3];
+ }
+ chip->channel[channum].chip = chip;
+ chip->channel[channum].out[0] = &chip->zeromod;
+ chip->channel[channum].out[1] = &chip->zeromod;
+ chip->channel[channum].out[2] = &chip->zeromod;
+ chip->channel[channum].out[3] = &chip->zeromod;
+ chip->channel[channum].chtype = ch_2op;
+ chip->channel[channum].cha = ~0;
+ chip->channel[channum].chb = ~0;
+ OPL3_ChannelSetupAlg(&chip->channel[channum]);
+ }
+ chip->noise = 0x306600;
+ chip->rateratio = (samplerate << RSM_FRAC) / 49716;
+}
+
+void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v)
+{
+ Bit8u high = (reg >> 8) & 0x01;
+ Bit8u regm = reg & 0xff;
+ switch (regm & 0xf0)
+ {
+ case 0x00:
+ if (high)
+ {
+ switch (regm & 0x0f)
+ {
+ case 0x04:
+ OPL3_ChannelSet4Op(chip, v);
+ break;
+ case 0x05:
+ chip->newm = v & 0x01;
+ break;
+ }
+ }
+ else
+ {
+ switch (regm & 0x0f)
+ {
+ case 0x08:
+ chip->nts = (v >> 6) & 0x01;
+ break;
+ }
+ }
+ break;
+ case 0x20:
+ case 0x30:
+ if (ad_slot[regm & 0x1f] >= 0)
+ {
+ OPL3_SlotWrite20(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v);
+ }
+ break;
+ case 0x40:
+ case 0x50:
+ if (ad_slot[regm & 0x1f] >= 0)
+ {
+ OPL3_SlotWrite40(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v);
+ }
+ break;
+ case 0x60:
+ case 0x70:
+ if (ad_slot[regm & 0x1f] >= 0)
+ {
+ OPL3_SlotWrite60(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v);
+ }
+ break;
+ case 0x80:
+ case 0x90:
+ if (ad_slot[regm & 0x1f] >= 0)
+ {
+ OPL3_SlotWrite80(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v);
+ }
+ break;
+ case 0xe0:
+ case 0xf0:
+ if (ad_slot[regm & 0x1f] >= 0)
+ {
+ OPL3_SlotWriteE0(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v);
+ }
+ break;
+ case 0xa0:
+ if ((regm & 0x0f) < 9)
+ {
+ OPL3_ChannelWriteA0(&chip->channel[9 * high + (regm & 0x0f)], v);
+ }
+ break;
+ case 0xb0:
+ if (regm == 0xbd && !high)
+ {
+ chip->tremoloshift = (((v >> 7) ^ 1) << 1) + 2;
+ chip->vibshift = ((v >> 6) & 0x01) ^ 1;
+ OPL3_ChannelUpdateRhythm(chip, v);
+ }
+ else if ((regm & 0x0f) < 9)
+ {
+ OPL3_ChannelWriteB0(&chip->channel[9 * high + (regm & 0x0f)], v);
+ if (v & 0x20)
+ {
+ OPL3_ChannelKeyOn(&chip->channel[9 * high + (regm & 0x0f)]);
+ }
+ else
+ {
+ OPL3_ChannelKeyOff(&chip->channel[9 * high + (regm & 0x0f)]);
+ }
+ }
+ break;
+ case 0xc0:
+ if ((regm & 0x0f) < 9)
+ {
+ OPL3_ChannelWriteC0(&chip->channel[9 * high + (regm & 0x0f)], v);
+ }
+ break;
+ }
+}
+
+void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v)
+{
+ Bit64u time1, time2;
+ chip->writebuf[chip->writebuf_last % OPL_WRITEBUF_SIZE].reg = reg;
+ chip->writebuf[chip->writebuf_last % OPL_WRITEBUF_SIZE].data = v;
+ time1 = chip->writebuf_lasttime + OPL_WRITEBUF_DELAY;
+ time2 = chip->writebuf_samplecnt;
+
+ if (time1 < time2)
+ {
+ time1 = time2;
+ }
+
+ chip->writebuf[chip->writebuf_last % OPL_WRITEBUF_SIZE].time = time1;
+ chip->writebuf_lasttime = time1;
+ chip->writebuf_last = (chip->writebuf_last + 1) % OPL_WRITEBUF_SIZE;
+}
+
+void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples)
+{
+ Bit32u i;
+
+ for(i = 0; i < numsamples; i++)
+ {
+ OPL3_GenerateResampled(chip, sndptr);
+ sndptr += 2;
+ }
+}
--- /dev/null
+++ b/opl/opl3.h
@@ -1,0 +1,135 @@
+//
+// Copyright (C) 2013-2016 Alexey Khokholov (Nuke.YKT)
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+//
+// Nuked OPL3 emulator.
+// Thanks:
+// MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh):
+// Feedback and Rhythm part calculation information.
+// forums.submarine.org.uk(carbon14, opl3):
+// Tremolo and phase generator calculation information.
+// OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
+// OPL2 ROMs.
+//
+// version: 1.7
+//
+
+#ifndef OPL_OPL3_H
+#define OPL_OPL3_H
+
+#include <inttypes.h>
+
+#define OPL_WRITEBUF_SIZE 1024
+#define OPL_WRITEBUF_DELAY 2
+
+typedef uintptr_t Bitu;
+typedef intptr_t Bits;
+typedef uint64_t Bit64u;
+typedef int64_t Bit64s;
+typedef uint32_t Bit32u;
+typedef int32_t Bit32s;
+typedef uint16_t Bit16u;
+typedef int16_t Bit16s;
+typedef uint8_t Bit8u;
+typedef int8_t Bit8s;
+
+typedef struct _opl3_slot opl3_slot;
+typedef struct _opl3_channel opl3_channel;
+typedef struct _opl3_chip opl3_chip;
+
+struct _opl3_slot {
+ opl3_channel *channel;
+ opl3_chip *chip;
+ Bit16s out;
+ Bit16s fbmod;
+ Bit16s *mod;
+ Bit16s prout;
+ Bit16s eg_rout;
+ Bit16s eg_out;
+ Bit8u eg_inc;
+ Bit8u eg_gen;
+ Bit8u eg_rate;
+ Bit8u eg_ksl;
+ Bit8u *trem;
+ Bit8u reg_vib;
+ Bit8u reg_type;
+ Bit8u reg_ksr;
+ Bit8u reg_mult;
+ Bit8u reg_ksl;
+ Bit8u reg_tl;
+ Bit8u reg_ar;
+ Bit8u reg_dr;
+ Bit8u reg_sl;
+ Bit8u reg_rr;
+ Bit8u reg_wf;
+ Bit8u key;
+ Bit32u pg_phase;
+ Bit32u timer;
+};
+
+struct _opl3_channel {
+ opl3_slot *slots[2];
+ opl3_channel *pair;
+ opl3_chip *chip;
+ Bit16s *out[4];
+ Bit8u chtype;
+ Bit16u f_num;
+ Bit8u block;
+ Bit8u fb;
+ Bit8u con;
+ Bit8u alg;
+ Bit8u ksv;
+ Bit16u cha, chb;
+};
+
+typedef struct _opl3_writebuf {
+ Bit64u time;
+ Bit16u reg;
+ Bit8u data;
+} opl3_writebuf;
+
+struct _opl3_chip {
+ opl3_channel channel[18];
+ opl3_slot slot[36];
+ Bit16u timer;
+ Bit8u newm;
+ Bit8u nts;
+ Bit8u rhy;
+ Bit8u vibpos;
+ Bit8u vibshift;
+ Bit8u tremolo;
+ Bit8u tremolopos;
+ Bit8u tremoloshift;
+ Bit32u noise;
+ Bit16s zeromod;
+ Bit32s mixbuff[2];
+ //OPL3L
+ Bit32s rateratio;
+ Bit32s samplecnt;
+ Bit16s oldsamples[2];
+ Bit16s samples[2];
+
+ Bit64u writebuf_samplecnt;
+ Bit32u writebuf_cur;
+ Bit32u writebuf_last;
+ Bit64u writebuf_lasttime;
+ opl3_writebuf writebuf[OPL_WRITEBUF_SIZE];
+};
+
+void OPL3_Generate(opl3_chip *chip, Bit16s *buf);
+void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf);
+void OPL3_Reset(opl3_chip *chip, Bit32u samplerate);
+void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v);
+void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v);
+void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples);
+#endif
--- a/opl/opl_sdl.c
+++ b/opl/opl_sdl.c
@@ -25,7 +25,7 @@
#include "SDL.h"
#include "SDL_mixer.h"
-#include "dbopl.h"
+#include "opl3.h"
#include "opl.h"
#include "opl_internal.h"
@@ -70,7 +70,7 @@
// OPL software emulator structure.
-static Chip opl_chip;
+static opl3_chip opl_chip;
static int opl_opl3mode;
// Temporary mixing buffer used by the mixing callback.
@@ -165,30 +165,7 @@
assert(nsamples < mixing_freq);
- if (opl_opl3mode)
- {
- Chip__GenerateBlock3(&opl_chip, nsamples, mix_buffer);
-
- // Mix into the destination buffer, doubling up into stereo.
-
- for (i=0; i<nsamples; ++i)
- {
- buffer[i * 2] = (int16_t) mix_buffer[i * 2];
- buffer[i * 2 + 1] = (int16_t) mix_buffer[i * 2 + 1];
- }
- }
- else
- {
- Chip__GenerateBlock2(&opl_chip, nsamples, mix_buffer);
-
- // Mix into the destination buffer, doubling up into stereo.
-
- for (i=0; i<nsamples; ++i)
- {
- buffer[i * 2] = (int16_t) mix_buffer[i];
- buffer[i * 2 + 1] = (int16_t) mix_buffer[i];
- }
- }
+ OPL3_GenerateStream(&opl_chip, buffer, nsamples);
}
// Callback function to fill a new sound buffer:
@@ -371,9 +348,7 @@
// Create the emulator structure:
- DBOPL_InitTables();
- Chip__Chip(&opl_chip);
- Chip__Setup(&opl_chip, mixing_freq);
+ OPL3_Reset(&opl_chip, mixing_freq);
opl_opl3mode = 0;
callback_mutex = SDL_CreateMutex();
@@ -465,7 +440,7 @@
opl_opl3mode = value & 0x01;
default:
- Chip__WriteReg(&opl_chip, reg_num, value);
+ OPL3_WriteRegBuffered(&opl_chip, reg_num, value);
break;
}
}