From c4288a8e614c2e972618368409cfbe7859c1751c Mon Sep 17 00:00:00 2001 From: Chris Moeller Date: Mon, 31 Mar 2014 19:00:27 -0700 Subject: [PATCH] Updated st3play with experimental AdLib support --- .../modplay/modplay.xcodeproj/project.pbxproj | 8 + Frameworks/modplay/modplay/dbopl.c | 215 +++++++++++------- Frameworks/modplay/modplay/dbopl.h | 4 +- Frameworks/modplay/modplay/resampler.c | 18 ++ Frameworks/modplay/modplay/resampler.h | 2 + Frameworks/modplay/modplay/st3play.c | 207 +++++++++++++++-- 6 files changed, 352 insertions(+), 102 deletions(-) diff --git a/Frameworks/modplay/modplay.xcodeproj/project.pbxproj b/Frameworks/modplay/modplay.xcodeproj/project.pbxproj index ac2ea8abe..dcc498bc6 100644 --- a/Frameworks/modplay/modplay.xcodeproj/project.pbxproj +++ b/Frameworks/modplay/modplay.xcodeproj/project.pbxproj @@ -11,6 +11,8 @@ 838A72E618DEC9A1007C8A7D /* resampler.c in Sources */ = {isa = PBXBuildFile; fileRef = 838A72E418DEC9A1007C8A7D /* resampler.c */; }; 838A72E718DEC9A1007C8A7D /* resampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 838A72E518DEC9A1007C8A7D /* resampler.h */; }; 839CAC4018DA746000D67EA9 /* ft2play.c in Sources */ = {isa = PBXBuildFile; fileRef = 839CAC3F18DA746000D67EA9 /* ft2play.c */; }; + 83EAF76818E8F70400C896A6 /* dbopl.c in Sources */ = {isa = PBXBuildFile; fileRef = 83EAF76618E8F70400C896A6 /* dbopl.c */; }; + 83EAF76918E8F70400C896A6 /* dbopl.h in Headers */ = {isa = PBXBuildFile; fileRef = 83EAF76718E8F70400C896A6 /* dbopl.h */; }; 83F4D54818D82105009B2DE6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 83F4D54618D82105009B2DE6 /* InfoPlist.strings */; }; 83F4D57718D821D2009B2DE6 /* st3play.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F4D57318D821D2009B2DE6 /* st3play.c */; }; 83F4D57818D821D2009B2DE6 /* st3play.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F4D57418D821D2009B2DE6 /* st3play.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -21,6 +23,8 @@ 838A72E518DEC9A1007C8A7D /* resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resampler.h; sourceTree = ""; }; 839CAC3E18DA744700D67EA9 /* ft2play.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ft2play.h; sourceTree = ""; }; 839CAC3F18DA746000D67EA9 /* ft2play.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ft2play.c; sourceTree = ""; }; + 83EAF76618E8F70400C896A6 /* dbopl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dbopl.c; sourceTree = ""; }; + 83EAF76718E8F70400C896A6 /* dbopl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dbopl.h; sourceTree = ""; }; 83F4D53A18D82105009B2DE6 /* modplay.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = modplay.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 83F4D54518D82105009B2DE6 /* modplay-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "modplay-Info.plist"; sourceTree = ""; }; 83F4D54718D82105009B2DE6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -74,6 +78,8 @@ 83F4D54318D82105009B2DE6 /* modplay */ = { isa = PBXGroup; children = ( + 83EAF76618E8F70400C896A6 /* dbopl.c */, + 83EAF76718E8F70400C896A6 /* dbopl.h */, 838A72E418DEC9A1007C8A7D /* resampler.c */, 838A72E518DEC9A1007C8A7D /* resampler.h */, 83F4D57318D821D2009B2DE6 /* st3play.c */, @@ -103,6 +109,7 @@ files = ( 838A72E718DEC9A1007C8A7D /* resampler.h in Headers */, 835CBC8218DA95AC0087A03E /* ft2play.h in Headers */, + 83EAF76918E8F70400C896A6 /* dbopl.h in Headers */, 83F4D57818D821D2009B2DE6 /* st3play.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -171,6 +178,7 @@ buildActionMask = 2147483647; files = ( 838A72E618DEC9A1007C8A7D /* resampler.c in Sources */, + 83EAF76818E8F70400C896A6 /* dbopl.c in Sources */, 83F4D57718D821D2009B2DE6 /* st3play.c in Sources */, 839CAC4018DA746000D67EA9 /* ft2play.c in Sources */, ); diff --git a/Frameworks/modplay/modplay/dbopl.c b/Frameworks/modplay/modplay/dbopl.c index 30b1c74de..aacee35f5 100644 --- a/Frameworks/modplay/modplay/dbopl.c +++ b/Frameworks/modplay/modplay/dbopl.c @@ -524,18 +524,14 @@ static void Operator_UpdateRates( struct Operator *o, const struct Chip* chip ) } static INLINE Bit32s Operator_RateForward( struct Operator *o, Bit32u add ) { + Bit32s ret; o->rateIndex += add; - Bit32s ret = o->rateIndex >> RATE_SH; + ret = o->rateIndex >> RATE_SH; o->rateIndex = o->rateIndex & RATE_MASK; return ret; } -static const Operator_VolumeHandler VolumeHandlerTable[5]; - -static INLINE void Operator_SetState( struct Operator *o, Bit8u s ) { - o->state = s; - o->volHandler = VolumeHandlerTable[ s ]; -} +static INLINE void Operator_SetState( struct Operator *o, Bit8u s ); static Bits Operator_Volume_Attack( struct Operator *o ) { Bit32s vol = o->volume; @@ -556,7 +552,6 @@ static Bits Operator_Volume_Attack( struct Operator *o ) { static Bits Operator_Volume_Decay( struct Operator *o ) { Bit32s vol = o->volume; - Bit32s change; vol += Operator_RateForward( o, o->decayAdd ); if ( vol >= o->sustainLevel ) { //Check if we didn't overshoot max attenuation, then just go off @@ -575,7 +570,6 @@ static Bits Operator_Volume_Decay( struct Operator *o ) { static Bits Operator_Volume_Sustain( struct Operator *o ) { Bit32s vol = o->volume; - Bit32s change; if ( o->reg20 & MASK_SUSTAIN ) { return vol; } @@ -592,7 +586,6 @@ static Bits Operator_Volume_Sustain( struct Operator *o ) { static Bits Operator_Volume_Release( struct Operator *o ) { Bit32s vol = o->volume; - Bit32s change; vol += Operator_RateForward( o, o->releaseAdd );; if ( vol >= ENV_MAX ) { o->volume = ENV_MAX; @@ -616,6 +609,11 @@ static const Operator_VolumeHandler VolumeHandlerTable[5] = { &Operator_Volume_Attack }; +static INLINE void Operator_SetState( struct Operator *o, Bit8u s ) { + o->state = s; + o->volHandler = VolumeHandlerTable[ s ]; +} + static INLINE Bitu Operator_ForwardVolume(struct Operator *o) { return o->currentLevel + (o->volHandler)(o); } @@ -672,10 +670,11 @@ static void Operator_Write60( struct Operator *o, const struct Chip* chip, Bit8u static void Operator_Write80( struct Operator *o, const struct Chip* chip, Bit8u val ) { Bit8u change = (o->reg80 ^ val ); + Bit8u sustain; if ( !change ) return; o->reg80 = val; - Bit8u sustain = val >> 4; + sustain = val >> 4; //Turn 0xf into 0x1f sustain |= ( sustain + 1) & 0x10; o->sustainLevel = sustain << ( ENV_BITS - 5 ); @@ -685,10 +684,11 @@ static void Operator_Write80( struct Operator *o, const struct Chip* chip, Bit8u } static void Operator_WriteE0( struct Operator *o, const struct Chip* chip, Bit8u val ) { + Bit8u waveForm; if ( !(o->regE0 ^ val) ) return; //in opl3 mode you can always selet 7 waveforms regardless of waveformselect - Bit8u waveForm = val & ( ( 0x3 & chip->waveFormMask ) | (0x7 & chip->opl3Active ) ); + waveForm = val & ( ( 0x3 & chip->waveFormMask ) | (0x7 & chip->opl3Active ) ); o->regE0 = val; #if ( DBOPL_WAVE == WAVE_HANDLER ) o->waveHandler = WaveHandlerTable[ waveForm ]; @@ -803,7 +803,9 @@ static INLINE struct Operator* Channel_Op( struct Channel *c, Bitu index ) { } static struct Channel* Channel_Block_sm2AM( struct Channel *c, struct Chip* chip, Bit32u samples, Bit32s* output ) { - if ( Operator_Silent( Channel_Op(c, 0) ) && Operator_Silent( Channel_Op(c, 1) ) ) { + Bitu i; + + if ( Operator_Silent( Channel_Op(c, 0) ) && Operator_Silent( Channel_Op(c, 1) ) ) { c->old[0] = c->old[1] = 0; return (c + 1); } @@ -811,7 +813,7 @@ static struct Channel* Channel_Block_sm2AM( struct Channel *c, struct Chip* chip Operator_Prepare( Channel_Op( c, 0 ), chip ); Operator_Prepare( Channel_Op( c, 1 ), chip ); - for ( Bitu i = 0; i < samples; i++ ) { + for ( i = 0; i < samples; i++ ) { //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise Bit32s mod = (Bit32u)((c->old[0] + c->old[1])) >> c->feedback; Bit32s sample; @@ -827,6 +829,8 @@ static struct Channel* Channel_Block_sm2AM( struct Channel *c, struct Chip* chip } static struct Channel* Channel_Block_sm2FM( struct Channel *c, struct Chip* chip, Bit32u samples, Bit32s* output ) { + Bitu i; + if ( Operator_Silent( Channel_Op(c, 1) ) ) { c->old[0] = c->old[1] = 0; return (c + 1); @@ -836,7 +840,7 @@ static struct Channel* Channel_Block_sm2FM( struct Channel *c, struct Chip* chip Operator_Prepare( Channel_Op( c, 0 ), chip ); Operator_Prepare( Channel_Op( c, 1 ), chip ); - for ( Bitu i = 0; i < samples; i++ ) { + for ( i = 0; i < samples; i++ ) { //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise Bit32s mod = (Bit32u)((c->old[0] + c->old[1])) >> c->feedback; Bit32s sample; @@ -852,7 +856,9 @@ static struct Channel* Channel_Block_sm2FM( struct Channel *c, struct Chip* chip } static struct Channel* Channel_Block_sm3AM( struct Channel *c, struct Chip* chip, Bit32u samples, Bit32s* output ) { - if ( Operator_Silent( Channel_Op( c, 0 ) ) && Operator_Silent( Channel_Op( c, 1 ) ) ) { + Bitu i; + + if ( Operator_Silent( Channel_Op( c, 0 ) ) && Operator_Silent( Channel_Op( c, 1 ) ) ) { c->old[0] = c->old[1] = 0; return (c + 1); } @@ -861,7 +867,7 @@ static struct Channel* Channel_Block_sm3AM( struct Channel *c, struct Chip* chip Operator_Prepare( Channel_Op( c, 0 ), chip ); Operator_Prepare( Channel_Op( c, 1 ), chip ); - for ( Bitu i = 0; i < samples; i++ ) { + for ( i = 0; i < samples; i++ ) { //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise Bit32s mod = (Bit32u)((c->old[0] + c->old[1])) >> c->feedback; Bit32s sample; @@ -878,7 +884,9 @@ static struct Channel* Channel_Block_sm3AM( struct Channel *c, struct Chip* chip } static struct Channel* Channel_Block_sm3FM( struct Channel *c, struct Chip* chip, Bit32u samples, Bit32s* output ) { - if ( Operator_Silent( Channel_Op( c, 1 ) ) ) { + Bitu i; + + if ( Operator_Silent( Channel_Op( c, 1 ) ) ) { c->old[0] = c->old[1] = 0; return (c + 1); } @@ -887,7 +895,7 @@ static struct Channel* Channel_Block_sm3FM( struct Channel *c, struct Chip* chip Operator_Prepare( Channel_Op( c, 0 ), chip ); Operator_Prepare( Channel_Op( c, 1 ), chip ); - for ( Bitu i = 0; i < samples; i++ ) { + for ( i = 0; i < samples; i++ ) { //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise Bit32s mod = (Bit32u)((c->old[0] + c->old[1])) >> c->feedback; Bit32s sample; @@ -904,6 +912,8 @@ static struct Channel* Channel_Block_sm3FM( struct Channel *c, struct Chip* chip } static struct Channel* Channel_Block_sm3FMFM( struct Channel *c, struct Chip* chip, Bit32u samples, Bit32s* output ) { + Bitu i; + if ( Operator_Silent( Channel_Op( c, 3 ) ) ) { c->old[0] = c->old[1] = 0; return (c + 2); @@ -915,7 +925,7 @@ static struct Channel* Channel_Block_sm3FMFM( struct Channel *c, struct Chip* ch Operator_Prepare( Channel_Op( c, 2 ), chip ); Operator_Prepare( Channel_Op( c, 3 ), chip ); - for ( Bitu i = 0; i < samples; i++ ) { + for ( i = 0; i < samples; i++ ) { //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise Bit32s mod = (Bit32u)((c->old[0] + c->old[1])) >> c->feedback; Bit32s sample; @@ -935,6 +945,8 @@ static struct Channel* Channel_Block_sm3FMFM( struct Channel *c, struct Chip* ch } static struct Channel* Channel_Block_sm3AMFM( struct Channel *c, struct Chip* chip, Bit32u samples, Bit32s* output ) { + Bitu i; + if ( Operator_Silent( Channel_Op( c, 0 ) ) && Operator_Silent( Channel_Op( c, 3 ) ) ) { c->old[0] = c->old[1] = 0; return (c + 2); @@ -946,7 +958,7 @@ static struct Channel* Channel_Block_sm3AMFM( struct Channel *c, struct Chip* ch Operator_Prepare( Channel_Op( c, 2 ), chip ); Operator_Prepare( Channel_Op( c, 3 ), chip ); - for ( Bitu i = 0; i < samples; i++ ) { + for ( i = 0; i < samples; i++ ) { //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise Bit32s mod = (Bit32u)((c->old[0] + c->old[1])) >> c->feedback; Bit32s sample; @@ -967,6 +979,8 @@ static struct Channel* Channel_Block_sm3AMFM( struct Channel *c, struct Chip* ch } static struct Channel* Channel_Block_sm3FMAM( struct Channel *c, struct Chip* chip, Bit32u samples, Bit32s* output ) { + Bitu i; + if ( Operator_Silent( Channel_Op( c, 1) ) && Operator_Silent( Channel_Op( c, 3 ) ) ) { c->old[0] = c->old[1] = 0; return (c + 2); @@ -978,7 +992,7 @@ static struct Channel* Channel_Block_sm3FMAM( struct Channel *c, struct Chip* ch Operator_Prepare( Channel_Op( c, 2 ), chip ); Operator_Prepare( Channel_Op( c, 3 ), chip ); - for ( Bitu i = 0; i < samples; i++ ) { + for ( i = 0; i < samples; i++ ) { //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise Bit32s mod = (Bit32u)((c->old[0] + c->old[1])) >> c->feedback; Bit32s sample; @@ -998,6 +1012,8 @@ static struct Channel* Channel_Block_sm3FMAM( struct Channel *c, struct Chip* ch } static struct Channel* Channel_Block_sm3AMAM( struct Channel *c, struct Chip* chip, Bit32u samples, Bit32s* output ) { + Bitu i; + if ( Operator_Silent( Channel_Op( c, 0 ) ) && Operator_Silent( Channel_Op( c, 2 ) ) && Operator_Silent( Channel_Op( c, 3 ) ) ) { c->old[0] = c->old[1] = 0; return (c + 2); @@ -1009,16 +1025,17 @@ static struct Channel* Channel_Block_sm3AMAM( struct Channel *c, struct Chip* ch Operator_Prepare( Channel_Op( c, 2 ), chip ); Operator_Prepare( Channel_Op( c, 3 ), chip ); - for ( Bitu i = 0; i < samples; i++ ) { + for ( i = 0; i < samples; i++ ) { //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise Bit32s mod = (Bit32u)((c->old[0] + c->old[1])) >> c->feedback; Bit32s sample; Bit32s out0; + Bits next; c->old[0] = c->old[1]; c->old[1] = Operator_GetSample( Channel_Op( c, 0 ), mod ); out0 = c->old[0]; sample = out0; - Bits next = Operator_GetSample( Channel_Op( c, 1 ), 0 ); + next = Operator_GetSample( Channel_Op( c, 1 ), 0 ); sample += Operator_GetSample( Channel_Op( c, 2 ), next ); sample += Operator_GetSample( Channel_Op( c, 3 ), 0 ); output[ i * 2 + 0 ] += sample & c->maskLeft; @@ -1085,6 +1102,8 @@ static Bit32s Channel_GeneratePercussion( struct Channel *chan, struct Chip* chi } static struct Channel* Channel_Block_sm2Percussion( struct Channel *c, struct Chip* chip, Bit32u samples, Bit32s* output ) { + Bitu i; + //Init the operators with the the current vibrato and tremolo values Operator_Prepare( Channel_Op( c, 0 ), chip ); Operator_Prepare( Channel_Op( c, 1 ), chip ); @@ -1093,7 +1112,7 @@ static struct Channel* Channel_Block_sm2Percussion( struct Channel *c, struct Ch Operator_Prepare( Channel_Op( c, 4 ), chip ); Operator_Prepare( Channel_Op( c, 5 ), chip ); - for ( Bitu i = 0; i < samples; i++ ) { + for ( i = 0; i < samples; i++ ) { output[i] = Channel_GeneratePercussion( c, chip ); } @@ -1101,6 +1120,8 @@ static struct Channel* Channel_Block_sm2Percussion( struct Channel *c, struct Ch } static struct Channel* Channel_Block_sm3Percussion( struct Channel *c, struct Chip* chip, Bit32u samples, Bit32s* output ) { + Bitu i; + //Init the operators with the the current vibrato and tremolo values Operator_Prepare( Channel_Op( c, 0 ), chip ); Operator_Prepare( Channel_Op( c, 1 ), chip ); @@ -1109,7 +1130,7 @@ static struct Channel* Channel_Block_sm3Percussion( struct Channel *c, struct Ch Operator_Prepare( Channel_Op( c, 4 ), chip ); Operator_Prepare( Channel_Op( c, 5 ), chip ); - for ( Bitu i = 0; i < samples; i++ ) { + for ( i = 0; i < samples; i++ ) { output[i * 2] = output[i * 2 + 1] = Channel_GeneratePercussion( c, chip ); } @@ -1181,10 +1202,11 @@ static void Channel_WriteA0( struct Channel *c, const struct Chip* chip, Bit8u v static void Channel_WriteB0( struct Channel *c, const struct Chip* chip, Bit8u val ) { Bit8u fourOp = chip->reg104 & chip->opl3Active & c->fourMask; + Bitu change; //Don't handle writes to silent fourop channels if ( fourOp > 0x80 ) return; - Bitu change = ( c->chanData ^ ( val << 8 ) ) & 0x1f00; + change = ( c->chanData ^ ( val << 8 ) ) & 0x1f00; if ( change ) { c->chanData ^= change; Channel_UpdateFrequency( c, chip, fourOp ); @@ -1227,6 +1249,7 @@ static void Channel_WriteC0( struct Channel *c, const struct Chip* chip, Bit8u v //4-op mode enabled for this channel if ( (chip->reg104 & c->fourMask) & 0x3f ) { struct Channel* chan0, *chan1; + Bit8u synth; //Check if it's the 2nd channel in a 4-op if ( !(c->fourMask & 0x80 ) ) { chan0 = c; @@ -1236,7 +1259,7 @@ static void Channel_WriteC0( struct Channel *c, const struct Chip* chip, Bit8u v chan1 = c; } - Bit8u synth = ( (chan0->regC0 & 1) << 0 )| (( chan1->regC0 & 1) << 1 ); + synth = ( (chan0->regC0 & 1) << 0 )| (( chan1->regC0 & 1) << 1 ); switch ( synth ) { case 0: chan0->synthHandler = &Channel_Block_sm3FMFM; @@ -1307,8 +1330,9 @@ void Chip_Init(void *_chip) { } static INLINE Bit32u Chip_ForwardNoise(struct Chip *chip) { + Bitu count; chip->noiseCounter += chip->noiseAdd; - Bitu count = chip->noiseCounter >> LFO_SH; + count = chip->noiseCounter >> LFO_SH; chip->noiseCounter &= WAVE_MASK; for ( ; count > 0; --count ) { //Noise calculation from mame @@ -1437,12 +1461,13 @@ void Chip_WriteReg( void *_chip, Bit32u reg, Bit8u val ) { //Always keep the highest bit enabled, for checking > 0x80 chip->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 ( !((chip->opl3Active ^ val) & 1 ) ) return; chip->opl3Active = ( val & 1 ) ? 0xff : 0; //Update the 0xc0 register for all channels to signal the switch to mono/stereo handlers - for ( int i = 0; i < 18;i++ ) { + for ( i = 0; i < 18; i++ ) { Channel_ResetC0( &chip->chan[i], chip ); } } else if ( reg == 0x08 ) { @@ -1507,7 +1532,8 @@ void Chip_GenerateBlock2( void *_chip, Bitu total, Bit32s* output ) { struct Channel* ch; int count; Bit32u samples = Chip_ForwardLFO( chip, total ); - for ( Bitu i = 0; i < samples; i++ ) { + Bitu i; + for ( i = 0; i < samples; i++ ) { output[i] = 0; } count = 0; @@ -1526,7 +1552,8 @@ void Chip_GenerateBlock3( void *_chip, Bitu total, Bit32s* output ) { struct Channel* ch; int count; Bit32u samples = Chip_ForwardLFO( chip, total ); - for ( Bitu i = 0; i < samples; i++ ) { + Bitu i; + for ( i = 0; i < samples; i++ ) { output[i * 2 + 0 ] = 0; output[i * 2 + 1 ] = 0; } @@ -1544,6 +1571,14 @@ void Chip_Setup( void *_chip, Bit32u clock, Bit32u rate ) { struct Chip *chip = (struct Chip *)_chip; double original = (double)clock / 288.0; double scale = original / (double)rate; +#ifdef WAVE_PRECISION + double freqScale; +#else + Bit32u freqScale; +#endif + int i; + Bit8u j; + if (fabs(scale - 1.0) < 0.00001) scale = 1.0; @@ -1561,41 +1596,46 @@ void Chip_Setup( void *_chip, Bit32u clock, Bit32u rate ) { //With higher octave this gets shifted up //-1 since the freqCreateTable = *2 #ifdef WAVE_PRECISION - double freqScale = ( 1 << 7 ) * scale * ( 1 << ( WAVE_SH - 1 - 10)); - for ( int i = 0; i < 16; i++ ) { + freqScale = ( 1 << 7 ) * scale * ( 1 << ( WAVE_SH - 1 - 10)); + for ( i = 0; i < 16; i++ ) { //Use rounding with 0.5 chip->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++ ) { + freqScale = (Bit32u)( 0.5 + scale * ( 1 << ( WAVE_SH - 1 - 10))); + for ( i = 0; i < 16; i++ ) { chip->freqMul[i] = freqScale * FreqCreateTable[ i ]; } #endif //-3 since the real envelope takes 8 steps to reach the single value we supply - for ( Bit8u i = 0; i < 76; i++ ) { + for ( j = 0; j < 76; j++ ) { Bit8u index, shift; - EnvelopeSelect( i, &index, &shift ); - chip->linearRates[i] = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH + ENV_EXTRA - shift - 3 ))); + EnvelopeSelect( j, &index, &shift ); + chip->linearRates[j] = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH + ENV_EXTRA - shift - 3 ))); } //Generate the best matching attack rate - for ( Bit8u i = 0; i < 62; i++ ) { + for ( j = 0; j < 62; j++ ) { Bit8u index, shift; - EnvelopeSelect( i, &index, &shift ); + Bit32s original, guessAdd, bestAdd; + Bit32u bestDiff, passes; + EnvelopeSelect( j, &index, &shift ); //Original amount of samples the attack would take - Bit32s original = (Bit32u)( (AttackSamplesTable[ index ] << shift) / scale); + original = (Bit32u)( (AttackSamplesTable[ index ] << shift) / scale); - Bit32s guessAdd = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH - shift - 3 ))); - Bit32s bestAdd = guessAdd; - Bit32u bestDiff = 1 << 30; - for( Bit32u passes = 0; passes < 16; passes ++ ) { + 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; count += guessAdd; - Bit32s change = count >> RATE_SH; + change = count >> RATE_SH; count &= RATE_MASK; if ( change ) { volume += ( ~volume * change ) >> 3; @@ -1603,8 +1643,8 @@ void Chip_Setup( void *_chip, Bit32u clock, Bit32u rate ) { samples++; } - Bit32s diff = original - samples; - Bit32u lDiff = labs( diff ); + diff = original - samples; + lDiff = labs( diff ); //Init last on first pass if ( lDiff < bestDiff ) { bestDiff = lDiff; @@ -1624,11 +1664,11 @@ void Chip_Setup( void *_chip, Bit32u clock, Bit32u rate ) { guessAdd--; } } - chip->attackRates[i] = bestAdd; + chip->attackRates[j] = bestAdd; } - for ( Bit8u i = 62; i < 76; i++ ) { + for ( j = 62; j < 76; j++ ) { //This should provide instant volume maximizing - chip->attackRates[i] = 8 << RATE_SH; + chip->attackRates[j] = 8 << RATE_SH; } //Setup the channels with the correct four op flags //Channels are accessed through a table so they appear linear here @@ -1653,7 +1693,7 @@ void Chip_Setup( void *_chip, Bit32u clock, Bit32u rate ) { //Clear Everything in opl3 mode Chip_WriteReg( chip, 0x105, 0x1 ); - for ( int i = 0; i < 512; i++ ) { + for ( i = 0; i < 512; i++ ) { if ( i == 0x105 ) continue; Chip_WriteReg( chip, i, 0xff ); @@ -1661,7 +1701,7 @@ void Chip_Setup( void *_chip, Bit32u clock, Bit32u rate ) { } Chip_WriteReg( chip, 0x105, 0x0 ); //Clear everything in opl2 mode - for ( int i = 0; i < 256; i++ ) { + for ( i = 0; i < 256; i++ ) { Chip_WriteReg( chip, i, 0xff ); Chip_WriteReg( chip, i, 0x0 ); } @@ -1669,6 +1709,9 @@ void Chip_Setup( void *_chip, Bit32u clock, Bit32u rate ) { static unsigned char doneTables = 0; static void InitTables( void ) { + int i, oct; + Bit8u j; + Bitu k; if ( doneTables ) return; #if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) @@ -1690,7 +1733,7 @@ static void InitTables( void ) { #endif #if ( DBOPL_WAVE == WAVE_TABLEMUL ) //Multiplication based tables - for ( int i = 0; i < 384; i++ ) { + 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 )); @@ -1698,24 +1741,24 @@ static void InitTables( void ) { } //Sine Wave Base - for ( int i = 0; i < 512; i++ ) { + 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 ( int i = 0; i < 256; i++ ) { + 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 ( int i = 0; i < 512; i++ ) { + 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 ( int i = 0; i < 256; i++ ) { + for ( i = 0; i < 256; i++ ) { WaveTable[ 0x700 + i ] = i * 8; WaveTable[ 0x6ff - i ] = ((Bit16s)0x8000) | i * 8; } @@ -1726,7 +1769,7 @@ static void InitTables( void ) { // |06 |0126|27 |7 |3 |4 |4 5 |5 | #if (( DBOPL_WAVE == WAVE_TABLELOG ) || ( DBOPL_WAVE == WAVE_TABLEMUL )) - for ( int i = 0; i < 256; i++ ) { + for ( i = 0; i < 256; i++ ) { //Fill silence gaps WaveTable[ 0x400 + i ] = WaveTable[0]; WaveTable[ 0x500 + i ] = WaveTable[0]; @@ -1744,29 +1787,29 @@ static void InitTables( void ) { #endif //Create the ksl table - for ( int oct = 0; oct < 8; oct++ ) { + for ( oct = 0; oct < 8; oct++ ) { int base = oct * 8; - for ( int i = 0; i < 16; i++ ) { + 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; + KslTable[ oct * 16 + i ] = (Bit8u)(val * 4); } } //Create the Tremolo table, just increase and decrease a triangle wave - for ( Bit8u i = 0; i < TREMOLO_TABLE / 2; i++ ) { - Bit8u val = i << ENV_EXTRA; - TremoloTable[i] = val; - TremoloTable[TREMOLO_TABLE - 1 - i] = val; + for ( j = 0; j < TREMOLO_TABLE / 2; j++ ) { + Bit8u val = j << ENV_EXTRA; + TremoloTable[j] = val; + TremoloTable[TREMOLO_TABLE - 1 - j] = val; } //Create a table with offsets of the channels from the start of the chip - struct Chip* chip = 0; - for ( Bitu i = 0; i < 32; i++ ) { - Bitu index = i & 0xf; + for ( k = 0; k < 32; k++ ) { + Bitu index = k & 0xf; Bitu blah; + struct Chip *chip = 0; if ( index >= 9 ) { - ChanOffsetTable[i] = 0; + ChanOffsetTable[k] = 0; continue; } //Make sure the four op channels follow eachother @@ -1774,34 +1817,35 @@ static void InitTables( void ) { index = (index % 3) * 2 + ( index / 3 ); } //Add back the bits for highest ones - if ( i >= 16 ) + if ( k >= 16 ) index += 9; blah = (Bitu)( (unsigned long)( &(chip->chan[ index ]) ) ); - ChanOffsetTable[i] = blah; + ChanOffsetTable[k] = (Bit16u)blah; } //Same for operators - for ( Bitu i = 0; i < 64; i++ ) { + for ( k = 0; k < 64; k++ ) { Bitu chNum; Bitu opNum; Bitu blah; struct Channel* chan = 0; - if ( i % 8 >= 6 || ( (i / 8) % 4 == 3 ) ) { - OpOffsetTable[i] = 0; + if ( k % 8 >= 6 || ( (k / 8) % 4 == 3 ) ) { + OpOffsetTable[k] = 0; continue; } - chNum = (i / 8) * 3 + (i % 8) % 3; + chNum = (k / 8) * 3 + (k % 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; + opNum = ( k % 8 ) / 3; blah = (Bitu)( (unsigned long) ( &(chan->op[opNum]) ) ); - OpOffsetTable[i] = ChanOffsetTable[ chNum ] + blah; + OpOffsetTable[k] = (Bit16u)(ChanOffsetTable[ chNum ] + blah); } #if 0 //Stupid checks if table's are correct - for ( Bitu i = 0; i < 18; i++ ) { - Bit32u find = (Bit16u)( &(chip->chan[ i ]) ); - for ( Bitu c = 0; c < 32; c++ ) { + for ( k = 0; k < 18; k++ ) { + Bit32u find = (Bit16u)( &(chip->chan[ k ]) ); + Bitu c; + for ( c = 0; c < 32; c++ ) { if ( ChanOffsetTable[c] == find ) { find = 0; break; @@ -1811,9 +1855,10 @@ static void InitTables( void ) { 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++ ) { + for ( k = 0; k < 36; k++ ) { + Bit32u find = (Bit16u)( &(chip->chan[ k / 2 ].op[k % 2]) ); + Bitu c; + for ( c = 0; c < 64; c++ ) { if ( OpOffsetTable[c] == find ) { find = 0; break; diff --git a/Frameworks/modplay/modplay/dbopl.h b/Frameworks/modplay/modplay/dbopl.h index 8861da622..f3268d5cf 100644 --- a/Frameworks/modplay/modplay/dbopl.h +++ b/Frameworks/modplay/modplay/dbopl.h @@ -43,8 +43,8 @@ typedef unsigned char Bit8u; typedef signed char Bit8s; typedef unsigned short Bit16u; typedef signed short Bit16s; -typedef unsigned long Bit32u; -typedef signed long Bit32s; +typedef unsigned int Bit32u; +typedef signed int Bit32s; #ifdef _MSC_VER typedef unsigned __int64 Bit64u; typedef signed __int64 Bit64s; diff --git a/Frameworks/modplay/modplay/resampler.c b/Frameworks/modplay/modplay/resampler.c index 1bcab7f26..7720230ef 100644 --- a/Frameworks/modplay/modplay/resampler.c +++ b/Frameworks/modplay/modplay/resampler.c @@ -283,6 +283,24 @@ void resampler_write_sample(void *_r, short s) } } +void resampler_write_sample_fixed(void *_r, int s, unsigned char depth) +{ + resampler * r = ( resampler * ) _r; + + if ( r->write_filled < resampler_buffer_size ) + { + float s32 = s; + s32 /= (double)(1 << (depth - 1)); + + r->buffer_in[ r->write_pos ] = s32; + r->buffer_in[ r->write_pos + resampler_buffer_size ] = s32; + + ++r->write_filled; + + r->write_pos = ( r->write_pos + 1 ) % resampler_buffer_size; + } +} + static int resampler_run_zoh(resampler * r, float ** out_, float * out_end) { int in_size = r->write_filled; diff --git a/Frameworks/modplay/modplay/resampler.h b/Frameworks/modplay/modplay/resampler.h index 42ad64dd0..a725f7dd9 100644 --- a/Frameworks/modplay/modplay/resampler.h +++ b/Frameworks/modplay/modplay/resampler.h @@ -13,6 +13,7 @@ #define resampler_set_quality EVALUATE(RESAMPLER_DECORATE,_resampler_set_quality) #define resampler_get_free_count EVALUATE(RESAMPLER_DECORATE,_resampler_get_free_count) #define resampler_write_sample EVALUATE(RESAMPLER_DECORATE,_resampler_write_sample) +#define resampler_write_sample_fixed EVALUATE(RESAMPLER_DECORATE,_resampler_write_sample_fixed) #define resampler_set_rate EVALUATE(RESAMPLER_DECORATE,_resampler_set_rate) #define resampler_ready EVALUATE(RESAMPLER_DECORATE,_resampler_ready) #define resampler_clear EVALUATE(RESAMPLER_DECORATE,_resampler_clear) @@ -43,6 +44,7 @@ void resampler_set_quality(void *, int quality); int resampler_get_free_count(void *); void resampler_write_sample(void *, short sample); +void resampler_write_sample_fixed(void *, int sample, unsigned char depth); void resampler_set_rate( void *, double new_factor ); int resampler_ready(void *); void resampler_clear(void *); diff --git a/Frameworks/modplay/modplay/st3play.c b/Frameworks/modplay/modplay/st3play.c index 32d9b24e6..8d80884f8 100644 --- a/Frameworks/modplay/modplay/st3play.c +++ b/Frameworks/modplay/modplay/st3play.c @@ -1,5 +1,5 @@ /* -** ST3PLAY v0.45 +** ST3PLAY v0.47 ** ============= ** ** C port of Scream Tracker 3's replayer, by 8bitbubsy (Olav Sørensen) @@ -63,6 +63,8 @@ #define inline __forceinline #endif +#include "dbopl.h" + #include "resampler.h" #include "st3play.h" @@ -199,6 +201,12 @@ typedef struct void *resampler[64]; #endif + void *fmChip; + void *fmResampler; + + const uint8_t *fmPatchTable[9]; + uint8_t fmLastB0[9]; + float f_outputFreq; float f_masterVolume; @@ -315,6 +323,7 @@ static const int16_t vibramp[64] = 192, 200, 208, 216, 224, 232, 240, 248 }; +static const char Adlib_PortBases[9] = {0, 1, 2, 8, 9, 10, 16, 17, 18}; // FUNCTION DECLARATIONS @@ -534,6 +543,26 @@ void * st3play_Alloc(uint32_t outputFreq, int8_t interpolation, int8_t ramp_styl return p; } +static int st3play_AdlibInit(PLAYER *p) +{ + p->fmChip = malloc( Chip_GetSize() ); + if ( !p->fmChip ) + return -1; + + Chip_Init( p->fmChip ); + Chip_Setup( p->fmChip, 3579545 * 4, 49716 ); + Chip_WriteReg( p->fmChip, 0x01, 0x20 ); // enable wave select, but rather pointless with dbopl + + p->fmResampler = resampler_create(); + if ( !p->fmResampler ) + return -1; + + resampler_set_quality( p->fmResampler, RESAMPLER_QUALITY_MAX ); + resampler_set_rate( p->fmResampler, 49716.0 / p->f_outputFreq ); + + return 0; +} + void st3play_Free(void *_p) { int i; @@ -542,6 +571,12 @@ void st3play_Free(void *_p) FreeSong(p); + if ( p->fmResampler ) + resampler_delete( p->fmResampler ); + + if ( p->fmChip ) + free( p->fmChip ); + #ifdef USE_VOL_RAMP for (i = 0; i < 64 * 2; ++i) #else @@ -601,9 +636,22 @@ static void settempo(PLAYER *p, uint16_t val) } } +static void st3play_AdlibHertzTouch(PLAYER *p, uint8_t ch, int Hertz, uint8_t keyoff) +{ + int Oct; + + for (Oct = 0; Hertz > 0x1FF; Oct++) + Hertz >>= 1; + + Chip_WriteReg( p->fmChip, 0xA0 + ch, Hertz & 255 ); + p->fmLastB0[ch] = (keyoff ? 0 : 0x20) | ((Hertz >> 8) & 3) | ((Oct & 7) << 2); + Chip_WriteReg( p->fmChip, 0xB0 + ch, p->fmLastB0[ch]); +} + static inline void setspd(PLAYER *p, uint8_t ch) { int32_t tmpspd; + uint8_t adlibChannel = (p->mseg[0x40 + ch] & 0x7F) - 16; tmpspd = p->chn[ch].aspd; @@ -636,16 +684,43 @@ static inline void setspd(PLAYER *p, uint8_t ch) // 14317056 is used in both the ST3 replayer and the S3M format docs if (tmpspd) voiceSetSamplingFrequency(p, ch, 14317056.0f / (float)tmpspd); + + if (adlibChannel < 9) + st3play_AdlibHertzTouch(p, adlibChannel, 14317056.0f / (float)tmpspd, 0); +} + +static void st3play_AdlibTouch(PLAYER *p, uint8_t ch, const uint8_t * patch, uint8_t vol) +{ + int Operator; + + if (!patch) + { + patch = p->fmPatchTable[ch]; + if (!patch) + return; + } + + p->fmPatchTable[ch] = patch; + + Operator = Adlib_PortBases[ch]; + + Chip_WriteReg( p->fmChip, 0x40 + Operator, (patch[2] & 0xC0) | + (((int)(patch[2] & 63) - 63) * vol + 63 * 64 - 32) / 64 ); + Chip_WriteReg( p->fmChip, 0x43 + Operator, (patch[3] & 0xC0) | + (((int)(patch[3] & 63) - 63) * vol + 63 * 64 - 32) / 64 ); } static inline void setvol(PLAYER *p, uint8_t ch, uint8_t sharp) { + uint8_t adlibChannel = (p->mseg[0x40 + ch] & 0x7F) - 16; p->chn[ch].achannelused |= 0x80; #ifdef USE_VOL_RAMP voiceSetVolume(p, ch + ((sharp == 2) ? 32 : 0), (sharp == 2) ? 0.0f : ((float)(p->chn[ch].avol) / 63.0f) * ((float)(p->chn[ch].chanvol) / 64.0f) * ((float)(p->globalvol) / 64.0f), sharp); #else voiceSetVolume(p, ch, ((float)(p->chn[ch].avol) / 63.0f) * ((float)(p->chn[ch].chanvol) / 64.0f) * ((float)(p->globalvol) / 64.0f), sharp); #endif + if (adlibChannel < 9) + st3play_AdlibTouch(p, adlibChannel, NULL, p->chn[ch].avol); } static inline void setpan(PLAYER *p, uint8_t ch) @@ -877,6 +952,30 @@ static inline uint8_t getnote(PLAYER *p) return (ch); } +static void st3play_AdlibPatch(PLAYER *p, uint8_t ch, const uint8_t *patch) +{ + int Operator = Adlib_PortBases[ch]; + + p->fmPatchTable[ch] = patch; + + Chip_WriteReg( p->fmChip, 0x20 + Operator, patch[0]); + Chip_WriteReg( p->fmChip, 0x60 + Operator, patch[4]); + Chip_WriteReg( p->fmChip, 0x80 + Operator, patch[6]); + Chip_WriteReg( p->fmChip, 0xE0 + Operator, patch[8] & 3); + + Chip_WriteReg( p->fmChip, 0x23 + Operator, patch[1]); + Chip_WriteReg( p->fmChip, 0x63 + Operator, patch[5]); + Chip_WriteReg( p->fmChip, 0x83 + Operator, patch[7]); + Chip_WriteReg( p->fmChip, 0xE3 + Operator, patch[9] & 3); + + Chip_WriteReg( p->fmChip, 0xC0 + ch, patch[10]); +} + +static void st3play_AdlibNoteOff(PLAYER *p, uint8_t ch) +{ + Chip_WriteReg( p->fmChip, 0xB0 + ch, p->fmLastB0[ch] & ~0x20 ); +} + static inline void doamiga(PLAYER *p, uint8_t ch) { uint8_t *insdat; @@ -889,6 +988,10 @@ static inline void doamiga(PLAYER *p, uint8_t ch) #ifdef USE_VOL_RAMP uint8_t volassigned = 0; #endif + uint8_t adlibChannel = (p->mseg[0x40 + ch] & 0x7F) - 16; + + if (!p->fmChip || !p->fmResampler) // safety check + adlibChannel = 255; if (p->chn[ch].ins) { @@ -900,7 +1003,7 @@ static inline void doamiga(PLAYER *p, uint8_t ch) insdat = &p->mseg[(uint32_t)(get_le16(&p->mseg[p->instrumentadd + ((p->chn[ch].ins - 1) << 1)])) << 4]; if (insdat[0]) { - if (insdat[0] == 1) + if (insdat[0] == 1 && adlibChannel >= 9) { p->chn[ch].ac2spd = get_le32(&insdat[0x20]); @@ -965,6 +1068,16 @@ static inline void doamiga(PLAYER *p, uint8_t ch) insrepend - insrepbeg, insrepend, loop, insdat[0x1F] & 4, insdat[0x1F] & 2, insdat[0x1E] == 4); } + else if (insdat[0] == 2 && adlibChannel < 9 ) + { + p->chn[ch].ac2spd = 8363 * 164 / 249; + p->chn[ch].avol = (int8_t)(insdat[0x1C]); + p->chn[ch].aorgvol = p->chn[ch].avol; + + st3play_AdlibPatch(p, adlibChannel, &insdat[0x10]); + voiceSetSource(p, ch, NULL, 0, 0, 0, 0, 0, 0, 0); + voiceSetSamplePosition(p, ch, 0); + } else { p->chn[ch].lastins = 0; @@ -997,19 +1110,28 @@ static inline void doamiga(PLAYER *p, uint8_t ch) p->chn[ch].avol = 0; p->chn[ch].asldspd = 65535; - setspd(p, ch); - setvol(p, ch, 0); + if (adlibChannel >= 9) + { + setspd(p, ch); + setvol(p, ch, 0); + } // shutdown channel voiceSetSource(p, ch, NULL, 0, 0, 0, 0, 0, 0, 0); voiceSetSamplePosition(p, ch, 0); + + if (adlibChannel < 9) + st3play_AdlibNoteOff(p, adlibChannel); } else { p->chn[ch].lastnote = p->chn[ch].note; - if ((p->chn[ch].cmd != ('G' - 64)) && (p->chn[ch].cmd != ('L' - 64))) - voiceSetSamplePosition(p, ch, p->chn[ch].astartoffset); + if (adlibChannel >= 9) + { + if ((p->chn[ch].cmd != ('G' - 64)) && (p->chn[ch].cmd != ('L' - 64))) + voiceSetSamplePosition(p, ch, p->chn[ch].astartoffset); + } if (!p->chn[ch].aorgspd || ((p->chn[ch].cmd != ('G' - 64)) && (p->chn[ch].cmd != ('L' - 64)))) { @@ -1017,11 +1139,18 @@ static inline void doamiga(PLAYER *p, uint8_t ch) p->chn[ch].aorgspd = p->chn[ch].aspd; p->chn[ch].avibcnt = 0; p->chn[ch].apancnt = 0; - + setspd(p, ch); } p->chn[ch].asldspd = scalec2spd(p, ch, stnote2herz(p, p->chn[ch].note)); + + if (adlibChannel < 9) + { + st3play_AdlibNoteOff(p, adlibChannel); + setspd(p, ch); + st3play_AdlibTouch(p, adlibChannel, NULL, p->chn[ch].avol); + } } } @@ -1099,7 +1228,7 @@ static inline void donotes(PLAYER *p) ch = getnote(p); if (ch == 255) break; // end of row/channels - if ((p->mseg[0x40 + ch] & 0x7F) <= 15) // no adlib channel types yet + if ((p->mseg[0x40 + ch] & 0x7F) <= 15 + 9) donewnote(p, ch, 0); } } @@ -1362,7 +1491,7 @@ static void loadheaderparms(PLAYER *p) insdat = &p->mseg[get_le16(&p->mseg[p->instrumentadd + (i << 1)]) << 4]; insoff = (uint32_t)(((uint32_t)(insdat[0x0D])<<16)|((uint16_t)(insdat[0x0F])<<8)|insdat[0x0E])<<4; - if (insoff && (insdat[0] == 1)) + if (insoff && (insdat[0] == 1)) // PCM { if (insoff > p->mseg_len) insoff = p->mseg_len; @@ -1391,6 +1520,11 @@ static void loadheaderparms(PLAYER *p) p->mseg[insoff + j] = p->mseg[insoff + j] - 0x80; } } + else if (insdat[0] == 2) // AdLib melodic + { + if (!p->fmChip && st3play_AdlibInit(p) < 0) + break; + } } } } @@ -1564,12 +1698,8 @@ static void s_setpanwave(PLAYER *p, chn_t *ch) // NON-ST3 static void s_setpanpos(PLAYER *p, chn_t *ch) { - if (p->stereomode) - { - ch->apanpos = (ch->info & 0x0F) << 4; - - setpan(p, ch->channelnum); - } + ch->apanpos = (ch->info & 0x0F) << 4; + setpan(p, ch->channelnum); } static void s_sndcntrl(PLAYER *p, chn_t *ch) // NON-ST3 @@ -1636,7 +1766,12 @@ static void s_notecutb(PLAYER *p, chn_t *ch) { ch->anotecutcnt--; if (!ch->anotecutcnt) + { + uint8_t adlibChannel = (p->mseg[0x40 + ch->channelnum] & 0x7F) - 16; voiceSetSamplingFrequency(p, ch->channelnum, 0); // cut note + if (adlibChannel < 9) + st3play_AdlibNoteOff(p, adlibChannel); + } } } @@ -3570,6 +3705,45 @@ void mixSampleBlock(PLAYER *p, float *outputStream, uint32_t sampleBlockLength) } } +static void st3play_AdlibMix(PLAYER *p, float *buffer, int32_t count) +{ + Bit32s tempbuffer[256]; + int inbuffer_free, i; + int outbuffer_avail; + + while (count) + { + inbuffer_free = resampler_get_free_count( p->fmResampler ); + + if (inbuffer_free > 256) + inbuffer_free = 256; + + if (inbuffer_free) + { + Chip_GenerateBlock2( p->fmChip, inbuffer_free, tempbuffer ); + for (i = 0; i < inbuffer_free; ++i) + resampler_write_sample_fixed( p->fmResampler, (int)tempbuffer[i], 16); + } + + outbuffer_avail = resampler_get_sample_count( p->fmResampler ); + + if (outbuffer_avail > count) + outbuffer_avail = count; + + for (i = 0; i < outbuffer_avail; ++i) + { + float sample = resampler_get_sample( p->fmResampler ); + resampler_remove_sample( p->fmResampler ); + + buffer[i * 2 + 0] += sample; + buffer[i * 2 + 1] += sample; + } + + buffer += outbuffer_avail * 2; + count -= outbuffer_avail; + } +} + void st3play_RenderFloat(void *_p, float *buffer, int32_t count) { PLAYER * p = (PLAYER *)_p; @@ -3591,6 +3765,9 @@ void st3play_RenderFloat(void *_p, float *buffer, int32_t count) { mixSampleBlock(p, outputStream, samplesTodo); + if (p->fmChip && p->fmResampler) + st3play_AdlibMix( p, outputStream, samplesTodo ); + outputStream += (samplesTodo << 1); }