| Chase H.Q. | Routines |
| Prev: F7D6 | Up: Map | Next: F8EB |
|
Runs the AY music driver (ts_music_service), then dispatches the current sound effect's parameter byte (set up by load_drum_script/load_drum_op) to one of three 1-bit "digitised sample" bit-bang players: two fixed 8-row sample tables (F8F2, F95A, played via the shared loop at $F8CD which pulses port $FE from bitmap data clocked out with RLC (HL)/DJNZ) or the procedural routine at play_drum_noise_burst. $F8AD (installed as the IM2 handler by setup_im2_interrupt_table) just sets a "frame occurred" flag ($F8A8) consumed here and re-enables interrupts.
All the "LD A,$00" / "LD HL,$0000" instructions below are self-modified: the operand byte(s) immediately following each opcode double as a persistent state variable, written directly (not via the instruction) by this routine and by titlescr_start_tune/$F7DB/$F7FE. Three such state bytes are the SFX "busy" flags named at titlescr_start_tune: $F837 (SFX slot 1), $F895 (SFX slot 2), $F8A2 (1-bit sample playback active).
Slot 1 ($F836-$F894): if $F837 = 0 (idle), arms it (=1) and reloads the sample-selector-stream read pointer ($F853) from the reload source at $F85E (set by load_drum_script/$F7FE) before falling into the stream-reading loop at sfx_read_stream_byte. If already armed, $F842 (a countdown, also the selector byte copied by load_drum_op) is decremented; only when it reaches 1 does sfx1_reenter_stream re-enter the stream-reading loop -- otherwise slot 1 is skipped this frame and control falls to slot 2.
Stream-reading loop (sfx_read_stream_byte): reads a byte from the selector stream; a byte of exactly 1 calls titlescr_drum_advance (titlescr_drum_advance's own re-entry, throttled by its own $F7F5 countdown) to pull in a fresh selector byte and restarts the loop with the reload pointer. Any other byte is the entry to act on this frame: bit 7 marks it as also arming slot 2 ($F842 and $895 both set to 1, banked via AF' so it doesn't disturb the byte being decoded); the low 3 bits (1/2/3) select which of the three 1-bit-sample engines to trigger this frame (play_fixed_sample_1 = sample table F8F2, play_fixed_sample_2 = sample table F95A, or play_drum_noise_burst the procedural generator), with the byte's upper 5 bits stashed via $F8CE as a playback-rate/pitch parameter for the two fixed samples. A low-3-bits value of 0 triggers nothing and falls through to slot 2. Slot 2 ($F894-$F8A1): if $F895 is set, decrements both $F842 and $F895 (companion countdowns for whatever slot 1 armed via the bit-7 path above); purpose of the parallel countdown not established further. Tail ($F8A1-$F8A6): if $F8A2 (sample-playback-active) is exactly 1, falls into titlescr_music_1/play_sample_row to pulse out the next row of whichever fixed sample was armed above; otherwise returns without playing anything this frame. Used by the routines at insert_high_score_entry, name_entry_input, run_title_screen, play_success_music and run_title_tune.
|
||||
| titlescr_music | F82F | CALL ts_music_service | Run the AY music driver for this frame | |
| F832 | XOR A | Clear the "frame occurred" flag consumed by | ||
| F833 | LD ($F8A8),A | wait_for_frame_flag | ||
| sfx1_check_busy | F836 | LD A,$00 | A = SFX slot 1 busy flag ($F837) | |
| F838 | AND A | |||
| F839 | JR NZ,sfx1_tick_countdown | Busy -> $F841 to tick the countdown | ||
| F83B | INC A | Idle -> arm slot 1 (busy = 1) | ||
| F83C | LD ($F837),A | |||
| F83F | JR sfx1_reload_pointer | Reload the read pointer and enter the loop | ||
| sfx1_tick_countdown | F841 | LD A,$00 | A = slot 1 countdown/selector byte ($F842) | |
| F843 | DEC A | |||
| F844 | JP Z,sfx1_reenter_stream | Reached 1 -> re-enter the stream-reading loop | ||
| F847 | LD ($F842),A | Else store the decremented countdown and skip | ||
| F84A | JP sfx2_tick_countdown | slot 1 entirely this frame | ||
| sfx1_reenter_stream | F84D | LD A,$00 | Reset the countdown to 0 (about to be replaced by | |
| F84F | LD ($F842),A | the next entry read from the stream) | ||
| F852 | LD HL,$0000 | HL = current stream read pointer ($F853) | ||
| sfx_read_stream_byte | F855 | LD A,(HL) | A = next byte from the selector stream | |
| F856 | DEC A | |||
| F857 | JP NZ,sfx_dispatch_entry | Not "1" -> $F866, this is an entry to act on | ||
| F85A | CALL titlescr_drum_advance | "1" -> pull in a fresh selector byte | ||
| sfx1_reload_pointer | F85D | LD HL,$0000 | Reload the stream pointer from the source set by | |
| F860 | LD ($F853),HL | load_drum_script/$F7FE ($F85E) and retry | ||
| F863 | JP sfx_read_stream_byte | |||
| sfx_dispatch_entry | F866 | INC HL | Advance and persist the stream pointer | |
| F867 | LD ($F853),HL | |||
| F86A | INC A | Restore the original entry byte (undo the DEC) | ||
| F86B | BIT 7,A | Bit 7 set -> also arm slot 2 | ||
| F86D | JR Z,titlescr_music_0 | |||
| F86F | AND $7F | Mask off bit 7 (banked via AF' so the low bits | ||
| F871 | EX AF,AF' | used for dispatch below are undisturbed) | ||
| F872 | LD A,$01 | |||
| F874 | LD ($F842),A | Arm slot 1's countdown/selector and slot 2's busy | ||
| F877 | LD ($F895),A | flag together | ||
| F87A | EX AF,AF' | |||
| titlescr_music_0 | F87B | LD D,A | D = entry byte (masked if bit 7 was set) | |
| F87C | AND $07 | Low 3 bits select which 1-bit-sample engine | ||
| F87E | JR Z,sfx2_tick_countdown | 0 -> nothing to trigger this frame | ||
| F880 | LD B,A | |||
| F881 | LD A,D | A = upper 5 bits: playback-rate/pitch parameter | ||
| F882 | SRL A | for the two fixed samples (stashed via $F8CE at | ||
| F884 | SRL A | play_fixed_sample_start) | ||
| F886 | SRL A | |||
| F888 | DEC B | |||
| F889 | JP Z,play_fixed_sample_1 | Selector 1 -> fixed sample table F8F2 | ||
| F88C | DEC B | |||
| F88D | JP Z,play_fixed_sample_2 | Selector 2 -> fixed sample table F95A | ||
| F890 | DEC B | |||
| F891 | JP Z,play_drum_noise_burst | Selector 3 -> procedural drum noise | ||
| sfx2_tick_countdown | F894 | LD A,$00 | A = SFX slot 2 busy flag ($F895) | |
| F896 | AND A | |||
| F897 | JR Z,sfx_tail_check_active | Idle -> nothing to tick | ||
| F899 | LD HL,$F842 | Busy -> decrement both companion countdowns | ||
| F89C | DEC (HL) | |||
| F89D | LD HL,$F895 | |||
| F8A0 | DEC (HL) | |||
| sfx_tail_check_active | F8A1 | LD A,$00 | A = 1-bit sample playback active flag ($F8A2) | |
| F8A3 | DEC A | |||
| F8A4 | JP Z,titlescr_music_1 | Active -> play the next row of the armed sample | ||
|
This entry point is used by the routines at finish_sample_playback and play_drum_noise_burst.
|
||||
| wait_for_frame_flag | F8A7 | LD A,$00 | ||
| F8A9 | AND A | |||
| F8AA | JR Z,wait_for_frame_flag | |||
| F8AC | RET | |||
|
IM2 interrupt handler (installed by setup_im2_interrupt_table): just sets the "frame occurred" flag ($F8A8) polled by wait_for_frame_flag and re-enables interrupts. The actual per-frame work happens synchronously from the main loop at psm_loop, not here.
|
||||
| frame_interrupt_handler | F8AD | PUSH AF | ||
| F8AE | LD A,$FF | |||
| F8B0 | LD ($F8A8),A | |||
| F8B3 | POP AF | |||
| F8B4 | EI | |||
| F8B5 | RET | |||
| play_fixed_sample_1 | F8B6 | LD HL,$F8F2 | ||
| F8B9 | LD D,$68 | |||
| F8BB | JR play_fixed_sample_start | |||
| play_fixed_sample_2 | F8BD | LD HL,$F95A | ||
| F8C0 | LD D,$E0 | |||
| play_fixed_sample_start | F8C2 | LD ($F8CE),A | ||
| F8C5 | LD A,$01 | |||
| F8C7 | LD ($F8A2),A | |||
| F8CA | JR play_sample_row | |||
| titlescr_music_1 | F8CC | EXX | ||
|
1-bit sample bit-bang loop: pulses port $FE (border/speaker) from bitmap data at HL, one row of 8 bits per iteration, RLC (HL) rotating the next bit into carry-adjacent position; D counts rows remaining.
|
||||
| play_sample_row | F8CD | LD B,$08 | ||
| titlescr_music_2 | F8CF | LD A,$10 | ||
| F8D1 | NOP | |||
| F8D2 | BIT 7,(HL) | |||
| F8D4 | JR NZ,titlescr_music_3 | |||
| F8D6 | RES 4,A | |||
| titlescr_music_3 | F8D8 | OUT ($FE),A | ||
| F8DA | RLC (HL) | |||
| F8DC | DJNZ titlescr_music_2 | |||
| F8DE | INC HL | |||
| F8DF | DEC D | |||
| F8E0 | JR Z,finish_sample_playback | |||
| F8E2 | LD A,($F8A8) | |||
| F8E5 | AND A | |||
| F8E6 | JP Z,play_sample_row | |||
| F8E9 | EXX | |||
| F8EA | RET | |||
| Prev: F7D6 | Up: Map | Next: F8EB |