Writing a music player for SPC700
BotB Academy n00b s0z
 
 
57002
Level 0 n00b
Aaendi
 
 
post #57002 :: 2015.05.10 9:30pm
  
  anewuser and KungFuFurby liēkd this
I am writing an SPC700 music player to be used in homebrew games, and I decided that I would arrange the data, in the same way you would see onscreen data in a typical music tracker.

track data:
byte 0: note
byte 1: octave
byte 2: volume left
byte 3: volume right
byte 4: instrument number
byte 5: echo, pitch modulation, noise enable, key on/off
byte 6: effect type
byte 7: effect parameter

The effects would include detuning, sweeping, vibrato, and stuff like that.

Now for the instrument format:
byte 0: sample number
byte 1&2: adsr
byte 3: gain

Anybody want to give constructive criticism on the way the format is layed out?
 
 
57016
Level 28 Chipist
KungFuFurby
 
 
 
post #57016 :: 2015.05.11 7:26am
Eight bytes per note (assuming this is on a per-note basis)? Do you have a byte before byte 0 that will indicate which bytes are actually active for each command? That's my instinct with this format that will allow this data to be compressed somewhat (it also reduces redundancy in the data). This byte, when set to zero, can also act as a delay command, with the second byte being the number of "rows/ticks" to skip.

The instrument data seems pretty standard. I would be tempted to fool around with gain using the effect commands, though.

Also... you're going to need a way to set up echo parameters. Byte 5, where you put the echo in, is most likely a switch (with actual echo setup going elsewhere).
 
 
57052
Level 0 n00b
Aaendi
 
 
post #57052 :: 2015.05.11 5:15pm
Thanks! Yeah, a song with 16 patterns of 64 rows would take up the entire 64kB. It doesn't make much sense to have the note take 2 bytes either. Should I use the second byte for detuning amount?
 
 
57064
Level 28 Chipist
KungFuFurby
 
 
 
post #57064 :: 2015.05.11 6:05pm :: edit 2015.05.11 6:07pm
In retrospect... if you're supporting up to 256 notes (and the octave will automatically incorporate with the note command), then yeah, you can swap out the octave with a detune amount (I also recommend having default tuning in the instrument as well to further reduce redundancy in the long run).
 
 
57144
Level 0 n00b
Aaendi
 
 
post #57144 :: 2015.05.13 2:21pm
I don't understand why people say the spc700 has a better instruction set than the 65816. There's no straight forward way of doing 16-bit indexing.
 
 
57151
Level 28 Chipist
KungFuFurby
 
 
 
post #57151 :: 2015.05.14 9:33am :: edit 2015.05.14 9:34am
The SPC700 in my eyes uses a Z80-like syntax for its assembly language (I had to learn to go backwards for how I usually read text to understand that kind of syntax, having only known 65816... and SPC700 ASM was the second ASM language that I learned!).

I got around that indexing problem by setting aside a pointer for indirect addressing, then continuously updating that pointer after processing a command so I don't ever run into the 8-bit indexing limit (of course I can always back it up if I'm going to swap out pointers).
 
 
57156
Level 0 n00b
Aaendi
 
 
post #57156 :: 2015.05.14 6:57pm
If I'm using a compressed data format, how would I interupt a channel for a sound effect, and get back to the right spot?
 
 
57165
Level 28 Chipist
KungFuFurby
 
 
 
post #57165 :: 2015.05.15 10:37am :: edit 2015.05.15 10:38am
The idea I had was to use 16 streams of channels rather than 8 (assuming each channel has its own collection of commands on a per-track basis). 8 are reserved for the music, while the other 8 are for the SFX (user should be able to define which channels can be overwritten by the SPC700 via setting bits). This way when the music is overwritten, it is still continuously being updated on a per-channel basis (except that the channel will be skipped when updating the DSP registers until the SFX is stopped, whether it be because of the end of the SFX & samples are done playing (or are at zero volume) or the SFX is voluntarily stopped by user). This also means for SFX, you use the same format as before.
 
 
57175
Level 0 n00b
Aaendi
 
 
post #57175 :: 2015.05.15 10:11pm
Did you make a sound engine? I don't want to reinvent the wheel if somebody else already did it.
 
 
57219
Level 28 Chipist
KungFuFurby
 
 
 
post #57219 :: 2015.05.17 8:10am :: edit 2015.05.17 8:17am
Mine is not even remotely complete (and it's untested). It also doesn't use your file format, as I came up with a different idea for a format (plus, I used TASM with native SPC700 syntax).

College is a major factor for me failing to properly develop the sound drivers, as they can get left abandoned for months at a time. It's almost functional in an Atari 2600 incarnation except for a few features failing to work properly and some synchronization problems (I went to the Atari 2600 figuring that it's a simpler system for me to try some magic on... and that got much farther than the SPC700 sound driver).

