mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
the adpcm example can now read wav files directly (so no need anymore to extract the binary frame data from them)
This commit is contained in:
parent
ec64a68a71
commit
2fad52d684
@ -3,7 +3,6 @@ TODO
|
|||||||
|
|
||||||
For next release
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- make the adpcm example read wav files directly (so no need anymore to extract the binary frame data from them)
|
|
||||||
- duplicate diskio for cx16 (get rid of cx16diskio, just copy diskio and tweak everything) + documentation
|
- duplicate diskio for cx16 (get rid of cx16diskio, just copy diskio and tweak everything) + documentation
|
||||||
- get f_seek_w working like in the BASIC program - this needs the changes to diskio.f_open to use suffixes ,p,m
|
- get f_seek_w working like in the BASIC program - this needs the changes to diskio.f_open to use suffixes ,p,m
|
||||||
- attempt to fix the expression codegen bug with reused temp vars (github #89)
|
- attempt to fix the expression codegen bug with reused temp vars (github #89)
|
||||||
@ -27,6 +26,7 @@ Future Things and Ideas
|
|||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
Compiler:
|
Compiler:
|
||||||
|
|
||||||
|
- add a mechanism to allocate variables into golden ram ($0400-$07ff on x16, $c000-$.... on c64 , take care of evalstack)
|
||||||
- ir: mechanism to determine for chunks which registers are getting input values from "outside"
|
- ir: mechanism to determine for chunks which registers are getting input values from "outside"
|
||||||
- ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk)
|
- ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk)
|
||||||
- ir: peephole opt: renumber registers in chunks to start with 1 again every time (but keep entry values in mind!)
|
- ir: peephole opt: renumber registers in chunks to start with 1 again every time (but keep entry values in mind!)
|
||||||
|
Binary file not shown.
BIN
examples/cx16/pcmaudio/adpcm-mono.wav
Normal file
BIN
examples/cx16/pcmaudio/adpcm-mono.wav
Normal file
Binary file not shown.
@ -16,24 +16,25 @@
|
|||||||
; HOW TO CREATE SUCH IMA-ADPCM ENCODED AUDIO? Use sox or ffmpeg:
|
; HOW TO CREATE SUCH IMA-ADPCM ENCODED AUDIO? Use sox or ffmpeg:
|
||||||
; $ sox --guard source.mp3 -r 8000 -c 1 -e ima-adpcm out.wav trim 01:27.50 00:09
|
; $ 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
|
; $ 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
|
||||||
;
|
; Or use a tool such as https://github.com/dbry/adpcm-xq .
|
||||||
; THEN use a tool to read the raw audio frame data from that resulting out.wav and save it as 'adpcm-mono.bin'.
|
|
||||||
;
|
;
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
ubyte num_adpcm_blocks
|
|
||||||
ubyte adpcm_blocks_left
|
ubyte adpcm_blocks_left
|
||||||
uword @requirezp nibblesptr
|
uword @requirezp nibblesptr
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
uword adpcm_size = &audiodata.adpcm_data_end - &audiodata.adpcm_data
|
wavfile.parse()
|
||||||
num_adpcm_blocks = (adpcm_size / 256) as ubyte ; NOTE: THE ADPCM DATA NEEDS TO BE ENCODED IN 256-byte BLOCKS !
|
|
||||||
|
|
||||||
txt.print_uw(adpcm_size)
|
txt.print_uw(wavfile.adpcm_size)
|
||||||
txt.print(" adpcm data size = ")
|
txt.print(" adpcm data size = ")
|
||||||
txt.print_ub(num_adpcm_blocks)
|
txt.print_ub(wavfile.num_adpcm_blocks)
|
||||||
txt.print(" blocks\n(b)enchmark or (p)layback? ")
|
txt.print(" blocks\nsamplerate = ")
|
||||||
|
txt.print_uw(wavfile.sample_rate)
|
||||||
|
txt.print(" vera rate = ")
|
||||||
|
txt.print_uw(wavfile.vera_rate_hz)
|
||||||
|
txt.print("\n(b)enchmark or (p)layback? ")
|
||||||
|
|
||||||
when c64.CHRIN() {
|
when c64.CHRIN() {
|
||||||
'b' -> benchmark()
|
'b' -> benchmark()
|
||||||
@ -42,11 +43,11 @@ main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub benchmark() {
|
sub benchmark() {
|
||||||
nibblesptr = &audiodata.adpcm_data
|
nibblesptr = wavfile.adpcm_data_ptr
|
||||||
|
|
||||||
txt.print("\ndecoding all blocks...\n")
|
txt.print("\ndecoding all blocks...\n")
|
||||||
c64.SETTIM(0,0,0)
|
c64.SETTIM(0,0,0)
|
||||||
repeat num_adpcm_blocks {
|
repeat wavfile.num_adpcm_blocks {
|
||||||
adpcm.init(peekw(nibblesptr), @(nibblesptr+2))
|
adpcm.init(peekw(nibblesptr), @(nibblesptr+2))
|
||||||
nibblesptr += 4
|
nibblesptr += 4
|
||||||
repeat 252 {
|
repeat 252 {
|
||||||
@ -57,14 +58,14 @@ main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
float duration_secs = (c64.RDTIM16() as float) / 60.0
|
float duration_secs = (c64.RDTIM16() as float) / 60.0
|
||||||
float words_per_second = 505.0 * (num_adpcm_blocks as float) / duration_secs
|
float words_per_second = 505.0 * (wavfile.num_adpcm_blocks as float) / duration_secs
|
||||||
txt.print_uw(words_per_second as uword)
|
txt.print_uw(words_per_second as uword)
|
||||||
txt.print(" words/sec\n")
|
txt.print(" words/sec\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
sub playback() {
|
sub playback() {
|
||||||
nibblesptr = &audiodata.adpcm_data
|
nibblesptr = wavfile.adpcm_data_ptr
|
||||||
adpcm_blocks_left = num_adpcm_blocks
|
adpcm_blocks_left = wavfile.num_adpcm_blocks
|
||||||
|
|
||||||
cx16.VERA_AUDIO_CTRL = %10101111 ; mono 16 bit
|
cx16.VERA_AUDIO_CTRL = %10101111 ; mono 16 bit
|
||||||
cx16.VERA_AUDIO_RATE = 0 ; halt playback
|
cx16.VERA_AUDIO_RATE = 0 ; halt playback
|
||||||
@ -77,12 +78,9 @@ main {
|
|||||||
cx16.VERA_IEN = %00001000 ; enable AFLOW
|
cx16.VERA_IEN = %00001000 ; enable AFLOW
|
||||||
sys.clear_irqd()
|
sys.clear_irqd()
|
||||||
|
|
||||||
cx16.VERA_AUDIO_RATE = 21 ; start playback at ~8000 hz
|
cx16.VERA_AUDIO_RATE = wavfile.vera_rate ; start playback
|
||||||
|
|
||||||
float rate = (cx16.VERA_AUDIO_RATE as float) * (25e6 / 65536.0)
|
txt.print("\naudio via irq\n")
|
||||||
txt.print("\naudio via irq at ")
|
|
||||||
txt.print_uw(rate as uword)
|
|
||||||
txt.print(" hz mono\n")
|
|
||||||
|
|
||||||
repeat {
|
repeat {
|
||||||
; audio will play via the IRQ.
|
; audio will play via the IRQ.
|
||||||
@ -117,8 +115,8 @@ main {
|
|||||||
adpcm_blocks_left--
|
adpcm_blocks_left--
|
||||||
if adpcm_blocks_left==0 {
|
if adpcm_blocks_left==0 {
|
||||||
; restart adpcm data from the beginning
|
; restart adpcm data from the beginning
|
||||||
nibblesptr = &audiodata.adpcm_data
|
nibblesptr = wavfile.adpcm_data_ptr
|
||||||
adpcm_blocks_left = num_adpcm_blocks
|
adpcm_blocks_left = wavfile.num_adpcm_blocks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,10 +193,66 @@ adpcm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
audiodata {
|
wavfile {
|
||||||
|
|
||||||
|
const ubyte WAVE_FORMAT_PCM = $1
|
||||||
|
const ubyte WAVE_FORMAT_ADPCM = $2
|
||||||
|
const ubyte WAVE_FORMAT_IEEE_FLOAT = $3
|
||||||
|
const ubyte WAVE_FORMAT_ALAW = $6
|
||||||
|
const ubyte WAVE_FORMAT_MULAW = $7
|
||||||
|
const ubyte WAVE_FORMAT_DVI_ADPCM = $11
|
||||||
|
|
||||||
|
uword sample_rate
|
||||||
|
uword vera_rate_hz
|
||||||
|
ubyte vera_rate
|
||||||
|
uword adpcm_size
|
||||||
|
uword adpcm_data_ptr
|
||||||
|
ubyte num_adpcm_blocks
|
||||||
|
|
||||||
|
sub parse() {
|
||||||
|
; "RIFF" , filesize (int32) , "WAVE", "fmt ", fmtsize (int32)
|
||||||
|
; we assume file sizes are <= 64Kb so don't have to worry about the upper 16 bits
|
||||||
|
uword @zp header = &wavdata.wav_data
|
||||||
|
if header[0]!=iso:'R' or header[1]!=iso:'I' or header[2]!=iso:'F' or header[3]!=iso:'F'
|
||||||
|
or header[8]!=iso:'W' or header[9]!=iso:'A' or header[10]!=iso:'V' or header[11]!=iso:'E'
|
||||||
|
or header[12]!=iso:'f' or header[13]!=iso:'m' or header[14]!=iso:'t' or header[15]!=iso:' ' {
|
||||||
|
txt.print("not a valid wav file\n")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
; uword filesize = peekw(header+4)
|
||||||
|
uword chunksize = peekw(header+16)
|
||||||
|
uword wavefmt = peekw(header+20)
|
||||||
|
uword nchannels = peekw(header+22)
|
||||||
|
sample_rate = peekw(header+24) ; we assume sample rate <= 65535 so we can ignore the upper word
|
||||||
|
uword block_align = peekw(header+32)
|
||||||
|
|
||||||
|
if block_align!=256 or nchannels!=1 or wavefmt!=WAVE_FORMAT_DVI_ADPCM {
|
||||||
|
txt.print("invalid wav specs\n")
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
; skip chunks until we reach the 'data' chunk
|
||||||
|
header += chunksize + 20
|
||||||
|
repeat {
|
||||||
|
chunksize = peekw(header+4) ; assume chunk size never exceeds 64kb so ignore upper word
|
||||||
|
if header[0]==iso:'d' and header[1]==iso:'a' and header[2]==iso:'t' and header[3]==iso:'a'
|
||||||
|
break
|
||||||
|
header += 8 + chunksize
|
||||||
|
}
|
||||||
|
adpcm_data_ptr = header + 8
|
||||||
|
adpcm_size = chunksize
|
||||||
|
num_adpcm_blocks = (chunksize / 256) as ubyte ; NOTE: THE ADPCM DATA NEEDS TO BE ENCODED IN 256-byte BLOCKS !
|
||||||
|
|
||||||
|
const float vera_freq_factor = 25e6 / 65536.0
|
||||||
|
vera_rate = (sample_rate as float / vera_freq_factor) + 1.0 as ubyte
|
||||||
|
vera_rate_hz = (vera_rate as float) * vera_freq_factor as uword
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wavdata {
|
||||||
%option align_page
|
%option align_page
|
||||||
adpcm_data:
|
wav_data:
|
||||||
%asmbinary "adpcm-mono.bin"
|
%asmbinary "adpcm-mono.wav"
|
||||||
adpcm_data_end:
|
wav_data_end:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user