256 lines
10 KiB
Tal
256 lines
10 KiB
Tal
( music.tal )
|
|
( )
|
|
( this is a simple tracker that can play music correctly using )
|
|
( varvara's audio devices. )
|
|
( )
|
|
( varvara doesn't guarantee that notes started at the "same" )
|
|
( time will end at the same time; there is no built-in clock )
|
|
( or synchronization, so relying on independent audio callbacks )
|
|
( will cause channels to de-sync. )
|
|
( )
|
|
( the tracker here races the audio callbacks against each other. )
|
|
( the first callback at a given time t will trigger all the notes )
|
|
( that should happen at time t. it will also update the internal )
|
|
( state of all channels to avoid duplicate plays later. )
|
|
( )
|
|
( to keep it simple there are some simplifying assumptions: )
|
|
( )
|
|
( 1. the music will loop forever )
|
|
( 2. all note durations will be multiples of a single "pulse duration" )
|
|
( 3. the tempo/pulse duration won't change during playback )
|
|
( 4. the longest note won't be held more than 255x the shortest )
|
|
( )
|
|
( each track is specified as a sequence of notes; each note is )
|
|
( a pitch/count pair. a rest, or silence, uses pitch 00. )
|
|
( count must be >= 1. )
|
|
( )
|
|
( each channel can loop independently; there is no need to keep their )
|
|
( lengths in sync with each other. )
|
|
|
|
|30 @Audio1 [ &vect $2 &pos $2 &out $1 &dur $2 &pad $1 &adsr $2 &len $2 &addr $2 &vol $1 &pitch $1 ]
|
|
|40 @Audio2 [ &vect $2 &pos $2 &out $1 &dur $2 &pad $1 &adsr $2 &len $2 &addr $2 &vol $1 &pitch $1 ]
|
|
|50 @Audio3 [ &vect $2 &pos $2 &out $1 &dur $2 &pad $1 &adsr $2 &len $2 &addr $2 &vol $1 &pitch $1 ]
|
|
|60 @Audio4 [ &vect $2 &pos $2 &out $1 &dur $2 &pad $1 &adsr $2 &len $2 &addr $2 &vol $1 &pitch $1 ]
|
|
|
|
( structure layout for channels )
|
|
|00 @ch $2 &start $2 &limit $2 &next-t $2
|
|
|
|
|0000
|
|
@dur $2 ( dur: the length of the shortest possible note )
|
|
@time $2 ( the current timestamp, in milliseconds )
|
|
@events $8 ( timeline: see .ch above )
|
|
@ch-1 $8 ( channel 1: see .ch above )
|
|
@ch-2 $8 ( channel 2: see .ch above )
|
|
@ch-3 $8 ( channel 3: see .ch above )
|
|
@ch-4 $8 ( channel 4: see .ch above )
|
|
@ch-end ( end of channels )
|
|
|
|
|0100
|
|
#0080 .dur STZ2 ( use 128 ms for 16th notes )
|
|
#0000 .time STZ2 ( start at t=0 )
|
|
|
|
( set up audio callbacks )
|
|
;on-audio-1 .Audio1/vect DEO2
|
|
;on-audio-2 .Audio2/vect DEO2
|
|
;on-audio-3 .Audio3/vect DEO2
|
|
;on-audio-4 .Audio4/vect DEO2
|
|
|
|
( adsr sample slen vol device )
|
|
#0231 ;square #0008 #77 .Audio1 setup-audio
|
|
#0231 ;saw #0010 #34 .Audio2 setup-audio
|
|
#0231 ;triangle #0004 #64 .Audio3 setup-audio
|
|
#011f ;noise #0200 #44 .Audio4 setup-audio
|
|
|
|
( set up the channel data structures )
|
|
;timeline ;track-1 setup-events
|
|
;track-1 ;track-2 .ch-1 setup-ch
|
|
;track-2 ;track-3 .ch-2 setup-ch
|
|
;track-3 ;track-4 .ch-3 setup-ch
|
|
;track-4 ;track-end .ch-4 setup-ch
|
|
BRK
|
|
|
|
( play a note and a duration on the given device )
|
|
@play-data ( note^ ms* dev^ -> )
|
|
STHk #05 ADD DEO2 ( note^ [dev^] ; dev/duration<-ms )
|
|
STHr #0f ADD DEO JMP2r ( ; dev/pitch<-note )
|
|
|
|
( convert pulse count into duration in milliseconds )
|
|
@count-to-ms ( count^ -> ms* )
|
|
#00 SWP .dur LDZ2 MUL2 JMP2r
|
|
|
|
( given a channel, find its device )
|
|
@ch-to-dev ( ch^ -> dev^ )
|
|
.ch-1 SUB #08 DIV #40 SFT #30 ADD JMP2r
|
|
|
|
( is ch ready to play the next note? )
|
|
@ch-is-ready ( ch^ -> bool^ )
|
|
.ch/next-t ADD LDZ2 .time LDZ2 EQU2 JMP2r
|
|
|
|
( increment the channel's position, looping back if needed )
|
|
@inc-ch ( ch^ -> )
|
|
STHk LDZ2 INC2 INC2 ( pos+2* [ch^] )
|
|
STHkr .ch/limit ADD LDZ2 ( pos+2* limit* [ch^] )
|
|
OVR2 GTH2 ?&ready ( pos+2* [ch^] ; is limit > pos+2 ? )
|
|
POP2 STHkr .ch/start ADD LDZ2 ( start* [ch^] )
|
|
&ready STHr STZ2 JMP2r ( ; ch<-inc-pos )
|
|
|
|
( if ready, play the channel )
|
|
@play-ch ( ch^ -> )
|
|
STHk ch-is-ready ?{ POPr JMP2r } ( )
|
|
STHkr LDZ2 LDA2 count-to-ms ( note^ ms* [ch^] )
|
|
DUP2 .time LDZ2 ADD2 ( note^ ms* next* [ch^] )
|
|
STHkr .ch/next-t ADD STZ2 ( note^ ms* [ch^] ; ch/next-t<-next )
|
|
STHkr ch-to-dev play-data ( [ch^] ; play note)
|
|
STHr !inc-ch ( ; increment pos )
|
|
|
|
@setup-events ( addr* limit* -> )
|
|
SWP2 .events STZ2k ( limit* addr* t^ ; t<-addr )
|
|
STHk INC INC STZ2 ( limit* addr* [t^] ; t/start<-addr )
|
|
STHr .ch/limit ADD STZ2 ( [ch^] ; ch/limit<-limit )
|
|
!advance-events
|
|
|
|
( set up the channel, including playing its first note )
|
|
@setup-ch ( addr* limit* ch^ -> )
|
|
STH SWP2 STHkr STZ2k ( limit* addr* ch^ [ch^] ; ch<-addr )
|
|
INC INC STZ2 ( limit* [ch^] ; ch/start<-addr )
|
|
STHkr .ch/limit ADD STZ2 ( [ch^] ; ch/limit<-limit )
|
|
STHr !play-ch
|
|
|
|
( set up the audio parameters )
|
|
@setup-audio ( adsr* sample* slen* vol^ dev^ -> )
|
|
STHk #0e ORA DEO ( [dev^] ; <-vol )
|
|
STHkr #0a ORA DEO2 ( [dev^] ; <-slen )
|
|
STHkr #0c ORA DEO2 ( [dev^] ; <-sample )
|
|
STHr #08 ORA DEO2 ( ; <-adsr )
|
|
JMP2r
|
|
|
|
@change-pulse ( ms* -> )
|
|
DUP2 .ch-1 update-ch-pulse
|
|
DUP2 .ch-2 update-ch-pulse
|
|
DUP2 .ch-3 update-ch-pulse
|
|
DUP2 .ch-4 update-ch-pulse
|
|
.dur STZ2 JMP2r
|
|
|
|
@update-ch-pulse ( ms* ch^ -> )
|
|
.ch/next-t ADD STHk LDZ2 ( ms* next-ms* [next-t^] )
|
|
.dur LDZ2 DIV2 ( ms* next-p* [next-t^] )
|
|
MUL2 STHr STZ2 JMP2r ( )
|
|
|
|
@on-audio-1 .ch-1 !on-audio
|
|
@on-audio-2 .ch-2 !on-audio
|
|
@on-audio-3 .ch-3 !on-audio
|
|
@on-audio-4 .ch-4 !on-audio
|
|
|
|
@on-audio ( ch^ -> BRK )
|
|
.ch/next-t ADD LDZ2 .time LDZ2 NEQ2k ?&neq
|
|
POP2 POP2 BRK
|
|
&neq POP2 .time STZ2
|
|
advance-events
|
|
.ch-1 play-ch
|
|
.ch-2 play-ch
|
|
.ch-3 play-ch
|
|
.ch-4 play-ch
|
|
BRK
|
|
|
|
@inc-events ( -> )
|
|
.events ( t^ )
|
|
STHk LDZ2 INC2 INC2 INC2 ( pos+3* [t^] )
|
|
STHkr .ch/limit ADD LDZ2 ( pos+3* limit* [t^] )
|
|
OVR2 GTH2 ?&ready ( pos+3* [t^] ; is limit > pos+2 ? )
|
|
POP2 STHkr .ch/start ADD LDZ2 ( start* [ch^] )
|
|
&ready STHr STZ2 JMP2r ( ; t<-inc-pos )
|
|
|
|
@advance-events ( -> )
|
|
.events ( t^ )
|
|
STHk .ch/next-t ADD LDZ2 .time LDZ2 GTH2 ?&skip ( [t^] ; t/next-t > time? )
|
|
STHkr LDZ2 DUP2 LDA2 JSR2 ( addr* [t^] )
|
|
INC2 INC2 LDA count-to-ms ( ms* [t^] )
|
|
.time LDZ2 ADD2 ( time+ms* [t^] )
|
|
STHr .ch/next-t ADD STZ2 ( ; t/next-t<-time+ms )
|
|
!inc-events
|
|
&skip POPr JMP2r
|
|
|
|
( this is the actual fun part: the note data for each track )
|
|
@timeline =slowdown 08
|
|
@track-1 2401 2b02 3001 2402 2e01 3001
|
|
@track-2 0004 3c02 3e01 3f01
|
|
@track-3 4301 4301 4402 4301 4301 4401 4601
|
|
@track-4 1004 3004 0103 0101 3002 3001 3001
|
|
@track-end
|
|
|
|
@slowdown ( -> )
|
|
.dur LDZ2 #0008 ADD2 !change-pulse
|
|
|
|
@saw ff ee dd cc bb aa 99 88 77 66 55 44 33 22 11 00
|
|
|
|
@triangle 80 ff 80 00
|
|
|
|
@square ff ff ff ff ff 00 00 00
|
|
|
|
( 512 random bytes to create noise )
|
|
@noise
|
|
da 4c 58 30 58 a7 d6 7a fd b1 60 2a 8a de 22 2f
|
|
fb 52 8a f3 58 62 37 3b 0a fb 85 2b da 24 d9 a1
|
|
88 fa 79 d8 3b 40 0c 58 54 40 14 92 50 44 d2 68
|
|
f2 8b b8 50 d1 70 03 74 1e 61 90 96 e6 1a eb b3
|
|
09 6b 65 d8 f2 fb af 36 bb b6 9d 90 9b 3e c2 1a
|
|
a0 de 1f 20 89 1b 85 53 b9 c9 55 ae f5 c9 4b 0a
|
|
5f 11 40 ca 6e b1 b9 35 3e 99 eb 46 6a e0 1a 4f
|
|
9a 6e 31 28 cb b2 1f 4a 17 ee 3b 05 4a 6f 6f 56
|
|
28 b3 90 07 65 f6 25 ed 4a 43 4b 99 8f 1a 48 19
|
|
aa 3c 64 d4 e5 80 c4 c3 ce 52 5f 12 ad 34 78 5c
|
|
bb 3a aa 26 d4 ed 0d 81 ee 35 1b c9 17 7f 7c ec
|
|
c3 84 2a 0d 1e 9a 74 2c 42 ce 1e 6d 5f e9 7d a5
|
|
b2 14 55 5b 57 51 38 1d c2 ad 50 b6 6f 71 b3 a2
|
|
7e ae b6 fc 77 7e c6 51 ef ae e7 f5 8f 23 2d 1a
|
|
78 b1 fd e3 f4 a6 50 bb 48 91 00 95 2f 8a 3e 64
|
|
ab 32 27 03 a1 7a c4 11 30 b1 3e 24 39 b5 22 0f
|
|
5f a1 6e 2b 9e e4 43 07 b6 74 c8 f7 17 93 c7 d0
|
|
1f 25 e1 80 12 5b c9 10 53 a5 4e 3f 8c 91 c8 c7
|
|
51 74 38 99 6c c3 e7 0e 7b 7d 25 bc e7 10 75 d0
|
|
b0 ed 33 33 20 fb 4c 5d 1b 23 3b 8a bd ae 31 32
|
|
17 0f 38 9b 79 da 8f da af 54 47 8e 68 77 b5 25
|
|
47 c9 be 87 3d f1 3d 35 a1 d5 dd 84 ff b8 73 d5
|
|
1f 75 e5 b7 2f f3 17 a5 06 39 17 af 4d e5 b8 a1
|
|
e7 93 a0 f9 9f 95 b7 f6 d3 b2 04 75 2b 27 f9 86
|
|
4b 0a 61 57 77 11 d3 31 91 a9 9e 8f 26 d7 9b fa
|
|
7c 36 4e 47 a5 53 ea 86 a6 63 b3 ce 84 03 d1 3c
|
|
e6 0b 89 b7 51 dd 33 86 e2 11 6e b8 b4 e0 08 b4
|
|
68 8c fe d4 18 d3 ae d4 8e 90 fc 52 f3 8c e9 2c
|
|
92 95 44 a9 39 22 20 45 69 fc 30 5e 68 1b 1c b0
|
|
cc 76 9e 04 d0 24 7f ea 0a d2 f4 d8 96 98 27 dc
|
|
3e 8e 95 5d 78 12 6a 9b b2 f5 f4 a9 52 88 05 8f
|
|
38 50 6c f4 bb d9 0f ea f4 de 9d f6 55 fc 99 3a
|
|
49 f2 0f 99 e8 f5 3d e9 37 69 fb 92 34 1b 69 46
|
|
dd 5b 17 7b 0e 9b 38 9f d7 a3 14 03 ba e7 b0 e1
|
|
8a 5a 82 72 ea bf 8e 85 8f d0 06 bc 3b 2b 01 d7
|
|
a2 e2 74 ca 28 78 e0 38 59 e2 b8 dc 39 6c a7 f3
|
|
3a a1 86 82 4b 1c 78 56 09 14 59 a6 55 39 5e 51
|
|
89 07 81 c7 b6 11 d6 26 0b 2f 17 a5 10 af 73 03
|
|
6c 68 22 04 32 58 b4 e5 c6 f2 e1 6b 99 d5 bb 4c
|
|
2b e1 93 ad 3b 1d 62 e2 f1 6a fa 13 92 3c de 8b
|
|
0e 1c 4f 8d ea 20 ba c2 9a 65 b1 b1 29 f0 ce 6f
|
|
49 3d 06 f8 18 0b 0d 55 d4 ec 95 d3 fa cb 10 9b
|
|
bd 61 d7 3f 07 5b 47 cc bb ae b2 df db f5 20 43
|
|
2a 11 54 11 54 05 ff 33 44 0a 1b 92 26 87 f8 58
|
|
56 a4 84 2e c4 4f 86 04 b8 d6 bb 0c 82 23 56 8a
|
|
d8 77 2f fc 27 30 e2 5f 19 3e ff a5 b8 ca 4e 87
|
|
dc b2 e9 6c d8 8f a9 7a be ad 85 6c a2 76 9f 32
|
|
e8 d5 b3 de b9 3a ce 23 36 4a de 7a e6 47 40 7c
|
|
b3 8c 2c 10 b1 3f c9 81 74 79 0a 4d 5e 73 01 24
|
|
ed 17 d3 e8 83 7e 54 bf d9 47 59 f0 0c 60 f7 41
|
|
67 52 c2 2a f1 93 c3 ac 00 00 67 87 3a c8 62 d3
|
|
33 20 7c 36 d4 88 57 cc fa a5 8a 69 f7 f9 06 7b
|
|
56 a6 c9 8f db a0 c0 07 94 0c a2 96 e1 26 7c 49
|
|
18 c1 18 4e d1 76 87 e3 43 9a 4b d0 fc cf 11 5e
|
|
f8 83 0c 52 05 57 8b 3c 32 84 3b 88 14 75 dc f7
|
|
42 ec 6d 5f e9 11 8d 33 76 56 ae 46 f1 99 e9 1d
|
|
34 df 4d 7d c6 57 fe 82 fd 9b 97 8e 89 74 ce 5a
|
|
fa 85 74 38 b1 3f f5 72 69 87 93 d8 c2 c9 e0 b2
|
|
ce e1 de b2 15 f9 21 c4 37 70 1c 4b f4 5e 8c dc
|
|
d9 fc f3 13 50 41 b8 8e 90 0b 40 bf a8 57 b8 e8
|
|
25 b4 c0 1c 99 96 bd 8b 64 40 6f 42 cd f9 22 f2
|
|
9f 80 92 c7 64 73 d9 0d 10 ef 86 c1 9a be aa 12
|
|
04 1f 78 e0 20 c4 f1 36 5c cc 7c 3f 53 07 8a 94
|
|
fb 97 62 78 fe 6b 3b 3d a1 02 f1 5d e4 ca fe d1
|