I might actually end up doing both over (well, partially...).
 
 
59898
Level 0 n00b
Aaendi
 
 
post #59898 :: 2015.09.08 3:11pm :: edit 2015.09.08 3:13pm
I started working on this again, and I implemented a "sample scaling" algorithm to allow a full frequency range of pulse waves without the low notes being effected by Gaussian interpolation.

I also implemented frequency sweeping.


define temp($00)
define tempo_delay($02)
define channel($03)
define key_on($04)
define pitch_mod($05)
define beat($06)
define pattern($07)
define song($09)
define key_off($0a)
define echo($0b)
define noise($0c)
define frequency($0e)

define track($10)
define left_volume($20)
define right_volume($21)
define detune($30)
define pitch($31)
define instrument($40)
define effects($41)
define octave($50)
define sweep($51)


define address($80)
define scale_factor($82)
define blocks_left($83)



define C-0($00)
define D-0($02)
define E-0($04)
define F-0($05)
define G-0($07)
define A-0($09)
define B-0($0b)
define C-1($0c)
define D-1($0e)
define E-1($10)
define F-1($11)
define G-1($13)
define A-1($15)
define B-1($17)
define C-2($18)
define D-2($1a)
define E-2($1c)
define F-2($1d)
define G-2($1f)
define A-2($21)
define B-2($23)
define C-3($24)
define D-3($26)
define E-3($28)
define F-3($29)
define G-3($2b)
define A-3($2d)
define B-3($2f)
define C-4($30)
define D-4($32)
define E-4($34)
define F-4($35)
define G-4($37)
define A-4($39)
define B-4($3b)
define C-5($3c)
define D-5($3e)
define E-5($40)
define F-5($41)
define G-5($43)
define A-5($45)
define B-5($47)
define C-6($48)
define D-6($4a)
define E-6($4c)
define F-6($4d)
define G-6($4f)
define A-6($51)
define B-6($53)
define C-7($54)
define D-7($56)
define E-7($58)
define F-7($59)
define G-7($5b)
define A-7($5d)
define B-7($5e)


str $fa=#$80
str $f1=#$11

str $f2=#$0f
str $f3=#$7f //FIR filter is all pass
str $f2=#$0c
str $f3=#$7f //left volume 100%
str $f2=#$1c
str $f3=#$80 //right volume 100%
str $f2=#$2c
str $f3=#$7f //echo volume 0%
str $f2=#$3c
str $f3=#$7f //echo volume 0%
str $f2=#$6c
str $f3=#$18
str $f2=#$0d
str $f3=#$20 //feedback 0%
str $f2=#$4d
str $f3=#$00 //no channel with echo
str $f2=#$5d
str $f3=#$80 //directory
str $f2=#$6d
str $f3=#$c0 //echo buffer
str $f2=#$7d
str $f3=#$01 //shortest delay possible

str {tempo_delay}=#$08















lda #$00
ldy #$81
stw {address}

ldx #$00
lda #$40
sta {scale_factor}
sample_scaling_loop:
sta {blocks_left}
ldw {address}
sta $8000,x
sta $8002,x
tya
sta $8001,x
sta $8003,x
inx
inx
inx
inx
phx



ldx #$00
ldy #$00

-;
lda wave,x
inx
phx
ldx {scale_factor}
-;
iny
sta ({address}),y
dex
cpy #$08
bne +

dec {blocks_left}
beq ++
pha

ldy #$00
lda #$82
sta ({address}),y
lda #$09
adw {address}
stw {address}
ldy #$00

pla

+;

cpx #$00
bne -
plx
bra --




+;
plx
plx
ldy #$00
lda #$83
sta ({address}),y
lda #$09
adw {address}
stw {address}

lsr {scale_factor}
lda {scale_factor}
bcc sample_scaling_loop

















big_loop:

str {beat}=#$20

ldx {song}
lda song+2,x
sta {pattern}
inx
lda song+2,x
sta {pattern}+1
inx
cpx song
bne +
ldx song+1
+;
stx {song}

ldy #$00
ldx #$00
-
lda ({pattern}),y
sta {track},x
iny
inx
cpx #$10
bne -



spc_loop:
lda $fd
beq spc_loop

channel_processing:




str {channel}=#$00
ldx #$00
-;




lda {effects},x
lsr
ror {key_on}
lsr
ror {key_off}
lsr
ror {echo}
lsr
ror {noise}
lsr
ror {pitch_mod}

lda {effects},x
and #$fc
sta {effects},x

lda {channel}
sta $f2



lda {left_volume},x
sta $f3
lda {right_volume},x
inc $f2
sta $f3

