217 lines
10 KiB
C
217 lines
10 KiB
C
#ifndef XTC_MIDI_H
|
|
#define XTC_MIDI_H
|
|
|
|
#include "xtc_project.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#define XTC_PROJECT_MAX_NOTES 4096U
|
|
#define XTC_MIDI_MAX_EVENTS 256U
|
|
#define XTC_MIDI_VOICES 32U
|
|
|
|
typedef struct {
|
|
uint64_t id, clip_id, start_tick, length_tick; /* Positions in clip source. */
|
|
unsigned int pitch, velocity, channel; /* 0..127, 1..127, 0..15. */
|
|
} xtc_note_info;
|
|
|
|
/* Control-thread batch edits. UINT64_MAX selects all notes in the clip;
|
|
* channel -1 selects all channels. Pitch bounds are inclusive. */
|
|
typedef struct {
|
|
uint64_t clip_id, note_id;
|
|
int channel;
|
|
unsigned int pitch_min, pitch_max;
|
|
} xtc_note_filter;
|
|
typedef enum { XTC_NOTES_EDIT, XTC_NOTES_REPEAT, XTC_NOTES_DELETE } xtc_note_action;
|
|
typedef struct {
|
|
xtc_note_action action;
|
|
uint64_t grid_tick; /* 0 preserves start; nearest grid, ties round later. */
|
|
int transpose; /* -127..127; out-of-range pitches reject the entire edit. */
|
|
int velocity, channel; /* -1 preserves, otherwise 1..127 / 0..15. */
|
|
unsigned int copies; /* REPEAT only: 1..4096 additional copies. */
|
|
uint64_t interval_tick; /* REPEAT only: positive spacing between copies. */
|
|
} xtc_note_edit;
|
|
/* Atomic validation then mutation; no partial edits or consumed IDs on failure.
|
|
* EDIT keeps IDs/durations. REPEAT leaves originals untouched and gives copies
|
|
* fresh IDs, transformed then offset by k*interval. DELETE uses only action.
|
|
* No matches returns NOT_FOUND. All notes must fit the existing source length;
|
|
* nothing is clamped, extended or merged. out_count is unchanged on failure,
|
|
* and reports original matched notes on success. No callback-thread use. */
|
|
xtc_result xtc_project_edit_notes(xtc_project *project, const xtc_note_filter *filter,
|
|
const xtc_note_edit *edit, size_t *out_count);
|
|
|
|
typedef enum {
|
|
XTC_MIDI_NOTE_ON = 1,
|
|
XTC_MIDI_NOTE_OFF,
|
|
XTC_MIDI_ALL_OFF,
|
|
XTC_MIDI_CONTROL, /* pitch = CC number, velocity = 0..127 value */
|
|
XTC_MIDI_BEND /* pitch = LSB, velocity = MSB of 14-bit bend; center 8192 */
|
|
} xtc_midi_type;
|
|
|
|
typedef struct {
|
|
unsigned int offset; /* Sample offset within THIS block, strictly < frames. */
|
|
xtc_midi_type type;
|
|
unsigned int channel, pitch, velocity;
|
|
} xtc_midi_event;
|
|
typedef struct xtc_midi_plan xtc_midi_plan;
|
|
|
|
/* Control-thread model APIs, stable note IDs; deletion cascades from clips/tracks.
|
|
* MIDI clips cannot reference audio. Creation transactionally adds an instrument
|
|
* source -> output route if no instrument exists. Other clip edits stay shared. */
|
|
/**
|
|
* @brief Adds a MIDI clip and ensures an instrument output route exists.
|
|
*
|
|
* @param project Project model; borrowed for this call.
|
|
* @param track Stable track identifier.
|
|
* @param start Start position in musical ticks.
|
|
* @param length Duration in musical ticks.
|
|
* @param out_id Receives the id.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_project_add_midi_clip(xtc_project *project, uint64_t track, uint64_t start, uint64_t length,
|
|
uint64_t *out_id);
|
|
/**
|
|
* @brief Copies the number of notes in the project.
|
|
*
|
|
* @param project Project model; borrowed for this call.
|
|
* @param out_count Receives the count.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_project_note_count(const xtc_project *project, size_t *out_count);
|
|
/**
|
|
* @brief Copies a note snapshot selected by dense list index.
|
|
*
|
|
* @param project Project model; borrowed for this call.
|
|
* @param index Zero-based index in the dense list.
|
|
* @param out_note Receives the note.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_project_get_note(const xtc_project *project, size_t index, xtc_note_info *out_note);
|
|
/**
|
|
* @brief Adds a validated MIDI note with a new stable identifier.
|
|
*
|
|
* @param project Project model; borrowed for this call.
|
|
* @param clip Stable clip identifier.
|
|
* @param start Start position in musical ticks.
|
|
* @param length Duration in musical ticks.
|
|
* @param pitch MIDI note number, 0 to 127.
|
|
* @param velocity MIDI note velocity, 1 to 127.
|
|
* @param channel MIDI channel, 0 to 15.
|
|
* @param out_id Receives the id.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_project_add_note(xtc_project *project, uint64_t clip, uint64_t start, uint64_t length,
|
|
unsigned int pitch, unsigned int velocity, unsigned int channel, uint64_t *out_id);
|
|
/**
|
|
* @brief Replaces a note's source range, pitch, velocity, and channel after validation.
|
|
*
|
|
* @param project Project model; borrowed for this call.
|
|
* @param id Stable identifier of the object to find or edit.
|
|
* @param start Start position in musical ticks.
|
|
* @param length Duration in musical ticks.
|
|
* @param pitch MIDI note number, 0 to 127.
|
|
* @param velocity MIDI note velocity, 1 to 127.
|
|
* @param channel MIDI channel, 0 to 15.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_project_edit_note(xtc_project *project, uint64_t id, uint64_t start, uint64_t length, unsigned int pitch,
|
|
unsigned int velocity, unsigned int channel);
|
|
/**
|
|
* @brief Removes a note selected by stable identifier.
|
|
*
|
|
* @param project Project model; borrowed for this call.
|
|
* @param id Stable identifier of the object to find or edit.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_project_remove_note(xtc_project *project, uint64_t id);
|
|
/* Complete 3-byte note on/off and CC0..127. Velocity-zero on -> off.
|
|
* CC120/123 decode to ALL_OFF; other CCs are interpreted by prepared bindings.
|
|
* Unsupported messages return UNSUPPORTED; malformed supported messages INVALID.
|
|
* Output unchanged on error. No running-status/SysEx/program support. */
|
|
/**
|
|
* @brief Decodes a complete note, controller or all-notes-off MIDI message into a block event.
|
|
*
|
|
* @param bytes Borrowed MIDI message bytes.
|
|
* @param size Number of message bytes.
|
|
* @param offset Sample offset within the current block.
|
|
* @param out_event Receives the event.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_midi_decode(const unsigned char *bytes, size_t size, unsigned int offset, xtc_midi_event *out_event);
|
|
/* Control-thread compile; immutable ranges plus exclusively audio-owned runtime.
|
|
* Rejects >32 simultaneous scheduled notes. Separate 32 live voices steal oldest.
|
|
* Constant-tempo sine instrument, velocity *0.1, above-Nyquist notes silent. */
|
|
/**
|
|
* @brief Compiles scheduled notes and mixer state into a bounded sine-instrument plan.
|
|
*
|
|
* @param project Project model; borrowed for this call.
|
|
* @param sample_rate Sample rate in hertz.
|
|
* @param out_plan Receives the newly allocated plan; caller owns it on success.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_midi_plan_create(const xtc_project *project, unsigned int sample_rate, xtc_midi_plan **out_plan);
|
|
/**
|
|
* @brief Releases scheduled notes and instrument state; accepts NULL.
|
|
*
|
|
* @param plan Instrument plan and its single-owner runtime state.
|
|
*/
|
|
void xtc_midi_plan_destroy(xtc_midi_plan *plan);
|
|
/* Set before publication, while quiescent. Zero preserves raw scheduled notes.
|
|
* Linear boundary envelopes do not delay note scheduling; live note-offs and
|
|
* panic remain immediate. Max 65536 frames. */
|
|
xtc_result xtc_midi_plan_set_fade_frames(xtc_midi_plan *plan, size_t frames);
|
|
/* Audio owner or stopped only. Reset clears live notes and panic suppression.
|
|
* Panic silences live notes and scheduled notes already started at position;
|
|
* later scheduled notes can start. MIDI CC120/123 affects its own channel. */
|
|
/**
|
|
* @brief Clears live voices, scheduling continuity, and panic suppression.
|
|
*
|
|
* @param plan Instrument plan and its single-owner runtime state.
|
|
*/
|
|
void xtc_midi_plan_reset(xtc_midi_plan *plan);
|
|
/**
|
|
* @brief Silences live voices and suppresses scheduled notes already started at the given position.
|
|
*
|
|
* @param plan Instrument plan and its single-owner runtime state.
|
|
* @param position Absolute sample position at the start of the block.
|
|
*/
|
|
void xtc_midi_plan_panic(xtc_midi_plan *plan, uint64_t position);
|
|
/* No allocation, I/O, locks or GUI. Events sorted by offset, equal offsets retain
|
|
* caller order, count<=256, frames<=65536. Invalid input leaves state/output alone.
|
|
* Renders [position,position+frames); discontinuity clears live voices, chases
|
|
* scheduled notes at their correct phase. Note-off is immediate (no envelope). */
|
|
/* Distinct stereo outputs; NULL right retains mono (gain only). */
|
|
/**
|
|
* @brief Renders scheduled and live MIDI with sample-offset events and track gain and pan.
|
|
*
|
|
* @param p Instrument plan and its single-owner runtime state.
|
|
* @param position Absolute sample position at the start of the block.
|
|
* @param events Borrowed MIDI events sorted by sample offset.
|
|
* @param count Number of MIDI events.
|
|
* @param left Destination left-channel buffer.
|
|
* @param right Destination right-channel buffer; NULL selects mono rendering.
|
|
* @param frames Number of audio frames.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_midi_plan_render_stereo(xtc_midi_plan * p, uint64_t position, const xtc_midi_event * events, size_t count, float *left,
|
|
float *right, size_t frames);
|
|
/**
|
|
* @brief Renders scheduled and live MIDI to mono without stereo pan attenuation.
|
|
*
|
|
* @param plan Instrument plan and its single-owner runtime state.
|
|
* @param position Absolute sample position at the start of the block.
|
|
* @param events Borrowed MIDI events sorted by sample offset.
|
|
* @param count Number of MIDI events.
|
|
* @param output Destination buffer with room for the requested frames.
|
|
* @param frames Number of audio frames.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_midi_plan_render(xtc_midi_plan *plan, uint64_t position, const xtc_midi_event *events, size_t count,
|
|
float *output, size_t frames);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|