Skip to content

Track Generators

This document details each track generator in MIDI Sketch.

Track Overview

MIDI Sketch generates 8 tracks across different MIDI channels:

Channel Assignment

TrackChannelProgramRole
Vocal0Piano (0)Main melody
Aux5Pad (89)Sub-melody support
Chord2E.Piano (4)Harmonic backing
Bass3E.Bass (33)Harmonic foundation
Motif4Synth (81)BackgroundMotif style
Arpeggio5Synth (81)SynthDriven style
Drums9GM DrumsRhythm
SE15-Section markers

Vocal Track

Source: src/track/vocal.cpp (~470 lines), src/track/melody_designer.cpp (~520 lines)

The vocal system uses a template-driven melody designer for predictable, stylistically-accurate melody generation.

Architecture

The vocal generation is split into two components:

  1. MelodyDesigner (melody_designer.cpp) - Template-driven pitch selection
  2. Vocal Generator (vocal.cpp) - Section structure and coordination

Melody Templates

7 melody templates define melodic characteristics:

IDNamePlateauMax StepUse Case
0Auto--VocalStyle-based selection
1PlateauTalk0.652NewJeans, Billie Eilish style
2RunUpTarget0.204YOASOBI, Ado style
3DownResolve0.303B-section, pre-chorus
4HookRepeat0.403TikTok, K-POP hooks
5SparseAnchor0.502Official髭男dism, ballad
6CallResponse--Duet patterns
7JumpAccent--Emotional peaks
  • Plateau ratio: Probability of staying on the same pitch (higher = more repetitive)
  • Max step: Maximum interval in semitones (lower = smoother)

Generation Flow

Pitch Selection (4 Choices Only)

The MelodyDesigner limits pitch selection to 4 options:

cpp
enum class PitchChoice {
    Same,       // Stay on current pitch (plateau_ratio)
    StepUp,     // +1 semitone
    StepDown,   // -1 semitone
    TargetStep  // ±2 toward target (if template has target)
};

This constrained approach produces more natural, singable melodies.

Vocal Attitudes

AttitudeDescriptionImplementation
CleanConservative, singableChord tones only, on-beat
ExpressiveEmotional, dynamicTensions allowed, timing variance
RawEdgy, unconventionalNon-chord tones, boundary breaking

Phrase Caching

Phrases are cached by section type to ensure musical coherence:

cpp
std::map<SectionType, std::vector<Phrase>> phraseCache_;

// A section uses same/similar phrases when repeated
// Chorus maintains its melodic identity

Range Constraints

cpp
struct VocalRange {
    uint8_t low = 60;   // C4
    uint8_t high = 79;  // G5
};

Aux Track

Source: src/track/aux_track.cpp (~440 lines)

The Aux (auxiliary) track provides sub-melody support for the main vocal. It's not a counter-melody, but a "perceptual control layer" that enhances the main melody.

Purpose

RoleDescription
AddictivenessPulse loops create repetitive, catchy patterns
PhysicalityGroove accents add body movement feel
StabilityPhrase tails provide resolution
StructureHelps listeners perceive section boundaries

Aux Functions

5 auxiliary functions are available:

IDFunctionDescription
APulseLoopRepetitive same-pitch or fixed-interval patterns
BTargetHintHints at vocal target with chord tones
CGrooveAccentRhythmic accents with staccato
DPhraseTailEnd-of-phrase descending resolution
EEmotionalPadLong sustained chord tones

Template → Aux Mapping

Each melody template automatically selects appropriate aux functions:

TemplateAux FunctionsReason
PlateauTalkA (PulseLoop)Ice Cream / minimal style
RunUpTargetB + DYOASOBI ascending then resolving
HookRepeatA + CTikTok repetitive hooks
SparseAnchorE + DBallad emotional support

Generation Constraints

  • Always generated after vocal (to avoid collisions)
  • Narrower range than vocal (50-70% of vocal range)
  • Lower velocity (0.5-0.8× vocal velocity)
  • Uses HarmonyContext to avoid dissonance with vocal

Chord Track

Source: src/track/chord_track.cpp (~820 lines)

Generates harmonic voicings with voice leading optimization.

Voicing Types

Voice Leading Algorithm

cpp
int voiceLeadingDistance(Voicing& prev, Voicing& next) {
    int distance = 0;
    for (int i = 0; i < 4; i++) {
        distance += abs(prev.notes[i] - next.notes[i]);
    }
    return distance;
}

// Select voicing that minimizes distance
Voicing selectBestVoicing(Voicing& prev, vector<Voicing>& candidates) {
    return min_element(candidates, [&](auto& a, auto& b) {
        return voiceLeadingDistance(prev, a) < voiceLeadingDistance(prev, b);
    });
}

Bass Coordination

Uses BassAnalysis to avoid doubling:

