music: add tracker3

This commit is contained in:
Vince Weaver 2022-01-12 16:06:46 -05:00
parent 8769952043
commit 105af64ded
13 changed files with 1503 additions and 0 deletions

View File

@ -0,0 +1,62 @@
include ../../Makefile.inc
DOS33 = ../../utils/dos33fs-utils/dos33
EMPTY_DISK = ../../empty_disk
HGR2PNG = ../../utils/hgr-utils/png2hgr
LINKER_SCRIPTS = ../../linker_scripts
TOKENIZE = ../../utils/asoft_basic-utils/tokenize_asoft
all: tiny_tracker3.dsk
####
tiny_tracker3.dsk: HELLO D2
cp $(EMPTY_DISK)/empty.dsk ./tiny_tracker3.dsk
$(DOS33) -y tiny_tracker3.dsk SAVE A HELLO
$(DOS33) -y tiny_tracker3.dsk -t BIN -a 0x6000 BSAVE D2
####
HELLO: hello.bas
$(TOKENIZE) < hello.bas > HELLO
####
peasant_music.s: peasant.txt text_to_tiny
./text_to_tiny peasant.txt > peasant_music.s
####
mA2E_2.s: mA2E_2.txt text_to_tiny
./text_to_tiny mA2E_2.txt > mA2E_2.s
####
mA2E_3.s: mA2E_3.txt text_to_tiny
./text_to_tiny mA2E_3.txt > mA2E_3.s
####
D2: d2.o
ld65 -o D2 d2.o -C $(LINKER_SCRIPTS)/apple2_6000.inc
d2.o: d2.s \
zp.inc hardware.inc \
mA2E_2.s mA2E_3.s \
interrupt_handler.s mockingboard_init.s \
tracker_init.s mockingboard_constants.s ay3_write_regs.s
ca65 -o d2.o d2.s -l d2.lst
####
text_to_tiny: text_to_tiny.o
$(CC) -o text_to_tiny text_to_tiny.o -lm
text_to_tiny.o: text_to_tiny.c
$(CC) $(CFLAGS) -c text_to_tiny.c
####
clean:
rm -f *~ *.o *.lst D2 HELLO text_to_tiny mA2E_2.s mA2E_3.s

View File

@ -0,0 +1,37 @@
;=====================
;=====================
;=====================
; ay3 write regs
;=====================
;=====================
;=====================
; write all 14 registers
; address in X
; data in A
ay3_write_regs:
ldx #13
ay3_write_reg_loop:
lda #MOCK_AY_LATCH_ADDR ; latch_address for PB1 ; 2
ldy #MOCK_AY_INACTIVE ; go inactive ; 2
stx MOCK_6522_ORA1 ; put address on PA1 ; 4
sta MOCK_6522_ORB1 ; latch_address on PB1 ; 4
sty MOCK_6522_ORB1 ; 4
; value
lda AY_REGS,X
sta MOCK_6522_ORA1 ; put value on PA1 ; 4
lda #MOCK_AY_WRITE ; ; 2
sta MOCK_6522_ORB1 ; write on PB1 ; 4
sty MOCK_6522_ORB1 ; 4
dex
bpl ay3_write_reg_loop
; rts

55
music/tiny_tracker3/d2.s Normal file
View File

@ -0,0 +1,55 @@
; Apple II graphics/music in 1k
; by deater (Vince Weaver) <vince@deater.net>
; Zero Page
.include "zp.inc"
.include "hardware.inc"
; goal is 332 bytes
; 319 bytes -- switch songs to mA2E_3
; 415 bytes -- double length of song
; 334 bytes -- merge length into value
; if can straddle interrupt vector, save 10 bytes
; if can guarantee Y is 0 on entry, save 2 bytes
d2:
;===================
; music Player Setup
tracker_song = peasant_song
; assume mockingboard in slot#4
; inline mockingboard_init
.include "mockingboard_init.s"
.include "tracker_init.s"
; start the music playing
cli
bob:
lda KEYPRESS
bpl bob
quiet:
lda #$3f
sta AY_REGS+7
end:
brk
.include "interrupt_handler.s"
.include "mockingboard_constants.s"
; music
.include "mA2E_3.s"

View File

