8bitworkshop/presets/c64/sidtune.dasm

333 lines
5.9 KiB
Plaintext

; Title: "NewKidOnTheBlock"
; Chip: 6581 C64 used when composing.
; Author: Frantic/Hack'n'Trade
; https://codebase64.org/doku.php?id=base:256_bytes_tune_player
;---------------------------------
; CONSTANTS
;
DEBUG = 1
NUMBEROFVOICES = 3 ;Using all three Voices
S = $10 ;Song "speed"
;---------------------------------
; ZERO PAGE ADDRESSES
;
TICKCOUNTERS = $02 ;Use zp for tickcounters.. TICKCOUNTERS+0, TICKCOUNTERS+7,
;TICKCOUNTERS+14 will be used.
DATAPOS = $03 ;Use zp for SONGPOSITIONS... 0, 7, 14..
FILTERHI = $23
;---------------------------------
; CODE
;
include "cartheader.dasm"
Start: sei
ldy #$02 ;Set it to $02 so the first incorrectly timed
;iteration won't affect anything
sty FILTERHI ;Init filtersweep to make it a bit more deterministic.
;Init counters and sonpositions
lda #(NUMBEROFVOICES-1)*7 ;Voice indeX
_initlp: tax
sta DATAPOS,x ;Init datapos+0 to 0, datapos+7 to 7 and datapos+14 to 14.
sty TICKCOUNTERS,x ;y can be anything.. doesn't matter, but now I happen to
;init the filter so set it to $01 too
sec
sbc #7
bpl _initlp
;--
; Main player loop
_outerloop:
_wrast: cpx $d012 ;After the loop, x is a negative number, thus well above $3e
;(or whatever the critical raster value is again..)
bne _wrast ;First iteration won't be correct though, but since the
;counters are set to 2 initially it doesn't matter.
#if DEBUG
lda #1
sta $d020
sta $d021
#endif
jsr sweep
stx $d416 ;filter hi
ldx #(NUMBEROFVOICES-1)*7 ;Voice indeX
;Right here is a good place for Voice specific code, if there is any reason for that.
_innerloop:
dec TICKCOUNTERS,x
bne _loopend
;Time for new sound settings, turn gate and oscillator off..
lda #8
sta $d404,x
;Turn on global volume to make sure we'll hear anything at all.
;Reason for having this code *inside* the loop:
; To make sure the player won't run too fast and get executed
; twice on the same rasterline.
lda #$5f ;Hi-pass + Lo-pass filter on.
sta $d418
lda #$a2 ;Filter used on middle (melody) voice.
sta $d417
;Parse data sequence data
ldy DATAPOS,x
_newseq:
iny
lda _musicdata-1,y ;Get databyte
bne _nonewseq
lda _musicdata-0,y ;Get jumpval if it's jumptime
tay ;..and use new one instead
bpl _newseq ;This means data may not be larger than $80 bytes
_nonewseq:
sty DATAPOS,x
pha
and #$0f ;Note value
tay
lda _freqhi,y
sta $d401,x ;Freq hi
lda _freqlo,y
sta $d400,x ;Freq lo
pla
lsr
lsr
lsr
lsr
tay
lda adtab,y
sta $d405,x
lda durtab,y
sta TICKCOUNTERS,x
lda ctrltab,y
sta $d404,x
_loopend:
txa
.byte $cb,7 ;axs #7 / sbx #7 / whatever..
bpl _innerloop
#if DEBUG
dec $d020
dec $d021
jmp _outerloop
#endif
bmi _outerloop
sweep
inc $23
ldx $23
ldy #$00
rts
;---------------------------------
; "Instruments"
;
; Using AD only to save space. (SR is set to 00 as default)
;
; A pattern is S*8 ticks long, so using "instrument" 5 we
; can represent a whole empty pattern by just one byte in
; the sequence data. At the same time, this format allows
; for changes to the waveform every tick, which means we
; can also make drums and such things. But, not in this
; tune. Perhaps in the next one..
;
; 00 01 02 03 04 05 06
adtab: .byte $1c, $1b, $cd, $2b, $1a, $00, $ad
ctrltab: .byte $11, $11, $21, $21, $21, $00, $21
durtab: .byte S*1, S*3, S*6, S*2, S*1, S*8, S*8
;---------------------------------
; Sequence data
;
; Voc0 starts at 0
; Voc1 starts at 7
; Voc2 starts at 14
;
; Note and duration stored in one byte and the byte following a $00 (JP)
; byte is interpreted as the destination of a jump to another place in
; the data.
_musicdata:
_Voc0start:
.byte $00 | G4
.byte $00 | Az4
.byte $00 | C5
.byte $00 | D5
.byte $00 | Dz5
.byte JP
.byte <(_Voc0komp-_musicdata)
_Voc1start:
.byte $20 | D5
.byte $30 | Dz5
.byte $20 | D5
.byte $40 | A4
.byte $40 | Az4
.byte JP
.byte <(_Voc1melody-_musicdata)
_Voc2start:
;-
.byte $50 | 0
.byte $50 | 0
.byte $50 | 0
.byte $50 | 0
;-
.byte $50 | 0
_Voc2loop:
.byte $50 | 0
.byte $50 | 0
.byte $20 | C5
.byte $40 | Dz4
.byte $40 | F4
;-
.byte $50 | 0
.byte $60 | D5
.byte $20 | Dz5
.byte $30 | Az4
.byte $20 | A4
.byte $30 | F4
;-
.byte $60 | G4
.byte $50 | 0
.byte $50 | 0
.byte $60 | C5
;-
.byte $50 | 0
.byte $60 | D5
.byte $60 | Dz5
.byte $60 | F5
;-
.byte $60 | G5
.byte JP
.byte <(_Voc2loop-_musicdata)
_Voc0komp:
.byte $10 | G5
.byte $00 | D4
.byte $00 | Fz4
.byte $00 | A4
.byte $00 | Az4
.byte $00 | C5
.byte $10 | D5
.byte $00 | Dz4
.byte $00 | F4
.byte $00 | G4
.byte $00 | Az4
.byte $00 | C5
.byte $10 | Dz5
.byte $00 | F4
.byte $00 | A4
.byte $00 | C5
.byte $00 | D5
.byte $00 | Dz5
.byte $10 | F5
.byte JP
.byte <(_Voc0start-_musicdata)
_Voc1melody:
.byte $20 | C5
.byte $30 | Az4
.byte $20 | A4
.byte $30 | F4
;-
.byte $60 | G4
.byte $50 | 0
.byte $20 | F4
.byte $30 | Dz4
.byte $20 | F4
.byte $30 | Dz4
;-
.byte $20 | D4
.byte $30 | Dz4
.byte $20 | D4
.byte $30 | Fz4
.byte $20 | G4
.byte $30 | Dz4
.byte $00 | C4
.byte $00 | Dz4
.byte $00 | F4
.byte $00 | G4
.byte $00 | A4
.byte $00 | C5
.byte $00 | G5
.byte $00 | F5
.byte JP
.byte <(_Voc1start-_musicdata)
;---------------------------------
;Note freq data
;
; Only using needed notes.
JP = 0
C4 = 1
D4 = 2
Dz4 = 3
;E4 = 2;Not used
F4 = 4
Fz4 = 5
G4 = 6
;Gz4 = 6;Not used
A4 = 7
Az4 = 8
;B4 = 8;Not used
C5 = 9
;Cz5 = 9;Not used
D5 = 10
Dz5 = 11
;E5 = 11;Not used
F5 = 12
;Fz5 = 13;Not used
G5 = 13
;Gz5 ;Not used
;A5 ;Not used
;Az5 = 14;Not used
_freqlo = *-1 ;-1 to exclude the corresponding first byte (in _freqhi) used as a "wrap flag"
.byte $77
.byte $61,$e1
.byte $f7,$8f,$30
.byte $8f,$4e
.byte $ef
.byte $c3,$c3
.byte $ef
.byte $60
_freqhi:
.byte $00 ;WRAP
.byte $07
.byte $08,$08
.byte $09,$0a,$0b
.byte $0c,$0d
.byte $0e
.byte $10,$11
.byte $13
.byte $16