Using Carillon Player & FX Hammer

©2000-2001 Aleksi Eeben (email: aleksi@cncd.fi)
http://www.cncd.fi/aeeben

Carillon Player Routines
Fade In/Fade Out
Player Variables in Work RAM
Using Your Own Sound FX Routines


Carillon Player Routines

Note that any registers may change during any of these calls. If you are using interrupts don't forget to store all the registers. Also be sure to use proper banking!

Player_Initialize
$4000
in Music Bank

Initializes hardware sound registers and player variables at $c7c0-$c7ef. Call this at program startup before using any other Carillon Player or FX Hammer routines.

Example:

ld    a,MusicBank            ; Any of the Music Banks
ld    [rROMB0],a
call  Player_Initialize      ; Initialize Carillon Player and FX Hammer

This routine is not needed at later time except for that if you need to disable all the sound circuits (by writing $00 to rNR52) for example during pause mode.

Player_MusicStart
$4003
in Music Bank

Starts playing song number 0. Call Player_SongSelect right after this call to select another song.

Example:

ld    a,MusicBank
ld    [rROMB0],a             ; Switch to desired Music Bank
ld    [CurrentMusicBank],a   ; Store Music Bank number for later use
call  Player_MusicStart      ; Start playing song number 0

Player_MusicStop
$4006
in Music Bank

Stops playing the current song. Any sound FX currently playing are not affected.

Example:

ld    a,[CurrentMusicBank]
ld    [rROMB0],a             ; Switch to current Music Bank
call  Player_MusicStop       ; Stop music

Note: Calling this routine is not necessary when switching to a different song or Music Bank.

Player_SongSelect
$400c
in Music Bank

Call this to select a song other than song number zero. Load register A with song number (0 - 7). Always call Player_MusicStart before calling this routine.

Example:

ld    a,MusicBank
ld    [rROMB0],a             ; Switch to desired Music Bank
ld    [CurrentMusicBank],a   ; Store Music Bank number for later use
call  Player_MusicStart      ; Start music first...
ld    a,3
call  Player_SongSelect      ; Start playing song number 3 (instead of 0)

Player_MusicUpdate
$4100
in Music Bank

This must be called once every frame to keep the music playing. (After all your VBlank routines is usually fine.)

Example:

ld    a,[CurrentMusicBank]
ld    [rROMB0],a             ; Switch to current Music Bank
call  Player_MusicUpdate     ; Keep music playing

The routine takes only 0 - 3 LCD lines of raster time (Less than 2% CPU usage).

Player_SampleUpdate
$4000
in Sample Bank

If the song is using samples (ie. there is a sample bank for that song) you must call this routine four times every frame.

For example at LCD lines $10, $36, $5d and $83. This way no VBlank time is wasted ever.

Example:

ld    a,[CurrentSampleBank]  ; Get active Sample Bank number
ld    [rROMB0],a             ; Switch to current Sample Bank
call  Player_SampleUpdate    ; Update Waveform RAM

Each call takes less than 1 LCD line of raster time.

The most working solution for timing is to use a series of LYC-interrupts. You can also use a simple LCD line wait if that works with the program (maybe for title and menu screens).

SoundFX_Trig
$4000
in SoundFX Bank

Call this to start playing a sound FX. Load register A with sound FX number (0 - 59). This can be done at any point in your game program.

Example:

ld    a,SoundFXBank
ld    [rROMB0],a             ; Switch to SoundFX Bank
ld    a,5
call  SoundFX_Trig           ; Trig sound FX number 5

SoundFX_Stop
$4003
in SoundFX Bank

Call this if you need to stop a sound FX currently playing. Remember that calling Player_MusicStop doesn't affect sound FX.

Example:

ld    a,SoundFXBank
ld    [rROMB0],a             ; Switch to SoundFX Bank
call  SoundFX_Stop           ; Stop any sound FX playing

SoundFX_Update
$4006
in SoundFX bank

This must be called once every frame to keep the sound FX playing. Right after Player_MusicUpdate is fine.

Example:

