mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-11-29 14:51:17 +00:00
182 lines
4.3 KiB
Plaintext
182 lines
4.3 KiB
Plaintext
|
|
||
|
//#resource "vcs-ca65.h"
|
||
|
|
||
|
import "vcslib.ecs"
|
||
|
|
||
|
component Song
|
||
|
songdata: array of 0..255
|
||
|
end
|
||
|
|
||
|
// TODO: merge with SoundChannel
|
||
|
component MusicChannel
|
||
|
duration: 0..255
|
||
|
note: 0..255
|
||
|
duty: 0..255
|
||
|
end
|
||
|
|
||
|
component MusicPlayer
|
||
|
timer: 0..255 default 255
|
||
|
channel: [MusicChannel]
|
||
|
songptr: 0..65535
|
||
|
volume: 0..15 default 15
|
||
|
tempo: 0..255 default 7
|
||
|
end
|
||
|
|
||
|
|
||
|
// Table of AUDF base values for each note
|
||
|
resource FREQZ ---
|
||
|
.byte 30, 30, 30, 30, 30, 28, 26, 25, 23, 22, 21, 19, 18, 17, 16, 15, 14, 13, 12, 12, 11, 10, 10, 9, 8, 8, 7, 7, 6, 6, 5, 5, 30, 29, 27, 25, 24, 22, 21, 20, 19, 18, 16, 15, 15, 14, 13, 12, 11, 11, 10, 31, 29, 27, 25, 24, 23, 21, 20, 19, 18, 16, 15, 15
|
||
|
---
|
||
|
// Table of duty-cycle bits for each note
|
||
|
resource DUTYZ ---
|
||
|
.byte 247, 247, 247, 247, 1, 73, 219, 1, 219, 73, 0, 219, 181, 85, 85, 85, 181, 219, 247, 1, 73, 181, 0, 73, 219, 17, 219, 17, 219, 73, 247, 85, 247, 1, 85, 247, 73, 247, 181, 17, 1, 0, 247, 247, 0, 1, 17, 73, 181, 0, 17, 0, 1, 85, 247, 73, 0, 181, 73, 1, 0, 247, 247, 0
|
||
|
---
|
||
|
// Table of AUDC values for each note
|
||
|
resource TONEZ ---
|
||
|
.byte 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
|
||
|
---
|
||
|
|
||
|
system MusicPlayer
|
||
|
on preframe do once
|
||
|
---
|
||
|
{{!musicpulse}} ; update song
|
||
|
{{!musicframe}} ; update registers
|
||
|
---
|
||
|
on postframe do once
|
||
|
---
|
||
|
{{!musicframe}} ; update registers
|
||
|
---
|
||
|
// TODO: unroll?
|
||
|
on musicframe do foreach [MusicChannel]
|
||
|
---
|
||
|
; Update channel pitch in AUDF0
|
||
|
; 8-bit rotation of duty cycle bits
|
||
|
lda {{get duration}}
|
||
|
beq :++
|
||
|
lda {{set duty}}
|
||
|
asl
|
||
|
bcc :+
|
||
|
ora #1
|
||
|
: sta {{set duty}}
|
||
|
lda {{get note}}
|
||
|
beq :+
|
||
|
; If next bit is set, add 1 to AUDF0
|
||
|
adc #0
|
||
|
sta AUDF0,x
|
||
|
:
|
||
|
---
|
||
|
on musicpulse do foreach [MusicChannel]
|
||
|
---
|
||
|
; Decrement the volumes for each channel
|
||
|
; Also decrement next-note timer, fetch next note
|
||
|
lda {{get duration}}
|
||
|
beq :+
|
||
|
lsr
|
||
|
sta AUDV0,x
|
||
|
dec {{set duration}}
|
||
|
:
|
||
|
---
|
||
|
on musicpulse do with [MusicPlayer]
|
||
|
---
|
||
|
lda {{get timer}}
|
||
|
bmi @Done
|
||
|
beq @NextData
|
||
|
dec {{set timer}}
|
||
|
jmp @Done
|
||
|
; Timer ran out, so fetch next note
|
||
|
@NextData:
|
||
|
ldx #0
|
||
|
lda ({{get songptr}},x)
|
||
|
bmi @LoadDuration
|
||
|
; < $80, play next note
|
||
|
ldx {{get channel}} ; next channel
|
||
|
tay
|
||
|
{{!musicnote}}
|
||
|
inx
|
||
|
txa
|
||
|
and #1
|
||
|
sta {{set channel}} ; inc next channel
|
||
|
jmp @IncDataPtr
|
||
|
; >= $80, load next duration
|
||
|
@LoadDuration:
|
||
|
cmp #$ff ; $ff = end of song
|
||
|
bne @NoResetTrack
|
||
|
sta {{set timer}}
|
||
|
{{!musicdone}}
|
||
|
jmp @Done
|
||
|
@NoResetTrack:
|
||
|
and #$7f
|
||
|
; asl
|
||
|
sta {{set timer}} ; store duration * 2
|
||
|
@IncDataPtr:
|
||
|
; increment song pointer
|
||
|
inc {{set songptr 0}}
|
||
|
bne @Done
|
||
|
inc {{set songptr 8}}
|
||
|
@Done:
|
||
|
---
|
||
|
// TODO: should use "with"?
|
||
|
on musicnote do select all [MusicChannel]
|
||
|
---
|
||
|
; Play a note
|
||
|
; X = channel (0,1)
|
||
|
; Y = note index (0-63)
|
||
|
lda {{^FREQZ}},y
|
||
|
sta {{base note}},x
|
||
|
lda {{^DUTYZ}},y
|
||
|
sta {{base duty}},x
|
||
|
lda {{^TONEZ}},y
|
||
|
sta AUDC0,x
|
||
|
; TODO: consts?
|
||
|
lda {{get MusicPlayer:tempo}}
|
||
|
sta {{base duration}},x
|
||
|
lda {{get MusicPlayer:volume}}
|
||
|
sta AUDV0,x
|
||
|
---
|
||
|
on playmusic do foreach [MusicPlayer] limit 1
|
||
|
---
|
||
|
lda #<{{arg 0}}
|
||
|
sta {{set songptr 0}}
|
||
|
lda #>{{arg 0}}
|
||
|
sta {{set songptr 8}}
|
||
|
lda #0
|
||
|
sta {{set timer}}
|
||
|
---
|
||
|
on stopmusic do foreach [MusicPlayer] limit 1
|
||
|
---
|
||
|
lda #$ff
|
||
|
sta {{set timer}}
|
||
|
---
|
||
|
end
|
||
|
|
||
|
///
|
||
|
|
||
|
demo music
|
||
|
using FrameLoop
|
||
|
using MusicPlayer
|
||
|
entity [MusicChannel] end
|
||
|
entity [MusicChannel] end
|
||
|
entity MusicPlayer [MusicPlayer]
|
||
|
const volume = 10
|
||
|
const tempo = 31
|
||
|
end
|
||
|
system music
|
||
|
on musicdone do with [MusicPlayer]
|
||
|
---
|
||
|
; TODO: nested exprs
|
||
|
; {{!playmusic ^SampleMusic}}
|
||
|
;{{^SampleMusic}}
|
||
|
{{!playmusic SampleMusic}}
|
||
|
---
|
||
|
on preframeloop do once
|
||
|
---
|
||
|
{{!musicdone}}
|
||
|
---
|
||
|
end
|
||
|
end demo
|
||
|
|
||
|
resource SampleMusic ---
|
||
|
.byte $35,$41,$8a,$37,$43,$8a,$33,$3f,$8a,$30,$3c,$94,$3e,$32,$8a,$3a,$2e,$94,$35,$29,$8a,$37,$2b,$8a,$33,$27,$8a,$30,$24,$94,$32,$26,$8a,$2e,$22,$94,$29,$1d,$8a,$2b,$1f,$8a,$27,$1b,$8a,$24,$18,$94,$1a,$26,$8a,$18,$24,$8a,$17,$23,$8a,$16,$22,$a8,$3a,$35,$ff
|
||
|
---
|
||
|
|