diff --git a/bin/d10_speaker.dsk b/bin/d10_speaker.dsk index 815d89e..514f095 100644 Binary files a/bin/d10_speaker.dsk and b/bin/d10_speaker.dsk differ diff --git a/documentation/AppleIIAsm Library Collection Technical Manual/0.6.0/0.0 Title_to_TOC.md b/documentation/AppleIIAsm Library Collection Technical Manual/0.6.0/0.0 Title_to_TOC.md index 632ebd5..d38c356 100644 --- a/documentation/AppleIIAsm Library Collection Technical Manual/0.6.0/0.0 Title_to_TOC.md +++ b/documentation/AppleIIAsm Library Collection Technical Manual/0.6.0/0.0 Title_to_TOC.md @@ -77,6 +77,7 @@ limitations under the License. - [Disk 7 -- CONVERT Macros](12.0%20quick_reference_d7_mac.convert.md) - [Disk 8 -- LORES Macros](13.0%20quick_reference_d8_mac.lores.md) - [Disk 9 -- HIRES Macros](14.0%20quick_reference_d9_mac.hires.md) + - [Disk 10 -- SPEAKER Macros](15.0%20quick_reference_d10_mac.speaker.md) 7. Detailed References and Source Code Listings - [Disk 1: Required Library and Aliases](30.0%20Detailed_Reference_D1_REQUIRED.md) - [Disk 2: STDIO Macros and Subroutines](31.0%20Detailed_Reference_D2_STDIO.md) @@ -87,6 +88,7 @@ limitations under the License. - [Disk 7: Data Type Conversion Macros and Subroutines](36.0%20Detailed_Reference_D7_CONVERT.md) - [Disk 8: Low Resolution Macros and Subroutines](37.0%20Detailed_Reference_D8_LORES.md) - [Disk 9: High Resolution Macros and Subroutines](38.0%20Detailed_Reference_D9_HIRES.md) + - [Disk 10: Internal Macros and Subroutines](39.0%20Detailed_Reference_D10_SPEAKER.md) 8. Appendices - Supplemental Texts - Further Reference diff --git a/documentation/AppleIIAsm Library Collection Technical Manual/0.6.0/15.0 Quick_Reference_D10_MAC.SPEAKER.md b/documentation/AppleIIAsm Library Collection Technical Manual/0.6.0/15.0 Quick_Reference_D10_MAC.SPEAKER.md index e69de29..b5a7cd4 100644 --- a/documentation/AppleIIAsm Library Collection Technical Manual/0.6.0/15.0 Quick_Reference_D10_MAC.SPEAKER.md +++ b/documentation/AppleIIAsm Library Collection Technical Manual/0.6.0/15.0 Quick_Reference_D10_MAC.SPEAKER.md @@ -0,0 +1,22 @@ +# Disk #10: The Internal Speaker + + + +The Speaker collection contains macros and subroutines for outputting sound on the Apple II internal speaker. Currently, this is limited to square wave notes and song playing, as well as as few standard sound effects. Ideally, future updates will include a subroutine using duty-cycling that is capable of producing elemental "instruments" for a variety of timbres. + + + +| MACRO | DEPENDENCY | PARAMETERS | ACTION | DESTROYS | CYCLES | BYTES | +| ------- | -------------------- | ---------- | --------------------------------------- | -------- | ------ | ----- | +| `STMPO` | `SETTEMPO` | | Set the tempo | NZCV | 240 | 6 | +| `PNOTE` | `PLAYNOTE` `REDTONE` | | Play note in song | NZCV | 172+ | 3 | +| `SSONG` | none | | Set song sequence | NZCV | 48 | 36 | +| `NEXTN` | none | | Advance to next note in song | NZCV | 24 | 17 | +| `PREVN` | none | | Move to previous note in song | NZCV | 28 | 17 | +| `RSTRT` | none | | Restart song index | NZCV | 16 | 12 | +| `FFWRD` | none | | Fast forward a number of notes in song | NZCV | 27 | 19 | +| `REWND` | none | | Rewind a number of notes in song | NZCV | 35 | 25 | +| `PTONE` | `REDTONE` | | Play a non-song tone | NZCV | 220+ | 18 | +| `PFREQ` | `REDTONE` | | Play a non-song frequency | NZCV | 214+ | 15 | +| `PSONG` | `PNOTE` `NEXTN` | | Play an entire song sequence | NZCV | 226+ | 42 | +| `SFX` | `SOUNDFX` | | Play a sound effect from the collection | NZCV | 1962 | 18 | \ No newline at end of file diff --git a/documentation/AppleIIAsm Library Collection Technical Manual/0.6.0/17.0 Quick_Reference_D11_MAC.APPLECHOP.md b/documentation/AppleIIAsm Library Collection Technical Manual/0.6.0/17.0 Quick_Reference_D11_MAC.APPLECHOP.md deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/AppleIIAsm Library Collection Technical Manual/0.6.0/39.0 Detailed_Reference_D10_SPEAKER.md b/documentation/AppleIIAsm Library Collection Technical Manual/0.6.0/39.0 Detailed_Reference_D10_SPEAKER.md new file mode 100644 index 0000000..e22bdbb --- /dev/null +++ b/documentation/AppleIIAsm Library Collection Technical Manual/0.6.0/39.0 Detailed_Reference_D10_SPEAKER.md @@ -0,0 +1,1744 @@ +# Disk 10: SPEAKER + + + +- Part I: The Speaker Collection + - Speaker Components + - Speaker Header File + - REDTONE Subroutine + - SETTEMPO Subroutine + - Speaker Macros and Subroutines + - STMPO + - PNOTE + - PLAYNOTE + - SSONG + - NEXTN + - PREVN + - RSTRT + - FFWRD + - REWND + - PTONE + - PFREQ + - PSONG + - SFX + - SOUNDFX +- Part II: Speaker Collection Demo + + + +--- + + + +# Part I: The Internal Speaker + + + +The Internal Speaker Collection includes macros and subroutines dedicated to manipulating the internal speaker to play music and sound effects. + + + +--- + +## Speaker Components + + + +The Speaker collection contains the following components: + +- A header file that includes hooks, vectors, memory space and subroutines for using the speaker. +- A macro library that includes all of the macros used for manipulating the speaker. +- Subroutines used by the various macros. +- A demonstration file that shows how each macro works. + + + +--- + + + +## Speaker Collection Header File + +| Condition | Value | +| ------------- | ------------------------------------------------------------ | +| Name | File: HEAD.SPEAKER.ASM | +| Type | Header File | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin 8 Pro | +| OS | Apple DOS 3.3 | +| Purpose | Provide appropriate hooks and routines for the Speaker Collection | +| Dependencies | none | +| Bytes | 198 | +| Notes | none | +| See Also | none | + +--- + +*DETAILS* + +The Speaker header file contains various hooks, vectors, memory space and subroutines for manipulating the Apple II internal speaker. This file is required for inclusion in the main executable whenever a subroutine or macro from the speaker collection is used. + + + +`LISTING 10.00: HEAD.SPEAKER.ASM Source (first part)` + +```assembly +* +*``````````````````````````````* +* HEAD.SPEAKER.ASM * +* * +* THIS HEADER FILE HOLDS A * +* NUMBER OF DIFFERENT HOOKS, * +* VECTORS, SUBROUTINES AND * +* MEMORY LOCATIONS FOR USE BY * +* THE SPEAKER COLLECTION. * +* * +* MANY OF THESE INDIRECTLY * +* COME FROM DON LANCASTER'S * +* /ASSEMBLY COOKBOOK FOR THE * +* APPLE II/IIE/ AND THE FAMOUS * +* RED BOOK. * +* * +* AUTHOR: NATHAN RIGGS * +* CONTACT: NATHAN.RIGGS@ * +* OUTLOOK.COM * +* * +* DATE: 03-JUN-2021 * +* ASSEMBLER: MERLIN 8 PRO * +* OS: DOS 3.3 * +* * +* SIZE: 198 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +SPKR EQU $C030 ; SPEAKER SOFT SWITCH +TAPEOUT EQU $C020 ; TAPE OUT SOFT SWITCH; UNUSED IN IIE +NWAIT EQU $FCA8 ; MONITOR WAIT SUBROUTINE +* +** THE FOLLOWING IS A LIST OF INDICES FOR +** EACH NOTE IN THE NOTE TABLE. +* +NIND_END EQU 000 ; END OF SONG, USE TWICE +NIND_A1 EQU 001 ; NOTE A BELOW MID C +NIND_A1S EQU 002 ; A# +NIND_B1F EQU 003 ; B FLAT +NIND_B1 EQU 004 ; B +NIND_C1 EQU 005 ; C +NIND_C1S EQU 006 ; C# +NIND_D1F EQU 007 ; D FLAT +NIND_D1 EQU 008 ; D +NIND_D1S EQU 009 ; D# +NIND_E1F EQU 010 ; E FLAT +NIND_E1 EQU 011 ; E +NIND_F1 EQU 012 ; F +NIND_F1S EQU 013 ; F# +NIND_G1F EQU 014 ; G FLAT +NIND_G1 EQU 015 ; G +NIND_G1S EQU 016 ; G# +NIND_A1F EQU 017 ; A FLAT +NIND_A2 EQU 018 ; NOTE A ABOVE MID C +NIND_A2S EQU 019 ; A# +NIND_B2F EQU 020 ; B FLAT +NIND_B2 EQU 021 ; B +NIND_C2 EQU 022 ; C +NIND_C2S EQU 023 ; C# +NIND_D2F EQU 024 ; D FLAT +NIND_D2 EQU 025 ; D +NIND_D2S EQU 026 ; D# +NIND_E2F EQU 027 ; E FLAT +NIND_E2 EQU 028 ; E +NIND_F2 EQU 029 ; F +NIND_F2S EQU 030 ; F# +NIND_G2F EQU 031 ; G FLAT +NIND_G2 EQU 032 ; G +NIND_G2S EQU 033 ; G# +NIND_A2F EQU 034 ; A FLAT +NIND_A3 EQU 035 ; SECOND A ABOVE MID C +NIND_R EQU 036 ; SILENT OR REST +* +** THE FOLLOWING IS A LIST OF INDICES TO +** THE NOTE DURATIONS IN THE DURATION TABLE +* +DIND_64 EQU 00 ; 64TH NOTE +DIND_32 EQU 01 ; 32ND NOTE +DIND_16 EQU 02 ; 16TH NOTE +DIND_D16 EQU 03 ; DOTTED 16TH +DIND_8 EQU 04 ; 8TH NOTE +DIND_D8 EQU 05 ; DOTTED 8TH +DIND_4 EQU 06 ; 1/4 NOTE +DIND_D4 EQU 07 ; DOTTED 1/4 +DIND_H EQU 08 ; HALF NOTE +DIND_DH EQU 09 ; DOTTED HALF NOTE +DIND_W EQU 10 ; WHOLE NOTE +* + JMP _SKIPSPKR +* +** THE FOLLOWING TABLE OF NOTES STORES THE +** "MAGIC" NUMBERS FOR EACH NOTE FREQUENCY +* +NOTETBL +* +NOTE_END DFB $00 ; {0C1B} END OF SONG, USE TWICE +NOTE_A1 DFB 232 ; {0C1B} NOTE A BELOW MID C +NOTE_A1S DFB 219 ; {0C1B} A# +NOTE_B1F DFB 219 ; {0C1B} B FLAT +NOTE_B1 DFB 207 ; {0C1B} B +NOTE_C1 DFB 195 ; {0C1B} C +NOTE_C1S DFB 184 ; {0C1B} C# +NOTE_D1F DFB 184 ; {0C1B} D FLAT +NOTE_D1 DFB 174 ; {0C1B} D +NOTE_D1S DFB 164 ; {0C1B} D# +NOTE_E1F DFB 164 ; {0C1B} E FLAT +NOTE_E1 DFB 155 ; {0C1B} E +NOTE_F1 DFB 146 ; {0C1B} F +NOTE_F1S DFB 138 ; {0C1B} F# +NOTE_G1F DFB 138 ; {0C1B} G FLAT +NOTE_G1 DFB 130 ; {0C1B} G +NOTE_G1S DFB 123 ; {0C1B} G# +NOTE_A1F DFB 123 ; {0C1B} A FLAT +NOTE_A2 DFB 116 ; {0C1B} NOTE A ABOVE MID C +NOTE_A2S DFB 110 ; {0C1B} A# +NOTE_B2F DFB 110 ; {0C1B} B FLAT +NOTE_B2 DFB 103 ; {0C1B} B +NOTE_C2 DFB 98 ; {0C1B} C +NOTE_C2S DFB 92 ; {0C1B} C# +NOTE_D2F DFB 92 ; {0C1B} D FLAT +NOTE_D2 DFB 87 ; {0C1B} D +NOTE_D2S DFB 82 ; {0C1B} D# +NOTE_E2F DFB 82 ; {0C1B} E FLAT +NOTE_E2 DFB 78 ; {0C1B} E +NOTE_F2 DFB 73 ; {0C1B} F +NOTE_F2S DFB 69 ; {0C1B} F# +NOTE_G2F DFB 69 ; {0C1B} G FLAT +NOTE_G2 DFB 65 ; {0C1B} G +NOTE_G2S DFB 61 ; {0C1B} G# +NOTE_A2F DFB 61 ; {0C1B} A FLAT +NOTE_A3 DFB 58 ; {0C1B} SECOND A ABOVE MID C +NOTE_R DFB $FF ; {0C1B} SILENT OR REST +* +** THE FOLLOWING TABLE HOLDS THE DURATION +** VALUES FOR A NOTE. THESE ARE SET BY THE +** SETTEMPO SUBROUTINE. +* +DURTBL +* +DUR_64 DFB 02 ; {0C1B} 64TH NOTE -- TEMPO / 4 +DUR_32 DFB 04 ; {0C1B} 32ND NOTE -- TEMPO / 2 +DUR_16 DFB 09 ; {0C1B} 16TH NOTE -- TEMP0 * 1 +DUR_D16 DFB 13 ; {0C1B} DOTTED 16TH -- S/2+S +DUR_8 DFB 18 ; {0C1B} 8TH NOTE -- TEMPO * 2 +DUR_D8 DFB 24 ; {0C1B} DOTTED 8TH -- TEMPO * 3 +DUR_4 DFB 32 ; {0C1B} 1/4 NOTE -- TEMPO * 4 +DUR_D4 DFB 54 ; {0C1B} DOTTED 1/4 -- TEMPO * 6 +DUR_H DFB 72 ; {0C1B} HALF NOTE -- TEMPO * 8 +DUR_DH DFB 108 ; {0C1B} DOTTED HALF NOTE -- TEMPO * 12 +DUR_W DFB 144 ; {0C1B} WHOLE NOTE -- TEMPO * 16 +* +TEMPO DFB $09 ; {0C1B} MASTER TEMPO CONTROL ($0F MAX) +TEMPMUL DFB $80 ; {0C1B} TEMPO MULT (00=X1 $80=X2 $40=X4) +NPAUSE DFB $48 ; {0C1B} INTERNOTE PAUSE TIME +* +** THE FOLLOWING ARE USED BY THE REDTONE PLAYER. +** THESE ARE SET BEFORE PLAYING EACH NOTE. +* +NOTEP DFB 00,00 ; {0C2B} CURRENT ADDRESS IN SONG +DURAT DFB $72 ; {0C1B} DURATION GOES HERE +DURCNT DFB $72 ; {0C1B} GETS COUNTED HERE +DURMUL DFB $80 ; {0C1B} DURATION MULTIPLIER +PITCH DFB $72 ; {0C1B} PITCH GOES HERE +* +SONGLOC DFB 00,00 ; {0C2B} LOW,HIGH OF SONG ADDRESS +* +``` + + + +--- + + + +### The REDTONE Subroutine + +_SUMMARY_ + +| Condition | Value | +| --------------- | ------------------------------------------------------------ | +| Name | `REDTONE` | +| Type | Subroutine | +| File | HEAD.SPEAKER.ASM | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin Pro 8 | +| OS | Apple DOS 3.3 | +| Purpose | Play a square wave tone | +| Input | PITCH = Tone pitch
DURAT = Tone duration
DURMUL = Duration multiplier | +| Output | none | +| Dependencies | none | +| Flags Destroyed | NZCV | +| Cycles | 194+ | +| Bytes | 51 | +| Notes | none | +| See Also | none | + +--- + +*DETAILS* + +The `REDTONE` subroutine is so tried and true that this version is basically ripped straight from the pages of Don Lancaster's *Assembly Cookbook for the Apple II/Apple IIe*. In turn, this was mostly taken from the REDBOOK manual for the Apple II. + +The subroutine assumes that PITCH, DURAT and DURMUL have already been set, and proceeds to play the tone specified at the given duration. DURMUL can be used to slow down or speed up the duration by a constant factor. + + + +```assembly +* +*``````````````````````````````* +* REDTONE * +* * +* PLAY A SQUARE WAVE AT THE * +* GIVEN FREQUENCY AND FOR A * +* GIVEN DURATION. NOTE THAT * +* THIS IS A VERY COMMON * +* SUBROUTINE, AND I DID NOT * +* WRITE IT. THIS COMES FROM * +* THE FAMOUS APPLE II REDBOOK, * +* WITH SOME MINOR MODIFICATION * +* BY DON LANCASTER. * +* * +* INPUT * +* * +* NONE * +* * +* DESTROY: NZCIDV * +* ^^^ ^ * +* * +* CYCLES: 194+ * +* SIZE: 51 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +REDTONE PHA ; {3C1B} SAVE REGISTERS + TYA ; {2C1B} + PHA ; {3C1B} + TXA ; {2C1B} + PHA ; {3C1B} + LDA DURAT ; {4C3B} MOVE DURATION VALUE TO + STA DURCNT ; {4C3B} COUNTABLE LOCATION + LDY #$00 ; {3C2B} INIT FAST DURATION COUNTER + TYA ; {2C1B} INIT DURATION MULTIPLIER +:WHAP LDX PITCH ; {4C3B} GET PITCH VALUE + CPX #$FF ; {3C2B} IS IT SILENT? + BEQ :LOCKX ; {3C2B} YES, KEEP IT SILENT + BIT SPKR ; {3C2B} WHAP SPEAKER +:NOWHAP DEY ; {2C1B} DECREMENT FAST DURATION COUNT + BNE :NOC5 ; {3C2B} IF NO BORROW + CLC ; {2C1B} + ADC DURMUL ; {4C3B} DURATION MULTIPLIER + BNE :NOC5 ; {3C2B} IGNORE ALL BUT ZERO RESULTS + DEC DURCNT ; {6C3B} DECREMENT SLOW DURATION + BEQ :EXITRED ; {3C2B} IF FINISHED +:NOC5 DEX ; {2C1B} DECREMENT PITCH VALUE + BNE :NOWHAP ; {3C2B} PITCH NOT DONE + BEQ :WHAP ; {3C2B} PITCH DONE, ALWAYS TAKEN +:LOCKX INX ; {2C1B} TRAP X TO $FF + BEQ :NOWHAP ; {3C2B} ALWAYS TAKEN +:EXITRED PLA ; {3C1B} RESTORE REGISTERS + TAX ; {2C1B} + PLA ; {3C1B} + TAY ; {2C1B} + PLA ; {3C1B} + RTS ; {6C1B} AND EXIT +* +``` + + + +--- + +### The SETTEMPO Subroutine + +_SUMMARY_ + +| Condition | Value | +| --------------- | ------------------------------------- | +| Name | `SETTEMPO` | +| Type | Subroutine | +| File | HEAD.SPEAKER.ASM | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin Pro 8 | +| OS | Apple DOS 3.3 | +| Purpose | Set the song tempo and note durations | +| Input | .A = Tempo | +| Output | none | +| Dependencies | none | +| Flags Destroyed | NZCV | +| Cycles | 230 | +| Bytes | 84 | +| Notes | none | +| See Also | none | + +--- + +*DETAILS* + +The `SETTEMPO` subroutine sets the song tempo, altering the note durations appropriately. The tempo is passed via the .A register. + + + +`LISTING 10:01: The SETTEMPO Subroutine (and end of header)` + +```assembly +* +*``````````````````````````````* +* SETTEMPO * +* * +* SETS THE TEMPO, INCLUDING * +* ALTERING THE DURATIONS OF * +* NOTES. * +* * +* INPUT: * +* * +* .A = TEMPO * +* * +* DESTROY: NZCIDV * +* ^^^ ^ * +* * +* CYCLES: 230 * +* SIZE: 84 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +SETTEMPO + STA TEMPO ; {4C3B} STORE TEMPO + LSR ; {2C1B} DIVIDE BY TWO + STA DUR_32 ; {4C3B} = TEMPO / 2 + LSR ; {2C1B} DIVIDE BY 2 AGAIN + STA DUR_64 ; {4C3B} = TEMPO / 4 + LDA TEMPO ; {4C3B} + STA DUR_16 ; {4C3B} = TEMPO + LSR ; {2C1B} DIV BY 2 + CLC ; {2C1B} + ADC TEMPO ; {4C3B} ADD 16TH + STA DUR_D16 ; {4C3B} = 1.5 * 16TH + LDA TEMPO ; {4C3B} + ASL ; {2C1B} MUL BY 2 + STA DUR_8 ; {4C3B} = TEMPO * 2 + LSR ; {2C1B} DIV BY 2 + CLC ; {2C1B} + ADC DUR_8 ; {4C3B} ADD 8TH + STA DUR_D8 ; {4C3B} = 1.5 * 8TH + LDA TEMPO ; {4C3B} + ASL ; {2C1B} MUL BY 2 + ASL ; {2C1B} BY 4 + STA DUR_4 ; {4C3B} = TEMPO * 4 + LSR ; {2C1B} DIV BY 2 + CLC ; {2C1B} + ADC DUR_4 ; {4C3B} ADD 1/4 NOTE + STA DUR_D4 ; {4C3B} = 1.5 * 1/4TH NOTE + LDA TEMPO ; {4C3B} + ASL ; {2C1B} MUL BY TWO + ASL ; {2C1B} BY 4 + ASL ; {2C1B} BY 8 + STA DUR_H ; {4C3B} = TEMPO * 8 + LSR ; {2C1B} DIV BY 2 + CLC ; {2C1B} + ADC DUR_H ; {4C3B} ADD HALF NOTE + STA DUR_DH ; {4C3B} = 1.5 * HALF NOTE + LDA TEMPO ; {4C3B} + ASL ; {2C1B} MUL BY 2 + ASL ; {2C1B} BY 4 + ASL ; {2C1B} BY 8 + ASL ; {2C1B} BY 16 + STA DUR_W ; {4C3B} = TEMPO * 16 + RTS ; {6C1B} +* +_SKIPSPKR +* +``` + + + +--- + + + +## SPEAKER Macros and Subroutines + + + +The MAC.SPEAKER.ASM file contains all of the macros currently available for manipulating the internal Apple II speaker. + + + +`LISTING 10.02: The MAC.SPEAKER.ASM Heading` + +```assembly +* +*``````````````````````````````* +* MAC.SPEAKER * +* * +* THIS IS A MACRO LIBRARY FOR * +* THE SPEAKER COLLECTION. * +* THESE ARE REQUIRED FOR MUCH * +* OF THE COLLECTION TO WORK. * +* * +* AUTHOR: NATHAN RIGGS * +* CONTACT: NATHAN.RIGGS@ * +* OUTLOOK.COM * +* * +* DATE: 03-JUN-2021 * +* ASSEMBLER: MERLIN 8 PRO * +* OS: DOS 3.3 * +* * +* SUBROUTINES USED * +* * +* * +* LIST OF MACROS * +* * +* STMPO : SET TEMPO * +* PNOTE : PLAY SONG NOTE * +* SSONG : SET SONG ADDRESS * +* NEXTN : MOVE TO NEXT NOTE * +* PREVN : MOVE TO PREV NOTE * +* RSTRT : MOVE TO FIRST NOTE * +* FFRWD : JUMP AHEAD X NOTES * +* REWND : JUMP BACK X NOTES * +* PTONE : PLAY A TONE--NO SONG * +* PFREQ : PLAY A FREQUENCY * +* PSONG : PLAY A WHOLE SONG * +* SFX : PLAY SOUND EFFECT * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +``` + + + +--- + +### THE STMPO MACRO + +_SUMMARY_ + +| Condition | Value | +| --------------- | ----------------------- | +| Name | `STMPO` | +| Type | Macro | +| File | `MAC.SPEAKER.ASM` | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin Pro 8 | +| OS | Apple DOS 3.3 | +| Purpose | Set song and note tempo | +| Input | ]1 = Tempo | +| Output | none | +| Dependencies | `SETTEMPO` | +| Flags Destroyed | NZCV | +| Cycles | 240 | +| Bytes | 6 | +| Notes | none | +| See Also | none | + +--- + +*DETAILS* + +The `STMPO` macro sets the tempo for playing songs and determining note durations. + + + +`LISTING 10.03: The SETTEMPO Macro Source` + +```assembly +* +*``````````````````````````````* +* STMPO * +* * +* SET THE PLAYBACK TEMPO. * +* * +* PARAMETERS: * +* * +* ]1 = TEMPO ($0F MAX) * +* * +* CYCLES: 240 * +* SIZE: 6 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +STMPO MAC + LDA ]1 ; {4C3B} + JSR SETTEMPO ; {236C3B} + <<< +* +``` + + + +--- + +### THE PNOTE MACRO + +_SUMMARY_ + +| Condition | Value | +| --------------- | ------------------------------------------------- | +| Name | `PNOTE` | +| Type | Macro | +| File | `MAC.SPEAKER.ASM` | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin Pro 8 | +| OS | Apple DOS 3.3 | +| Purpose | Play the currently queued note in a song sequence | +| Input | none | +| Output | none | +| Dependencies | `PLAYNOTE` | +| Flags Destroyed | NZCV | +| Cycles | 172+ | +| Bytes | 3 | +| Notes | none | +| See Also | none | + +--- + +*DETAILS* + +The `PNOTE` macro simply JSR's (GOSUB) to the `PLAYNOTE` subroutine, which plays the current note in a registered song sequence. The Song's address is set with the `SSONG` macro, with the tempo set by the `STMPO` macro. + + + +`LISTING 10.04: The PNOTE Macro Source` + +```assembly +* +*``````````````````````````````* +* PNOTE * +* * +* PLAY THE NOTE THAT IS BEING * +* POINTED TO IN THE SONG. * +* * +* PARAMETERS: * +* * +* NONE * +* * +* CYCLES: 172+ * +* SIZE: 3 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +PNOTE MAC + JSR PLAYNOTE {172C3B} + <<< +* +``` + + + +--- + +### THE PLAYNOTE SUBROUTINE + +_SUMMARY_ + +| Condition | Value | +| --------------- | ------------------------------------------------- | +| Name | `PLAYNOTE` | +| Type | Subroutine | +| File | `SUB.PLAYNOTE.ASM` | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin Pro 8 | +| OS | Apple DOS 3.3 | +| Purpose | Play the currently queued note in a song sequence | +| Input | none | +| Output | none | +| Dependencies | `REDTONE` | +| Flags Destroyed | NZCV | +| Cycles | 166+ | +| Bytes | 46 | +| Notes | none | +| See Also | none | + +--- + +*DETAILS* + +The `PLAYNOTE` subroutine assumes that a song has been set with the `SSONG` macro and that the tempo has been set with the `STMPO` macro, then plays the note in a song sequence currently pointed at in NOTEP using the `REDTONE` subroutine. + +The NIND_XXX constants and the DIND_XXX constants can be used for pointing to the proper values to be inputted into `PLAYNOTE`. These simply point to sequential values used to reference each note, the frequencies of which are stored in a table of bytes; this is so that the frequency and duration values can be changed on the fly, if needed. + + + +`LISTING 10.05: The PLAYNOTE Subroutine Source` + +```assembly +* +*``````````````````````````````* +* PLAYNOTE * +* * +* PLAYS THE CURRENT NOTE IN A * +* SONG SEQUENCE, THE ADDRESS * +* BEING PROVIDED BY THE SSONG * +* MACRO. * +* * +* INPUT * +* * +* NONE * +* * +* DESTROY: NZCIDV * +* ^^^ ^ * +* * +* CYCLES: 166+ * +* SIZE: 46 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +PLAYNOTE + LDY #$00 ; {3C2B} RESET .Y POINTER + LDA TEMPMUL ; {4C3B} SET TEMPO MULTIPLIER + STA DURMUL ; {4C3B} + LDA NOTEP ; {4C3B} TRANSFER TO ZERO PAGE + STA ADDR4 ; {3C2B} + LDA NOTEP+1 ; {4C3B} + STA ADDR4+1 ; {3C2B} + LDA (ADDR4),Y ; {6C3B} LOAD CURRENT NOTE INDEX + BEQ :PLAYDONE ; {3C2B} IF 00, EXIT + TAX ; {2C1B} MOVE OFFSET TO .X POINTER + LDA NOTETBL,X ; {5C2B} GET NOTE FREQUENCY + STA PITCH ; {4C3B} + INY ; {2C1B} INCREASE SONG POINTER +:NOCARRY LDA (ADDR4),Y ; {6C3B} GET DURATION POINTER + TAX ; {2C1B} MOVE OFFSET TO .X POINTER + LDA DURTBL,X ; {5C2B} GET DURATION VALUE + STA DURAT ; {4C3B} + JSR REDTONE ; {194C0B} PLAY NOTE + LDA NPAUSE ; {0C3B} BRIEFLY PAUSE BETWEEN NOTES + JSR NWAIT ; {6C3B} CYCLES VARY TOO MUCH TO COUNT +:PLAYDONE + RTS ; {6C1B} +``` + + + +--- + +### THE SSONG MACRO + +_SUMMARY_ + +| Condition | Value | +| --------------- | ----------------------------- | +| Name | `SSONG` | +| Type | Macro | +| File | `MAC.SPEAKER.ASM` | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin Pro 8 | +| OS | Apple DOS 3.3 | +| Purpose | Set the song sequence address | +| Input | ]1 = Song address | +| Output | none | +| Dependencies | none | +| Flags Destroyed | NZCV | +| Cycles | 48+ | +| Bytes | 36 | +| Notes | none | +| See Also | none | + +--- + +*DETAILS* + +The `SSONG` macro sets the address of the song sequence to be played by other macros in the collection. This must be specified prior to using `PNOTE`, `NEXTN`, `PREVN`, `RSTRT`, `FFWRD`, `REWND` or `PSONG`. + + + +`LISTING 10.06: The SSONG Macro Source` + +```assembly +* +*``````````````````````````````* +* SSONG * +* * +* SET THE SONG TO BE PLAYED. * +* * +* PARAMETERS: * +* * +* ]1 = SONG ADDRESS * +* * +* CYCLES: 48 * +* SIZE: 36 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +SSONG MAC + IF #=]1 + LDA ]1/$100 ; {4C3B} + STA SONGLOC+1 ; {4C3B} + LDA ]1 ; {4C3B} + STA SONGLOC ; {4C3B} + ELSE + LDA ]1+1 ; {4C3B} + STA SONGLOC+1 ; {4C3B} + LDA ]1 ; {4C3B} + STA SONGLOC ; {4C3B} + FIN + LDA SONGLOC ; {4C3B} + STA NOTEP ; {4C3B} + LDA SONGLOC+1 ; {4C3B} + STA NOTEP+1 ; {4C3B} + <<< +* +``` + + + +--- + +### THE NEXTN MACRO + +_SUMMARY_ + +| Condition | Value | +| --------------- | ----------------------------------------------- | +| Name | `NEXTN` | +| Type | Macro | +| File | `MAC.SPEAKER.ASM` | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin Pro 8 | +| OS | Apple DOS 3.3 | +| Purpose | Move note pointer in song sequence to next note | +| Input | none | +| Output | none | +| Dependencies | none | +| Flags Destroyed | NZCV | +| Cycles | 24+ | +| Bytes | 17 | +| Notes | none | +| See Also | `PREVN` `RSTRT` `REWND` `FFWRD` | + +--- + +*DETAILS* + +The `NEXTN` macro moves the note pointer in the currently registered song sequence forward one note. This is mostly for stepping through a song in-between accomplishing other tasks, which potentially allows for "real-time" song playing as long as the note durations are short enough and the time between notes is kept minimal. + + + +`LISTING 10.07: The NEXTN Macro Source` + +```assembly +* +*``````````````````````````````* +* NEXTN * +* * +* MOVE TO THE NEXT NOTE IN THE * +* CURRENT SONG. * +* * +* PARAMETERS: * +* * +* NONE * +* * +* CYCLES: 24 * +* SIZE: 17 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +NEXTN MAC + LDA NOTEP ; {4C3B} + CLC ; {2C1B} + ADC #2 ; {3C2B} + STA NOTEP ; {4C3B} + LDA NOTEP+1 ; {4C3B} + ADC #0 ; {3C2B} + STA NOTEP+1 ; {4C3B} + <<< +* +``` + + + +--- + +### THE PREVN MACRO + +_SUMMARY_ + +| Condition | Value | +| --------------- | ------------------------------------------------ | +| Name | `PREVN` | +| Type | Macro | +| File | `MAC.SPEAKER.ASM` | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin Pro 8 | +| OS | Apple DOS 3.3 | +| Purpose | Move note pointer in song sequence to prior note | +| Input | none | +| Output | none | +| Dependencies | none | +| Flags Destroyed | NZCV | +| Cycles | 24+ | +| Bytes | 17 | +| Notes | none | +| See Also | `NEXTN` `RSTRT` `REWND` `FFWRD` | + +--- + +*DETAILS* + +The `PREVN` macro moves the note pointer in the current song sequence to the previous registered note. This probably has limited usefulness, but everyone likes playing a song backwards now and then. + + + +`LISTING 10.08: The PREVN Macro Source` + +```assembly +* +*``````````````````````````````* +* PREVN * +* * +* MOVE TO THE PREVIOUS NOTE * +* IN THE CURRENT SONG. * +* * +* PARAMETERS: * +* * +* NONE * +* * +* CYCLES: 24 * +* SIZE: 17 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +PREVN MAC + LDA NOTEP ; {4C3B} + SEC ; {2C1B} + SBC #2 ; {3C2B} + STA NOTEP ; {4C3B} + LDA NOTEP+1 ; {4C3B} + SBC #0 ; {3C2B} + STA NOTEP+1 ; {4C3B} + <<< +* +``` + + + +--- + +### THE RSTRT MACRO + +_SUMMARY_ + +| Condition | Value | +| --------------- | ------------------------------------------------ | +| Name | `RESTRT` | +| Type | Macro | +| File | `MAC.SPEAKER.ASM` | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin Pro 8 | +| OS | Apple DOS 3.3 | +| Purpose | Reset the song sequence pointer to the beginning | +| Input | none | +| Output | none | +| Dependencies | none | +| Flags Destroyed | NZCV | +| Cycles | 16 | +| Bytes | 2 | +| Notes | none | +| See Also | `NEXTN` `PREVN` `REWND` `FFWRD` | + +--- + +*DETAILS* + +The `RESTRT` macro simply resets the note pointer for the currently registered song sequence, allowing the song to be replayed from the beginning. + + + +`LISTING 10.09: The RESTRT Macro Source` + +```assembly +* +*``````````````````````````````* +* RSTRT * +* * +* RESET THE SONG POINTER TO * +* POINT TO THE FIRST NOTE. * +* * +* PARAMETERS: * +* * +* NONE * +* * +* CYCLES: 16 * +* SIZE: 2 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +RSTRT MAC + LDA SONGLOC ; {4C3B} + STA NOTEP ; {4C3B} + LDA SONGLOC+1 ; {4C3B} + STA NOTEP+1 ; {4C3B} + <<< +* +``` + + + +--- + +### THE FFWRD MACRO + +_SUMMARY_ + +| Condition | Value | +| --------------- | ---------------------------------------------- | +| Name | `FFWRD` | +| Type | Macro | +| File | `MAC.SPEAKER.ASM` | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin Pro 8 | +| OS | Apple DOS 3.3 | +| Purpose | Fast-forward a song by a given number of notes | +| Input | none | +| Output | none | +| Dependencies | none | +| Flags Destroyed | NZCV | +| Cycles | 29 | +| Bytes | 19 | +| Notes | none | +| See Also | `NEXTN` `PREVN` `REWND` `RSTSRT` | + +--- + +*DETAILS* + +The `FFWRD` macro skips the given number of notes in the registered song sequence starting at where the current note pointer is located. It should be noted that this does not protect from overflowing past the sequence end, so caution should be used. + + + +`LISTING 10.10: The FFWRD Macro Source` + +```assembly +* +*``````````````````````````````* +* FFWRD * +* * +* FAST FORWARD THE GIVEN # OF * +* SONG NOTES. * +* * +* PARAMETERS: * +* * +* ]1 = NUMBER OF NOTES * +* * +* CYCLES: 27 * +* SIZE: 19 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +FFWRD MAC + LDA ]1 ; {4C3B} + ASL ; {2C1B} + CLC ; {2C1B} + ADC NOTEP ; {4C3B} + STA NOTEP ; {4C3B} + LDA NOTEP+1 ; {4C3B} + ADC #0 ; {3C2B} + STA NOTEP+1 ; {4C3B} + <<< +* +``` + + + +--- + +### THE REWND MACRO + +_SUMMARY_ + +| Condition | Value | +| --------------- | ---------------------------------------- | +| Name | `REWND` | +| Type | Macro | +| File | `MAC.SPEAKER.ASM` | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin Pro 8 | +| OS | Apple DOS 3.3 | +| Purpose | Rewind a song by a given number of notes | +| Input | none | +| Output | none | +| Dependencies | none | +| Flags Destroyed | NZCV | +| Cycles | 35 | +| Bytes | 25 | +| Notes | none | +| See Also | `NEXTN` `PREVN` `FFWRD` `RSTSRT` | + +--- + +*DETAILS* + +The `REWND` macro moves the note pointer for the given song sequence backward by a specified number of notes. As with `FFWRD`, this macro does not protect against overflowing beyond the bounds of the song sequence. + + + +`LISTING 10.11: The REWND Macro Source` + +```assembly +* +*``````````````````````````````* +* REWND * +* * +* REWIND BY THE GIVEN # OF * +* SONG NOTES. * +* * +* PARAMETERS: * +* * +* ]1 = NUMBER OF NOTES * +* * +* CYCLES: 35 * +* SIZE: 25 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +REWND MAC + LDA ]1 ; {4C3B} + ASL ; {2C1B} + STA SCRATCH ; {4C3B} + LDA NOTEP ; {4C3B} + SEC ; {2C1B} + SBC SCRATCH ; {4C3B} + STA NOTEP ; {4C3B} + LDA NOTEP+1 ; {4C3B} + SBC #0 ; {3C2B} + STA NOTEP+1 ; {4C3B} + <<< +* +``` + + + +--- + +### THE PTONE MACRO + +_SUMMARY_ + +| Condition | Value | +| --------------- | ----------------------------------------------- | +| Name | `PTONE` | +| Type | Macro | +| File | `MAC.SPEAKER.ASM` | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin Pro 8 | +| OS | Apple DOS 3.3 | +| Purpose | Play a note without affecting the song sequence | +| Input | ]1 = Note code
]2 = Duration code | +| Output | none | +| Dependencies | `REDTONE` | +| Flags Destroyed | NZCV | +| Cycles | 220+ | +| Bytes | 18 | +| Notes | none | +| See Also | `PNOTE` `PFREQ` | + +--- + +*DETAILS* + +The `PTONE` macro plays a tone independently from the music playing functions, using the same system for addressing notes as the `PNOTE` macro. + + + +`LISTING 10.12: The PTONE Macro Source` + +```assembly +* +*``````````````````````````````* +* PTONE * +* * +* PLAY A TONE SEPARATELY FROM * +* BEING INCLUDED IN A SONG. * +* * +* PARAMETERS: * +* * +* ]1 = NOTE CODE * +* ]2 = DURATION CODE * +* * +* CYCLES: 220+ * +* SIZE: 18 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +PTONE MAC + LDX ]1 ; {4C3B} + LDA NOTETBL,X ; {5C3B} + STA PITCH ; {4C3B} + LDX ]2 ; {4C3B} + LDA DURTBL,X ; {5C3B} + STA DURAT ; {4C3B} + JSR REDTONE ; {194C0B} + <<< +* +``` + + + +--- + +### THE PFREQ MACRO + +_SUMMARY_ + +| Condition | Value | +| --------------- | ---------------------------------------------------- | +| Name | `PFREQ` | +| Type | Macro | +| File | `MAC.SPEAKER.ASM` | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin Pro 8 | +| OS | Apple DOS 3.3 | +| Purpose | Play a frequency without affecting the song sequence | +| Input | ]1 = Frequency value
]2 = Duration value | +| Output | none | +| Dependencies | `REDTONE` | +| Flags Destroyed | NZCV | +| Cycles | 214+ | +| Bytes | 15 | +| Notes | none | +| See Also | `PNOTE` `PTONE` | + +--- + +*DETAILS* + +The `PFREQ` macro plays a frequency on the Apple II internal speaker without altering the song note pointer. Both parameters accept values from 0 to 255 (#$FF). + + + +`LISTING 10.13: The PFREQ Macro Source` + +```assembly +* +*``````````````````````````````* +* PFREQ * +* * +* PLAY A SQUARE WAVE FREQUENCY * +* APART FROM ANY SONG. * +* * +* PARAMETERS: * +* * +* ]1 = FREQUENCY BYTE * +* ]2 = DURATION BYTE * +* * +* CYCLES: 214+ * +* SIZE: 15 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +PFREQ MAC + LDA ]1 ; {4C3B} + STA PITCH ; {4C3B} + LDA ]2 ; {4C3B} + STA DURAT ; {4C3B} + JSR REDTONE ; {194C3B} + <<< +* +``` + + + +--- + +### THE PSONG MACRO + +_SUMMARY_ + +| Condition | Value | +| --------------- | ---------------------------------------- | +| Name | `PSONG` | +| Type | Macro | +| File | `MAC.SPEAKER.ASM` | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin Pro 8 | +| OS | Apple DOS 3.3 | +| Purpose | Play a song sequence all the way through | +| Input | none | +| Output | none | +| Dependencies | `PNOTE` `NEXTN` | +| Flags Destroyed | NZCV | +| Cycles | 226+ | +| Bytes | 42 | +| Notes | none | +| See Also | `PNOTE` | + +--- + +*DETAILS* + +The `PSONG` macro plays an entire song sequence, with a loop that does not terminate until the final note of a sequence is reached. Obviously, this can create delays that are unacceptable in many situations, but there are a few reasons a user might want to play through an entire song. + + + +`LISTING 10.14: The PSONG Macro Source` + +```assembly +* +*``````````````````````````````* +* PSONG * +* * +* PLAY AN ENTIRE SONG SERIES. * +* * +* PARAMETERS: * +* * +* NONE * +* * +* CYCLES: 226+ * +* SIZE: 42 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +PSONG MAC +]LP1 + PNOTE ; {172C3B} + LDA NOTEP ; {4C3B} + STA ADDR4 ; {4C3B} + LDA NOTEP+1 ; {4C3B} + STA ADDR4+1 ; {4C3B} + LDY #0 ; {3C2B} + LDA (ADDR4),Y ; {5C3B} + BEQ ]EXITSONG ; {3C2B} + NEXTN ; {24C17B} + JMP ]LP1 ; {3C3B} +]EXITSONG + <<< +* +``` + + + +--- + +### THE SFX MACRO + +_SUMMARY_ + +| Condition | Value | +| --------------- | ------------------------------------------------------------ | +| Name | `SFX` | +| Type | Macro | +| File | `MAC.SPEAKER.ASM` | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin Pro 8 | +| OS | Apple DOS 3.3 | +| Purpose | Play a pre-determined sound effect | +| Input | ]1 = Sound effect code
]2 = First Variable
]3 = Second Variable | +| Output | none | +| Dependencies | `SOUNDFX` | +| Flags Destroyed | NZCV | +| Cycles | 1962+ | +| Bytes | 18 | +| Notes | none | +| See Also | none | + +--- + +*DETAILS* + +The `SFX` macro plays one of a number of different preset sound effects, the effect signified by the first parameter. The second and third parameters serve to alter variables in each sound effect; the effect this has differs based on the sound effect played, so the source of the `SOUNDFX` subroutine should be viewed for an overview of what these variables might do. + + + +`LISTING 10.15: The SFX Macro Source` + +```assembly +* +*``````````````````````````````* +* SFX * +* * +* PLAY A NUMBER OF PREMADE * +* SOUND EFFECTS. MANY OF THESE * +* ALLOW FOR SOME TONAL CONTROL * +* * +* PARAMETERS: * +* * +* ]1 = SOUND EFFECT TO PLAY * +* ]2 = FIRST VARIABLE * +* ]3 = SECOND VARIABLE * +* * +* CYCLES: 1962 (NOT ACCURATE) * +* SIZE: 18 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +SFX MAC + LDA ]1 ; {4C3B} + STA BPAR1 ; {3C2B} + LDA ]2 ; {4C3B} + STA BPAR2 ; {3C2B} + LDA ]3 ; {4C3B} + STA BPAR3 ; {3C2B} + JSR SOUNDFX ; {1941C3B} + <<< +* +``` + + + +--- + +### THE SOUNDFX SUBROUTINE + +_SUMMARY_ + +| Condition | Value | +| --------------- | ------------------------------------------------------------ | +| Name | `SOUNDFX` | +| Type | Subroutine | +| File | `SUB.SOUNDFX.ASM` | +| Author | Nathan Riggs | +| Last Revision | 03-JUN-2021 | +| Assembler | Merlin Pro 8 | +| OS | Apple DOS 3.3 | +| Purpose | Play a pre-determined sound effect | +| Input | BPAR1 = Sound effect code
BPAR2 = First Variable
BPAR3 = Second Variable | +| Output | none | +| Dependencies | `SOUNDFX` | +| Flags Destroyed | NZCV | +| Cycles | 1962+ | +| Bytes | 287 | +| Notes | none | +| See Also | none | + +--- + +*DETAILS* + +The `SOUNDFX` subroutine plays one of a number of premade sound effects on the Apple II internal speaker, allowing for some tweaking of the effect via the second and third parameters of the subroutine (BPAR2 and BPAR3). While there are only a limited number of effects currently available, a future update will expand upon them. + +Note that the cycle count registered for this subroutine is nowhere near the actual number of cycles to be used, since only a small part of the subroutine is run upon being called. For a more accurate count, see the source code at the point(s) where each sound effect is created. + +Many of these effects were created by others; when this is so, credit is given in the source. + + + +`LISTING 10.16: The SOUNDFX Subroutine Source` + +```assembly +* +*``````````````````````````````* +* SOUNDFX * +* * +* CONTAINS A NUMBER OF SOUND * +* EFFECTS THAT ARE REQUESTED * +* BY NUMBER. MANY OF THESE CAN * +* ACCEPT VARIABLES TO CHANGE * +* THE TONE,DURATION,SWEEP, AND * +* SO ON. * +* * +* SOME OF THESE ARE COPIED * +* DIRECTLY FROM OTHER SOURCES. * +* WHERE EACH EFFECT COMES FROM * +* IS LABELED AT THE STARTING * +* POSITION OF THAT EFFECT. * +* * +* INPUT: * +* * +* BPAR1 = EFFECT NUMBER * +* BPAR2 = VARIABLE ONE * +* BLAR3 = VARIABLE TWO * +* * +* DESTROY: NZCIDV * +* ^^^ ^ * +* * +* CYCLES: 1941 (HIGHLY FLAWED) * +* SIZE: 287 BYTES * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +]CNTR EQU BPAR2 ; MACHINE GUN BURSTS +]PWDTH EQU BPAR3 ; SWOOP PULSE WIDTH--40,80,128,160 +]PCNT EQU BPAR2 ; SWOOP PULSE COUNT--1 +]PSTEP EQU BPAR2 ; WORM STEP--1,77,129,179 +]WWDTH EQU BPAR3 ; WORM PULSE WIDTH--176,88 +]PLIMIT EQU BPAR4 ; PULSE LIMIT +]F1 EQU BPAR2 ; ALERT FIRST FREQUENCY +]F2 EQU BPAR3 ; ALERT 2ND FREQUENCY +* +]DUR DFB #08 ; {0C1B} ALERT DURATION +]WT DFB #10 ; {0C1B} ALERT REST PERIOD +* +SOUNDFX +* + LDA BPAR1 ; {3C2B} + CMP #0 ; {3C2B} + BEQ :MGUN ; {3C2B} + CMP #1 ; {3C2B} + BEQ :SWOOP ; {3C2B} + CMP #2 ; {3C2B} + BEQ :WORM ; {3C2B} + CMP #3 ; {3C2B} + BEQ :ALERT ; {3C2B} +* +:MGUN JMP ]MGUN ; {3C3B} +:SWOOP JMP ]SWOOP ; {3C3B} +:WORM JMP ]WORM ; {3C3B} +:ALERT JMP ]ALERT ; {3C3B} +* +** FROM BOB SANDER-CEDARLOFF'S CONTRIBUTION IN +** V1, ISS. 5 OF APPLE ASSEMBLY LINE. +* +]MGUN ; 33C,17B FOR THIS EFFECT ONLY +:A2 BIT SPKR ; {4C3B} + LDY $BA00,X ; {5C3B} GET "RANDOM" PULSE WIDTH +:A1 DEY ; {2C1B} DELAY LOOP FOR PULSE WIDTH + BNE :A1 ; {3C2B} + DEX ; {2C1B} GET NEXT PULSE + BNE :A2 ; {3C2B} + DEC ]CNTR ; {5C2B} GET NEXT BURST + BNE :A2 ; {3C2B} + RTS ; {6C1B} +* +** FROM BOB SANDER-CEDARLOFF'S CONTRIBUTION IN +** V1, ISS. 5 OF APPLE ASSEMBLY LINE. +* +]SWOOP ; 34C,18B FOR THIS SOUND EFFECT +:B1 LDY ]PCNT ; {3C2B} +:B2 BIT SPKR ; {4C3B} + LDX ]PWDTH ; {3C2B} +:B3 DEX ; {2C1B} DELAY LOOP FOR ONE PULSE + BNE :B3 ; {3C2B} + DEY ; {2C1B} LOOP FOR NUMBER OF PULSES + BNE :B2 ; {3C2B} AT EACH PULSE WIDTH + DEC ]PWDTH ; {5C2B} SHRINK PULSE WIDTH + BNE :B1 ; {3C2B} TO LIMIT OF 0 + RTS ; {6C1B} +* +** FROM BOB SANDER-CEDARLOFF'S CONTRIBUTION IN +** V1, ISS. 5 OF APPLE ASSEMBLY LINE. +* +]WORM ; 47C,26B FOR THIS SOUND EFFECT + LDA ]WWDTH ; {3C2B} + STA ]PLIMIT ; {3C2B} +:C1 BIT SPKR ; {4C3B} + LDX ]WWDTH ; {3C2B} DELAY LOOP FOR PULSE WIDTH +:C2 PHA ; {3C1B} LONGER DELAY LOOP + PLA ; {3C1B} + DEX ; {2C1B} END OF PULSE? + BNE :C2 ; {3C2B} NO + CLC ; {2C1B} CHANGE PULSE WIDTH BY STEP + LDA ]WWDTH ; {3C2B} + ADC ]PSTEP ; {3C2B} + STA ]WWDTH ; {3C2B} + CMP ]PLIMIT ; {3C2B} + BNE :C1 ; {3C2B} + RTS ; {6C1B} +]ALERT ; 1788C,196B FOR THIS EFFECT + PFREQ ]F1;]DUR ; {214C15B} + LDA ]WT ; {4C3B} + JSR NWAIT ; {6C3B} + PFREQ ]F2;]DUR ; {214C15B} + LDA ]WT ; {4C3B} + JSR NWAIT ; {6C3B} + PFREQ ]F1;]DUR ; {214C15B} + LDA ]WT ; {4C3B} + JSR NWAIT ; {6C3B} + PFREQ ]F2;]DUR ; {214C15B} + LDA ]WT ; {4C3B} + JSR NWAIT ; {6C3B} + PFREQ ]F1;]DUR ; {214C15B} + LDA ]WT ; {4C3B} + JSR NWAIT ; {6C3B} + PFREQ ]F2;]DUR ; {214C15B} + LDA ]WT ; {4C3B} + JSR NWAIT ; {6C3B} + PFREQ ]F1;]DUR ; {214C15B} + LDA ]WT ; {4C3B} + JSR NWAIT ; {6C3B} + PFREQ ]F2;]DUR ; {214C15B} + RTS ; {6C1B} +* +``` + + + +--- + +# PART II: Speaker Collection Demo + + + +The following listing contains examples of how to use the various macros in the Speaker Collection. + + + +`LISTING 10.17: The Speaker Collection Demo` + +```assembly +* +*``````````````````````````````* +* DEMO.SPEAKER.ASM * +* * +* A DEMONSTRATION OF HOW TO * +* USE THE VARIOUS MACROS IN * +* THE SPEAKER COLLECTION. * +* * +* AUTHOR: NATHAN RIGGS * +* CONTACT: NATHAN.RIGGS@ * +* OUTLOOK.COM * +* * +* DATE: 03-JUN-2021 * +* ASSEMBLER: MERLIN 8 PRO * +* OS: DOS 3.3 * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* + CYC AVE + EXP OFF + TR ON + DSK DEMO.SPEAKER + ORG $6000 + OBJ $BFE0 +* + PUT MIN.HEAD.REQUIRED.ASM + USE MIN.MAC.REQUIRED.ASM + PUT MIN.HEAD.SPEAKER.ASM + USE MIN.MAC.SPEAKER.ASM +* +*``````````````````````````````* +* PLAYING A FREQUENCY * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +** THE PFREQ MACRO PLAYS A FREQUENCY AT THE +** SPECIFIED PITCH AND DURATION. NOTE THAT +** THIS IS NOT ATTACHED TO PLAYING A SONG +** SEQUENCE, NOR DOES IT ACCEPT THE NOTE AND +** DURATION OFFSETS MEANT FOR PLAYING SONGS. +* + PFREQ #195;#141 + PFREQ #174;#141 + PFREQ #155;#141 + PFREQ #146;#141 + PFREQ #130;#141 + PFREQ #116;#141 + PFREQ #103;#141 +* +*``````````````````````````````* +* PLAYING A TONE * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +** THE PTONE MACRO PLAYS A TONE OUTSIDE OF +** PLAYING NOTES IN A SONG. THIS USES THE NOTE +** AND DURATION OFFSETS NORMALLY USED BY SONG-PLAYING +** FUNCTIONS. +* + PTONE #NIND_C1;#DIND_W + PTONE #NIND_D1;#DIND_W + PTONE #NIND_E1;#DIND_W + PTONE #NIND_F1;#DIND_W + PTONE #NIND_G1;#DIND_W + PTONE #NIND_A2;#DIND_W + PTONE #NIND_B2;#DIND_W +* +*``````````````````````````````* +* PLAYING SONGS * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +** THE STMPO MACRO SETS THE TEMPO FOR A SONG. THIS +** CHANGES THE DURATIONS OF NOTES AS WELL. +* + STMPO #$09 +* +** THE SSONG MACRO SETS THE ADDRESS OF THE SONG TO +** BE PLAYED. +* + SSONG #SCALE +* +** THE PNOTE MACRO PLAYS THE NOTE CURRENTLY INDEXED +** IN A SONG SET BY THE SSONG MACRO. +* + PNOTE +* +** THE NEXTN ADVANCES THE SONG BY A SINGLE NOTE. +* + NEXTN + PNOTE + NEXTN + PNOTE + NEXTN + PNOTE + NEXTN + PNOTE + NEXTN + PNOTE + NEXTN + PNOTE + NEXTN +* +** THE PREVN MACRO MOVES THE SONG NOTE POINTER ONE +** NOTE BACKWARDS. +* + PREVN + PNOTE + PREVN + PNOTE + PREVN + PNOTE + PREVN + PNOTE + PREVN + PNOTE + PREVN + PNOTE + PREVN + PNOTE +* +** THE FFWRD MACRO AND THE REWND MACRO MOVE THE SONG +** POINTER A SPECIFIED NUMBER OF NOTES FORWARDS OR +** BACKWARD. +* + FFWRD #2 + PNOTE + REWND #2 + PNOTE +* +** THE RSTRT MACRO SETS THE NOTE INDEX OF A SONG +** BACK TO THE FIRST NOTE. +* + RSTRT +* +** THE PSONG MACRO PLAYS A SONG FROM BEGINNING TO END. +* + PSONG +* +*``````````````````````````````* +* PLAYING SOUND EFFECTS * +*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,* +* +** THE SFX MACRO PLAYS ONE OF A NUMBER OF DIFFERENT +** STANDARDIZED SOUND EFFECTS. WHILE THE SELECTION IS +** SMALL NOW, MORE WILL BE ADDED IN A FUTURE DEDICATED +** UPDATE TO THE SPEAKER COLLECTION. +* + SFX #0;#10;#0 + SFX #1;#1;#160 + SFX #2;#1;#176 + SFX #3;#12;#6 +* + JSR $3D0 +* + PUT MIN.LIB.REQUIRED.ASM + PUT MIN.SUB.PLAYNOTE.ASM + PUT MIN.SUB.SOUNDFX.ASM +* +SCALE DFB NIND_D1S,DIND_W + DFB NIND_C1,DIND_D8 + DFB NIND_D1,DIND_D8 + DFB NIND_D1S,DIND_D8 + DFB NIND_E1,DIND_D8 + DFB NIND_F1,DIND_H + DFB NIND_D1S,DIND_H + DFB NIND_D1,DIND_D8 + DFB NIND_D1S,DIND_D8 + DFB NIND_F1,DIND_D8 + DFB NIND_G1S,DIND_D8 + DFB NIND_G1,DIND_W + DFB NIND_END,NIND_END +* +``` + + +