From e675b415841449bf38167c3caaeae7c08e895056 Mon Sep 17 00:00:00 2001 From: Christopher Shepherd Date: Sat, 29 Dec 2012 13:48:03 -0500 Subject: [PATCH] initial commit --- README.md | 6 +- libsound.asm | 1526 ++++++++++++++++++++++++++++++++++++++++++++++++++ libsound.h | 53 ++ 3 files changed, 1584 insertions(+), 1 deletion(-) create mode 100644 libsound.asm create mode 100644 libsound.h diff --git a/README.md b/README.md index be2e344..87c829a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ libsoundGS ========== -Apple IIGS sound library \ No newline at end of file +Apple IIGS sound library + +Streams a long-playing song from disk, also supports playing of other one-shot sounds while this is happening. + +Written in ORCA/M assembler, but presents a C stack-based calling interface (was written with the intent of linking to ORCA/C modules). diff --git a/libsound.asm b/libsound.asm new file mode 100644 index 0000000..d3ec2b6 --- /dev/null +++ b/libsound.asm @@ -0,0 +1,1526 @@ +* +* disk streaming sound driver library for ORCA/M Assembler on Apple IIgs +* Christopher Shepherd , July 2007 - May 2012 +* +* 1 infinite-length streaming sound from disk +* up to 8 sounds swapped into DOC RAM on-demand and played simultaneously +* DOC oscillators and DOC RAM are all managed/allocated for you +* good stuff eh? +* + + case on + + keep libsound2 + mcopy libsound.macros + +*DUMMY999 start libsound +* end + +BGSoundStart start + using SGlobals + + tsc + tcs + phd + phb + phk + plb + tcd + + pushword #0000 + pushword #0000 + pushword #429 + pushlong #FilePath + jsl soundPlayStart + + plb + pld + + + + rtl + end + +* +* int soundInit( int MMID ); +* get DOC ready and install MIRQ vector +* carry set if error +* +soundInit start + using SGlobals + +begin equ 1 +* 4-byte temporary variable: for handle deref +HndlRef equ begin +* 4-byte temporary variable: deref'd handle in DP +BuffPtr equ begin+4 + +rtn equ begin+8 +mmid equ rtn+3 +finish equ mmid+2 + +stkAdj equ finish-(rtn+3) +varspace equ rtn-begin + + tsc + sec + sbc #varspace + tcs + phd + phb + phk + plb + tcd + + stz errorFlag + + lda mmid + sta ourMMID + + ldx #$0100 + ldy #0000 + jsr AllocDP + jsr CheckError + bcs siret + stx HndlRef + sty HndlRef+2 + ldy #0002 + lda [HndlRef],y + pha + _SoundStartUp +* bcs siret + + ldx #$2000 + ldy #0000 + jsr AllocDP +* jsr CheckError + bcs siret + stx HndlRef + sty HndlRef+2 + lda [HndlRef] + sta BuffPtr + sta BuffPtrSave + ldy #0002 + lda [HndlRef],y + sta BuffPtr+2 + sta BuffPtrSave+2 + jsr DOCHalt + pushLong #SoundMIRQV + _SetSoundMIRQV + bcs siret + + ldx #$00E1 ; $E1 - oscillator enable? + lda #$00FF ; all registers? + jsr SetDOCReg + +siret tay + + lda rtn+1 + sta rtn+stkAdj+1 + lda rtn + sta rtn+stkAdj + plb + pld + tsc + clc + adc #stkAdj+varspace + tcs + clc + lda errorFlag + beq siret2 + sec +siret2 tya + rtl + end + +* +* int loadOneSound( char *pathname ); +* pathname is gs/os pathname (16-bit length followed by data) +* returns carry set if (GS/OS or MM) error +* otherwise returns sound ID number for use in soundPlayShort +* +loadOneSound start + using SGlobals + +begin equ 1 +hndlref equ begin +buffptr equ hndlref+4 + +rtn equ buffptr+4 +path equ rtn+3 +finish equ path+4 +stkAdj equ finish-path +varspace equ rtn-begin + + tsc + sec + sbc #varspace + tcs + phd + phb + phk + plb + tcd + stz errorFlag +* OpenGS + lda path + sta LOSOPath + lda path+2 + sta LOSOPath+2 + _OpenGS LOSOpenParams + bcc geteof + inc errorFlag + brl losend +* GetEOFGS +geteof lda LOSOHndl + sta LOSEOFHndl + sta LOSReadHndl + sta LOSCloseHndl + _GetEOFGS LOSEOFParams + bcc lalloc + inc errorFlag + brl losend +* Alloc +lalloc ldx LOSEOF + stx LOSReadReq + ldy LOSEOF+2 + sty LOSReadReq+2 + jsr Alloc + bcc lalloc2 + inc errorFlag + jmp losend +lalloc2 stx hndlref + sty hndlref+2 + lda [hndlref] + sta buffptr + sta LOSReadData + ldy #0002 + lda [hndlref],y + sta buffptr+2 + sta LOSReadData+2 +* ReadGS + _ReadGS LOSReadParams + bcc lclose + inc errorFlag + bra losend +* CloseGS +lclose _CloseGS LOSCloseParams + bcc lentry + inc errorFlag + bra losend +* put entry in table +lentry ldx #0000 + txy +lentry2 lda SoundTable,x + bne next + lda SoundTable+2,x + bne next +* found good entry + lda LOSReadData + sta SoundTable,x + lda LOSReadData+2 + sta SoundTable+2,x + lda LOSEOF + sta SoundTable+4,x + lda LOSEOF+2 + sta SoundTable+6,x + +* compute length of sound in pages of $100, and round up +* then store it at the right offset in LengthTbl + phx + tya + asl a + tax + lda LOSEOF + and #$FF00 + xba + inc a + sta LengthTbl,x + plx + + tya + bra losend +next inx + inx + inx + inx + inx + inx + inx + inx + iny + bra lentry2 +* return +losend tay + lda rtn+1 + sta rtn+stkAdj+1 + lda rtn + sta rtn+stkAdj + plb + pld + tsc + clc + adc #stkAdj+varspace + tcs + clc + lda errorFlag + beq losend2 + sec +losend2 tya + rtl + end + + +* +* int soundPlayShort( int soundid, int rate ); +* swap a SHORT (32KB or less) sound into DOC RAM and play it +* int soundid - sound id number from loadOneSound +* int rate - sound playback rate +* int length - length of sound in bytes +* +soundPlayShort start + using SGlobals + +begin equ 1 +length2 equ begin +dataAddr equ begin+2 +oscnum equ dataAddr+4 +docpage equ oscnum+2 +genoffset equ docpage+2 + +rtn equ genoffset+2 +soundid equ rtn+3 +rate equ soundid+2 +finish equ rate+2 +stkAdj equ finish-(rtn+3) +varspace equ rtn-begin + + tsc + sec + sbc #varspace + tcs + phd + phb + phk + plb + tcd + stz errorFlag + +* find an unused generator + ldx #00 +genck lda genmap+2,x + beq found + cmp #$FFFF + beq failed + inx + inx + inx + inx + inx + inx + inx + inx + bra genck +failed inc errorFlag + lda #0900 + brl gh +* don't map it off as used yet, in case there's no ram +* just save the table offset +found stx genoffset + lda genmap,x + sta oscnum + +* find enough free pages in DOC ram to play + lda soundid + asl a + tax + lda LengthTbl,x + tay + ldx #0000 +ramsrch jsr canfit + bcc found2 + inx + cpx #$0080 + bcc ramsrch +* failed + inc errorFlag + lda #0800 + brl gh +* found it +* x = doc page number +found2 stx docpage + jsr markused + +* map generator as used and store info about what's for dinner + ldx genoffset + lda #0001 + sta genmap+2,x + lda docpage + sta genmap+6,x + lda soundid + sta genmap+4,x + +* transfer sound into DOC + asl a + asl a + asl a + tax + lda SoundTable,x + sta dataAddr + lda SoundTable+2,x + sta dataAddr+2 + lda SoundTable+4,x + tay + lda docpage + clc + adc #$80 + xba + jsr PutDOCRAM + +* play it for one shot + lda #00 ; freq low + clc + adc oscnum + tax + lda rate + and #$00FF + jsr SetDOCReg + lda #$20 ; freq hi + clc + adc oscnum + tax + lda rate + xba + and #$00FF + jsr SetDOCReg + lda #$40 ; volume + clc + adc oscnum + tax + lda #$00FF + jsr SetDOCReg + lda #$80 ; addr + clc + adc oscnum + tax + lda #$0080 ; $8000 + clc + adc docpage ; doc page we ended up getting + jsr SetDOCReg + lda #$C0 ; wavetbl + clc + adc oscnum + tax + lda #$003F ; play 32k sound + jsr SetDOCReg + lda #$A0 ; control + clc + adc oscnum + tax + lda #$000A ; one-shot, int enable + jsr SetDOCReg + +* go home +gh tay + lda rtn+1 + sta rtn+stkAdj+1 + lda rtn + sta rtn+stkAdj + plb + pld + tsc + clc + adc #stkAdj+varspace + tcs + clc + lda errorFlag + beq spsend2 + sec +spsend2 tya + rtl + end + +* +* int soundPlayStart( string *path, int rate, int oversample, int echoDelay ); +* begin playing long sound at *path +* oversample = 0 - no oversampling +* oversample = 1 - 2X oversample +* oversample = 2 - 4X oversample +* echoDelay - number of VBLs to desync L/R channels for faux stereo +* carry set if (typically GSOS) error +* +soundPlayStart start + using SGlobals + +begin equ 1 +* 4-byte variable: handle +HndlRef equ begin +* 4-byte variable: deref'd buffer in DP +BuffPtr equ begin+4 +* note that HndlRef isn't used here but the stack frames have to +* match because the same DP vars are used in different internal calls +* and i don't want to ask for DP pages + +rtn equ begin+8 +path equ rtn+3 +rate equ path+4 +osx equ rate+2 +echo equ osx+2 +finish equ echo+2 +stkAdj equ finish-(rtn+3) +varspace equ rtn-begin + + tsc + sec + sbc #varspace + tcs + phd + phb + phk + plb + tcd + + stz errorFlag + +* restore saved buffptr into dp + lda BuffPtrSave + sta BuffPtr + lda BuffPtrSave+2 + sta BuffPtr+2 + +* set rate in DOC params + lda rate + + xba + and #$FF00 + sta RegTbl2 + ora #$0010 + sta RegTbl2+4 + and #$FF00 + ora #$0008 + sta RegTbl2+8 + + lda rate + and #$FF00 + ora #$0020 + sta RegTbl2+2 + and #$FF00 + ora #$0030 + sta RegTbl2+6 + and #$FF00 + ora #$0028 + sta RegTbl2+10 + +* set path in GS/OS params + lda path + sta OPath + lda path+2 + sta OPath+2 + +* set oversampling + lda osx + sta OverSample + +* set echo delay + lda echo + sta EchoDelay + + jsr DOCInit + jsr FileOpen + bcs end1 + jsr FirstDiskRead + bcs end1 + ldy #0000 +pl1 lda RegTbl2,y + cmp #$FFFF + beq pl2 + and #$00FF + tax + lda RegTbl2,y + xba + and #$00FF + jsr SetDOCReg + iny + iny + bra pl1 +pl2 ldx EchoDelay + beq noecho +vbl sep #$20 + longa off +vbl1 lda $E0C019 + bpl vbl1 +vbl2 lda $E0C019 + bpl vbl2 + rep #$20 + longa on + dex + bne vbl +noecho ldx #$00A0 ; A0 - Control 0 + lda #0000 ; 00 - free run, no int, no halt (playing) + jsr SetDOCReg + + stz BadIntCount + stz SndBank + stz EndFlag + + lda #$FFFF + sta IntFlag + lda EndFlag + beq end1 + jsr DOCHalt +end1 tay + lda rtn+1 + sta rtn+stkAdj+1 + lda rtn + sta rtn+stkAdj + plb + pld + tsc + clc + adc #stkAdj+varspace + tcs + clc + lda errorFlag + beq end12 + sec +end12 tya + rtl + end + +* +* int soundMaint( void ); +* call often to keep sound playing +* carry set if error +* +soundMaint start + using SGlobals + +begin equ 1 +HndlRef equ begin +BuffPtr equ HndlRef+4 + +rtn equ begin+8 +finish equ rtn+3 +stkAdj equ 0 +varspace equ rtn-begin + + tsc + sec + sbc #varspace + tcs + phd + phb + phk + plb + tcd + + stz errorFlag + lda BuffPtrSave + sta BuffPtr + lda BuffPtrSave+2 + sta BuffPtr+2 + + lda IntFlag + beq NextChunk +mret tay + lda rtn+1 + sta rtn+stkAdj+1 + lda rtn + sta rtn+stkAdj + plb + pld + tsc + clc + adc #stkAdj+varspace + tcs + clc + lda errorFlag + beq mret2 + sec +mret2 tya + rtl + +NextChunk anop + dec IntFlag + jsr DiskRead + bcs end2 + ldx SndBank + jsr PutSndData + lda SndBank + inc a + cmp #0004 + bne notFour + lda #0000 +notFour sta SndBank + lda IntFlag + bne mret + +* interrupt happened during refilling (too slow!) + inc BadIntCount + lda BadIntCount + cmp #0003 + beq end2 + bra mret + +end2 anop + pha + jsr DOCHalt + jsr CloseFile + pla + bra mret + end + +* +* int soundStop( void ); +* call to stop sound from playing +* carry set, A=errno if error +* +soundStop start + using SGlobals + +rtn equ 1 +stkAdj equ 0 + + tsc + phd + phb + phk + plb + tcd + + stz errorFlag + jsr DOCHalt + jsr CloseFile + + lda rtn+1 + sta rtn+stkAdj+1 + lda rtn + sta rtn+stkAdj + plb + pld + tsc +* don't perform adc #0000 +* clc +* adc #stkAdj + tcs + clc + lda #0000 + rtl + end + +* +* internal subroutines +* + +* halt all DOC voices +DOCHalt start + using SGlobals + + ldx #$00A0 + lda #$0001 +dh jsr SetDOCReg + inx + cpx #$00C0 + bne dh + rts + end + +* read a DOC register +* a = data +* x = register +GetDOCReg start + using SGlobals + + sep #$20 + longa off +busy lda $E1C03C + bmi busy + lda $E100CA + and $0F + sta $E1C03C + txa + sta $E1C03E + lda $E1C03D + lda $E1C03D + rep #$20 + longa on + rts + end + +* set a DOC register +* a = data +* x = register +SetDOCReg start + using SGlobals + + sep #$20 + longa off + pha +busy2 lda $E1C03C + bmi busy2 + lda $E100CA + and $0F + sta $E1C03C + txa + sta $E1C03E + pla + sta $E1C03D + rep #$20 + longa on + rts + end + +* init DOC registers to defaults +DOCInit start + using SGlobals + + sep #$20 + longa off + lda $E100CA + and #$0F + ora #$60 + sta $E1C03C ; DOC RAM, auto-increment + lda #00 + sta $E1C03E + sta $E1C03F ; address $0000 + ldy #00 + lda #$80 +base sta $E1C03D ; put $80 (baseline) into DOC RAM + iny + bne base + rep #$20 + longa on + ldy #0000 +init lda RegTbl1,y + cmp #$FFFF + beq ret + and #$00FF + tax + lda RegTbl1,y + xba + and #$00FF + jsr SetDOCReg + iny + iny + bra init +ret rts + end + +* slam data from buffer into DOC ram +* for short sounds +* $5 - pointer to the data +* a - DOC RAM address (8000,9000,A000, etc) +* x - number of pages perhaps? +* y - length of sample +PutDOCRAM start + using SGlobals + +length equ 1 +BuffPtr equ 3 + + sty length + xba ; $8000 -> $0080 + tax + sep #$20 + longa off + lda $E100CA + and #$0F + ora #$60 ; DOC RAM, auto increment + sta $E1C03C + lda #00 + sta $E1C03E ; address low byte: 00 + txa + sta $E1C03F ; set DOC page + ldy #0000 +sloop2 lda [BuffPtr],y + bne nozero2 + inc a +nozero2 sta $E1C03D + iny + cpy length + bcc sloop2 + lda #00 + sta $E1C03D ; 00 byte for end of sound +ret2 rep #$20 + longa on + rts + end + +* slam data from buffer into DOC ram +* for long sounds / oversampler engine +* 2012/05/05 - New stack-based version, DOESN'T SUPPORT OVERSAMPLING +* a, y - trashed +* $5 - pointer to the data +* x = DOC 4K page number (0,1,2,3) +PutSndData start + using SGlobals + +* you'd better have DP that supports this if you call me +BuffPtr equ 5 + + phb + lda >$000002 ; Save $00/0002 - $00/0000B + pha ; Because it's about to get stomped on + lda >$000004 + pha + lda >$000006 + pha + lda >$000008 + pha + lda BuffPtr + sta >$000002 ; $00/0002 has low word of BuffPtr + lda RTrans + sta >$000004 ; $00/0004 has low word of RTrans + lda RReq + sta >$000006 ; $00/0006 has low word of RReq + tdc + pha ; Keep old DPage Register too + lda #$C000 + tcd ; Direct Page register is now $C000 + tsc + sta >$000008 ; $00/0008 has old stack pointer + sep #$20 + longa off + lda #00 + pha + plb ; Data Bank $00 + rep #$30 + longa on + lda >$000002 + tcs ; Stack pointer at top of sound + sep #$20 + longa off + + lda $E100CA + and #$0F + ora #$60 ; DOC RAM, auto increment + sta $3C + lda #00 + sta $3E ; address low byte: 00 + + txa ; x=0, a=$00 + asl a ; x=1, a=$20 + asl a ; x=2, a=$40 + asl a ; x=3, a=$60 + asl a + asl a + sta $3F ; set DOC page + + ldy |$000004 +sloop pla ; Use the stack, luke! + bne noover + inc a +noover sta $3D + dey + bne sloop + + rep #$20 + longa on + lda >$000004 + cmp >$000006 + beq ret2 + sep #$20 + longa off + stz $3D ; 00 byte for end of sound + rep #$20 + longa on +ret2 lda >$000008 + tcs ; Restore Stack Pointer + pla + tcd ; Restore Direct Page Register + pla + sta >$000008 + pla ; Restore the $00/000x bytes + sta >$000006 ; that we trashed + pla + sta >$000004 + pla + sta >$000002 + plb ; Restore Data Bank + rts + +OverSample2x anop + longa off + cpx #02 + beq OverSample4x + pha + rep #$20 + longa on + clc + adc OSByte2 + lsr a + sep #$20 + longa off + sta $E1C03D + pla + sta OSByte2 + rts + +OverSample4x anop + longa off + pha + rep #$20 + longa on + clc + adc OSByte2 + lsr a + sta OSByte1 + clc + adc OSByte2 + lsr a + sep #$20 + longa off + sta $E1C03D + lda OSByte1 + sta $E1C03D + pla + sta OSByte2 + rep #$20 + longa on + clc + adc OSByte1 + lsr a + sep #$20 + longa off + sta $E1C03D + lda OSByte2 + rts + end + +* Sound MIRQ handler +SoundMIRQV start + using SGlobals + + php + phb + phd + rep #$30 + longa on + phk + plb + ldx #$00E0 ; oscillator interrupt register + jsr GetDOCReg + bit #$0080 ; interrupt? + beq smi1 + and #$003E ; get osc number + lsr a + cmp #0008 ; oscillator8? + bne not8 + stz IntFlag ; clear interrupt flag to show this happened +not8 cmp #0004 + bne not4 + lda #0000 + jsr clearreg + bra smi1 +not4 cmp #12 + bne not12 + lda #0001 + jsr clearreg + bra smi1 +not12 cmp #20 + bne not20 + lda #0002 + jsr clearreg + bra smi1 +not20 cmp #28 + bne smi1 + lda #0003 + jsr clearreg +smi1 ldx #$00A0 ; Control Register 0 + jsr GetDOCReg + and #0001 ; halted? + beq smi2 + + dec EndFlag + + jsr DOCHalt +smi2 pld + plb + plp + clc + rtl + +* mark generator as unused again, and free its managed pages +* a = register offset in genmap table +clearreg anop + asl a + asl a + asl a + tax + phx + lda #0000 + sta genmap+2,x ; mark generator unused + lda genmap+4,x ; sound number currently playing + asl a + tax + lda LengthTbl,x ; length in pages in y + tay + plx + lda genmap+6,x ; offset in x + tax + jsr markfree + rts + end + +* read a chunk from disk +* first time - fill low and high $4000's +FirstDiskRead start + using SGlobals + + lda #0000 + sta SDisp + sta SDisp+2 ; init position to 0 + _SetMarkGS SeekParams + + jsr CheckError + + ldx BuffPtrSave + ldy BuffPtrSave+2 + stx RData + sty RData+2 ; set GSOS to read to our allocated buffer + lda #$2000 + ldx OverSample + beq noOS +OS lsr a ; reduce to $2000 or $1000 if 2x or 4x oversample + dex + bne OS +noOS sta RReq + stz RReq+2 + _ReadGS ReadParams + + jsr CheckError + + ldx #0000 + jsr PutSndData + _ReadGS ReadParams + + jsr CheckError + + ldx #0001 + jsr PutSndData + _ReadGS ReadParams + + jsr CheckError + + ldx #0002 + jsr PutSndData + _ReadGS ReadParams + + jsr CheckError + + ldx #0003 + jsr PutSndData + + clc + rts + end + +* close the soundfile +CloseFile start + using SGlobals + + _CloseGS CloseParams + rts + end + +* just get one chunk from disk +DiskRead start + using SGlobals + + _ReadGS ReadParams + rts + end + +* open the file for reading +FileOpen start + using SGlobals + + _OpenGS OpenParams + + jsr CheckError + + lda OHndl + sta RHndl + sta CHndl + sta GHndl + sta SHndl + _GetEOFGS GetEOFParams + + jsr CheckError + + rts + end + +* Get Memory from the Memory Manager +* x = size lo +* y = size hi +Alloc start + using SGlobals + + pha + pha + phy + phx + pushword ourMMID + pushword #$C000 + pushlong #$000000 + _NewHandle + jsr CheckError + plx + ply + rts + + end +AllocDP start + using SGlobals + + pha + pha + phy + phx + pushword ourMMID + pushword #$C005 + pushlong #$000000 + _NewHandle + jsr CheckError + plx + ply + rts + end +* Check to see if there's room in DOC ram to fix X pages at X offset +* x = page # offset to start searching +* y = length in pages +canfit start + using SGlobals + + phx + phy + txa + asl a + tax +check lda docrammap,x + bne notOK + dey + beq OK + inx + inx + bra check +notOK ply + plx + sec + lda #0700 + rts +OK ply + plx + clc + rts + end + +* mark pages free +* x = offset +* y = pages +markfree start + using SGlobals + + txa + asl a + tax + lda #0000 +mark3 sta docrammap,x + dey + beq done2 + inx + inx + bra mark3 +done2 rts + end + +* mark pages used +* x = offset +* y = pages +markused start + using SGlobals + + txa + asl a + tax + lda #0001 +mark2 sta docrammap,x + dey + beq done + inx + inx + bra mark2 +done rts + end + +* +* Check for toolbox and GS/OS errors +* +CheckError start + using SGlobals + + bcs setFlag + rts + +setFlag inc errorFlag + rts + + end + +* +* Global Variables and such +* + +SGlobals data + +ourMMID dc i2'$00' +BuffPtrSave dc i4'$00' + +errorFlag dc i2'$00' + +RegTbl2 anop + dc i1'$00,$01' ; freq low0 = E3 + dc i1'$20,$02' ; freq high0 = 01 (freq0 = 1E3 or d483) + dc i1'$10,$01' ; freq low16 = E3 + dc i1'$30,$02' ; freq high16 = 01 (freq16 = 1E3 or d483) + dc i1'$08,$01' ; freq low8 = E3 + dc i1'$28,$02' ; freq high8 = 01 (freq8 = 1E3 or d483) + dc i1'$40,$FF' ; volume0 = FF + dc i1'$50,$FF' ; volume16 = FF + dc i1'$48,$00' ; volume8 = 00 + dc i1'$80,$00' ; addr0 = 00 + dc i1'$88,$00' ; addr8 = 00 (formerly 80) + dc i1'$90,$00' ; addr16 = 00 + dc i1'$C0,$3F' ; multi0 = 3F (play 32k sound) + dc i1'$C8,$3D' ; multi8 = 3D (play 32k sound, 1/4 resolution) + dc i1'$D0,$3F' ; multi16 = 3F (play 32k sound) + dc i1'$A0,$01' ; control0 = 01 (free run, halt, no int) + dc i1'$A8,$08' ; control8 = 08 (free run, no halt, int) + dc i1'$B0,$10' ; control16 = 10 (free run, no halt, no int, stereo?) + dc i1'$FF,$FF' ; end of table + +RegTbl1 anop +* 0, 8, and 16 for long sound / oversampler engine + dc i1'$00,$00' ; freq low0 = 00 + dc i1'$20,$08' ; freq hi0 = 08 + dc i1'$10,$00' ; freq low16 = 00 + dc i1'$30,$08' ; freq hi16 = 08 + dc i1'$08,$00' ; freq low8 = 00 + dc i1'$28,$08' ; freq hi8 = 00 + dc i1'$40,$00' ; volume 0 = 00 + dc i1'$50,$00' ; volume 16 = 00 + dc i1'$48,$00' ; volume 8 = 00 + dc i1'$80,$00' ; address low0 = 00 + dc i1'$88,$00' ; address low8 = 00 + dc i1'$90,$00' ; address low16 = 00 + dc i1'$C0,$00' ; wavtbl0 = 00 + dc i1'$C8,$00' ; wavtbl8 = 00 + dc i1'$D0,$00' ; wavtbl16 = 00 + dc i1'$A0,$02' ; control0 = 02 (one shot) + dc i1'$A8,$02' ; control8 = 02 (one shot) + dc i1'$B0,$02' ; control16 = 02 (one shot) +* we use 4, 12, 20, and 28 for the one-shot sounds + dc i1'$04,$00' ; freq low4 = 00 + dc i1'$24,$08' ; freq hi4 = 08 + dc i1'$0C,$00' ; freq low12 = 00 + dc i1'$2C,$08' ; freq hi12 = 08 + dc i1'$14,$00' ; freq low20 = 00 + dc i1'$34,$08' ; freq hi20 = 08 + dc i1'$18,$00' ; freq low28 = 00 + dc i1'$38,$08' ; freq hi28 = 08 + dc i1'$44,$00' ; volume4 = 00 + dc i1'$4C,$00' ; volume12 = 00 + dc i1'$54,$00' ; volume20 = 00 + dc i1'$58,$00' ; volume28 = 00 + dc i1'$84,$00' ; address low4 = 00 + dc i1'$8C,$00' ; address low12 = 00 + dc i1'$94,$00' ; address low20 = 00 + dc i1'$98,$00' ; address low24 = 00 + dc i1'$C4,$00' ; wavtbl4 = 00 + dc i1'$CC,$00' ; wavtbl12 = 00 + dc i1'$D4,$00' ; wavtbl20 = 00 + dc i1'$D8,$00' ; wavtbl28 = 00 + dc i1'$A4,$02' ; control4 = 02 (one shot) + dc i1'$AC,$02' ; control12 = 02 (one shot) + dc i1'$B4,$02' ; control20 = 02 (one shot) + dc i1'$B8,$02' ; control28 = 02 (one shot) +* 6,14,22,30 - 4 more voices for one-shotters + dc i1'$06,$00' ; freq low6 = 00 + dc i1'$26,$08' ; freq hi6 = 08 + dc i1'$0E,$00' ; freq low14 = 00 + dc i1'$2E,$08' ; freq hi14 = 08 + dc i1'$16,$00' ; freq low22 = 00 + dc i1'$36,$08' ; freq hi22 = 08 + dc i1'$1A,$00' ; freq low30 = 00 + dc i1'$3A,$08' ; freq hi30 = 08 + dc i1'$46,$00' ; volume6 = 00 + dc i1'$4E,$00' ; volume14 = 00 + dc i1'$56,$00' ; volume22 = 00 + dc i1'$5A,$00' ; volume30 = 00 + dc i1'$86,$00' ; address low6 = 00 + dc i1'$8E,$00' ; address low14 = 00 + dc i1'$96,$00' ; address low22 = 00 + dc i1'$9A,$00' ; address low30 = 00 + dc i1'$C6,$00' ; wavtbl6 = 00 + dc i1'$CE,$00' ; wavtbl14 = 00 + dc i1'$D6,$00' ; wavtbl22 = 00 + dc i1'$DA,$00' ; wavtbl30 = 00 + dc i1'$A6,$02' ; control6 = 02 (one shot) + dc i1'$AE,$02' ; control14 = 02 (one shot) + dc i1'$B6,$02' ; control22 = 02 (one shot) + dc i1'$BA,$02' ; control30 = 02 (one shot) + dc i1'$FF,$FF' ; end of table + +IntFlag dc i2'$FFFF' +EndFlag dc i2'0000' +EchoDelay dc i2'0000' +SndBank dc i2'0000' +BadIntCount dc i2'0000' +OverSample dc i2'0000' +Length dc i2'0000' +Length2 dc i2'0000' +OSByte1 dc i2'0000' +OSByte2 dc i2'0000' + +OpenParams dc i2'$0002' +OHndl dc i2'0000' +OPath dc a4'FilePath' + +FilePath dosin ':music:thewire.wav' + +ReadParams dc i2'$0004' +RHndl dc i2'0000' +RData dc i2'0000' + dc i2'0000' +RReq dc i2'0000' + dc i2'0000' +RTrans dc i2'0000' + dc i2'0000' + +CloseParams dc i2'$0001' +CHndl dc i2'0000' + +GetEOFParams dc i2'$0002' +GHndl dc i2'0000' +GEOF dc i2'0000' + dc i2'0000' + +SeekParams dc i2'$0003' +SHndl dc i2'0000' +SBase dc i2'0000' +SDisp dc i2'0000' + dc i2'0000' + +LOSOpenParams dc i2'$0002' +LOSOHndl dc i2'0000' +LOSOPath dc i4'0000' + +LOSEOFParams dc i2'$0002' +LOSEOFHndl dc i2'0000' +LOSEOF dc i4'0000' + +LOSReadParams dc i2'$0004' +LOSReadHndl dc i2'0000' +LOSReadData dc i4'0000' +LOSReadReq dc i4'0000' +LOSReadTrans dc i4'0000' + +LOSCloseParams dc i2'$0001' +LOSCloseHndl dc i2'0000' + +* room to hold the pointers to up to 32 sounds loaded into RAM, and their +* lengths in bytes +* hopefully this is more than you ever need + +SoundTable anop +addr0 dc i4'0000,0000' +addr1 dc i4'0000,0000' +addr2 dc i4'0000,0000' +addr3 dc i4'0000,0000' +addr4 dc i4'0000,0000' +addr5 dc i4'0000,0000' +addr6 dc i4'0000,0000' +addr7 dc i4'0000,0000' +addr8 dc i4'0000,0000' +addr9 dc i4'0000,0000' +addr10 dc i4'0000,0000' +addr11 dc i4'0000,0000' +addr12 dc i4'0000,0000' +addr13 dc i4'0000,0000' +addr14 dc i4'0000,0000' +addr15 dc i4'0000,0000' +addr16 dc i4'0000,0000' +addr17 dc i4'0000,0000' +addr18 dc i4'0000,0000' +addr19 dc i4'0000,0000' +addr20 dc i4'0000,0000' +addr21 dc i4'0000,0000' +addr22 dc i4'0000,0000' +addr23 dc i4'0000,0000' +addr24 dc i4'0000,0000' +addr25 dc i4'0000,0000' +addr26 dc i4'0000,0000' +addr27 dc i4'0000,0000' +addr28 dc i4'0000,0000' +addr29 dc i4'0000,0000' +addr30 dc i4'0000,0000' +addr31 dc i4'0000,0000' + +* and now their lengths, in pages +LengthTbl anop +length0 dc i2'0000' +length1 dc i2'0000' +lengthx dc i2'0000' +length3 dc i2'0000' +length4 dc i2'0000' +length5 dc i2'0000' +length6 dc i2'0000' +length7 dc i2'0000' +length8 dc i2'0000' +length9 dc i2'0000' +length10 dc i2'0000' +length11 dc i2'0000' +length12 dc i2'0000' +length13 dc i2'0000' +length14 dc i2'0000' +length15 dc i2'0000' +length16 dc i2'0000' +length17 dc i2'0000' +length18 dc i2'0000' +length19 dc i2'0000' +length20 dc i2'0000' +length21 dc i2'0000' +length22 dc i2'0000' +length23 dc i2'0000' +length24 dc i2'0000' +length25 dc i2'0000' +length26 dc i2'0000' +length27 dc i2'0000' +length28 dc i2'0000' +length29 dc i2'0000' +length30 dc i2'0000' +length31 dc i2'0000' + +* map of DOC RAM in pages of $100 +* 2 bytes each, 32K of ram = $80*2 = $FF +docrammap ds 256 + dc i2'$FFFF,$FFFF' + +* map of DOC generators we're going to manage, and if they're in use +* 2 bytes - generator number +* 2 bytes - in use? 0001 if yet +* 2 bytes - sound currently playing +* 2 bytes - doc ram offset +genmap anop +gen1 dc i2'4,0000,0000,0000' +gen2 dc i2'12,0000,0000,0000' +gen3 dc i2'20,0000,0000,0000' +gen4 dc i2'28,0000,0000,0000' +gen5 dc i2'6,0000,0000,0000' +gen6 dc i2'14,0000,0000,0000' +gen7 dc i2'22,0000,0000,0000' +gen8 dc i2'30,0000,0000,0000' + dc i2'$FFFF,$FFFF' + + end diff --git a/libsound.h b/libsound.h new file mode 100644 index 0000000..fa06e2b --- /dev/null +++ b/libsound.h @@ -0,0 +1,53 @@ +/* + * libsound.h + * + * function prototypes and definitions + */ + +/* + * int soundInit( int MMID ); + * pass Memory Manager ID to soundInit (it will request $4000 bytes with this + * ID) + */ +extern int soundInit( int MMID ); + +/* + * int soundPlayStart( char *path, int rate, int oversample, int echodelay ); + * *path is pathname of sound file to begin playing + * NOTE: *path isn't a c-string, it's a GSOS string (2 byte length+data) + * oversample = 0 for no oversample, 1 for 2X, 2 for 4X + * echodelay is the delay (in VBL intervals) between L and R channels for + * a faux stereo effect + */ +int soundPlayStart( char *path, int rate, int oversample, int echodelay ); + +void BGSoundStart( void ); + +/* + * int soundMaint( void ); + * call this function often to keep the music playing + */ +int soundMaint( void ); + +/* + * int soundStop( void ); + * call this to stop the sound from playing + */ +int soundStop( void ); + +/* + * int soundPlayShort( int soundid, int rate ); + * swap a short (<32KB) sound into available DOC RAM and + * play it on an available generator + * rate is DOC playback rate + * soundid is sound ID returned from loadOneSound(), see next function + */ +int soundPlayShort( int soundid, int rate ); + +/* + * int loadOneSound( char *path ); + * load a sound from disk via GS/OS, allocate RAM for it from MM, + * and return a sound ID to use for future soundPlayShort() calls + * *path is a GS/OS path (16-bit length + data) + */ +int loadOneSound( char *path );