AppleIIAsm-Collection/documentation/AppleIIAsm Library Collection Technical Manual/0.6.1/39.0 Detailed_Reference_D10_SPEAKER.md

1745 lines
58 KiB
Markdown
Raw Normal View History

# 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
*
```