@ -0,0 +1,92 @@
;; HARDWARE LOCATIONS
KEYPRESS = $C000
KEYRESET = $C010
;; SOFT SWITCHES
CLR80COL = $C000 ; PAGE0/PAGE1 normal
SET80COL = $C001 ; PAGE0/PAGE1 switches PAGE0 in Aux instead
EIGHTYCOLOFF = $C00C
EIGHTYCOLON = $C00D
SPEAKER = $C030
SET_GR = $C050
SET_TEXT = $C051
FULLGR = $C052
TEXTGR = $C053
PAGE1 = $C054
PAGE2 = $C055
LORES = $C056 ; Enable LORES graphics
HIRES = $C057 ; Enable HIRES graphics
AN3 = $C05E ; Annunciator 3
PADDLE_BUTTON0 = $C061
PADDL0 = $C064
PTRIG = $C070
;; BASIC ROUTINES
NORMAL = $F273
HGR2 = $F3D8
HCLR = $F3F2
HPOSN = $F411 ; (Y,X),(A) (values stores in HGRX,XH,Y)
XDRAW0 = $F65D
;; MONITOR ROUTINES
HLINE = $F819 ;; HLINE Y,$2C at A
VLINE = $F828 ;; VLINE A,$2D at Y
CLRSCR = $F832 ;; Clear low-res screen
CLRTOP = $F836 ;; clear only top of low-res screen
SETGR = $FB40 ;; GR
SETCOL = $F864 ;; COLOR=A
TEXT = $FB36
TABV = $FB5B ;; VTAB to A
BELL = $FBDD ;; ring the bell
BASCALC = $FBC1 ;;
VTAB = $FC22 ;; VTAB to CV
HOME = $FC58 ;; Clear the text screen
WAIT = $FCA8 ;; delay 1/2(26+27A+5A^2) us
CROUT1 = $FD8B
SETINV = $FE80 ;; INVERSE
SETNORM = $FE84 ;; NORMAL
COUT = $FDED ;; output A to screen
COUT1 = $FDF0 ;; output A to screen
COLOR_BLACK = 0
COLOR_RED = 1
COLOR_DARKBLUE = 2
COLOR_PURPLE = 3
COLOR_DARKGREEN = 4
COLOR_GREY = 5
COLOR_MEDIUMBLUE = 6
COLOR_LIGHTBLUE = 7
COLOR_BROWN = 8
COLOR_ORANGE = 9
COLOR_GREY2 = 10
COLOR_PINK = 11
COLOR_LIGHTGREEN = 12
COLOR_YELLOW = 13
COLOR_AQUA = 14
COLOR_WHITE = 15
COLOR_BOTH_BLACK = $00
COLOR_BOTH_RED = $11
COLOR_BOTH_DARKBLUE = $22
COLOR_BOTH_DARKGREEN = $44
COLOR_BOTH_GREY = $55
COLOR_BOTH_MEDIUMBLUE = $66
COLOR_BOTH_LIGHTBLUE = $77
COLOR_BOTH_BROWN = $88
COLOR_BOTH_ORANGE = $99
COLOR_BOTH_PINK = $BB
COLOR_BOTH_LIGHTGREEN = $CC
COLOR_BOTH_YELLOW = $DD
COLOR_BOTH_AQUA = $EE
COLOR_BOTH_WHITE = $FF

View File

@ -0,0 +1,6 @@
5 HOME
10 PRINT "TINY TRACKER #3"
20 PRINT CHR$(4);"CATALOG"
25 PRINT:PRINT "AUTOMATICALLY STARTING"
30 PRINT "]BRUN D2"
40 PRINT CHR$(4);"BRUN D2"

View File

@ -0,0 +1,189 @@
;================================
;================================
; mockingboard interrupt handler
;================================
;================================
; On Apple II/6502 the interrupt handler jumps to address in 0xfffe
; This is in the ROM, which saves the registers
; on older IIe it saved A to $45 (which could mess with DISK II)
; newer IIe doesn't do that.
; It then calculates if it is a BRK or not (which trashes A)
; Then it sets up the stack like an interrupt and calls 0x3fe
; Note: the IIc is much more complicated
; its firmware tries to decode the proper source
; based on various things, including screen hole values
; we bypass that by switching out ROM and replacing the
; $fffe vector with this, but that does mean we have
; to be sure status flag and accumulator set properly
interrupt_handler:
php ; save status flags
; we don't use decimal mode so no need to clear it?
; A is saved in $45 by firmware
; we are assuming a II/II+/IIe here
txa
pha ; save X
tya
pha ; save Y
; inc $0404 ; debug (flashes char onscreen)
ay3_irq_handler:
;==========================================
; clear 6522 interrupt by reading T1C-L ; 4
bit MOCK_6522_T1CL
; drop note down after first
lda #$C
sta AY_REGS+8
sta AY_REGS+10
; lda #$0E
; sta AY_REGS+8 ; $08 volume A
; lda #$0C
; sta AY_REGS+9 ; $09 volume B
; sta AY_REGS+10 ; $0A volume C
;============================
; see if still counting down
lda SONG_COUNTDOWN
bpl done_update_song
set_notes_loop:
;==================
; load next byte
ldy SONG_OFFSET
lda tracker_song,Y
;==================
; see if hit end
cmp #$FF
bne all_ok
;====================================
; if at end, loop back to beginning
lda #0 ; reset song offset
sta SONG_OFFSET
beq set_notes_loop ; bra
all_ok:
; see if note
; tay
; and #$C0
; cmp #$C0
; beq handle_timing
note_only:
; tya
; NNNNNLLC -- c=channel, n=note
tay
ldx #0
lsr
bcc channel_a
ldx #4 ; skip to C
channel_a:
and #$3
sta SONG_COUNTDOWN
; inc SONG_COUNTDOWN
tya
lsr
lsr
lsr
; and #$FE ; fine register value, want in X
; tax
; tya ; get note
; and #$1F
tay ; lookup in table
lda frequencies_low,Y
sta AY_REGS,X ; set proper register value
lda frequencies_high,Y
sta AY_REGS+1,X
lda #$F
sta AY_REGS+8
;============================
; point to next
; assume less than 256 bytes
inc SONG_OFFSET
lda SONG_COUNTDOWN
beq set_notes_loop ; bra
.include "ay3_write_regs.s"
; jsr ay3_write_regs
handle_timing:
; was timing
; tya
; and #$3f
; sta SONG_COUNTDOWN
; inc SONG_OFFSET
done_update_song:
dec SONG_COUNTDOWN
;=================================
; Finally done with this interrupt
;=================================
done_ay3_irq_handler:
pla
tay ; restore Y
pla
tax ; restore X
; on II+/IIe the firmware saves A in $45
; this won't work on a IIc/IIgs
lda $45 ; restore A
plp ; restore flags
rti ; return from interrupt ; 6
;============
; typical
; ???? cycles