lda {detune},x
sta {temp}


lda {pitch},x
phx
ldy #$00
ldx #$0c
div
tax
lda note_scale,y
str {frequency}=#$00
sta {frequency}+1

lda note_scale+1,y
sec
sbc note_scale,y
ldy {temp}
mul
adw {frequency}
pha

lda octave_scale,x
mul
stw {frequency}
lda octave_scale,x
ply
mul
tya
ldy #$00
adw {frequency}






plx

inc $f2
sta $f3
inc $f2
sty $f3


lda {instrument},x
tay
lda instrument_data,y
clc
adc {octave},x
inc $f2
sta $f3
lda instrument_data+1,y
inc $f2
sta $f3
lda instrument_data+2,y
inc $f2
sta $f3
lda instrument_data+3,y
inc $f2
sta $f3

lda {sweep},x
clc
adc {detune},x
sta {detune},x
lda {pitch},x
adc #$00
sta {pitch},x



inx
inx


lda {channel}
clc
adc #$10
sta {channel}
cmp #$80
beq +
jmp -
+;


str $f2=#$5c
str $f3={key_off}



str $f2=#$4d
str $f3={echo}

str $f2=#$2d
str $f3={pitch_mod}

str $f2=#$3d
str $f3={noise}

str $f2=#$4c
str $f3={key_on} //key on





dec {tempo_delay}
beq +
jmp spc_loop
+;



music_tracking:

ldx #$00
-;


lda ({track},x)
sta {effects},x
inc {track},x

lda ({track},x)
sta {left_volume},x
inc {track},x

lda ({track},x)
sta {right_volume},x
inc {track},x

lda ({track},x)
sta {detune},x
inc {track},x

lda ({track},x)
sta {pitch},x
inc {track},x

lda ({track},x)
sta {octave},x
inc {track},x

lda ({track},x)
sta {instrument},x
inc {track},x

lda ({track},x)
sta {sweep},x
inc {track},x

inx
inx

cpx #$10
beq +
jmp -
+;






str {tempo_delay}=#$08

dec {beat}
bne +
jmp big_loop
+;



jmp spc_loop

instrument_data:
db $00,$fe,$a4,$00



song:
db $02,$00
dw pattern



pattern:
dw $4100,$4200,$4000,$4000,$4000,$4000,$4000,$4000



note_scale:
db 64,68,72,76,81,85,91,96,102,108,114,121,128


octave_scale:
db 1,2,4,8,16,32,64,128

wave:
db $88,$88,$88,$88,$88,$77,$77,$77

seek($834000)


//track format: effects, left volume, right volume, detune, pitch, octave, instrument, sweep


track:


db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0


db 1,127,127,0,{C-6},4,0,0
db 1,127,127,0,{E-6},4,0,8
db 1,127,127,0,{G-6},4,0,8
db 1,127,127,0,{B-6},4,0,0
db 1,127,127,0,{C-6},4,0,0
db 1,127,127,0,{E-6},4,0,8
db 1,127,127,0,{G-6},4,0,8
db 1,127,127,0,{B-6},4,0,0
db 1,127,127,0,{C-6},4,0,0
db 1,127,127,0,{E-6},4,0,8
db 1,127,127,0,{G-6},4,0,8
db 1,127,127,0,{B-6},4,0,0
db 1,127,127,0,{C-6},4,0,0
db 1,127,127,0,{E-6},4,0,8
db 1,127,127,0,{G-6},4,0,8
db 1,127,127,0,{B-6},4,0,0
db 1,127,127,0,{D-6},4,0,0
db 1,127,127,0,{F-6},4,0,8
db 1,127,127,0,{A-6},4,0,8
db 1,127,127,0,{C-7},4,0,0
db 1,127,127,0,{D-6},4,0,0
db 1,127,127,0,{F-6},4,0,8
db 1,127,127,0,{A-6},4,0,8
db 1,127,127,0,{C-7},4,0,0
db 1,127,127,0,{D-6},4,0,0
db 1,127,127,0,{F-6},4,0,8
db 1,127,127,0,{A-6},4,0,8
db 1,127,127,0,{C-7},4,0,0
db 1,127,127,0,{D-6},4,0,0
db 1,127,127,0,{F-6},4,0,8
db 1,127,127,0,{A-6},4,0,8
db 1,127,127,0,{C-7},4,0,0



db 9,16,8,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 9,8,4,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 9,16,8,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 9,8,4,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 9,16,8,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 9,8,4,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 9,8,4,0,0,0,0,0
db 9,16,8,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 9,8,4,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 2,0,0,0,0,0,0,0
db 2,0,0,0,0,0,0,0



seek($838000)
directory:
 
 

LOGIN or REGISTER to add your own comments!