187 lines
5.8 KiB
Tal
187 lines
5.8 KiB
Tal
( mp3.tal )
|
|
|
|
( commands are ended by newlines: )
|
|
( )
|
|
( help show all these commands )
|
|
( load FILE load FILE and start playing )
|
|
( loadpaused FILE load FILE without playing )
|
|
( pause pause, or unpause, playback )
|
|
( stop stops playback, unloads file )
|
|
( seek # seeks to sample # )
|
|
( seek +N | seek -N seeks forward, or back, N samples )
|
|
( seek +Ns | seek -Ns seeks forward, or back, N seconds )
|
|
( jump # jumps to MPEG frame # )
|
|
( jump +N | jump -N jumps forward, or back, N frames )
|
|
( jump +Ns | jump -Ns jumps forward, or back, N seconds )
|
|
( volume P set volume to P percent, 0-100 )
|
|
( mute mute playback )
|
|
( unmute unmute playback )
|
|
( tag print all ID3 data; seeking back may remove tag data )
|
|
|
|
@Console [
|
|
|10 &vector $2
|
|
|12 &read $1
|
|
( 13 - 14 padding )
|
|
|15 &live $1
|
|
|15 &exit $1
|
|
|17 &type $1
|
|
|18 &write $1
|
|
|19 &error $1
|
|
( 1a - 1b padding )
|
|
|1c &addr $2
|
|
|1e &mode $1
|
|
|1f &exec $1
|
|
]
|
|
|
|
|0100
|
|
( initialize buffer )
|
|
;buffer ;buffer/pos STA2
|
|
|
|
( run mpg123 )
|
|
;on-console .Console/vector DEO2
|
|
;program .Console/addr DEO2 ( cmd addr )
|
|
#03 .Console/mode DEO ( cmd mode )
|
|
#01 .Console/exec DEO ( exec )
|
|
|
|
;cmd1 print
|
|
;cmd2 print
|
|
|
|
BRK
|
|
|
|
@printerr ( s* -> )
|
|
LDAk ?{ #0a .Console/error DEO POP2 JMP2r }
|
|
LDAk .Console/error DEO INC2 !printerr
|
|
|
|
@print ( s* -> )
|
|
LDAk ?{ POP2 JMP2r }
|
|
LDAk .Console/write DEO INC2 !print
|
|
|
|
@on-console ( -> brk )
|
|
.Console/type DEI #01 EQU ?{ BRK } ( )
|
|
.Console/read DEI #0a EQU ?&newline ( )
|
|
;buffer/pos LDA2k STH2k ( pos* buf* [buf*] )
|
|
.Console/read DEI STH2r STA ( pos* buf ; buf<-c )
|
|
INC2 SWP2 STA2 BRK ( ; pos<-buf+1 )
|
|
&newline ( )
|
|
#00 ;buffer/pos LDA2 STA on-line ( ; buf<-0, run on-line )
|
|
;buffer ;buffer/pos STA2 BRK ( )
|
|
|
|
|
|
( called when a newline is reached )
|
|
( buffer is guaranteed to be null-terminated )
|
|
( newline is implied but not included )
|
|
@on-line ( -> )
|
|
;buffer LDAk LIT "@ EQU ?{ POP2 JMP2r }
|
|
INC2k LDA LIT "F EQU ?on-frame
|
|
( INC2k LDA LIT "H EQU ?on-help )
|
|
( INC2k LDA LIT "I EQU ?on-id3 )
|
|
( INC2k LDA LIT "P EQU ?on-paused )
|
|
( INC2k LDA LIT "R EQU ?on-revision )
|
|
( INC2k LDA LIT "S EQU ?on-status )
|
|
( INC2k LDA LIT "T EQU ?on-tag )
|
|
!printerr
|
|
|
|
( === START NEW CODE === )
|
|
|
|
( e.g. "@F 184 8713 4.81 227.60" )
|
|
( seen when playing )
|
|
( the fields here are: )
|
|
( @F <curr-frame> <total-frames> <curr-secs> <remaining-secs> )
|
|
( )
|
|
( debugging output on stderr is: <curr-time> <rem-time> <width> )
|
|
@on-frame ( buf0* -> )
|
|
#0003 ADD2 ( buf1* ; skip "@F " )
|
|
#20 find-next INC2 ( buf2* ; skip curr frame )
|
|
#20 find-next INC2 ( buf3* ; skip next frame )
|
|
parse-dec STH2 INC2 ( buf4* [curr*] ; parse curr time )
|
|
LDAk LIT "5 LTH ?{ INC2r } ( buf4* [curr*] ; maybe round curr )
|
|
#20 find-next INC2 ( buf5* [curr*] ; skip fractional part )
|
|
parse-dec STH2 INC2 ( buf4* [curr* rem*] ; parse total time )
|
|
LDAk LIT "5 LTH ?{ INC2r } ( buf4* [curr* rem*] ; maybe round rem )
|
|
POP2 STH2r STH2r SWP2 ( curr* rem* )
|
|
OVR2 emit #2019 DEO ( curr* rem* ; print curr )
|
|
DUP2 emit #2019 DEO ( curr* rem* ; print rem )
|
|
OVR2 ADD2 SWP2 ( total* curr* )
|
|
calc-width emit #0a19 DEO ( width* )
|
|
JMP2r ( width* )
|
|
|
|
( emit a short in hexadecimal notation. )
|
|
@emit ( n* -> )
|
|
SWP /byte
|
|
&byte DUP #04 SFT /hex #0f AND ( >> )
|
|
&hex #30 ADD DUP #39 GTH #27 MUL ADD .Console/error DEO JMP2r
|
|
|
|
( returns value between 0000 and 00d0 )
|
|
( )
|
|
( the basic idea is that we shift both values left until )
|
|
( the total is small enough that it can be multiplied by )
|
|
( 0xd0, i.e. 208. we take some care to round correctly, )
|
|
( which helps give a smoother transition between values. )
|
|
@calc-width ( total* curr* -> width* )
|
|
STH2 ( total* [curr*] )
|
|
DUP2 #013c LTH2 ?&ready
|
|
&scale DUP2 #0277 LTH2 ?&almost #01 SFT2 LITr 01 SFT2r !&scale
|
|
&almost INC2 #01 SFT2 INC2r LITr 01 SFT2r
|
|
&ready LIT2r 00d0 MUL2r STH2r SWP2 DIV2 JMP2r
|
|
|
|
( find the next occurrence of a byte in the given string. )
|
|
( )
|
|
( returns the position of the character found. )
|
|
@find-next ( buf* c^ -> buf+i* )
|
|
STH &loop LDAk STHkr EQU ?{ INC2 !&loop } POPr JMP2r
|
|
|
|
( parse a decimal number as a short )
|
|
( )
|
|
( returns an updated buffer position and the parsed short )
|
|
@parse-dec ( buf* -> buf+i* x* )
|
|
LIT2r 000a LIT2r 0000 ( buf* [10* acc*] )
|
|
&loop LDAk LIT "0 SUB ( buf+i* n^ [10* acc*] )
|
|
DUP #09 GTH ?&done ( buf+i* n^ [10* acc*] )
|
|
OVR2r MUL2r #00 SWP ( buf+i* n* [10* 10acc*] )
|
|
STH2 ADD2r INC2 !&loop ( buf+i+1* [10* 10acc+n*] )
|
|
&done POP STH2r POP2r JMP2r ( buf+i* acc* )
|
|
|
|
( === END NEW CODE === )
|
|
|
|
( e.g. "@H HELP/H: command listing (LONG/SHORT forms), command case insensitve" )
|
|
( seen in response to the "help" command )
|
|
@on-help ( buf* -> )
|
|
POP2r JMP2r
|
|
|
|
( e.g. "@I ID3v2.artist:Chipzel" )
|
|
( seen when loading a track )
|
|
@on-id3 ( buf* -> )
|
|
POP2 JMP2r
|
|
|
|
( e.g. "@P 0" or "@P 1" )
|
|
( seen when pausing or unpausing )
|
|
@on-paused ( buf* -> )
|
|
POP2 JMP2r
|
|
|
|
( e.g. "@R MPG123 (ThOr) v10" )
|
|
( seen on start up )
|
|
@on-revision ( buf* -> )
|
|
POP2 JMP2r
|
|
|
|
( e.g. "@S 1.0 3 44100 Joint-Stereo 0 1044 2 0 0 0 320 0 1" )
|
|
( seen when playback starts )
|
|
@on-status ( buf* -> )
|
|
POP2 JMP2r
|
|
|
|
( e.g. "@T ID3v2.TPE1:" )
|
|
( seen in response to the "tag" command for extended tag info )
|
|
@on-tag ( buf* -> )
|
|
POP2 JMP2r
|
|
|
|
@program
|
|
"mpg123 20 "-R 00
|
|
|
|
@cmd1
|
|
"loadpaused 20 "tokyo-skies.mp3 0a 00
|
|
|
|
@cmd2
|
|
"pause 0a 00
|
|
|
|
|
|
@buffer $200 &pos $2 ( input buffer )
|