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