View File

@ -0,0 +1,212 @@
'' TITLE: Mockingboard Tune 2 - 2021
' AUTHOR: mA2E / dSr
' COMMENTS:
'
' LOOP: 640
'
' BPM: 250
' TEMPO: 6
' FREQ: 1000000
' IRQ: 50
'
' LYRICS: 0
'
' ENDHEADER
-------
' 0
0 F 3-- C 5-- C 4--
1 ----- ----- -----
2 ----- ----- -----
3 ----- ----- -----
4 ----- ----- F 4--
5 ----- ----- -----
6 ----- ----- -----
7 ----- ----- -----
8 F 4-- F 5-- G 4--
9 ----- ----- -----
A ----- ----- -----
B ----- ----- -----
C ----- ----- G#4--
D ----- ----- -----
E ----- ----- -----
F ----- ----- -----
10 F 3-- G 5-- C 4--
11 ----- ----- -----
12 ----- ----- -----
13 ----- ----- -----
14 ----- ----- F 4--
15 ----- ----- -----
16 ----- ----- -----
17 ----- ----- -----
18 F 4-- G#5-- G 4--
19 ----- ----- -----
1A ----- ----- -----
1B ----- ----- -----
1C ----- ----- G#4--
1D ----- ----- -----
1E ----- ----- -----
1F ----- ----- -----
20 F 3-- G 5-- C 4--
21 ----- ----- -----
22 ----- ----- -----
23 ----- ----- -----
24 ----- ----- F 4--
25 ----- ----- -----
26 ----- ----- -----
27 ----- ----- -----
28 F 4-- G#5-- G 4--
29 ----- ----- -----
2A ----- ----- -----
2B ----- ----- -----
2C ----- ----- G#4--
2D ----- ----- -----
2E ----- ----- -----
2F ----- ----- -----
30 F 3-- C 6-- C 4--
31 ----- ----- -----
32 ----- ----- -----
33 ----- ----- -----
34 ----- ----- F 4--
35 ----- ----- -----
36 ----- ----- -----
37 ----- ----- -----
38 F 4-- ----- G 4--
39 ----- ----- -----
3A ----- ----- -----
3B ----- ----- -----
3C ----- ----- G#4--
3D ----- ----- -----
3E ----- ----- -----
3F ----- ----- -----
' 1
0 D#3-- A#5-- D#4--
1 ----- ----- -----
2 ----- ----- -----
3 ----- ----- -----
4 ----- ----- G 4--
5 ----- ----- -----
6 ----- ----- -----
7 ----- ----- -----
8 D#4-- G#5-- G#4--
9 ----- ----- -----
A ----- ----- -----
B ----- ----- -----
C ----- ----- A#4--
D ----- ----- -----
E ----- ----- -----
F ----- ----- -----
10 D#3-- G 5-- D#4--
11 ----- ----- -----
12 ----- ----- -----
13 ----- ----- -----
14 ----- ----- G 4--
15 ----- ----- -----
16 ----- ----- -----
17 ----- ----- -----
18 D#4-- F 5-- G#4--
19 ----- ----- -----
1A ----- ----- -----
1B ----- ----- -----
1C ----- ----- A#4--
1D ----- ----- -----
1E ----- ----- -----
1F ----- ----- -----
20 D#3-- G 5-- D#4--
21 ----- ----- -----
22 ----- ----- -----
23 ----- ----- -----
24 ----- ----- G 4--
25 ----- ----- -----
26 ----- ----- -----
27 ----- ----- -----
28 D#4-- G#5-- G#4--
29 ----- ----- -----
2A ----- ----- -----
2B ----- ----- -----
2C ----- ----- A#4--
2D ----- ----- -----
2E ----- ----- -----
2F ----- ----- -----
30 D#3-- G 5-- D#4--
31 ----- ----- -----
32 ----- ----- -----
33 ----- ----- -----
34 ----- ----- G 4--
35 ----- ----- -----
36 ----- ----- -----
37 ----- ----- -----
38 D#4-- ----- G#4--
39 ----- ----- -----
3A ----- ----- -----
3B ----- ----- -----
3C ----- ----- A#4--
3D ----- ----- -----
3E ----- ----- -----
3F ----- ----- -----
' 2
0 C#3-- G 5-- C#4--
1 ----- ----- -----
2 ----- ----- -----
3 ----- ----- -----
4 ----- ----- F 4--
5 ----- ----- -----
6 ----- ----- -----
7 ----- ----- -----
8 C#4-- ----- G 4--
9 ----- ----- -----
A ----- ----- -----
B ----- ----- -----
C ----- ----- G#4--
D ----- ----- -----
E ----- ----- -----
F ----- ----- -----
10 C#3-- G#5-- C#4--
11 ----- ----- -----
12 ----- ----- -----
13 ----- ----- -----
14 ----- ----- F 4--
15 ----- ----- -----
16 ----- ----- -----
17 ----- ----- -----
18 C#4-- F 5-- G 4--
19 ----- ----- -----
1A ----- ----- -----
1B ----- ----- -----
1C ----- ----- G#4--
1D ----- ----- -----
1E ----- ----- -----
1F ----- ----- -----
20 C#3-- ----- C#4--
21 ----- ----- -----
22 ----- ----- -----
23 ----- ----- -----
24 ----- ----- F 4--
25 ----- ----- -----
26 ----- ----- -----
27 ----- ----- -----
28 C#4-- ----- G 4--
29 ----- ----- -----
2A ----- ----- -----
2B ----- ----- -----
2C ----- ----- G#4--
2D ----- ----- -----
2E ----- ----- -----
2F ----- ----- -----
30 C#3-- ----- C#4--
31 ----- ----- -----
32 ----- ----- -----
33 ----- ----- -----
34 ----- ----- F 4--
35 ----- ----- -----
36 ----- ----- -----
37 ----- ----- -----
38 C#4-- ----- G 4--
39 ----- ----- -----
3A ----- ----- -----
3B ----- ----- -----
3C ----- ----- A#4--
3D ----- ----- -----
3E ----- ----- -----
3F ----- ----- -----

