Skip to content

Sequencer Class

spessasus edited this page Oct 17, 2024 · 25 revisions

Sequencer Class

This is the module that plays the parsed MIDI files using the Synthetizer class.

Tip

If you encounter any errors in this documentation, please open an issue!

Table of Contents

Importing

// normal install
import {Sequencer} from "./spessasynth_lib/sequencer/sequencer.js";
// npm package
import {Sequencer} from "spessasynth_lib";

Important

Using the npm package? Make sure you've read this

Initialization

const sequencer = new Sequencer(midiBuffers, synth, options);
  • midiBuffers - an array of the MIDI files to play. Either MIDI or objects with two properties:
    • binary: the ArrayBuffer representation of the file. Can be mixed up.
    • altName - alternative name of the sequence if it doesn't have one. Can be undefined.
  • synth - the synthetizer to use. An instance of the Synthetizer class.
  • options - an optional Object with options for the sequencer:
    • skipToFirstNoteOn - a boolean indicating if the sequencer should skip to the first note on. Defaults to true.
    • autoPlay - a boolean indicating if the first supplied sequence should start playing. Defaults to true.
    • preservePlaybackState - a boolean indicating if seeking or changing the playback rate will be kept paused instead of resuming. Defaults to false.

Tip

For performance reasons, it is recommended passing the binary data rather than the parsed MIDI instance.

Caution

Due to the way the sequencer has been coded, only one sequencer can be used with a Synthetizer instance at once! If this is something that you want to be fixed, feel free to open an issue.

Methods

loadNewSongList

Loads a new song list.

sequencer.loadNewSongList(midiBuffers, autoPlay = true);
  • midiBuffers - an array of the parsed MIDI files to play, Either MIDI or objects (can be mixed up) with two properties:
    • binary - the ArrayBuffer representation of the file.
    • altName - alternative name of the sequence if it doesn't have one (like file name for example). string, can be undefined.
  • autoPlay - a boolean indicating if the first supplied sequence should start playing. Defaults to true.

Note

If only one file is supplied, the loop will be set to false.

play

Starts playing the sequence. If the sequence was paused, it won't change any controllers, but if it wasn't (ex. the time was changed) then it will go through all the controller changes from the start before playing. This function does NOT modify the current playback time!

sequencer.play(resetTime);
  • resetTime - boolean, if set to true then the playback will start from 0. Defaults to false;

pause

Pauses the playback of the sequence.

sequencer.pause();

stop

Stops the playback of the sequence. Currently only used internally by the pause function.

sequencer.stop();

nextSong

Plays the next song in the list.

sequencer.nextSong();

previousSong

Plays the previous song in the list.

sequencer.previousSong();

connectMidiOutput

Connects a given MIDI output port and plays the sequence to it.

sequencer.connectMidiOutput(output);
  • output - a MIDIOutput object, the output port to play to.

Tip

Pass undefined to use SpessaSynth.

Note

You can also use MIDIDeviceHandler

addOnSongChangeEvent

Hooks up a given callback function to the song change event.

sequencer.addOnSongChangeEvent(callback, id);
  • callback - the function that gets called back, takes a MidiData instance (the new song).
  • id - string, unique identifier for the callback. Can be anything as long as it's unique.

Important

This is the MidiData type, not MIDI. It has all the properties of MIDI, except the tracks property, which is the actual song data.

addOnTimeChangeEvent

Hooks up a given callback function to the time change event.

sequencer.addOnTimeChangeEvent(callback, id);
  • callback - the function that gets called back, takes a number (the new time, in seconds).
  • id - string, unique identifier for the callback. Can be anything as long as it's unique.

addOnSongEndedEvent

Hooks up a given callback function to the song end.

sequencer.addOnSongEndedEvent(callback, id);
  • callback - the function that gets called back, no arguments.
  • id - string, unique identifier for the callback. Can be anything as long as it's unique.

Warning

This will only get called if the loop is disabled.

getMIDI

Gets the actual MIDI sequence, complete with track data.

const data = await sequencer.getMIDI();

Important

This function is asynchronous.

Warning

The track data can potentially have hundreds of thousands of messages for complex MIDIs. Use sparingly!

Properties

Time control

paused

Read-only boolean, indicating that if the sequencer's playback is paused.

if(sequencer.paused)
{
   console.log("Sequencer paused!");
}
else
{
   console.log("Sequencer playing or stopped!");
}

playbackRate

Indicates how fast the song plays (1 is normal, 0.5 is half speed etc.)

sequencer.playbackRate = 0.5; // the playback speed is half the normal speed

loop

Boolean that controls if the sequencer loops.

sequencer.loop = false; // the playback will stop after reaching the end

currentTime

Property used for changing and reading the current playback time.

get

Returns the current playback time in seconds.

console.log("The sequence is currently "+sequencer.currentTime+" seconds in.");
set

Sets the current playback time. Calls stop and then play internally.

sequencer.currentTime = 0; // go to the start

skipToFirstNoteOn

A boolean indicating if the sequencer should skip to the first note on when the time is set to 0.

sequencer.skipToFirstNoteOn = false; // sequencer will no longer skip

preservePlaybackState

A boolean indicating if seeking or changing the playback rate will be kept paused instead of resuming.

sequencer.preservePlaybackState = true; // now the song will stay paused when seeking

Song Info

midiData

The data of the current sequence. Essentially MIDI except for the tracks property (the song data).

console.log(`This song is named "${sequencer.midiData.midiName}"`);

Tip

To get the actual MIDI data, use the getMIDI method.

Important

The sequencer doesn't instantly get the new midi information. Make sure to use addOnSongChangeEvent instead of waiting or assuming that the data is available instantly. Also keep in mind that The sequencer preloads the samples for the MIDI, which might take a bit!

duration

Length of the track in seconds. Equivalent of Audio.duration;

console.log(`The track lasts for ${sequencer.duration} seconds!`);

songIndex

The current index of the song that's playing

console.log(sequencer.songIndex); // 0

songsAmount

The amount of songs in the queue.

console.log(sequencer.songsAmount); // 3

Events

onTextEvent

A callback function if defined. Will be called on a text event, like lyrics.

sequencer.onTextEvent = (messageData, messageType) => {
    const text = new TextDecoder("utf-8").decode(messageData.buffer);
    console.log("Text event:", text)
}

Parameters:

  • messageData - Uint8Array, the message's data (excluding the statusByte).
  • messageType - the Status byte of the meta message useful for derermining if the message is lyrics, or something else.

onError

A callback function if defined. Will be called on MIDI parsing error.

sequencer.onError = e => {
    console.log(e);
}
  • e - string, the error message. For example Invalid MIDI Header! Expected "MThd", got "#!/u"
Clone this wiki locally