xtc/include/xtc/xtc_editing.h

110 lines
8.1 KiB
C

#ifndef XTC_EDITING_H
#define XTC_EDITING_H
#include "xtc_midi.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Control thread only. Nonempty unique stable IDs, at most MAX_CLIPS.
* All operations clone/validate before publication: errors preserve the project,
* ID counters and optional count-element output. No media loading or DSP work.
* MOVE/DUPLICATE amount is a signed tick displacement, bounded by MAX_TICK.
* DUPLICATE retains tracks, source ranges, notes and media with fresh IDs.
* ALIGN amount is an absolute timeline start; SLIP amount is a signed source
* offset change (audio or MIDI), retaining timeline start/length.
* FADE sets both audio boundary fades to amount ticks (0 removes); each must
* fit within half the current clip duration. MIDI clips reject this operation.
* out_ids receives resulting IDs (removed IDs for DELETE). May be NULL. */
typedef enum { XTC_CLIPS_MOVE, XTC_CLIPS_DUPLICATE, XTC_CLIPS_DELETE, XTC_CLIPS_ALIGN, XTC_CLIPS_SLIP, XTC_CLIPS_FADE } xtc_clip_operation;
xtc_result xtc_project_transform_clips(xtc_project *project,const uint64_t *ids,size_t count,
xtc_clip_operation operation,int64_t amount,uint64_t *out_ids);
/* Control-thread chord strumming in selected MIDI clips, including hidden source
* notes. Groups share source onset and channel within one clip. Pitch order is
* ascending (descending=0) or descending (1), equal pitches ordered by stable ID.
* Spacing is 1..960 ticks; original note ends and all other properties remain.
* Any nonpositive resulting duration rejects the entire edit. No chords returns
* NOT_FOUND. Allocation/validation errors preserve the project and IDs. */
xtc_result xtc_project_strum(xtc_project *project,const uint64_t *ids,size_t count,
uint64_t spacing,int descending);
/* Insert a gap or delete [begin,begin+length), removing contained clips/notes
* and shifting later clips, markers, mixer/instrument/graph plugin automation.
* Crossing clips reject (split them first); source notes and static tempo stay
* unchanged. No interpolated automation guard points are synthesized. Atomic.
* remove must be 0 or 1. GUI loop preferences are outside the project. */
xtc_result xtc_project_ripple_time(xtc_project *project,uint64_t begin,uint64_t length,int remove);
/* Non-bus track copy with fresh track/clip/note IDs. Copies source references,
* instrument settings, mix, bus route and mixer automation; inserts adjacent to
* source. Shared modular graph and live-input target are unchanged. Atomic. */
xtc_result xtc_project_duplicate_track(xtc_project *project,uint64_t track,const char *name,uint64_t *out);
/* MIDI split strictly inside the visible clip. Keeps left ID; right gets fresh
* clip/note IDs and copied complete source notes with an adjusted source offset.
* Hidden source notes remain editable. MIDI instruments may retrigger at the new
* clip boundary; the original sine preserves source phase. Atomic. */
xtc_result xtc_project_split_midi(xtc_project *project,uint64_t clip,uint64_t tick,uint64_t *out_right);
/* Consolidate >=2 MIDI clips on one track into a fresh clip spanning their
* bounding range. Copies only audible note intersections, crops at visible
* boundaries, drops hidden notes, retains overlaps and gaps. Fresh IDs; atomic.
* Cropped notes start anew; instrument envelopes/phase can change. */
xtc_result xtc_project_merge_midi(xtc_project *project,const uint64_t *ids,size_t count,uint64_t *out);
/* Adds 1..8 unique nonzero semitone intervals (-127..127) to EVERY source note
* in selected MIDI clips, retaining originals/articulation and allocating fresh
* note IDs. Mixed selections, pitch overflow and capacity reject atomically. */
xtc_result xtc_project_chordify(xtc_project *project,const uint64_t *ids,size_t count,const int *intervals,size_t interval_count);
/* Offline arpeggio: replaces all source notes in selected MIDI clips with fresh
* IDs. Equal-onset/channel notes form a chord lasting to its longest note end.
* step 1..3840, gate 1..100 percent, descending 0/1. Cycles sorted pitches (ties
* by original ID); each step inherits its chosen note velocity/channel. Atomic. */
xtc_result xtc_project_arpeggiate(xtc_project *project,const uint64_t *ids,size_t count,uint64_t step,unsigned int gate,int descending);
/* MIDI transforms affect ALL source notes in selected MIDI clips, including
* notes hidden by trims. Mixed audio/MIDI selections reject; IDs and unaffected
* fields persist. Initialize the edit struct to zero and set the fields for its
* type; other fields are ignored. No matching notes returns NOT_FOUND. Edits are atomic.
* Swing: grid 1..3840, swing 0..100 delays alternate grid points by up to half
* a grid; strength 0..100 blends toward the nearest swung point (ties later).
* Swing durations stay fixed. LEGATO ends at the next strictly later onset in
* the same clip/channel (chords stay together), or source end for the last onset.
* Out-of-source results reject the complete operation. */
typedef enum { XTC_MIDI_TRANSFORM_SWING, XTC_MIDI_TRANSFORM_GATE, XTC_MIDI_TRANSFORM_LEGATO, XTC_MIDI_TRANSFORM_SCALE, XTC_MIDI_TRANSFORM_VELOCITY, XTC_MIDI_TRANSFORM_HUMANIZE } xtc_midi_transform_type;
typedef struct {
xtc_midi_transform_type type;
uint64_t grid;
unsigned int swing,strength;
unsigned int velocity_percent; /* VELOCITY: 0..400, rounded scaling then offset, clamp to 1..127. */
int velocity_offset; /* -127..127 */
unsigned int root,scale; /* SCALE: root 0..11 (C..B), scale 0 chromatic, 1 major, 2 natural minor; nearest ties lower. */
unsigned int gate_percent; /* GATE: 1..400, rounded length, minimum 1 tick. */
unsigned int seed; /* HUMANIZE: stable note-ID keyed 32-bit PRNG seed. */
unsigned int timing_variation,velocity_variation; /* 0..960 ticks, 0..127 velocity; source overflow rejects, velocity clamps. */
} xtc_midi_transform;
xtc_result xtc_project_transform_midi(xtc_project *project,const uint64_t *ids,size_t count,const xtc_midi_transform *edit);
/* Matching linear boundary fades for two partially overlapping non-MIDI clips
* on one track. Order is inferred. Equal starts/ends, containment and adjacency
* reject; opposite fades, media, gains and positions remain unchanged.
* No allocation or I/O; control-thread only, errors leave both clips intact. */
xtc_result xtc_project_crossfade(xtc_project *project,uint64_t first,uint64_t second);
/* Session static mixer comparison. Capture owns an independent snapshot of
* gain/pan/mute/solo for all tracks/buses. Recall requires the exact same stable
* track ID set (order may change), and publishes atomically. Routing, automation,
* instrument/plugin state are excluded; automation still overrides static gain
* and pan. Snapshots are not serialized. out is unchanged on capture failure. */
typedef struct xtc_mix_snapshot xtc_mix_snapshot;
xtc_result xtc_mix_snapshot_create(const xtc_project *project,xtc_mix_snapshot **out);
void xtc_mix_snapshot_destroy(xtc_mix_snapshot *snapshot);
xtc_result xtc_mix_snapshot_recall(const xtc_mix_snapshot *snapshot,xtc_project *project);
/* Repeat the bounding phrase span, including gaps, 1..1024 additional copies.
* Originals remain selected by the caller; all copies publish together. */
xtc_result xtc_project_repeat_clips(xtc_project *project,const uint64_t *ids,size_t count,unsigned int copies);
/* Independent clipboard snapshot; captures notes/trim/media references, no media
* bytes or instrument assignments. Paste maps source track spacing to existing
* destination tracks beginning at destination_track; rejects missing/bus tracks.
* start is the new earliest clip position. No OS clipboard integration.
* out_ids, if non-NULL, has clipboard_count elements; unchanged on failure. */
typedef struct xtc_clipboard xtc_clipboard;
xtc_result xtc_clipboard_create(const xtc_project *project,const uint64_t *ids,size_t count,xtc_clipboard **out);
void xtc_clipboard_destroy(xtc_clipboard *clipboard);
size_t xtc_clipboard_count(const xtc_clipboard *clipboard);
xtc_result xtc_clipboard_paste(const xtc_clipboard *clipboard,xtc_project *project,
uint64_t destination_track,uint64_t start,uint64_t *out_ids);
#ifdef __cplusplus
}
#endif
#endif