ld    a,SoundFXBank
ld    [rROMB0],a             ; Switch to SoundFX Bank
call  SoundFX_Update         ; Keep sound FX playing

The routine takes less than 1 LCD line of raster time.

Important note: If you cannot (for any reason) call Player_MusicUpdate and SoundFX_Update once every frame you should turn off the music and sound FX during that period to avoid any unwanted bleeps.

Fade In/Fade Out

Carillon sets the master volume register (rNR50) to maximum ($77) in Player_Initialize but doesn't change that value afterwards. You can use this register for fading sound ($77, $66, $55, $44, $33, $22, $11, $00 at desired rate, then call Player_MusicStop and SoundFX_Stop). Do not forget to restore the maximum level ($77) before starting another song or trigging sound FX.


Player Variables in Work RAM

$c7c0

MusicFlag

New music note data is read at the current tempo (Speed) when MusicFlag = $00.
Music is stopped when MusicFlag = $01 (No more new notes are read).

MusicFlag is set to $01 when the end of music data is reached (Some channels may still be active).

$c7c1

Speed

Current Tempo

Default = $07, changed using command TMPx in block data.

$c7c2

StepP

Step time counter

Starts at value in Speed, decremented by one every frame. One step is advanced when StepP = Speed/2 or StepP = $00.

$c7c3

PatternP

Current step (n * $08)

$c7c4

PatternH

Current block (block number + $50)

$c7c5

 

SequencerP

 

Current position in Block Order List

In Player_MusicSelect SequencerP is set to (actual song starting position - 1) and PatternP is set to $00.

$c7c6

 

Ch1Flags

Bit 1: Ch1 reserved for sound FX routines (1 = yes, 0 = no)
Bit 0: Ch1 music note playing (1 = no, 0 = yes)

When Ch1Flags is not $00, no instrument sound data is read and all Ch1 sound registers (rNR1x) remain intact.

$c7c7

Ch1Count

Countdown (in frames) before moving to next step in sound data

$c7c8

Ch1SndP

High nybble: CH1-2 Sound number
Low nybble: Current step in sound data

$c7c9

Ch1Note

Current Ch1 Note (before arpeggiato)

$c7ca

Ch1FreqL

Ch1 Frequency Low-order byte (before modulation/slide)

$c7cb

Ch1FreqH

Ch1 Frequency High-order byte (before modulation/slide)

$c7cc

 

Ch2Flags

 

Bit 1: Ch2 reserved for sound FX routines (1 = yes, 0 = no)
Bit 0: Ch2 music note playing (1 = no, 0 = yes)

When Ch2Flags is not $00, no instrument sound data is read and all Ch2 sound registers (rNR2x) remain intact.

$c7cd

Ch2Count

Countdown (in frames) before moving to next step in sound data

$c7ce

Ch2SndP

High nybble: CH1-2 Sound number
Low nybble: Current step in sound data

$c7cf

Ch2Note

Current Ch2 Note (before arpeggiato)

$c7d0

Ch2FreqL

Ch2 Frequency Low-order byte (before modulation/slide)

$c7d1

Ch2FreqH

Ch2 Frequency High-order byte (before modulation/slide)

$c7d2

 

Ch3Flags

 

Bit 2: Ch3 reserved for playing a sample trigged in music data (1 = yes, 0 = no)
Bit 1: Ch3 reserved for sound FX routines (1 = yes, 0 = no)
Bit 0: Ch3 music note playing (1 = no, 0 = yes)

When Ch3Flags is not $00, no instrument sound data is read and all Ch3 sound registers (rNR3x) remain intact.

$c7d3

Ch3Count

Countdown (in frames) before moving to next step in sound data

$c7d4

Ch3Wave

Current Waveform (n * $10) in Waveform RAM

$c7d5

Ch3SndP

High nybble: WAV3 Sound number
Low nybble: Current step in sound data

$c7d6

Ch3Note

Current Ch3 Note (before arpeggiato)

$c7d7

Ch3FreqL

Ch3 Frequency Low-order byte (before modulation/slide)

