Home

Awesome

ZzFX Music Generator

This is a music generator for use in tiny JavaScript productions (i.e. js13k games). ZzFXM uses a modified version of the super-tiny ZzFX library by Frank Force to generate instruments. The modified version of ZzFX is able create an array of audio data without immediately playing it.

The song format is loosely based on the MOD format, using patterns to handle repeating blocks of song data. Unlike MOD, patterns can be variable in length allowing repeatitive sequences of pattern data to be broken down into smaller chunks. Each pattern can also contain a variable number of channels, reducing the need to store empty data.

Use

<!-- load dependencies -->
<script src="zzfx.js"></script>
<script src="zzfxm.min.js"></script>

<script>
  // Create a song
  let mySongData = zzfxM(...song);

  // Play the song (returns a AudioBufferSourceNode)
  let myAudioNode = zzfxP(...mySongData);

  // Stop the song
  myAudioNode.stop();
</script>

Tooling

This repo contains various tools to help you generate and work with ZzFXM songs:

Tracker

A browser-based music tracker for composing songs for ZzFXM. (Available online.)

Song Conversion Tool

A CLI tool for converting file in ProTracker MOD (M.K.) format to the ZzFXM format. This allows you to use tools such as MilkyTracker or the browser-based Bassoon Tracker to author your songs. In order to keep ZzFXM small, only the volume and pattern break effects are 100% supported. The volume sliding effect is partially emulated by the song conversion tool by replacing the effect with computed volume steps.

Song Packer Tool

The song packer CLI tool compresses song data. It uses plugins so you can extend it with custom code if you need to.

Local Modules

This repo contains various local node modules that are shared between the tools. Please use them if you wish to create additional tooling.

Song Format

A ZzFXM song is a series of nested arrays containing instrument, pattern and sequence data:

[                                     // Song
  [                                     // Instruments
    [.9, 0, 143, , , .35, 3],             // Instrument 0
    [1, 0, 216, , , .45, 1, 4, , ,50],    // Instrument 1
    [.75, 0, 196, , .08, .18, 3]          // Instrument 2
  ],
  [                                     // Patterns
    [                                     // Pattern 0
      [                                     // Channel 0
        0,                                    // Using instrument 0
        -1,                                   // From the left speaker
        1,                                    // play C-1
        0, 0, 0,                              // rest (x3)
        3.5,                                  // play E-1 with 50% attenuation
        0, 0, 0                               // rest (x3)
      ],
      [                                     // Channel 1
        1,                                    // Using instrument 1
        1,                                    // From the right speaker
        2,                                    // play D-1
        2.25,                                 // play D-1 with 25% attenuation
        3.5,                                  // Play E-1 with 50% attenuation
        4.75,                                 // Play F-1 with 75% attenuation
        -1,                                   // Release the note
        0, 0, 0                               // rest (x3)
      ]
    ]
  ],
  [                                     // Sequence
    0,                                    // Play pattern 0
    0,                                    // ...and again
  ],
  120,                                  // 120 BPM
  {                                     // Metadata
    title: "My Song",                      // Name of the song
    author: "Keith Clark"                  // Name of the author/composer
  }
]

Song Structure

[
  <instrument-list>,
  <pattern-list>,
  <sequence>,
  <speed>?,
  <metadata>?
]

<instrument-list> structure

[
  <instrument>,
  ...
]

<instrument> structure

[
  <zzfx-sound-volume>?,
  <zzfx-sound-randomness>?,
  <zzfx-sound-frequency>?,
  <zzfx-sound-attack>?,
  <zzfx-sound-sustain>?,
  <zzfx-sound-release>?,
  <zzfx-sound-shape>?,
  <zzfx-sound-shapeCurve>?,
  <zzfx-sound-slide>?,
  <zzfx-sound-deltaSlide>?,
  <zzfx-sound-pitchJump>?,
  <zzfx-sound-pitchJumpTime>?,
  <zzfx-sound-repeatTime>?,
  <zzfx-sound-noise>?,
  <zzfx-sound-modulation>?,
  <zzfx-sound-bitCrush>?,
  <zzfx-sound-delay>?,
  <zzfx-sound-sustain-volume>?,
  <zzfx-sound-decay>?,
  <zzfx-sound-tremolo>?
]

An instrument is an array of optional ZzFX sound parameters. Any missing paramaters will be populated using the ZzFX default values.

