From dab32fea09aa92e80334651cced9cbbbb7a9fd8a Mon Sep 17 00:00:00 2001 From: d6 Date: Tue, 25 Apr 2023 23:17:13 -0400 Subject: [PATCH] basic WAV support --- wave.tal | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 wave.tal diff --git a/wave.tal b/wave.tal new file mode 100644 index 0000000..607b36a --- /dev/null +++ b/wave.tal @@ -0,0 +1,137 @@ +( wave.tal ) +( ) +( currently reads PCM data ) + +( WAV format (number byte order is LE) ) +( ) +( BYTES EXAMPLE BYTES DESCRIPTION ) +( 0-3 "RIFF" 52 49 46 46 riff string ) +( 4-7 10248036 64 5f 9c 00 overall file size - 8 bytes ) +( 8-11 "WAVE" 57 41 56 45 wave string ) +( 12-15 "fmt " 66 6d 74 20 fmt string ) +( 16-19 1 01 00 00 00 length of format data? [???] ) +( 20-21 1 01 00 type of data, 1 is PCM ) +( 22-23 1 01 00 number of channels, 1 is mono ) +( 24-27 44100 44 ac 00 00 sample-rate, 44100 is 44.1 kHz ) +( 28-31 44100 44 ac 00 00 [rate * channels * bits/channel]/8 ) +( 32-33 1 01 00 [bitrate*channels]/8 ) +( 34-35 8 08 00 bitrate, i.e. bits per sample ) +( 36-39 "data" 64 61 74 61 data string ) +( 40-43 10248000 40 5f 9c 00 data size in bytes ) +( 44+ PCM data, little endian byte order ) +( ) +( more complex WAV files may have other structures. ) +( ) +( we can validate whether the WAV is a format we can handle ) +( by comparing byes 4-7 with bytes 40-43. if the former is ) +( 36 bytes larger than the latter, the file has a standard ) +( structure which we can easily parse. ) +( ) +( s16 -> u8: hi-byte + 0x80 ) +( stereo -> mono, take second sample ) + +|30 @Audio0 [ &vec $2 &pos $2 &out $1 &pad $3 &adsr $2 &len $2 &addr $2 &vol $1 &pitch $1 ] +|40 @Audio1 [ &vec $2 &pos $2 &out $1 &pad $3 &adsr $2 &len $2 &addr $2 &vol $1 &pitch $1 ] +|50 @Audio2 [ &vec $2 &pos $2 &out $1 &pad $3 &adsr $2 &len $2 &addr $2 &vol $1 &pitch $1 ] +|60 @Audio3 [ &vec $2 &pos $2 &out $1 &pad $3 &adsr $2 &len $2 &addr $2 &vol $1 &pitch $1 ] +|a0 @File [ &vec $2 &ok $2 &stat $2 &del $1 &append $1 &name $2 &len $2 &r $2 &w $2 ] + +|0000 + @done $1 + +|0100 + ;path .File/name DEO2 + parse + #2000 .File/len DEO2 + #2000 ;len0 STA2 #2000 ;buf0 zero-buf-u8 + #2000 ;len1 STA2 #2000 ;buf1 zero-buf-u8 + !play0 + +@zero-buf-u8 ( len* buf* -> ) + STH2k ADD2 STH2 SWP2r ( [limit=buf+len* buf*] ) + #80 ( 80^ [limit* buf*] ) + &loop ( 80^ [limit* pos*] ) + DUP STH2kr STA ( 80^ [limit* pos*] ; pos<-80 ) + INC2r GTH2kr STHr ?&loop ( 80^ [limit* pos+1*] ) + POP POP2r POP2r JMP2r ( ) + +( data created using: ) +( lame --decode tokyo-skies.mp3 # produced tokyo-skies.wav ) +( sox tokyo-skies.wav -c 1 -e unsigned-integer -b 8 tokyo-skies-mono-u8.wav ) +( sox tokyo-skies-mono-u8.wav tokyo-skies.raw ) + +( @path "tokyo-skies.raw 00 ) +@path "tokyo-skies-mono-u8.wav 00 +( @path "tokyo-skies.wav 00 ) + +( TODO: actually parse ) +@parse ( -> ) + #002c .File/len DEO2 + ;buf0 .File/r DEO2 + .File/ok DEI2 + #002c EQU2 ?&ok #0000 DIV &ok JMP2r + +@reload-mono-u8 ( l-addr* b-addr* -> ) + .done LDZ ?&skip ( l-addr* b-addr* ) + .File/r DEO2 ( l-addr* ) + .File/ok DEI2 ( l-addr* read* ) + DUP2 ROT2 STA2 ( read* ; l-addr<-read ) + #2000 EQU2 ?&end ( ; if we read 0x2000 we are not done ) + #01 .done STZ ( ; done<-1 ) + &end JMP2r ( ) + &skip POP2 POP2 JMP2r ( ) + +@reload-stereo-s16 ( l-addr* b-addr* -> ) + .done LDZ ?&skip ( l-addr* b-addr* ) + SWP2 ( b-addr* l-addr* ) + ;scratch .File/r DEO2 ( b-addr* l-addr* ) + .File/ok DEI2 ( b-addr* l-addr* read* ) + DUP2 #02 SFT2 ROT2 STA2 ( b-addr* read* ; l-addr<-read/4 ) + DUP2 #2000 EQU2 ?&end ( b-addr* read* ; if we read 0x2000 we are not done ) + #01 .done STZ ( b-addr* read* ; done<-1 ) + &end ( b-addr* read* ) + SWP2 STH2 ;scratch ( read* scratch* [b-addr*] ) + DUP2 ROT2 ADD2 SWP2 ( limit=scratch+read* scratch* [b-addr*] ) + INC2 ( limit* scratch+3* [b-addr*] ) + &loop ( limit* pos* [bpos*] ) + s16-to-u8 ( limit* pos+4* sample^ [bpos*] ) + STH2kr STA ( limit* pos* [bpos*] ; bpos<-sample ) + INC2r ( limit* pos+4* [bpos+1*] ) + GTH2k ?&loop ( limit* pos+4* [bpos+1*] ) + POP2r ( limit* pos+4* ) + &skip POP2 POP2 JMP2r ( ) + +@s16-to-u8 ( pos* -> pos+4* sample^ ) + LDAk #80 ADD #00 SWP STH2 + INC2 INC2 + LDAk #80 ADD #00 SWP STH2 + ADD2r LITr 01 SFT2r NIPr + INC2 INC2 + STHr JMP2r + +@play0 ( -> ) ;play1 ;len0 ;buf0 !play +@play1 ( -> ) ;play0 ;len1 ;buf1 !play + +@play ( next* l-addr* b-addr* -> ) + OVR2 LDA2 ORAk ?&nonzero ( next* l-addr* b-addr* n* ) + POP2 POP2 POP2 POP2 ( ; clear stack ) + #010f BRK ( ; exit ) + &nonzero ( next* l-addr b-addr* n* ) + OVR2 output ( next* l-addr b-addr* ; play buf1 ) + reload-mono-u8 ( next* ; load more data ) +( reload-stereo-s16 ) ( next* ; load more data ) + .Audio0/vec DEO2 ( ; Audio0/vec<-next ) + BRK ( ) + +@output ( len* addr* -> ) + .Audio0/addr DEO2 ( ; <- write buf addr ) + .Audio0/len DEO2 ( ; <- write len ) + #0000 .Audio0/adsr DEO2 ( ; <- write ignore envelope ) + #ff .Audio0/vol DEO ( ; <- play 100% volume ) + #bc .Audio0/pitch DEO ( ; <- play standard sample once ) + JMP2r + +@len0 $2 @buf0 $2000 +@len1 $2 @buf1 $2000 + +@scratch $2000