View File

@ -0,0 +1,145 @@
'' TITLE: Mockingboard Tune 3 - 2021
' AUTHOR: mA2E / dSr
' COMMENTS:
'
' LOOP: 640
'
' BPM: 250
' TEMPO: 6
' FREQ: 1000000
' IRQ: 50
'
' LYRICS: 0
'
' ENDHEADER
-------
' 1
0 G 3-- ----- G 6--
1 ----- ----- -----
2 ----- ----- -----
3 G 4-- ----- D 6--
4 ----- ----- -----
5 F 3-- ----- -----
6 G 3- ----- A#5--
7 ----- ----- -----
8 G 3-- ----- G 5--
9 ----- ----- -----
A ----- ----- -----
B G 4-- ----- A#5--
C ----- ----- -----
D F 3-- ----- -----
E G 3-- ----- D 6--
F ----- ----- -----
10 D#3-- ----- G 6--
11 ----- ----- -----
12 ----- ----- -----
13 D#4-- ----- D#6--
14 ----- ----- -----
15 D 3- ----- -----
16 D#3-- ----- A#5--
17 ----- ----- -----
18 D#3-- ----- G 5--
19 ----- ----- -----
1A ----- ----- -----
1B D#4-- ----- A#5--
1C ----- ----- -----
1D D 3-- ----- -----
1E D#3-- ----- G 6--
1F ----- ----- -----
20 F 3-- ----- F 6--
21 ----- ----- -----
22 ----- ----- -----
23 F 4-- ----- -----
24 ----- ----- C 6--
25 D#3-- ----- -----
26 F 3-- ----- A 5--
27 ----- ----- -----
28 F 3-- ----- F 5--
29 ----- ----- -----
2A ----- ----- -----
2B F 4-- ----- A 5--
2C ----- ----- -----
2D D#3-- ----- -----
2E F 3-- ----- D#6--
2F ----- ----- -----
30 D 3-- ----- D 6--
31 ----- ----- -----
32 ----- ----- -----
33 D 4-- ----- D#6--
34 ----- ----- -----
35 C 3-- ----- -----
36 D 3-- ----- D 6--
37 ----- ----- -----
38 D 3-- ----- C 6--
39 ----- ----- -----
3A ----- ----- -----
3B D 4-- ----- A#5--
3C ----- ----- -----
3D C 3-- ----- -----
3E D 3-- ----- A 5--
3F ----- ----- -----
' 1
0 G 3-- ----- G 6--
1 ----- ----- -----
2 ----- ----- -----
3 G 4-- ----- -----
4 ----- ----- -----
5 F 3-- ----- -----
6 G 3- ----- F 6--
7 ----- ----- D 6--
8 G 3-- ----- G 5--
9 ----- ----- -----
A ----- ----- -----
B G 4-- ----- -----
C ----- ----- A#5--
D F 3-- ----- -----
E G 3-- ----- C 6--
F ----- ----- -----
10 D#3-- ----- G 6--
11 ----- ----- -----
12 ----- ----- -----
13 D#4-- ----- -----
14 ----- ----- -----
15 D 3- ----- -----
16 D#3-- ----- F 6--
17 ----- ----- G 6--
18 D#3-- ----- D#6--
19 ----- ----- -----
1A ----- ----- -----
1B D#4-- ----- -----
1C ----- ----- D 6--
1D D 3-- ----- -----
1E D#3-- ----- A#5--
1F ----- ----- -----
20 F 3-- ----- C 6--
21 ----- ----- -----
22 ----- ----- -----
23 F 4-- ----- -----
24 ----- ----- -----
25 D#3-- ----- -----
26 F 3-- ----- A#5--
27 ----- ----- C 6--
28 F 3-- ----- A 5--
29 ----- ----- -----
2A ----- ----- -----
2B F 4-- ----- -----
2C ----- ----- G 5--
2D D#3-- ----- -----
2E F 3-- ----- A 5--
2F ----- ----- -----
30 D 3-- ----- F 5--
31 ----- ----- -----
32 ----- ----- -----
33 D 4-- ----- G 5--
34 ----- ----- -----
35 C 3-- ----- -----
36 D 3-- ----- A 5--
37 ----- ----- -----
38 D 3-- ----- -----
39 ----- ----- C 6--
3A ----- ----- -----
3B D 4-- ----- -----
3C ----- ----- F 5--
3D C 3-- ----- -----
3E D 3-- ----- -----
3F ----- ----- -----

