Skip to main content

Overview

MIDI clips contain note data, timing information, and control events. They can be created from scratch, imported from MIDI files, or recorded in real-time.

Creating MIDI Clips

From Scratch

Double-click on a MIDI track to create an empty clip at the cursor position:
public MidiClip(MidiTrack parent, long startingTime = 0)
{
    Track = parent;
    Color = parent.Color;
    _midiClipData = new MidiClipData();
    _pianoRollEditor = new PianoRoll(this, Track as MidiTrack);
    StartTick = startingTime;
}

From Time Selection

Create a clip with a specific duration based on a time selection:
public MidiClip(MidiTrack parent, TimeSelection time)
{
    Track = parent;
    Color = parent.Color;
    _midiClipData = new MidiClipData(time);
    _pianoRollEditor = new PianoRoll(this, Track as MidiTrack);
    StartTick = TimeLineV2.MusicalTimeToTicks(time.Start, true);
}

From MIDI File

Import existing MIDI files:
public MidiClip(MidiTrack parent, string filePath, long startingTime = 0)
{
    Track = parent;
    Name = Path.GetFileNameWithoutExtension(filePath);
    Color = parent.Color;
    var midiFile = MidiFile.Read(filePath);
    _midiClipData = new MidiClipData(midiFile);
    _pianoRollEditor = new PianoRoll(this, Track as MidiTrack);
    StartTick = startingTime;
}

MIDI Clip Data Structure

The MidiClipData class manages the underlying MIDI file and note collection:
public class MidiClipData
{
    public MidiFile MidiFile { get; set; }
    public List<PNote> Notes { get; set; } = new();
    public TempoMap TempoMap { get; set; }
    
    public MidiClipData(MidiFile midiFile)
    {
        MidiFile = midiFile;
        foreach (var note in midiFile.GetNotes())
        {
            Notes.Add(new PNote(note));
        }
        TempoMap = midiFile.GetTempoMap();
    }
}

Note Representation

Each note is wrapped in a PNote object:
public class PNote
{
    /// <summary>
    /// Note data like time, length, velocity, pitch
    /// </summary>
    public Note Data { get; set; }
    
    /// <summary>
    /// Note state (enabled/disabled)
    /// </summary>
    public bool Enabled { get; set; } = true;
}

Clip Properties

Duration and Timing

Clip duration is calculated from the MIDI data:
protected override long GetClipDuration()
{
    return TimeLineV2.SecondsToTicks(
        _midiClipData.MidiFile.GetDuration<MetricTimeSpan>().TotalSeconds, 
        false
    );
}

Width Calculation

Clip width adapts to zoom level:
protected override float GetClipWidth()
{
    return TimeLineV2.SecondsToTicks(
        _midiClipData.MidiFile.GetDuration<MetricTimeSpan>().TotalSeconds, 
        false
    ) * TimeLineV2.PixelsPerTick;
}

Editing MIDI Clips

Opening the Piano Roll

Double-click a clip to open it in the piano roll editor:
protected override void OnClipDoubleClickLeft()
{
    ArrangementView.SelectedClips.Clear();
    MidiClipView.SelectedMidiClip = this;
    _pianoRollEditor._notes = _midiClipData.Notes.ToList();
    BottomView.RenderedWindow = BottomViewWindows.MidiClipView;
}

Updating Clip Data

Modify clip data programmatically:
public void UpdateClipData(MidiClipData newdata)
{
    _midiClipData = newdata;
}

Visual Rendering

Clips display MIDI notes in the arrangement view:
protected override void RenderClipContent(float menuBarHeight, float clipHeight)
{
    MidiRenderer.RenderMidiData(
        _midiClipData, 
        ImGui.GetWindowPos() + new Vector2(0, menuBarHeight), 
        ClipWidth, 
        clipHeight, 
        Track.Enabled
    );
}

MIDI Clip Operations

Time Stretching

Resize clips to half or double their length:
// Half speed (twice as long)
midiClip.MidiClipData.MidiFile.Resize(2);

// Double speed (half as long)
midiClip.MidiClipData.MidiFile.Resize(0.5f);
Available in the MIDI Clip View panel.

Clip View Panel

The MIDI Clip View provides advanced editing features:
public static class MidiClipView
{
    public enum MidiClipViewTabs
    {
        Notes,
        Envelopes
    }
    
    public static MidiClip SelectedMidiClip { get; set; }
}

Available Features

Note Editing

Full piano roll editor with note drawing, selection, and modification.

Time Operations

Resize, reverse, and time-stretch MIDI data.

Velocity Control

Adjust velocity ranges for all notes or selected notes.

Envelopes

Automate MIDI CC parameters with envelope curves.

Clip Information Display

View timing information in musical notation:
string start = $"{SelectedMidiClip.StartMusicalTime.Bars}:{SelectedMidiClip.StartMusicalTime.Beats}:{SelectedMidiClip.StartMusicalTime.Ticks}";
string end = $"{SelectedMidiClip.EndMusicalTime.Bars}:{SelectedMidiClip.EndMusicalTime.Beats}:{SelectedMidiClip.EndMusualTime.Ticks}";
var length = SelectedMidiClip.EndMusicalTime - SelectedMidiClip.StartMusicalTime;
string duration = $"{length.Bars}:{length.Beats}:{length.Ticks}";

Working with Notes

Note Properties

Each note contains:
  • Pitch: MIDI note number (0-127)
  • Velocity: Note intensity (0-127)
  • Time: Start position in ticks
  • Length: Duration in ticks
  • Channel: MIDI channel (0-15)

Note States

Notes can be enabled or disabled:
// Disable notes (mute without deleting)
note.Enabled = false;

// Re-enable notes
note.Enabled = true;
Disabled notes appear dimmed in the piano roll and won’t play during playback.
When updating clip data, always ensure the tempo map is synchronized to maintain correct timing.

Performance Considerations

Files with thousands of notes may cause slowdowns in the piano roll. Consider splitting into smaller clips or quantizing dense data.
The clip view updates in real-time as you edit. For complex operations, edits are batched to maintain smooth performance.
Each clip maintains its own copy of MIDI data. Use linked clips (future feature) to share data between instances.

File Format Support

Lumix supports standard MIDI file formats:
  • Type 0: Single track
  • Type 1: Multiple tracks (merged on import)
  • Type 2: Multiple independent patterns
Imported MIDI files preserve tempo maps, time signatures, and control change events.

See Also

Build docs developers (and LLMs) love