mirror of
https://github.com/irmen/prog8.git
synced 2024-11-29 17:50:35 +00:00
tweaks cx16 sample streaming example, also added a new one
This commit is contained in:
parent
966b017670
commit
17f7b11148
@ -1195,6 +1195,7 @@ asmsub set_sprcol_irq_handler(uword address @AY) clobbers(A) {
|
|||||||
asmsub set_aflow_irq_handler(uword address @AY) clobbers(A) {
|
asmsub set_aflow_irq_handler(uword address @AY) clobbers(A) {
|
||||||
; Sets the AFLOW irq handler to use with enable_irq_handlers(). Also enables AFLOW irqs.
|
; Sets the AFLOW irq handler to use with enable_irq_handlers(). Also enables AFLOW irqs.
|
||||||
; NOTE: unless a proper irq handler is already running, you should enclose this call in set_irqd() / clear_irqd() to avoid system crashes.
|
; NOTE: unless a proper irq handler is already running, you should enclose this call in set_irqd() / clear_irqd() to avoid system crashes.
|
||||||
|
; NOTE: the handler itself must fill the audio fifo buffer to at least 25% full again (1 KB) or the aflow irq will keep triggering!
|
||||||
%asm {{
|
%asm {{
|
||||||
php
|
php
|
||||||
sei
|
sei
|
||||||
|
@ -108,6 +108,7 @@ class TestCompilerOnExamplesCx16: FunSpec({
|
|||||||
"vtui/testvtui",
|
"vtui/testvtui",
|
||||||
"pcmaudio/play-adpcm",
|
"pcmaudio/play-adpcm",
|
||||||
"pcmaudio/stream-wav",
|
"pcmaudio/stream-wav",
|
||||||
|
"pcmaudio/stream-pcm-simple",
|
||||||
"pcmaudio/vumeter",
|
"pcmaudio/vumeter",
|
||||||
"sprites/dragon",
|
"sprites/dragon",
|
||||||
"sprites/dragons",
|
"sprites/dragons",
|
||||||
|
@ -224,6 +224,8 @@ Here they are, all available in ``cx16``:
|
|||||||
|
|
||||||
``set_aflow_irq_handler (uword address)``
|
``set_aflow_irq_handler (uword address)``
|
||||||
Sets the audio buffer underrun interrupt handler routine. Also enables AFLOW interrupts.
|
Sets the audio buffer underrun interrupt handler routine. Also enables AFLOW interrupts.
|
||||||
|
Note: the handler must fill the Vera's audio fifo buffer by itself with at least 25% worth of data (1 kb)
|
||||||
|
otherwise the aflow irq keeps triggering.
|
||||||
|
|
||||||
``disable_irq_handlers ()``
|
``disable_irq_handlers ()``
|
||||||
Hand control back to the system default IRQ handler.
|
Hand control back to the system default IRQ handler.
|
||||||
|
124
examples/cx16/pcmaudio/stream-pcm-simple.p8
Normal file
124
examples/cx16/pcmaudio/stream-pcm-simple.p8
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
; This program can stream a simple uncompressed PCM file from the sdcard.
|
||||||
|
; Currently it has been set up to play a 16 bit stereo PCM file,
|
||||||
|
; and it plays it in the given sample frequency typed in by the user.
|
||||||
|
;
|
||||||
|
; It uses a AFLOW irq handler to refill the vera's PCM fifo buffer,
|
||||||
|
; and sets a flag that signals the main program to load the next block of
|
||||||
|
; data from disk. It is problematic to call kernal I/O routines inside an irq handler,
|
||||||
|
; otherwise the aflow handler itself could have loaded the pcm data straight into
|
||||||
|
; the vera's fifo buffer. But this could lead to race conditions so we need explicit buffering.
|
||||||
|
;
|
||||||
|
; The IRQ handlers are installed using Prog8's support routines for irq handlers.
|
||||||
|
; The sample data is simply read using diskio.f_read() routine, but that uses MACPTR internally for fast loads.
|
||||||
|
|
||||||
|
|
||||||
|
%import diskio
|
||||||
|
%import textio
|
||||||
|
%option no_sysinit
|
||||||
|
|
||||||
|
main {
|
||||||
|
|
||||||
|
|
||||||
|
sub start() {
|
||||||
|
str MUSIC_FILENAME = "?"*32
|
||||||
|
txt.print("what sample rate (hz) do you want to play at: ")
|
||||||
|
void txt.input_chars(MUSIC_FILENAME)
|
||||||
|
music.vera_rate_hz = conv.str2uword(MUSIC_FILENAME)
|
||||||
|
if music.vera_rate_hz==0
|
||||||
|
music.vera_rate_hz=44100
|
||||||
|
music.calculate_vera_rate(music.vera_rate_hz)
|
||||||
|
|
||||||
|
txt.print("\nname of raw .pcm file to play on drive 8: ")
|
||||||
|
while 0==txt.input_chars(MUSIC_FILENAME) {
|
||||||
|
; until user types a name...
|
||||||
|
}
|
||||||
|
|
||||||
|
if diskio.f_open(MUSIC_FILENAME) {
|
||||||
|
cx16.rombank(0)
|
||||||
|
void diskio.fastmode(1)
|
||||||
|
music.init()
|
||||||
|
interrupts.setup()
|
||||||
|
music.start()
|
||||||
|
} else {
|
||||||
|
txt.print("\nio error")
|
||||||
|
}
|
||||||
|
|
||||||
|
repeat {
|
||||||
|
interrupts.wait()
|
||||||
|
if interrupts.aflow {
|
||||||
|
; read the next 1024 bytes of audio data into the buffer
|
||||||
|
txt.chrout('.')
|
||||||
|
if diskio.f_read(interrupts.audio_buffer, 1024) != 1024
|
||||||
|
break
|
||||||
|
interrupts.aflow = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interrupts {
|
||||||
|
bool aflow
|
||||||
|
uword audio_buffer = memory("audiobuffer", 1024, 0)
|
||||||
|
|
||||||
|
sub setup() {
|
||||||
|
aflow = false
|
||||||
|
sys.memset(audio_buffer, 1024, 0)
|
||||||
|
cx16.enable_irq_handlers(true)
|
||||||
|
cx16.set_aflow_irq_handler(&aflow_handler)
|
||||||
|
; no other irqs in this example.
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub wait() {
|
||||||
|
%asm {{
|
||||||
|
wai
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub aflow_handler() -> bool {
|
||||||
|
; copy 1024 bytes of audio data from the buffer into vera's fifo, quickly!
|
||||||
|
%asm {{
|
||||||
|
lda p8v_audio_buffer
|
||||||
|
sta _loop+1
|
||||||
|
sta _lp2+1
|
||||||
|
lda p8v_audio_buffer+1
|
||||||
|
sta _loop+2
|
||||||
|
sta _lp2+2
|
||||||
|
ldx #4
|
||||||
|
ldy #0
|
||||||
|
_loop lda $ffff,y
|
||||||
|
sta cx16.VERA_AUDIO_DATA
|
||||||
|
iny
|
||||||
|
_lp2 lda $ffff,y
|
||||||
|
sta cx16.VERA_AUDIO_DATA
|
||||||
|
iny
|
||||||
|
bne _loop
|
||||||
|
inc _loop+2
|
||||||
|
inc _lp2+2
|
||||||
|
dex
|
||||||
|
bne _loop
|
||||||
|
}}
|
||||||
|
aflow = true ; signal main program to read the next block of audio data: it is unsafe to to I/O in a irq handler!
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
music {
|
||||||
|
uword vera_rate_hz
|
||||||
|
ubyte vera_rate
|
||||||
|
|
||||||
|
sub init() {
|
||||||
|
cx16.VERA_AUDIO_RATE = 0 ; halt playback
|
||||||
|
cx16.VERA_AUDIO_CTRL = %10111011 ; stereo 16 bit, volume 11
|
||||||
|
}
|
||||||
|
|
||||||
|
sub start() {
|
||||||
|
cx16.VERA_AUDIO_RATE = vera_rate ; start playback
|
||||||
|
}
|
||||||
|
|
||||||
|
sub calculate_vera_rate(uword sample_rate) {
|
||||||
|
const uword vera_freq_factor = 25_000_000 / 65536
|
||||||
|
vera_rate = (sample_rate / vera_freq_factor) as ubyte + 1
|
||||||
|
vera_rate_hz = vera_rate * vera_freq_factor
|
||||||
|
}
|
||||||
|
}
|
@ -128,10 +128,6 @@ main {
|
|||||||
|
|
||||||
repeat {
|
repeat {
|
||||||
interrupts.wait()
|
interrupts.wait()
|
||||||
if interrupts.vsync {
|
|
||||||
interrupts.vsync=false
|
|
||||||
; ...do something triggered by vsync irq...
|
|
||||||
}
|
|
||||||
if interrupts.aflow {
|
if interrupts.aflow {
|
||||||
interrupts.aflow=false
|
interrupts.aflow=false
|
||||||
if not music.load_next_block(block_size)
|
if not music.load_next_block(block_size)
|
||||||
@ -158,13 +154,12 @@ interrupts {
|
|||||||
|
|
||||||
sub set_handler() {
|
sub set_handler() {
|
||||||
sys.set_irqd()
|
sys.set_irqd()
|
||||||
cx16.CINV = &handler ; handles both AFLOW and VSYNC
|
cx16.CINV = &handler ; handler for AFLOW
|
||||||
cx16.VERA_IEN = %00001001 ; enable AFLOW + VSYNC
|
cx16.VERA_IEN = %00001000 ; enable AFLOW only
|
||||||
sys.clear_irqd()
|
sys.clear_irqd()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool aflow
|
bool aflow
|
||||||
bool vsync
|
|
||||||
|
|
||||||
asmsub wait() {
|
asmsub wait() {
|
||||||
%asm {{
|
%asm {{
|
||||||
@ -173,6 +168,8 @@ interrupts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub handler() {
|
sub handler() {
|
||||||
|
; we only handle aflow in this example.
|
||||||
|
|
||||||
if cx16.VERA_ISR & %00001000 !=0 {
|
if cx16.VERA_ISR & %00001000 !=0 {
|
||||||
; Filling the fifo is the only way to clear the Aflow irq.
|
; Filling the fifo is the only way to clear the Aflow irq.
|
||||||
; So we do this here, otherwise the aflow irq will keep triggering.
|
; So we do this here, otherwise the aflow irq will keep triggering.
|
||||||
@ -183,10 +180,6 @@ interrupts {
|
|||||||
cx16.restore_virtual_registers()
|
cx16.restore_virtual_registers()
|
||||||
aflow = true
|
aflow = true
|
||||||
}
|
}
|
||||||
if cx16.VERA_ISR & %00000001 !=0 {
|
|
||||||
cx16.VERA_ISR = %00000001
|
|
||||||
vsync = true
|
|
||||||
}
|
|
||||||
|
|
||||||
%asm {{
|
%asm {{
|
||||||
ply
|
ply
|
||||||
@ -233,23 +226,30 @@ music {
|
|||||||
}
|
}
|
||||||
|
|
||||||
asmsub uncompressed_block_8() {
|
asmsub uncompressed_block_8() {
|
||||||
; optimized loop to put 1024 bytes of data into the fifo as fast as possible
|
; copy 1024 bytes of audio data from the buffer into vera's fifo, quickly!
|
||||||
; converting unsigned wav 8 bit samples to signed 8 bit on the fly
|
; converting unsigned wav 8 bit samples to signed 8 bit on the fly.
|
||||||
%asm {{
|
%asm {{
|
||||||
lda p8v_buffer
|
lda p8v_buffer
|
||||||
sta cx16.r0L
|
sta _loop+1
|
||||||
|
sta _lp2+1
|
||||||
lda p8v_buffer+1
|
lda p8v_buffer+1
|
||||||
sta cx16.r0H
|
sta _loop+2
|
||||||
|
sta _lp2+2
|
||||||
ldx #4
|
ldx #4
|
||||||
- ldy #0
|
ldy #0
|
||||||
- lda (cx16.r0),y
|
_loop lda $ffff,y
|
||||||
eor #$80 ; convert to signed 8-bit
|
eor #$80 ; convert to signed
|
||||||
sta cx16.VERA_AUDIO_DATA
|
sta cx16.VERA_AUDIO_DATA
|
||||||
iny
|
iny
|
||||||
bne -
|
_lp2 lda $ffff,y
|
||||||
inc cx16.r0H
|
eor #$80 ; convert to signed
|
||||||
|
sta cx16.VERA_AUDIO_DATA
|
||||||
|
iny
|
||||||
|
bne _loop
|
||||||
|
inc _loop+2
|
||||||
|
inc _lp2+2
|
||||||
dex
|
dex
|
||||||
bne --
|
bne _loop
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@ -264,22 +264,27 @@ music {
|
|||||||
}
|
}
|
||||||
|
|
||||||
asmsub uncompressed_block_16() {
|
asmsub uncompressed_block_16() {
|
||||||
; optimized loop to put 1024 bytes of data into the fifo as fast as possible
|
; copy 1024 bytes of audio data from the buffer into vera's fifo, quickly!
|
||||||
%asm {{
|
%asm {{
|
||||||
lda p8v_buffer
|
lda p8v_buffer
|
||||||
sta cx16.r0L
|
sta _loop+1
|
||||||
|
sta _lp2+1
|
||||||
lda p8v_buffer+1
|
lda p8v_buffer+1
|
||||||
sta cx16.r0H
|
sta _loop+2
|
||||||
|
sta _lp2+2
|
||||||
ldx #4
|
ldx #4
|
||||||
- ldy #0
|
ldy #0
|
||||||
- lda (cx16.r0),y
|
_loop lda $ffff,y
|
||||||
sta cx16.VERA_AUDIO_DATA
|
sta cx16.VERA_AUDIO_DATA
|
||||||
iny
|
iny
|
||||||
bne -
|
_lp2 lda $ffff,y
|
||||||
inc cx16.r0H
|
sta cx16.VERA_AUDIO_DATA
|
||||||
|
iny
|
||||||
|
bne _loop
|
||||||
|
inc _loop+2
|
||||||
|
inc _lp2+2
|
||||||
dex
|
dex
|
||||||
bne --
|
bne _loop
|
||||||
rts
|
|
||||||
}}
|
}}
|
||||||
; original prog8 code:
|
; original prog8 code:
|
||||||
; uword @requirezp ptr = main.start.buffer
|
; uword @requirezp ptr = main.start.buffer
|
||||||
|
Loading…
Reference in New Issue
Block a user