View File

@ -0,0 +1,16 @@
init_addresses:
.byte <MOCK_6522_DDRB1,<MOCK_6522_DDRA1 ; set the data direction for all pins of PortA/PortB to be output
.byte <MOCK_6522_ACR,<MOCK_6522_IER ; Continuous interrupts, clear all interrupts
.byte <MOCK_6522_IFR,<MOCK_6522_IER ; enable interrupt on timer overflow
.byte <MOCK_6522_T1CL,<MOCK_6522_T1CH ; set oflow value, start counting
.byte <MOCK_6522_ORB1,<MOCK_6522_ORB1 ; reset ay-3-8910
; note, terminated by the $ff below
init_values:
.byte $ff,$ff ; set the data direction for all pins of PortA/PortB to be output
.byte $40,$7f
.byte $C0,$C0
.byte $CE,$C7 ; c7ce / 1.023e6 = .050s, 20Hz
.byte MOCK_AY_RESET,MOCK_AY_INACTIVE

View File

@ -0,0 +1,105 @@
; Mockingboad programming:
; + Has two 6522 I/O chips connected to two AY-3-8910 chips
; + Optionally has some speech chips controlled via the outport on the AY
; + Often in slot 4
; TODO: how to auto-detect?
; References used:
; http://macgui.com/usenet/?group=2&id=8366
; 6522 Data Sheet
; AY-3-8910 Data Sheet
;========================
; Mockingboard card
; Essentially two 6522s hooked to the Apple II bus
; Connected to AY-3-8910 chips
; PA0-PA7 on 6522 connected to DA0-DA7 on AY
; PB0 on 6522 connected to BC1
; PB1 on 6522 connected to BDIR
; PB2 on 6522 connected to RESET
; left speaker
MOCK_6522_ORB1 = $C400 ; 6522 #1 port b data
MOCK_6522_ORA1 = $C401 ; 6522 #1 port a data
MOCK_6522_DDRB1 = $C402 ; 6522 #1 data direction port B
MOCK_6522_DDRA1 = $C403 ; 6522 #1 data direction port A
MOCK_6522_T1CL = $C404 ; 6522 #1 t1 low order latches
MOCK_6522_T1CH = $C405 ; 6522 #1 t1 high order counter
MOCK_6522_T1LL = $C406 ; 6522 #1 t1 low order latches
MOCK_6522_T1LH = $C407 ; 6522 #1 t1 high order latches
MOCK_6522_T2CL = $C408 ; 6522 #1 t2 low order latches
MOCK_6522_T2CH = $C409 ; 6522 #1 t2 high order counters
MOCK_6522_SR = $C40A ; 6522 #1 shift register
MOCK_6522_ACR = $C40B ; 6522 #1 auxilliary control register
MOCK_6522_PCR = $C40C ; 6522 #1 peripheral control register
MOCK_6522_IFR = $C40D ; 6522 #1 interrupt flag register
MOCK_6522_IER = $C40E ; 6522 #1 interrupt enable register
MOCK_6522_ORANH = $C40F ; 6522 #1 port a data no handshake
; right speaker
MOCK_6522_ORB2 = $C480 ; 6522 #2 port b data
MOCK_6522_ORA2 = $C481 ; 6522 #2 port a data
MOCK_6522_DDRB2 = $C482 ; 6522 #2 data direction port B
MOCK_6522_DDRA2 = $C483 ; 6522 #2 data direction port A
; AY-3-8910 commands on port B
; RESET BDIR BC1
MOCK_AY_RESET = $0 ; 0 0 0
MOCK_AY_INACTIVE = $4 ; 1 0 0
MOCK_AY_READ = $5 ; 1 0 1
MOCK_AY_WRITE = $6 ; 1 1 0
MOCK_AY_LATCH_ADDR = $7 ; 1 1 1
;========================
;========================
; Mockingboard Init
;========================
;========================
; Left channel only
mockingboard_init:
; sei ; disable interrupts, is this necessary?
;=========================
; Setup Interrupt Handler
;=========================
; NOTE: we don't support IIc as it's a hack
; traditionally Mockingboard on IIc was rare
;========================
; set up interrupt
; Vector address goes to 0x3fe/0x3ff
; can save 10 bytes if we load in memory so this
; is in the right place automatically
lda #<interrupt_handler ; 2
sta $03fe ; 3
lda #>interrupt_handler ; 2
sta $03ff ; 3
;=========
; 10
;=========================
; Initialize the 6522s
; Reset Left AY-3-8910
;===========================
; entries=10
; 14 + 2*entries = 34 bytes
ldy #0 ; 2
init_it_loop:
lda init_values,Y ; 3
ldx init_addresses,Y ; 3
bmi doneit ; 2
iny ; 1
sta $c400,X ; 3
bne init_it_loop ; 2
doneit:

