Fix dual speed in percussion mode
Use noise calculation like in MAME Run the generator in same tremolo/vibrato blocks for more speed Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@3382
This commit is contained in:
parent
a14636aea0
commit
445eeda8f7
2 changed files with 207 additions and 144 deletions
|
@ -27,8 +27,7 @@
|
|||
//TODO Don't delay first operator 1 sample in opl3 mode
|
||||
//TODO Maybe not use class method pointers but a regular function pointers with operator as first parameter
|
||||
//TODO Fix panning for the Percussion channels, would any opl3 player use it and actually really change it though?
|
||||
//TODO don't use variables in work structure for tremolo and vibrato but give the variables as parameters to GetSample
|
||||
//TODO Since the vibrato takes 1024 samples it's easier to run the emulator in same vibrato chunks, vibrato would be costfree
|
||||
//TODO Check if having the same accuracy in all frequency multipliers sounds better or not
|
||||
|
||||
//DUNNO Keyon in 4op, switch to 2op without keyoff.
|
||||
*/
|
||||
|
@ -47,22 +46,31 @@
|
|||
|
||||
namespace DBOPL {
|
||||
|
||||
#define MAX_SAMPLES 256
|
||||
#define OPLRATE ((double)(14318180.0 / 288.0))
|
||||
|
||||
//Only need 4 valid bits at the top for vibrato
|
||||
#define VIBRATO_SH ( 32 - 4 )
|
||||
//Need 6 bits of accuracy
|
||||
#define TREMOLO_SH ( 32 - 6 )
|
||||
#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 12.20
|
||||
//Have to keep some bits in the top to allow for freqmul 0.5
|
||||
#define WAVE_BITS 12
|
||||
//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 )
|
||||
|
@ -271,21 +279,6 @@ static const WaveHandler WaveHandlerTable[8] = {
|
|||
|
||||
#endif
|
||||
|
||||
//Structto hold the data everything well yeh works with
|
||||
static struct {
|
||||
Bitu samples;
|
||||
Bits vibrato;
|
||||
Bits tremolo;
|
||||
inline void SetVibrato( Bit8s vib ) {
|
||||
vibrato = vib;
|
||||
vibrato &= ~0x80;
|
||||
}
|
||||
Bit32s output[MAX_SAMPLES * 2];
|
||||
//Could intermix the vib/trem table for slightly better cache hits
|
||||
Bit8s vibTable[MAX_SAMPLES];
|
||||
Bit8s tremTable[MAX_SAMPLES];
|
||||
} Work;
|
||||
|
||||
/*
|
||||
Operator
|
||||
*/
|
||||
|
@ -343,11 +336,20 @@ inline void Operator::UpdateAttenuation( ) {
|
|||
void Operator::UpdateFrequency( ) {
|
||||
Bit32u freq = chanData & (( 1 << 10 ) - 1);
|
||||
Bit32u block = (chanData >> 10) & 0xff;
|
||||
|
||||
waveAdd = (freq << block) * freqMul;
|
||||
#ifdef WAVE_PRECISION
|
||||
block = 7 - block;
|
||||
waveAdd = ( freq * freqMul ) >> block;
|
||||
#else
|
||||
waveAdd = ( freq << block ) * freqMul;
|
||||
#endif
|
||||
if ( reg20 & MASK_VIBRATO ) {
|
||||
vibStrength = (Bit8u)(freq >> 7);
|
||||
|
||||
#ifdef WAVE_PRECISION
|
||||
vibrato = ( vibStrength * freqMul ) >> block;
|
||||
#else
|
||||
vibrato = ( vibStrength << block ) * freqMul;
|
||||
#endif
|
||||
} else {
|
||||
vibStrength = 0;
|
||||
vibrato = 0;
|
||||
|
@ -378,7 +380,7 @@ INLINE Bit32s Operator::RateForward( Bit32u add ) {
|
|||
|
||||
template< Operator::State yes>
|
||||
Bits Operator::TemplateVolume( ) {
|
||||
Bit32s vol = activeLevel;
|
||||
Bit32s vol = volume;
|
||||
Bit32s change;
|
||||
switch ( yes ) {
|
||||
case OFF:
|
||||
|
@ -389,7 +391,7 @@ Bits Operator::TemplateVolume( ) {
|
|||
return vol;
|
||||
vol += ( (~vol) * change ) >> 3;
|
||||
if ( vol < ENV_MIN ) {
|
||||
activeLevel = ENV_MIN;
|
||||
volume = ENV_MIN;
|
||||
rateIndex = 0;
|
||||
SetState( DECAY );
|
||||
return ENV_MIN;
|
||||
|
@ -400,7 +402,7 @@ Bits Operator::TemplateVolume( ) {
|
|||
if ( vol >= sustainLevel ) {
|
||||
//Check if we didn't overshoot max attenuation, then just go off
|
||||
if ( vol >= ENV_MAX ) {
|
||||
activeLevel = ENV_MAX;
|
||||
volume = ENV_MAX;
|
||||
SetState( OFF );
|
||||
return ENV_MAX;
|
||||
}
|
||||
|
@ -417,13 +419,13 @@ Bits Operator::TemplateVolume( ) {
|
|||
case RELEASE:
|
||||
vol += RateForward( releaseAdd );;
|
||||
if ( vol >= ENV_MAX ) {
|
||||
activeLevel = ENV_MAX;
|
||||
volume = ENV_MAX;
|
||||
SetState( OFF );
|
||||
return ENV_MAX;
|
||||
}
|
||||
break;
|
||||
}
|
||||
activeLevel = vol;
|
||||
volume = vol;
|
||||
return vol;
|
||||
}
|
||||
|
||||
|
@ -436,31 +438,15 @@ static const VolumeHandler VolumeHandlerTable[5] = {
|
|||
};
|
||||
|
||||
INLINE Bitu Operator::ForwardVolume() {
|
||||
return totalLevel + (this->*volHandler)()
|
||||
#if defined ( DBOPL_TREMOLO )
|
||||
+ (Work.tremolo & tremoloMask)
|
||||
#endif
|
||||
;
|
||||
return currentLevel + (this->*volHandler)();
|
||||
}
|
||||
|
||||
|
||||
INLINE Bitu Operator::ForwardWave() {
|
||||
#if defined ( DBOPL_VIBRATO )
|
||||
if ( vibStrength >> (Bit8u)(Work.vibrato) ) {
|
||||
Bit32s add = vibrato >> (Bit8u)(Work.vibrato);
|
||||
//Sign extend over the shift value
|
||||
Bit32s neg = Work.vibrato >> 16;
|
||||
//Negate the add with -1 or 0
|
||||
add = ( add ^ neg ) - neg;
|
||||
waveIndex += add + waveAdd;
|
||||
return waveIndex >> WAVE_SH;
|
||||
}
|
||||
#endif
|
||||
waveIndex += waveAdd;
|
||||
waveIndex += waveCurrent;
|
||||
return waveIndex >> WAVE_SH;
|
||||
}
|
||||
|
||||
|
||||
void Operator::Write20( const Chip* chip, Bit8u val ) {
|
||||
Bit8u change = (reg20 ^ val );
|
||||
if ( !change )
|
||||
|
@ -539,12 +525,25 @@ INLINE void Operator::SetState( Bit8u s ) {
|
|||
}
|
||||
|
||||
INLINE bool Operator::Silent() const {
|
||||
if ( !ENV_SILENT( totalLevel + activeLevel ) )
|
||||
if ( !ENV_SILENT( totalLevel + volume ) )
|
||||
return false;
|
||||
if ( !(rateZero & ( 1 << state ) ) )
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
INLINE void Operator::Prepare( const Chip* chip ) {
|
||||
currentLevel = totalLevel + (chip->tremoloValue & tremoloMask);
|
||||
waveCurrent = waveAdd;
|
||||
if ( vibStrength >> chip->vibratoShift ) {
|
||||
Bit32s add = vibrato >> chip->vibratoShift;
|
||||
//Sign extend over the shift value
|
||||
Bit32s neg = chip->vibratoSign;
|
||||
//Negate the add with -1 or 0
|
||||
add = ( add ^ neg ) - neg;
|
||||
waveCurrent += add;
|
||||
}
|
||||
}
|
||||
|
||||
void Operator::KeyOn( Bit8u mask ) {
|
||||
if ( !keyOn ) {
|
||||
|
@ -590,7 +589,7 @@ Bits INLINE Operator::GetSample( Bits modulation ) {
|
|||
Bitu vol = ForwardVolume();
|
||||
if ( ENV_SILENT( vol ) ) {
|
||||
//Simply forward the wave
|
||||
waveIndex += waveAdd;
|
||||
waveIndex += waveCurrent;
|
||||
return 0;
|
||||
} else {
|
||||
Bitu index = ForwardWave();
|
||||
|
@ -604,6 +603,7 @@ Operator::Operator() {
|
|||
freqMul = 0;
|
||||
waveIndex = 0;
|
||||
waveAdd = 0;
|
||||
waveCurrent = 0;
|
||||
keyOn = 0;
|
||||
ksr = 0;
|
||||
reg20 = 0;
|
||||
|
@ -614,8 +614,9 @@ Operator::Operator() {
|
|||
SetState( OFF );
|
||||
rateZero = (1 << OFF);
|
||||
sustainLevel = ENV_MAX;
|
||||
activeLevel = ENV_MAX;
|
||||
currentLevel = ENV_MAX;
|
||||
totalLevel = ENV_MAX;
|
||||
volume = ENV_MAX;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -786,7 +787,7 @@ void Channel::ResetC0( const Chip* chip ) {
|
|||
};
|
||||
|
||||
template< bool opl3Mode>
|
||||
void Channel::GeneratePercussion( Bit32s* output ) {
|
||||
INLINE void Channel::GeneratePercussion( Chip* chip, Bit32s* output ) {
|
||||
Channel* chan = this;
|
||||
|
||||
//BassDrum
|
||||
|
@ -805,8 +806,8 @@ void Channel::GeneratePercussion( Bit32s* output ) {
|
|||
Operator* op2 = ( this + 1 )->Op(0);
|
||||
Operator* op4 = ( this + 2 )->Op(0);
|
||||
|
||||
//Precalculate stuff used by other oupts
|
||||
Bit32u noiseBit = rand() & 0x2;
|
||||
//Precalculate stuff used by other outputs
|
||||
Bit32u noiseBit = (chip->ForwardNoise() & 0x1) << 1;
|
||||
Bit32u c2 = op2->ForwardWave();
|
||||
//(bit 7 ^ bit 2) | bit 3 -> combined in bit 1
|
||||
Bit32u phaseBit = ( (c2 >> 6) ^ ( c2 >> 1 ) ) | ( c2 >> 2 );
|
||||
|
@ -832,7 +833,10 @@ void Channel::GeneratePercussion( Bit32s* output ) {
|
|||
sample += op3->GetWave( sdIndex, sdVol );
|
||||
}
|
||||
//Tom-tom
|
||||
sample += op4->GetSample( 0 );
|
||||
Bit32u ttVol = op4->ForwardVolume();
|
||||
if ( !ENV_SILENT( ttVol ) ) {
|
||||
sample += op4->GetWave( c4, ttVol );
|
||||
}
|
||||
//Top-Cymbal
|
||||
Operator* op5 = ( this + 2 )->Op(1);
|
||||
Bit32u tcVol = op5->ForwardVolume();
|
||||
|
@ -850,7 +854,7 @@ void Channel::GeneratePercussion( Bit32s* output ) {
|
|||
}
|
||||
|
||||
template<SynthMode mode>
|
||||
Channel* Channel::BlockTemplate( ) {
|
||||
Channel* Channel::BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ) {
|
||||
switch( mode ) {
|
||||
case sm2AM:
|
||||
case sm3AM:
|
||||
|
@ -891,16 +895,24 @@ Channel* Channel::BlockTemplate( ) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
for ( Bitu i = 0; i < Work.samples; i++ ) {
|
||||
Work.vibrato = Work.vibTable[i];
|
||||
Work.tremolo = Work.tremTable[i];
|
||||
|
||||
//Init the operators with the the current vibrato and tremolo values
|
||||
Op( 0 )->Prepare( chip );
|
||||
Op( 1 )->Prepare( chip );
|
||||
if ( mode > sm4Start ) {
|
||||
Op( 2 )->Prepare( chip );
|
||||
Op( 3 )->Prepare( chip );
|
||||
}
|
||||
if ( mode > sm6Start ) {
|
||||
Op( 4 )->Prepare( chip );
|
||||
Op( 5 )->Prepare( chip );
|
||||
}
|
||||
for ( Bitu i = 0; i < samples; i++ ) {
|
||||
//Early out for percussion handlers
|
||||
if ( mode == sm2Percussion ) {
|
||||
GeneratePercussion<false>( Work.output + i );
|
||||
GeneratePercussion<false>( chip, output + i );
|
||||
continue; //Prevent some unitialized value bitching
|
||||
} else if ( mode == sm3Percussion ) {
|
||||
GeneratePercussion<true>( Work.output + i * 2 );
|
||||
GeneratePercussion<true>( chip, output + i * 2 );
|
||||
continue; //Prevent some unitialized value bitching
|
||||
}
|
||||
|
||||
|
@ -936,7 +948,7 @@ Channel* Channel::BlockTemplate( ) {
|
|||
switch( mode ) {
|
||||
case sm2AM:
|
||||
case sm2FM:
|
||||
Work.output[ i ] += sample;
|
||||
output[ i ] += sample;
|
||||
break;
|
||||
case sm3AM:
|
||||
case sm3FM:
|
||||
|
@ -944,8 +956,8 @@ Channel* Channel::BlockTemplate( ) {
|
|||
case sm3AMFM:
|
||||
case sm3FMAM:
|
||||
case sm3AMAM:
|
||||
Work.output[ i * 2 + 0 ] += sample & maskLeft;
|
||||
Work.output[ i * 2 + 1 ] += sample & maskRight;
|
||||
output[ i * 2 + 0 ] += sample & maskLeft;
|
||||
output[ i * 2 + 1 ] += sample & maskRight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -979,31 +991,53 @@ Chip::Chip() {
|
|||
opl3Active = 0;
|
||||
}
|
||||
|
||||
|
||||
Bit8u Chip::ForwardTremolo( ) {
|
||||
tremoloCounter += tremoloAdd;
|
||||
if ( tremoloCounter >= (TREMOLO_TABLE << TREMOLO_SH) ) {
|
||||
tremoloCounter -= TREMOLO_TABLE << TREMOLO_SH;
|
||||
INLINE Bit32u Chip::ForwardNoise() {
|
||||
noiseCounter += noiseAdd;
|
||||
Bitu count = noiseCounter >> LFO_SH;
|
||||
noiseCounter &= WAVE_MASK;
|
||||
for ( ; count > 0; --count ) {
|
||||
//Noise calculation from mame
|
||||
noiseValue ^= ( 0x800302 ) & ( 0 - (noiseValue & 1 ) );
|
||||
noiseValue >>= 1;
|
||||
}
|
||||
Bitu index = tremoloCounter >> TREMOLO_SH;
|
||||
return TremoloTable[ index ] >> tremoloShift;
|
||||
return noiseValue;
|
||||
}
|
||||
|
||||
Bit8s Chip::ForwardVibrato( ) {
|
||||
vibratoCounter += vibratoAdd;
|
||||
Bitu index = vibratoCounter >> VIBRATO_SH;
|
||||
//Vibrato shift, basically makes the shift greater reducing the actual final value
|
||||
return VibratoTable[index & 7] + vibratoShift;
|
||||
INLINE Bit32u Chip::ForwardLFO( Bit32u samples ) {
|
||||
//Current vibrato value, runs 4x slower than tremolo
|
||||
vibratoSign = ( VibratoTable[ vibratoIndex >> 2] ) >> 7;
|
||||
vibratoShift = ( VibratoTable[ vibratoIndex >> 2] & 7) + vibratoStrength;
|
||||
tremoloValue = TremoloTable[ tremoloIndex ] >> tremoloStrength;
|
||||
|
||||
//Check hom many samples there can be done before the value changes
|
||||
Bit32u todo = LFO_MAX - lfoCounter;
|
||||
Bit32u count = (todo + lfoAdd - 1) / lfoAdd;
|
||||
if ( count > samples ) {
|
||||
count = samples;
|
||||
lfoCounter += count * lfoAdd;
|
||||
} else {
|
||||
lfoCounter += count * lfoAdd;
|
||||
lfoCounter &= (LFO_MAX - 1);
|
||||
//Maximum of 7 vibrato value * 4
|
||||
vibratoIndex = ( vibratoIndex + 1 ) & 31;
|
||||
//Clip tremolo to the the table size
|
||||
if ( tremoloIndex + 1 < TREMOLO_TABLE )
|
||||
++tremoloIndex;
|
||||
else
|
||||
tremoloIndex = 0;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
void Chip::WriteBD( Bit8u val ) {
|
||||
Bit8u change = regBD ^ val;
|
||||
if ( !change )
|
||||
return;
|
||||
regBD = val;
|
||||
//TODO could do this with shift and xor?
|
||||
vibratoShift = (val & 0x40) ? 0x00 : 0x01;
|
||||
tremoloShift = (val & 0x80) ? 0x00 : 0x02;
|
||||
vibratoStrength = (val & 0x40) ? 0x00 : 0x01;
|
||||
tremoloStrength = (val & 0x80) ? 0x00 : 0x02;
|
||||
if ( val & 0x20 ) {
|
||||
//Drum was just enabled, make sure channel 6 has the right synth
|
||||
if ( change & 0x20 ) {
|
||||
|
@ -1150,53 +1184,69 @@ Bit32u Chip::WriteAddr( Bit32u port, Bit8u val ) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Chip::GenerateBlock2( Bitu samples ) {
|
||||
Work.samples = samples;
|
||||
for ( Bitu i = 0; i < Work.samples; i++ ) {
|
||||
Work.vibTable[i] = ForwardVibrato();
|
||||
Work.tremTable[i] = ForwardTremolo();
|
||||
Work.output[i] = 0;
|
||||
}
|
||||
int count = 0;
|
||||
for( Channel* ch = chan; ch < chan + 9; ) {
|
||||
count++;
|
||||
ch = (ch->*(ch->synthHandler))();
|
||||
void Chip::GenerateBlock2( Bitu total, Bit32s* output ) {
|
||||
while ( total > 0 ) {
|
||||
Bit32u samples = ForwardLFO( total );
|
||||
for ( Bitu i = 0; i < samples; i++ ) {
|
||||
output[i] = 0;
|
||||
}
|
||||
int count = 0;
|
||||
for( Channel* ch = chan; ch < chan + 9; ) {
|
||||
count++;
|
||||
ch = (ch->*(ch->synthHandler))( this, samples, output );
|
||||
}
|
||||
total -= samples;
|
||||
output += samples;
|
||||
}
|
||||
}
|
||||
|
||||
void Chip::GenerateBlock3( Bitu samples ) {
|
||||
Work.samples = samples;
|
||||
for ( Bitu i = 0; i < Work.samples; i++ ) {
|
||||
Work.vibTable[i] = ForwardVibrato();
|
||||
Work.tremTable[i] = ForwardTremolo();
|
||||
Work.output[i*2 + 0] = 0;
|
||||
Work.output[i*2 + 1] = 0;
|
||||
}
|
||||
int count = 0;
|
||||
for( Channel* ch = chan; ch < chan + 18; ) {
|
||||
count++;
|
||||
ch = (ch->*(ch->synthHandler))();
|
||||
void Chip::GenerateBlock3( Bitu total, Bit32s* output ) {
|
||||
while ( total > 0 ) {
|
||||
Bit32u samples = ForwardLFO( total );
|
||||
for ( Bitu i = 0; i < samples; i++ ) {
|
||||
output[i * 2 + 0 ] = 0;
|
||||
output[i * 2 + 1 ] = 0;
|
||||
}
|
||||
int count = 0;
|
||||
for( Channel* ch = chan; ch < chan + 18; ) {
|
||||
count++;
|
||||
ch = (ch->*(ch->synthHandler))( this, samples, output );
|
||||
}
|
||||
total -= samples;
|
||||
output += samples * 2;
|
||||
}
|
||||
}
|
||||
|
||||
void Chip::Setup( Bit32u rate ) {
|
||||
//Vibrato forwards every 1024 samples
|
||||
vibratoAdd = (Bit32u)((double)rate * (double)( 1 << (VIBRATO_SH - 10) ) / OPLRATE);
|
||||
vibratoCounter = 0;
|
||||
//tremolo forwards every 64 samples
|
||||
//We use a 52 entry table, real is 210, so repeat each sample an extra 4 times
|
||||
tremoloAdd = (Bit32u)((double)rate * (double)( 1 << (TREMOLO_SH - 6 - 2) ) / OPLRATE);
|
||||
tremoloCounter = 0;
|
||||
//10 bits of frequency counter
|
||||
double original = OPLRATE;
|
||||
// double original = rate;
|
||||
double scale = original / (double)rate;
|
||||
|
||||
//Noise counter is run at the same precision as general waves
|
||||
noiseAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) );
|
||||
noiseCounter = 0;
|
||||
noiseValue = 1; //Make sure it triggers the noise xor the first time
|
||||
//The low frequency oscillation counter
|
||||
//Every time his overflows vibrato and tremoloindex are increased
|
||||
lfoAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) );
|
||||
lfoCounter = 0;
|
||||
vibratoIndex = 0;
|
||||
tremoloIndex = 0;
|
||||
|
||||
//With higher octave this gets shifted up
|
||||
//-1 since the freqCreateTable = *2
|
||||
double scale = (OPLRATE * (double)( 1 << ( WAVE_SH - 10 - 1))) / rate;
|
||||
#ifdef WAVE_PRECISION
|
||||
double freqScale = ( 1 << 7 ) * scale * ( 1 << ( WAVE_SH - 1 - 10));
|
||||
for ( int i = 0; i < 16; i++ ) {
|
||||
//Use rounding with 0.5
|
||||
freqMul[i] = (Bit32u)( 0.5 + scale * FreqCreateTable[ i ] );
|
||||
freqMul[i] = (Bit32u)( 0.5 + freqScale * FreqCreateTable[ i ] );
|
||||
}
|
||||
#else
|
||||
Bit32u freqScale = (Bit32u)( 0.5 + scale * ( 1 << ( WAVE_SH - 1 - 10)));
|
||||
for ( int i = 0; i < 16; i++ ) {
|
||||
freqMul[i] = freqScale * FreqCreateTable[ i ];
|
||||
}
|
||||
#endif
|
||||
|
||||
scale = OPLRATE / rate;
|
||||
//-3 since the real envelope takes 8 steps to reach the single value we supply
|
||||
for ( Bit8u i = 0; i < 76; i++ ) {
|
||||
Bit8u index, shift;
|
||||
|
@ -1456,12 +1506,15 @@ void Handler::WriteReg( Bit32u addr, Bit8u val ) {
|
|||
}
|
||||
|
||||
void Handler::Generate( MixerChannel* chan, Bitu samples ) {
|
||||
Bit32s buffer[ 512 * 2 ];
|
||||
if ( samples > 512 )
|
||||
samples = 512;
|
||||
if ( !chip.opl3Active ) {
|
||||
chip.GenerateBlock2( samples );
|
||||
chan->AddSamples_m32( samples, Work.output );
|
||||
chip.GenerateBlock2( samples, buffer );
|
||||
chan->AddSamples_m32( samples, buffer );
|
||||
} else {
|
||||
chip.GenerateBlock3( samples );
|
||||
chan->AddSamples_s32( samples, Work.output );
|
||||
chip.GenerateBlock3( samples, buffer );
|
||||
chan->AddSamples_s32( samples, buffer );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,10 +28,6 @@
|
|||
|
||||
//Select the type of wave generator routine
|
||||
#define DBOPL_WAVE WAVE_TABLEMUL
|
||||
//Enable vibrato in the output
|
||||
#define DBOPL_VIBRATO
|
||||
//Enable tremolo in the output
|
||||
#define DBOPL_TREMOLO
|
||||
|
||||
namespace DBOPL {
|
||||
|
||||
|
@ -44,20 +40,21 @@ typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume );
|
|||
#endif
|
||||
|
||||
typedef Bits ( DBOPL::Operator::*VolumeHandler) ( );
|
||||
typedef Channel* ( DBOPL::Channel::*SynthHandler) ( );
|
||||
typedef Channel* ( DBOPL::Channel::*SynthHandler) ( Chip* chip, Bit32u samples, Bit32s* output );
|
||||
|
||||
//Different synth modes that can generate blocks of data
|
||||
typedef enum {
|
||||
smNone,
|
||||
sm2AM,
|
||||
sm2FM,
|
||||
sm2Percussion,
|
||||
sm3AM,
|
||||
sm3FM,
|
||||
sm4Start,
|
||||
sm3FMFM,
|
||||
sm3AMFM,
|
||||
sm3FMAM,
|
||||
sm3AMAM,
|
||||
sm6Start,
|
||||
sm2Percussion,
|
||||
sm3Percussion,
|
||||
} SynthMode;
|
||||
|
||||
|
@ -95,14 +92,16 @@ public:
|
|||
Bit32u waveStart;
|
||||
#endif
|
||||
Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index
|
||||
Bit32u waveAdd;
|
||||
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; //totalLeve is added to every generated volume
|
||||
Bit32s activeLevel; //The currently active volume
|
||||
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;
|
||||
|
@ -129,7 +128,7 @@ private:
|
|||
public:
|
||||
void UpdateAttenuation();
|
||||
void UpdateRates( const Chip* chip );
|
||||
void UpdateFrequency( );
|
||||
void UpdateFrequency( );
|
||||
|
||||
void Write20( const Chip* chip, Bit8u val );
|
||||
void Write40( const Chip* chip, Bit8u val );
|
||||
|
@ -138,6 +137,8 @@ public:
|
|||
void WriteE0( const Chip* chip, Bit8u val );
|
||||
|
||||
bool Silent() const;
|
||||
void Prepare( const Chip* chip );
|
||||
|
||||
void KeyOn( Bit8u mask);
|
||||
void KeyOff( Bit8u mask);
|
||||
|
||||
|
@ -182,20 +183,23 @@ struct Channel {
|
|||
|
||||
//call this for the first channel
|
||||
template< bool opl3Mode >
|
||||
void GeneratePercussion( Bit32s* output );
|
||||
void GeneratePercussion( Chip* chip, Bit32s* output );
|
||||
|
||||
//Generate blocks of data in specific modes
|
||||
template<SynthMode mode>
|
||||
Channel* BlockTemplate( );
|
||||
Channel* BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output );
|
||||
Channel();
|
||||
};
|
||||
|
||||
struct Chip {
|
||||
//This is used as the base counter for vibrato and tremolo
|
||||
Bit32u tremoloCounter;
|
||||
Bit32u tremoloAdd;
|
||||
Bit32u vibratoCounter;
|
||||
Bit32u vibratoAdd;
|
||||
Bit32u lfoCounter;
|
||||
Bit32u lfoAdd;
|
||||
|
||||
|
||||
Bit32u noiseCounter;
|
||||
Bit32u noiseAdd;
|
||||
Bit32u noiseValue;
|
||||
|
||||
//Frequency scales for the different multiplications
|
||||
Bit32u freqMul[16];
|
||||
|
@ -211,23 +215,29 @@ struct Chip {
|
|||
Bit8u reg08;
|
||||
Bit8u reg04;
|
||||
Bit8u regBD;
|
||||
Bit8u vibratoIndex;
|
||||
Bit8u tremoloIndex;
|
||||
Bit8s vibratoSign;
|
||||
Bit8u vibratoShift;
|
||||
Bit8u tremoloShift;
|
||||
Bit8u tremoloValue;
|
||||
Bit8u vibratoStrength;
|
||||
Bit8u tremoloStrength;
|
||||
//Mask for allowed wave forms
|
||||
Bit8u waveFormMask;
|
||||
//0 or -1 when enabled
|
||||
Bit8s opl3Active;
|
||||
|
||||
Bit8u ForwardTremolo();
|
||||
Bit8s ForwardVibrato();
|
||||
//Return the maximum amount of samples before and LFO change
|
||||
Bit32u ForwardLFO( Bit32u samples );
|
||||
Bit32u ForwardNoise();
|
||||
|
||||
void WriteBD( Bit8u val );
|
||||
void WriteReg(Bit32u reg, Bit8u val );
|
||||
|
||||
Bit32u WriteAddr( Bit32u port, Bit8u val );
|
||||
|
||||
void GenerateBlock2( Bitu samples );
|
||||
void GenerateBlock3( Bitu samples );
|
||||
void GenerateBlock2( Bitu samples, Bit32s* output );
|
||||
void GenerateBlock3( Bitu samples, Bit32s* output );
|
||||
|
||||
void Generate( Bit32u samples );
|
||||
void Setup( Bit32u r );
|
||||
|
|
Loading…
Add table
Reference in a new issue