Skip to content

Commit de9a866

Browse files
committed
Migrate to a more versatile common player loop that handles delayed DMA on/off. Add two variants with different execution order, one for TFMX v1, that remain compatible with the macro state flag and effects mode flag. Flag Quik'n'Silva accordingly. Implement the rare DMA on with arg. // fixes #21 fixes #19 related to #15
1 parent 90dde18 commit de9a866

4 files changed

Lines changed: 70 additions & 46 deletions

File tree

src/Chris/ByChecksum.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ void tfmxaudiodecoder::TFMXDecoder::traitsByChecksum() {
5252
// Turrican II (1991) ingame music requires a special player variant
5353
// with different execution order of macros and effects.
5454
if (T2_checksums.count(crc1) >= 1) {
55-
variant.styleT2 = true;
55+
variant.execOrder = MOD_MAC_SEQ;
5656
}
5757
// Turrican (1990) is a TFMXv1 variant and strictly requires old
5858
// features such as non-scaled vibrato/portamento.
@@ -83,6 +83,10 @@ void tfmxaudiodecoder::TFMXDecoder::traitsByChecksum() {
8383
setTFMXv1();
8484
variant.macroLoopExtraWait = true;
8585
}
86+
// The Adventures of Quik & Silva.
87+
else if (crc1 == 0x04f469a6 || crc1 == 0xd37c9008 ) {
88+
variant.execOrder = MAC_MOD_SEQ;
89+
}
8690
// Rock'n'Roll (1989). No checksum based adjustments required, because
8791
// it uses the unique header tag that was specific to TFMX before v1.
8892
// Except for the intro.

src/Chris/Macro.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,13 +175,34 @@ void TFMXDecoder::macroFunc_StartSample(VoiceVars& voice) {
175175
// There are variants of the "DMAon" macro command, which
176176
// are not needed because we don't emulate access to Amiga
177177
// custom chip registers like DMACON, INTENA and INTREQ.
178-
if (variant.styleT2) {
179-
voice.macro.delayedOn = true;
178+
if ( variant.noDelayedDMAon ) {
179+
voice.ch->on();
180180
}
181181
else {
182-
voice.ch->on();
183-
voice.effectsMode = (sbyte)cmd.bb;
182+
voice.macro.delayedOn = true;
183+
}
184+
185+
// Variants of the player can set the macro wait value here.
186+
// The high byte (in cmd.aa) is set to zero early, so only the
187+
// low byte (in cmd.bb) would matter. However, as the low byte
188+
// is 0 for all but a very few TFMX files, the resulting wait
189+
// value would stay at 0, which would be pointless.
190+
//
191+
// Furthermore, of the existing files that run a subsequent Wait
192+
// command, that wait value would take precedence. It can be
193+
// assumed that setting the wait value here is not the real goal.
194+
//
195+
// Instead, of the few remaining files that set the first parameter
196+
// to 1, they want the player to run sound synthesis via the effects
197+
// processor a first time before turning on the audio channel.
198+
if (cmd.bb != 0) {
199+
voice.effectsMode = 1;
200+
if (variant.execOrder == MOD_MAC_SEQ) {
201+
processModulation(voice);
202+
return;
203+
}
184204
}
205+
185206
voice.macro.step++;
186207
macroEvalAgain = true;
187208
}

src/Chris/TFMXDecoder.cpp

Lines changed: 28 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -303,8 +303,9 @@ bool TFMXDecoder::init(void *data, udword length, int songNumber) {
303303
variant.macroLoopExtraWait = false;
304304
variant.bpmSpeed5 = false;
305305
variant.noAddBeginCount = false;
306+
variant.noDelayedDMAon = false;
306307
variant.noTrackMute = false;
307-
variant.styleT2 = false;
308+
variant.execOrder = MAC_MOD_SEQ;
308309

309310
PattCmdFuncs[0] = &TFMXDecoder::pattCmd_End;
310311
PattCmdFuncs[1] = &TFMXDecoder::pattCmd_Loop;
@@ -506,6 +507,8 @@ void TFMXDecoder::setTFMXv1() {
506507
variant.portaOverride = true;
507508
variant.setNoteV1 = true;
508509
variant.extraWaitV1 = true;
510+
variant.noDelayedDMAon = true;
511+
variant.execOrder = SEQ_MOD_MAC;
509512
MacroDefs[0xd] = &macroDef_AddVolume;
510513
// max. macro cmd = $19
511514
for (ubyte m = 0x1a; m<0x40; m++) {
@@ -746,12 +749,7 @@ int TFMXDecoder::run() {
746749
#if defined(DEBUG_RUN)
747750
dumpTimestamp(songPosCurrent);
748751
#endif
749-
if (variant.styleT2) {
750-
playerStyleT2();
751-
}
752-
else {
753-
playerCommon();
754-
}
752+
playerCommon();
755753
tickFPadd += tickFP;
756754
int tick = tickFPadd>>8;
757755
tickFPadd &= 0xff;
@@ -766,39 +764,35 @@ void TFMXDecoder::playerCommon() {
766764
if ( !songEnd || loopMode ) {
767765
handleWaitOnPaulaDone();
768766
handleDelayedDMAoff();
769-
for (ubyte v=0; v<voices; v++) {
770-
VoiceVars& voice = voiceVars[v];
771-
processMacroMain( voice );
772-
processModulation( voice );
773-
voice.ch->paula.period = voice.outputPeriod;
774-
}
775-
runMain();
776-
}
777-
}
778767

779-
// Note: This is not final yet. In variants of the TFMX player, order of
780-
// execution and usage of macro state/skip flag, effects mode flag and
781-
// extra wait is all over the place.
782-
void TFMXDecoder::playerStyleT2() {
783-
#if defined(DEBUG_RUN)
784-
cout << " playerStyleT2()" << endl;
785-
#endif
786-
if ( !songEnd || loopMode ) {
787-
handleWaitOnPaulaDone();
788-
handleDelayedDMAoff();
789-
for (ubyte v=0; v<voices; v++) {
790-
VoiceVars& voice = voiceVars[v];
791-
if (voice.macro.state <= 0) {
768+
if (variant.execOrder == MOD_MAC_SEQ) {
769+
for (ubyte v=0; v<voices; v++) {
770+
VoiceVars& voice = voiceVars[v];
792771
processModulation( voice );
793772
processMacroMain( voice );
773+
voice.ch->paula.period = voice.outputPeriod;
794774
}
795-
else if (voice.macro.state > 0) {
775+
runMain();
776+
}
777+
else if (variant.execOrder == SEQ_MOD_MAC) {
778+
runMain();
779+
for (ubyte v=0; v<voices; v++) {
780+
VoiceVars& voice = voiceVars[v];
781+
processModulation( voice );
782+
processMacroMain( voice );
783+
voice.ch->paula.period = voice.outputPeriod;
784+
}
785+
}
786+
else { // if (variant.execOrder == MAC_MOD_SEQ) {
787+
for (ubyte v=0; v<voices; v++) {
788+
VoiceVars& voice = voiceVars[v];
796789
processMacroMain( voice );
797-
voice.effectsMode = 1; // force to ON for this player variant
790+
processModulation( voice );
791+
voice.ch->paula.period = voice.outputPeriod;
798792
}
799-
voice.ch->paula.period = voice.outputPeriod;
793+
runMain();
800794
}
801-
runMain();
795+
802796
handleDelayedDMAon();
803797
}
804798
}
@@ -840,12 +834,7 @@ void TFMXDecoder::noteCmd() {
840834
v.note = cmd.aa;
841835
v.keyUp = false;
842836
v.macro.offset = getMacroOffset(cmd.bb & 0x7f);
843-
if (variant.styleT2) {
844-
v.macro.state = 1;
845-
}
846-
else {
847-
initMacro(v);
848-
}
837+
v.macro.state = 1;
849838
}
850839
else { // cmd.aa >= $c0 portamento note
851840
v.portamento.count = cmd.bb;

src/Chris/TFMXDecoder.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@ class TFMXDecoder : public Decoder {
8585
udword trackTableEnd;
8686
} offsets;
8787

88+
enum ExecOrder {
89+
// SEQ : sequencer
90+
// MAC : macro processing
91+
// MOD : modulation/effects processing
92+
SEQ_MOD_MAC,
93+
MOD_MAC_SEQ,
94+
MAC_MOD_SEQ
95+
};
96+
8897
struct Admin {
8998
sword speed, count; // speed and speed count
9099
int startSpeed, startSong;
@@ -250,7 +259,6 @@ class TFMXDecoder : public Decoder {
250259
void runMain();
251260
void processPTTR(Track&);
252261
void playerCommon();
253-
void playerStyleT2();
254262

255263
void processModulation(VoiceVars&);
256264
void addBegin(VoiceVars&);
@@ -556,8 +564,10 @@ class TFMXDecoder : public Decoder {
556564
bool macroLoopExtraWait;
557565
bool bpmSpeed5;
558566
bool noAddBeginCount;
567+
bool noDelayedDMAon;
559568
bool noTrackMute;
560-
bool styleT2;
569+
// Main player order of execution.
570+
ExecOrder execOrder;
561571
} variant;
562572

563573
struct {

0 commit comments

Comments
 (0)