View File

@ -0,0 +1,532 @@
/* make music for tiny_music player */
#define VERSION "1.0"
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
static int octave_adjust=0;
static int notes_used[64];
static int allocated_notes[64];
static int notes_allocated=0;
static int total_len=0;
unsigned short frequencies[]={
//C C# D D# E F F# G G# A A# B
//0x7A3,0x735,0x6CD,0x66C,0x60F,0x5B8,0x566,0x518,0x4CF,0x48A,0x449,0x40B,
0x3D1,0x39A,0x366,0x336,0x307,0x2DC,0x2B3,0x28C,0x267,0x245,0x224,0x205,
0x1E8,0x1CD,0x1B3,0x19B,0x183,0x16E,0x159,0x146,0x133,0x122,0x112,0x102, //3
0x0F4,0x0E6,0x0D9,0x0CD,0x0C1,0x0B7,0x0AC,0x0A3,0x099,0x091,0x089,0x081, //4
0x07A,0x073,0x06C,0x066,0x060,0x05B,0x056,0x051,0x04C,0x048,0x044,0x040, //5
//0x03D,0x039,0x036,0x033,0x030,0x02D,0x02B,0x028,0x026,0x024,0x022,0x020, //6
//0x01E,0x01C,0x01B,0x019,0x018,0x016,0x015,0x014,0x013,0x012,0x011,0x010,
//0x00F,0x00E,0x00D,0x00C,0x00C,0x00B,0x00A,0x00A,0x009,0x009,0x008,0x008,
};
// CLLNNNN
int note_to_ed(char note, int flat, int sharp, int octave) {
int offset;
switch(note) {
case 'C': offset=0; break;
case 'D': offset=2; break;
case 'E': offset=4; break;
case 'F': offset=5; break;
case 'G': offset=7; break;
case 'A': offset=9; break;
case 'B': offset=11; break;
case 'R': offset=12; flat=0; sharp=0; octave=3; break;
default:
fprintf(stderr,"Unknown note %c\n",note);
return -1;
}
if (flat==1) offset--;
if (sharp==1) offset++;
if (sharp==2) offset+=2;
offset=((((octave+octave_adjust)-3)&0x3)*12)+offset;
// offset=((((octave+octave_adjust)-3)&0x3)<<4)|offset;
return offset;
}
static int debug=0;
static int line=0;
static int header_version=0;
struct note_type {
unsigned char which;
unsigned char note;
int sharp,flat;
int octave;
int len;
int enabled;
int freq;
int length;
int left;
int ed_freq;
int offset;
};
static int allocate_note(int which) {
int i;
for(i=0;i<notes_allocated;i++) {
if (allocated_notes[i]==which) return i;
}
allocated_notes[notes_allocated]=which;
notes_allocated++;
return notes_allocated-1;
}
static int get_note(char *string, int sp, struct note_type *n, int line) {
int freq;
int ch;
// fprintf(stderr,"VMW: Entering, sp=%d\n",sp);
/* Skip white space */
while((string[sp]==' ' || string[sp]=='\t')) sp++;
if (string[sp]=='\n') return -1;
/* return early if no change */
ch=string[sp];
// fprintf(stderr,"VMW: %d %d\n",ch,sp);
if (ch=='-') {
if (header_version==0) return sp+6;
else {
return sp+11;
}
}
/* get note info */
n->sharp=0;
n->flat=0;
n->ed_freq=-1;
n->note=ch;
sp++;
if (string[sp]==' ') ;
else if (string[sp]=='#') n->sharp=1;
else if (string[sp]=='-') n->flat=1;
else if (string[sp]=='=') n->flat=2;
else {
fprintf(stderr,"Unknown note modifier %c, line %d:%d\n",
string[sp],line,sp);
fprintf(stderr,"String: %s\n",string);
}
// printf("Sharp=%d Flat=%d\n",n->sharp,n->flat);
sp++;
n->octave=string[sp]-'0';
sp++;
sp++;
n->len=string[sp]-'0';
sp++;
if (n->note!='-') {
freq=note_to_ed(n->note,n->flat,n->sharp,
n->octave);
n->enabled=1;
n->length=0;
n->ed_freq=freq;
}
if (header_version==2) sp+=6;
return sp;
}
static int get_string(char *string, char *key, char *output, int strip_linefeed) {
char *found;
found=strstr(string,key);
found=found+strlen(key);
/* get rid of leading whitespace */
while(1) {
if ((*found==' ') || (*found=='\t')) found++;
else break;
}
strcpy(output,found);
/* remove trailing linefeed */
if (strip_linefeed) output[strlen(output)-1]=0;
return 0;
}
static void print_help(int just_version, char *exec_name) {
printf("\ntext_to_ed version %s by Vince Weaver <vince@deater.net>\n\n",VERSION);
if (just_version) exit(0);
printf("This created Electric Duet files\n\n");
printf("Usage:\n");
printf("\t%s [-h] [-v] [-d] [-o X] [-i X] textfile outbase\n\n",
exec_name);
printf("\t-h: this help message\n");
printf("\t-v: version info\n");
printf("\t-d: print debug messages\n");
printf("\t-o: Offset octave by X\n");
printf("\t-i: set second instrument to X\n");
exit(0);
}
int main(int argc, char **argv) {
char string[BUFSIZ];
char *result;
char *in_filename;
char temp[BUFSIZ];
FILE *in_file=NULL;
//int attributes=0;
int loop=0;
int sp,external_frequency,irq;
struct note_type a,b,c;
int copt;
char song_name[BUFSIZ];
char author_name[BUFSIZ];
char comments[BUFSIZ];
char *comments_ptr=comments;
unsigned char sharp_char[]=" #-=";
/* Parse command line arguments */
while ((copt = getopt(argc, argv, "dhvo:i:"))!=-1) {
switch (copt) {
case 'd':
/* Debug messages */
printf("Debug enabled\n");
debug=1;
break;
case 'h':
/* help */
print_help(0,argv[0]);
break;
case 'v':
/* version */
print_help(1,argv[0]);
break;
case 'o':
/* octave offset */
octave_adjust=atoi(optarg);
break;
default:
print_help(0,argv[0]);
break;
}
}
if (argv[optind]!=NULL) {
/* Open the input file */
if (argv[optind][0]=='-') {
in_file=stdin;
}
else {
in_filename=strdup(argv[optind]);
in_file=fopen(in_filename,"r");
if (in_file==NULL) {
fprintf(stderr,"Couldn't open %s\n",in_filename);
return -1;
}
}
}
/* Get the info for the header */
while(1) {
result=fgets(string,BUFSIZ,in_file);
if (result==NULL) break;
line++;
if (strstr(string,"ENDHEADER")) break;
if (strstr(string,"HEADER:")) {
get_string(string,"HEADER:",temp,1);
header_version=atoi(temp);
printf("Found header version %d\n",header_version);
}
if (strstr(string,"TITLE:")) {
get_string(string,"TITLE:",song_name,1);
}
if (strstr(string,"AUTHOR:")) {
get_string(string,"AUTHOR:",author_name,1);
}
if (strstr(string,"COMMENTS:")) {
get_string(string,"COMMENTS:",comments_ptr,0);
comments_ptr=&comments[strlen(comments)];
}
if (strstr(string,"FREQ:")) {
get_string(string,"FREQ:",temp,1);
external_frequency=atoi(temp);
}
if (strstr(string,"IRQ:")) {
get_string(string,"IRQ:",temp,1);
irq=atoi(temp);
}
if (strstr(string,"LOOP:")) {
get_string(string,"LOOP:",temp,1);
loop=atoi(temp);
}
}
a.which='A'; b.which='B'; c.which='C';
// algorithm
// get A,B,C
// int first=1;
// int a_last=0,b_last=0,same_count=0;
// int a_len=0,b_len=0,a_freq=0,b_freq=0;
int current_length=0;
int first=1;
int a_last=-1,c_last=-1;
unsigned char temp_value;
printf("peasant_song:\n");
printf("; register init\n");
//printf("\t.byte $00,$00,$00,$00,$00,$00 ; $00: A/B/C fine/coarse\n");
//printf("\t.byte $00 ; $06\n");
//printf("\t.byte $38 ; $07 mixer (ABC on)\n");
//printf("\t.byte $0E,$0C,$0C ; $08 volume A/B/C\n");
//printf("\t.byte $00,$00,$00,$00 ; $09\n");
printf("\n");
while(1) {
result=fgets(string,BUFSIZ,in_file);
if (result==NULL) break;
line++;
a.ed_freq=-1;
b.ed_freq=-1;
c.ed_freq=-1;
a.length=0;
b.length=0;
c.length=0;
/* skip comments */
if (string[0]=='\'') continue;
if (string[0]=='-') continue;
if (string[0]=='*') continue;
sp=0;
/* Skip line number */
while((string[sp]!=' ' && string[sp]!='\t')) sp++;
sp=get_note(string,sp,&a,line);
if (sp!=-1) sp=get_note(string,sp,&b,line);
if (sp!=-1) sp=get_note(string,sp,&c,line);
if (a.ed_freq>=0) {
a.offset=allocate_note(a.ed_freq);
notes_used[a.ed_freq]++;
printf("; A: %d\n",a.ed_freq);
}
if (b.ed_freq>=0) {
b.offset=allocate_note(b.ed_freq);
notes_used[b.ed_freq]++;
printf("; B: %d\n",b.ed_freq);
}
if (c.ed_freq>=0) {
c.offset=allocate_note(c.ed_freq);
notes_used[c.ed_freq]++;
printf("; C: %d\n",c.ed_freq);
}
if ((a.ed_freq>=0)||(b.ed_freq>=0)||(c.ed_freq>=0)) {
printf("; none: a=%d c=%d len=%d\n",a_last,c_last,current_length);
//NNNNNLLC
if (!first) {
if (a_last>=0) {
temp_value=(a_last<<3)|0;
if (c_last<0) temp_value|=(current_length<<1);
printf("\t.byte $%02X ; A=%d L=%d\n",
temp_value,
a_last,c_last>=0?0:current_length);
total_len++;
a_last=-1;
}
if (c_last>=0) {
printf("\t.byte $%02X ; C=%d L=%d\n",
(unsigned char)(c_last<<3)|((current_length)<<1)|1,
c_last,current_length);
total_len++;
c_last=-1;
}
}
current_length=0;
//if (!first) {
// printf("\t.byte $%02X ; L = %d\n",
// current_length|0xc0,current_length);
// printf("\n");
// current_length=0;
// total_len++;
//}
first=0;
}
if (a.ed_freq>=0) {
a_last=a.offset;
}
if (b.ed_freq>=0) {
}
if (c.ed_freq>=0) {
c_last=c.offset;
}
#if 0
if (a.ed_freq>=0) {
printf("\t.byte $%02X ; A = %c%c%d freq=%d offset=%d\n",
a.offset,
a.note,sharp_char[a.sharp+2*a.flat],
a.octave,
a.ed_freq,a.offset);
total_len++;
}
if (b.ed_freq>=0) {
printf("\t.byte $%02X ; B = %c%c%d\n",
b.offset|0x40,
b.note,sharp_char[b.sharp+2*b.flat],
b.octave);
total_len++;
}
if (c.ed_freq>=0) {
printf("\t.byte $%02X ; C = %c%c%d freq=%d offset=%d\n",
c.offset|0x80,
c.note,sharp_char[c.sharp+2*c.flat],
c.octave,
c.ed_freq,c.offset);
total_len++;
}
#endif
current_length++;
}
printf("; last: a=%d c=%d len=%d\n",a_last,c_last,current_length);
if (a_last>=0) {
temp_value=(a_last<<3)|0;
if (c_last<0) temp_value|=(current_length<<1);
printf("\t.byte $%02X ; A=%d L=%d\n",
temp_value,
a_last,c_last>=0?0:current_length);
total_len++;
a_last=-1;
}
if (c_last>=0) {
printf("\t.byte $%02X ; C=%d L=%d\n",
(unsigned char)(c_last<<3)|((current_length)<<1)|1,
c_last,current_length);
total_len++;
c_last=-1;
}
// printf("\t.byte $%02X ; L = %d\n",
// current_length|0xc0,current_length);
// printf("\n");
printf("\t.byte $FF ; end\n");
total_len++;
int o,n;
for(o=0;o<4;o++) {
printf("; Octave %d : ",o);
for(n=0;n<12;n++) {
printf("%d ",notes_used[(o*12)+n]);
}
printf("\n");
}
printf("; %d notes allocated\n",notes_allocated);
printf(";.byte ");
for(n=0;n<notes_allocated;n++) {
printf("%d,",allocated_notes[n]);
}
printf("\n");
printf("frequencies_high:\n");
printf(".byte ");
for(n=0;n<notes_allocated;n++) {
printf("$%02X",(frequencies[allocated_notes[n]]>>8));
if (n!=(notes_allocated-1)) printf(",");
total_len++;
}
printf("\n");
printf("frequencies_low:\n");
printf(".byte ");
for(n=0;n<notes_allocated;n++) {
printf("$%02X",(frequencies[allocated_notes[n]])&0xff);
if (n!=(notes_allocated-1)) printf(",");
total_len++;
}
printf("\n");
printf("; total len=%d\n",total_len);
(void) irq;
(void) loop;
(void) external_frequency;
return 0;
}

View File

@ -0,0 +1,23 @@
tracker_init:
; setup initial ay-3-8910 values (this depends on song)
init_registers_to_zero:
ldx #$13 ; clear more than have to for other
lda #0 ; vars
; sta SONG_OFFSET ; also in
; sta SONG_COUNTDOWN
init_loop:
sta AY_REGS,X
dex
bpl init_loop
; jsr ay3_write_regs
lda #$38
sta AY_REGS+7 ; $07 mixer (ABC on)
; lda #$0E
; sta AY_REGS+8 ; $08 volume A
; lda #$0C
; sta AY_REGS+9 ; $09 volume B
; sta AY_REGS+10 ; $0A volume C

View File

@ -0,0 +1,29 @@
; zero page
; pre-defined applesoft vars
CH = $24
CV = $25
GBASL = $26
GBASH = $27
BASL = $28
BASH = $29
AY_REGS = $70
FRAME = $80
SONG_OFFSET = $81
SONG_COUNTDOWN = $82
OUR_ROT = $A5
HGR_X = $E0
HGR_XH = $E1
HGR_Y = $E2
HGR_COLOR = $E4
HGR_PAGE = $E6
HGR_SCALE = $E7
COUNT = $FB