peasant: hook up trogdor speech

This commit is contained in:
Vince Weaver 2021-09-17 19:18:38 -04:00
parent f278aba111
commit 74c93ace2d
12 changed files with 653 additions and 6 deletions

View File

@ -161,8 +161,9 @@ TROGDOR: trogdor.o
ld65 -o TROGDOR trogdor.o -C $(LINKER_SCRIPTS)/apple2_6000.inc
trogdor.o: trogdor.s zp.inc \
graphics_trogdor/trogdor_graphics.inc sprites/peasant_sprite.inc \
graphics_trogdor/trogdor_graphics.inc sprites/trogdor_sprites.inc \
sprites/inventory_sprites.inc \
ssi263_simple_speech.s \
draw_box.s hgr_rectangle.s hgr_font.s hgr_input.s \
hgr_7x28_sprite_mask.s hgr_1x5_sprite.s hgr_save_restore.s \
wait_a_bit.s draw_peasant.s hgr_text_box.s \
@ -235,6 +236,9 @@ graphics_end/ending_graphics.inc:
sprites/inventory_sprites.inc:
cd sprites && make
sprites/trogdor_sprites.inc:
cd sprites && make
###
clean:

View File

@ -11,6 +11,8 @@
ending:
jsr mockingboard_setup_interrupt
jsr hgr_make_tables
jsr HGR2 ; Hi-res graphics, no text at bottom

View File

@ -96,6 +96,7 @@ escape_handler:
sei ; turn off music
jsr clear_ay_both ; clear AY state
jsr mockingboard_disable_interrupt
;=============================
; start new game
@ -177,3 +178,4 @@ escape_handler:
.include "wait_a_bit.s"
.include "graphics/graphics_intro.inc"

View File

@ -156,6 +156,8 @@ mockingboard_patch:
sta setup_irq_smc4+2 ; 37
sta setup_irq_smc5+2 ; 38
sta setup_irq_smc6+2 ; 39
sta disable_irq_smc1+2 ; 34
sta disable_irq_smc2+2 ; 35
rts
.endif

View File

