Docs

MIDI Player

A MidiPlayer reference can be used to control the playback of a MIDI Player module as well as processing the currently loaded MIDI sequency. It also acts as event controller for building customised UI elements that display the MIDI content.

Class methods

asMidiProcessor

Returns a typed MIDI processor reference (for setting attributes etc).

MidiPlayer.asMidiProcessor()



connectToMetronome

Connects this MIDI player to the given metronome.

MidiPlayer.connectToMetronome(var metronome)



connectToPanel

Connect this to the panel and it will be automatically updated when something changes.

MidiPlayer.connectToPanel(var panel)


This function is particularly helpful when you want to build a custom UI for the MIDI Player's content.

Once this is called and a ScriptPanel is connected to this reference, It will automatically cause a repaint of the ScriptPanel on these events:

You can then use the functions getNoteRectangleList and getPlaybackPosition() to fetch the data and write the UI logic you want.

convertEventListToNoteRectangles

Converts a given array of Message holders to a rectangle list.

MidiPlayer.convertEventListToNoteRectangles(var eventList, var targetBounds)



create

Creates an empty sequence with the given length.

MidiPlayer.create(int nominator, int denominator, int barLength)


The nominator and denominator will define the time signature, so for a 3/4 time signature and 7 bars, use MidiPlayer.create(3, 4, 7)

Be aware that this adds a new sequence to the player add the end of the list, so you probably want to check isEmpty() if you just want to write a bunch of notes

flushMessageList

Writes the given array of MessageHolder objects into the current sequence. This is undoable.

MidiPlayer.flushMessageList(var messageList)



getEventList

Creates an array containing all MIDI messages wrapped into MessageHolders for processing.

MidiPlayer.getEventList()


This is the first step of three when you want to process the content of a MIDI Player.
It creates an array of MessageHolder objects which can be used to transform the MIDI data.

The event ID of the events will be created consecutively and the events are sorted chronologically. You can find the matching note-off event to a note-on event using something like this:

inline function getNoteOff(list, noteOn)
{
    for(e in list)
    {
        if(e.isNoteOff() && e.getEventId() == noteOn.getEventId())
            return e;
    }
}

The timestamp will be using the current samplerate and host BPM tempo to convert the relative MIDI timing to absolute sample positions. Be careful to never change the order of a note-on / note-off pair, otherwise the results will be very weird.

There are a few new helper functions in the Engine class to help you converting between the domains (search for QuarterBeats )

Also make sure to call flushMessageList() after finishing the processing to apply the changes.

getLastPlayedNotePosition

Returns the position of the last played note.

MidiPlayer.getLastPlayedNotePosition()



getMidiFileList

Returns a list of all MIDI files that are embedded in the plugin.

MidiPlayer.getMidiFileList()



getNoteRectangleList

Returns an array containing all notes converted to the space supplied with the target bounds [x, y, w, h].

MidiPlayer.getNoteRectangleList(var targetBounds)


This converts the MIDI data in the current sequence to a list of rectangles for each note scaled to fill the rectangle supplied as argument.

A rectangle in HISEScript is always an array of 4 integers:
[x, y, width, height] .

The most simple application of this is to draw a piano-roll content into a Panel.

// Fetch a Panel
const var Panel = Content.getComponent("Panel1");

// Fetch a MIDI Player
const var Player = Synth.getMidiPlayer("MIDI Player1");

// Connect the player to the panel to make it update automatically
Player.connectToPanel(Panel);

Panel.setPaintRoutine(function(g)
{
    // create a list of note rectangles.
    // the argument is the boundaries of this panel so it will scale
    // them to the dimensions of the entire panel.
    var entireArea = [0, 0, this.getWidth(), this.getHeight()];
    var list = Player.getNoteRectangleList(entireArea);
    
    g.setColour(Colours.white);

    // Now we can simply iterate over them and paint them
    for(note in list)
    {
        // `note` is a array with 4 numbers and can be passed
        // into all Graphic API functions pretty conveniently.
        g.fillRect(note);
    }
});


getNumSequences

Returns the number of loaded sequences.

MidiPlayer.getNumSequences()



getNumTracks

Returns the number of tracks in the current sequence.

MidiPlayer.getNumTracks()



getPlaybackPosition

Returns the playback position in the current loop between 0.0 and 1.0.

MidiPlayer.getPlaybackPosition()



getTicksPerQuarter

Returns the tick resolution for a quarter note.

MidiPlayer.getTicksPerQuarter()



getTimeSignature

