Using interruption player on ZX Spectrum

The following code will allow you to play a music under interruption, on ZX Spectrum (without using the firmware).

This code was kindly provided by Gusman. A big thanks to him!

PrepareMusic:
ld hl, MUSIC_ADDRESS ;load your song address
xor a ;subsong 0
call PLY_AKG_INIT ;call initialization routine
ret

PlayMusic:
call Interrupt_Setup ;This function is totally unnecessary, 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
;play music
call PLY_AKG_PLAY
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

;reenable interrupts
ei
;return from interrupt handler
ret

.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