Implemented sample-based synth for APU
This commit is contained in:
parent
38a9be86c2
commit
d892f29ea1
|
@ -21,7 +21,7 @@
|
|||
@knob [ &x $2 &y $2 &value $1 ]
|
||||
@head [ &pos $1 ]
|
||||
@track [ &active $1 &ch1 $20 &ch2 $20 &ch3 $20 &ch4 $20 ]
|
||||
@adsr [ &ch1a $1 &ch1d $1 &ch1s $1 &ch1r $1 &ch2a $1 &ch2d $1 &ch2s $1 &ch2r $1 &ch3a $1 &ch3d $1 &ch3s $1 &ch3r $1 &ch4a $1 &ch4d $1 &ch4s $1 &ch4r $1 ]
|
||||
@adsr [ &ch1 $2 &ch2 $2 &ch3 $2 &ch4 $2 ]
|
||||
@volume [ &ch1 $1 &ch2 $1 &ch3 $1 &ch4 $1 ]
|
||||
|
||||
( devices )
|
||||
|
@ -29,7 +29,7 @@
|
|||
|00 @System [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ]
|
||||
|10 @Console [ &vector $2 &pad $6 &char $1 &byte $1 &short $2 &string $2 ]
|
||||
|20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &color $1 ]
|
||||
|30 @Audio [ &wave $2 &envelope $2 &pad $4 &volume $1 &pitch $1 &play $1 &value $2 &delay $2 &finish $1 ]
|
||||
|30 @Audio [ &pad $8 &adsr $2 &len $2 &addr $2 &volume $1 &pitch $1 ]
|
||||
|40 @Controller [ &vector $2 &button $1 &key $1 ]
|
||||
|60 @Mouse [ &vector $2 &x $2 &y $2 &state $1 &chord $1 ]
|
||||
|70 @File [ &vector $2 &success $2 &offset $2 &pad $2 &name $2 &length $2 &load $2 &save $2 ]
|
||||
|
@ -37,6 +37,7 @@
|
|||
( vectors )
|
||||
|
||||
|0100
|
||||
@noise-wave
|
||||
|
||||
( theme ) #e0fa .System/r DEO2 #30fa .System/g DEO2 #30fa .System/b DEO2
|
||||
( vectors ) ;on-screen .Screen/vector DEO2
|
||||
|
@ -55,10 +56,10 @@
|
|||
.trkframe/x2 PEK2 .ctlframe/x2 POK2 .chnframe/y2 PEK2 .ctlframe/y2 POK2
|
||||
|
||||
( default settings )
|
||||
;adsr-envelope .Audio/envelope DEO2
|
||||
#00 .adsr/ch1a POK #40 .adsr/ch1d POK #80 .adsr/ch1s POK #c0 .adsr/ch1r POK #88 .volume/ch1 POK
|
||||
#10 .adsr/ch2a POK #50 .adsr/ch2d POK #90 .adsr/ch2s POK #d0 .adsr/ch2r POK #88 .volume/ch2 POK
|
||||
#20 .adsr/ch3a POK #60 .adsr/ch3d POK #a0 .adsr/ch3s POK #e0 .adsr/ch3r POK #88 .volume/ch3 POK
|
||||
#048c .adsr/ch1 POK2 #88 .volume/ch1 POK
|
||||
#159d .adsr/ch2 POK2 #88 .volume/ch2 POK
|
||||
#26ae .adsr/ch3 POK2 #88 .volume/ch3 POK
|
||||
#260e .adsr/ch4 POK2 #88 .volume/ch4 POK
|
||||
|
||||
.volume/ch3 PEK .Audio/volume DEO
|
||||
|
||||
|
@ -120,9 +121,9 @@ BRK
|
|||
|
||||
@play ( pitch -- )
|
||||
|
||||
#80 ORA .Audio/pitch DEO
|
||||
;triangle-wave .Audio/wave DEO2
|
||||
.track/active PEK .Audio/play DEO
|
||||
;triangle-wave .Audio/addr DEO2
|
||||
;triangle-wave/end ;triangle-wave SUB2 #0001 SFT2 .Audio/len DEO2
|
||||
.Audio/pitch DEO
|
||||
|
||||
RTN
|
||||
|
||||
|
@ -154,21 +155,21 @@ BRK
|
|||
|
||||
.Mouse/x DEI2 .ctlframe/x1 PEK2 SUB2 8- 8/ SWP POP #02 DIV
|
||||
DUP #00 NEQ ,&no-a JNZ
|
||||
;adsr #00 .track/active PEK #04 MUL ADD2 GET
|
||||
.adsr .track/active PEK #02 MUL ADD PEK
|
||||
#10 .Mouse/state DEI #10 EQU #e0 MUL ADD ADD
|
||||
;adsr #00 .track/active PEK #04 MUL ADD2 PUT &no-a
|
||||
.adsr .track/active PEK #02 MUL ADD POK &no-a
|
||||
DUP #01 NEQ ,&no-d JNZ
|
||||
;adsr #00 .track/active PEK #04 MUL ADD2 #0001 ADD2 GET
|
||||
#10 .Mouse/state DEI #10 EQU #e0 MUL ADD ADD
|
||||
;adsr #00 .track/active PEK #04 MUL ADD2 #0001 ADD2 PUT &no-d
|
||||
.adsr .track/active PEK #02 MUL ADD PEK
|
||||
DUP #f0 AND STH #01 .Mouse/state DEI #10 EQU #0e MUL ADD ADD #0f AND STHr ADD
|
||||
.adsr .track/active PEK #02 MUL ADD POK &no-d
|
||||
DUP #02 NEQ ,&no-s JNZ
|
||||
;adsr #00 .track/active PEK #04 MUL ADD2 #0002 ADD2 GET
|
||||
.adsr .track/active PEK #02 MUL ADD #01 ADD PEK
|
||||
#10 .Mouse/state DEI #10 EQU #e0 MUL ADD ADD
|
||||
;adsr #00 .track/active PEK #04 MUL ADD2 #0002 ADD2 PUT &no-s
|
||||
.adsr .track/active PEK #02 MUL ADD #01 ADD POK &no-s
|
||||
DUP #03 NEQ ,&no-r JNZ
|
||||
;adsr #00 .track/active PEK #04 MUL ADD2 #0003 ADD2 GET
|
||||
#10 .Mouse/state DEI #10 EQU #e0 MUL ADD ADD
|
||||
;adsr #00 .track/active PEK #04 MUL ADD2 #0003 ADD2 PUT &no-r
|
||||
.adsr .track/active PEK #02 MUL ADD #01 ADD PEK
|
||||
DUP #f0 AND STH #01 .Mouse/state DEI #10 EQU #0e MUL ADD ADD #0f AND STHr ADD
|
||||
.adsr .track/active PEK #02 MUL ADD #01 ADD POK &no-r
|
||||
DUP #05 NEQ ,&no-left JNZ
|
||||
;volume #00 .track/active PEK ADD2 GET
|
||||
#10 .Mouse/state DEI #10 EQU #e0 MUL ADD ADD
|
||||
|
@ -190,30 +191,44 @@ BRK
|
|||
DUP #ff NEQ ,&skip1 JNZ
|
||||
POP ,&listen2 JMP
|
||||
&skip1
|
||||
#00 SWP ;notes ADD2 GET #80 ORA .Audio/pitch DEO
|
||||
.adsr/ch1 PEK2 .Audio/adsr DEO2
|
||||
.volume/ch1 PEK .Audio/volume DEO
|
||||
;square-wave .Audio/wave DEO2
|
||||
#00 .Audio/play DEO
|
||||
;square-wave .Audio/addr DEO2
|
||||
;square-wave/end ;square-wave SUB2 #0001 SFT2 .Audio/len DEO2
|
||||
#00 SWP ;notes ADD2 GET .Audio/pitch DEO
|
||||
&listen2
|
||||
;track/ch2 #00 .head/pos PEK #08 DIV ADD2 GET
|
||||
#01 SUB
|
||||
DUP #ff NEQ ,&skip2 JNZ
|
||||
POP ,&listen3 JMP
|
||||
&skip2
|
||||
#00 SWP ;notes ADD2 GET #80 ORA .Audio/pitch DEO
|
||||
.adsr/ch2 PEK2 .Audio/adsr DEO2
|
||||
.volume/ch2 PEK .Audio/volume DEO
|
||||
;square-wave .Audio/wave DEO2
|
||||
#01 .Audio/play DEO
|
||||
;triangle-wave .Audio/addr DEO2
|
||||
;triangle-wave/end ;triangle-wave SUB2 #0001 SFT2 .Audio/len DEO2
|
||||
#00 SWP ;notes ADD2 GET .Audio/pitch DEO
|
||||
&listen3
|
||||
;track/ch3 #00 .head/pos PEK #08 DIV ADD2 GET
|
||||
#01 SUB
|
||||
DUP #ff NEQ ,&skip3 JNZ
|
||||
POP ,&end JMP
|
||||
POP ,&listen4 JMP
|
||||
&skip3
|
||||
#00 SWP ;notes ADD2 GET #80 ORA .Audio/pitch DEO
|
||||
.adsr/ch3 PEK2 .Audio/adsr DEO2
|
||||
.volume/ch3 PEK .Audio/volume DEO
|
||||
;triangle-wave .Audio/wave DEO2
|
||||
#02 .Audio/play DEO
|
||||
;sine-wave .Audio/addr DEO2
|
||||
;sine-wave/end ;sine-wave SUB2 #0001 SFT2 .Audio/len DEO2
|
||||
#00 SWP ;notes ADD2 GET .Audio/pitch DEO
|
||||
&listen4
|
||||
;track/ch4 #00 .head/pos PEK #08 DIV ADD2 GET
|
||||
#01 SUB
|
||||
DUP #ff NEQ ,&skip4 JNZ
|
||||
POP ,&end JMP
|
||||
&skip4
|
||||
#0000 .Audio/adsr DEO2
|
||||
.volume/ch4 PEK .Audio/volume DEO
|
||||
;noise-wave .Audio/addr DEO2
|
||||
;noise-wave-end ;noise-wave SUB2 #0001 SFT2 .Audio/len DEO2
|
||||
#00 SWP ;notes ADD2 GET #80 ORA .Audio/pitch DEO
|
||||
&end
|
||||
|
||||
RTN
|
||||
|
@ -319,14 +334,14 @@ RTN
|
|||
.trkframe/y1 PEK2 #0038 ADD2 ;draw-octave JSR2
|
||||
.trkframe/x1 PEK2 #0028 SUB2 .Screen/x DEO2
|
||||
.trkframe/y1 PEK2 #0030 ADD2 .Screen/y DEO2
|
||||
;font_hex #0028 ADD2 .Screen/addr DEO2
|
||||
;font_hex #0020 ADD2 .Screen/addr DEO2
|
||||
#23 .Screen/color DEO
|
||||
.trkframe/x1 PEK2 #0030 SUB2 .Screen/x DEO2
|
||||
;font_hex #0060 ADD2 .Screen/addr DEO2
|
||||
#23 .Screen/color DEO
|
||||
.trkframe/x1 PEK2 #0028 SUB2 .Screen/x DEO2
|
||||
.trkframe/y1 PEK2 #0068 ADD2 .Screen/y DEO2
|
||||
;font_hex #0020 ADD2 .Screen/addr DEO2
|
||||
;font_hex #0018 ADD2 .Screen/addr DEO2
|
||||
#23 .Screen/color DEO
|
||||
.trkframe/x1 PEK2 #0030 SUB2 .Screen/x DEO2
|
||||
;font_hex #0060 ADD2 .Screen/addr DEO2
|
||||
|
@ -342,8 +357,11 @@ RTN
|
|||
RTN
|
||||
|
||||
@draw-knob ( x* y* value -- )
|
||||
|
||||
.track/active PEK #03 EQU ;&blank JNZ2
|
||||
|
||||
&force
|
||||
( load ) .knob/value POK .knob/y POK2 .knob/x POK2
|
||||
|
||||
.knob/x PEK2 .Screen/x DEO2
|
||||
.knob/y PEK2 .Screen/y DEO2 ;knob_icns .Screen/addr DEO2 #21 .Screen/color DEO
|
||||
.knob/x PEK2 8+ .Screen/x DEO2 ;knob_icns 8+ .Screen/addr DEO2 #21 .Screen/color DEO
|
||||
|
@ -360,31 +378,45 @@ RTN
|
|||
|
||||
RTN
|
||||
|
||||
&blank
|
||||
|
||||
( load ) .knob/value POK .knob/y POK2 .knob/x POK2
|
||||
|
||||
.knob/x PEK2 .Screen/x DEO2
|
||||
.knob/y PEK2 .Screen/y DEO2 #20 .Screen/color DEO
|
||||
.knob/x PEK2 8+ .Screen/x DEO2 #20 .Screen/color DEO
|
||||
.knob/y PEK2 8+ .Screen/y DEO2 #20 .Screen/color DEO
|
||||
.knob/x PEK2 .Screen/x DEO2 #20 .Screen/color DEO
|
||||
.knob/x PEK2 #0004 ADD2 .Screen/x DEO2
|
||||
.knob/y PEK2 #0010 ADD2 .Screen/y DEO2
|
||||
#20 .Screen/color DEO
|
||||
RTN
|
||||
|
||||
@draw-controls ( -- )
|
||||
|
||||
.ctlframe/x1 PEK2 .ctlframe/y1 PEK2 .ctlframe/x2 PEK2 .ctlframe/y2 PEK2 #01 ;line-rect JSR2
|
||||
( env )
|
||||
.ctlframe/x1 PEK2 8+ .ctlframe/y1 PEK2 8+ #22 ;env_txt ;draw-label JSR2
|
||||
.ctlframe/x1 PEK2 8+ .ctlframe/y1 PEK2 #0010 ADD2
|
||||
;adsr #00 .track/active PEK #04 MUL ADD2 GET #04 SFT
|
||||
.adsr .track/active PEK #02 MUL ADD PEK #04 SFT
|
||||
;draw-knob JSR2
|
||||
.ctlframe/x1 PEK2 #0018 ADD2 .ctlframe/y1 PEK2 #0010 ADD2
|
||||
;adsr #00 .track/active PEK #04 MUL ADD2 #0001 ADD2 GET #04 SFT
|
||||
.adsr .track/active PEK #02 MUL ADD PEK #0f AND
|
||||
;draw-knob JSR2
|
||||
.ctlframe/x1 PEK2 #0028 ADD2 .ctlframe/y1 PEK2 #0010 ADD2
|
||||
;adsr #00 .track/active PEK #04 MUL ADD2 #0002 ADD2 GET #04 SFT
|
||||
.adsr .track/active PEK #02 MUL ADD #01 ADD PEK #04 SFT
|
||||
;draw-knob JSR2
|
||||
.ctlframe/x1 PEK2 #0038 ADD2 .ctlframe/y1 PEK2 #0010 ADD2
|
||||
;adsr #00 .track/active PEK #04 MUL ADD2 #0003 ADD2 GET #04 SFT
|
||||
.adsr .track/active PEK #02 MUL ADD #01 ADD PEK #0f AND
|
||||
;draw-knob JSR2
|
||||
( vol )
|
||||
.ctlframe/x1 PEK2 #0058 ADD2 .ctlframe/y1 PEK2 8+ #22 ;vol_txt ;draw-label JSR2
|
||||
.ctlframe/x1 PEK2 #0058 ADD2 .ctlframe/y1 PEK2 #0010 ADD2
|
||||
;volume #00 .track/active PEK ADD2 GET #04 SFT
|
||||
;draw-knob JSR2
|
||||
;draw-knob/force JSR2
|
||||
.ctlframe/x1 PEK2 #0068 ADD2 .ctlframe/y1 PEK2 #0010 ADD2
|
||||
;volume #00 .track/active PEK ADD2 GET #0f AND
|
||||
;draw-knob JSR2
|
||||
;draw-knob/force JSR2
|
||||
|
||||
RTN
|
||||
|
||||
|
@ -469,31 +501,10 @@ RTN
|
|||
|
||||
RTN
|
||||
|
||||
@adsr-envelope ( -- )
|
||||
#ff ;adsr #00 .Audio/play DEI #04 MUL ADD2 GET SOUND
|
||||
#80 ;adsr #00 .Audio/play DEI #04 MUL ADD2 #0001 ADD2 GET SOUND
|
||||
#80 ;adsr #00 .Audio/play DEI #04 MUL ADD2 #0002 ADD2 GET SOUND
|
||||
#00 ;adsr #00 .Audio/play DEI #04 MUL ADD2 #0003 ADD2 GET SOUND
|
||||
SOUND_FINISH
|
||||
BRK
|
||||
|
||||
@square-wave ( -- )
|
||||
#a800 SOUND
|
||||
#a880 SOUND
|
||||
#5800 SOUND
|
||||
#5880 SOUND
|
||||
BRK
|
||||
|
||||
@triangle-wave ( -- )
|
||||
#ff40 SOUND
|
||||
#0080 SOUND
|
||||
#8040 SOUND
|
||||
BRK
|
||||
|
||||
@ch1_txt [ "CHN0 00 ]
|
||||
@ch2_txt [ "CHN1 00 ]
|
||||
@ch3_txt [ "CHN2 00 ]
|
||||
@ch4_txt [ "---- 00 ]
|
||||
@ch1_txt [ "SQR 00 ]
|
||||
@ch2_txt [ "TRI 00 ]
|
||||
@ch3_txt [ "SINE 00 ]
|
||||
@ch4_txt [ "DRUM 00 ]
|
||||
@env_txt [ "Envelope 00 ]
|
||||
@vol_txt [ "Volume 00 ]
|
||||
|
||||
|
@ -588,4 +599,62 @@ RTN
|
|||
0010 103c 1010 0c00 0000 4444 4444 3800 0000 4444 2828 1000 0000 4454 5454 2800
|
||||
0000 4428 1028 4400 0000 4444 443c 0438 0000 7c08 1020 7c00 000c 0810 1008 0c00
|
||||
0008 0808 0808 0800 0030 1008 0810 3000 0000 0032 4c00 0000 3c42 99a1 a199 423c
|
||||
]
|
||||
]
|
||||
|
||||
@square-wave
|
||||
a800 5800
|
||||
&end
|
||||
|
||||
@triangle-wave
|
||||
8000 81ff 83ff 85ff 87ff 89ff 8bff 8dff 8fff 91ff 93ff 95ff 97ff
|
||||
99ff 9bff 9dff 9fff a1ff a3ff a5ff a7ff a9ff abff adff afff b1ff
|
||||
b3ff b5ff b7ff b9ff bbff bdff bfff c1ff c3ff c5ff c7ff c9ff cbff
|
||||
cdff cfff d1ff d3ff d5ff d7ff d9ff dbff ddff dfff e1ff e3ff e5ff
|
||||
e7ff e9ff ebff edff efff f1ff f3ff f5ff f7ff f9ff fbff fdff ffff
|
||||
fdff fbff f9ff f7ff f5ff f3ff f1ff efff edff ebff e9ff e7ff e5ff
|
||||
e3ff e1ff dfff ddff dbff d9ff d7ff d5ff d3ff d1ff cfff cdff cbff
|
||||
c9ff c7ff c5ff c3ff c1ff bfff bdff bbff b9ff b7ff b5ff b3ff b1ff
|
||||
afff adff abff a9ff a7ff a5ff a3ff a1ff 9fff 9dff 9bff 99ff 97ff
|
||||
95ff 93ff 91ff 8fff 8dff 8bff 89ff 87ff 85ff 83ff 81ff 8000 7e00
|
||||
7c00 7a00 7800 7600 7400 7200 7000 6e00 6c00 6a00 6800 6600 6400
|
||||
6200 6000 5e00 5c00 5a00 5800 5600 5400 5200 5000 4e00 4c00 4a00
|
||||
4800 4600 4400 4200 4000 3e00 3c00 3a00 3800 3600 3400 3200 3000
|
||||
2e00 2c00 2a00 2800 2600 2400 2200 2000 1e00 1c00 1a00 1800 1600
|
||||
1400 1200 1000 0e00 0c00 0a00 0800 0600 0400 0200 0001 0200 0400
|
||||
0600 0800 0a00 0c00 0e00 1000 1200 1400 1600 1800 1a00 1c00 1e00
|
||||
2000 2200 2400 2600 2800 2a00 2c00 2e00 3000 3200 3400 3600 3800
|
||||
3a00 3c00 3e00 4000 4200 4400 4600 4800 4a00 4c00 4e00 5000 5200
|
||||
5400 5600 5800 5a00 5c00 5e00 6000 6200 6400 6600 6800 6a00 6c00
|
||||
6e00 7000 7200 7400 7600 7800 7a00 7c00 7e00
|
||||
&end
|
||||
|
||||
@sine-wave
|
||||
8000 84c5 8989 8e49 9305 97b9 9c66 a108 a59e aa27 aea1 b30a b761
|
||||
bba5 bfd3 c3ea c7ea cbcf cf9a d349 d6d9 da4b dd9d e0cd e3db e6c6
|
||||
e98b ec2c eea6 f0f8 f322 f523 f6fb f8a8 fa2a fb81 fcac fdaa fe7c
|
||||
ff20 ff98 ffe2 fffe ffed ffae ff42 fea9 fde3 fcef fbd0 fa84 f90c
|
||||
f76a f59d f3a6 f186 ef3e ecce ea37 e77b e499 e194 de6c db23 d7b9
|
||||
d430 d088 ccc5 c8e6 c4ed c0db bcb2 b874 b422 afbd ab47 a6c1 a22e
|
||||
9d8f 98e5 9433 8f79 8ab9 85f6 8131 7c6b 77a7 72e5 6e28 6972 64c4
|
||||
601f 5b85 56f9 527b 4e0e 49b2 4569 4136 3d18 3913 3527 3155 2d9f
|
||||
2a07 268d 2333 1ffb 1ce4 19f1 1721 1478 11f4 0f98 0d64 0b58 0976
|
||||
07be 0631 04d0 039a 0290 01b4 0104 0081 002c 0004 0009 003d 009d
|
||||
012b 01e7 02cf 03e3 0524 0691 0828 09eb 0bd7 0ded 102b 1292 151f
|
||||
17d2 1aaa 1da6 20c6 2407 2769 2aea 2e8a 3247 361f 3a12 3e1d 4240
|
||||
4679 4ac7 4f27 5399 581b 5cab 6147 65ee 6a9f 6f57 7415 78d8 7d9d
|
||||
8262 8727 8bea 90a8 9560 9a11 9eb8 a354 a7e4 ac66 b0d8 b538 b986
|
||||
bdbf c1e2 c5ed c9e0 cdb8 d175 d515 d896 dbf8 df39 e259 e555 e82d
|
||||
eae0 ed6d efd4 f212 f428 f614 f7d7 f96e fadb fc1c fd30 fe18 fed4
|
||||
ff62 ffc2 fff6 fffb ffd3 ff7e fefb fe4b fd6f fc65 fb2f f9ce f841
|
||||
f689 f4a7 f29b f067 ee0b eb87 e8de e60e e31b e004 dccc d972 d5f8
|
||||
d260 ceaa cad8 c6ec c2e7 bec9 ba96 b64d b1f1 ad84 a906 a47a 9fe0
|
||||
9b3b 968d 91d7 8d1a 8858 8394 7ece 7a09 7546 7086 6bcc 671a 6270
|
||||
5dd1 593e 54b8 5042 4bdd 478b 434d 3f24 3b12 3719 333a 2f77 2bcf
|
||||
2846 24dc 2193 1e6b 1b66 1884 15c8 1331 10c1 0e79 0c59 0a62 0895
|
||||
06f3 057b 042f 0310 021c 0156 00bd 0051 0012 0001 001d 0067 00df
|
||||
0183 0255 0353 047e 05d5 0757 0904 0adc 0cdd 0f07 1159 13d3 1674
|
||||
1939 1c24 1f32 2262 25b4 2926 2cb6 3065 3430 3815 3c15 402c 445a
|
||||
489e 4cf5 515e 55d8 5a61 5ef7 6399 6846 6cfa 71b6 7676 7b3a
|
||||
&end
|
||||
|
||||
@noise-wave-end
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
|00 @System [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ]
|
||||
|20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &color $1 ]
|
||||
|30 @Audio [ &wave $2 &env $2 &pad $4 &vol $1 &pitch $1 &play $1 &value $2 &delay $2 &finish $1 ]
|
||||
|30 @Audio [ &pad $8 &adsr $2 &len $2 &addr $2 &volume $1 &pitch $1 ]
|
||||
|
||||
|0100 ( -> )
|
||||
|
||||
|
@ -19,9 +19,10 @@
|
|||
#0ff0 .System/b DEO2
|
||||
|
||||
;on-frame .Screen/vector DEO2 ( run on-frame every 1/60th of a second )
|
||||
#ff .Audio/vol DEO ( set volume to max )
|
||||
;saw .Audio/wave DEO2 ( set waveform to saw for audio engine )
|
||||
;env .Audio/env DEO2 ( set envelope for audio engine )
|
||||
#ff .Audio/volume DEO ( set volume to max )
|
||||
;saw .Audio/addr DEO2 ( set waveform to saw for audio engine )
|
||||
;saw/end ;saw SUB2 #0002 SFT2 .Audio/len DEO2
|
||||
#1202 .Audio/adsr DEO2 ( set envelope for audio engine )
|
||||
|
||||
BRK
|
||||
|
||||
|
@ -34,8 +35,7 @@ BRK
|
|||
;melody #00 .progress PEK ADD2 GET
|
||||
|
||||
( play note )
|
||||
DUP #80 ORA .Audio/pitch DEO
|
||||
#01 .Audio/play DEO
|
||||
DUP .Audio/pitch DEO
|
||||
|
||||
( erase last note )
|
||||
#20 .Screen/color DEO
|
||||
|
@ -59,23 +59,39 @@ BRK
|
|||
( defines a sawtooth wave. )
|
||||
|
||||
@saw ( -> )
|
||||
|
||||
#6000 .Audio/value DEO2
|
||||
#0000 .Audio/delay DEO2 ( move to volume #600 after 0 delay )
|
||||
#0000 .Audio/value DEO2
|
||||
#ffff .Audio/delay DEO2 ( reach volume 0 after the whole note. Interpolated linearly )
|
||||
|
||||
BRK
|
||||
|
||||
( defines an envelope )
|
||||
|
||||
@env ( -> )
|
||||
|
||||
#ffff .Audio/value DEO2
|
||||
#1000 .Audio/delay DEO2 ( move pretty quickly to volume #ffff (maximum) )
|
||||
#0000 .Audio/value DEO2
|
||||
#4000 .Audio/delay DEO2 ( interpolating linearly, move to #0000 after a delay of #4000 where #8000 is half a second )
|
||||
#00 .Audio/finish DEO ( end the envelope )
|
||||
dfa0 df40 dee0 de80 de20 ddc0 dd60 dd00
|
||||
dca0 dc40 dbe0 db80 db20 dac0 da60 da00
|
||||
d9a0 d940 d8e0 d880 d820 d7c0 d760 d700
|
||||
d6a0 d640 d5e0 d580 d520 d4c0 d460 d400
|
||||
d3a0 d340 d2e0 d280 d220 d1c0 d160 d100
|
||||
d0a0 d040 cfe0 cf80 cf20 cec0 ce60 ce00
|
||||
cda0 cd40 cce0 cc80 cc20 cbc0 cb60 cb00
|
||||
caa0 ca40 c9e0 c980 c920 c8c0 c860 c800
|
||||
c7a0 c740 c6e0 c680 c620 c5c0 c560 c500
|
||||
c4a0 c440 c3e0 c380 c320 c2c0 c260 c200
|
||||
c1a0 c140 c0e0 c080 c020 bfc0 bf60 bf00
|
||||
bea0 be40 bde0 bd80 bd20 bcc0 bc60 bc00
|
||||
bba0 bb40 bae0 ba80 ba20 b9c0 b960 b900
|
||||
b8a0 b840 b7e0 b780 b720 b6c0 b660 b600
|
||||
b5a0 b540 b4e0 b480 b420 b3c0 b360 b300
|
||||
b2a0 b240 b1e0 b180 b120 b0c0 b060 b000
|
||||
afa0 af40 aee0 ae80 ae20 adc0 ad60 ad00
|
||||
aca0 ac40 abe0 ab80 ab20 aac0 aa60 aa00
|
||||
a9a0 a940 a8e0 a880 a820 a7c0 a760 a700
|
||||
a6a0 a640 a5e0 a580 a520 a4c0 a460 a400
|
||||
a3a0 a340 a2e0 a280 a220 a1c0 a160 a100
|
||||
a0a0 a040 9fe0 9f80 9f20 9ec0 9e60 9e00
|
||||
9da0 9d40 9ce0 9c80 9c20 9bc0 9b60 9b00
|
||||
9aa0 9a40 99e0 9980 9920 98c0 9860 9800
|
||||
97a0 9740 96e0 9680 9620 95c0 9560 9500
|
||||
94a0 9440 93e0 9380 9320 92c0 9260 9200
|
||||
91a0 9140 90e0 9080 9020 8fc0 8f60 8f00
|
||||
8ea0 8e40 8de0 8d80 8d20 8cc0 8c60 8c00
|
||||
8ba0 8b40 8ae0 8a80 8a20 89c0 8960 8900
|
||||
88a0 8840 87e0 8780 8720 86c0 8660 8600
|
||||
85a0 8540 84e0 8480 8420 83c0 8360 8300
|
||||
82a0 8240 81e0 8180 8120 80c0 8060 8000
|
||||
&end
|
||||
|
||||
BRK
|
||||
|
||||
|
|
126
src/apu.c
126
src/apu.c
|
@ -13,87 +13,69 @@ WITH REGARD TO THIS SOFTWARE.
|
|||
#include "uxn.h"
|
||||
#include "apu.h"
|
||||
|
||||
static Uint32 note_advances[12] = {
|
||||
0x82d01286 / (SAMPLE_FREQUENCY / 30), /* C7 */
|
||||
0x8a976073 / (SAMPLE_FREQUENCY / 30),
|
||||
0x92d5171d / (SAMPLE_FREQUENCY / 30), /* D7 */
|
||||
0x9b904100 / (SAMPLE_FREQUENCY / 30),
|
||||
0xa4d053c8 / (SAMPLE_FREQUENCY / 30), /* E7 */
|
||||
0xae9d36b0 / (SAMPLE_FREQUENCY / 30), /* F7 */
|
||||
0xb8ff493e / (SAMPLE_FREQUENCY / 30),
|
||||
0xc3ff6a72 / (SAMPLE_FREQUENCY / 30), /* G7 */
|
||||
0xcfa70054 / (SAMPLE_FREQUENCY / 30),
|
||||
0xdc000000 / (SAMPLE_FREQUENCY / 30), /* A7 */
|
||||
0xe914f623 / (SAMPLE_FREQUENCY / 30),
|
||||
0xf6f11003 / (SAMPLE_FREQUENCY / 30) /* B7 */
|
||||
#define NOTE_PERIOD 0x10000
|
||||
#define ADSR_STEP (SAMPLE_FREQUENCY / 0xf)
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
static Uint32 advances[12] = {
|
||||
0x80000, 0x879c8, 0x8facd, 0x9837f, 0xa1451, 0xaadc1,
|
||||
0xb504f, 0xbfc88, 0xcb2ff, 0xd7450, 0xe411f, 0xf1a1c
|
||||
};
|
||||
|
||||
static void
|
||||
render_note(Apu *apu, Uxn *u, int note_i, Sint16 *samples, int n_samples)
|
||||
/* clang-format on */
|
||||
|
||||
static Sint32
|
||||
envelope(Apu *c, Uint32 age)
|
||||
{
|
||||
int i;
|
||||
Note *note = &apu->notes[note_i];
|
||||
while(n_samples--) {
|
||||
Sint32 sample = 1;
|
||||
for(i = 0; i < 2; ++i) {
|
||||
WaveformGenerator *wv = ¬e->wv[i];
|
||||
apu->queue = &wv->queue;
|
||||
wv->count += wv->advance;
|
||||
while(wv->count > wv->period) {
|
||||
wv->count -= wv->period;
|
||||
wv->start_value = wv->end_value;
|
||||
if(apu->queue->i == apu->queue->n) {
|
||||
apu->queue->i = apu->queue->n = 0;
|
||||
if(!apu->queue->finishes) {
|
||||
*apu->channel_ptr = note_i;
|
||||
evaluxn(u, wv->vector);
|
||||
}
|
||||
}
|
||||
if(!apu->queue->n) {
|
||||
note->playing = 0;
|
||||
return;
|
||||
}
|
||||
wv->end_value = (Sint16)apu->queue->dat[apu->queue->i++];
|
||||
wv->period = (30 << 4) * apu->queue->dat[apu->queue->i++];
|
||||
if(!c->r) return 0x0888;
|
||||
if(age < c->a) return 0x0888 * age / c->a;
|
||||
if(age < c->d) return 0x0444 * (2 * c->d - c->a - age) / (c->d - c->a);
|
||||
if(age < c->s) return 0x0444;
|
||||
if(age < c->r) return 0x0444 * (c->r - age) / (c->r - c->s);
|
||||
c->advance = 0;
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
void
|
||||
apu_render(Apu *c, Sint16 *sample, Sint16 *end)
|
||||
{
|
||||
Sint32 s;
|
||||
if(!c->advance || !c->period) return;
|
||||
while(sample < end) {
|
||||
c->count += c->advance;
|
||||
c->i += c->count / c->period;
|
||||
c->count %= c->period;
|
||||
if(c->i >= c->len) {
|
||||
if(!c->repeat) {
|
||||
c->advance = 0;
|
||||
return;
|
||||
}
|
||||
if(wv->period >> 9)
|
||||
sample *= wv->start_value + (Sint32)(wv->end_value - wv->start_value) * (Sint32)(wv->count >> 10) / (Sint32)(wv->period >> 10);
|
||||
else
|
||||
sample *= wv->end_value;
|
||||
c->i %= c->len;
|
||||
}
|
||||
for(i = 0; i < 2; ++i)
|
||||
*(samples++) += sample / 0xf * note->volume[i] / 0x10000;
|
||||
s = (Sint16)(mempeek16(c->addr, c->i * 2) + 0x8000) * envelope(c, c->age++);
|
||||
*sample++ += s * c->volume_l / 0x8000;
|
||||
*sample++ += s * c->volume_r / 0x8000;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
apu_render(Apu *apu, Uxn *u, Sint16 *samples, int n_samples)
|
||||
apu_start(Apu *c, Uint16 adsr, Uint8 pitch)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < n_samples * 2; ++i)
|
||||
samples[i] = 0;
|
||||
for(i = 0; i < apu->n_notes; ++i)
|
||||
if(apu->notes[i].playing) render_note(apu, u, i, samples, n_samples);
|
||||
apu->queue = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
apu_play_note(Note *note, Uint16 wave_vector, Uint16 envelope_vector, Uint8 volume, Uint8 pitch, Uint8 impl)
|
||||
{
|
||||
int i;
|
||||
if(pitch >= 108 || impl == 0) return;
|
||||
note->playing = 1;
|
||||
note->impl = impl;
|
||||
for(i = 0; i < 2; ++i) {
|
||||
note->volume[i] = 0xf & (volume >> 4 * (1 - i));
|
||||
note->wv[i].count = note->wv[i].period = 0;
|
||||
note->wv[i].end_value = 0x8000 * (1 - i);
|
||||
note->wv[i].queue.n = note->wv[i].queue.i = 0;
|
||||
note->wv[i].queue.finishes = 0;
|
||||
note->wv[i].queue.is_envelope = i;
|
||||
if(pitch < 108 && c->len)
|
||||
c->advance = advances[pitch % 12] >> (8 - pitch / 12);
|
||||
else {
|
||||
c->advance = 0;
|
||||
return;
|
||||
}
|
||||
note->wv[0].vector = wave_vector;
|
||||
note->wv[0].advance = note_advances[pitch % 12] >> (8 - pitch / 12);
|
||||
note->wv[1].vector = envelope_vector;
|
||||
note->wv[1].advance = (30 << 20) / SAMPLE_FREQUENCY;
|
||||
c->a = ADSR_STEP * (adsr >> 12);
|
||||
c->d = ADSR_STEP * (adsr >> 8 & 0xf) + c->a;
|
||||
c->s = ADSR_STEP * (adsr >> 4 & 0xf) + c->d;
|
||||
c->r = ADSR_STEP * (adsr >> 0 & 0xf) + c->s;
|
||||
c->age = 0;
|
||||
c->i = 0;
|
||||
if(c->len <= 0x100) /* single cycle mode */
|
||||
c->period = NOTE_PERIOD * 337 / 2 / c->len;
|
||||
else /* sample repeat mode */
|
||||
c->period = NOTE_PERIOD;
|
||||
}
|
||||
|
|
31
src/apu.h
31
src/apu.h
|
@ -14,31 +14,14 @@ typedef unsigned int Uint32;
|
|||
typedef signed int Sint32;
|
||||
|
||||
#define SAMPLE_FREQUENCY 44100
|
||||
#define POLYPHONY 4
|
||||
|
||||
typedef struct {
|
||||
Uint16 *dat;
|
||||
Uint8 i, n, sz, finishes, is_envelope;
|
||||
} Queue;
|
||||
|
||||
typedef struct {
|
||||
Uint32 count, advance, period;
|
||||
Uint16 vector;
|
||||
Sint16 start_value, end_value;
|
||||
Queue queue;
|
||||
} WaveformGenerator;
|
||||
|
||||
typedef struct {
|
||||
WaveformGenerator wv[2];
|
||||
Sint8 volume[2];
|
||||
Uint8 playing, impl;
|
||||
} Note;
|
||||
|
||||
typedef struct {
|
||||
Queue *queue;
|
||||
Note *notes;
|
||||
Uint8 *channel_ptr;
|
||||
int n_notes;
|
||||
Uint8 *addr;
|
||||
Uint32 count, advance, period, age, a, d, s, r;
|
||||
Uint16 i, len;
|
||||
Uint8 volume_l, volume_r, pitch, repeat;
|
||||
} Apu;
|
||||
|
||||
void apu_render(Apu *apu, Uxn *u, Sint16 *samples, int n_samples);
|
||||
void apu_play_note(Note *note, Uint16 wave_vector, Uint16 envelope_vector, Uint8 volume, Uint8 pitch, Uint8 impl);
|
||||
void apu_render(Apu *c, Sint16 *sample, Sint16 *end);
|
||||
void apu_start(Apu *c, Uint16 adsr, Uint8 pitch);
|
||||
|
|
|
@ -22,8 +22,8 @@ static SDL_Window *gWindow;
|
|||
static SDL_Renderer *gRenderer;
|
||||
static SDL_Texture *gTexture;
|
||||
static Ppu ppu;
|
||||
static Apu apu;
|
||||
static Device *devscreen, *devmouse, *devctrl, *devapu;
|
||||
static Apu apu[POLYPHONY];
|
||||
static Device *devscreen, *devmouse, *devctrl;
|
||||
|
||||
Uint8 zoom = 0, debug = 0, reqdraw = 0;
|
||||
|
||||
|
@ -43,7 +43,12 @@ error(char *msg, const char *err)
|
|||
static void
|
||||
audio_callback(void *u, Uint8 *stream, int len)
|
||||
{
|
||||
apu_render(&apu, (Uxn *)u, (Sint16 *)stream, len >> 2);
|
||||
int i;
|
||||
Sint16 *samples = (Sint16 *)stream;
|
||||
SDL_memset(stream, 0, len);
|
||||
for(i = 0; i < POLYPHONY; ++i)
|
||||
apu_render(&apu[i], samples, samples + len / 2);
|
||||
(void)u;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -92,7 +97,7 @@ quit(void)
|
|||
}
|
||||
|
||||
int
|
||||
init(Uxn *u)
|
||||
init(void)
|
||||
{
|
||||
SDL_AudioSpec as;
|
||||
if(!initppu(&ppu, 48, 32, 16))
|
||||
|
@ -116,7 +121,7 @@ init(Uxn *u)
|
|||
as.channels = 2;
|
||||
as.callback = audio_callback;
|
||||
as.samples = 512;
|
||||
as.userdata = u;
|
||||
as.userdata = NULL;
|
||||
audio_id = SDL_OpenAudioDevice(NULL, 0, &as, NULL, 0);
|
||||
if(!audio_id)
|
||||
return error("Audio", SDL_GetError());
|
||||
|
@ -242,22 +247,23 @@ file_talk(Device *d, Uint8 b0, Uint8 w)
|
|||
static void
|
||||
audio_talk(Device *d, Uint8 b0, Uint8 w)
|
||||
{
|
||||
if(w && b0 == 0xa) {
|
||||
if(d->dat[0xa] >= apu.n_notes) apu.notes = SDL_realloc(apu.notes, (d->dat[0xa] + 1) * sizeof(Note));
|
||||
while(d->dat[0xa] >= apu.n_notes) SDL_zero(apu.notes[apu.n_notes++]);
|
||||
apu_play_note(&apu.notes[d->dat[0xa]], mempeek16(d->dat, 0x0), mempeek16(d->dat, 0x2), d->dat[0x8], d->dat[0x9] & 0x7f, d->dat[0x9] > 0x7f);
|
||||
} else if(w && b0 == 0xe && apu.queue != NULL) {
|
||||
if(apu.queue->n == apu.queue->sz) {
|
||||
apu.queue->sz = apu.queue->sz < 4 ? 4 : apu.queue->sz * 2;
|
||||
apu.queue->dat = SDL_realloc(apu.queue->dat, apu.queue->sz * sizeof(*apu.queue->dat));
|
||||
}
|
||||
if(apu.queue->is_envelope)
|
||||
apu.queue->dat[apu.queue->n++] = mempeek16(d->dat, 0xb) >> 1;
|
||||
else
|
||||
apu.queue->dat[apu.queue->n++] = mempeek16(d->dat, 0xb) + 0x8000;
|
||||
apu.queue->dat[apu.queue->n++] = mempeek16(d->dat, 0xd);
|
||||
} else if(w && b0 == 0xf && apu.queue != NULL)
|
||||
apu.queue->finishes = 1;
|
||||
Apu *c;
|
||||
if(!w) return;
|
||||
c = &apu[d->dat[0x7] % POLYPHONY];
|
||||
SDL_LockAudioDevice(audio_id);
|
||||
if(b0 == 0x1) c->period -= (Sint16)mempeek16(d->dat, 0x0);
|
||||
if(b0 == 0x3 || b0 == 0xf) c->len = mempeek16(d->dat, (b0 & 0x8) | 0x2);
|
||||
if(b0 == 0x5 || b0 == 0xf) c->addr = &d->mem[mempeek16(d->dat, (b0 & 0x8) | 0x4)];
|
||||
if(b0 == 0x6 || b0 == 0xf) {
|
||||
c->volume_l = d->dat[(b0 & 0x8) | 0x6] >> 4;
|
||||
c->volume_r = d->dat[(b0 & 0x8) | 0x6] & 0xf;
|
||||
}
|
||||
if(b0 == 0xf) {
|
||||
c->repeat = !(d->dat[0xf] & 0x80);
|
||||
apu_start(c, mempeek16(d->dat, 0x8), d->dat[0xf] & 0x7f);
|
||||
d->dat[0x7]++;
|
||||
}
|
||||
SDL_UnlockAudioDevice(audio_id);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -297,7 +303,6 @@ start(Uxn *u)
|
|||
while(1) {
|
||||
SDL_Event event;
|
||||
double elapsed, start = SDL_GetPerformanceCounter();
|
||||
SDL_LockAudioDevice(audio_id);
|
||||
while(SDL_PollEvent(&event) != 0) {
|
||||
switch(event.type) {
|
||||
case SDL_QUIT:
|
||||
|
@ -326,7 +331,6 @@ start(Uxn *u)
|
|||
}
|
||||
}
|
||||
evaluxn(u, mempeek16(devscreen->dat, 0));
|
||||
SDL_UnlockAudioDevice(audio_id);
|
||||
if(reqdraw)
|
||||
redraw(ppu.output, u);
|
||||
elapsed = (SDL_GetPerformanceCounter() - start) / (double)SDL_GetPerformanceFrequency() * 1000.0f;
|
||||
|
@ -347,13 +351,13 @@ main(int argc, char **argv)
|
|||
return error("Boot", "Failed");
|
||||
if(!loaduxn(&u, argv[1]))
|
||||
return error("Load", "Failed");
|
||||
if(!init(&u))
|
||||
if(!init())
|
||||
return error("Init", "Failed");
|
||||
|
||||
portuxn(&u, 0x0, "system", system_talk);
|
||||
portuxn(&u, 0x1, "console", console_talk);
|
||||
devscreen = portuxn(&u, 0x2, "screen", screen_talk);
|
||||
devapu = portuxn(&u, 0x3, "audio", audio_talk);
|
||||
portuxn(&u, 0x3, "audio", audio_talk);
|
||||
devctrl = portuxn(&u, 0x4, "controller", nil_talk);
|
||||
portuxn(&u, 0x5, "---", nil_talk);
|
||||
devmouse = portuxn(&u, 0x6, "mouse", nil_talk);
|
||||
|
@ -367,8 +371,6 @@ main(int argc, char **argv)
|
|||
portuxn(&u, 0xe, "---", nil_talk);
|
||||
portuxn(&u, 0xf, "---", nil_talk);
|
||||
|
||||
apu.channel_ptr = &devapu->dat[0xa];
|
||||
|
||||
/* Write screen size to dev/screen */
|
||||
mempoke16(devscreen->dat, 2, ppu.hor * 8);
|
||||
mempoke16(devscreen->dat, 4, ppu.ver * 8);
|
||||
|
|
Loading…
Reference in New Issue