Returns an object with properties about the length of the current sequence.

MidiPlayer.getTimeSignature()



isEmpty

Checks if the MIDI player contains a sequence to read / write.

MidiPlayer.isEmpty()


This doesn't check whether the current sequence contains any notes, but checks whether there is any sequence loaded at all: If you load up the MIDI Player, it will not have a sequence loaded until you either load a MIDI file, or call Midiplayer.create .

If you want to check whether the sequence is empty, you can use this:

// Do not call this in the audio thread obviously...
inline function sequenceHasNoEvents(player)
{
    return player.getEventList().length == 0;
}


play

Starts playing. Use the timestamp to delay the event or use the currents event timestamp for sample accurate playback.

MidiPlayer.play(int timestamp)



record

Starts recording (not yet implemented). Use the timestamp to delay the event or use the currents event timestamp for sample accurate playback.

MidiPlayer.record(int timestamp)



redo

Redo the last edit.

MidiPlayer.redo()


Just like undo() , this will not use the global undo manager, but a dedicated undo manager for each MIDI player (otherwise the actions interfere with changing UI values, which would be very annoying).

reset

Resets the current sequence to the last loaded file.

MidiPlayer.reset()



saveAsMidiFile

Saves the current sequence into the given file at the track position.

MidiPlayer.saveAsMidiFile(var file, int trackIndex)


This overwrites the track (starting with one) in the given file.

This is not undoable and the original content will be swept into digital nirvana (except if you have a backup of the original file, obviously), so NEVER use this method unless you know exactly what to do .

setAutomationHandlerConsumesControllerEvents

This will send any CC messages from the MIDI file to the global MIDI handler.

MidiPlayer.setAutomationHandlerConsumesControllerEvents(bool shouldBeEnabled)



setFile

Loads a MIDI file and switches to this sequence if specified.

MidiPlayer.setFile(var fileName, bool clearExistingSequences, bool selectNewSequence)



setGlobalPlaybackRatio

Sets a global playback ratio (for all MIDI players).

MidiPlayer.setGlobalPlaybackRatio(double globalRatio)



setPlaybackCallback

Attaches a callback with two arguments (timestamp, playState) that gets executed when the play state changes.

MidiPlayer.setPlaybackCallback(var playbackCallback, var synchronous)



setPlaybackPosition

Sets the playback position in the current loop. Input must be between 0.0 and 1.0.

MidiPlayer.setPlaybackPosition(var newPosition)


Similar to AudioSampleProcessor.setFile() , this will load a file into the MIDI player.

It uses the standard HISE syntax for file references . The other arguments let you choose


setRecordEventCallback

Sets a inline function that will process every note that is about to be recorded.

MidiPlayer.setRecordEventCallback(var recordEventCallback)



setRepaintOnPositionChange

If true, the panel will get a repaint() call whenever the playback position changes.

MidiPlayer.setRepaintOnPositionChange(var shouldRepaintPanel)


By default this is off, but if you need your connected Panel to repaint during playback (eg. to display a ruler that indicates the position), set this to true and it repaint() will be called periodically during playback.

setSequence

Enables the (previously loaded) sequence with the given index.

MidiPlayer.setSequence(int sequenceIndex)



setSequenceCallback

Attaches a callback that gets executed whenever the sequence was changed.

MidiPlayer.setSequenceCallback(var updateFunction)



setSyncToMasterClock

Syncs the playback of this MIDI player to the master clock (external or internal).

MidiPlayer.setSyncToMasterClock(bool shouldSyncToMasterClock)



setTimeSignature

Sets the timing information of the current sequence using the given object.

MidiPlayer.setTimeSignature(var timeSignatureObject)



setTrack

Sets the track index (starting with one).

MidiPlayer.setTrack(int trackIndex)


This makes the MIDI Player choose the selected track (again, starting with 1 , not with zero). Be aware that changing tracks is not as "dynamic" as switching between different sequences.

setUseGlobalUndoManager

If enabled, it uses the global undo manager for all edits (So you can use Engine.undo()).

MidiPlayer.setUseGlobalUndoManager(bool shouldUseGlobalUndoManager)



setUseTimestampInTicks

Uses Ticks instead of samples when editing the MIDI data.

MidiPlayer.setUseTimestampInTicks(bool shouldUseTicksAsTimestamps)



stop

Starts playing. Use the timestamp to delay the event or use the currents event timestamp for sample accurate playback.

MidiPlayer.stop(int timestamp)



undo

Undo the last edit.

MidiPlayer.undo()