# 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<br />DURAT = Tone duration<br />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<br />]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<br />]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<br />]2 = First Variable<br />]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<br />BPAR2 = First Variable<br />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
*
```