cpp
if (bassAnalysis.hasRootOnBeat1) {
    // Use rootless voicing - bass provides root
    voicing = generateRootlessVoicing(chord);
} else {
    // Include root in chord voicing
    voicing = generateFullVoicing(chord);
}

Register Constraints

cpp
constexpr uint8_t CHORD_LOW = 48;   // C3
constexpr uint8_t CHORD_HIGH = 84;  // C6

Bass Track

Source: src/track/bass.cpp (~450 lines)

Generates the harmonic foundation with root-focused patterns.

Pattern Types

PatternDescriptionRhythm
SparseMinimal, ballad-styleBeat 1 only
StandardPop/rock baselineBeats 1, 3 with fills
DrivingEnergetic, forwardEighth notes throughout

Generation Logic

Approach Notes

Beat 4 may use chromatic approach to next root:

cpp
// If next chord root is C
// Beat 4 could be B (half step below) or Db (half step above)
uint8_t approachNote = nextRoot - 1; // chromatic approach

Drums Track

Source: src/track/drums.cpp (~680 lines)

Generates drum patterns with fills and dynamics.

GM Drum Map

cpp
constexpr uint8_t KICK = 36;
constexpr uint8_t SNARE = 38;
constexpr uint8_t SIDE_STICK = 37;
constexpr uint8_t CLOSED_HH = 42;
constexpr uint8_t OPEN_HH = 46;
constexpr uint8_t RIDE = 51;
constexpr uint8_t CRASH = 49;
constexpr uint8_t TOM_HIGH = 50;
constexpr uint8_t TOM_MID = 47;
constexpr uint8_t TOM_LOW = 45;

Pattern Styles

Fill Types

cpp
enum class FillType {
    TomDescend,    // High → Mid → Low tom
    TomAscend,     // Low → Mid → High tom
    SnareRoll,     // Rapid snare hits
    Combo          // Mixed elements
};

Fills are inserted at:

  • Section transitions
  • Every 4 or 8 bars
  • Before chorus

Ghost Notes

Velocity-reduced snare articulations for groove:

cpp
// Main snare: velocity 100
// Ghost note: velocity 40-60

Motif Track

Source: src/track/motif.cpp (~470 lines)

For BackgroundMotif composition style. Creates repeating patterns.

Parameters

cpp
struct MotifParams {
    MotifLength length;           // TwoBars, FourBars
    RhythmDensity rhythm_density; // Sparse, Medium, Driving
    MotifMotion motion;           // Stepwise, GentleLeap
    RepeatScope repeat_scope;     // FullSong, PerSection
    MotifRegister register_;      // Mid, High
};

Pattern Generation

Register Ranges

RegisterRange
MidC3 (48) - C5 (72)
HighC4 (60) - C6 (84)

Arpeggio Track

Source: src/track/arpeggio.cpp (~200 lines)

For SynthDriven composition style. Creates arpeggiated patterns.

Parameters

cpp
struct ArpeggioParams {
    ArpeggioPattern pattern;  // Up, Down, UpDown, Random
    ArpeggioSpeed speed;      // Eighth, Sixteenth, Triplet
    uint8_t octave_range;     // 1-3 octaves
    float gate;               // Note length ratio (0.0-1.0)
    bool sync_chord;          // Follow chord changes
};

Pattern Types

Speed Conversion

cpp
Tick getNoteDuration(ArpeggioSpeed speed) {
    switch (speed) {
        case Eighth:    return TICKS_PER_BEAT / 2;    // 240
        case Sixteenth: return TICKS_PER_BEAT / 4;    // 120
        case Triplet:   return TICKS_PER_BEAT / 3;    // 160
    }
}

SE Track

Source: src/track/se.cpp (~15 lines)

Minimal track for section markers (text events only).

cpp
void generateSE(Song& song) {
    for (auto& section : song.arrangement.sections) {
        MidiEvent marker;
        marker.tick = section.start_tick;
        marker.type = MidiEventType::Text;
        marker.text = section.name;
        song.se.addEvent(marker);
    end
}

Velocity Calculation

Common velocity formula across tracks:

cpp
uint8_t calculateVelocity(
    uint8_t baseVelocity,
    int beat,
    SectionType section,
    float trackBalance
) {
    float beatAdjust = getBeatAccent(beat);      // Strong beats: +10
    float sectionMult = getSectionEnergy(section); // Chorus: 1.2

    return clamp(
        baseVelocity * beatAdjust * sectionMult * trackBalance,
        1, 127
    );
}

Track Balance

TrackBalanceNotes
Vocal1.00Lead instrument
Aux0.50-0.80Sub-melody support
Chord0.75Supporting
Bass0.85Foundation
Drums0.90Timing driver
Motif0.70Background
Arpeggio0.85Mid-level

Released under the MIT License.