C++ API Reference
This page documents the native C++ API and the C ABI used by FFI and WASM bindings. The C ABI accepts JSON for configuration; it has no binary configuration structs.
MidiSketch Class
Constructor
#include "midisketch.h"
midisketch::MidiSketch sketch;Header Files
- midisketch.h - C++ class API
- midisketch_c.h - C ABI for FFI/WASM bindings
- core/types.h - Core types included by the C++ API
generate(params)
Generate a song from the lower-level GeneratorParams type.
midisketch::GeneratorParams params;
params.key = midisketch::Key::C;
params.bpm = 120;
params.seed = 12345;
sketch.generate(params);generateFromConfig(config)
Generate MIDI from SongConfig. bpm = 0 and seed = 0 select the style default tempo and a generated seed. chord_progression_id = 255 selects a progression from the style recommendations.
using namespace midisketch;
SongConfig config;
config.style_preset_id = 0;
config.key = Key::C;
config.bpm = 120;
config.seed = 12345;
config.chord_progression_id = 255;
config.form = StructurePattern::StandardPop;
config.vocal_attitude = VocalAttitude::Expressive;
config.drums_enabled = true;
config.guitar_enabled = true;
config.arpeggio_enabled = false;
config.arpeggio.pattern = ArpeggioPattern::Up;
config.arpeggio.speed = ArpeggioSpeed::Sixteenth;
config.arpeggio.octave_range = 2;
config.arpeggio.gate = 0.8f;
config.arpeggio.sync_chord = true;
config.chord_extension.enable_7th = false;
config.chord_extension.seventh_probability = 0.15f;
config.humanize = false;
config.call_setting = CallSetting::Auto;
config.call_density = CallDensity::Standard;
sketch.generateFromConfig(config);Parameter Dependencies
Some fields take effect only when their parent option is enabled. For example, arpeggio.pattern is ignored when arpeggio_enabled is false. See Option Relationships for the dependency tree.
generateVocal(config)
Generate the vocal track without accompaniment.
SongConfig config;
config.style_preset_id = 0;
config.key = Key::C;
config.bpm = 120;
config.vocal_attitude = VocalAttitude::Expressive;
sketch.generateVocal(config);regenerateVocal(config)
Regenerate the vocal track while retaining the current chord progression and structure. The seed overload regenerates with a new seed.
sketch.regenerateVocal(12345);
VocalConfig vocal_config;
vocal_config.seed = 12345;
vocal_config.vocal_low = 60;
vocal_config.vocal_high = 79;
vocal_config.vocal_attitude = VocalAttitude::Expressive;
vocal_config.vocal_style = VocalStylePreset::Auto;
vocal_config.keep_motif = false;
sketch.regenerateVocal(vocal_config);VocalConfig constructed in C++ has present_fields = kAllFields, so all declared fields participate. JSON updates can provide a subset; readFrom records the supplied fields in present_fields.
generateAccompanimentForVocal(config?)
Generate enabled accompaniment tracks for an existing vocal. Call this after generateVocal(), generateWithVocal(), or setVocalNotes().
sketch.generateAccompanimentForVocal();
AccompanimentConfig accompaniment;
accompaniment.seed = 12345;
accompaniment.drums_enabled = true;
accompaniment.guitar_enabled = true;
accompaniment.arpeggio_enabled = false;
accompaniment.arpeggio_gate = 80; // 0-100
accompaniment.humanize_timing = 0.4f; // 0.0-1.0
accompaniment.humanize_velocity = 0.3f; // 0.0-1.0
sketch.generateAccompanimentForVocal(accompaniment);AccompanimentConfig constructed in C++ has present_fields = kAllFields. Its probability and humanization fields use normalized 0.0-1.0 floats; arpeggio_gate uses 0-100.
regenerateAccompaniment(seedOrConfig)
Keep the current vocal and regenerate accompaniment tracks with a new seed or configuration.
sketch.regenerateAccompaniment(12345);
AccompanimentConfig accompaniment;
accompaniment.seed = 12345;
accompaniment.drums_enabled = true;
accompaniment.arpeggio_enabled = true;
sketch.regenerateAccompaniment(accompaniment);generateWithVocal(config)
Generate all tracks with vocal-first priority.
SongConfig config;
config.style_preset_id = 0;
config.key = Key::C;
config.bpm = 120;
sketch.generateWithVocal(config);setVocalNotes(config, notes)
Initialize structure and chords from config, replace the vocal track with supplied notes, and then generate accompaniment. NoteEvent constructors are private; use NoteEventBuilder::create().
SongConfig config;
config.style_preset_id = 0;
config.key = Key::C;
config.bpm = 120;
std::vector<NoteEvent> notes = {
NoteEventBuilder::create(0, 480, 60, 100),
NoteEventBuilder::create(480, 480, 62, 100),
NoteEventBuilder::create(960, 960, 64, 100),
};
sketch.setVocalNotes(config, notes);
sketch.generateAccompanimentForVocal();
auto midi = sketch.getMidi();getMidi()
Return the generated MIDI file as an owning std::vector<uint8_t> copy.
std::vector<uint8_t> midi_data = sketch.getMidi();
std::ofstream out("output.mid", std::ios::binary);
out.write(reinterpret_cast<const char*>(midi_data.data()),
static_cast<std::streamsize>(midi_data.size()));getVocalPreviewMidi()
Return a minimal MIDI file containing the vocal melody and root-bass guide as an owning byte-vector copy.
auto preview = sketch.getVocalPreviewMidi();getEventsJson()
Return event data for visualization or playback as an owning std::string copy.
std::string events_json = sketch.getEventsJson();getMelody() / setMelody(melody)
Save and restore vocal melody candidates.
MelodyData candidate = sketch.getMelody();
// ...try another candidate...
sketch.setMelody(candidate);getSong() / getParams() / getWarnings()
Return read-only references to state owned by sketch. The references remain valid until destruction; later generation calls can change their contents.
const Song& song = sketch.getSong();
const GeneratorParams& params = sketch.getParams();
const std::vector<std::string>& warnings = sketch.getWarnings();getWarnings() reports non-fatal warnings from the latest generation operation.
getHarmonyContext()
Return the read-only harmony context used by the piano-roll safety API.
const IHarmonyContext& harmony = sketch.getHarmonyContext();setMidiFormat(format) / getMidiFormat()
Select or query the MIDI output format. New MidiSketch instances use MidiFormat::SMF1 by default.
sketch.setMidiFormat(MidiFormat::SMF1); // Standard MIDI File Type 1
sketch.setMidiFormat(MidiFormat::SMF2); // MIDI 2.0 Container File
MidiFormat format = sketch.getMidiFormat();resolvedBlueprintId()
Return the blueprint selected by the latest generation. Call this after generation.
uint8_t blueprint_id = sketch.resolvedBlueprintId();version()
Return the library version string as a borrowed static string.
const char* version = MidiSketch::version();Generation Workflows
MidiSketch supports BGM-first, vocal-first, and custom-vocal workflows.
Choosing a Workflow
| Workflow | Use case |
|---|---|
| BGM-first | Generate accompaniment before adding vocals |
| Vocal-first | Iterate on a generated melody before accompaniment |
| Custom Vocal | Import notes and generate matching accompaniment |
BGM-First Workflow
MidiSketch sketch;
SongConfig config;
config.style_preset_id = 0;
config.skip_vocal = true;
sketch.generateFromConfig(config);
VocalConfig vocal;
vocal.seed = 0;
vocal.vocal_low = 60;
vocal.vocal_high = 79;
sketch.regenerateVocal(vocal);
auto midi = sketch.getMidi();Vocal-First Workflow
MidiSketch sketch;
SongConfig config;
config.style_preset_id = 0;
sketch.generateVocal(config);
VocalConfig vocal;
vocal.seed = 12345;
vocal.vocal_attitude = VocalAttitude::Expressive;
sketch.regenerateVocal(vocal);
sketch.generateAccompanimentForVocal();
auto midi = sketch.getMidi();Custom Vocal Import Workflow
MidiSketch sketch;
SongConfig config;
config.style_preset_id = 0;
std::vector<NoteEvent> notes = {
NoteEventBuilder::create(0, 480, 60, 100),
NoteEventBuilder::create(480, 480, 62, 100),
NoteEventBuilder::create(960, 960, 64, 100),
};
sketch.setVocalNotes(config, notes);
sketch.generateAccompanimentForVocal();
auto midi = sketch.getMidi();Core Types
SongConfig
The high-level configuration passed to generateFromConfig(), generateVocal(), generateWithVocal(), and setVocalNotes().
struct SongConfig {
uint8_t style_preset_id = 0;
uint8_t blueprint_id = 0; // 255 = random blueprint
uint8_t mood = 0;
bool mood_explicit = false;
Key key = Key::C;
uint16_t bpm = 0; // 0 = style default
uint32_t seed = 0; // 0 = random
uint8_t chord_progression_id = 255; // 255 = style auto-selection
StructurePattern form = StructurePattern::StandardPop;
bool form_explicit = false;
uint16_t target_duration_seconds = 0; // 0 = use form
VocalAttitude vocal_attitude = VocalAttitude::Clean;
VocalStylePreset vocal_style = VocalStylePreset::Auto;
uint8_t drive_feel = 50; // 0-100
bool drums_enabled = true;
bool drums_enabled_explicit = false;
bool arpeggio_enabled = false;
bool guitar_enabled = true;
bool skip_vocal = false;
uint8_t vocal_low = 60;
uint8_t vocal_high = 79;
ArpeggioParams arpeggio;
ChordExtensionParams chord_extension;
bool chord_ext_prob_explicit = false;
CompositionStyle composition_style = CompositionStyle::MelodyLead;
bool composition_style_explicit = false;
MotifChordParams motif_chord;
MotifRepeatScope motif_repeat_scope = MotifRepeatScope::FullSong;
ArrangementGrowth arrangement_growth = ArrangementGrowth::LayerAdd;
bool humanize = false;
float humanize_timing = 0.4f;
float humanize_velocity = 0.3f;
ModulationTiming modulation_timing = ModulationTiming::None;
int8_t modulation_semitones = 2;
bool se_enabled = true;
CallSetting call_setting = CallSetting::Auto;
bool call_notes_enabled = true;
IntroChant intro_chant = IntroChant::None;
MixPattern mix_pattern = MixPattern::None;
CallDensity call_density = CallDensity::Standard;
MelodyTemplateId melody_template = MelodyTemplateId::Auto;
MelodicComplexity melodic_complexity = MelodicComplexity::Standard;
HookIntensity hook_intensity = HookIntensity::Normal;
VocalGrooveFeel vocal_groove = VocalGrooveFeel::Straight;
bool enable_syncopation = false;
EnergyCurve energy_curve = EnergyCurve::GradualBuild;
uint8_t melody_max_leap = 0;
uint8_t melody_syncopation_prob = 0xFF;
uint8_t melody_phrase_length = 0;
uint8_t melody_long_note_ratio = 0xFF;
int8_t melody_chorus_register_shift = INT8_MIN;
uint8_t melody_hook_repetition = 0;
uint8_t melody_use_leading_tone = 0;
uint8_t motif_length = 0;
uint8_t motif_note_count = 0;
uint8_t motif_motion = 0xFF;
uint8_t motif_register_high = 0;
uint8_t motif_rhythm_density = 0xFF;
bool addictive_mode = false;
uint8_t mora_rhythm_mode = 2;
uint8_t syllabic_sub_rate = 0;
};The JSON field names are the snake_case names shown above. Nested fields are arpeggio, chord_extension, and motif_chord.
ArpeggioParams / ChordExtensionParams
struct ArpeggioParams {
ArpeggioPattern pattern = ArpeggioPattern::Auto;
ArpeggioSpeed speed = ArpeggioSpeed::Auto;
uint8_t octave_range = 2;
float gate = -1.0f; // 0.0-1.0; -1 = style default
bool sync_chord = true;
uint8_t base_velocity = 90;
};
struct ChordExtensionParams {
bool enable_sus = false;
bool enable_7th = false;
bool enable_9th = false;
bool tritone_sub = false;
float sus_probability = 0.2f;
float seventh_probability = 0.15f;
float ninth_probability = 0.25f;
float tritone_sub_probability = 0.5f;
};VocalConfig
Direct C++ construction supplies every field because present_fields defaults to kAllFields (~0u). JSON parsing sets present_fields to the fields present in the object, enabling partial updates.
struct VocalConfig {
static constexpr uint32_t kAllFields = ~0u;
uint32_t present_fields = kAllFields;
uint32_t seed = 0;
uint8_t vocal_low = 60;
uint8_t vocal_high = 79;
VocalAttitude vocal_attitude = VocalAttitude::Clean;
VocalStylePreset vocal_style = VocalStylePreset::Auto;
MelodyTemplateId melody_template = MelodyTemplateId::Auto;
MelodicComplexity melodic_complexity = MelodicComplexity::Standard;
HookIntensity hook_intensity = HookIntensity::Normal;
VocalGrooveFeel vocal_groove = VocalGrooveFeel::Straight;
CompositionStyle composition_style = CompositionStyle::MelodyLead;
bool keep_motif = false;
};AccompanimentConfig
struct AccompanimentConfig {
static constexpr uint32_t kAllFields = ~0u;
uint32_t present_fields = kAllFields;
uint32_t seed = 0;
bool drums_enabled = true;
bool arpeggio_enabled = false;
bool guitar_enabled = true;
uint8_t arpeggio_pattern = 0;
uint8_t arpeggio_speed = 1;
uint8_t arpeggio_octave_range = 2;
uint8_t arpeggio_gate = 80;
bool arpeggio_sync_chord = true;
bool chord_ext_sus = false;
bool chord_ext_7th = false;
bool chord_ext_9th = false;
bool chord_ext_tritone_sub = false;
float chord_ext_sus_prob = 0.2f;
float chord_ext_7th_prob = 0.15f;
float chord_ext_9th_prob = 0.25f;
float chord_ext_tritone_sub_prob = 0.5f;
bool humanize = false;
float humanize_timing = 0.4f;
float humanize_velocity = 0.3f;
bool se_enabled = true;
bool call_enabled = false;
uint8_t call_density = 2;
uint8_t intro_chant = 0;
uint8_t mix_pattern = 0;
bool call_notes_enabled = true;
};The C++ type uses normalized floats for chord-extension probabilities and humanization. The integer 0-100 field is arpeggio_gate only.
NoteEvent
struct NoteEvent {
Tick start_tick;
Tick duration;
uint8_t note; // MIDI note number, 0-127
uint8_t velocity; // MIDI velocity, 0-127
bool is_syllabic_subdivision = false;
};The default and four-argument constructors are private. Use NoteEventBuilder::create(start, duration, note, velocity) for direct construction. Tick is uint32_t.
Understanding Ticks
The core timing constants are 480 ticks per quarter note, 240 per eighth note, 120 per sixteenth note, and 1,920 per 4/4 bar. MIDI_C4 is 60.
auto note = NoteEventBuilder::create(480, 480, 60, 100);MelodyData
struct MelodyData {
uint32_t seed;
std::vector<NoteEvent> notes;
};Enums
Key
enum class Key : uint8_t {
C = 0, Cs, D, Eb, E, F, Fs, G, Ab, A, Bb, B
};VocalAttitude
enum class VocalAttitude : uint8_t { Clean = 0, Expressive, Raw };CompositionStyle
enum class CompositionStyle : uint8_t {
MelodyLead = 0, BackgroundMotif, SynthDriven
};VocalStylePreset
enum class VocalStylePreset : uint8_t {
Auto = 0, Standard, Vocaloid, UltraVocaloid, Idol, Ballad, Rock,
CityPop, Anime, BrightKira, CoolSynth, CuteAffected, PowerfulShout, KPop
};MelodyTemplateId
enum class MelodyTemplateId : uint8_t {
Auto = 0, PlateauTalk, RunUpTarget, DownResolve,
HookRepeat, SparseAnchor, CallResponse, JumpAccent
};MelodicComplexity / HookIntensity
enum class MelodicComplexity : uint8_t { Simple = 0, Standard, Complex };
enum class HookIntensity : uint8_t { Off = 0, Light, Normal, Strong, Maximum };VocalGrooveFeel
enum class VocalGrooveFeel : uint8_t {
Straight = 0, OffBeat, Swing, Syncopated, Driving16th, Bouncy8th
};StructurePattern
StructurePattern has 18 values, numbered 0 through 17 in declaration order.
enum class StructurePattern : uint8_t {
StandardPop = 0, BuildUp, DirectChorus, RepeatChorus, ShortForm,
FullPop, FullWithBridge, DriveUpbeat, Ballad, AnthemStyle, ExtendedFull,
ChorusFirst, ChorusFirstShort, ChorusFirstFull,
ImmediateVocal, ImmediateVocalFull, AChorusB, DoubleVerse
};ModulationTiming / EnergyCurve
enum class ModulationTiming : uint8_t {
None = 0, LastChorus, AfterBridge, EachChorus, Random
};
enum class EnergyCurve : uint8_t {
GradualBuild = 0, FrontLoaded, WavePattern, SteadyState
};CallSetting / CallDensity / IntroChant / MixPattern
enum class CallSetting : uint8_t { Auto = 0, Enabled, Disabled };
enum class CallDensity : uint8_t { None = 0, Minimal, Standard, Intense };
enum class IntroChant : uint8_t { None = 0, Gachikoi, Shouting };
enum class MixPattern : uint8_t { None = 0, Standard, Tiger };ArrangementGrowth / MotifRepeatScope
enum class ArrangementGrowth : uint8_t { LayerAdd = 0, RegisterAdd };
enum class MotifRepeatScope : uint8_t { FullSong = 0, Section };TrackRole
enum class TrackRole : uint8_t {
Vocal = 0, Chord, Bass, Drums, SE, Motif, Arpeggio, Aux, Guitar
};ArpeggioPattern / ArpeggioSpeed
Both enums have an Auto = 255 sentinel for style or blueprint selection.
enum class ArpeggioPattern : uint8_t {
Up = 0, Down, UpDown, Random, Pinwheel, PedalRoot, Alberti, BrokenChord,
Auto = 255
};
enum class ArpeggioSpeed : uint8_t {
Eighth = 0, Sixteenth, Triplet, Auto = 255
};MoraRhythmMode
MoraRhythmMode is represented by the uint8_t mora_rhythm_mode field in SongConfig.
enum class MoraRhythmMode : uint8_t { Standard = 0, MoraTimed, Auto };MotifMotion / MotifRhythmDensity
enum class MotifMotion : uint8_t {
Stepwise = 0, GentleLeap, WideLeap, NarrowStep, Disjunct, Ostinato
};
enum class MotifRhythmDensity : uint8_t { Sparse = 0, Medium, Driving };MidiFormat
enum class MidiFormat : uint8_t {
SMF1 = 1, // Standard MIDI File Type 1
SMF2 = 2 // MIDI 2.0 Container File
};Constants
using Tick = uint32_t;
constexpr Tick TICKS_PER_BEAT = 480;
constexpr uint8_t BEATS_PER_BAR = 4;
constexpr Tick TICKS_PER_BAR = 1920;
constexpr uint8_t MIDI_C4 = 60;
constexpr MidiFormat kDefaultMidiFormat = MidiFormat::SMF1;C API (midisketch_c.h)
The C ABI is intended for FFI and WASM bindings. Configuration and melody inputs are JSON strings. Binary configuration structs are not part of the current header.
Memory and Threading
midisketch_get_midi(), midisketch_get_vocal_preview_midi(), midisketch_get_events(), midisketch_get_dissonance(), and midisketch_get_piano_roll_safety() allocate result objects. Free them with their matching midisketch_free_* function.
Names, error messages, and other const char* results are borrowed; never pass them to midisketch_free(). midisketch_get_warnings_json() and midisketch_get_melody_json() return thread-local storage replaced by the next call on the same thread. The default-config JSON, pointer candidate getters, single-tick piano-roll results, and string-conversion helpers use shared static storage. Synchronize calls that share a handle and synchronize pointer-returning query calls when they can run concurrently.
Handle Management
MidiSketchHandle midisketch_create(void);
void midisketch_destroy(MidiSketchHandle handle);MIDI Format
MidiSketchError midisketch_set_midi_format(
MidiSketchHandle handle, MidiSketchMidiFormat format);
MidiSketchMidiFormat midisketch_get_midi_format(MidiSketchHandle handle);The default is MIDISKETCH_MIDI_FORMAT_SMF1. Native builds support both formats. WASM builds return MIDISKETCH_ERROR_UNSUPPORTED_FORMAT (7) when asked to select SMF2.
Generation Functions
MidiSketchError midisketch_generate_accompaniment(MidiSketchHandle handle);
MidiSketchError midisketch_regenerate_accompaniment(
MidiSketchHandle handle, uint32_t new_seed);These no-config entry points require a generated song. The JSON entry points are listed below.
Output Functions
MidiSketchMidiData* midisketch_get_midi(MidiSketchHandle handle);
MidiSketchMidiData* midisketch_get_vocal_preview_midi(MidiSketchHandle handle);
void midisketch_free_midi(MidiSketchMidiData* data);
MidiSketchEventData* midisketch_get_events(MidiSketchHandle handle);
void midisketch_free_events(MidiSketchEventData* data);
MidiSketchDissonanceData* midisketch_get_dissonance(MidiSketchHandle handle);
void midisketch_free_dissonance(MidiSketchDissonanceData* data);
MidiSketchInfo midisketch_get_info(MidiSketchHandle handle);MidiSketchInfo.track_count is the engine's nine defined track roles, including disabled or empty roles. Serialized MIDI omits empty tracks; event JSON may include track roles with empty notes.
Preset Information
uint8_t midisketch_structure_count(void);
uint8_t midisketch_mood_count(void);
uint8_t midisketch_chord_count(void);
const char* midisketch_structure_name(uint8_t id);
const char* midisketch_mood_name(uint8_t id);
const char* midisketch_chord_name(uint8_t id);
const char* midisketch_chord_display(uint8_t id);
uint16_t midisketch_mood_default_bpm(uint8_t id);
uint8_t midisketch_style_preset_count(void);
const char* midisketch_style_preset_name(uint8_t id);
const char* midisketch_style_preset_display_name(uint8_t id);
const char* midisketch_style_preset_description(uint8_t id);
uint16_t midisketch_style_preset_tempo_default(uint8_t id);
uint8_t midisketch_style_preset_allowed_attitudes(uint8_t id);
MidiSketchStylePresetSummary midisketch_get_style_preset(uint8_t id);
MidiSketchChordCandidates* midisketch_get_progressions_by_style_ptr(uint8_t style_id);
MidiSketchFormCandidates* midisketch_get_forms_by_style_ptr(uint8_t style_id);
MidiSketchChordCandidates midisketch_get_progressions_by_style(uint8_t style_id);
MidiSketchFormCandidates midisketch_get_forms_by_style(uint8_t style_id);The _ptr candidate getters return shared static buffers and are not thread-safe. The by-value variants return a copy. Pointers inside MidiSketchStylePresetSummary refer to library-owned strings.
Blueprint Information
typedef enum {
MIDISKETCH_PARADIGM_TRADITIONAL = 0,
MIDISKETCH_PARADIGM_RHYTHM_SYNC = 1,
MIDISKETCH_PARADIGM_MELODY_DRIVEN = 2
} MidiSketchParadigm;
typedef enum {
MIDISKETCH_RIFF_FREE = 0,
MIDISKETCH_RIFF_LOCKED_CONTOUR = 1,
MIDISKETCH_RIFF_LOCKED_PITCH = 2,
MIDISKETCH_RIFF_LOCKED_ALL = 3,
MIDISKETCH_RIFF_EVOLVING = 4,
MIDISKETCH_RIFF_LOCKED = MIDISKETCH_RIFF_LOCKED_CONTOUR
} MidiSketchRiffPolicy;
uint8_t midisketch_blueprint_count(void);
const char* midisketch_blueprint_name(uint8_t id);
MidiSketchParadigm midisketch_blueprint_paradigm(uint8_t id);
MidiSketchRiffPolicy midisketch_blueprint_riff_policy(uint8_t id);
uint8_t midisketch_blueprint_weight(uint8_t id);
uint8_t midisketch_blueprint_drums_required(uint8_t id);
uint8_t midisketch_vocal_style_call_enabled(uint8_t style);
uint16_t midisketch_blueprint_tempo_min(uint8_t id);
uint16_t midisketch_blueprint_tempo_max(uint8_t id);
uint8_t midisketch_get_resolved_blueprint_id(MidiSketchHandle handle);
const char* midisketch_get_warnings_json(MidiSketchHandle handle);The blueprint tempo getters return 0 for an invalid ID. The resolved ID is 255 before generation. The warning JSON is an array string such as [] and its pointer is thread-local and borrowed.
JSON Config API (WASM)
MidiSketchError midisketch_generate_from_json(
MidiSketchHandle handle, const char* config_json, size_t json_length);
MidiSketchError midisketch_generate_vocal_from_json(
MidiSketchHandle handle, const char* config_json, size_t json_length);
MidiSketchError midisketch_generate_with_vocal_from_json(
MidiSketchHandle handle, const char* config_json, size_t json_length);
const char* midisketch_create_default_config_json(uint8_t style_id);
MidiSketchConfigError midisketch_validate_config_json(
const char* config_json, size_t json_length);
MidiSketchConfigError midisketch_get_last_config_error(MidiSketchHandle handle);
MidiSketchError midisketch_regenerate_vocal_from_json(
MidiSketchHandle handle, const char* config_json, size_t json_length);
MidiSketchError midisketch_generate_accompaniment_from_json(
MidiSketchHandle handle, const char* config_json, size_t json_length);
MidiSketchError midisketch_regenerate_accompaniment_from_json(
MidiSketchHandle handle, const char* config_json, size_t json_length);
MidiSketchError midisketch_set_vocal_notes_from_json(
MidiSketchHandle handle, const char* json, size_t json_length);
const char* midisketch_get_melody_json(MidiSketchHandle handle);
MidiSketchError midisketch_set_melody_from_json(
MidiSketchHandle handle, const char* json, size_t json_length);config_json uses the snake_case SongConfig fields. midisketch_create_default_config_json() returns a borrowed static string replaced by the next call. Passing NULL or an empty string to midisketch_regenerate_vocal_from_json() selects the seed-only overload. Accompaniment JSON uses AccompanimentConfig fields; its probability and humanization values are normalized floats (0.0-1.0), while arpeggio_gate is 0-100. The C implementation records supplied JSON fields for partial VocalConfig and AccompanimentConfig updates.
midisketch_set_vocal_notes_from_json() accepts this shape:
{
"config": {"style_preset_id": 0, "key": 0, "bpm": 120},
"notes": [
{"start_tick": 0, "duration": 480, "pitch": 60, "velocity": 100}
]
}midisketch_get_melody_json() returns {"seed":N,"notes":[...]}. Its pointer is thread-local and replaced by the next call on the same thread.
Piano Roll Safety API
MidiSketchPianoRollData* midisketch_get_piano_roll_safety(
MidiSketchHandle handle, uint32_t start_tick, uint32_t end_tick, uint32_t step);
MidiSketchPianoRollInfo* midisketch_get_piano_roll_safety_at(
MidiSketchHandle handle, uint32_t tick);
MidiSketchPianoRollInfo* midisketch_get_piano_roll_safety_with_context(
MidiSketchHandle handle, uint32_t tick, uint8_t prev_pitch);
void midisketch_free_piano_roll_data(MidiSketchPianoRollData* data);
size_t midisketch_piano_roll_data_count(const MidiSketchPianoRollData* data);
uint8_t midisketch_piano_roll_data_was_truncated(const MidiSketchPianoRollData* data);
const char* midisketch_reason_to_string(uint16_t reason);
const char* midisketch_collision_to_string(const MidiSketchCollisionInfo* collision);Batch results own an array and are limited to 100,000 samples. Use the count and truncation helpers instead of reading the encoded count field directly. Single-tick results and the two string-conversion functions use shared static storage and must be consumed before the next call.
The safety values and reason flags are bit-compatible with the header:
typedef enum {
MIDISKETCH_NOTE_SAFE = 0,
MIDISKETCH_NOTE_WARNING = 1,
MIDISKETCH_NOTE_DISSONANT = 2
} MidiSketchNoteSafety;
typedef enum {
MIDISKETCH_REASON_NONE = 0,
MIDISKETCH_REASON_CHORD_TONE = 1,
MIDISKETCH_REASON_TENSION = 2,
MIDISKETCH_REASON_SCALE_TONE = 4,
MIDISKETCH_REASON_LOW_REGISTER = 8,
MIDISKETCH_REASON_TRITONE = 16,
MIDISKETCH_REASON_LARGE_LEAP = 32,
MIDISKETCH_REASON_MINOR_2ND = 64,
MIDISKETCH_REASON_MAJOR_7TH = 128,
MIDISKETCH_REASON_NON_SCALE = 256,
MIDISKETCH_REASON_PASSING_TONE = 512,
MIDISKETCH_REASON_OUT_OF_RANGE = 1024,
MIDISKETCH_REASON_TOO_HIGH = 2048,
MIDISKETCH_REASON_TOO_LOW = 4096
} MidiSketchNoteReason;
typedef struct {
uint8_t track_role;
uint8_t colliding_pitch;
uint8_t interval_semitones;
} MidiSketchCollisionInfo;
typedef struct {
uint32_t tick;
int8_t chord_degree;
uint8_t current_key;
uint8_t safety[128];
uint16_t reason[128];
MidiSketchCollisionInfo collision[128];
uint8_t recommended[8];
uint8_t recommended_count;
} MidiSketchPianoRollInfo;
typedef struct {
MidiSketchPianoRollInfo* data;
size_t count;
} MidiSketchPianoRollData;Error Codes
typedef enum {
MIDISKETCH_OK = 0,
MIDISKETCH_ERROR_INVALID_PARAM = 1,
MIDISKETCH_ERROR_INVALID_STRUCTURE = 2, /* deprecated, ABI compatibility */
MIDISKETCH_ERROR_INVALID_MOOD = 3, /* deprecated, ABI compatibility */
MIDISKETCH_ERROR_INVALID_CHORD = 4, /* deprecated, ABI compatibility */
MIDISKETCH_ERROR_GENERATION_FAILED = 5, /* deprecated, ABI compatibility */
MIDISKETCH_ERROR_OUT_OF_MEMORY = 6, /* deprecated, ABI compatibility */
MIDISKETCH_ERROR_UNSUPPORTED_FORMAT = 7
} MidiSketchError;
const char* midisketch_error_string(MidiSketchError error);
const char* midisketch_config_error_string(MidiSketchConfigError error);The error-string functions return borrowed static messages. MidiSketchConfigError values run from MIDISKETCH_CONFIG_OK = 0 through MIDISKETCH_CONFIG_INVALID_TARGET_DURATION = 35; the enum in midisketch_c.h is authoritative.
typedef enum {
MIDISKETCH_CONFIG_OK = 0,
MIDISKETCH_CONFIG_INVALID_STYLE = 1,
MIDISKETCH_CONFIG_INVALID_CHORD = 2,
MIDISKETCH_CONFIG_INVALID_FORM = 3,
MIDISKETCH_CONFIG_INVALID_ATTITUDE = 4,
MIDISKETCH_CONFIG_INVALID_VOCAL_RANGE = 5,
MIDISKETCH_CONFIG_INVALID_BPM = 6,
MIDISKETCH_CONFIG_DURATION_TOO_SHORT = 7,
MIDISKETCH_CONFIG_INVALID_MODULATION = 8,
MIDISKETCH_CONFIG_INVALID_KEY = 9,
MIDISKETCH_CONFIG_INVALID_COMPOSITION_STYLE = 10,
MIDISKETCH_CONFIG_INVALID_ARPEGGIO_PATTERN = 11,
MIDISKETCH_CONFIG_INVALID_ARPEGGIO_SPEED = 12,
MIDISKETCH_CONFIG_INVALID_VOCAL_STYLE = 13,
MIDISKETCH_CONFIG_INVALID_MELODY_TEMPLATE = 14,
MIDISKETCH_CONFIG_INVALID_MELODIC_COMPLEXITY = 15,
MIDISKETCH_CONFIG_INVALID_HOOK_INTENSITY = 16,
MIDISKETCH_CONFIG_INVALID_VOCAL_GROOVE = 17,
MIDISKETCH_CONFIG_INVALID_CALL_DENSITY = 18,
MIDISKETCH_CONFIG_INVALID_INTRO_CHANT = 19,
MIDISKETCH_CONFIG_INVALID_MIX_PATTERN = 20,
MIDISKETCH_CONFIG_INVALID_MOTIF_REPEAT_SCOPE = 21,
MIDISKETCH_CONFIG_INVALID_ARRANGEMENT_GROWTH = 22,
MIDISKETCH_CONFIG_INVALID_MODULATION_TIMING = 23,
MIDISKETCH_CONFIG_INVALID_BLUEPRINT = 24,
MIDISKETCH_CONFIG_INVALID_CALL_SETTING = 25,
MIDISKETCH_CONFIG_INVALID_ENERGY_CURVE = 26,
MIDISKETCH_CONFIG_INVALID_DRIVE_FEEL = 27,
MIDISKETCH_CONFIG_INVALID_MORA_RHYTHM_MODE = 28,
MIDISKETCH_CONFIG_INVALID_PROBABILITY = 29,
MIDISKETCH_CONFIG_INVALID_ARPEGGIO_RANGE = 30,
MIDISKETCH_CONFIG_INVALID_MELODY_OVERRIDE = 31,
MIDISKETCH_CONFIG_INVALID_MOTIF_OVERRIDE = 32,
MIDISKETCH_CONFIG_INVALID_JSON = 33,
MIDISKETCH_CONFIG_INVALID_MOOD = 34,
MIDISKETCH_CONFIG_INVALID_TARGET_DURATION = 35
} MidiSketchConfigError;C API Structures
typedef struct {
uint8_t* data;
size_t size;
} MidiSketchMidiData;
typedef struct {
char* json;
size_t length;
} MidiSketchEventData;
typedef struct {
char* json;
size_t length;
} MidiSketchDissonanceData;
typedef struct {
uint16_t total_bars;
uint32_t total_ticks;
uint16_t bpm;
uint8_t track_count;
} MidiSketchInfo;
typedef struct {
uint8_t id;
const char* name;
const char* display_name;
const char* description;
uint16_t tempo_default;
uint8_t allowed_attitudes;
} MidiSketchStylePresetSummary;
typedef struct { uint8_t count; uint8_t ids[20]; } MidiSketchChordCandidates;
typedef struct { uint8_t count; uint8_t ids[10]; } MidiSketchFormCandidates;The piano-roll safety structs and MidiSketchNoteSafety, MidiSketchNoteReason, and MidiSketchCollisionInfo declarations are also defined in midisketch_c.h; their arrays contain 128 MIDI pitches.
Utilities
const char* midisketch_version(void);
void* midisketch_malloc(size_t size);
void midisketch_free(void* ptr);midisketch_version() returns a borrowed static string. midisketch_malloc() and midisketch_free() are the allocator pair for FFI memory explicitly allocated through the C ABI.
Complete Example
C++ Example
#include "midisketch.h"
#include <fstream>
int main() {
using namespace midisketch;
MidiSketch sketch;
SongConfig config;
config.style_preset_id = 0;
config.key = Key::C;
config.bpm = 120;
config.seed = 12345;
config.vocal_attitude = VocalAttitude::Expressive;
sketch.generateFromConfig(config);
const auto midi = sketch.getMidi();
std::ofstream out("output.mid", std::ios::binary);
out.write(reinterpret_cast<const char*>(midi.data()),
static_cast<std::streamsize>(midi.size()));
return 0;
}C Example
#include "midisketch_c.h"
#include <stdio.h>
#include <string.h>
int main(void) {
MidiSketchHandle handle = midisketch_create();
if (!handle) return 1;
const char config[] =
"{\"style_preset_id\":0,\"key\":0,\"bpm\":120,\"seed\":12345}";
const size_t config_length = sizeof(config) - 1;
MidiSketchError error = midisketch_generate_from_json(
handle, config, config_length);
if (error != MIDISKETCH_OK) {
fprintf(stderr, "%s\n", midisketch_error_string(error));
midisketch_destroy(handle);
return 1;
}
MidiSketchMidiData* midi = midisketch_get_midi(handle);
if (!midi) {
midisketch_destroy(handle);
return 1;
}
FILE* file = fopen("output.mid", "wb");
if (file) {
fwrite(midi->data, 1, midi->size, file);
fclose(file);
}
midisketch_free_midi(midi);
midisketch_destroy(handle);
return file ? 0 : 1;
}