mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-11-23 06:32:11 +00:00
333 lines
5.9 KiB
Plaintext
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
|