ParamDescriptionDefaultMin ValueMax Value
volumeVolume scale (percent)1-10000000001000000000
randomnessHow much to randomize frequency (percent Hz)0.05-10000000001000000000
frequencyFrequency of sound (Hz)440-10000000001000000000
attackAttack time, how fast sound starts (seconds)003
sustainSustain time, how long sound holds (seconds)003
releaseRelease time, how fast sound fades out (seconds)003
shapeShape of the sound wave (0=sin, 1=triangle, 2=saw, 3=tan, 4=bit noise)0--
shapeCurveSquarenes of wave (0=square, 1=normal, 2=pointy)001000000000
slideHow much to slide frequency (kHz/s)0-10000000001000000000
deltaSlideHow much to change slide (kHz/s/s)0-10000000001000000000
pitchJumpFrequency of pitch jump (Hz)0-10000000001000000000
pitchJumpTimeTime of pitch jump (seconds)0-10000000001000000000
repeatTimeResets some parameters periodically (seconds)0-10000000001000000000
noiseHow much random noise to add (percent)0-10000000001000000000
modulationFrequency of modulation wave, negative flips phase (Hz)0-10000000001000000000
bitCrushResamples at a lower frequency in (samples*100)0-10000000001000000000
delayOverlap with itself for reverb and flanger effects (seconds)001000000000
sustainVolumeVolume level for sustain (percent)1-10000000001000000000
decayDecay time, how long to reach sustain after attack001
tremoloTrembling effect, rate controlled by repeat time (precent)001

<pattern-list> structure

[
  <pattern>,
  ...
]

<pattern> structure

[
  <channel>,
  ...
]

<channel> structure

[
  <channel-instrument>, <channel-panning>, <channel-note>+
]

Channel data is a single array containing the instrument, panning and note data the current pattern. The first slot indicates which instrument to use for playing notes. Slot 2 contains the channel panning value and slots 3 onwards hold the note. If the array slot for an instrument, panning or note value is left empty it will coalesced to 0.

<channel-instrument> structure

<integer>

This contains an integer index pointing to the songs instrument array.

<channel-panning> structure

<number>

Set the stereo positioning of the song channel. A value of -1 will cause the channel to play from the left speaker. A value of 1 will cause the channel to play from the right speaker. A value between -1 and 1 will move the channel between the left and right speaker, with 0 causing the channel to play from both.

<channel-note> structure

<number>

The note value describes both the period and attenuation of a note. The period is the integer part of the number and the attentuation is the decimal part (0 - 0.99).

If the period is a value between 1 and 36 the corresponding note will be played using the channel instrument. When a new period is set any note currently playing in the channel is stopped and the channel attenuation is reset. A note value of 0 indicates a noop and -1 indicates note release (stops playing the note)

ValueNoteValueNoteValueNote
01C-10dC-219C-3
02C#10eC#21aC#3
03D-10fD-21bD-3
04D#110D#21cD#3
05E-111E-21dE-3
06F-112F-21eF-3
07F#113F#21fF#3
08G-114G-220G-3
09G#115G#221G#3
0aA-116A-222A-3
0bA#117A#223A#3
0cB-118B-224B-3

The attenuation component is used to control volume - here is an example of playing consecutive C-1 notes while fading out:

[
  1,    // full volume
  1.2,  // 80% volume
  1.4,  // 60% volume
  1.6,  // 40% volume
  1.8   // 20% volume,
  -1    // release (mute the note)
]

<sequence> structure

[
  <integer>,
  ...
]

Sequence is an array of numbers indexing <pattern> entries in the <pattern-list>. Each pattern in the sequence is played until there are no remaining values, at which point the song is complete.

[0, 1, 1, 2]       // play pattern 0 followed by pattern 1 (twice) then pattern 2

<speed> structure

<integer>

The speed of the song in BPM.

<metadata> structure

{
  <song-property>,
  ...
}

Metadata is used to store song information that isn't required for playback such as the title, credits and human-readable aliases for data.

PropertyDescription
titleTitle of the song
authorName of the composer
authorUrlURL of the composer (Website, GitHub profile, Twitter)
licenseThe license for the song
instrumentsArray of instrument names that map to <instrument-list>
const mySong = [
  [
    [1, 0, 200],
    [1, 0, 500]
  ],
  [ /* ... patterns ... */ ],
  [ /* ... sequence ... */ ],
  120,
  {
    "title": "My Song",
    "author": "Keith Clark",
    "authorUrl": "https://keithclark.co.uk/"
    "license": "CC0",
    "instruments": ["Bass", "Piano"]
  }
]