From 41d7fe69c89befea5ed7cfd0cbeb5ca9da63234a Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Wed, 31 May 2023 01:14:56 -0400 Subject: [PATCH] title: add sound --- games/sb/Makefile | 4 +- games/sb/audio.s | 204 ++++++++++++++++++++++++++++++++++++++ games/sb/lc_detect.s | 40 ++++++++ games/sb/qload.s | 2 +- games/sb/sound/Makefile | 6 ++ games/sb/sound/purple.btc | Bin 0 -> 7102 bytes games/sb/title.s | 52 +++++++++- games/sb/zp.inc | 8 ++ 8 files changed, 313 insertions(+), 3 deletions(-) create mode 100644 games/sb/audio.s create mode 100644 games/sb/lc_detect.s create mode 100644 games/sb/sound/Makefile create mode 100644 games/sb/sound/purple.btc diff --git a/games/sb/Makefile b/games/sb/Makefile index dd70aa6c..65c860c0 100644 --- a/games/sb/Makefile +++ b/games/sb/Makefile @@ -78,7 +78,9 @@ TITLE: title.o title.o: title.s zx02_optim.s \ zp.inc hardware.inc \ - hgr_vscroll.s \ + hgr_vscroll.s audio.s \ + purple.s lc_detect.s \ + sound/purple.btc.zx02 \ graphics/czmg4ap_title.hgr.zx02 \ graphics/videlectrix_top.hgr.zx02 ca65 -o title.o title.s -l title.lst diff --git a/games/sb/audio.s b/games/sb/audio.s new file mode 100644 index 00000000..e6193a09 --- /dev/null +++ b/games/sb/audio.s @@ -0,0 +1,204 @@ +; Based on BTC.SYSTEM by Oliver Schmidt + +; How to generate proper audio for this: + +; -Open MP3 in Audacity +; -Change Project Rate (Hz) to 33,000 (bottom left box) +; -Tracks --> Mix... --> Mix Stereo Down to Mono +; -File --> Export --> Export as WAV +; - Select "WAV (Microsoft) signed 16-bit PCM" +; - Under "Edit Metadata Tags" hit "Clear", then "Okay" +; -Open saved WAV file in BTc Sound Encoder 3.0 +; -Change Algorithm to "1 bit" (leave fineness as BTc16) +; -File --> Export binary file .BTC format + + +spkr = $C030 + +;**************************************************************** +;* Audio playback * +;**************************************************************** +; audio file in BTC_L/BTC_H +; pages to play in X + + +play_audio: + ldy #0 + + ; loop here as long as BITs are [F]alse (aka 0) +F_NX: NOP ; 2 2 + NOP ; 2 2 + NOP ; 2 2 + BIT $00 ; 3 3 +F_RD: LDA (BTC_L),y ; 5 5 5 + ASL ; 2 2 2 + BCS T_1_SW ; 2/3 2 + NOP ; 2 2 + NOP ; 2 2 + NOP ; 2 2 + NOP ; 2 2 +F_1: JSR delay ; 6 (+13) 19 + ASL ; 2 2 = 31 + BCS T_2_SW ; 2/3 + NOP ; 2 + NOP ; 2 + NOP ; 2 + NOP ; 2 +F_2: JSR delay ; 6 (+13) + ASL ; 2 + BCS T_3_SW ; 2/3 + NOP ; 2 + NOP ; 2 + NOP ; 2 + NOP ; 2 +F_3: JSR delay ; 6 (+13) + ASL ; 2 + BCS T_4_SW ; 2/3 + NOP ; 2 + NOP ; 2 + NOP ; 2 + NOP ; 2 +F_4: JSR delay ; 6 (+13) + ASL ; 2 + BCS T_5_SW ; 2/3 + NOP ; 2 + NOP ; 2 + NOP ; 2 + NOP ; 2 +F_5: JSR delay ; 6 (+13) + ASL ; 2 + BCS T_6_SW ; 2/3 + NOP ; 2 + NOP ; 2 + NOP ; 2 + NOP ; 2 +F_6: JSR delay ; 6 (+13) + ASL ; 2 + BCS T_7_SW ; 2/3 + NOP ; 2 + NOP ; 2 + NOP ; 2 + NOP ; 2 +F_7: JSR delay ; 6 (+13) + ASL ; 2 + BCS T_8_SW ; 2/3 2 2 + NOP ; 2 2 2 + NOP ; 2 2 2 + NOP ; 2 2 2 + NOP ; 2 2 2 +F_8: INY ; 2 2 2 + BNE F_NX ; 2/3 3 = 31 2 + INC BTC_H ; 5 5 + DEX ; 2 2 + BNE F_RD ; 2/3 3 = 31 + RTS + ; click speaker on transitions +T_1_SW: STA spkr ; 4 [SW]itch to [T]rue on BIT [1] + BCS T_1 ; 3 (always) +T_2_SW: STA spkr ; 4 [SW]itch to [T]rue on BIT [2] + BCS T_2 ; 3 (always) +T_3_SW: STA spkr ; 4 [SW]itch to [T]rue on BIT [3] + BCS T_3 ; 3 (always) +T_4_SW: STA spkr ; 4 [SW]itch to [T]rue on BIT [4] + BCS T_4 ; 3 (always) +T_5_SW: STA spkr ; 4 [SW]itch to [T]rue on BIT [5] + BCS T_5 ; 3 (always) +T_6_SW: STA spkr ; 4 [SW]itch to [T]rue on BIT [6] + BCS T_6 ; 3 (always) +T_7_SW: STA spkr ; 4 [SW]itch to [T]rue on BIT [7] + BCS T_7 ; 3 (always) +T_8_SW: STA spkr ; 4 [SW]itch to [T]rue on BIT [8] + BCS T_8 ; 3 (always) + +F_1_SW: STA spkr ; 4 [SW]itch to [F]alse on BIT [1] + BCC F_1 ; 3 (always) +F_2_SW: STA spkr ; 4 [SW]itch to [F]alse on BIT [2] + BCC F_2 ; 3 (always) +F_3_SW: STA spkr ; 4 [SW]itch to [F]alse on BIT [3] + BCC F_3 ; 3 (always) +F_4_SW: STA spkr ; 4 [SW]itch to [F]alse on BIT [4] + BCC F_4 ; 3 (always) +F_5_SW: STA spkr ; 4 [SW]itch to [F]alse on BIT [5] + BCC F_5 ; 3 (always) +F_6_SW: STA spkr ; 4 [SW]itch to [F]alse on BIT [6] + BCC F_6 ; 3 (always) +F_7_SW: STA spkr ; 4 [SW]itch to [F]alse on BIT [7] + BCC F_7 ; 3 (always) +F_8_SW: STA spkr ; 4 [SW]itch to [F]alse on BIT [8] + BCC F_8 ; 3 (always) + + ; loop here as long as BITs are [T]rue (aka 1) +T_NX: NOP ; 2 + NOP ; 2 + NOP ; 2 + BIT $00 ; 3 +T_RD: LDA (BTC_L),y ; 5 + ASL ; 2 + BCC F_1_SW ; 2/3 + NOP ; 2 + NOP ; 2 + NOP ; 2 + NOP ; 2 +T_1: JSR delay ; 6 (+13) + ASL ; 2 + BCC F_2_SW ; 2/3 + NOP ; 2 + NOP ; 2 + NOP ; 2 + NOP ; 2 +T_2: JSR delay ; 6 (+13) + ASL ; 2 + BCC F_3_SW ; 2/3 + NOP ; 2 + NOP ; 2 + NOP ; 2 + NOP ; 2 +T_3: JSR delay ; 6 (+13) + ASL ; 2 + BCC F_4_SW ; 2/3 + NOP ; 2 + NOP ; 2 + NOP ; 2 + NOP ; 2 +T_4: JSR delay ; 6 (+13) + ASL ; 2 + BCC F_5_SW ; 2/3 + NOP ; 2 + NOP ; 2 + NOP ; 2 + NOP ; 2 +T_5: JSR delay ; 6 (+13) + ASL ; 2 + BCC F_6_SW ; 2/3 + NOP ; 2 + NOP ; 2 + NOP ; 2 + NOP ; 2 +T_6: JSR delay ; 6 (+13) + ASL ; 2 + BCC F_7_SW ; 2/3 + NOP ; 2 + NOP ; 2 + NOP ; 2 + NOP ; 2 +T_7: JSR delay ; 6 (+13) + ASL ; 2 + BCC F_8_SW ; 2/3 + NOP ; 2 + NOP ; 2 + NOP ; 2 + NOP ; 2 +T_8: INY ; 2 + BNE T_NX ; 2/3 + INC BTC_H ; 5 + DEX ; 2 + BNE T_RD ; 2/3 + RTS + +delay: + nop ; 2 + nop ; 2 + BIT $00 ; 3 + RTS ; 6 = 13 + + diff --git a/games/sb/lc_detect.s b/games/sb/lc_detect.s new file mode 100644 index 00000000..3123a6ae --- /dev/null +++ b/games/sb/lc_detect.s @@ -0,0 +1,40 @@ +; Code from TotalReplay by 4am and qkumba + +;------------------------------------------------------------------------------ +; Has64K +; Checks whether computer has functioning language card (64K) +; +; in: none +; out: C clear if 64K detected +; C set if 64K not detected +; all other flags and registers clobbered +; ROM in memory (not LC RAM bank) +;------------------------------------------------------------------------------ + +detect_language_card: + + ; enable language card + ; READ_RAM1_WRITE_RAM1 + + bit $C08B + bit $C08B + + lda #$AA ; test #1 for $D0 page + sta $D000 + eor $D000 + bne no_lc + lsr $D000 ; test #2 for $D0 page + lda #$55 + eor $D000 + bne no_lc + clc + bcc done_detect + +no_lc: + sec + +done_detect: + ; READ_ROM_NO_WRITE + bit $C08A + + rts diff --git a/games/sb/qload.s b/games/sb/qload.s index 29ee7daa..5587fb00 100644 --- a/games/sb/qload.s +++ b/games/sb/qload.s @@ -183,7 +183,7 @@ sector_array: .byte 0, 0, 0, 0 ; LEVEL8, LEVEL9, LEVEL10 length_array: - .byte 16, 16, 16, 32 ; TITLE, DUCK, SB, FN + .byte 32, 16, 16, 32 ; TITLE, DUCK, SB, FN .byte 46, 46, 46, 46 ; LEVEL4, LEVEL5, LEVEL6, LEVEL7 .byte 46, 46, 32, 32 ; LEVEL8, LEVEL9, LEVEL10 diff --git a/games/sb/sound/Makefile b/games/sb/sound/Makefile new file mode 100644 index 00000000..236264ca --- /dev/null +++ b/games/sb/sound/Makefile @@ -0,0 +1,6 @@ +ZX02 = ~/research/6502_compression/zx02.git/build/zx02 -f + +all: purple.btc.zx02 + +purple.btc.zx02: purple.btc + $(ZX02) purple.btc purple.btc.zx02 diff --git a/games/sb/sound/purple.btc b/games/sb/sound/purple.btc new file mode 100644 index 0000000000000000000000000000000000000000..512271a4bed44f4ce43386f00a74ffc5145bb95f GIT binary patch literal 7102 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 YeIPr4gC0E#YJLqoXY#&x%m4rY literal 0 HcmV?d00001 diff --git a/games/sb/title.s b/games/sb/title.s index 477f76c1..7ed4b06d 100644 --- a/games/sb/title.s +++ b/games/sb/title.s @@ -27,6 +27,47 @@ hires_start: sta HGR_PAGE jsr hgr_make_tables + + ;========================================= + ; detect if we have a language card (64k) + ; and load sound into it if possible + ;=================================== + + lda #0 + sta SOUND_STATUS ; clear out, sound enabled + + jsr detect_language_card + bcs no_language_card + +yes_language_card: + + ; update sound status + lda SOUND_STATUS + ora #SOUND_IN_LC + sta SOUND_STATUS + + ;================================== + ; load sound into the language card + ; into $D000 set 1 + ;================================== + + ; read/write RAM, use $d000 bank1 + bit $C083 + bit $C083 + + lda #purple_data + sta ZX0_src+1 + + lda #$D0 ; decompress to $D000 + + jsr full_decomp + + +no_language_card: + + ;=================== ;=================== ; scroll the logo @@ -80,8 +121,11 @@ load_title_image: jsr full_decomp -; rts + ;========================== + ; Play sound + ;=========================== + jsr play_purple wait_until_keypress: @@ -109,8 +153,14 @@ done: .include "zx02_optim.s" .include "hgr_tables.s" .include "hgr_vscroll.s" + .include "audio.s" + .include "purple.s" + .include "lc_detect.s" title_data: .incbin "graphics/czmg4ap_title.hgr.zx02" vid_top: .incbin "graphics/videlectrix_top.hgr.zx02" + +purple_data: + .incbin "sound/purple.btc.zx02" diff --git a/games/sb/zp.inc b/games/sb/zp.inc index 6565f3a1..387dcddb 100644 --- a/games/sb/zp.inc +++ b/games/sb/zp.inc @@ -39,6 +39,14 @@ FRAMEH = $61 SCROLL = $62 XSAVE = $63 SCROLL_OFFSET = $64 +BTC_L = $65 +BTC_H = $66 +SOUND_STATUS = $67 + SOUND_DISABLED = $80 + SOUND_IN_LC = $01 ; $01 sound effects in language card + SOUND_MOCKINGBOARD = $02 ; mockingboard detected + + ;WAITING = $62 ;LETTERL = $63