Skip to content

Instantly share code, notes, and snippets.

@HertzDevil
Last active June 5, 2022 02:24
Show Gist options
  • Save HertzDevil/d204524485d3a37a1829 to your computer and use it in GitHub Desktop.
Save HertzDevil/d204524485d3a37a1829 to your computer and use it in GitHub Desktop.
famitracker nsf driver game boy port

A WLA DX port of the FamiTracker / 0CC-FamiTracker NSF driver with an external compiler script that allows certain binary music data exported from the tracker to play properly as a GBS music file or a GB ROM file.

The Roadmap

  • Port NSF driver to GB-Z80
    • driver.s
    • init.s
    • player.s
    • effects.s
    • instrument.s
    • apu.s
    • merge changes from 0.5.0 beta
  • Write Game Boy-specific driver code
    • Length counter
    • PU1 hardware sweep
    • Effects
      • Wxy
      • Xxx
      • EEy
      • EF0
      • EFy
      • Hxy
      • Ixy
      • Kxx
      • Nxy
      • Vxx
      • Vxy
    • NSF bankswitching
    • GB bankswitching
  • Write GB / GBS generator for existing FT binary music data
    • Compile GB / GBS files
    • Patch period table
    • Patch vibrato table / old vibrato style
  • Refactor 0CC-FamiTracker (...)

Compilation

Expects a NSF file exported from any of the following:

  • FamiTracker 0.4.6 / FamiTracker 0.4.5
  • FamiTracker 0.5.0 beta 5 (other beta versions will not be verified)
  • 0CC-FamiTracker 0.3.13

Bankswitched music data must be natively supported if tracker implementations are available. The current port is capable of emulating the bankswitching used in the NSF driver as long as the music data is aligned in the same way as the NSF.

The track should contain exactly one Namco 163 channel, and no other expansion chips. The driver shall read the two pulse channels, the N163 channel, and the noise channel. Global effects outside these channels may still work.

Pattern effects are translated as is from the N163 channel to the Game Boy wave channel. No conversion takes place to account for the different pitch scales across Famicom / NES and GB.

Tracker implementations of the Game Boy sound chip are free to alter the binary music data format where cross-console compatibility is not desired. In particular, the following implementation details shall be different if DRV_VERSION is not defined to be one of the values for existing FamiTracker builds: (see below)

  • Track initialization; (slightly different header formats)
  • Effective channels; (for FT compatibility, ignores channel 2 / 5 (triangle / DPCM), and reads channel 4 (n163 channel 1))
  • Pattern effect table; (new effects)
  • Bankswitching behaviour; (Game Boy uses 16 KB banks instead of 4 KB)
  • Channel pitch tables. (only one table required for Game Boy)

Compiler options

  • DRV_VERSION: The version of the binary music data. Must be one of VER_046, VER_050, VER_0CC, and VER_FINAL, which is reserved for future tracker implementations. These options change the specific details the driver may use to read the slightly different data formats properly.
  • TEST_CODE: The name of an assembly source code file containing at least the ft_music_init and ft_music_play labels. If the file exists, compiles using this file instead of the default driver source code.
  • NOISE_MODE: Determines how notes on the noise channel map to Game Boy noise pitches. Must be one of the following:
  • `DEFAULT_NOISE`: Maps `n` to `((n & 0x0F) << 4) | 0x07`. Note pitches repeat per 16 notes as in FamiTracker.
  • `APPROX_NOISE`: Uses a lookup table to map noise pitches as closely as possible to the NES noise channel.
  • `SCALE_NOISE`: Maps `n` to `n >= 0x40 ? /*lookup table*/[min(0x48, n) - 0x40] : (n >> 2 << 4) | (n & 0x03)`. This option expands noise channel notes such that note pitches run consecutively from C-0 to B-7, and moreover prevent the noise channel from wrapping around its pitch on overflow or underflow. This option allows the noise channel to take all 68 different noise pitches continuously.