$c7d8

Ch3FreqH

Ch3 Frequency High-order byte (before modulation/slide)

$c7d9

Ch4Flags

Bit 1: Ch4 reserved for sound FX routines (1 = yes, 0 = no)
Bit 0: Ch4 music note playing (1 = no, 0 = yes)

When Ch4Flags is not $00, no instrument sound data is read and all Ch4 sound registers (rNR4x) remain intact.

$c7da

Ch4Count

Countdown (in frames) before moving to next step in sound data

$c7db

Ch4SndP

High nybble: PRC4 Sound number
Low nybble: Current step in sound data

$c7dc

Ch3Init

Internally set when Waveform RAM is reloaded

$c7dd

Modulate

Bit 7: Vibrato/Slide
Bit 2: Modulate Ch3
Bit 1: Modulate Ch2
Bit 0: Modulate Ch1

$c7de

VibratoP

Vibrato Phase (and Width)

$c7df

VibSpeed

Vibrato Speed

$c7e0

ModLAdd

Slide Add Low-order byte

$c7e1

ModL

Current Slide Amount Low-order byte

$c7e2

ModHAdd

Slide Add High-order byte

$c7e3

ModH

Current Slide Amount High-order byte

$c7e4

SampleL

Sample address Low-order byte

$c7e5

SampleH

Sample address High-order byte

$c7e6

SamCount

Sample blocks left to play

$c7e7

TrigCount

Used for timing

$c7e8

NewPanMask

Pan position for trigged sample

$c7e9

NewSampleL

Temporary storage for trigging sample

$c7ea

NewSampleH

Temporary storage for trigging sample

$c7eb

NewSamCount

Sample length in blocks

$c7ec

FXCurrentPri

FX Hammer: Priority of current Sound FX playing ($00 = lowest)

$c7ed

FXSoundCount

FX Hammer: Countdown (in frames) before moving to next step in Sound FX

$c7ee

FXSoundP

FX Hammer: Current Step

$c7ef

FXSoundH

FX Hammer: Current Sound FX (FX number + $44)


 

Using Your Own Sound FX Routines

Before using your own routines to play a sound FX you must first reserve the corresponding channel or channels:

Reserving Channel 1

- Write $03 to Ch1Flags ($c7c6)

Reserving Channel 2

- Write $03 to Ch2Flags ($c7cc)

Reserving Channel 3*

- Write $03 to Ch3Flags
($c7d2)

- If using samples in the music, write $00 to both TrigCount ($c7e7) and SamCount ($c7e6)

- Note that Waveform RAM may contain any waveform (or if using samples even some "random" buzz), so you must immediately reload the Waveform RAM

Reserving Channel 4

- Write $03 to Ch4Flags ($c7d9)

Since the sound registers may contain any values at this time, you should start playing the sound FX immediately.

* Important note on Channel 3 usage: If using samples in the music (Sample Player add-on), you must skip all Sample_Update calls while playing a sound FX on Channel 3.

After your sound FX is finished the used channels must be released:

Releasing Channel 1

- Write $00 to rNR10 (FX might have used the Ch1 slide function)

- Write $08 to rNR12, then write $80 to rNR14 (Cuts any FX tail)

- Write $01 to Ch1Flags ($c7c6)

Releasing Channel 2

- Write $08 to rNR22, then write $80 to rNR14 (Cuts any FX tail)

- Write $01 to Ch2Flags ($c7cc)

Releasing Channel 3*

- Write $00 to rNR32 (Cuts any FX tail)

- Write $ff to Ch3Wave ($c7d4) to make sure the Waveform RAM is reloaded by the music player

- If using samples in the music, again write $00 to both TrigCount ($c7e7) and SamCount ($c7e6)

- Write $01 to Ch3Flags
($c7d2)

Releasing Channel 4

- Write $08 to rNR42, then write $80 to NR44 (Cuts any FX tail)

- Write $01 to Ch4Flags ($c7d9)

Note: If using FX Hammer you shouldn't use channels 2 and 4 in your own sound FX routines.