[Scummvm-git-logs] scummvm master -> f4a7f3f69ac202df7121e04d10742a29fc2f75a2
neuromancer
noreply at scummvm.org
Tue Jul 8 06:40:59 UTC 2025
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
f4a7f3f69a FREESCAPE: improved code for c64 music, which starts to work
Commit: f4a7f3f69ac202df7121e04d10742a29fc2f75a2
https://github.com/scummvm/scummvm/commit/f4a7f3f69ac202df7121e04d10742a29fc2f75a2
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-07-08T08:36:01+02:00
Commit Message:
FREESCAPE: improved code for c64 music, which starts to work
Changed paths:
engines/freescape/games/driller/c64.cpp
engines/freescape/games/driller/c64.music.cpp
engines/freescape/games/driller/driller.cpp
diff --git a/engines/freescape/games/driller/c64.cpp b/engines/freescape/games/driller/c64.cpp
index 4209f028e1e..314efbef187 100644
--- a/engines/freescape/games/driller/c64.cpp
+++ b/engines/freescape/games/driller/c64.cpp
@@ -158,7 +158,7 @@ void DrillerEngine::loadAssetsC64FullGame() {
} else
error("Unknown C64 release");
- //_playerSid = new DrillerSIDPlayer(_mixer);
+ _playerSid = new DrillerSIDPlayer(_mixer);
}
diff --git a/engines/freescape/games/driller/c64.music.cpp b/engines/freescape/games/driller/c64.music.cpp
index bf9c5f4bf18..2bab24e4520 100644
--- a/engines/freescape/games/driller/c64.music.cpp
+++ b/engines/freescape/games/driller/c64.music.cpp
@@ -547,301 +547,233 @@ void DrillerSIDPlayer::playVoice(int voiceIndex, bool tempoTick) {
}
}
- // --- Tempo Tick: Process note/delay ---
- if (tempoTick) { // Added braces for clarity
- // Corresponds to L0964 -> L096E path when tempo_ctr hits 0
-
- // Decrement voice delay counter (0x0969 dec voice1_ctrl2,x)
- if (v.delayCounter >= 0) { // If positive or zero, decrement
- v.delayCounter--;
- // --- Fix 4: Add Logging ---
- debug(DEBUG_LEVEL >= 2, "Driller V1: Tempo Tick - Delay Counter decremented to %d", v.delayCounter);
- // --- End Fix 4 ---
- }
-
- // If counter is still non-negative (was >= 0 before decrement), note holds
+ if (tempoTick) {
if (v.delayCounter >= 0) {
- // bmi L09B6 is false
- // Apply continuous effects for this frame (original jumps to L0B33 via L096E)
- applyContinuousEffects(v, sidOffset, instA0, instA1);
- return; // Return AFTER applying effects for the holding note
- }
-
- // --- Delay Counter Expired (was 0, now -1): Read New Note/Command (L09B6 onwards) ---
- debug(DEBUG_LEVEL >= 1, "Driller V1: Delay Counter Expired - Reading new pattern data"); // Add this log
-
- // ... rest of pattern reading logic ...
-
- } else { // Not a tempo tick
- applyContinuousEffects(v, sidOffset, instA0, instA1);
- return; // No note processing on non-tempo ticks
- }
-
- // If tempoTick was true AND delayCounter became < 0, pattern processing happened above.
- // If we reach here, it means a new note/command was processed.
- // Do we need to call applyContinuousEffects *again*?
- // The original assembly jumps to voice_done (0B30, 0CCB etc) after effects or note setting.
- // Let's assume effects are applied either during hold (in the delayCounter >= 0 block)
- // or implicitly handled as part of the new note setup (e.g. frequency set directly).
- // Avoid calling applyContinuousEffects twice per tick.
- // The structure now correctly handles this:
- // - If !tempoTick -> applyEffects -> return
- // - If tempoTick:
- // - Decrement delay
- // - If delay >= 0 -> applyEffects -> return
- // - If delay < 0 -> processPattern -> (applyNote potentially called) -> implicit return (end of function)
-
- // --- Delay Counter Expired (was 0, now -1): Read New Note/Command (L09B6 onwards) ---
- // Reset delay counter - will be set by FD command later if needed. Stays -1 for now.
-
- // Store track/pattern pointers locally (like 09B6-09BE)
- // Already have v.trackDataPtr, v.patternDataPtr
-
- // Get current pattern index from track (09C0-09CE)
- uint8_t patternNum = v.trackDataPtr[v.trackIndex];
-
- // Handle track end/loop markers (0AE7, 0AF2)
- if (patternNum == 0xFF) { // End of track list
- debug(DEBUG_LEVEL >= 1, "Driller V%d: Track %d end marker (FF), looping.", voiceIndex, v.trackIndex);
- v.trackIndex = 0; // Loop to start
- patternNum = v.trackDataPtr[v.trackIndex];
- if (patternNum == 0xFF || patternNum == 0xFE || !tune_track_data[_targetTuneIndex][voiceIndex]) { // Check again after loop or if track is null initially
- debug(DEBUG_LEVEL >= 0, "Driller V%d: Stopping music after track loop (FF/FE/Null).", voiceIndex);
- stopMusic(); // Stop if loop points to end marker or track is invalid
- return;
- }
- } else if (patternNum == 0xFE) { // Stop playback command
- debug(DEBUG_LEVEL >= 0, "Driller V%d: Stopping music due to track marker FE.", voiceIndex);
- stopMusic();
- return;
- }
-
- if (patternNum >= NUM_PATTERNS) {
- debug(DEBUG_LEVEL >= 0, "Driller V%d: Invalid pattern number %d at track index %d", voiceIndex, patternNum, v.trackIndex);
- v.trackIndex++; // Skip invalid entry
- // Fetch next pattern number immediately to avoid getting stuck in invalid state for a frame
- size_t trackSize = (voiceIndex == 0) ? sizeof(voice1_track_data) : ((voiceIndex == 1) ? sizeof(voice2_track_data) : sizeof(voice3_track_data));
- if (v.trackIndex >= trackSize) { // Check for track end
- debug(DEBUG_LEVEL >= 0, "Driller V%d: Stopping music, track index out of bounds after skipping invalid pattern.", voiceIndex);
- stopMusic();
- return;
- }
- patternNum = v.trackDataPtr[v.trackIndex];
- if (patternNum == 0xFF || patternNum == 0xFE) {
- debug(DEBUG_LEVEL >= 0, "Driller V%d: Stopping music, encountered FF/FE after skipping invalid pattern.", voiceIndex);
- stopMusic();
- return;
- }
- if (patternNum >= NUM_PATTERNS) { // Still invalid? Stop.
- debug(DEBUG_LEVEL >= 0, "Driller V%d: Stopping music, encountered second invalid pattern.", voiceIndex);
- stopMusic();
- return;
- }
- // Continue with the new valid patternNum
- }
-
- // Only update pattern pointer if it changed or wasn't set
- if (v.patternDataPtr != pattern_addresses[patternNum]) {
- v.patternDataPtr = pattern_addresses[patternNum];
- v.patternIndex = 0; // Reset index when pattern changes
- debug(DEBUG_LEVEL >= 2, "Driller V%d: Switched to Pattern %d", voiceIndex, patternNum);
- }
-
- // Reset state related to previous note/effects for gate control
- _tempControl3 = 0xFF; // Reset gate mask (0x09D0) - Currently unused in C++ code
- v.whatever0 = 0; // Reset effect states (0x09D5 onwards)
- v.whatever1 = 0;
- v.whatever2 = 0;
-
- // --- Read Pattern Data Loop (0x09E0 read_note_or_ctrl) ---
- bool noteProcessed = false;
- while (!noteProcessed) {
- if (!v.patternDataPtr) { // Safety check
- debug(DEBUG_LEVEL >= 0, "Driller V%d: Pattern pointer is null!", voiceIndex);
- v.trackIndex++; // Advance track to avoid getting stuck
- noteProcessed = true; // Exit loop, try next track index next frame
- break;
- }
-
- // Check pattern bounds - Use FF as terminator
- if (v.patternIndex >= 255) { // Sanity check pattern length
- debug(DEBUG_LEVEL >= 0, "Driller V%d: Pattern index overflow (>255), resetting.", voiceIndex);
- v.patternIndex = 0; // Reset pattern index
- v.trackIndex++; // Advance track index
- noteProcessed = true; // Exit loop
- break; // Go to next track entry
- }
-
- uint8_t cmd = v.patternDataPtr[v.patternIndex];
- debug(DEBUG_LEVEL >= 3, "Driller V%d: Reading Pat %d Idx %d: Cmd $%02X", voiceIndex, patternNum, v.patternIndex, cmd);
-
- if (cmd == 0xFF) { // End of pattern marker (0x0AD6)
- debug(DEBUG_LEVEL >= 2, "Driller V%d: End of Pattern %d detected.", voiceIndex, patternNum);
- v.patternIndex = 0; // Reset pattern index
- v.trackIndex++; // Advance track index (0x0ADF)
- noteProcessed = true; // Exit inner loop, done processing for this tick
- break; // Exit pattern loop, next tick will get next pattern index from track
+ v.delayCounter--;
}
- if (cmd >= 0xFD) { // --- Control Commands ---
- v.patternIndex++; // Consume command byte
- if (!v.patternDataPtr || v.patternDataPtr[v.patternIndex] == 0xFF) { // Check bounds before reading data
- debug(DEBUG_LEVEL >= 1, "Driller V%d: Pattern ended unexpectedly after Fx command.", voiceIndex);
- noteProcessed = true;
- break;
+ // If delay counter has expired, read new data from the pattern.
+ if (v.delayCounter < 0) {
+ debug(DEBUG_LEVEL >= 1, "Driller V%d: Delay Counter Expired - Reading new pattern data", voiceIndex);
+
+ // --- Start of inlined pattern reading logic ---
+ // Get current pattern index from track (09C0-09CE)
+ uint8_t patternNum = v.trackDataPtr[v.trackIndex];
+
+ // Handle track end/loop markers (0AE7, 0AF2)
+ if (patternNum == 0xFF) { // End of track list
+ debug(DEBUG_LEVEL >= 1, "Driller V%d: Track %d end marker (FF), looping.", voiceIndex, v.trackIndex);
+ v.trackIndex = 0; // Loop to start
+ patternNum = v.trackDataPtr[v.trackIndex];
+ if (patternNum == 0xFF || patternNum == 0xFE || !tune_track_data[_targetTuneIndex][voiceIndex]) { // Check again after loop or if track is null initially
+ debug(DEBUG_LEVEL >= 0, "Driller V%d: Stopping music after track loop (FF/FE/Null).", voiceIndex);
+ stopMusic(); // Stop if loop points to end marker or track is invalid
+ return;
+ }
+ } else if (patternNum == 0xFE) { // Stop playback command
+ debug(DEBUG_LEVEL >= 0, "Driller V%d: Stopping music due to track marker FE.", voiceIndex);
+ stopMusic();
+ return;
}
- uint8_t dataByte = v.patternDataPtr[v.patternIndex]; // Read data byte
- // Effect FD: Set Note Duration (0x09E5 + 0x09ED)
- if (cmd == 0xFD) {
- v.noteDuration = dataByte; // Store duration (0x09EF)
- debug(DEBUG_LEVEL >= 2, "Driller V%d: Cmd FD, Set Duration = %d", voiceIndex, v.noteDuration);
- }
- // Effect FC: Portamento Up (0x0A17) / FE in disassembly comment? Check logic.
- // Original checks FD, then FB, then FA. FE is not checked explicitly.
- // Assuming FE should behave like FC based on command range >= FD.
- else if (cmd == 0xFE) { // FC in disassembly checks cmp #$FB, bne @effect_fc_2
- debug(DEBUG_LEVEL >= 2, "Driller V%d: Cmd FE/FC, Porta Up Param = $%02X", voiceIndex, dataByte);
- if (v.currentNote > 0) { // Only apply if a note is playing
- v.whatever2 = (instA0[7] & 0x02) ? 4 : 2; // Porta Up Type
- v.portaStepRaw = dataByte;
- v.whatever0 = 0;
- v.whatever1 = 0; // Reset other effects
- v.portaSpeed = 0; // Force recalc
+ if (patternNum >= NUM_PATTERNS) {
+ debug(DEBUG_LEVEL >= 0, "Driller V%d: Invalid pattern number %d at track index %d", voiceIndex, patternNum, v.trackIndex);
+ v.trackIndex++; // Skip invalid entry
+ // Fetch next pattern number immediately to avoid getting stuck in invalid state for a frame
+ size_t trackSize = (voiceIndex == 0) ? sizeof(voice1_track_data) : ((voiceIndex == 1) ? sizeof(voice2_track_data) : sizeof(voice3_track_data));
+ if (v.trackIndex >= trackSize) { // Check for track end
+ debug(DEBUG_LEVEL >= 0, "Driller V%d: Stopping music, track index out of bounds after skipping invalid pattern.", voiceIndex);
+ stopMusic();
+ return;
}
+ patternNum = v.trackDataPtr[v.trackIndex];
+ if (patternNum == 0xFF || patternNum == 0xFE) {
+ debug(DEBUG_LEVEL >= 0, "Driller V%d: Stopping music, encountered FF/FE after skipping invalid pattern.", voiceIndex);
+ stopMusic();
+ return;
+ }
+ if (patternNum >= NUM_PATTERNS) { // Still invalid? Stop.
+ debug(DEBUG_LEVEL >= 0, "Driller V%d: Stopping music, encountered second invalid pattern.", voiceIndex);
+ stopMusic();
+ return;
+ }
+ // Continue with the new valid patternNum
}
- // Effect FB: Portamento Down (0x09FB)
- else { // Must be FB (This case unreachable if cmd == 0xFE handled above?)
- // Correction: Original logic is cmp $FD -> bcc check_fb_fc -> cmp $FB -> bcc check_fa -> cmp $FB -> bne effect_fc -> effect_fb
- // So if >= FD, it *is* FD. If not FD, then check FB. If FB, do FB. If not FB, do FC (lda #2, bne do_effect).
- // Let's fix the logic:
- /* Handled above for FD */
- debug(DEBUG_LEVEL >= 0, "Driller V%d: Unexpected path for Cmd $%02X", voiceIndex, cmd);
- }
- // Continue reading pattern (next_note_or_ctrl 09F2/0A15)
- v.patternIndex++;
-
- } else if (cmd >= 0xFB) { // Effect FB/FC
- v.patternIndex++; // Consume command byte
- if (!v.patternDataPtr || v.patternDataPtr[v.patternIndex] == 0xFF) { // Check bounds before reading data
- debug(DEBUG_LEVEL >= 1, "Driller V%d: Pattern ended unexpectedly after FB/FC command.", voiceIndex);
- noteProcessed = true;
- break;
+
+ // Only update pattern pointer if it changed or wasn't set
+ if (v.patternDataPtr != pattern_addresses[patternNum]) {
+ v.patternDataPtr = pattern_addresses[patternNum];
+ v.patternIndex = 0; // Reset index when pattern changes
+ debug(DEBUG_LEVEL >= 2, "Driller V%d: Switched to Pattern %d", voiceIndex, patternNum);
}
- uint8_t portaParam = v.patternDataPtr[v.patternIndex]; // Consume data byte
-
- if (v.currentNote > 0) {
- // Set porta type (1=Down(FB), 2=Up(FC)) or (3=DownH, 4=UpH)
- if (cmd == 0xFB) { // effect_fb_1
- v.whatever2 = (instA0[7] & 0x02) ? 3 : 1; // (0A01)
- debug(DEBUG_LEVEL >= 2, "Driller V%d: Cmd FB, Porta Down Param = $%02X (Type %d)", voiceIndex, portaParam, v.whatever2);
- } else { // FC (effect_fc_2)
- v.whatever2 = (instA0[7] & 0x02) ? 4 : 2; // (0A17 -> 0A01)
- debug(DEBUG_LEVEL >= 2, "Driller V%d: Cmd FC, Porta Up Param = $%02X (Type %d)", voiceIndex, portaParam, v.whatever2);
+
+ // Reset state related to previous note/effects for gate control
+ _tempControl3 = 0xFF; // Reset gate mask (0x09D0) - Currently unused in C++ code
+ v.whatever0 = 0; // Reset effect states (0x09D5 onwards)
+ v.whatever1 = 0;
+ v.whatever2 = 0;
+
+ // --- Read Pattern Data Loop (0x09E0 read_note_or_ctrl) ---
+ bool noteProcessed = false;
+ while (!noteProcessed) {
+ if (!v.patternDataPtr) { // Safety check
+ debug(DEBUG_LEVEL >= 0, "Driller V%d: Pattern pointer is null!", voiceIndex);
+ v.trackIndex++; // Advance track to avoid getting stuck
+ noteProcessed = true; // Exit loop, try next track index next frame
+ break;
}
- v.portaStepRaw = portaParam; // Store raw porta speed (0A0A / 0A19->0A0A)
- v.whatever0 = 0; // Reset vibrato state (0A0D)
- v.whatever1 = 0; // Reset arpeggio state (0A0F)
- v.portaSpeed = 0; // Force recalc
- } else {
- debug(DEBUG_LEVEL >= 2, "Driller V%d: Ignoring FB/FC command, no note playing.", voiceIndex);
- }
- v.patternIndex++; // Continue reading pattern (0A15)
-
- } else if (cmd == 0xFA) { // --- Effect FA: Set Instrument --- (0x0A1B)
- v.patternIndex++;
- if (!v.patternDataPtr || v.patternDataPtr[v.patternIndex] == 0xFF) { // Check bounds before reading data
- debug(DEBUG_LEVEL >= 1, "Driller V%d: Pattern ended unexpectedly after FA command.", voiceIndex);
- noteProcessed = true;
- break;
- }
- uint8_t instNum = v.patternDataPtr[v.patternIndex];
- if (instNum >= NUM_INSTRUMENTS) {
- debug(DEBUG_LEVEL >= 0, "Driller V%d: Invalid instrument number %d, using 0.", voiceIndex, instNum);
- instNum = 0;
- }
- v.instrumentIndex = instNum * 8; // Store base offset (0A28)
- debug(DEBUG_LEVEL >= 2, "Driller V%d: Cmd FA, Set Instrument = %d", voiceIndex, instNum);
-
- // Update local pointers for instrument data
- instBase = v.instrumentIndex;
- if (instBase < 0 || (size_t)instBase >= sizeof(instrumentDataA0))
- instBase = 0; // Bounds check
- instA0 = &instrumentDataA0[instBase];
- instA1 = &instrumentDataA1[instBase];
-
- // Set ADSR based on instrument (0A2C - 0A3E)
- uint8_t adsrByte = instA0[0]; // 0A2C
- v.sustainRelease = adsrByte & 0x0F; // Low nibble to SR (0A32) -> ctrl0
- v.attackDecay = adsrByte & 0xF0; // High nibble to AD (0A3B/0A3E) -> something_else[0/1]
- // Store in voice state for SID write later
- v.ctrl0 = v.sustainRelease;
- v.something_else[0] = v.attackDecay; // Map to something_else array
- v.something_else[1] = v.attackDecay; // Seems duplicated in disassembly?
- // Also set PW from instA0[0]? Disassembly sets something_else[0] and [1] to AD (hi nibble)
- // Pulse width seems set later from something_else[0] and [2] ? Let's use [0] for AD.
- // Let's assume instA0[2] (often xx) and instA0[3] (often 00) are PW lo/hi nibble?
- // Or maybe something_else[0]/[2] ARE PW and ADSR needs separate vars?
- // Revisit PW setting in applyNote based on L0AC2. It uses something_else[0] and [2].
- // Let's store ADSR in dedicated vars, and use something_else for PW based on instrument.
- // What part of instrument sets PW? L0AC2 uses something_else[0/2]. FA command sets something_else[0/1/2].
- // FA: pla -> and #F0 -> sta something_else[0] / [1]
- // FA: pha -> and #0F -> sta something_else[2] / ctrl0
- // This means: AD Hi Nibble -> PW Lo Byte? AD Hi Nibble -> something_else[1]? SR Lo Nibble -> PW Hi Nibble? SR Lo Nibble -> ctrl0?
- // Let's follow the variable names:
- v.attackDecay = instA0[0] & 0xF0; // Stored in something_else[0] & [1]
- v.sustainRelease = instA0[0] & 0x0F; // Stored in something_else[2] & ctrl0
- v.something_else[0] = v.attackDecay;
- v.something_else[1] = v.attackDecay; // ???
- v.something_else[2] = v.sustainRelease; // PW Hi?
- v.ctrl0 = v.sustainRelease; // SR?
-
- debug(DEBUG_LEVEL >= 3, "Driller V%d: Inst %d - ADSR Byte: $%02X -> AD: $%02X, SR: $%02X", voiceIndex, instNum, adsrByte, v.attackDecay, v.sustainRelease);
-
- // Continue reading pattern (0A41 -> 09F2)
- v.patternIndex++;
-
- } else { // --- Plain Note --- (0x0A1D -> 0A44)
- v.currentNote = cmd; // Store note value (0A44)
- debug(DEBUG_LEVEL >= 2, "Driller V%d: Note Cmd = $%02X (%d)", voiceIndex, v.currentNote, v.currentNote);
- // Set delay counter based on previously read duration (FD command)
- // If no FD command, duration is 0, so delayCounter is set to 0
- // The counter is checked *after* decrementing. So if duration is N, it lasts N ticks.
- // If duration is 1, counter=1 -> dec=0 -> hold -> dec=-1 -> new note. Lasts 1 tick.
- // If duration is 0, counter=0 -> dec=-1 -> new note. Lasts 0 ticks (effectively ignored?).
- // Let's set counter = duration.
- v.delayCounter = v.noteDuration; // (0A47 -> 0A4A)
- v.noteDuration = 0; // Reset duration for next note
-
- // Reset hard restart counters (0A4D)
- v.whatever3 = 0;
- v.whatever4 = 0;
-
- // Reset glide down timer (0A55)
- v.glideDownTimer = 2; // voice1_two_ctr = 2
-
- // Handle legato/slide (Instrument A0[7] & 0x02) (0A5D)
- if (instA0[7] & 0x02) { // Check legato bit
- // Copy AD high nibble again? (0A64) - Seems redundant
- // v.something_else[0] = v.attackDecay; // If something_else maps to PW, this overwrites PW?
- // Copy SR low nibble again? (0A6A)
- // v.sustainRelease = v.ctrl0; // Ensure SR matches instrument
- // Store in something_else[2]? Original stores ctrl0 to [2] (0A6D)
- // v.something_else[2] = v.ctrl0; // Map ADSR to structure? No, assume PW.
- // This block in assembly seems to just reload ADSR values into temp locations? Ignore for C++ struct model.
- debug(DEBUG_LEVEL >= 3, "Driller V%d: Legato instrument flag set.", voiceIndex);
- }
+ // Check pattern bounds - Use FF as terminator
+ if (v.patternIndex >= 255) { // Sanity check pattern length
+ debug(DEBUG_LEVEL >= 0, "Driller V%d: Pattern index overflow (>255), resetting.", voiceIndex);
+ v.patternIndex = 0; // Reset pattern index
+ v.trackIndex++; // Advance track index
+ noteProcessed = true; // Exit loop
+ break; // Go to next track entry
+ }
+
+ uint8_t cmd = v.patternDataPtr[v.patternIndex];
+ debug(DEBUG_LEVEL >= 3, "Driller V%d: Reading Pat %d Idx %d: Cmd $%02X", voiceIndex, patternNum, v.patternIndex, cmd);
+
+ if (cmd == 0xFF) { // End of pattern marker (0x0AD6)
+ debug(DEBUG_LEVEL >= 2, "Driller V%d: End of Pattern %d detected.", voiceIndex, patternNum);
+ v.patternIndex = 0; // Reset pattern index
+ v.trackIndex++; // Advance track index (0x0ADF)
+ noteProcessed = true; // Exit inner loop, done processing for this tick
+ break; // Exit pattern loop, next tick will get next pattern index from track
+ }
- // Apply Note Data
- applyNote(v, sidOffset, instA0, instA1, voiceIndex);
+ if (cmd >= 0xFD) { // --- Control Commands ---
+ v.patternIndex++; // Consume command byte
+ if (!v.patternDataPtr || v.patternDataPtr[v.patternIndex] == 0xFF) { // Check bounds before reading data
+ debug(DEBUG_LEVEL >= 1, "Driller V%d: Pattern ended unexpectedly after Fx command.", voiceIndex);
+ noteProcessed = true;
+ break;
+ }
+ uint8_t dataByte = v.patternDataPtr[v.patternIndex]; // Read data byte
+
+ // Effect FD/FE: Set Note Duration (0x09E5 + 0x09ED)
+ // Any command >= FD that is not FF (end of pattern) sets the duration.
+ v.noteDuration = dataByte; // Store duration (0x09EF)
+ debug(DEBUG_LEVEL >= 2, "Driller V%d: Cmd $%02X, Set Duration = %d", voiceIndex, cmd, v.noteDuration);
+
+ // Continue reading pattern (next_note_or_ctrl 09F2/0A15)
+ v.patternIndex++;
+
+ } else if (cmd >= 0xFB) { // Effect FB/FC
+ v.patternIndex++; // Consume command byte
+ if (!v.patternDataPtr || v.patternDataPtr[v.patternIndex] == 0xFF) { // Check bounds before reading data
+ debug(DEBUG_LEVEL >= 1, "Driller V%d: Pattern ended unexpectedly after FB/FC command.", voiceIndex);
+ noteProcessed = true;
+ break;
+ }
+ uint8_t portaParam = v.patternDataPtr[v.patternIndex]; // Consume data byte
+
+ if (v.currentNote > 0) {
+ // Set porta type (1=Down(FB), 2=Up(FC)) or (3=DownH, 4=UpH)
+ if (cmd == 0xFB) { // effect_fb_1
+ v.whatever2 = (instA0[7] & 0x02) ? 3 : 1; // (0A01)
+ debug(DEBUG_LEVEL >= 2, "Driller V%d: Cmd FB, Porta Down Param = $%02X (Type %d)", voiceIndex, portaParam, v.whatever2);
+ } else { // FC (effect_fc_2)
+ v.whatever2 = (instA0[7] & 0x02) ? 4 : 2; // (0A17 -> 0A01)
+ debug(DEBUG_LEVEL >= 2, "Driller V%d: Cmd FC, Porta Up Param = $%02X (Type %d)", voiceIndex, portaParam, v.whatever2);
+ }
+
+ v.portaStepRaw = portaParam; // Store raw porta speed (0A0A / 0A19->0A0A)
+ v.whatever0 = 0; // Reset vibrato state (0A0D)
+ v.whatever1 = 0; // Reset arpeggio state (0A0F)
+ v.portaSpeed = 0; // Force recalc
+ } else {
+ debug(DEBUG_LEVEL >= 2, "Driller V%d: Ignoring FB/FC command, no note playing.", voiceIndex);
+ }
+ v.patternIndex++; // Continue reading pattern (0A15)
+
+ } else if (cmd == 0xFA) { // --- Effect FA: Set Instrument --- (0x0A1B)
+ v.patternIndex++;
+ if (!v.patternDataPtr || v.patternDataPtr[v.patternIndex] == 0xFF) { // Check bounds before reading data
+ debug(DEBUG_LEVEL >= 1, "Driller V%d: Pattern ended unexpectedly after FA command.", voiceIndex);
+ noteProcessed = true;
+ break;
+ }
+ uint8_t instNum = v.patternDataPtr[v.patternIndex];
+ if (instNum >= NUM_INSTRUMENTS) {
+ debug(DEBUG_LEVEL >= 0, "Driller V%d: Invalid instrument number %d, using 0.", voiceIndex, instNum);
+ instNum = 0;
+ }
+ v.instrumentIndex = instNum * 8; // Store base offset (0A28)
+ debug(DEBUG_LEVEL >= 2, "Driller V%d: Cmd FA, Set Instrument = %d", voiceIndex, instNum);
+
+ // Update local pointers for instrument data
+ instBase = v.instrumentIndex;
+ if (instBase < 0 || (size_t)instBase >= sizeof(instrumentDataA0))
+ instBase = 0; // Bounds check
+ instA0 = &instrumentDataA0[instBase];
+ instA1 = &instrumentDataA1[instBase];
+
+ // Set ADSR based on instrument (0A2C - 0A3E)
+ uint8_t adsrByte = instA0[0]; // 0A2C
+ v.sustainRelease = adsrByte & 0x0F; // Low nibble to SR (0A32) -> ctrl0
+ v.attackDecay = adsrByte & 0xF0; // High nibble to AD (0A3B/0A3E) -> something_else[0/1]
+ // Store in voice state for SID write later
+ v.ctrl0 = v.sustainRelease;
+ v.something_else[0] = v.attackDecay;
+ v.something_else[1] = v.attackDecay; // Seems duplicated in disassembly?
+ // Also set PW from instA0[0]? Disassembly sets something_else[0] and [1] to AD (hi nibble)
+ // Pulse width seems set later from something_else[0] and [2] ? Let's use [0] for AD.
+ // Let's assume instA0[2] (often xx) and instA0[3] (often 00) are PW lo/hi nibble?
+ // Or maybe something_else[0]/[2] ARE PW and ADSR needs separate vars?
+ // Revisit PW setting in applyNote based on L0AC2. It uses something_else[0] and [2].
+ // Let's store ADSR in dedicated vars, and use something_else for PW based on instrument.
+ // What part of instrument sets PW? L0AC2 uses something_else[0/2]. FA command sets something_else[0/1/2].
+ // FA: pla -> and #F0 -> sta something_else[0] / [1]
+ // FA: pha -> and #0F -> sta something_else[2] / ctrl0
+ // This means: AD Hi Nibble -> PW Lo Byte? AD Hi Nibble -> something_else[1]? SR Lo Nibble -> PW Hi Nibble? SR Lo Nibble -> ctrl0?
+ // Let's follow the variable names:
+ v.attackDecay = instA0[0] & 0xF0; // Stored in something_else[0] & [1]
+ v.sustainRelease = instA0[0] & 0x0F; // Stored in something_else[2] & ctrl0
+ v.something_else[0] = v.attackDecay;
+ v.something_else[1] = v.attackDecay; // ???
+ v.something_else[2] = v.sustainRelease; // PW Hi?
+ v.ctrl0 = v.sustainRelease; // SR?
+
+ debug(DEBUG_LEVEL >= 3, "Driller V%d: Inst %d - ADSR Byte: $%02X -> AD: $%02X, SR: $%02X", voiceIndex, instNum, adsrByte, v.attackDecay, v.sustainRelease);
+
+ // Continue reading pattern (0A41 -> 09F2)
+ v.patternIndex++;
+
+ } else { // --- Plain Note --- (0x0A1D -> 0A44)
+ v.currentNote = cmd; // Store note value (0A44)
+ debug(DEBUG_LEVEL >= 2, "Driller V%d: Note Cmd = $%02X (%d)", voiceIndex, v.currentNote, v.currentNote);
+ // Set delay counter based on previously read duration (FD command)
+ v.delayCounter = v.noteDuration; // (0A47 -> 0A4A)
+
+ // Reset hard restart counters (0A4D)
+ v.whatever3 = 0;
+ v.whatever4 = 0;
+
+ // Reset glide down timer (0A55)
+ v.glideDownTimer = 2; // voice1_two_ctr = 2
+
+ // Handle legato/slide (Instrument A0[7] & 0x02) (0A5D)
+ if (instA0[7] & 0x02) { // Check legato bit
+ debug(DEBUG_LEVEL >= 3, "Driller V%d: Legato instrument flag set.", voiceIndex);
+ }
+
+ // Apply Note Data
+ applyNote(v, sidOffset, instA0, instA1, voiceIndex);
+
+ // Continue reading pattern (but we are done with this note)
+ v.patternIndex++;
+ noteProcessed = true; // Exit the pattern reading loop for this frame
+ }
- // Continue reading pattern (but we are done with this note)
- v.patternIndex++;
- noteProcessed = true; // Exit the pattern reading loop for this frame
+ } // End while(!noteProcessed)
+ // --- End of inlined pattern reading logic ---
}
+ }
- } // End while(!noteProcessed)
+ // ALWAYS apply continuous effects for the current state of the voice, then return.
+ applyContinuousEffects(v, sidOffset, instA0, instA1);
// After processing note or commands for this tick, if a note wasn't fully processed (e.g. pattern end)
// we might need to apply effects. But if noteProcessed = true, applyNote was called which handles final writes.
@@ -987,8 +919,8 @@ void DrillerSIDPlayer::applyNote(VoiceState &v, int sidOffset, const uint8_t *in
// In applyNote, right before writing ADSR to SID:
// Set ADSR (0xAB6)
- writeAD = v.attackDecay;
- writeSR = v.sustainRelease;
+ writeAD = instA0[2];
+ writeSR = instA0[3];
// --- TEMPORARY TEST: Override ADSR for Inst 1 and 4 ---
currentInstNum = v.instrumentIndex / 8;
diff --git a/engines/freescape/games/driller/driller.cpp b/engines/freescape/games/driller/driller.cpp
index 062ee4b7be6..af8acda17be 100644
--- a/engines/freescape/games/driller/driller.cpp
+++ b/engines/freescape/games/driller/driller.cpp
@@ -277,13 +277,13 @@ void DrillerEngine::gotoArea(uint16 areaID, int entranceID) {
_gameStateVars[0x1f] = 0;
if (areaID == _startArea && entranceID == _startEntrance) {
- /*if (isC64())
+ if (isC64())
_playerSid->startMusic();
- else {*/
+ else {
playSound(_soundIndexStart, true);
// Start playing music, if any, in any supported format
playMusic("Matt Gray - The Best Of Reformation - 07 Driller Theme");
- //}
+ }
} else if (areaID == 127) {
assert(entranceID == 0);
More information about the Scummvm-git-logs
mailing list