`n` ranges from 0 to 95 corresponding to notes C-0 to B-7. See the table below for register values of all notes. - `SOFT_ENV`: If defined, where the hardware volume envelope is available, and the volume changes while the envelope setting remains unchanged at `8`, the sound driver changes the volume by writing to the volume register without retriggering the note. - `REFRESH_RATE`: The output refresh rate of the track. A valid value for `TIMER_RATE` must be provided for this to work. Note that WLA DX does not enforce expressions to be integers. - `TIMER_RATE`: The Game Boy internal timer rate. If defined, both the GBS file and the GB ROM image use timer interrupts instead of vertical blank interrupts; otherwise, both this option and `REFRESH_RATE` are ignored. Must be one of `4096`, `16384`, `65536`, and `262144`. - `DIVIDER`: If defined, causes the sound driver to refresh only once per `DIVIDER` interrupts. This option is often required for high `TIMER_RATE` values where accurate timing is desired, including the default settings, so that the timer modulo value at $FF06 fits into an 8-bit unsigned value.

Instrument type

All instruments share one type, based on the N163 sequence instrument type. Unlike N163, a Game Boy instrument may store zero waves; instruments do not overwrite the wave buffer on the wave channel whenever the wave index is greater than the instrument wave count.

Before tracker implementations are available, the driver should be expected to read both 2A03 and N163 instruments properly. 0CC-FamiTracker already did this in a generic manner; the official FamiTracker does not put instrument types into exported data, but this is not much of an issue as 2A03 and N163 instruments cannot be interchangeably used there.

Channel behaviour

Volume values do not write unless they are different from the register values. Volume mixing of the channel and the instrument does not affect the hardware envelope rate where available.

The wave channel maps internal volumes to permissible values:

  • 8-F: 100%
  • 4-7: 50%
  • 1-3: 25%
  • 0: 0%

The wave channel ignores hardware volume envelope settings in volume sequences.

Tracker implementations should not display notes on the noise channel as "?-#" where SCALE_NOISE is defined.

Sequence extensions

Instrument volume sequences support the hardware volume envelope by overloading the high nibble of the sequence terms.

Arpeggio schemes are as in 0CC-FamiTracker.

Absolute pitch sequences are as in FamiTracker beta. Any term is equivalent to first applying an arpeggio to the current note.

Duty / noise mode settings are as in FamiTracker. They may not alter the noise channel's frequency divider even when DEFAULT_NOISE is used.

There are no plans to add pan control to instrument sequences at this moment. Pan settings might overload the duty / noise settings.

Miscellaneous

The compiler and the sound driver both assume that the NTSC region is used.

By default, the sound driver assigns 16384 to TIMER_RATE, 60 to REFRESH_RATE, and 3 to DIVIDER. With these parameters, the sound driver refreshes once per timer interrupt at a rate of exactly 16384 ÷ 3 ÷ (256 - 165) = 60.015 Hz; if vertical blank interrupts are used instead, this rate becomes exactly 4194304 ÷ 70224 = 59.73 Hz, and the standard tempo (150 BPM) will be scaled to approximately 149.32 BPM. The GBS file puts the refresh rate settings in the GBS header, and the GB ROM image manually writes these values during initialization.

There are no plans to implement the fast pitch/vibrato mode or the wave/speech kits from LSDj.

The GBS specification states that either the vertical blank or the timer shall be used to clock the sound driver, but never both. Any feature requiring both interrupts will not be available.

Contacts

For suggestions message @HertzDevil on Twitter or hezedefil on Skype. Do not contact through places designated for 0CC-FamiTracker.

Hardware Differences

