diff --git a/compiler/test/TestCompilerOnExamples.kt b/compiler/test/TestCompilerOnExamples.kt index 530329da2..9a6c6a482 100644 --- a/compiler/test/TestCompilerOnExamples.kt +++ b/compiler/test/TestCompilerOnExamples.kt @@ -114,6 +114,8 @@ class TestCompilerOnExamplesCx16: FunSpec({ "pcmaudio/vumeter", "sprites/dragon", "sprites/dragons", + "zsmkit/demo1", + "zsmkit/demo2", "amiga", "audioroutines", "automatons", diff --git a/docs/source/todo.rst b/docs/source/todo.rst index c2cb468d9..b5ca7ebc5 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -5,11 +5,6 @@ merge problem: if 2 library modules both have merge, stuff breaks (math & prog8_ for releasenotes: gfx2.width and gfx2.height got renamed as gfx_lores.WIDTH/HEIGHT or gfx_hires4.WIDTH/HEIGTH constants. Screen mode routines also renamed. -replace zsound example by a zsmkit example -contribute a short how-to to the zsmkit repo for building a suitable blob -write a howto for integrating third party library code like zsmkit and vtui - - regenerate symbol dump files diff --git a/examples/cx16/zsmkit/README.txt b/examples/cx16/zsmkit/README.txt new file mode 100644 index 000000000..36d117ef2 --- /dev/null +++ b/examples/cx16/zsmkit/README.txt @@ -0,0 +1,44 @@ +Prog8 ZSMKIT music player library integration +--------------------------------------------- + +ZSMKIT: https://github.com/mooinglemur/zsmkit +(evolution of Zerobyte's ZSOUND, by MooingLemur). Read the README there! + + +DEMO1: LOW-RAM ZSMKIT + STREAMING +---------------------------------- +demo1.p8 shows a way to embed the zsmkit blob into the program itself (at $0830). +It then uses the streaming support in zsmkit to load the song from disk as it is played. +It shows some other features such as callbacks and pausing as well. +The way the zsmkit blob is embedded into the program is done by telling prog8 that +the 'main' block of the program has to start at $0830, and the very first command +in that block is not the usual 'start' subroutine but a %asmbinary command to load +and embed the zsmkit blob right there and then. + + + +DEMO2: HI-RAM ZSMKIT + PRELOADING +---------------------------------- +demo2.p8 shows a simpler program that loads a zsmkit blob into upper memory at $8c00 +and then also preloads the whole music file into hi-ram. No streaming is used to +play it, it plays everything from ram. +Note that the zsmkit blob used for this is a smaller build as the $0830 one because +this one was configured without streaming support enabled. + + +CUSTOMIZING ZSMKIT +------------------ + +Read the README on the zsmkit github repo. It contains a lot of important information, +about how zsmkit works, but also about the various things you have to configure to build a +new library blob to your liking. The example here includes two recently built variants of the blob, +so you don't immediately have to build something yourself, but if you want to enable or disable +streaming support or change the load address you'll have to build one yourself. +See the "alternative builds" chapter. + + +FUTURE: ZSMKIT V2 +----------------- +If all goes well, there will be a zsmkit v2 in the future that has some important changes +that will make it much easier to integrate it into prog8 programs. Less RAM usage and +a fixed jump table location, among other changes. diff --git a/examples/cx16/zsmkit/demo1.p8 b/examples/cx16/zsmkit/demo1.p8 new file mode 100644 index 000000000..268928af1 --- /dev/null +++ b/examples/cx16/zsmkit/demo1.p8 @@ -0,0 +1,112 @@ +%import textio +%import palette +%import zsmkit_low + +;; Proof Of Concept ZSM player using a binary blob version of zsmkit by MooingLemur +;; This version shows how you could integrate the zsmkit blob located in lower memory at $0830. +;; It embeds the blob into the prg itself, no separate loading is necessary. +;; It uses zsmkit's streaming ability to load the song data from disk on the fly. + + +main $0830 { + ; this has to be the first statement to make sure it loads at the specified module address $0830 + %asmbinary "lib/zsmkit-0830.bin" + + const ubyte zsmkit_bank = 1 + bool loopchanged = false + bool beat = false + uword loop_number = 0 + + sub start() { + txt.print("zsmkit demo program (drive 8)!\n") + txt.print("during playback, press return to pause/unpause\n") + + zsmkit.zsm_init_engine(zsmkit_bank) + play_music() + } + + asmsub callback_handler(ubyte prio @X, ubyte type @Y, ubyte arg @A) { + %asm {{ + brk + cpy #1 + beq _loop + cpy #2 + beq _sync + rts +_loop: + inc p8v_loopchanged + rts +_sync: + inc p8v_beat + rts + }} + } + + sub play_music() { + uword next_free + zsmkit.zsm_setfile(0, iso:"music/MUSIC.ZSM") + cx16.rambank(2) + + txt.print(iso:"STARTING IN BANK 2, ADDRESS $A000") + txt.nl() + txt.print(iso:"NOW LOADING PCM FROM MUSIC.ZSM") + txt.nl() + + next_free = zsmkit.zsm_loadpcm(0, $a000) + + txt.print(iso:"NOW AT BANK ") + txt.print_ub(cx16.getrambank()) + txt.print(iso:", ADDRESS ") + txt.print_uwhex(next_free, true) + txt.nl() + + zsmkit.zsm_play(0) + zsmkit.zsm_setcb(0, &callback_handler) + + bool paused = false + uword oldjoy = $ffff + ubyte intensity = 0 + + repeat { + uword newjoy + newjoy, void = cx16.joystick_get(0) + if (newjoy != oldjoy and (newjoy & $10) == 0) { + if (paused) { + zsmkit.zsm_play(0) + paused = false + } else { + zsmkit.zsm_stop(0) + paused = true + } + zsmkit.zsm_close(1) + zsmkit.zsm_setfile(1, iso:"PAUSE.ZSM") + zsmkit.zsm_play(1) + } + oldjoy = newjoy + + sys.waitvsync() + zsmkit.zsm_tick(0) + if (loopchanged) { + txt.nl() + loop_number += 1 + loopchanged = false + txt.print(iso:"LOOP NUMBER: ") + txt.print_uw(loop_number) + txt.nl() + zsmkit.zsm_setrate(0, 60+(loop_number << 2)) + } + if (beat) { + intensity = 16 + beat = false + } else if (not paused) { + txt.print(".") + } + if (intensity > 0) { + intensity -= 1 + palette.set_color(0, (intensity >> 1) * $111) + } + zsmkit.zsm_fill_buffers() + + } + } +} diff --git a/examples/cx16/zsmkit/demo2.p8 b/examples/cx16/zsmkit/demo2.p8 new file mode 100644 index 000000000..d85dd3bad --- /dev/null +++ b/examples/cx16/zsmkit/demo2.p8 @@ -0,0 +1,51 @@ +%import diskio +%import textio +%import zsmkit_high + +;; Proof Of Concept ZSM player using a binary blob version of zsmkit by MooingLemur +;; This version is a bit simpler as "demo1". +;; This one shows how you could integrate the zsmkit blob located in higher memory at $8c30. +;; It loads the blob separately. It also doesn't use streaming, +;; it simply loads the whole ZSM file into high memory (bank 2 onwards) at the start too. + +main { + const ubyte zsmkit_bank = 1 + + sub start() { + txt.print("zsmkit demo program (dynamic loading)\n") + + load_and_init_zsmkit(iso:"lib/zsmkit-8c00.bin") + load_music_file(iso:"music/MUSIC.ZSM") + + play_music() + } + + sub load_and_init_zsmkit(str blobname) { + if diskio.load_raw(blobname, $8c00)>0 + zsmkit.zsm_init_engine(zsmkit_bank) + else { + txt.print("error loading zsmkit blob\n") + sys.exit(1) + } + } + + sub load_music_file(str filename) { + cx16.rambank(zsmkit_bank+1) + if diskio.load_raw(filename, $a000)==0 { + txt.print("error loading music file\n") + sys.exit(1) + } + } + + sub play_music() { + cx16.rambank(zsmkit_bank+1) + zsmkit.zsm_setmem(0, $a000) + zsmkit.zsm_play(0) + + repeat { + sys.waitvsync() + zsmkit.zsm_tick(0) + txt.chrout('.') + } + } +} diff --git a/examples/cx16/zsmkit/lib/zsmkit-0830.bin b/examples/cx16/zsmkit/lib/zsmkit-0830.bin new file mode 100644 index 000000000..7a4a97221 Binary files /dev/null and b/examples/cx16/zsmkit/lib/zsmkit-0830.bin differ diff --git a/examples/cx16/zsmkit/lib/zsmkit-8c00.bin b/examples/cx16/zsmkit/lib/zsmkit-8c00.bin new file mode 100644 index 000000000..a272612cf Binary files /dev/null and b/examples/cx16/zsmkit/lib/zsmkit-8c00.bin differ diff --git a/examples/cx16/zsmkit/music/MUSIC.ZSM b/examples/cx16/zsmkit/music/MUSIC.ZSM new file mode 100644 index 000000000..8f5eb4272 Binary files /dev/null and b/examples/cx16/zsmkit/music/MUSIC.ZSM differ diff --git a/examples/cx16/zsmkit/music/PAUSE.ZSM b/examples/cx16/zsmkit/music/PAUSE.ZSM new file mode 100644 index 000000000..a98d6d1d5 Binary files /dev/null and b/examples/cx16/zsmkit/music/PAUSE.ZSM differ diff --git a/examples/cx16/zsmkit/zsmkit_high.p8 b/examples/cx16/zsmkit/zsmkit_high.p8 new file mode 100644 index 000000000..7140b1b36 --- /dev/null +++ b/examples/cx16/zsmkit/zsmkit_high.p8 @@ -0,0 +1,35 @@ + +; romsubs for zsmkit loaded at $8c00 + +zsmkit { + romsub $8C00 = zsm_init_engine(ubyte bank @A) clobbers(A, X, Y) + romsub $8C03 = zsm_tick(ubyte type @A) clobbers(A, X, Y) + + romsub $8C06 = zsm_play(ubyte prio @X) clobbers(A, X, Y) + romsub $8C09 = zsm_stop(ubyte prio @X) clobbers(A, X, Y) + romsub $8C0C = zsm_rewind(ubyte prio @X) clobbers(A, X, Y) + romsub $8C0F = zsm_close(ubyte prio @X) clobbers(A, X, Y) + romsub $8C12 = zsm_fill_buffers() clobbers(A, X, Y) + romsub $8C15 = zsm_setlfs(ubyte prio @X, ubyte lfn_sa @A, ubyte device @Y) clobbers(A, X, Y) + romsub $8C18 = zsm_setfile(ubyte prio @X, str filename @AY) clobbers(A, X, Y) + romsub $8C1B = zsm_loadpcm(ubyte prio @X, uword data_ptr @AY) clobbers(X) -> uword @AY + romsub $8C1E = zsm_setmem(ubyte prio @X, uword data_ptr @AY) clobbers(A, X, Y) + romsub $8C21 = zsm_setatten(ubyte prio @X, ubyte value @A) clobbers(A, X, Y) + romsub $8C24 = zsm_setcb(ubyte prio @X, uword func_ptr @AY) clobbers(A, X, Y) + romsub $8C27 = zsm_clearcb(ubyte prio @X) clobbers(A, X, Y) + romsub $8C2A = zsm_getstate(ubyte prio @X) clobbers(X) -> bool @Pc, bool @Pz, uword @AY + romsub $8C2D = zsm_setrate(ubyte prio @X, uword rate @AY) clobbers(A, X, Y) + romsub $8C30 = zsm_getrate(ubyte prio @X) clobbers() -> uword @AY + romsub $8C33 = zsm_setloop(ubyte prio @X, bool loop @Pc) clobbers(A, X, Y) + romsub $8C36 = zsm_opmatten(ubyte prio @X, ubyte channel @Y, ubyte value @A) clobbers(A, X, Y) + romsub $8C39 = zsm_psgatten(ubyte prio @X, ubyte channel @Y, ubyte value @A) clobbers(A, X, Y) + romsub $8C3C = zsm_pcmatten(ubyte prio @X, ubyte value @A) clobbers(A, X, Y) + romsub $8C3F = zsm_set_int_rate(ubyte value @A, ubyte frac @Y) clobbers(A, X, Y) + + romsub $8C4B = zcm_setmem(ubyte slot @X, uword data_ptr @AY) clobbers(A) + romsub $8C4E = zcm_play(ubyte slot @X, ubyte volume @A) clobbers(A, X) + romsub $8C51 = zcm_stop() clobbers(A) + + romsub $8C54 = zsmkit_setisr() clobbers(A) + romsub $8C57 = zsmkit_clearisr() clobbers(A) +} diff --git a/examples/cx16/zsmkit/zsmkit_low.p8 b/examples/cx16/zsmkit/zsmkit_low.p8 new file mode 100644 index 000000000..34e5df1ce --- /dev/null +++ b/examples/cx16/zsmkit/zsmkit_low.p8 @@ -0,0 +1,35 @@ + +; romsubs for zsmkit loaded at $0830 + +zsmkit { + romsub $0830 = zsm_init_engine(ubyte bank @A) clobbers(A, X, Y) + romsub $0833 = zsm_tick(ubyte type @A) clobbers(A, X, Y) + + romsub $0836 = zsm_play(ubyte prio @X) clobbers(A, X, Y) + romsub $0839 = zsm_stop(ubyte prio @X) clobbers(A, X, Y) + romsub $083c = zsm_rewind(ubyte prio @X) clobbers(A, X, Y) + romsub $083f = zsm_close(ubyte prio @X) clobbers(A, X, Y) + romsub $0842 = zsm_fill_buffers() clobbers(A, X, Y) + romsub $0845 = zsm_setlfs(ubyte prio @X, ubyte lfn_sa @A, ubyte device @Y) clobbers(A, X, Y) + romsub $0848 = zsm_setfile(ubyte prio @X, str filename @AY) clobbers(A, X, Y) + romsub $084b = zsm_loadpcm(ubyte prio @X, uword data_ptr @AY) clobbers(X) -> uword @AY + romsub $084e = zsm_setmem(ubyte prio @X, uword data_ptr @AY) clobbers(A, X, Y) + romsub $0851 = zsm_setatten(ubyte prio @X, ubyte value @A) clobbers(A, X, Y) + romsub $0854 = zsm_setcb(ubyte prio @X, uword func_ptr @AY) clobbers(A, X, Y) + romsub $0857 = zsm_clearcb(ubyte prio @X) clobbers(A, X, Y) + romsub $085A = zsm_getstate(ubyte prio @X) clobbers(X) -> bool @Pc, bool @Pz, uword @AY + romsub $085D = zsm_setrate(ubyte prio @X, uword rate @AY) clobbers(A, X, Y) + romsub $0860 = zsm_getrate(ubyte prio @X) clobbers() -> uword @AY + romsub $0863 = zsm_setloop(ubyte prio @X, bool loop @Pc) clobbers(A, X, Y) + romsub $0866 = zsm_opmatten(ubyte prio @X, ubyte channel @Y, ubyte value @A) clobbers(A, X, Y) + romsub $0869 = zsm_psgatten(ubyte prio @X, ubyte channel @Y, ubyte value @A) clobbers(A, X, Y) + romsub $086C = zsm_pcmatten(ubyte prio @X, ubyte value @A) clobbers(A, X, Y) + romsub $086F = zsm_set_int_rate(ubyte value @A, ubyte frac @Y) clobbers(A, X, Y) + + romsub $087B = zcm_setmem(ubyte slot @X, uword data_ptr @AY) clobbers(A) + romsub $087E = zcm_play(ubyte slot @X, ubyte volume @A) clobbers(A, X) + romsub $0881 = zcm_stop() clobbers(A) + + romsub $0884 = zsmkit_setisr() clobbers(A) + romsub $0887 = zsmkit_clearisr() clobbers(A) +} diff --git a/examples/cx16/zsound/COLONY.ZSM b/examples/cx16/zsound/COLONY.ZSM deleted file mode 100644 index bdf618d33..000000000 Binary files a/examples/cx16/zsound/COLONY.ZSM and /dev/null differ diff --git a/examples/cx16/zsound/TERMINATOR2.ZCM b/examples/cx16/zsound/TERMINATOR2.ZCM deleted file mode 100644 index 9a2f6a1e1..000000000 Binary files a/examples/cx16/zsound/TERMINATOR2.ZCM and /dev/null differ diff --git a/examples/cx16/zsound/THRILLER.ZCM b/examples/cx16/zsound/THRILLER.ZCM deleted file mode 100644 index 554c8102a..000000000 Binary files a/examples/cx16/zsound/THRILLER.ZCM and /dev/null differ diff --git a/examples/cx16/zsound/pcmplayer.txt b/examples/cx16/zsound/pcmplayer.txt deleted file mode 100644 index 440635265..000000000 --- a/examples/cx16/zsound/pcmplayer.txt +++ /dev/null @@ -1,80 +0,0 @@ -;........... -; init_pcm : -; =========================================================================== -; Arguments: (none) -; Returns: (none) -; Affects: A -; --------------------------------------------------------------------------- -; Call this before using any of the other routines. -; -; Initializes the memory locations used by PCMM player to a stopped playback -; state, sets VERA playback rate to 0 (disabled) and clears the PCM FIFO -; also sets the volume to 15 (F). - - -;........... -; play_pcm : -; =========================================================================== -; Arguments: (none) -; Returns: (none) -; Affects: A,X,Y -; --------------------------------------------------------------------------- -; Call this once per frame to ensure that the PCM samples are being fed -; into VERA's PCM FIFO. While this routine is technically IRQ-safe, it is -; recommended that it not be executed during the VSYNC IRQ, as higher -; quality sample streams can consume up to ~30k CPU cycles to process. -; -; Consistent, jitter-free low-latency playback can be assured using a line IRQ -; -; If using ZSM player module, it is recommended that this call happen after -; the ZSM player's update function (playmusic) so that any PCM events will -; be processed on the same frame. - -;........... -; stop_pcm : -; =========================================================================== -; Arguments: (none) -; Returns: (none) -; Affects: A -; --------------------------------------------------------------------------- -; Disables PCM playback in VERA_audio_rate register, clears the FIFO, and -; sets the PCM player module's status to clear. - -;............. -; start_digi : -; =========================================================================== -; Arguments: Pointer to digi parameter table in memory. -; .A = RAM bank -; .XY = Memory address -; Returns: none -; Affects: none -; --------------------------------------------------------------------------- -; Documentation and terminology in Zsound uses the term "digi" to refer to -; a digital audio clip, as the term "sample" also refers to an individual -; PCM sample. Thus "digi" disambiguates between the two. -; -; start_digi expects a pointer to a digi parameter table in memory (low or -; high memory are both acceptable locations. If in Hi memory, the table -; must exist entirely within the same bank. -; -; The table's contents are the same as the DIGITAB struct at the -; beginning of this inc file. -; -; note that start_digi is a one-shot call to trigger a digi. There is -; currently no infrastructure to make callbacks at the end of a digi's -; playback, or any granular controls to modify a playback in progress -; such as volume changes, etc. -; -; In the future, more granular controls are planned, but the exact -; nature and functionality are as yet to be determined. - -;................. -; set_pcm_volume : -; =========================================================================== -; Arguments: Pointer to digi parameter table in memory. -; .A = new volume level (only the 4 LSB are used) -; -; Returns: none -; Affects: none -; --------------------------------------------------------------------------- -; Sets the PCM volume level 0..F diff --git a/examples/cx16/zsound/play-zsound.p8 b/examples/cx16/zsound/play-zsound.p8 deleted file mode 100644 index ea36b5398..000000000 --- a/examples/cx16/zsound/play-zsound.p8 +++ /dev/null @@ -1,118 +0,0 @@ -%import textio -%import diskio -%import palette -%zeropage basicsafe -%zpreserved $22,$2d ; zsound lib uses this region - - -;; Proof Of Concept Zsound player using a binary blob version of zsound library by ZeroByte relocated to something usable here. -;; Can play ZSM (music) and ZCM (pcm samples). - -; NOTE: the ZSound library is DEPRECATED and ZSMKIT is its successor. -; find prog8 examples with ZSMKIT here: https://github.com/mooinglemur/zsmkit/tree/main/p8demo - -; "issues": -; - prog8 (or rather, 64tass) cannot "link" other assembly object files so we have to incbin a binary blob. -; - zsound player ZP usage is only known after compilation of zsound lib. And then this has to be blocked off in the prog8 program. -; - zsound lib BSS section has to be expanded into real zeros as part of the included binary. -; - zsound binary starts with 2 byte prg header that shifts the jump table 2 bytes (not a big issue but a bit untidy) -; - prog8 always sticks main module at the beginning so can't create a container module to stick zsound in (if you want to load it at the beginning) -; - prog8 always has some bootstrap code after the basic launcher so we can only start loading stuff after that -; - prog8 main has to be set to a fixed address (in this case $0830) to which the special zsound binary has been compiled as well. - - -main $0830 { - -zsound_lib: - ; this has to be the first statement to make sure it loads at the specified module address $0830 - %asmbinary "zsound_combo-0830.bin" - - ; note: jump table is offset by 2 from the load address (because of prg header) - romsub $0832 = zsm_init() clobbers(A) - romsub $0835 = zsm_play() clobbers(A, X, Y) - romsub $0838 = zsm_playIRQ() clobbers(A, X, Y) - romsub $083b = zsm_start(ubyte bank @A, uword song_address @XY) clobbers(A, X, Y) -> bool @Pc - romsub $083e = zsm_stop() - romsub $0841 = zsm_setspeed(uword hz @XY) clobbers(A, X, Y) - romsub $0844 = zsm_setloop(ubyte count @A) - romsub $0847 = zsm_forceloop(ubyte count @A) - romsub $084a = zsm_noloop() - romsub $084d = zsm_setcallback(uword address @XY) - romsub $0850 = zsm_clearcallback() clobbers(A) - romsub $0853 = zsm_get_music_speed() clobbers(A) -> uword @XY - romsub $0856 = pcm_init() clobbers(A) - romsub $0859 = pcm_trigger_digi(ubyte bank @A, uword song_address @XY) - romsub $085c = pcm_play() clobbers(A, X, Y) - romsub $085f = pcm_stop() clobbers(A) - romsub $0862 = pcm_set_volume(ubyte volume @A) - - const ubyte song_bank = 1 - const uword song_address = $a000 - const ubyte digi_bank = 6 - const uword digi_address = $a000 - const ubyte zcm_DIGITAB_size = 8 ; header size - - sub start() { - txt.print("zsound demo program (drive 8)!\n") - - cbm.SETMSG(%10000000) ; enable kernal status messages for load - cx16.rambank(song_bank) - if diskio.load_raw("colony.zsm", song_address)==0 { - txt.print("?can't load\n") - return - } - cx16.rambank(digi_bank) - if diskio.load_raw("terminator2.zcm", digi_address)==0 { - txt.print("?can't load\n") - return - } else { - ; initialize header pointer of the zcm to point to actual sample data - ; this will be set correcly by zsound lib itself if left at zero - ; poke(digi_address+2, digi_bank) - ; pokew(digi_address, digi_address+zcm_DIGITAB_size) - } - cbm.SETMSG(0) - txt.nl() - cx16.rambank(song_bank) - - play_music() - } - - sub play_music() { - zsm_init() - pcm_init() - zsm_setcallback(&end_of_song_cb) - if zsm_start(song_bank, song_address)==false { - txt.print("\nmusic speed: ") - txt.print_uw(zsm_get_music_speed()) - txt.print(" hz\nplaying song! hit enter to also play a digi sample!\n") - - repeat { - cx16.r0, void = cx16.joystick_get(0) - if cx16.r0!=$ffff - pcm_trigger_digi(digi_bank, digi_address) - - sys.waitvsync() - repeat 1400 { - ; artificially delay calling the play routine so we can see its raster time - %asm {{ - nop - }} - } - palette.set_color(0, $84c) - pcm_play() - palette.set_color(0, $f25) - zsm_play() - palette.set_color(0, $000) - } - zsm_stop() - pcm_stop() - } else { - txt.print("?song start error\n") - } - } - - sub end_of_song_cb() { - txt.print("end of song!\n") - } -} diff --git a/examples/cx16/zsound/stream-test-zcm.p8 b/examples/cx16/zsound/stream-test-zcm.p8 deleted file mode 100644 index d15ac3253..000000000 --- a/examples/cx16/zsound/stream-test-zcm.p8 +++ /dev/null @@ -1,91 +0,0 @@ -%import textio -%import diskio -%zpreserved $22,$2d ; zsound lib uses this region - -; NOTE: the ZSound library is DEPRECATED and ZSMKIT is its successor. -; find prog8 examples with ZSMKIT here: https://github.com/mooinglemur/zsmkit/tree/main/p8demo - -; NOTE: this is a proof of concept to stream ZCM digi from disk while playing. -; currently there's no real streaming API / circular buffer in zsound, -; so it simply loads the whole ZCM file in chunks in memory sequentially. -; But it does so while the playback is going on in the background. -; It seems fast enough to stream + play 16khz 16bit stereo samples. (around 64 Kb/sec) -; Maybe we can go faster but 22 Khz seemed too much to keep up with. - -main $0830 { - -zsound_lib: - ; this has to be the first statement to make sure it loads at the specified module address $0830 - %asmbinary "zsound_combo-0830.bin" - - ; note: jump table is offset by 2 from the load address (because of prg header) - romsub $0832 = zsm_init() clobbers(A) - romsub $0835 = zsm_play() clobbers(A, X, Y) - romsub $0838 = zsm_playIRQ() clobbers(A, X, Y) - romsub $083b = zsm_start(ubyte bank @A, uword song_address @XY) clobbers(A, X, Y) -> bool @Pc - romsub $083e = zsm_stop() - romsub $0841 = zsm_setspeed(uword hz @XY) clobbers(A, X, Y) - romsub $0844 = zsm_setloop(ubyte count @A) - romsub $0847 = zsm_forceloop(ubyte count @A) - romsub $084a = zsm_noloop() - romsub $084d = zsm_setcallback(uword address @XY) - romsub $0850 = zsm_clearcallback() clobbers(A) - romsub $0853 = zsm_get_music_speed() clobbers(A) -> uword @XY - romsub $0856 = pcm_init() clobbers(A) - romsub $0859 = pcm_trigger_digi(ubyte bank @A, uword song_address @XY) - romsub $085c = pcm_play() clobbers(A, X, Y) - romsub $085f = pcm_stop() clobbers(A) - romsub $0862 = pcm_set_volume(ubyte volume @A) - - const ubyte digi_bank = 1 - const uword digi_address = $a000 - const ubyte zcm_DIGITAB_size = 8 ; header size - const uword ram_bank_size = $2000 - - bool load_ok = false - - sub prebuffer() { - txt.print("prebuffering...") - void diskio.f_read(digi_address, ram_bank_size*4) - } - - sub start() { - txt.print("\nzsound digi streaming (drive 8)!\n") - - if not diskio.f_open("thriller.zcm") { - txt.print("?no file\n") - return - } - - cx16.rambank(digi_bank) - prebuffer() - - pcm_init() - pcm_trigger_digi(digi_bank, digi_address) - cx16.enable_irq_handlers(true) - cx16.set_vsync_irq_handler(&zsm_playroutine_irq) - - txt.print("\nstreaming from file, playback in irq!\n") - uword size = 1 - while size!=0 { - size = diskio.f_read(digi_address, ram_bank_size) ; load next bank - txt.print_ub(cx16.getrambank()) - txt.spc() - sys.wait(5) ; artificial delay - } - - txt.print("sound file end reached.\n") - diskio.f_close() - - repeat { - } - - pcm_stop() ;unreached - cx16.disable_irq_handlers() - } - - sub zsm_playroutine_irq() -> bool { - pcm_play() - return true - } -} diff --git a/examples/cx16/zsound/zsmplayer.txt b/examples/cx16/zsound/zsmplayer.txt deleted file mode 100644 index ee529ef23..000000000 --- a/examples/cx16/zsound/zsmplayer.txt +++ /dev/null @@ -1,195 +0,0 @@ -;.............. -; init_player : -; =========================================================================== -; Arguments: (none) -; Returns: (none) -; Affects: A -; --------------------------------------------------------------------------- -; Call this before using any of the other routines. -; -; Initializes the memory locations used by ZSM player to a stopped playback -; state, with the data pointer pointing at a dummy "end-of-data" command frame. - - -;............ -; playmusic : -; =========================================================================== -; Arguments: none -; Returns: none -; Affects: See stepmusic -; --------------------------------------------------------------------------- -; 60hz frontend for stepmusic. -; Call it once per frame to play ZSM music. -; -; Playmusic calls stepmusic however many times is determined from the ZSM tick -; rate header information. This function does not "smooth" time - i.e. it -; just calls stepmusic N times in a row. For more accurate timing -; you should generate your own timing source and call stepmusic directly. -; -; NOTE: playmusic calls stepmusic, WHICH IS NOT IRQ SAFE! Use playmusic_IRQ instead -; if you wish to run the music update during the IRQ handler, or else your -; handler should save and restore the VERA ctrl register and the address -; registers for the data0 data port. - - -;................ -; playmusic_IRQ : -; =========================================================================== -; IRQ-safe version of playmusic, which restores VERA registers and the active -; HiRAM bank. -; -; It does NOT save or restore the CPU registers. Your IRQ handler should -; pull those from the stack prior to RTI as usual if not jumping into the -; Kernal's once per frame routine. -; -; Alternatively, you can use this interface as a VERA-safe call from outside -; of IRQ handlers. A,X,and Y are still clobbered by stepmusic. - - -;............ -; stepmusic : -; =========================================================================== -; Arguments: (none) -; Returns: Carry flag: (currently broken) 0=playing, 1=stopped or looped -; Affects: A,X,Y, VERA CTRL and data port 0 address registers -; --------------------------------------------------------------------------- -; Advances the music by one tick. -; Music must be initialized by startmusic before this will have any effect. -; -; This routine may be removed from the API in future revisions! -; -; Call as many times per frame as required by the ZSM's playback rate. -; (usually 60Hz - once per frame) -; THIS ROUTINE IS NOT SAFE to call directly during IRQ, as it clobbers VERA -; registers w/o fixing them (for speed reasons). If your program -; is designed to run the music player during an IRQ, use one of the IRQ-safe -; wrapper functions that save and restore VERA before calling this -; core routine, or else be sure to save the states of the affected VERA registers - - -;-----------------------------------------------------[Music Control]-------- - - -;............. -; startmusic : -; =========================================================================== -; Arguments: -; A : HIRAM bank of tune -; XY : Memory address of beginning of ZSM header -; Returns: Carry flag: 0=success, 1=fail -; Affects: A,X,Y -; --------------------------------------------------------------------------- -; Uses the ZSM header to determine the default playback parameters. -; Copies them into the active data structures, and adjusts header pointers -; such as loop and PCM (future) sample bank offsets relative to where the -; ZSM was actually loaded into memory. -; -; Calls setmusicspeed with the song's default play speed from header. -; Defaults the looping behavior based on the ZSM being played. If the tune -; contains a loop, the playback is set for infinite loop mode. If it does -; not, the loop pointer is set to the beginning of the tune, but looping -; remains disabled. -; You may call set_loop, force_loop, or disable_loop to modify these defaults -; afterwards. - - -;............ -; stopmusic : -; =========================================================================== -; Arguments: (none) -; Returns: (none) -; Affects: (none) -; --------------------------------------------------------------------------- -; Halts music playback, silences all voices used by the current tune, -; and clears music channel mask - - -; ------------------------------------------------[On-The-Fly Controls]------ - - -;................ -; setmusicspeed : -; =========================================================================== -; Arguments: -; X/Y : Playback speed in Hz. (x=lo, y=hi) -; Returns: (none) -; Affects: A,X,Y -; --------------------------------------------------------------------------- -; Converts Hz into ticks/frame, and adjusts playback speed to the new rate. -; Setting a 60hz song to play back at 120hz will play at double speed and -; setting it to 30hz will play at 1/2 speed. -; (I suppose I should make an accessor function to return the native speed -; of a ZSM so that you don't have to guess in order to make calculated speed -; changes) - - -;............. -; force_loop : -; =========================================================================== -; Arguments: .A = number of times to loop the music. 0 = infinite -; Returns: none -; Affects: none -; --------------------------------------------------------------------------- -; Note that if the music was intended to be a one-shot playback (i.e. contains -; no loop), this will force looping play of the entire song. Use set_loop -; to modify the looper's behavior without forcing looping play of non-looped -; songs. - - -;........... -; set_loop : -; =========================================================================== -; Arguments: .A = number of times to loop the music. 0 = infinite -; Returns: none -; Affects: none -; --------------------------------------------------------------------------- -; Sets the number of repeats that loopback mode will perform after the current -; pass through the song is finished. If the playback mode is one-shot (no looping) -; then this will have no effect. - - -;............... -; disable_loop : -; =========================================================================== -; Arguments: none -; Returns: none -; Affects: none -; --------------------------------------------------------------------------- -; When music reaches EOF, playback will stop, regardless of loops in the tune. -; Has no effect if looping was not already enabled. - - -;-----------------------------------------------------[Information]---------- - - -;............... -; set_callback : -; =========================================================================== -; Arguments: -; .XY = address of callback function -; Returns: none -; Affects: none -; --------------------------------------------------------------------------- -; Sets a notification callback whenever a tune finishes or loops. -; The callback passes the following parameters: -; Z=0 if music is stopped, Z=1 if music is playing -; .A = number of remaining loops - -;................. -; clear_callback : -; =========================================================================== -; Arguments: none -; Returns: none -; Affects: A -; --------------------------------------------------------------------------- -; Disables the EOF notification callback - -;.................. -; get_music_speed : -; =========================================================================== -; Arguments: none -; Returns: .XY = song's play rate in Hz -; Affects: none -; --------------------------------------------------------------------------- -; This function returns the default playback rate in Hz of the active song. -; This is NOT the current playback speed, but the speed in the song's header. diff --git a/examples/cx16/zsound/zsound_combo-0830.bin b/examples/cx16/zsound/zsound_combo-0830.bin deleted file mode 100644 index d94449725..000000000 Binary files a/examples/cx16/zsound/zsound_combo-0830.bin and /dev/null differ