mirror of
https://github.com/irmen/prog8.git
synced 2024-12-22 18:30:01 +00:00
restructure play-adpcm example code, stream-wav can now play stereo adpcm wavs
This commit is contained in:
parent
836bc9d456
commit
f75fd0811e
@ -1,8 +1,6 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- stream-wav example: add stereo adpcm support
|
||||
|
||||
- [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 ....
|
||||
- [on branch: ir-less-branch-opcodes] IR: reduce the number of branch instructions such as BEQ, BEQR, etc (gradually), replace with CMP(I) + status branch instruction
|
||||
- IR: reduce amount of CMP/CMPI after instructions that set the status bits correctly (LOADs? INC? etc), but only after setting the status bits is verified!
|
||||
|
@ -12,6 +12,9 @@ adpcm {
|
||||
; $ sox --guard source.mp3 -r 8000 -c 1 -e ima-adpcm out.wav trim 01:27.50 00:09
|
||||
; $ ffmpeg -i source.mp3 -ss 00:01:27.50 -to 00:01:36.50 -ar 8000 -ac 1 -c:a adpcm_ima_wav -block_size 256 -map_metadata -1 -bitexact out.wav
|
||||
; And/or use a tool such as https://github.com/dbry/adpcm-xq (make sure to set the correct block size, -b8)
|
||||
;
|
||||
; NOTE: for speed reasons this implementation doesn't guard against clipping errors.
|
||||
; if the output sounds distorted, lower the volume of the source waveform to 80% and try again etc.
|
||||
|
||||
|
||||
; IMA-ADPCM file data stream format:
|
||||
@ -40,8 +43,8 @@ adpcm {
|
||||
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
|
||||
32767]
|
||||
|
||||
uword @zp predict ; decoded 16 bit pcm sample for first channel.
|
||||
uword @zp predict_2 ; decoded 16 bit pcm sample for second channel.
|
||||
uword @requirezp predict ; decoded 16 bit pcm sample for first channel.
|
||||
uword @requirezp predict_2 ; decoded 16 bit pcm sample for second channel.
|
||||
ubyte @requirezp index
|
||||
ubyte @requirezp index_2
|
||||
uword @zp pstep
|
||||
@ -76,8 +79,17 @@ adpcm {
|
||||
pstep >>= 1
|
||||
cx16.r0s += pstep
|
||||
if nibble & %1000
|
||||
cx16.r0s = -cx16.r0s
|
||||
predict += cx16.r0s as uword
|
||||
predict -= cx16.r0s
|
||||
else
|
||||
predict += cx16.r0s
|
||||
|
||||
; NOTE: the original C/Python code uses a 32 bits prediction value and clips it to a 16 bit word
|
||||
; but for speed reasons we only work with 16 bit words here all the time (with possible clipping error)
|
||||
; if predicted > 32767:
|
||||
; predicted = 32767
|
||||
; elif predicted < -32767:
|
||||
; predicted = - 32767
|
||||
|
||||
index += t_index[nibble]
|
||||
if_neg ; was: if index & 128
|
||||
index = 0
|
||||
@ -101,8 +113,17 @@ adpcm {
|
||||
pstep_2 >>= 1
|
||||
cx16.r0s += pstep_2
|
||||
if nibble_2 & %1000
|
||||
cx16.r0s = -cx16.r0s
|
||||
predict_2 += cx16.r0s as uword
|
||||
predict_2 -= cx16.r0s
|
||||
else
|
||||
predict_2 += cx16.r0s
|
||||
|
||||
; NOTE: the original C/Python code uses a 32 bits prediction value and clips it to a 16 bit word
|
||||
; but for speed reasons we only work with 16 bit words here all the time (with possible clipping error)
|
||||
; if predicted > 32767:
|
||||
; predicted = 32767
|
||||
; elif predicted < -32767:
|
||||
; predicted = - 32767
|
||||
|
||||
index_2 += t_index[nibble_2]
|
||||
if_neg ; was: if index & 128
|
||||
index_2 = 0
|
||||
|
@ -18,11 +18,11 @@
|
||||
main {
|
||||
|
||||
ubyte adpcm_blocks_left
|
||||
uword @requirezp nibblesptr
|
||||
uword vera_rate_hz
|
||||
ubyte vera_rate
|
||||
ubyte num_adpcm_blocks
|
||||
uword adpcm_size
|
||||
uword @requirezp nibblesptr
|
||||
|
||||
sub start() {
|
||||
if not wavfile.parse_header(&wavdata.wav_data) {
|
||||
@ -45,10 +45,19 @@ main {
|
||||
txt.print("\n\n(b)enchmark or (p)layback? ")
|
||||
|
||||
when cbm.CHRIN() {
|
||||
'b' -> when wavfile.nchannels {
|
||||
1-> benchmark_mono()
|
||||
2-> benchmark_stereo()
|
||||
}
|
||||
'b' -> {
|
||||
cbm.SETTIM(0,0,0)
|
||||
when wavfile.nchannels {
|
||||
1-> {
|
||||
mono.benchmark()
|
||||
decoding_report(1 + 252*2)
|
||||
}
|
||||
2-> {
|
||||
stereo.benchmark()
|
||||
decoding_report(2 + 248*4)
|
||||
}
|
||||
}
|
||||
}
|
||||
'p' -> playback()
|
||||
}
|
||||
}
|
||||
@ -64,127 +73,6 @@ main {
|
||||
num_adpcm_blocks = (adpcm_size / 256) as ubyte ; THE ADPCM DATA NEEDS TO BE ENCODED IN 256-byte BLOCKS !
|
||||
}
|
||||
|
||||
sub benchmark_mono() {
|
||||
nibblesptr = &wavdata.wav_data + wavfile.data_offset
|
||||
|
||||
txt.print("\ndecoding all blocks...\n")
|
||||
cbm.SETTIM(0,0,0)
|
||||
repeat num_adpcm_blocks {
|
||||
adpcm.init(peekw(nibblesptr), @(nibblesptr+2))
|
||||
nibblesptr += 4
|
||||
decode_mono_nibbles()
|
||||
}
|
||||
|
||||
decoding_report(1 + 252*2)
|
||||
}
|
||||
|
||||
sub decode_mono_nibbles() {
|
||||
; slightly unrolled
|
||||
ubyte @zp nibble
|
||||
repeat 252/2 {
|
||||
unroll 2 {
|
||||
nibble = @(nibblesptr)
|
||||
adpcm.decode_nibble(nibble & 15) ; first word
|
||||
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict)
|
||||
cx16.VERA_AUDIO_DATA = msb(adpcm.predict)
|
||||
adpcm.decode_nibble(nibble>>4) ; second word
|
||||
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict)
|
||||
cx16.VERA_AUDIO_DATA = msb(adpcm.predict)
|
||||
nibblesptr++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uword[8] left
|
||||
uword[8] right
|
||||
|
||||
sub benchmark_stereo() {
|
||||
nibblesptr = &wavdata.wav_data + wavfile.data_offset
|
||||
txt.print("\n\ndecoding all blocks...\n")
|
||||
cbm.SETTIM(0,0,0)
|
||||
|
||||
repeat num_adpcm_blocks {
|
||||
|
||||
adpcm.init(peekw(nibblesptr), @(nibblesptr+2))
|
||||
nibblesptr += 4
|
||||
adpcm.init_second(peekw(nibblesptr), @(nibblesptr+2))
|
||||
nibblesptr += 4
|
||||
|
||||
repeat 248/8 {
|
||||
decode_stereo_nibbles()
|
||||
nibblesptr += 8
|
||||
copy_stereo_to_fifo()
|
||||
}
|
||||
}
|
||||
|
||||
decoding_report(2 + 248*4)
|
||||
}
|
||||
|
||||
asmsub copy_stereo_to_fifo() clobbers(A, Y) {
|
||||
%asm {{
|
||||
; copy to vera PSG fifo buffer
|
||||
ldy #0
|
||||
- lda p8_left,y
|
||||
sta cx16.VERA_AUDIO_DATA
|
||||
lda p8_left+1,y
|
||||
sta cx16.VERA_AUDIO_DATA
|
||||
lda p8_right,y
|
||||
sta cx16.VERA_AUDIO_DATA
|
||||
lda p8_right+1,y
|
||||
sta cx16.VERA_AUDIO_DATA
|
||||
iny
|
||||
iny
|
||||
cpy #16
|
||||
bne -
|
||||
}}
|
||||
}
|
||||
|
||||
sub decode_stereo_nibbles() {
|
||||
; decode 4 left channel nibbles
|
||||
ubyte @zp nibble = @(nibblesptr)
|
||||
adpcm.decode_nibble(nibble & 15) ; first word
|
||||
left[0] = adpcm.predict
|
||||
adpcm.decode_nibble(nibble>>4) ; second word
|
||||
left[1] = adpcm.predict
|
||||
nibble = @(nibblesptr+1)
|
||||
adpcm.decode_nibble(nibble & 15) ; first word
|
||||
left[2] = adpcm.predict
|
||||
adpcm.decode_nibble(nibble>>4) ; second word
|
||||
left[3] = adpcm.predict
|
||||
nibble = @(nibblesptr+2)
|
||||
adpcm.decode_nibble(nibble & 15) ; first word
|
||||
left[4] = adpcm.predict
|
||||
adpcm.decode_nibble(nibble>>4) ; second word
|
||||
left[5] = adpcm.predict
|
||||
nibble = @(nibblesptr+3)
|
||||
adpcm.decode_nibble(nibble & 15) ; first word
|
||||
left[6] = adpcm.predict
|
||||
adpcm.decode_nibble(nibble>>4) ; second word
|
||||
left[7] = adpcm.predict
|
||||
|
||||
; decode 4 right channel nibbles
|
||||
nibble = @(nibblesptr+4)
|
||||
adpcm.decode_nibble_second(nibble & 15) ; first word
|
||||
right[0] = adpcm.predict_2
|
||||
adpcm.decode_nibble_second(nibble>>4) ; second word
|
||||
right[1] = adpcm.predict_2
|
||||
nibble = @(nibblesptr+5)
|
||||
adpcm.decode_nibble_second(nibble & 15) ; first word
|
||||
right[2] = adpcm.predict_2
|
||||
adpcm.decode_nibble_second(nibble>>4) ; second word
|
||||
right[3] = adpcm.predict_2
|
||||
nibble = @(nibblesptr+6)
|
||||
adpcm.decode_nibble_second(nibble & 15) ; first word
|
||||
right[4] = adpcm.predict_2
|
||||
adpcm.decode_nibble_second(nibble>>4) ; second word
|
||||
right[5] = adpcm.predict_2
|
||||
nibble = @(nibblesptr+7)
|
||||
adpcm.decode_nibble_second(nibble & 15) ; first word
|
||||
right[6] = adpcm.predict_2
|
||||
adpcm.decode_nibble_second(nibble>>4) ; second word
|
||||
right[7] = adpcm.predict_2
|
||||
}
|
||||
|
||||
sub decoding_report(float pcm_words_per_block) {
|
||||
const float REFRESH_RATE = 25.0e6/(525.0*800) ; Vera VGA refresh rate is not precisely 60 hz!
|
||||
float duration_secs = (cbm.RDTIM16() as float) / REFRESH_RATE
|
||||
@ -212,23 +100,25 @@ main {
|
||||
nibblesptr = &wavdata.wav_data + wavfile.data_offset
|
||||
adpcm_blocks_left = num_adpcm_blocks
|
||||
|
||||
when wavfile.nchannels {
|
||||
1 -> cx16.VERA_AUDIO_CTRL = %10101111 ; mono 16 bit
|
||||
2 -> cx16.VERA_AUDIO_CTRL = %10111111 ; stereo 16 bit
|
||||
}
|
||||
sys.set_irqd()
|
||||
cx16.VERA_AUDIO_RATE = 0 ; halt playback
|
||||
repeat 1024 {
|
||||
cx16.VERA_AUDIO_DATA = 0
|
||||
}
|
||||
|
||||
sys.set_irqd()
|
||||
when wavfile.nchannels {
|
||||
1 -> cx16.CINV = &irq_handler_mono
|
||||
2 -> cx16.CINV = &irq_handler_stereo
|
||||
1 -> {
|
||||
cx16.VERA_AUDIO_CTRL = %10101011 ; mono 16 bit, volume 11
|
||||
cx16.CINV = &mono.irq_handler
|
||||
}
|
||||
2 -> {
|
||||
cx16.VERA_AUDIO_CTRL = %10111011 ; stereo 16 bit, volume 11
|
||||
cx16.CINV = &stereo.irq_handler
|
||||
}
|
||||
}
|
||||
|
||||
cx16.VERA_IEN = %00001000 ; enable AFLOW
|
||||
sys.clear_irqd()
|
||||
|
||||
cx16.VERA_AUDIO_RATE = vera_rate ; start playback
|
||||
|
||||
txt.print("\naudio via irq\n")
|
||||
@ -243,22 +133,48 @@ main {
|
||||
; txt.print("audio off.\n")
|
||||
}
|
||||
|
||||
sub irq_handler_mono() {
|
||||
}
|
||||
|
||||
mono {
|
||||
sub benchmark() {
|
||||
main.nibblesptr = &wavdata.wav_data + wavfile.data_offset
|
||||
txt.print("\ndecoding all blocks...\n")
|
||||
repeat main.num_adpcm_blocks
|
||||
decode_block()
|
||||
}
|
||||
|
||||
sub decode_block() {
|
||||
; refill the fifo buffer with one decoded adpcm block (1010 bytes of pcm data)
|
||||
adpcm.init(peekw(main.nibblesptr), @(main.nibblesptr+2))
|
||||
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict)
|
||||
cx16.VERA_AUDIO_DATA = msb(adpcm.predict)
|
||||
main.nibblesptr += 4
|
||||
ubyte @zp nibble
|
||||
repeat 252/2 {
|
||||
unroll 2 {
|
||||
nibble = @(main.nibblesptr)
|
||||
adpcm.decode_nibble(nibble & 15) ; first word
|
||||
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict)
|
||||
cx16.VERA_AUDIO_DATA = msb(adpcm.predict)
|
||||
adpcm.decode_nibble(nibble>>4) ; second word
|
||||
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict)
|
||||
cx16.VERA_AUDIO_DATA = msb(adpcm.predict)
|
||||
main.nibblesptr++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub irq_handler() {
|
||||
if cx16.VERA_ISR & %00001000 {
|
||||
; AFLOW irq.
|
||||
;; cx16.vpoke(1,$fa0c, $a0) ; paint a screen color
|
||||
|
||||
; refill the fifo buffer with one decoded adpcm block (1010 bytes of pcm data)
|
||||
adpcm.init(peekw(nibblesptr), @(nibblesptr+2))
|
||||
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict)
|
||||
cx16.VERA_AUDIO_DATA = msb(adpcm.predict)
|
||||
nibblesptr += 4
|
||||
decode_mono_nibbles()
|
||||
adpcm_blocks_left--
|
||||
if adpcm_blocks_left==0 {
|
||||
decode_block()
|
||||
main.adpcm_blocks_left--
|
||||
if main.adpcm_blocks_left==0 {
|
||||
; restart adpcm data from the beginning
|
||||
nibblesptr = &wavdata.wav_data + wavfile.data_offset
|
||||
adpcm_blocks_left = num_adpcm_blocks
|
||||
main.nibblesptr = &wavdata.wav_data + wavfile.data_offset
|
||||
main.adpcm_blocks_left = main.num_adpcm_blocks
|
||||
txt.print("end of data, restarting.\n")
|
||||
}
|
||||
|
||||
@ -276,33 +192,108 @@ main {
|
||||
}}
|
||||
}
|
||||
|
||||
sub irq_handler_stereo() {
|
||||
}
|
||||
|
||||
stereo {
|
||||
|
||||
sub benchmark() {
|
||||
main.nibblesptr = &wavdata.wav_data + wavfile.data_offset
|
||||
txt.print("\n\ndecoding all blocks...\n")
|
||||
|
||||
repeat main.num_adpcm_blocks
|
||||
decode_block()
|
||||
}
|
||||
|
||||
sub decode_block() {
|
||||
; refill the fifo buffer with one decoded adpcm block (1010 bytes of pcm data)
|
||||
adpcm.init(peekw(main.nibblesptr), @(main.nibblesptr+2)) ; left channel
|
||||
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict)
|
||||
cx16.VERA_AUDIO_DATA = msb(adpcm.predict)
|
||||
adpcm.init_second(peekw(main.nibblesptr+4), @(main.nibblesptr+6)) ; right channel
|
||||
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict_2)
|
||||
cx16.VERA_AUDIO_DATA = msb(adpcm.predict_2)
|
||||
main.nibblesptr += 8
|
||||
repeat 248/8
|
||||
decode_nibbles_unrolled()
|
||||
}
|
||||
|
||||
sub decode_nibbles_unrolled() {
|
||||
; decode 4 left channel nibbles
|
||||
uword[8] left
|
||||
uword[8] right
|
||||
ubyte @requirezp nibble = @(main.nibblesptr)
|
||||
adpcm.decode_nibble(nibble & 15) ; first word
|
||||
left[0] = adpcm.predict
|
||||
adpcm.decode_nibble(nibble>>4) ; second word
|
||||
left[1] = adpcm.predict
|
||||
nibble = @(main.nibblesptr+1)
|
||||
adpcm.decode_nibble(nibble & 15) ; first word
|
||||
left[2] = adpcm.predict
|
||||
adpcm.decode_nibble(nibble>>4) ; second word
|
||||
left[3] = adpcm.predict
|
||||
nibble = @(main.nibblesptr+2)
|
||||
adpcm.decode_nibble(nibble & 15) ; first word
|
||||
left[4] = adpcm.predict
|
||||
adpcm.decode_nibble(nibble>>4) ; second word
|
||||
left[5] = adpcm.predict
|
||||
nibble = @(main.nibblesptr+3)
|
||||
adpcm.decode_nibble(nibble & 15) ; first word
|
||||
left[6] = adpcm.predict
|
||||
adpcm.decode_nibble(nibble>>4) ; second word
|
||||
left[7] = adpcm.predict
|
||||
|
||||
; decode 4 right channel nibbles
|
||||
nibble = @(main.nibblesptr+4)
|
||||
adpcm.decode_nibble_second(nibble & 15) ; first word
|
||||
right[0] = adpcm.predict_2
|
||||
adpcm.decode_nibble_second(nibble>>4) ; second word
|
||||
right[1] = adpcm.predict_2
|
||||
nibble = @(main.nibblesptr+5)
|
||||
adpcm.decode_nibble_second(nibble & 15) ; first word
|
||||
right[2] = adpcm.predict_2
|
||||
adpcm.decode_nibble_second(nibble>>4) ; second word
|
||||
right[3] = adpcm.predict_2
|
||||
nibble = @(main.nibblesptr+6)
|
||||
adpcm.decode_nibble_second(nibble & 15) ; first word
|
||||
right[4] = adpcm.predict_2
|
||||
adpcm.decode_nibble_second(nibble>>4) ; second word
|
||||
right[5] = adpcm.predict_2
|
||||
nibble = @(main.nibblesptr+7)
|
||||
adpcm.decode_nibble_second(nibble & 15) ; first word
|
||||
right[6] = adpcm.predict_2
|
||||
adpcm.decode_nibble_second(nibble>>4) ; second word
|
||||
right[7] = adpcm.predict_2
|
||||
main.nibblesptr += 8
|
||||
|
||||
%asm {{
|
||||
; copy to vera PSG fifo buffer
|
||||
ldy #0
|
||||
- lda p8_left,y
|
||||
sta cx16.VERA_AUDIO_DATA
|
||||
lda p8_left+1,y
|
||||
sta cx16.VERA_AUDIO_DATA
|
||||
lda p8_right,y
|
||||
sta cx16.VERA_AUDIO_DATA
|
||||
lda p8_right+1,y
|
||||
sta cx16.VERA_AUDIO_DATA
|
||||
iny
|
||||
iny
|
||||
cpy #16
|
||||
bne -
|
||||
}}
|
||||
}
|
||||
|
||||
sub irq_handler() {
|
||||
if cx16.VERA_ISR & %00001000 {
|
||||
; AFLOW irq.
|
||||
;; cx16.vpoke(1,$fa0c, $a0) ; paint a screen color
|
||||
|
||||
; refill the fifo buffer with one decoded adpcm block (1010 bytes of pcm data)
|
||||
; left channel
|
||||
adpcm.init(peekw(nibblesptr), @(nibblesptr+2))
|
||||
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict)
|
||||
cx16.VERA_AUDIO_DATA = msb(adpcm.predict)
|
||||
nibblesptr += 4
|
||||
; right channel
|
||||
adpcm.init_second(peekw(nibblesptr), @(nibblesptr+2))
|
||||
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict_2)
|
||||
cx16.VERA_AUDIO_DATA = msb(adpcm.predict_2)
|
||||
nibblesptr += 4
|
||||
repeat 31 {
|
||||
decode_stereo_nibbles()
|
||||
nibblesptr += 8
|
||||
copy_stereo_to_fifo()
|
||||
}
|
||||
|
||||
adpcm_blocks_left--
|
||||
if adpcm_blocks_left==0 {
|
||||
decode_block()
|
||||
main.adpcm_blocks_left--
|
||||
if main.adpcm_blocks_left==0 {
|
||||
; restart adpcm data from the beginning
|
||||
nibblesptr = &wavdata.wav_data + wavfile.data_offset
|
||||
adpcm_blocks_left = num_adpcm_blocks
|
||||
main.nibblesptr = &wavdata.wav_data + wavfile.data_offset
|
||||
main.adpcm_blocks_left = main.num_adpcm_blocks
|
||||
txt.print("end of data, restarting.\n")
|
||||
}
|
||||
|
||||
|
@ -79,17 +79,17 @@ main {
|
||||
}
|
||||
|
||||
if wavfile.wavefmt==wavfile.WAVE_FORMAT_DVI_ADPCM {
|
||||
if(wavfile.block_align!=256 or wavfile.nchannels!=1) {
|
||||
error("unsupported format!")
|
||||
if(wavfile.block_align!=256) {
|
||||
error("unsupported block alignment!")
|
||||
}
|
||||
}
|
||||
|
||||
txt.print("\ngood file! playback starts!\n")
|
||||
cx16.rombank(0) ; activate kernal bank for faster calls
|
||||
cx16.VERA_AUDIO_RATE = 0 ; halt playback
|
||||
cx16.VERA_AUDIO_CTRL = %10101111 ; mono 16 bit
|
||||
cx16.VERA_AUDIO_CTRL = %10101011 ; mono 16 bit, volume 11
|
||||
if wavfile.nchannels==2
|
||||
cx16.VERA_AUDIO_CTRL = %10111111 ; stereo 16 bit
|
||||
cx16.VERA_AUDIO_CTRL = %10111011 ; stereo 16 bit, volume 11
|
||||
if(wavfile.bits_per_sample==8)
|
||||
cx16.VERA_AUDIO_CTRL &= %11011111 ; set to 8 bit instead
|
||||
repeat 1024
|
||||
@ -103,7 +103,7 @@ main {
|
||||
if diskio.f_open(MUSIC_FILENAME) {
|
||||
uword block_size = 1024
|
||||
if wavfile.wavefmt==wavfile.WAVE_FORMAT_DVI_ADPCM
|
||||
block_size = wavfile.block_align
|
||||
block_size = wavfile.block_align * 2 ; read 2 adpcm blocks at a time (512 bytes)
|
||||
void diskio.f_read(buffer, wavfile.data_offset) ; skip to actual sample data start
|
||||
void diskio.f_read(buffer, block_size) ; preload buffer
|
||||
cx16.VERA_AUDIO_RATE = vera_rate ; start playback
|
||||
@ -144,6 +144,7 @@ main {
|
||||
interrupt {
|
||||
|
||||
bool aflow_semaphore
|
||||
uword @requirezp nibblesptr
|
||||
|
||||
asmsub wait_and_clear_aflow_semaphore() {
|
||||
%asm {{
|
||||
@ -159,8 +160,17 @@ interrupt {
|
||||
if cx16.VERA_ISR & %00001000 {
|
||||
; AFLOW irq occurred, refill buffer
|
||||
aflow_semaphore = 0
|
||||
if wavfile.wavefmt==wavfile.WAVE_FORMAT_DVI_ADPCM
|
||||
adpcm_block()
|
||||
if wavfile.wavefmt==wavfile.WAVE_FORMAT_DVI_ADPCM {
|
||||
nibblesptr = main.start.buffer
|
||||
if wavfile.nchannels==2 {
|
||||
adpcm_block_stereo()
|
||||
adpcm_block_stereo()
|
||||
}
|
||||
else {
|
||||
adpcm_block_mono()
|
||||
adpcm_block_mono()
|
||||
}
|
||||
}
|
||||
else if wavfile.bits_per_sample==16
|
||||
uncompressed_block_16()
|
||||
else
|
||||
@ -235,9 +245,8 @@ interrupt {
|
||||
; }
|
||||
}
|
||||
|
||||
sub adpcm_block() {
|
||||
sub adpcm_block_mono() {
|
||||
; refill the fifo buffer with one decoded adpcm block (1010 bytes of pcm data)
|
||||
uword @requirezp nibblesptr = main.start.buffer
|
||||
adpcm.init(peekw(nibblesptr), @(nibblesptr+2))
|
||||
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict)
|
||||
cx16.VERA_AUDIO_DATA = msb(adpcm.predict)
|
||||
@ -256,4 +265,85 @@ interrupt {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub adpcm_block_stereo() {
|
||||
; refill the fifo buffer with one decoded adpcm block (1010 bytes of pcm data)
|
||||
adpcm.init(peekw(nibblesptr), @(nibblesptr+2)) ; left channel
|
||||
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict)
|
||||
cx16.VERA_AUDIO_DATA = msb(adpcm.predict)
|
||||
adpcm.init_second(peekw(nibblesptr+4), @(nibblesptr+6)) ; right channel
|
||||
cx16.VERA_AUDIO_DATA = lsb(adpcm.predict_2)
|
||||
cx16.VERA_AUDIO_DATA = msb(adpcm.predict_2)
|
||||
nibblesptr += 8
|
||||
repeat 248/8
|
||||
decode_nibbles_unrolled()
|
||||
}
|
||||
|
||||
|
||||
sub decode_nibbles_unrolled() {
|
||||
; decode 4 left channel nibbles
|
||||
uword[8] left
|
||||
uword[8] right
|
||||
ubyte @requirezp nibble = @(nibblesptr)
|
||||
adpcm.decode_nibble(nibble & 15) ; first word
|
||||
left[0] = adpcm.predict
|
||||
adpcm.decode_nibble(nibble>>4) ; second word
|
||||
left[1] = adpcm.predict
|
||||
nibble = @(nibblesptr+1)
|
||||
adpcm.decode_nibble(nibble & 15) ; first word
|
||||
left[2] = adpcm.predict
|
||||
adpcm.decode_nibble(nibble>>4) ; second word
|
||||
left[3] = adpcm.predict
|
||||
nibble = @(nibblesptr+2)
|
||||
adpcm.decode_nibble(nibble & 15) ; first word
|
||||
left[4] = adpcm.predict
|
||||
adpcm.decode_nibble(nibble>>4) ; second word
|
||||
left[5] = adpcm.predict
|
||||
nibble = @(nibblesptr+3)
|
||||
adpcm.decode_nibble(nibble & 15) ; first word
|
||||
left[6] = adpcm.predict
|
||||
adpcm.decode_nibble(nibble>>4) ; second word
|
||||
left[7] = adpcm.predict
|
||||
|
||||
; decode 4 right channel nibbles
|
||||
nibble = @(nibblesptr+4)
|
||||
adpcm.decode_nibble_second(nibble & 15) ; first word
|
||||
right[0] = adpcm.predict_2
|
||||
adpcm.decode_nibble_second(nibble>>4) ; second word
|
||||
right[1] = adpcm.predict_2
|
||||
nibble = @(nibblesptr+5)
|
||||
adpcm.decode_nibble_second(nibble & 15) ; first word
|
||||
right[2] = adpcm.predict_2
|
||||
adpcm.decode_nibble_second(nibble>>4) ; second word
|
||||
right[3] = adpcm.predict_2
|
||||
nibble = @(nibblesptr+6)
|
||||
adpcm.decode_nibble_second(nibble & 15) ; first word
|
||||
right[4] = adpcm.predict_2
|
||||
adpcm.decode_nibble_second(nibble>>4) ; second word
|
||||
right[5] = adpcm.predict_2
|
||||
nibble = @(nibblesptr+7)
|
||||
adpcm.decode_nibble_second(nibble & 15) ; first word
|
||||
right[6] = adpcm.predict_2
|
||||
adpcm.decode_nibble_second(nibble>>4) ; second word
|
||||
right[7] = adpcm.predict_2
|
||||
nibblesptr += 8
|
||||
|
||||
%asm {{
|
||||
; copy to vera PSG fifo buffer
|
||||
ldy #0
|
||||
- lda p8_left,y
|
||||
sta cx16.VERA_AUDIO_DATA
|
||||
lda p8_left+1,y
|
||||
sta cx16.VERA_AUDIO_DATA
|
||||
lda p8_right,y
|
||||
sta cx16.VERA_AUDIO_DATA
|
||||
lda p8_right+1,y
|
||||
sta cx16.VERA_AUDIO_DATA
|
||||
iny
|
||||
iny
|
||||
cpy #16
|
||||
bne -
|
||||
}}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,4 +5,4 @@ org.gradle.daemon=true
|
||||
kotlin.code.style=official
|
||||
javaVersion=11
|
||||
kotlinVersion=1.9.10
|
||||
version=9.5-SNAPSHOT
|
||||
version=9.5
|
||||
|
Loading…
Reference in New Issue
Block a user