@ -275,3 +275,117 @@ setup_irq_smc6:
; clear interrupt and start counting
rts
;=============================
; Setup
;=============================
mockingboard_disable_interrupt:
;.ifdef PT3_ENABLE_APPLE_IIC
; lda APPLEII_MODEL
; cmp #'C'
; bne done_iic_hack
;
; ; bypass the firmware interrupt handler
; ; should we do this on IIe too? probably faster
;
; ; first we have to copy the ROM to the language card
;
; sei ; disable interrupts
;
;
;
;copy_rom_loop:
; lda $c089 ; read ROM, write RAM1
; lda $c089
; ldy #0
;read_rom_loop:
; lda $D000,Y
; sta $400,Y ; note this uses text page as
; temporary data store
; iny
; bne read_rom_loop
; lda $c08B ; read/write RAM1
; lda $c08B ;
;write_rom_loop:
; lda $400,Y
; sta $D000,Y
; iny
; bne write_rom_loop
; inc read_rom_loop+2
; inc write_rom_loop+5
; bne copy_rom_loop
; lda #<interrupt_handler
; sta $fffe
; lda #>interrupt_handler
; sta $ffff
; lda #$EA ; nop out the "lda $45" in the irq handler
; sta interrupt_smc
; sta interrupt_smc+1
;.endif
;
;done_iic_hack:
;=========================
; Setup Interrupt Handler
;=========================
; Vector address goes to 0x3fe/0x3ff
; FIXME: should chain any existing handler
; lda #<interrupt_handler
; sta $03fe
; lda #>interrupt_handler
; sta $03ff
;============================
; Enable 50Hz clock on 6522
;============================
; Note, on Apple II the clock isn't 1MHz but is actually closer to
; roughly 1.023MHz, and every 65th clock is stretched (it's complicated)
; 4fe7 / 1.023e6 = .020s, 50Hz
; 9c40 / 1.023e6 = .040s, 25Hz
; 411a / 1.023e6 = .016s, 60Hz
; French Touch uses
; 4e20 / 1.000e6 = .020s, 50Hz, which assumes 1MHz clock freq
sei ; disable interrupts just in case
lda #$40 ; Continuous interrupts, don't touch PB7
disable_irq_smc1:
sta MOCK_6522_ACR ; ACR register
lda #$7F ; clear all interrupt flags
disable_irq_smc2:
sta MOCK_6522_IER ; IER register (interrupt enable)
; lda #$C0
;setup_irq_smc3:
; sta MOCK_6522_IFR ; IFR: 1100, enable interrupt on timer one oflow
;setup_irq_smc4:
; sta MOCK_6522_IER ; IER: 1100, enable timer one interrupt
; lda #$E7
; lda #$20
;setup_irq_smc5:
; sta MOCK_6522_T1CL ; write into low-order latch
; lda #$4f
; lda #$4E
;setup_irq_smc6:
; sta MOCK_6522_T1CH ; write into high-order latch,
; ; load both values into counter
; ; clear interrupt and start counting
rts

View File

@ -5,9 +5,10 @@ pt3_init_song=QLOAD_LOC+$BF9
clear_ay_both=QLOAD_LOC+$E82
reset_ay_both=QLOAD_LOC+$E40
mockingboard_setup_interrupt=QLOAD_LOC+$E8F
mockingboard_disable_interrupt=QLOAD_LOC+$EB7
mockingboard_init=QLOAD_LOC+$E31
mockingboard_patch=QLOAD_LOC+$F67
mockingboard_detect=QLOAD_LOC+$F38
mockingboard_patch=QLOAD_LOC+$F73
mockingboard_detect=QLOAD_LOC+$F44
PT3_LOC=QLOAD_LOC+$1000

View File

@ -1,6 +1,6 @@
HGR_SPRITE = ../../../utils/hgr-utils/hgr_make_sprite
all: inventory_sprites.inc ending_sprites.inc
all: inventory_sprites.inc ending_sprites.inc trogdor_sprites.inc
inventory_sprites.inc: inventory.png
$(HGR_SPRITE) -l arrow_sprite inventory.png 14 3 27 19 > inventory_sprites.inc
@ -60,6 +60,16 @@ ending_sprites.inc: end_sprites.png boat_sprites.png
$(HGR_SPRITE) -s -l foam1 end_sprites.png 183 38 195 85 >> ending_sprites.inc
trogdor_sprites.inc: trogdor_sprites.png
$(HGR_SPRITE) -l dashing0_sprite trogdor_sprites.png 14 6 20 45 > trogdor_sprites.inc
$(HGR_SPRITE) -l dashing1_sprite trogdor_sprites.png 28 6 34 45 >> trogdor_sprites.inc
$(HGR_SPRITE) -l dashing2_sprite trogdor_sprites.png 42 6 48 45 >> trogdor_sprites.inc
$(HGR_SPRITE) -l dashing3_sprite trogdor_sprites.png 56 6 62 45 >> trogdor_sprites.inc
$(HGR_SPRITE) -l dashing4_sprite trogdor_sprites.png 70 6 76 45 >> trogdor_sprites.inc
$(HGR_SPRITE) -l dashing5_sprite trogdor_sprites.png 84 6 90 45 >> trogdor_sprites.inc
$(HGR_SPRITE) -l dashing6_sprite trogdor_sprites.png 98 6 104 45 >> trogdor_sprites.inc
$(HGR_SPRITE) -l dashing7_sprite trogdor_sprites.png 112 6 118 45 >> trogdor_sprites.inc
$(HGR_SPRITE) -l dashing8_sprite trogdor_sprites.png 126 6 132 45 >> trogdor_sprites.inc
clean:
rm -f *~ inventory_sprites.inc ending_sprites.inc
rm -f *~ inventory_sprites.inc ending_sprites.inc trogdor_sprites.inc

100
games/peasant/ssi263.inc Normal file
View File

@ -0,0 +1,100 @@
;SPEECH_PTRL = $FE
;SPEECH_PTRH = $FF
SSI263_BASE = $40 ; First speech chip
SSI263_DRP = SSI263_BASE+$00 ; Reg0, Duration/Phoneme
SSI263_I = SSI263_BASE+$01 ; Reg1, Inflection
SSI263_RI = SSI263_BASE+$02 ; Reg2, Rate/Inflection
SSI263_CAA = SSI263_BASE+$03 ; Reg3, Control/Articulation/Amplitude
SSI263_F = SSI263_BASE+$04 ; Reg4, Filter Frequency
VIA6522_DDRB1 = $02 ; 6522 Data direction port B register
VIA6522_DDRA1 = $03 ; 6522 Data direction port A register
VIA6522_PCR2 = $8C ; 6522 #2 Peripheral control register
VIA6522_IFR2 = $8D ; 6522 #2 Interrupt flag register
VIA6522_IER2 = $8E ; 6522 #2 Interrupt enable register
VIA6522_IFR2_CA1 = $02
VIA6522_IER2_SET = $80
VIA6522_IER2_CA1 = $02
VIA6522_PCR2_CA2_LOW = $0C
VIA6522_PCR2_CA2_HI = $0E
VIA6522_PCR2_CA1_NEG = $00
VIA6522_PCR2_CA1_POS = $01
SSI263_CAA_CTL = $80 ; control bit
SSI263_DRP_TRANSITIONED_INFLECTION = $C0
SSI263_DRP_PHONEME_TIMING_IMMEDIATE_INFLECTION = $80
SSI263_DRP_FRAME_TIMING_IMMEDIATE_INFLECTION = $40
SSI263_DRP_DISABLE_AR = $00
DURATION_LONG = $00
PHONEME_PAUSE = $00 ; Pause
PHONEME_E = $01 ; mEEt
PHONEME_E1 = $02 ; bEnt
PHONEME_Y = $03 ; bEfore
PHONEME_YI = $04 ; Year
PHONEME_AY = $05 ; plEAse
PHONEME_IE = $06 ; anY
PHONEME_I = $07 ; sIx
PHONEME_A = $08 ; mAde
PHONEME_AI = $09 ; cAre
PHONEME_EH = $0A ; nEst
PHONEME_EH1 = $0B ; bElt
PHONEME_AE = $0C ; dAd
PHONEME_AE1 = $0D ; After
PHONEME_AH = $0E ; gOt
PHONEME_AH1 = $0F ; fAther
PHONEME_AW = $10 ; Office
PHONEME_O = $11 ; stOre
PHONEME_OU = $12 ; bOAt
PHONEME_OO = $13 ; lOOk
PHONEME_IU = $14 ; yOU
PHONEME_IU1 = $15 ; cOUld
PHONEME_U = $16 ; tUne
PHONEME_U1 = $17 ; cartOOn
PHONEME_UH = $18 ; wOnder
PHONEME_UH1 = $19 ; lOve
PHONEME_UH2 = $1A ; whAt
PHONEME_UH3 = $1B ; nUt
PHONEME_ER = $1C ; bIRd
PHONEME_R = $1D ; Roof
PHONEME_R1 = $1E ; Rug
PHONEME_R2 = $1F ; muetteR (German)
PHONEME_L = $20 ; Lift
PHONEME_L1 = $21 ; pLay
PHONEME_LF = $22 ; falL (final)
PHONEME_W = $23 ; Water
PHONEME_B = $24 ; Bag
PHONEME_D = $25 ; paiD
PHONEME_KV = $26 ; taG (glottal stop)
PHONEME_P = $27 ; Pen
PHONEME_T = $28 ; Tart
PHONEME_K = $29 ; Kit
PHONEME_HV = $2A ; (hold vocal)
PHONEME_HVC = $2B ; (hold vocal closure)
PHONEME_HF = $2C ; Heart
PHONEME_HFC = $2D ; (hold frictive closure)
PHONEME_HN = $2E ; (hold nasal)
PHONEME_Z = $2F ; Zero
PHONEME_S = $30 ; Same
PHONEME_J = $31 ; meaSure
PHONEME_SCH = $32 ; SHip
PHONEME_V = $33 ; Very
PHONEME_F = $34 ; Four
PHONEME_THV = $35 ; THere
PHONEME_TH = $36 ; wiTH
PHONEME_M = $37 ; More
PHONEME_N = $38 ; NiNe
PHONEME_NG = $39 ; raNG
PHONEME_CA = $3A ; mAerchen (German)
PHONEME_COH = $3B ; lOwe (French)
PHONEME_CU = $3C ; fUenf (German)
PHONEME_CUH = $3D ; menU (French)
PHONEME_E2 = $3E ; bittE (German)
PHONEME_LB = $3F ; Lube

View File

@ -0,0 +1,243 @@
.include "ssi263.inc"
; Simple speech routine for ssi-263
; to save space we only change the Phoneme/Delay each time, we don't
; mess with the other registers
;========================
; ssi263_write_chip
;========================
ssi263_write_chip:
wc_smc1:
sta $C000,X
rts
;========================
; read_chip
;========================
ssi263_read_chip:
rc_smc1:
lda $C000,X
rts
;========================
; ssi263_speech_init
;========================
; A = slot number of mockingboard
ssi263_speech_init:
sei ; disable interrupts
and #$7
ora #$c0 ; turn slot number into address
sta wc_smc1+2 ; update the read/write routines
sta rc_smc1+2
; Set 6522#2 peripheral control register to recognize the signal
; from the speech chip.
lda #(VIA6522_PCR2_CA2_LOW|VIA6522_PCR2_CA1_NEG)
ldx #VIA6522_PCR2
jsr ssi263_write_chip
lda #<ssi263_speech_irq ; point IRQ handler to our code
sta $3fe
lda #>ssi263_speech_irq
sta $3ff
; set defaults
; filter frequency
lda #$E9
ldx #SSI263_F
jsr ssi263_write_chip
; control / articulation/ amplitude
lda #$5C
ldx #SSI263_CAA
jsr ssi263_write_chip
; rate/inflection
lda #$A8
ldx #SSI263_RI
jsr ssi263_write_chip
; inflection
lda #$50
ldx #SSI263_I
jsr ssi263_write_chip
cli ; enable interrupts
rts
;============================
; ssi263_speech_shutdown
;============================
ssi263_speech_shutdown:
sei
rts
;=========================
; ssi263_speak
;=========================
; pointer to data in SPEECH_PTRL/H
ssi263_speak:
sei ; disable interrupts
; Set the busy flag
lda #$FF
sta speech_busy
; Set peripheral control register to recognize the signal from the
; speech chip.
lda #(VIA6522_PCR2_CA2_LOW|VIA6522_PCR2_CA1_NEG)
ldx #VIA6522_PCR2
jsr ssi263_write_chip
; Set transitioned inflection by setting value while toggling CTL
lda #SSI263_CAA_CTL
ldx #SSI263_CAA
jsr ssi263_write_chip
; Set transitioned inflection mode in register 0
lda #SSI263_DRP_TRANSITIONED_INFLECTION
ldx #SSI263_DRP
jsr ssi263_write_chip
; Lower control bit
lda #$70 ; also T=7
ldx #SSI263_CAA
jsr ssi263_write_chip
; Enable 6522 interrupts
lda #(VIA6522_IER2_SET|VIA6522_IER2_CA1)
ldx #VIA6522_IER2
jsr ssi263_write_chip
cli ; re-enable interrupts
rts
;====================
; speech interrupt
;====================
ssi263_speech_irq:
php ; save flags
cld
pha ; save A
txa
pha ; save X
tya
pha ; save Y
inc $0404 ; irq indicator on screen
; be sure it was a 6522#2 interrupt
ldx #VIA6522_IFR2
jsr ssi263_read_chip
bmi have_interrupt
; wasn't us, return to caller
; this assumes we can handle multiple interrupt sources
jmp end_interrupt
have_interrupt:
; Clear the 6522#2 CA interrupt flag
lda #VIA6522_IFR2_CA1
ldx #VIA6522_IFR2
jsr ssi263_write_chip
; Check if done with speech
ldy #0
lda (SPEECH_PTRL),Y
cmp #$ff
beq speech_end
not_end:
; Set the speech playing flag
lda #$ff
sta speech_playing
ldy #$00
; Get the next data
lda (SPEECH_PTRL),Y
ldx #SSI263_DRP ; duration/phoneme
jsr ssi263_write_chip
; Next data (inc 16 bit)
inc SPEECH_PTRL
bne no_oflo
inc SPEECH_PTRH
no_oflo:
; Finish the interrupt handler
jmp end_interrupt
speech_end:
; If at the end, turn everything off
; Toggle CTL while DR set to disable A/!R
lda #SSI263_CAA_CTL
ldx #SSI263_CAA
jsr ssi263_write_chip
lda #SSI263_DRP_DISABLE_AR
ldx #SSI263_DRP
jsr ssi263_write_chip
; Zero amplitude
lda #$70
ldx #SSI263_CAA
jsr ssi263_write_chip
; Clear busy and playing flags
lda #$00
sta speech_busy
sta speech_playing
; Disable interrupt in 6522
lda #VIA6522_IER2_CA1
ldx #VIA6522_IER2
jsr ssi263_write_chip
end_interrupt:
pla
tay ; restore Y
pla
tax ; restore X
pla ; restore A
interrupt_smc:
lda $45 ; restore A (II+/IIe)
plp ; restore flags
rti ; return from interrupt
speech_busy: .byte $00
speech_playing: .byte $00

View File

@ -13,6 +13,8 @@ trogdor:
lda #0
sta GAME_OVER
jsr setup_speech
jsr hgr_make_tables
jsr HGR2 ; Hi-res graphics, no text at bottom
@ -56,7 +58,23 @@ trogdor_cave:
;==================================
; text to speech, where available!
jsr wait_until_keypress
speech_loop:
; trogdor
lda #<trogdor_honestly
sta SPEECH_PTRL
lda #>trogdor_honestly
sta SPEECH_PTRH
jsr ssi263_speak
wait_for_speech:
lda speech_busy
bmi wait_for_speech
; jsr wait_until_keypress
jsr hgr_partial_restore
@ -254,8 +272,13 @@ peasant_text:
.include "speaker_beeps.s"
.include "ssi263_simple_speech.s"
.include "trogdor_speech.s"
.include "graphics_trogdor/trogdor_graphics.inc"
.include "sprites/trogdor_sprites.inc"
trogdor_string:
.byte 0,43,32, 0,253,82
.byte 8,41

View File

@ -0,0 +1,144 @@
setup_speech:
; jsr HOME
; lda #4 ; assume slot #4 for now
; jsr detect_ssi263
; lda irq_count
; clc
; adc #'A' ; hack to show if detected or not
; sta $400 ; (B is detected, A is not)
lda #4 ; assume slot #4 for now
jsr ssi263_speech_init
rts
;.include "ssi263_detect.s"
;.include "ssi263_simple_speech.s"
; the document
; "Phonetic Speech Dictionary for the SC-01 Speech Synthesizer"
; sc01-dictionary.pdf
; was very helpful here
trogdor_honestly:
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte PHONEME_AH1 ; AH1 ; I
.byte PHONEME_Y ; Y
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte PHONEME_K ; K ; Can
.byte PHONEME_AE1 ; AE1
.byte PHONEME_N ; N
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte PHONEME_AH ; AH ; Honestly
.byte PHONEME_N ; N
.byte PHONEME_EH1 ; EH1
.byte PHONEME_S ; S
.byte PHONEME_T ; T
.byte PHONEME_L ; L
.byte PHONEME_E1 ; E1
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte PHONEME_S ; S ; Say
.byte PHONEME_A ; A
.byte PHONEME_AY ; AY
.byte PHONEME_Y ; Y
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte PHONEME_I ; I1 ; it'll
; .byte PHONEME_I3 ; I3
.byte PHONEME_T ; T
.byte PHONEME_PAUSE ; PA
.byte PHONEME_I ; I
.byte PHONEME_L ; L
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte PHONEME_B ; B ; be
.byte PHONEME_E1 ; E1
.byte PHONEME_Y ; Y
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte PHONEME_A ; A ; A
.byte PHONEME_AY ; AY
.byte PHONEME_Y ; Y
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte PHONEME_P ; P ; pleasure
.byte PHONEME_L ; L
.byte PHONEME_EH1 ; EH1
.byte PHONEME_SCH ; SCH
.byte PHONEME_ER ; ER
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte PHONEME_AE1 ; AE1 ; and
.byte PHONEME_EH ; EH
.byte PHONEME_N ; N
.byte PHONEME_D ; D
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte PHONEME_AE1 ; AE1 ; an
.byte PHONEME_EH ; EH
.byte PHONEME_N ; N
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte PHONEME_AH ; AH ; honor
.byte PHONEME_N ; N
.byte PHONEME_ER ; ER
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte PHONEME_T ; T ; to
.byte PHONEME_IU ; IU
.byte PHONEME_U1 ; U1
.byte PHONEME_U1 ; U1
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte PHONEME_B ; B ; burninate
.byte PHONEME_ER ; ER
.byte PHONEME_R ; R
.byte PHONEME_N ; N
.byte PHONEME_I ; I
.byte PHONEME_N ; N
.byte PHONEME_A ; A
.byte PHONEME_A ; A
.byte PHONEME_Y ; Y
.byte PHONEME_T ; T
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte PHONEME_Y ; Y ; you
.byte PHONEME_IU ; IU
.byte PHONEME_U1 ; U1
.byte PHONEME_U1 ; U1
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA ; ,
.byte PHONEME_R ; R ; Rather
.byte PHONEME_AE1 ; AE1
.byte PHONEME_AE1 ; AE1
.byte PHONEME_EH ; EH
.byte PHONEME_TH ; TH
.byte PHONEME_ER ; ER
.byte PHONEME_R ; R
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte PHONEME_D ; D ; Dashing
.byte PHONEME_AE1 ; AE1
.byte PHONEME_EH ; EH
.byte PHONEME_SCH ; SCH
.byte PHONEME_I ; I
.byte PHONEME_NG ; NG
.byte PHONEME_PAUSE ; PA
.byte PHONEME_PAUSE ; PA
.byte $FF

View File

@ -35,6 +35,8 @@ GAME_OVER = $6C
NEW_LOCATION = $FF
NEW_FROM_DISK = $01
SPEECH_PTRL = $70
SPEECH_PTRH = $71
; pt3 player registers
AY_REGISTERS = $70