These differences between the Game Boy and Famicom / NES channels shall be observed when preparing music data for the port:

  • All Game Boy channels have higher pitch for higher register values (like N163), but pitch changes still become twice as sensitive when raised by an octave (like 2A03). This is because the Game Boy stores pitch as a complemented period; the frequency for a pulse channel with register value x is 131072 ÷ (2048 - x) Hz.
  • The wave channel's pitch register is 11-bit wide, whereas the N163 is internally 16-bit (left-shifted twice to match the 18-bit resolution of the sound chip).
  • When the wave channel's volume is at 50% or 25%, it simply right-shifts all samples in the wave buffer by 1 or 2 times respectively.
  • Writes the the noise channel's volume register will reset its LFSR state.

Noise lookup table for high pitches

Note value 40 41 42 43 44 45 46 47 >= 48
Register value F4 F4 F5 F5 F6 F6 F6 F6 F7

Note register table

Note PU1/PU2/WAV DEFAULT_NOISE APPROX_NOISE SCALE_NOISE
C-0 000 07 82 00
C#0 000 17 92 01
D-0 000 27 A2 02
D#0 000 37 B0 03
E-0 000 47 B2 10
F-0 000 57 C0 11
F#0 000 67 C2 12
G-0 000 77 D0 13
G#0 000 87 D1 20
A-0 000 97 D2 21
A#0 000 A7 E0 22
B-0 000 B7 E2 23
C-1 02C C7 F2 30
C#1 09D D7 F5 31
D-1 107 E7 F6 32
D#1 16B F7 F7 33
E-1 1C9 07 82 40
F-1 223 17 92 41
F#1 277 27 A2 42
G-1 2C7 37 B0 43
G#1 312 47 B2 50
A-1 358 57 C0 51
A#1 39B 67 C2 52
B-1 3DA 77 D0 53
C-2 416 87 D1 60
C#2 44E 97 D2 61
D-2 483 A7 E0 62
D#2 4B5 B7 E2 63
E-2 4E5 C7 F2 70
F-2 511 D7 F5 71
F#2 53B E7 F6 72
G-2 563 F7 F7 73
G#2 589 07 82 80
A-2 5AC 17 92 81
A#2 5CE 27 A2 82
B-2 5ED 37 B0 83
C-3 60B 47 B2 90
C#3 627 57 C0 91
D-3 642 67 C2 92
D#3 65B 77 D0 93
E-3 672 87 D1 A0
F-3 689 97 D2 A1
F#3 69E A7 E0 A2
G-3 6B2 B7 E2 A3
G#3 6C4 C7 F2 B0
A-3 6D6 D7 F5 B1
A#3 6E7 E7 F6 B2
B-3 6F7 F7 F7 B3
C-4 706 07 82 C0
C#4 714 17 92 C1
D-4 721 27 A2 C2
D#4 72D 37 B0 C3
E-4 739 47 B2 D0
F-4 744 57 C0 D1
F#4 74F 67 C2 D2
G-4 759 77 D0 D3
G#4 762 87 D1 E0
A-4 76B 97 D2 E1
A#4 773 A7 E0 E2
B-4 77B B7 E2 E3
C-5 783 C7 F2 F0
C#5 78A D7 F5 F1
D-5 790 E7 F6 F2
D#5 797 F7 F7 F3
E-5 79D 07 82 F4
F-5 7A2 17 92 F4
F#5 7A7 27 A2 F5
G-5 7AC 37 B0 F5
G#5 7B1 47 B2 F6
A-5 7B6 57 C0 F6
A#5 7BA 67 C2 F6
B-5 7BE 77 D0 F6
C-6 7C1 87 D1 F7
C#6 7C5 97 D2 F7
D-6 7C8 A7 E0 F7
D#6 7CB B7 E2 F7
E-6 7CE C7 F2 F7
F-6 7D1 D7 F5 F7
F#6 7D4 E7 F6 F7
G-6 7D6 F7 F7 F7
G#6 7D9 07 82 F7
A-6 7DB 17 92 F7
A#6 7DD 27 A2 F7
B-6 7DF 37 B0 F7
C-7 7E1 47 B2 F7
C#7 7E2 57 C0 F7
D-7 7E4 67 C2 F7
D#7 7E6 77 D0 F7
E-7 7E7 87 D1 F7
F-7 7E9 97 D2 F7
F#7 7EA A7 E0 F7
G-7 7EB B7 E2 F7
G#7 7EC C7 F2 F7
A-7 7ED D7 F5 F7
A#7 7EE E7 F6 F7
B-7 7EF F7 F7 F7

