What is Arkos Tracker? › Forums › Arkos Tracker forum › General discussion › ZX Basic integration
Tagged: zx spectrum basic
- This topic has 6 replies, 3 voices, and was last updated 4 years, 4 months ago by Targhan.
-
AuthorPosts
-
August 1, 2020 at 3:36 am #30138gusmanParticipant
Hi.
I have managed to get a complete song working on a spectrum 128k using ZX Basic, I compiled a player with the music using RASM, used Disark to extract the assembler source, created functions to init, play and stop and it works perfectly.
After that I wanted to do things in mid of the song (load some graphic screens and so on) and there I’m having a hard time.
I have found the CPC integration example and it mostly works, on the sync loop I test for a key press and if it’s pressed I exit the loop, do some work and then I call the loop again. It returns and continues playing but the music is screwed, it still plays the same rythm but the tones are completely off, sometimes are very high, others very low, others only a single tone is played (but with the same rythm)…
I think I must be missing something but have no idea at all.
Also, would it be possible to play the music only when an interrupt happens so I can do the graphic work while the music is still playing? I can mix assembler in the basic son an ASM example would be really nice.
Here are my hybrid functions (music.z80asm is the dissasembled player with the song).
sub initMusic() asm push ix ;ZX basic only needs IX to be preserved when asm is called ld hl, HERO_START xor a call PLY_AKG_INIT pop ix end asm end sub sub musicUntilPress() asm push ix Sync: ei nop halt di ;3 - Play one frame of the song. call PLY_AKG_PLAY ld bc, 32766 in a, (c) and 31 xor 31 jr nz, keyPressed ;4 - Loop! jr Sync keyPressed: pop ix end asm end sub sub stopMusic() asm push ix di call PLY_AKG_STOP ei pop ix end asm end sub asm Player: #include "music.z80asm"
August 1, 2020 at 10:24 am #30139AdminKeymasterHi,
I have no real idea why after you stop the song, and play it again, the song would be “destroyed”. The Stop itself only sends values to the PSG, so does not modify the song data itself.
Things to test:
– Do the same of what you do, without calling the STOP. Is the music still screwed?
– Make sure that whatever you’re doing after the STOP does not change the player or music data (do you display stuff on the screen, could it modify the buffer if you use the ROM buffer mode with the player?)As for playing from within a system interruption, it is of course possible, however I do NOT know how to trigger a system interruption with the ZX!! The player itself is system-agnostic so of course it is doable. Once you have set up the interruption handler, you can call the Play, but beware:
– The player modifies ALL the registers, including IX and IY, AF’ and all the auxiliary registers, so you have to save ALL of them (except for the stack, which the player modifies but saves and restores by itself).If you have a working example, maybe we could publish it on the website, some people asked me the same thing on CPC.
August 1, 2020 at 10:59 am #30140gusmanParticipantHi.
Thanks for the answer.
Hmmm, this is strange, I only call the most basic routines on my code, writing to the screen memory and nothing else (not using the ROM functions, I write to screen manually), I thought that something had to be preserved between the play calls but from your answer I assume that’s not the case…
I’m going to set up the interrupt handler and start debugging from there as I will be able to listen when the music gets corrupted.
I assume that if on my interupt handler only the music must be executed something like this would work, right?
`Interrput_Handler:
push af
push bc
push de
push ix
push iyexx
ex af, af’push af
push bc
push de
push ix
push iycall PLY_AKG_PLAY
pop iy
pop ix
pop de
pop bc
pop afex af, af’
exxpop iy
pop ix
pop de
pop bc
pop afreti`
I’m going to try it and if I get it working will post the interrupt setup example.
Cheers.
August 1, 2020 at 11:01 am #30141gusmanParticipantAlso, I have noticed something on the forum, whenever I try to edit my posts it gets me to other post!
It redirects me always to http://www.julien-nevo.com/arkostracker/index.php/forums/topic/editor-hard-crash/
Cheers.
August 1, 2020 at 11:06 am #30142AdminKeymasterYeah, the forum is strangely broken. I don’t have time correcting this, I prefer concentrating on what really matters :).
About your interruption handling:
– IX and IY are NOT double registers: only one version exist, IX’ and IY’ don’t.
– RETI shouldn’t be useful, simply RET.
– Just before the least RET, do a EI. The Z80 automatically performs a DI when calling an interruption.August 1, 2020 at 1:06 pm #30143gusmanParticipantOk, got it working, using the interrupt the music works without problems and my code runs perfectly without any change so… no idea why the music got corrupted, I suspect that something in the ROM interrupt routine was the culprit.
Yep, the code I posted had some fails, I was sleepy when I wrote it, last night was too long 🙂
Here is the code for setting up the player using the interrupt handler.
PrepareMusic: ld hl, HERO_START ;load your song address xor a ;subtrack 0 call PLY_AKG_INIT ;call initialization routine ret PlayMusic: call Interrupt_Setup ;This function is totally innecessary, just for readability of the code ret StopMusic: di ;disable interrupts call PLY_AKG_STOP ;stop the player IM 1 ;revert interrupt mode to mode 1 ei ;enable interrupts ret Player: ;your player+music code #include "music.z80asm" JP_ADDRESS EQU #FDFD ;JP address ;IM 2 mode must be used on the spectrum to have a custom interrupt handler. ;The spectrum architecture makes impossible to know what will be on the bus when an interrupt is executed ;so the handler must be in an address where it's high and low bytes are equal. ;To be able to store your interrupt handler anywhere three bytes at an address ;with that characteristic (FDFD in this case) are reserved and written with "jp Interrupt_Handler" Interrupt_Handler: push af ;store all registers push bc push de push hl push ix push iy exx ex af, af' push af push bc push de push hl call PLY_AKG_PLAY ;play music pop hl ;restore all registers pop de pop bc pop af ex af, af' exx pop iy pop ix pop hl pop de pop bc pop af ei ;reenable interrupts ret ;return from interrupt handler .align 256 Interrupt_Table: ;interrupt table must be aligned at page boundary ;with 256 + 1 bytes, all with the same value .defs 257 Interrupt_Setup: di ;Disable interrupts ld de, Interrupt_Table ;load interrupt table address ld hl, JP_ADDRESS ;load "JP" address ld a, d ld i, a ;load I with the interrupt table high byte ld a, l ;load a with lower byte of JP address (indifferent to use H or L, both must be equal) Interrupt_Table_Loop: ld (de), a ;fill the table inc e jr nz, Interrupt_Table_Loop inc d ;write the 257th byte of the table ld (de), a ld (hl), #C3 ;write JP inc l ld (hl), low(Interrupt_Handler) ;write interrupt handler address inc l ld (hl), high(Interrupt_Handler) im 2 ;set interrupt mode to 2 ei ;enable interrupts ret
To use it you first call PrepareMusic, when you want your music to start call PlayMusic and if you want to stop it then call StopMusic.
Hope it helps anyone else who wants to integrate it 😀
August 3, 2020 at 11:07 am #30147TarghanKeymasterAwesome, I’ll put that in a specific page of the website, with credits where it is due :).
-
AuthorPosts
- You must be logged in to reply to this topic.