gigatron/rom/Contrib/at67/gbas/runtime/audio_ROMv5a.i
2025-01-28 19:17:01 +03:00

364 lines
15 KiB
OpenEdge ABL

midiId EQU register0
audioAddr EQU register1
waveType EQU register2
midiNote EQU register4 ; register4 to register7 are the only free registers during time slicing
midiCommand EQU register5
midiPtr EQU register6
sndChannel EQU register8
sndFrequency EQU register9
sndVolume EQU register10
sndWaveType EQU register11
musicStream EQU register8
musicNote EQU register9
musicCommand EQU register10
musicPtr EQU register11
%SUB setMidiStream
setMidiStream LDWI _midisLut_
ADDW midiId
ADDW midiId
DEEK
RET
%ENDS
%SUB resetMidi
resetMidi LDI 1
STW midiDelay ; instant MIDI startup
LDI giga_soundChan1 >>8
ST audioAddr + 1
LDI 0
ST waveType ; wavA, (wavX is initialised by Macros)
resetMi_loop LDI giga_soundChan1
ST audioAddr ; reset low byte
LDW waveType
DOKE audioAddr ; wavA and wavX
INC audioAddr
INC audioAddr
LDI 0
DOKE audioAddr ; keyL and keyH
INC audioAddr + 1 ; increment high byte
LD audioAddr + 1
SUBI 4
BLE resetMi_loop
RET
%ENDS
%SUB playMidi
playMidi LDW midiStream
BEQ playM_exit0 ; 0x0000 = stop
LDI 5 ; keep pumping soundTimer
ST giga_soundTimer
LDW midiDelay
SUBI 1
STW midiDelay
BLE playM_start
playM_exit0 RET
playM_start PUSH
playM_process LDW midiStream
PEEK ; get midi stream byte
STW midiCommand
LDW midiStream
ADDI 0x01
STW midiStream
LDW midiCommand
ANDI 0xF0
XORI 0x90 ; check for start note
BNE playM_endnote
CALLI midiStartNote ; start note
BRA playM_process
playM_endnote XORI 0x10 ; check for end note
BNE playM_segment
CALLI midiEndNote ; end note
BRA playM_process
playM_segment XORI 0x50 ; check for new segment
BNE playM_delay
LDW midiStream ; midi score
DEEK
STW midiStream ; 0xD0 new midi segment address
BEQ playM_exit1 ; 0x0000 = stop
BRA playM_process
playM_delay LD midiCommand
STW midiDelay
playM_exit1 POP
RET
%ENDS
%SUB playMidiVol
playMidiVol LDW midiStream
BEQ playMV_exit0 ; 0x0000 = stop
LDI 5 ; keep pumping soundTimer
ST giga_soundTimer
LDW midiDelay
SUBI 1
STW midiDelay
BLE playMV_start
playMV_exit0 RET
playMV_start PUSH
playMV_process LDW midiStream
PEEK ; get midi stream byte
STW midiCommand
LDW midiStream
ADDI 0x01
STW midiStream
LDW midiCommand
ANDI 0xF0
XORI 0x90 ; check for start note
BNE playMV_endnote
CALLI midiStartNote ; start note
CALLI midiSetVolume ; set note volume
BRA playMV_process
playMV_endnote XORI 0x10 ; check for end note
BNE playMV_segment
CALLI midiEndNote ; end note
BRA playMV_process
playMV_segment XORI 0x50 ; check for new segment
BNE playMV_delay
LDW midiStream ; midi score
DEEK
STW midiStream ; 0xD0 new midi segment address
BEQ playMV_exit1 ; 0x0000 = stop
BRA playMV_process
playMV_delay LD midiCommand
STW midiDelay
playMV_exit1 POP
RET
%ENDS
%SUB midiStartNote
midiStartNote LDWI giga_notesTable - 22 ; giga_notesTable + (midi - 11)*2
STW midiPtr
LDW midiStream ; midi note
PEEK
LSLW
ADDW midiPtr
STW midiPtr
LUP 0x00 ; get ROM midi note low byte
ST midiNote
LDW midiPtr
LUP 0x01 ; get ROM midi note high byte
ST midiNote + 1
LDW midiCommand
ANDI 0x03 ; get channel
ADDI 0x01
ST midiPtr + 1
LDI 0xFC
ST midiPtr ; note address 0x01FC <-> 0x04FC
LDW midiNote
DOKE midiPtr ; set note
midiSN_exit LDW midiStream
ADDI 0x01 ; midiStream++
STW midiStream
RET
midiSetVolume LDI 0xFA
ST midiPtr ; wavA address 0x01FA <-> 0x04FA, (midiPtr is still valid from midiStartNote)
LDW midiStream ; midi volume
PEEK
POKE midiPtr
BRA midiSN_exit ; save a few bytes by using midiStartNote's epilogue
midiEndNote LDW midiCommand
ANDI 0x03 ; get channel
ADDI 0x01
ST midiPtr + 1
LDI 0xFC
ST midiPtr ; channels address 0x01FC <-> 0x04FC
LDI 0
DOKE midiPtr ; end note
RET
%ENDS
%SUB midiGetNote
midiGetNote LDWI giga_notesTable - 22 ; giga_notesTable + (midi - 11)*2
STW musicPtr
LD musicNote
LSLW
ADDW musicPtr
STW musicPtr
LUP 0x00 ; get ROM note low byte
;LSLW ; left shift low byte as SOUND command expects
ST musicNote ; a non system internal frequency
LDW musicPtr
LUP 0x01 ; get ROM note high byte
ST musicNote + 1
LDW musicNote ; this is needed for GET("MIDI_NOTE")
RET
%ENDS
%SUB resetMusic
resetMusic LDI giga_soundChan1 >>8
ST audioAddr + 1
LDI 0
ST waveType ; wavA, (wavX is initialised by Macros)
resetMu_loop LDI giga_soundChan1
ST audioAddr ; reset low byte
LDW waveType
DOKE audioAddr ; wavA and wavX
INC audioAddr
INC audioAddr
LDI 0
DOKE audioAddr ; keyL and keyH
INC audioAddr + 1 ; increment high byte
LD audioAddr + 1
SUBI 4
BLE resetMu_loop
RET
%ENDS
%SUB playMusic
playMusic PUSH
playN_process LDW musicStream
INC musicStream
PEEK ; get music stream byte
STW musicCommand
ANDI 0xF0
XORI 0x90 ; check for start note
BNE playN_endnote
LDW musicStream
INC musicStream
PEEK ; get music note
ST musicNote
CALLI midiGetNote ; get midi note from ROM
CALLI musicPlayNote
BRA playN_process
playN_endnote XORI 0x10 ; check for end note
BNE playN_segment
LDI 0
STW musicNote
CALLI musicPlayNote ; end note
BRA playN_process
playN_segment XORI 0x50 ; check for new segment
BNE playN_delay
LDW musicStream ; music stream
DEEK
STW musicStream ; 0xD0 new music segment address
BNE playN_process ; 0x0000 = stop
POP
RET
playN_delay LDW musicCommand
ST giga_soundTimer ; keep pumping soundTimer
STW waitVBlankNum
CALLI waitVBlanks
BRA playN_process
%ENDS
%SUB musicGetNote
musicGetNote LDWI giga_notesTable
ADDW musicNote
ADDW musicNote
STW musicPtr
LUP 0x00 ; get ROM note low byte
ST musicNote
LDW musicPtr
LUP 0x01 ; get ROM note high byte
ST musicNote + 1
LDW musicNote ; this is needed for GET("MUSIC_NOTE")
RET
%ENDS
%SUB musicPlayNote
musicPlayNote LDW musicCommand
ANDI 0x03 ; get channel
ADDI 0x01
ST musicPtr + 1
LDI 0xFC
ST musicPtr ; note address 0x01FC <-> 0x04FC
LDW musicNote
DOKE musicPtr ; set note
RET
%ENDS
%SUB soundAllOff
soundAllOff LDWI 0x01FC
STW sndChannel
LDI 0
DOKE sndChannel ; turn off channel 0
INC sndChannel + 1
DOKE sndChannel ; turn off channel 1
INC sndChannel + 1
DOKE sndChannel ; turn off channel 2
INC sndChannel + 1
DOKE sndChannel ; turn off channel 3
RET
%ENDS
%SUB soundOff
soundOff LDI 0xFC
ST sndChannel
LDI 0
DOKE sndChannel ; turn off channel
RET
%ENDS
%SUB soundOn
soundOn LDWI SYS_LSRW1_48
STW giga_sysFn
LDI 0xFC
ST sndChannel
LD sndFrequency
SYS 48
ST sndFrequency ; right shift low byte of sndFrequency by 1
LDW sndFrequency ; format = high:8 low:07, (bit 7 of low byte = 0)
DOKE sndChannel ; turn on channel
RET
%ENDS
%SUB soundOnV
soundOnV LDWI SYS_LSRW1_48
STW giga_sysFn
LDI 0xFC
ST sndChannel
LD sndFrequency
SYS 48
ST sndFrequency ; right shift low byte of sndFrequency by 1
LDW sndFrequency ; format = high:8 low:07, (bit 7 of low byte = 0)
DOKE sndChannel ; turn on channel
LDI 0xFA
ST sndChannel ; still pointing to the correct channel
LDI 63
SUBW sndVolume
ADDI 64
POKE sndChannel ; 0 -> 63 maps to 127 -> 64
INC sndChannel
LD sndWaveType
ANDI 3
POKE sndChannel ; wave type in wave X
RET
%ENDS
%SUB soundMod
soundMod LDI 0xFA
ST sndChannel
LDW sndWaveType ; format = high:waveX low:waveA
DOKE sndChannel ; set modulation
RET
%ENDS