mirror of
https://github.com/dschmenk/PLASMA.git
synced 2025-01-10 06:30:41 +00:00
Get all libraries to build
This commit is contained in:
parent
1f999a86e8
commit
4a033634ad
4
src/inc/fiber.plh
Normal file
4
src/inc/fiber.plh
Normal file
@ -0,0 +1,4 @@
|
||||
import fiber
|
||||
predef fbrInit(numPool), fbrStop(fid)#0, fbrExit#0, fbrStart(defaddr, param)
|
||||
predef fbrYield#0, fbrHalt#0, fbrResume(fid)#0
|
||||
end
|
4
src/inc/portio.plh
Normal file
4
src/inc/portio.plh
Normal file
@ -0,0 +1,4 @@
|
||||
import portio
|
||||
predef digitalRead(pin), portRead, digitalWrite(pin, val)#0
|
||||
predef portWrite(val)#0, analogRead(pin), delay(time)#0
|
||||
end
|
4
src/inc/sndseq.plh
Normal file
4
src/inc/sndseq.plh
Normal file
@ -0,0 +1,4 @@
|
||||
import sndseq
|
||||
predef spkrTone(pitch, duration)#0, spkrPWM(sample, speed, len)#0
|
||||
predef musicPlay(track, rept)#0, musicStop#0, getKey(backgroundProc)#1
|
||||
end
|
@ -1,7 +1,27 @@
|
||||
import spiport
|
||||
const SPI_SLAVE_READY = '@'
|
||||
const SPI_SLAVE_ERROR = '!'
|
||||
const SPI_SLAVE_BUSY = $FF
|
||||
//
|
||||
// Wiring constants for Arduino
|
||||
//
|
||||
const PINHIGH = 1
|
||||
const PINLOW = 0
|
||||
const PINOUTPUT = 1
|
||||
const PININPUT = 0
|
||||
const PINPULLUP = 2
|
||||
//
|
||||
// SPI commands to Wiring functions on Arduino
|
||||
//
|
||||
const CMDPINMODE = 3
|
||||
const CMDDIGREAD = 4
|
||||
const CMDDIGWRITE = 5
|
||||
const CMDANAREAD = 6
|
||||
const CMDANAWRITE = 7
|
||||
//
|
||||
// SPI commands to serial functions on Arduino
|
||||
//
|
||||
const CMDSERMODE = 8
|
||||
const CMDSERAVAIL = 9
|
||||
const CMDSERREAD = 10
|
||||
const CMDSERWRITE = 11
|
||||
predef spiXferByte(outbyte), spiSend(data), spiRecv, spiWriteBuf(buf, len), spiReadBuf(buf, len)
|
||||
predef spiDelay(time), spiReady
|
||||
end
|
||||
|
@ -1,23 +0,0 @@
|
||||
//
|
||||
// Wiring constants for Arduino
|
||||
//
|
||||
const PINHIGH = 1
|
||||
const PINLOW = 0
|
||||
const PINOUTPUT = 1
|
||||
const PININPUT = 0
|
||||
const PINPULLUP = 2
|
||||
//
|
||||
// SPI commands to Wiring functions on Arduino
|
||||
//
|
||||
const CMDPINMODE = 3
|
||||
const CMDDIGREAD = 4
|
||||
const CMDDIGWRITE = 5
|
||||
const CMDANAREAD = 6
|
||||
const CMDANAWRITE = 7
|
||||
//
|
||||
// SPI commands to serial functions on Arduino
|
||||
//
|
||||
const CMDSERMODE = 8
|
||||
const CMDSERAVAIL = 9
|
||||
const CMDSERREAD = 10
|
||||
const CMDSERWRITE = 11
|
@ -268,36 +268,3 @@ export def fbrResume(fid)#0
|
||||
fin
|
||||
end
|
||||
done
|
||||
|
||||
//
|
||||
// Test Fiber library
|
||||
//
|
||||
|
||||
def puth(h)#0
|
||||
word valstr
|
||||
|
||||
valstr = "0123456789ABCDEF"
|
||||
valstr++
|
||||
putc('$')
|
||||
putc(valstr->[(h >> 12) & $0F])
|
||||
putc(valstr->[(h >> 8) & $0F])
|
||||
putc(valstr->[(h >> 4) & $0F])
|
||||
putc(valstr->[ h & $0F])
|
||||
end
|
||||
|
||||
def fbrTest(fid, param)#0
|
||||
byte i
|
||||
|
||||
for i = 1 to param
|
||||
puth(fid); putc($0D)
|
||||
fbrYield
|
||||
next
|
||||
end
|
||||
|
||||
//puts("fbrSwap = "); puth(@fbrSwap); putln
|
||||
fbrInit(4)
|
||||
fbrStart(@fbrTest, 3)
|
||||
fbrStart(@fbrTest, 2)
|
||||
fbrStart(@fbrTest, 1)
|
||||
fbrYield; fbrYield; fbrYield; fbrYield
|
||||
done
|
||||
|
@ -25,7 +25,7 @@ export def portRead
|
||||
return (^FLAG0>>7)&1|(^FLAG1>>6)&2|(^FLAG2>>5)&4|(^FLAG3>>4)&8
|
||||
end
|
||||
|
||||
def digitalWrite(pin, val)#0
|
||||
export def digitalWrite(pin, val)#0
|
||||
ANN0[((pin&3)<<1)+(val&1)]
|
||||
end
|
||||
|
||||
|
838
src/libsrc/sndseq.pla
Executable file
838
src/libsrc/sndseq.pla
Executable file
@ -0,0 +1,838 @@
|
||||
include "inc/cmdsys.plh"
|
||||
include "inc/fileio.plh"
|
||||
include "inc/args.plh"
|
||||
//
|
||||
// Usage is documented following the source in this file...
|
||||
//
|
||||
const rndseed = $004E
|
||||
const LSB = 0
|
||||
const MSB = 1
|
||||
const MB_ARPEGGIO = 4 // In 16ths of a second
|
||||
const MAX_MBCH_NOTES = 9
|
||||
const SPKR_ARPEGGIO = 2 // In 16ths of a second
|
||||
const DUR16TH = 8
|
||||
const MAX_SPKR_NOTES = 4
|
||||
const NOTEDIV = 4
|
||||
//
|
||||
// 6522 VIA registers
|
||||
//
|
||||
struc t_VIA
|
||||
byte IORB // I/O Register B
|
||||
byte IORA // I/O Register A
|
||||
byte DDRB // Data Direction Register B
|
||||
byte DDRA // Data Direction Register A
|
||||
word T1C // Timer 1 Count
|
||||
word T1L // Timer 1 Latch
|
||||
word T2C // Timer 2 Count
|
||||
byte SR // Shift Register
|
||||
byte ACR // Aux Control Register
|
||||
byte PCR // Peripheral Control Register
|
||||
byte IFR // Interrupt Flag Register
|
||||
byte IER // Interrupt Enable Register
|
||||
byte IOA_noHS // I/O Register A - no HandShake
|
||||
end
|
||||
const T1CH = T1C+1
|
||||
//
|
||||
// AY-3-8910 PSG registers
|
||||
//
|
||||
struc t_PSG
|
||||
word AFREQ // A Frequency Period
|
||||
word BFREQ // B Frequency Period
|
||||
word CFREQ // C Frequency Period
|
||||
byte NGFREQ // Noise Generator Frequency Period
|
||||
byte MIXER // Enable=0/Disable=1 NG C(5) B(4) A(3) Tone C(2) B(1) A(0)
|
||||
byte AENVAMP // A Envelope/Amplitude
|
||||
byte BENVAMP // B Envelope/Amplitude
|
||||
byte CENVAMP // C Envelope/Amplitude
|
||||
word ENVPERIOD // Envelope Period
|
||||
byte ENVSHAPE // Envelope Shape
|
||||
end
|
||||
//
|
||||
// Sequence event
|
||||
//
|
||||
struc t_event
|
||||
byte deltatime // Event delta time in 4.4 seconds
|
||||
byte percnote // Percussion:7==0 ? Pitch:4-0 : Octave:6-4,Note:3-0
|
||||
byte perchanvol // Percussion ? EnvDur:7-0 : Channel:7,Volume:3-0
|
||||
end
|
||||
//
|
||||
// Predef routines
|
||||
//
|
||||
predef musicPlay(track, rept)#0
|
||||
predef musicStop#0
|
||||
//
|
||||
// Static sequencer values
|
||||
//
|
||||
word seqTrack, seqEvent, seqTime, eventTime, updateTime, musicSequence
|
||||
byte numNotes, seqRepeat
|
||||
byte indexA[2], indexB[2], indexC[2]
|
||||
byte noteA[2], noteB[2], noteC[2]
|
||||
word notes1[MAX_MBCH_NOTES], notes2[MAX_MBCH_NOTES]
|
||||
word notes[2] = @notes1, @notes2
|
||||
word periods1[MAX_MBCH_NOTES], periods2[MAX_MBCH_NOTES]
|
||||
word periods[2] = @periods1, @periods2
|
||||
//
|
||||
// MockingBoard data.
|
||||
//
|
||||
word[] mbVIAs // Treat this as an array of VIA ptrs
|
||||
word mbVIA1 = -1 // Init to "discover MockingBoard flag" value
|
||||
word mbVIA2 = 0
|
||||
//
|
||||
// Octave basis frequency periods (starting at MIDI note #12)
|
||||
// Notes will be encoded as basis note (LSNibble) and octave (MSNibble))
|
||||
//
|
||||
word[] spkrOctave0 // Overlay and scale mbOctave0 for speaker version
|
||||
word[12] mbOctave0 = 3900, 3681, 3474, 3279, 3095, 2922, 2758, 2603, 2457, 2319, 2189, 2066
|
||||
word[5] arpeggioDuration = DUR16TH, DUR16TH, DUR16TH/2, DUR16TH/3, DUR16TH/4
|
||||
//
|
||||
// Emulators are broken - they only activate the MockingBoard's 6522 Timer1
|
||||
// functionality when interrupts are enabled. This music sequencer is run
|
||||
// in polling mode without the use of MockingBoard interrupts. To work around
|
||||
// the emulators, MockingBoard interrupts are enabled, but the 6502 IRQs are
|
||||
// disabled. NO INTERRUPTS ARE HANDLED WHEN PLAYING MUSIC! The previous state
|
||||
// is restored between playing sequences.
|
||||
//
|
||||
asm vmincs
|
||||
!SOURCE "vmsrc/plvmzp.inc"
|
||||
end
|
||||
asm getStatusReg#1
|
||||
PHP
|
||||
PLA
|
||||
DEX
|
||||
STA ESTKL,X
|
||||
LDA #$00
|
||||
STA ESTKH,X
|
||||
RTS
|
||||
end
|
||||
asm setStatusReg(stat)#0
|
||||
LDA ESTKL,X
|
||||
INX
|
||||
PHA
|
||||
PLP
|
||||
RTS
|
||||
end
|
||||
asm disableInts#0
|
||||
SEI
|
||||
RTS
|
||||
end
|
||||
asm enableInts#0
|
||||
CLI
|
||||
RTS
|
||||
end
|
||||
//
|
||||
// Write Programmable Sound Generator Registers
|
||||
//
|
||||
asm psgWriteTone(pVIA, reg, freq, vol)#0
|
||||
LDA ESTKL+3,X
|
||||
STA TMPL
|
||||
LDA ESTKH+3,X
|
||||
STA TMPH
|
||||
LDY #$01
|
||||
LDA ESTKL+2,X
|
||||
LSR
|
||||
ADC #$08
|
||||
STA (TMP),Y
|
||||
DEY
|
||||
LDA #$07
|
||||
STA (TMP),Y
|
||||
LDA #$04
|
||||
STA (TMP),Y
|
||||
LDA ESTKL,X
|
||||
INY
|
||||
STA (TMP),Y
|
||||
DEY
|
||||
LDA #$06
|
||||
STA (TMP),Y
|
||||
LDA #$04
|
||||
STA (TMP),Y
|
||||
INX
|
||||
BNE +
|
||||
end
|
||||
asm psgWriteWord(pVIA, reg, val)#0
|
||||
LDA ESTKL+2,X
|
||||
STA TMPL
|
||||
LDA ESTKH+2,X
|
||||
STA TMPH
|
||||
+ LDY #$01
|
||||
TYA
|
||||
CLC
|
||||
ADC ESTKL+1,X
|
||||
STA (TMP),Y
|
||||
DEY
|
||||
LDA #$07
|
||||
STA (TMP),Y
|
||||
LDA #$04
|
||||
STA (TMP),Y
|
||||
LDA ESTKH,X
|
||||
INY
|
||||
STA (TMP),Y
|
||||
DEY
|
||||
LDA #$06
|
||||
STA (TMP),Y
|
||||
LDA #$04
|
||||
STA (TMP),Y
|
||||
BNE +
|
||||
end
|
||||
asm psgWrite(pVIA, reg, val)#0
|
||||
LDA ESTKL+2,X
|
||||
STA TMPL
|
||||
LDA ESTKH+2,X
|
||||
STA TMPH
|
||||
+ LDY #$01
|
||||
LDA ESTKL+1,X
|
||||
STA (TMP),Y
|
||||
DEY
|
||||
LDA #$07
|
||||
STA (TMP),Y
|
||||
LDA #$04
|
||||
STA (TMP),Y
|
||||
LDA ESTKL,X
|
||||
INY
|
||||
STA (TMP),Y
|
||||
DEY
|
||||
LDA #$06
|
||||
STA (TMP),Y
|
||||
LDA #$04
|
||||
STA (TMP),Y
|
||||
INX
|
||||
INX
|
||||
INX
|
||||
RTS
|
||||
end
|
||||
//
|
||||
// Apple II speaker tone generator routines
|
||||
//
|
||||
export asm spkrTone(pitch, duration)#0
|
||||
STX ESP
|
||||
LDY ESTKH,X
|
||||
LDA ESTKL,X
|
||||
BEQ +
|
||||
INY
|
||||
+ STA DSTL
|
||||
STY DSTH
|
||||
LDY ESTKH+1,X
|
||||
LDA ESTKL+1,X
|
||||
BEQ +
|
||||
INY
|
||||
+ STA TMPL
|
||||
STY TMPH
|
||||
TAX
|
||||
LDA #$FF
|
||||
PHP
|
||||
SEI
|
||||
;
|
||||
; Total loop count is 32 cycles, regardless of path taken
|
||||
;
|
||||
- NOP ; 2
|
||||
NOP ; 2
|
||||
BCS + ; 3
|
||||
;---
|
||||
;+7 = 12 (from BCS below)
|
||||
+
|
||||
-- SEC ; 2
|
||||
DEX ; 2
|
||||
BNE ++ ; 2/3
|
||||
;----
|
||||
; 6/7
|
||||
|
||||
DEY ; 2
|
||||
BNE +++ ; 2/3
|
||||
;----
|
||||
;+4/5 = 10/11
|
||||
|
||||
BIT $C030 ; 4
|
||||
LDX TMPL ; 3
|
||||
LDY TMPH ; 3
|
||||
;---
|
||||
;+10 = 20
|
||||
|
||||
TONELP SBC #$01 ; 2
|
||||
BCS - ; 2/3
|
||||
;----
|
||||
; 4/5
|
||||
|
||||
DEC DSTL ; 5
|
||||
BNE -- ; 3
|
||||
;----
|
||||
;+8 = 12
|
||||
|
||||
DEC DSTH ; This sequence isn't accounted for
|
||||
BNE -- ; since it is taken only in extreme cases
|
||||
BEQ TONEXIT
|
||||
|
||||
++ NOP ; 2
|
||||
NOP ; 2
|
||||
;---
|
||||
;+4 = 11 (from BNE above)
|
||||
|
||||
+++ BIT $C000 ; 4
|
||||
BMI TONEXIT ; 2
|
||||
BPL TONELP ; 3
|
||||
;---
|
||||
;+9 = 20
|
||||
TONEXIT PLP
|
||||
LDX ESP
|
||||
INX
|
||||
INX
|
||||
RTS
|
||||
end
|
||||
export asm spkrPWM(sample, speed, len)#0
|
||||
STX ESP
|
||||
LDY ESTKH,X
|
||||
LDA ESTKL,X
|
||||
BEQ +
|
||||
INY
|
||||
+ STY DSTH
|
||||
STA DSTL
|
||||
LDA ESTKL+2,X
|
||||
STA SRCL
|
||||
LDA ESTKH+2,X
|
||||
STA SRCH
|
||||
LDY ESTKL+1,X
|
||||
INY
|
||||
STY TMPL
|
||||
LDY #$00
|
||||
PHP
|
||||
SEI
|
||||
- LDA (SRC),Y
|
||||
SEC
|
||||
-- LDX TMPL
|
||||
--- DEX
|
||||
BNE ---
|
||||
SBC #$01
|
||||
BCS --
|
||||
BIT $C030
|
||||
INY
|
||||
BNE +
|
||||
INC SRCH
|
||||
+ DEC DSTL
|
||||
BNE -
|
||||
DEC DSTH
|
||||
BNE -
|
||||
PLP
|
||||
LDX ESP
|
||||
INX
|
||||
INX
|
||||
INX
|
||||
RTS
|
||||
end
|
||||
//
|
||||
// Search slots for MockingBoard
|
||||
//
|
||||
def mbTicklePSG(pVIA)
|
||||
pVIA->IER = $7F // Mask all interrupts
|
||||
pVIA->ACR = $00 // Stop T1 countdown
|
||||
pVIA->DDRB = $FF // Output enable port A and B
|
||||
pVIA->DDRA = $FF
|
||||
pVIA->IORA = $00 // Reset MockingBoard
|
||||
if pVIA->IORA == $00
|
||||
pVIA->IORA = $04 // Inactive MockingBoard control lines
|
||||
if pVIA->IORA == $04
|
||||
//
|
||||
// At least we know we have some sort of R/W in the ROM
|
||||
// address space. Most likely a MockingBoard or John Bell
|
||||
// 6522 board. We will assume its a MockingBoard because
|
||||
// emulators fail the following PSG read test.
|
||||
//
|
||||
//psgWriteWord(pVIA, 2, $DA7E)
|
||||
//if mbReadP(pVIA, 2) == $7E and mbReadP(pVIA, 3) == $0A
|
||||
return pVIA
|
||||
//fin
|
||||
fin
|
||||
fin
|
||||
return 0
|
||||
end
|
||||
def mbSearch(slot)
|
||||
if slot
|
||||
mbVIA1 = mbTicklePSG($C000 + (slot << 8))
|
||||
if mbVIA1
|
||||
mbVIA2 = mbTicklePSG(mbVIA1 + $80)
|
||||
return slot
|
||||
fin
|
||||
else
|
||||
for slot = 1 to 7
|
||||
if slot == 3 or slot == 6
|
||||
continue
|
||||
fin
|
||||
mbVIA1 = mbTicklePSG($C000 + (slot << 8))
|
||||
if mbVIA1
|
||||
mbVIA2 = mbTicklePSG(mbVIA1 + $80)
|
||||
return slot
|
||||
fin
|
||||
next
|
||||
fin
|
||||
return 0
|
||||
end
|
||||
def psgSetup(pVIA)#0
|
||||
psgWrite(pVIA, MIXER, $3F) // Turn everything off
|
||||
psgWrite(pVIA, AENVAMP, $00)
|
||||
psgWrite(pVIA, BENVAMP, $00)
|
||||
psgWrite(pVIA, CENVAMP, $10)
|
||||
psgWrite(pVIA, NGFREQ, $01)
|
||||
psgWriteWord(pVIA, ENVPERIOD, $0001)
|
||||
psgWrite(pVIA, ENVSHAPE, $00) // Single decay
|
||||
psgWriteWord(pVIA, AFREQ, $0000) // Fast response to update
|
||||
psgWriteWord(pVIA, BFREQ, $0000)
|
||||
psgWriteWord(pVIA, CFREQ, $0000)
|
||||
psgWrite(pVIA, MIXER, $38) // Tone on C, B, A
|
||||
end
|
||||
//
|
||||
// Sequence notes through MockingBoard
|
||||
//
|
||||
def mbSequence(yield, func)#0
|
||||
word period, n, yieldTime
|
||||
byte note, volume, channel, i, overflow, status, quit
|
||||
|
||||
//
|
||||
// Reset oscillator table
|
||||
//
|
||||
indexA[0] = 0; indexA[1] = 0
|
||||
indexB[0] = 1; indexB[1] = 1
|
||||
indexC[0] = 2; indexC[1] = 2
|
||||
noteA[0] = 0; noteA[1] = 0
|
||||
noteB[0] = 0; noteB[1] = 0
|
||||
noteC[0] = 0; noteC[1] = 0
|
||||
//
|
||||
// Get the PSGs ready
|
||||
//
|
||||
status = getStatusReg
|
||||
disableInts
|
||||
mbVIA1->ACR = $40 // Continuous T1 interrupts
|
||||
mbVIA1=>T1L = $F9C2 // 16 Ints/sec
|
||||
mbVIA1=>T1C = $F9C2 // 16 Ints/sec
|
||||
mbVIA1->IFR = $40 // Clear interrupt
|
||||
mbVIA1->IER = $C0 // Enable Timer1 interrupt
|
||||
psgSetup(mbVIA1)
|
||||
if mbVIA2; psgSetup(mbVIA2); fin
|
||||
overflow = 0
|
||||
if yield and func
|
||||
yieldTime = seqTime + yield
|
||||
else
|
||||
yieldTime = $7FFF
|
||||
fin
|
||||
updateTime = seqTime
|
||||
quit = FALSE
|
||||
repeat
|
||||
while eventTime == seqTime
|
||||
note = seqEvent->percnote
|
||||
if note & $80
|
||||
//
|
||||
// Note event
|
||||
//
|
||||
volume = seqEvent->perchanvol
|
||||
channel = (volume & mbVIA2.LSB) >> 7 // Clever - mbVIA2.0 will be $80 if it exists
|
||||
if volume & $0F
|
||||
//
|
||||
// Note on
|
||||
//
|
||||
for i = 0 to MAX_MBCH_NOTES-1
|
||||
//
|
||||
// Look for available slot in active note table
|
||||
//
|
||||
if !notes[channel, i].LSB //or notes[channel, i] == note
|
||||
break
|
||||
fin
|
||||
next
|
||||
//
|
||||
// Full note table, kick one out
|
||||
//
|
||||
if i == MAX_MBCH_NOTES
|
||||
i = overflow
|
||||
overflow = (overflow + 1) % MAX_MBCH_NOTES
|
||||
else
|
||||
numNotes++
|
||||
fin
|
||||
notes[channel, i] = note | (volume << 8)
|
||||
periods[channel, i] = mbOctave0[note & $0F] >> ((note >> 4) & $07)
|
||||
else
|
||||
//
|
||||
// Note off
|
||||
//
|
||||
for i = 0 to MAX_MBCH_NOTES-1
|
||||
//
|
||||
// Remove from active note table
|
||||
//
|
||||
if notes[channel, i].LSB == note
|
||||
notes[channel, i] = 0
|
||||
numNotes--
|
||||
break
|
||||
fin
|
||||
next
|
||||
fin
|
||||
updateTime = seqTime
|
||||
else
|
||||
//
|
||||
// Percussion event
|
||||
//
|
||||
period = seqEvent->perchanvol
|
||||
if period
|
||||
if (period & $80)
|
||||
psgWrite(mbVIA1, MIXER, $1C) // NG on C, Tone on B, A
|
||||
psgWrite(mbVIA1, CENVAMP, $10)
|
||||
psgWrite(mbVIA1, ENVSHAPE, (note >> 4) & $04)
|
||||
psgWrite(mbVIA1, NGFREQ, (note >> 1) & $1F)
|
||||
psgWrite(mbVIA1, ENVPERIOD+1, period & $7F)
|
||||
elsif mbVIA2
|
||||
psgWrite(mbVIA2, MIXER, $1C) // NG on C, Tone on B, A
|
||||
psgWrite(mbVIA2, CENVAMP, $10)
|
||||
psgWrite(mbVIA2, ENVSHAPE, (note >> 4) & $04)
|
||||
psgWrite(mbVIA2, NGFREQ, (note >> 1) & $1F)
|
||||
psgWrite(mbVIA2, ENVPERIOD+1, period)
|
||||
fin
|
||||
else
|
||||
if seqRepeat
|
||||
//
|
||||
// Reset sequence
|
||||
//
|
||||
musicPlay(seqTrack, TRUE)
|
||||
seqTime = -1 // Offset seqTime++ later
|
||||
else
|
||||
musicStop
|
||||
fin
|
||||
quit = TRUE // Exit out
|
||||
break
|
||||
fin
|
||||
fin
|
||||
//
|
||||
// Next event
|
||||
//
|
||||
seqEvent = seqEvent + t_event
|
||||
eventTime = seqEvent->deltatime + eventTime
|
||||
loop
|
||||
if updateTime <= seqTime
|
||||
//
|
||||
// Time slice active note tables (arpeggio)
|
||||
//
|
||||
for channel = 0 to 1
|
||||
//
|
||||
// Multiplex oscillator A
|
||||
//
|
||||
i = indexA[channel]
|
||||
repeat
|
||||
i = (i + 3) % MAX_MBCH_NOTES
|
||||
n = notes[channel, i]
|
||||
if n // Non-zero volume
|
||||
break
|
||||
fin
|
||||
until i == indexA[channel]
|
||||
if n.LSB <> noteA[channel]
|
||||
psgWriteTone(mbVIAs[channel], AFREQ, periods[channel, i], n.MSB)
|
||||
noteA[channel] = n.LSB
|
||||
indexA[channel] = i
|
||||
fin
|
||||
//
|
||||
// Multiplex oscillator B
|
||||
//
|
||||
i = indexB[channel]
|
||||
repeat
|
||||
i = (i + 3) % MAX_MBCH_NOTES
|
||||
n = notes[channel, i]
|
||||
if n // Non-zero volume
|
||||
break
|
||||
fin
|
||||
until i == indexB[channel]
|
||||
if n.LSB <> noteB[channel]
|
||||
psgWriteTone(mbVIAs[channel], BFREQ, periods[channel, i], n.MSB)
|
||||
noteB[channel] = n.LSB
|
||||
indexB[channel] = i
|
||||
fin
|
||||
//
|
||||
// Multiplex oscillator C
|
||||
//
|
||||
i = indexC[channel]
|
||||
repeat
|
||||
i = (i + 3) % MAX_MBCH_NOTES
|
||||
n = notes[channel, i]
|
||||
if n // Non-zero volume
|
||||
break
|
||||
fin
|
||||
until i == indexC[channel]
|
||||
if n.LSB <> noteC[channel]
|
||||
psgWrite(mbVIAs[channel], MIXER, $38) // Tone on C, B, A
|
||||
psgWriteTone(mbVIAs[channel], CFREQ, periods[channel, i], n.MSB)
|
||||
noteC[channel] = n.LSB
|
||||
indexC[channel] = i
|
||||
fin
|
||||
next
|
||||
updateTime = seqTime + MB_ARPEGGIO - (numNotes >> 2)
|
||||
fin
|
||||
//
|
||||
// Increment time tick
|
||||
//
|
||||
seqTime++
|
||||
while !(mbVIA1->IFR & $40) // Wait for T1 interrupt
|
||||
if ^$C000 > 127; quit = TRUE; break; fin
|
||||
*rndseed++
|
||||
loop
|
||||
mbVIA1->IFR = $40 // Clear interrupt
|
||||
if yieldTime <= seqTime; func()#0; yieldTime = seqTime + yield; fin
|
||||
until quit
|
||||
psgWrite(mbVIA1, MIXER, $FF) // Turn everything off
|
||||
psgWrite(mbVIA1, AENVAMP, $00)
|
||||
psgWrite(mbVIA1, BENVAMP, $00)
|
||||
psgWrite(mbVIA1, CENVAMP, $00)
|
||||
if mbVIA2
|
||||
psgWrite(mbVIA2, MIXER, $FF)
|
||||
psgWrite(mbVIA2, AENVAMP, $00)
|
||||
psgWrite(mbVIA2, BENVAMP, $00)
|
||||
psgWrite(mbVIA2, CENVAMP, $00)
|
||||
fin
|
||||
mbVIA1->ACR = $00 // Stop T1 countdown
|
||||
mbVIA1->IER = $7F // Mask all interrupts
|
||||
mbVIA1->IFR = $40 // Clear interrupt
|
||||
setStatusReg(status))
|
||||
end
|
||||
//
|
||||
// Sequence notes through Apple II speaker
|
||||
//
|
||||
def spkrSequence(yield, func)#0
|
||||
word period, duration, yieldTime
|
||||
byte note, i, n, overflow
|
||||
|
||||
//
|
||||
// Start sequencing
|
||||
//
|
||||
overflow = 0
|
||||
if yield and func
|
||||
yieldTime = seqTime + yield
|
||||
else
|
||||
yieldTime = $7FFF
|
||||
fin
|
||||
updateTime = seqTime
|
||||
repeat
|
||||
while eventTime == seqTime
|
||||
note = seqEvent->percnote
|
||||
if note & $80
|
||||
//
|
||||
// Note event
|
||||
//
|
||||
if seqEvent->perchanvol & $0F
|
||||
//
|
||||
// Note on
|
||||
//
|
||||
for i = 0 to MAX_SPKR_NOTES-1
|
||||
//
|
||||
// Look for available slot in active note table
|
||||
//
|
||||
if !notes1[i] or note == notes1[i]
|
||||
break
|
||||
fin
|
||||
next
|
||||
if i == MAX_SPKR_NOTES
|
||||
//
|
||||
// Full note table, kick one out
|
||||
//
|
||||
overflow = (overflow + 1) & (MAX_SPKR_NOTES-1)
|
||||
i = overflow
|
||||
elsif !notes1[i]
|
||||
//
|
||||
// Add new note
|
||||
//
|
||||
numNotes++
|
||||
fin
|
||||
notes1[i] = note
|
||||
periods1[i] = spkrOctave0[note & $0F] >> ((note >> 4) & $07)
|
||||
else
|
||||
//
|
||||
// Note off
|
||||
//
|
||||
for i = 0 to MAX_SPKR_NOTES-1
|
||||
//
|
||||
// Remove from active note table
|
||||
//
|
||||
if notes1[i] == note
|
||||
notes1[i] = 0
|
||||
numNotes--
|
||||
break
|
||||
fin
|
||||
next
|
||||
fin
|
||||
else
|
||||
//
|
||||
// Percussion event
|
||||
//
|
||||
if seqEvent->perchanvol
|
||||
//spkrPWM($D000, 0, 64) // Play some random sample as percussion
|
||||
else
|
||||
if seqRepeat
|
||||
musicPlay(seqTrack, TRUE)
|
||||
else
|
||||
musicStop
|
||||
fin
|
||||
return
|
||||
fin
|
||||
fin
|
||||
//
|
||||
// Next event
|
||||
//
|
||||
seqEvent = seqEvent + t_event
|
||||
eventTime = eventTime + seqEvent->deltatime
|
||||
loop
|
||||
if numNotes > 1
|
||||
for i = 0 to MAX_SPKR_NOTES-1
|
||||
if notes1[i]
|
||||
spkrTone(periods1[i], arpeggioDuration[numNotes])
|
||||
fin
|
||||
*rndseed++
|
||||
next
|
||||
seqTime++
|
||||
else
|
||||
period = 0
|
||||
for i = 0 to MAX_SPKR_NOTES-1
|
||||
if notes1[i]
|
||||
period = periods1[i]
|
||||
break;
|
||||
fin
|
||||
*rndseed++
|
||||
next
|
||||
duration = eventTime - seqTime
|
||||
seqTime = duration + seqTime
|
||||
spkrTone(period, DUR16TH * duration)
|
||||
fin
|
||||
if ^$C000 > 127; return; fin
|
||||
if yieldTime <= seqTime; func()#0; yieldTime = seqTime + yield; fin
|
||||
until FALSE
|
||||
end
|
||||
//
|
||||
// No sequence, just waste time and yield
|
||||
//
|
||||
def noSequence(yield, func)#0
|
||||
//
|
||||
// Start wasting time
|
||||
//
|
||||
if !yield or !func
|
||||
yield = 0
|
||||
fin
|
||||
seqTime = 0
|
||||
repeat
|
||||
seqTime++
|
||||
if seqTime < 0; seqTime = 1; fin // Capture wrap-around
|
||||
*rndseed++
|
||||
spkrTone(0, DUR16TH) // Waste 16th of a second playing silence
|
||||
if ^$C000 > 127; return; fin
|
||||
if yield == seqTime; func()#0; seqTime = 0; fin
|
||||
until FALSE
|
||||
end
|
||||
//
|
||||
// Start sequencing music track
|
||||
//
|
||||
export def musicPlay(track, rept)#0
|
||||
byte i
|
||||
|
||||
//
|
||||
// First time search for MockingBoard
|
||||
//
|
||||
if mbVIA1 == -1
|
||||
if !mbSearch(0)
|
||||
//
|
||||
// No MockingBoard - scale octave0 for speaker
|
||||
//
|
||||
for i = 0 to 11
|
||||
spkrOctave0[i] = mbOctave0[i]/NOTEDIV
|
||||
next
|
||||
fin
|
||||
fin
|
||||
//
|
||||
// Zero out active notes
|
||||
//
|
||||
for i = 0 to MAX_MBCH_NOTES-1; notes1[i] = 0; notes2[i] = 0; next
|
||||
for i = 0 to MAX_MBCH_NOTES-1; periods1[i] = 0; periods2[i] = 0; next
|
||||
//
|
||||
// Start sequencing
|
||||
//
|
||||
seqRepeat = rept
|
||||
seqTrack = track
|
||||
seqEvent = seqTrack
|
||||
seqTime = 0
|
||||
eventTime = seqEvent->deltatime
|
||||
numNotes = 0
|
||||
//
|
||||
// Select proper sequencer based on hardware
|
||||
//
|
||||
if mbVIA1
|
||||
musicSequence = @mbSequence
|
||||
else
|
||||
musicSequence = @spkrSequence
|
||||
fin
|
||||
end
|
||||
//
|
||||
// Stop sequencing music track
|
||||
//
|
||||
export def musicStop#0
|
||||
musicSequence = @noSequence
|
||||
end
|
||||
//
|
||||
// Get a keystroke and convert it to upper case
|
||||
//
|
||||
export def getKey(backgroundProc)#1
|
||||
byte key
|
||||
|
||||
while ^$C000 < 128
|
||||
musicSequence($08, backgroundProc)#0 // Call background proc every half second
|
||||
loop
|
||||
key = ^$C000 & $7F
|
||||
^$C010
|
||||
return key
|
||||
end
|
||||
done
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
There are three main externally callable routines in this module:
|
||||
|
||||
musicPlay(trackPtr, trackRepeat)
|
||||
Start playing a track sequence in the getUpperKey routine
|
||||
Params:
|
||||
Pointer to a track sequence created from the cvtmidi.py tool
|
||||
Repeat flag - TRUE or FALSE.
|
||||
The first time its is called, it will try and search for a MockingBoard.
|
||||
However, it is noted that this can cause problems if a Z-80 card is installed.
|
||||
The scanning routine might cause a hang if it encounters a Z-80 card before
|
||||
it finds a MockingBoard. In order to make this robust, it might be best to
|
||||
prompt the user to search for the MockingBoard, enter the actual MockingBoard
|
||||
slot, or skip the MockingBoard and use the internal speaker.
|
||||
|
||||
musicStop()
|
||||
Stop playing a track sequence in the getUpperKey routine
|
||||
The getUpperKey routine will call a dummy sequence routine that will
|
||||
keep the correct timing for any background processing
|
||||
|
||||
getKey()
|
||||
Wait for a keypress and return the character
|
||||
While waiting for the keypress, the track sequence will be played though
|
||||
either the MockingBoard (if present) or the internal speaker. Optionally,
|
||||
a background function can be called periodically based on the sequencer
|
||||
timing, so its pretty accurate.
|
||||
|
||||
The low level internal speaker routines used to generate tones and waveforms
|
||||
can be called for warnings, sound effects, etc:
|
||||
|
||||
spkrTone(period, duration)
|
||||
Play a tone
|
||||
Params:
|
||||
(1020000 / 64 / period) Hz
|
||||
(duration * 32 * 256 / 1020000) seconds
|
||||
|
||||
spkrPWM(samples, speed, len)
|
||||
Play a Pulse Width Modulated waveform
|
||||
Params:
|
||||
Pointer to 8 bit pulse width samples
|
||||
Speed to play through samples
|
||||
Length of sample
|
||||
|
||||
The main routines for sequencing music are:
|
||||
|
||||
mbSequence(yield, func)
|
||||
spkrSequence(yield, func)
|
||||
noSequence(yield, func)
|
||||
|
||||
All three try and provide more functionality than would be present in
|
||||
previous music sequencers. The MockingBoard sequencer will attempt to play up
|
||||
to 9 tones per sound generator (18 if a MockingBoard II is found). Up to
|
||||
four notes will be played simultaneously on the internal speaker. In order
|
||||
to play more notes than the hardware normally supports, a technique using
|
||||
arpeggio (playing multiple notes in a quick sequence rather than concurrently)
|
||||
pulls off this feat. The sequencers will immediately return if a keypress is
|
||||
detected. Finally, during the sequencing, a background function can be periodically
|
||||
called every 'yield' time which has a resolution of a 16th of a second. Pass
|
||||
in zero for 'yield' and/or 'func' to disable any background calls.
|
17
src/makefile
17
src/makefile
@ -23,6 +23,8 @@ CONIO = CONIO\#FE1000
|
||||
SANE = SANE\#FE1000
|
||||
FPSTR = FPSTR\#FE1000
|
||||
FPU = FPU\#FE1000
|
||||
SNDSEQ = SNDSEQ\#FE1000
|
||||
PLAYSEQ = PLAYSEQ\#FE1000
|
||||
SANITY = SANITY\#FE1000
|
||||
RPNCALC = RPNCALC\#FE1000
|
||||
WIZNET = WIZNET\#FE1000
|
||||
@ -49,6 +51,7 @@ TESTLIB = TESTLIB\#FE1000
|
||||
PROFILE = PROFILE\#FE1000
|
||||
MEMMGR = MEMMGR\#FE1000
|
||||
MEMTEST = MEMTEST\#FE1000
|
||||
FIBERTEST = FIBERTEST\#FE1000
|
||||
FIBER = FIBER\#FE1000
|
||||
LONGJMP = LONGJMP\#FE1000
|
||||
PLASM = plasm
|
||||
@ -72,7 +75,7 @@ TXTTYPE = .TXT
|
||||
#SYSTYPE = \#FF2000
|
||||
#TXTTYPE = \#040000
|
||||
|
||||
all: $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM802) $(PLVM03) $(CMD) $(PLASMAPLASM) $(CODEOPT) $(ARGS) $(MEMMGR) $(MEMTEST) $(FIBER) $(LONGJMP) $(ED) $(MON) $(ROD) $(SIEVE) $(UTHERNET2) $(UTHERNET) $(ETHERIP) $(INET) $(DHCP) $(HTTPD) $(ROGUE) $(ROGUEMAP) $(ROGUECOMBAT) $(ROGUEIO) $(HGR1) $(TONE) $(DGR) $(DGRTEST) $(FILEIO) $(CONIO) $(PORTIO) $(SPIPORT) $(SDFAT) $(FATCAT) $(FATGET) $(FATPUT) $(FATWDSK) $(FATRDSK) $(SANE) $(FPSTR) $(FPU) $(SANITY) $(RPNCALC)
|
||||
all: $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM802) $(PLVM03) $(CMD) $(PLASMAPLASM) $(CODEOPT) $(ARGS) $(MEMMGR) $(MEMTEST) $(FIBER) $(FIBERTEST) $(LONGJMP) $(ED) $(MON) $(ROD) $(SIEVE) $(UTHERNET2) $(UTHERNET) $(ETHERIP) $(INET) $(DHCP) $(HTTPD) $(ROGUE) $(ROGUEMAP) $(ROGUECOMBAT) $(ROGUEIO) $(HGR1) $(TONE) $(DGR) $(DGRTEST) $(FILEIO) $(CONIO) $(PORTIO) $(SPIPORT) $(SDFAT) $(FATCAT) $(FATGET) $(FATPUT) $(FATWDSK) $(FATRDSK) $(SANE) $(FPSTR) $(FPU) $(SANITY) $(RPNCALC) $(SNDSEQ) $(PLAYSEQ)
|
||||
|
||||
clean:
|
||||
-rm *FE1000 *FF2000 $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM03)
|
||||
@ -156,6 +159,18 @@ $(FIBER): libsrc/fiber.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AMOW < libsrc/fiber.pla > libsrc/fiber.a
|
||||
acme --setpc 4094 -o $(FIBER) libsrc/fiber.a
|
||||
|
||||
$(FIBERTEST): samplesrc/fibertest.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AMOW < samplesrc/fibertest.pla > samplesrc/fibertest.a
|
||||
acme --setpc 4094 -o $(FIBERTEST) samplesrc/fibertest.a
|
||||
|
||||
$(SNDSEQ): libsrc/sndseq.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AMOW < libsrc/sndseq.pla > libsrc/sndseq.a
|
||||
acme --setpc 4094 -o $(SNDSEQ) libsrc/sndseq.a
|
||||
|
||||
$(PLAYSEQ): samplesrc/playseq.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AMOW < samplesrc/playseq.pla > samplesrc/playseq.a
|
||||
acme --setpc 4094 -o $(PLAYSEQ) samplesrc/playseq.a
|
||||
|
||||
$(LONGJMP): libsrc/longjmp.pla $(PLVM02) $(PLASM)
|
||||
./$(PLASM) -AMOW < libsrc/longjmp.pla > libsrc/longjmp.a
|
||||
acme --setpc 4094 -o $(LONGJMP) libsrc/longjmp.a
|
||||
|
88
src/mkrel
Executable file
88
src/mkrel
Executable file
@ -0,0 +1,88 @@
|
||||
cp CMD#FF2000 prodos/CMD.BIN
|
||||
cp PLASMA.SYSTEM#FF2000 prodos/PLASMA.SYSTEM.SYS
|
||||
cp PLASMA16.SYSTEM#FF2000 prodos/PLASMA16.SYSTEM.SYS
|
||||
|
||||
mkdir prodos/sys
|
||||
cp ARGS#FE1000 prodos/sys/ARGS.REL
|
||||
cp CONIO#FE1000 prodos/sys/CONIO.REL
|
||||
cp DGR#FE1000 prodos/sys/DGR.REL
|
||||
cp DHCP#FE1000 prodos/sys/DHCP.REL
|
||||
cp ED#FE1000 prodos/sys/ED.REL
|
||||
cp ETHERIP#FE1000 prodos/sys/ETHERIP.REL
|
||||
cp FIBER#FE1000 prodos/sys/FIBER.REL
|
||||
cp FILEIO#FE1000 prodos/sys/FILEIO.REL
|
||||
cp FPSTR#FE1000 prodos/sys/FPSTR.REL
|
||||
cp FPU#FE1000 prodos/sys/FPU.REL
|
||||
cp INET#FE1000 prodos/sys/INET.REL
|
||||
cp LONGJMP#FE1000 prodos/sys/LONGJMP.REL
|
||||
cp MEMMGR#FE1000 prodos/sys/MEMMGR.REL
|
||||
cp PORTIO#FE1000 prodos/sys/PORTIO.REL
|
||||
cp SANE#FE1000 prodos/sys/SANE.REL
|
||||
cp SDFAT#FE1000 prodos/sys/SDFAT.REL
|
||||
cp SPIPORT#FE1000 prodos/sys/SPIPORT.REL
|
||||
cp SNDSEQ#FE1000 prodos/sys/SNDSEQ.REL
|
||||
cp UTHERNET#FE1000 prodos/sys/UTHERNET.REL
|
||||
cp UTHERNET2#FE1000 prodos/sys/UTHERNET2.REL
|
||||
cp ../sysfiles/FP6502.CODE#060000 prodos/sys/FP6502.CODE.BIN
|
||||
cp ../sysfiles/ELEMS.CODE#060000 prodos/sys/ELEMS.CODE.BIN
|
||||
|
||||
mkdir prodos/demos
|
||||
cp DGRTEST#FE1000 prodos/demos/DGRTEST.REL
|
||||
cp RPNCALC#FE1000 prodos/demos/RPNCALC.REL
|
||||
cp ROD#FE1000 prodos/demos/ROD.REL
|
||||
|
||||
mkdir prodos/demos/rogue
|
||||
cp ROGUE#FE1000 prodos/demos/rogue/ROGUE.REL
|
||||
cp ROGUECOMBAT#FE1000 prodos/demos/rogue/ROGUECOMBAT.REL
|
||||
cp ROGUEIO#FE1000 prodos/demos/rogue/ROGUEIO.REL
|
||||
cp ROGUEMAP#FE1000 prodos/demos/rogue/ROGUEMAP.REL
|
||||
cp samplesrc/LEVEL0#040000 prodos/demos/rogue/LEVEL0.TXT
|
||||
cp samplesrc/LEVEL1#040000 prodos/demos/rogue/LEVEL1.TXT
|
||||
|
||||
mkdir prodos/demos/sdutils
|
||||
cp FATCAT#FE1000 prodos/demos/sdutils/FATCAT.REL
|
||||
cp FATGET#FE1000 prodos/demos/sdutils/FATGET.REL
|
||||
cp FATPUT#FE1000 prodos/demos/sdutils/FATPUT.REL
|
||||
cp FATREADDSK#FE1000 prodos/demos/sdutils/FATREADDSK.REL
|
||||
cp FATWRITEDSK#FE1000 prodos/demos/sdutils/FATWRITEDSK.REL
|
||||
|
||||
mkdir prodos/demos/net
|
||||
cp HTTPD#FE1000 prodos/demos/net/HTTPD.REL
|
||||
|
||||
mkdir prodos/demos/music
|
||||
cp PLAYSEQ#FE1000 prodos/demos/music/PLAYSEQ.REL
|
||||
cp mockingboard/ultima3.seq prodos/demos/music/ULTIMA3.SEQ.BIN
|
||||
|
||||
mkdir prodos/bld
|
||||
cp PLASM#FE1000 prodos/bld/PLASM.REL
|
||||
cp CODEOPT#FE1000 prodos/bld/CODEOPT.REL
|
||||
cp samplesrc/dgrtest.pla prodos/bld/DGRTEST.PLA.TXT
|
||||
cp samplesrc/hello.pla prodos/bld/HELLO.PLA.TXT
|
||||
cp samplesrc/fibertest.pla prodos/bld/FIBERTEST.PLA.TXT
|
||||
cp samplesrc/mon.pla prodos/bld/MON.PLA.TXT
|
||||
cp samplesrc/memtest.pla prodos/bld/MEMTEST.PLA.TXT
|
||||
cp samplesrc/rod.pla prodos/bld/ROD.PLA.TXT
|
||||
cp samplesrc/sieve.pla prodos/bld/SIEVE.PLA.TXT
|
||||
cp samplesrc/test.pla prodos/bld/TEST.PLA.TXT
|
||||
cp samplesrc/testlib.pla prodos/bld/TESTLIB.PLA.TXT
|
||||
cp samplesrc/playseq.pla prodos/bld/PLAYSEQ.PLA.TXT
|
||||
cp samplesrc/rpncalc.pla prodos/bld/RPNCALC.PLA.TXT
|
||||
|
||||
mkdir prodos/bld/inc
|
||||
cp inc/args.plh prodos/bld/inc/ARGS.PLH.TXT
|
||||
cp inc/cmdsys.plh prodos/bld/inc/CMDSYS.PLH.TXT
|
||||
cp inc/conio.plh prodos/bld/inc/CONIO.PLH.TXT
|
||||
cp inc/dgr.plh prodos/bld/inc/DGR.PLH.TXT
|
||||
cp inc/fiber.plh prodos/bld/inc/FIBER.PLH.TXT
|
||||
cp inc/fileio.plh prodos/bld/inc/FILEIO.PLH.TXT
|
||||
cp inc/fpstr.plh prodos/bld/inc/FPSTR.PLH.TXT
|
||||
cp inc/fpu.plh prodos/bld/inc/FPU.PLH.TXT
|
||||
cp inc/inet.plh prodos/bld/inc/INET.PLH.TXT
|
||||
cp inc/longjmp.plh prodos/bld/inc/LONGJMP.PLH.TXT
|
||||
cp inc/memmgr.plh prodos/bld/inc/MEMMGR.PLH.TXT
|
||||
cp inc/sane.plh prodos/bld/inc/SANE.PLH.TXT
|
||||
cp inc/portio.plh prodos/bld/inc/PORTIO.PLH.TXT
|
||||
cp inc/sdfat.plh prodos/bld/inc/SDFAT.PLH.TXT
|
||||
cp inc/sndseq.plh prodos/bld/inc/SNDSEQ.PLH.TXT
|
||||
cp inc/spiport.plh prodos/bld/inc/SPIPORT.PLH.TXT
|
||||
cp inc/testlib.plh prodos/bld/inc/TESTLIB.PLH.TXT
|
24
src/samplesrc/fibertest.pla
Normal file
24
src/samplesrc/fibertest.pla
Normal file
@ -0,0 +1,24 @@
|
||||
//
|
||||
// Test Fiber library
|
||||
//
|
||||
|
||||
include "inc/cmdsys.plh"
|
||||
include "inc/fiber.plh"
|
||||
|
||||
def fbrTest(fid, param)#0
|
||||
byte i
|
||||
|
||||
for i = 1 to param
|
||||
puth(fid); putc($0D)
|
||||
fbrYield
|
||||
next
|
||||
end
|
||||
|
||||
//puts("fbrSwap = "); puth(@fbrSwap); putln
|
||||
fbrInit(4)
|
||||
fbrStart(@fbrTest, 3)
|
||||
fbrStart(@fbrTest, 2)
|
||||
fbrStart(@fbrTest, 1)
|
||||
fbrYield; fbrYield; fbrYield; fbrYield
|
||||
|
||||
done
|
39
src/samplesrc/playseq.pla
Normal file
39
src/samplesrc/playseq.pla
Normal file
@ -0,0 +1,39 @@
|
||||
include "inc/cmdsys.plh"
|
||||
include "inc/args.plh"
|
||||
include "inc/fileio.plh"
|
||||
include "inc/sndseq.plh"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// These are utility sequences/routines needed to test the music sequencer code.
|
||||
//
|
||||
word arg
|
||||
word ref
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// More utility routines to test the getKey routine
|
||||
//
|
||||
// Sample background process
|
||||
//
|
||||
def backgroundProc#0
|
||||
^$0400++
|
||||
end
|
||||
|
||||
arg = argNext(argFirst)
|
||||
if ^arg
|
||||
ref = fileio:open(arg)
|
||||
if ref
|
||||
fileio:read(ref, heapmark(), heapavail())
|
||||
fileio:close(ref)
|
||||
musicPlay(heapmark(), TRUE)
|
||||
getKey(@backgroundProc)
|
||||
musicStop
|
||||
else
|
||||
puts("File not found.\n")
|
||||
fin
|
||||
fin
|
||||
|
||||
done
|
||||
////////////////////////////////////////////////////////////////////////////////
|
@ -1,7 +1,8 @@
|
||||
include "inc/cmdsys.plh"
|
||||
include "inc/conio.plh"
|
||||
|
||||
import rogueio
|
||||
word rnd, getkb, home, gotoxy, tone
|
||||
word rnd, getkb, tone
|
||||
end
|
||||
import roguemap
|
||||
predef moveplayer
|
||||
@ -138,28 +139,28 @@ export def fight(player, enemy)
|
||||
word p_atck, e_atck
|
||||
|
||||
repeat
|
||||
home()
|
||||
gotoxy(0, 0)
|
||||
conio:home()
|
||||
conio:gotoxy(0, 0)
|
||||
puts(player+name)
|
||||
gotoxy(1, 2)
|
||||
conio:gotoxy(1, 2)
|
||||
puts("Skill :"); puti(player->skill)
|
||||
gotoxy(1, 3)
|
||||
conio:gotoxy(1, 3)
|
||||
puts("Health :"); puti(player->health)
|
||||
gotoxy(1, 4)
|
||||
conio:gotoxy(1, 4)
|
||||
puts("Energy :"); puti(player->energy)
|
||||
gotoxy(20, 0)
|
||||
conio:gotoxy(20, 0)
|
||||
puts(entity[enemy->kind])
|
||||
gotoxy(21, 2)
|
||||
conio:gotoxy(21, 2)
|
||||
puts("Power :"); puti(enemy->power)
|
||||
gotoxy(21, 3)
|
||||
conio:gotoxy(21, 3)
|
||||
puts("Life :"); puti(enemy->life)
|
||||
for e_atck = 0 to 9
|
||||
gotoxy(0, 10 + e_atck)
|
||||
conio:gotoxy(0, 10 + e_atck)
|
||||
puts(@ascii_warrior + e_atck * 11)
|
||||
gotoxy(20, 10 + e_atck)
|
||||
conio:gotoxy(20, 10 + e_atck)
|
||||
puts(ascii_entity[enemy->kind] + e_atck * 11)
|
||||
next
|
||||
gotoxy(12, 8); puts("F)ight or R)un?")
|
||||
conio:gotoxy(12, 8); puts("F)ight or R)un?")
|
||||
if toupper(getkb()) == 'R'
|
||||
return 1
|
||||
else
|
||||
|
@ -1,7 +1,5 @@
|
||||
include "inc/cmdsys.plh"
|
||||
|
||||
const modkeep = $2000
|
||||
const modinitkeep = $4000
|
||||
include "inc/conio.plh"
|
||||
|
||||
byte[] initstr
|
||||
byte = " ( )\n"
|
||||
@ -22,10 +20,7 @@ word titlestr = @initstr
|
||||
// Machine specific routines
|
||||
//
|
||||
|
||||
export word rnd, getkb, home, gotoxy, tone
|
||||
export word open, read, close, newline
|
||||
|
||||
byte noapple1 = "APPLE 1 NOT SUPPORTED."
|
||||
export word rnd, getkb, tone
|
||||
|
||||
const ENV_REG = $FFDF
|
||||
|
||||
@ -35,8 +30,6 @@ const a2rndnum = $4E // ZP location of RND
|
||||
const a2rndl = $4E
|
||||
const a2rndh = $4F
|
||||
|
||||
word iobuff
|
||||
|
||||
word a3rndnum = 12345
|
||||
|
||||
def a3rnd
|
||||
@ -60,7 +53,7 @@ def a2tone(duration, delay)
|
||||
^SPEAKER
|
||||
for i = 0 to delay
|
||||
next
|
||||
duration = duration - 1
|
||||
duration--
|
||||
loop
|
||||
return 0
|
||||
end
|
||||
@ -75,183 +68,41 @@ def a3tone(duration, pitch)
|
||||
return 0
|
||||
end
|
||||
|
||||
//
|
||||
// ProDOS file routines
|
||||
//
|
||||
|
||||
def a2open(path, access)
|
||||
byte params[6]
|
||||
|
||||
params.0 = 3
|
||||
params:1 = path
|
||||
params:3 = heapallocalign($0400, 8, @iobuff)
|
||||
params.5 = 0
|
||||
syscall($C8, @params)
|
||||
return params.5
|
||||
end
|
||||
def a2close(refnum)
|
||||
byte params[2]
|
||||
|
||||
if iobuff
|
||||
heaprelease(iobuff)
|
||||
iobuff = 0
|
||||
fin
|
||||
params.0 = 1
|
||||
params.1 = refnum
|
||||
return syscall($CC, @params)
|
||||
end
|
||||
def a2read(refnum, buff, len)
|
||||
byte params[8]
|
||||
|
||||
params.0 = 4
|
||||
params.1 = refnum
|
||||
params:2 = buff
|
||||
params:4 = len
|
||||
params:6 = 0
|
||||
syscall($CA, @params)
|
||||
return params:6
|
||||
end
|
||||
def a2newline(refnum, emask, nlchar)
|
||||
byte params[4]
|
||||
|
||||
params.0 = 3
|
||||
params.1 = refnum
|
||||
params.2 = emask
|
||||
params.3 = nlchar
|
||||
return syscall($C9, @params)
|
||||
end
|
||||
|
||||
//
|
||||
// SOS file routines
|
||||
//
|
||||
|
||||
def a3open(path, access)
|
||||
byte params[7]
|
||||
|
||||
params.0 = 4
|
||||
params:1 = path
|
||||
params.3 = 0
|
||||
params:4 = @access
|
||||
params.6 = 1
|
||||
syscall($C8, @params)
|
||||
return params.3
|
||||
end
|
||||
def a3close(refnum)
|
||||
byte params[2]
|
||||
|
||||
params.0 = 1
|
||||
params.1 = refnum
|
||||
return syscall($CC, @params)
|
||||
end
|
||||
def a3read(refnum, buff, len)
|
||||
byte params[8]
|
||||
|
||||
params.0 = 4
|
||||
params.1 = refnum
|
||||
params:2 = buff
|
||||
params:4 = len
|
||||
params:6 = 0
|
||||
syscall($CA, @params)
|
||||
return params:6
|
||||
end
|
||||
def a3newline(refnum, emask, nlchar)
|
||||
byte params[4]
|
||||
|
||||
params.0 = 3
|
||||
params.1 = refnum
|
||||
params.2 = $FF
|
||||
params.3 = nlchar
|
||||
return syscall($C9, @params)
|
||||
end
|
||||
|
||||
//
|
||||
// Apple /// console routines
|
||||
//
|
||||
|
||||
def dev_status(devnum, code, list)
|
||||
byte params[5]
|
||||
|
||||
params.0 = 3
|
||||
params.1 = devnum
|
||||
params.2 = code
|
||||
params:3 = list
|
||||
return syscall($82, @params)
|
||||
end
|
||||
def a3keypressed
|
||||
byte count
|
||||
dev_status(cmdsys.devcons, 5, @count)
|
||||
return count
|
||||
end
|
||||
|
||||
def a3getkb
|
||||
while not a3keypressed
|
||||
while not conio:keypressed()
|
||||
a3rndnum = a3rndnum + 123
|
||||
loop
|
||||
return getc()
|
||||
end
|
||||
|
||||
def a3home
|
||||
putc(28)
|
||||
return 0
|
||||
end
|
||||
|
||||
def a3gotoxy(ch, cv)
|
||||
putc(24)
|
||||
putc(ch)
|
||||
putc(25)
|
||||
putc(cv)
|
||||
return 0
|
||||
end
|
||||
|
||||
//
|
||||
// Apple ][ console routines
|
||||
//
|
||||
|
||||
def a2home
|
||||
return call($FC58, 0, 0, 0, 0) // home()
|
||||
end
|
||||
|
||||
def a2gotoxy(x, y)
|
||||
^$24 = x + ^$20
|
||||
return call($FB5B, y + ^$22, 0, 0, 0)
|
||||
end
|
||||
|
||||
//
|
||||
// Set machine specific routines
|
||||
//
|
||||
|
||||
when MACHID & $C8
|
||||
is $08 // Apple 1
|
||||
puts(@noapple1)
|
||||
puts("APPLE 1 NOT SUPPORTED.")
|
||||
return -1
|
||||
is $C0 // Apple ///
|
||||
rnd = @a3rnd
|
||||
getkb = @a3getkb
|
||||
home = @a3home
|
||||
gotoxy = @a3gotoxy
|
||||
tone = @a3tone
|
||||
open = @a3open
|
||||
read = @a3read
|
||||
close = @a3close
|
||||
newline = @a3newline
|
||||
break
|
||||
otherwise // Apple ][
|
||||
rnd = @a2rnd
|
||||
getkb = @a2getkb
|
||||
home = @a2home
|
||||
gotoxy = @a2gotoxy
|
||||
tone = @a2tone
|
||||
open = @a2open
|
||||
read = @a2read
|
||||
close = @a2close
|
||||
newline = @a2newline
|
||||
wend
|
||||
|
||||
//
|
||||
// Print title page
|
||||
//
|
||||
|
||||
home()
|
||||
conio:home()
|
||||
while ^titlestr
|
||||
puts(titlestr)
|
||||
titlestr = titlestr + ^titlestr + 1
|
||||
|
@ -2,13 +2,15 @@
|
||||
// Map module
|
||||
//
|
||||
include "inc/cmdsys.plh"
|
||||
include "inc/conio.plh"
|
||||
include "inc/fileio.plh"
|
||||
|
||||
import rogueio
|
||||
const O_READ = 1
|
||||
const O_WRITE = 2
|
||||
const O_READ_WRITE = 3
|
||||
|
||||
word rnd, getkb, home, gotoxy, tone, open, read, close, newline
|
||||
word rnd, getkb, tone
|
||||
end
|
||||
|
||||
//
|
||||
@ -175,14 +177,14 @@ export def loadmap(level)
|
||||
// Set level map and read it
|
||||
//
|
||||
catacomb[catacomb] = '0' + level
|
||||
mapref = open(@catacomb, O_READ)
|
||||
mapref = fileio:open(@catacomb)
|
||||
if mapref
|
||||
newline(mapref, $7F, $0D)
|
||||
fileio:newline(mapref, $7F, $0D)
|
||||
for row = 1 to maprows - 2
|
||||
l = read(mapref, map + (row << 6) + 1, mapcols)
|
||||
l = fileio:read(mapref, map + (row << 6) + 1, mapcols)
|
||||
^(map + (row << 6) + l) = WALL_TILE
|
||||
next
|
||||
close(mapref)
|
||||
fileio:close(mapref)
|
||||
return TRUE
|
||||
fin
|
||||
return FALSE
|
||||
@ -260,7 +262,7 @@ export def drawmap(xorg, yorg, viewfield, viewdir, lightdist, viewdist)
|
||||
//
|
||||
// Clear screen
|
||||
//
|
||||
home()
|
||||
conio:home()
|
||||
//
|
||||
// Draw background map if in light
|
||||
//
|
||||
@ -302,96 +304,96 @@ export def drawmap(xorg, yorg, viewfield, viewdir, lightdist, viewdist)
|
||||
occluded = 1
|
||||
when o & 7
|
||||
is 0
|
||||
//
|
||||
// Run through lit octant beam points
|
||||
//
|
||||
//
|
||||
// Run through lit octant beam points
|
||||
//
|
||||
for l = 1 to dbeam[lightdist]
|
||||
//
|
||||
// Check parent visiblity
|
||||
//
|
||||
//
|
||||
// Check parent visiblity
|
||||
//
|
||||
if vispix[vbeam[l]]
|
||||
imap = ((yorg - ybeam[l]) << rowshift) + xorg + xbeam[l]
|
||||
tile = ^(map + imap)
|
||||
if tile & OPAQUE_TILE
|
||||
//
|
||||
// The view stops here
|
||||
//
|
||||
//
|
||||
// The view stops here
|
||||
//
|
||||
vispix[l] = 0
|
||||
else
|
||||
//
|
||||
// This tile is transparent
|
||||
//
|
||||
//
|
||||
// This tile is transparent
|
||||
//
|
||||
vispix[l] = 1
|
||||
//
|
||||
// Check adjacent tile for opaqueness - improves wall display
|
||||
//
|
||||
//
|
||||
// Check adjacent tile for opaqueness - improves wall display
|
||||
//
|
||||
adjtile = ^(map + imap + 1) & INV_TILE
|
||||
if adjtile & OPAQUE_TILE
|
||||
^(viewmap + imap + 1) = adjtile | VIEWED_TILE
|
||||
screen.[ycentr-ybeam[l], xcentr+xbeam[l]+1] = adjtile
|
||||
fin
|
||||
fin
|
||||
fin
|
||||
//
|
||||
// Update view
|
||||
//
|
||||
//
|
||||
// Update view
|
||||
//
|
||||
^(viewmap + imap) = tile | VIEWED_TILE
|
||||
if tile <> PIT_TILE
|
||||
if tile <> PIT_TILE
|
||||
screen.[ycentr-ybeam[l], xcentr+xbeam[l]] = tile & INV_TILE
|
||||
fin
|
||||
fin
|
||||
else
|
||||
vispix[l] = 0
|
||||
fin
|
||||
next
|
||||
//
|
||||
// Run through visible octant beam points
|
||||
//
|
||||
//
|
||||
// Run through visible octant beam points
|
||||
//
|
||||
for l = l to dbeam[viewdist]
|
||||
//
|
||||
// Check parent visiblity
|
||||
//
|
||||
//
|
||||
// Check parent visiblity
|
||||
//
|
||||
if vispix[vbeam[l]]
|
||||
imap = ((yorg - ybeam[l]) << rowshift) + xorg + xbeam[l]
|
||||
tile = ^(map + imap)
|
||||
if tile & OPAQUE_TILE
|
||||
//
|
||||
// The view stops here
|
||||
//
|
||||
//
|
||||
// The view stops here
|
||||
//
|
||||
vispix[l] = 0
|
||||
else
|
||||
//
|
||||
// This tile is transparent
|
||||
//
|
||||
//
|
||||
// This tile is transparent
|
||||
//
|
||||
vispix[l] = 1
|
||||
occluded = 0
|
||||
occluded = 0
|
||||
fin
|
||||
//
|
||||
// If the tile is in light, update view
|
||||
//
|
||||
if tile & LIT_TILE
|
||||
//
|
||||
// If the tile is in light, update view
|
||||
//
|
||||
if tile & LIT_TILE
|
||||
^(viewmap + imap) = tile | VIEWED_TILE
|
||||
screen.[ycentr-ybeam[l], xcentr+xbeam[l]] = tile & INV_TILE
|
||||
darkness = 0
|
||||
fin
|
||||
fin
|
||||
else
|
||||
vispix[l] = 0
|
||||
fin
|
||||
//
|
||||
// Advance beam distance
|
||||
//
|
||||
if l == dbeam[dist]
|
||||
if occluded
|
||||
//
|
||||
// Beam fully occluded
|
||||
// Advance beam distance
|
||||
//
|
||||
break
|
||||
fin
|
||||
//
|
||||
// Update distance
|
||||
//
|
||||
if l == dbeam[dist]
|
||||
if occluded
|
||||
//
|
||||
// Beam fully occluded
|
||||
//
|
||||
break
|
||||
fin
|
||||
//
|
||||
// Update distance
|
||||
//
|
||||
occluded = 1
|
||||
dist = dist + 1
|
||||
fin
|
||||
next
|
||||
fin
|
||||
next
|
||||
break
|
||||
is 1
|
||||
for l = 1 to dbeam[lightdist]
|
||||
|
@ -1,4 +1,5 @@
|
||||
include "inc/cmdsys.plh"
|
||||
include "inc/conio.plh"
|
||||
|
||||
import roguemap
|
||||
const xcentr = 20
|
||||
@ -41,7 +42,7 @@ import roguecombat
|
||||
end
|
||||
|
||||
import rogueio
|
||||
word rnd, getkb, home, gotoxy, tone
|
||||
word rnd, getkb, tone
|
||||
end
|
||||
|
||||
const maxlight = 10
|
||||
@ -200,24 +201,24 @@ end
|
||||
//
|
||||
|
||||
def status#0
|
||||
gotoxy(0, statusline)
|
||||
conio:gotoxy(0, statusline)
|
||||
puts(@helthstr)
|
||||
puti(player.health)
|
||||
gotoxy(9, statusline)
|
||||
conio:gotoxy(9, statusline)
|
||||
puts(@enrgystr)
|
||||
puti(player.energy)
|
||||
gotoxy(17, statusline)
|
||||
conio:gotoxy(17, statusline)
|
||||
puts(@oilstr)
|
||||
puti(player:oil/10)
|
||||
gotoxy(25, statusline)
|
||||
conio:gotoxy(25, statusline)
|
||||
puts(@goldstr)
|
||||
puti(player.gold)
|
||||
if player.raft
|
||||
gotoxy(32, statusline)
|
||||
conio:gotoxy(32, statusline)
|
||||
puts(@raftstr)
|
||||
fin
|
||||
if player.key
|
||||
gotoxy(36, statusline)
|
||||
conio:gotoxy(36, statusline)
|
||||
puts(@keystr)
|
||||
fin
|
||||
end
|
||||
@ -461,7 +462,7 @@ def play
|
||||
if player.health == 0
|
||||
return FALSE
|
||||
fin
|
||||
gotoxy(xcentr, ycentr)
|
||||
conio:gotoxy(xcentr, ycentr)
|
||||
when toupper(getkb())
|
||||
is 'I'
|
||||
if totaldarkness
|
||||
@ -598,7 +599,7 @@ def play
|
||||
break
|
||||
is 'X'
|
||||
clearstatus
|
||||
gotoxy(0, statusline)
|
||||
conio:gotoxy(0, statusline)
|
||||
puts(@quitstr)
|
||||
if toupper(getkb()) == 'Y'
|
||||
player.health = 0
|
||||
@ -637,7 +638,7 @@ while loadmap(level)
|
||||
totaldarkness = drawmap(player.xpos, player.ypos, player.fov, player.angle, player.lamp, maxview)
|
||||
if not totaldarkness
|
||||
drawentities
|
||||
gotoxy(xcentr, ycentr)
|
||||
conio:gotoxy(xcentr, ycentr)
|
||||
putc(vplayer[player.angle])
|
||||
fin
|
||||
status
|
||||
@ -647,7 +648,7 @@ while loadmap(level)
|
||||
player.key = 0
|
||||
level = level + 1
|
||||
clearstatus
|
||||
gotoxy(0, statusline)
|
||||
conio:gotoxy(0, statusline)
|
||||
if player.health == 0
|
||||
break
|
||||
fin
|
||||
|
Loading…
x
Reference in New Issue
Block a user