Bit 3 of the noise pitch register is determined by the noise LFSR size.

Pattern effects

Global

Effect Range Description
Bxx All [1] As in FamiTracker.
Cxx All As in FamiTracker. Parameter xx is unused.
Dxx All As in FamiTracker.
Fxx All As in FamiTracker. Also exports separately to speed and tempo commands.
Oxx xx: 00 - 1F As in 0CC-FamiTracker.

Common

Effect Range Description
0xy All As in FamiTracker. Also as in 0CC-FamiTracker.
1xx All As in FamiTracker.
2xx All As in FamiTracker.
3xx All As in FamiTracker.
4xy All As in FamiTracker.
7xy All As in FamiTracker.
A0y All As in FamiTracker.
Ax0 All As in FamiTracker.
Gxx All As in FamiTracker.
Lxx xx: 00 - 7F As in 0CC-FamiTracker.
Mxy x, y: 1 - F As in 0CC-FamiTracker.
Pxx All As in FamiTracker.
Qxy All As in FamiTracker.
Rxy All As in FamiTracker.
Sxx xx: 00 - 7F As in FamiTracker. Disables hardware note length.
Txy All As in 0CC-FamiTracker.

Chip-specific

Effect Range Description
Wxy x, y: 0 - 7 [2] Sets the master volume to x for left channel, y for right channel.
Xxx xx: 00 - FE Writes xx to the hardware timer modulo register immediately. Adjusts the timer's current value accordingly.

Channel-specific

Effect Range Channel Description
EEy y: 1 - F PU1, PU2, NOI Gets the current mixed volume and writes y as the hardware volume envelope rate. Does not allow the channel and the instrument to write to the volume register until the next note.
EF0 - PU1, PU2, NOI Disables envelope rate overriding, and returns volume control to the channel and the current instrument immediately.
EFy y: 1 - F PU1, PU2, NOI Performs EEy, then enables envelope rate overriding as though all future notes perform the EEy effect on triggering.
Hxy x, y: 0 - 7 [2] PU1 As in FamiTracker, but disables hardsweep sweep if x == 7. H00 is not guaranteed to leave the frequency changed.
Ixy x, y: 0 - 7 [2] PU1 As in FamiTracker, but disables hardsweep sweep if x == 7. I00 is not guaranteed to leave the frequency changed. The Game Boy does not silence the channel on frequency overflow.
Kxx xx: 00 - 3F [2] PU1, PU2, NOI Enables hardware note length. Sets the note length register to xx on all future notes.
Kxx All WAV Enables hardware note length. Sets the note length register to xx on all future notes.
Nxy x, y: 0 - 1 [2] PU1, PU2, WAV, NOI Disables left channel output if x == 0. Disables right channel output if y == 0.
Vxx xx: 00 - 03 [2] PU1, PU2 As in FamiTracker.
Vxx xx: 00 - 3F [3] WAV As in FamiTracker. Behaves similarly to the N163 Vxx effect.
Vxy x: 0 - 7, y: 0 - 1 [2] NOI Enables 7-bit noise LFSR if y == 1. If NOISE_MODE is defined to be DEFAULT_NOISE, sets the frequency divider to x (otherwise the noise note values determine the frequency divider).

During compilation, the driver builds an appropriate command jump table depending on the DRV_VERSION option. Code for unused effects may be removed by checking this option against the VER_ values.

[1] xx: 00 - 7F in official builds.
[2] Masks unused bits for out-of-range parameters.
[3] xx: 00 - 0F in official builds.

@untoxa
Copy link

untoxa commented May 24, 2020

Dear HertzDevil, won't you please open the source of the player?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment