- new facade API: video params ex (dimensions/rate/par/interlacing/ preview format/divider), audio params, preview divider, and undoable-flagged setters mirroring the dialog's dual undo/no-undo modes; label setting gains node_set_label_ex - the dialog's own SequenceParamCommand is gone; accept now issues facade calls (per-field commands, unchanged fields skipped) - preset system stays UI-side by design: its flat XML schema never touches engine objects - the auto-cache checkbox maps to the engine's existing stub (no undo noise)
549 lines
21 KiB
C
549 lines
21 KiB
C
/***
|
|
|
|
Oak - Non-Linear Video Editor
|
|
Copyright (C) 2026 Oak Team
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
#ifndef OAKENGINE_TIMELINE_H
|
|
#define OAKENGINE_TIMELINE_H
|
|
|
|
#include <stdint.h>
|
|
|
|
#include "export.h"
|
|
#include "footage.h"
|
|
#include "init.h"
|
|
#include "project.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* @file timeline.h
|
|
* @brief C ABI for sequences (Oak timelines)
|
|
*
|
|
* An OakEngineSequence wraps the engine's olive::Sequence node
|
|
* (engine/node/project/sequence/sequence.h, a ViewerOutput). Most of the
|
|
* family is inspection; playhead, workarea, the sequence parameters
|
|
* (video/audio/preview/auto-cache, see below) and clip/track editing are
|
|
* writes, undoable unless documented otherwise.
|
|
*
|
|
* Handles are borrowed from their owning OakEngineProject (Qt QObject parent
|
|
* chain; sequences are added to the project graph which becomes their
|
|
* parent). There is deliberately no oakengine_sequence_free(): a sequence
|
|
* handle becomes invalid when its project is freed. Sequences created with
|
|
* oakengine_sequence_new() are additionally undoable -- undoing the creation
|
|
* removes the sequence from the project (but keeps it alive under the undo
|
|
* command), redoing brings it back.
|
|
*
|
|
* Time is exposed in the two representations used across the engine
|
|
* (olive::core::Timecode terminology, core/util/timecodefunctions.h):
|
|
*
|
|
* - seconds: a plain double (`*_seconds` accessors), or a rational seconds
|
|
* value as a numerator/denominator int pair (`*_rational`);
|
|
*
|
|
* - timestamp: an int64 count of timebase units, where the timebase is the
|
|
* sequence's frame duration (the frame rate flipped, e.g. 1001/30000 for
|
|
* a 30000/1001 sequence) -- i.e. a frame number. This matches how the
|
|
* engine converts between Rational times and frame timestamps
|
|
* (Timecode::time_to_timestamp / timestamp_to_time).
|
|
*
|
|
* Conventions match oakengine/project.h: booleans are int, 0
|
|
* (OAKENGINE_OK)/negative OAKENGINE_E_* return codes, buf/size string output,
|
|
* NULL handles yield no-ops or OAKENGINE_E_INVALID.
|
|
*/
|
|
|
|
/**
|
|
* @brief Create a new sequence named `name` in `project` and return its
|
|
* borrowed handle (NULL on failure; `project` NULL -> NULL).
|
|
*
|
|
* The sequence gets the application's default parameters
|
|
* (ViewerOutput::set_default_parameters(): width/height/pixel aspect/
|
|
* interlacing/audio layout from Config, frame rate from the
|
|
* DefaultSequenceFrameRate config entry, 30000/1001 by default) and starts
|
|
* with zero tracks. The creation is pushed onto the global undo stack like
|
|
* the application's "Create New Sequence" action (minus opening a viewer).
|
|
*/
|
|
OAKENGINE_API OakEngineSequence *
|
|
oakengine_sequence_new(OakEngineProject *project, const char *name);
|
|
|
|
/**
|
|
* @brief Sequence name (Node::get_label()). Uses the buf/size convention.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_name(const OakEngineSequence *self,
|
|
char *buf, int buf_size);
|
|
|
|
/**
|
|
* @brief Length of the sequence content in seconds
|
|
* (ViewerOutput::get_length()). 0 for an empty sequence.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_get_length(const OakEngineSequence *self,
|
|
double *seconds);
|
|
|
|
/**
|
|
* @brief Length of the sequence content as rational seconds
|
|
* (ViewerOutput::get_length().numerator()/denominator()).
|
|
*/
|
|
OAKENGINE_API int
|
|
oakengine_sequence_get_length_rational(const OakEngineSequence *self, int *num,
|
|
int *den);
|
|
|
|
/**
|
|
* @brief Sequence frame rate as a num/den pair, e.g. 30000/1001
|
|
* (ViewerOutput::get_video_params().frame_rate()).
|
|
*/
|
|
OAKENGINE_API int
|
|
oakengine_sequence_get_frame_rate(const OakEngineSequence *self, int *num,
|
|
int *den);
|
|
|
|
/**
|
|
* @brief Sequence video dimensions and pixel aspect ratio
|
|
* (ViewerOutput::get_video_params()). Any output pointer may be NULL.
|
|
*/
|
|
OAKENGINE_API int
|
|
oakengine_sequence_get_video_params(const OakEngineSequence *self, int *width,
|
|
int *height, int *par_num, int *par_den);
|
|
|
|
/* ---- Sequence parameters (sequence dialog) ------------------------------------
|
|
*
|
|
* The parameter set shown by the application's sequence dialog
|
|
* (app/dialog/sequence): video size/frame rate/pixel aspect/interlacing,
|
|
* preview pixel format and resolution divider, audio sample rate/channel
|
|
* layout, and the video auto-cache flag. Setters take an `undoable` flag:
|
|
* 1 pushes one undoable command onto the global undo stack (direct
|
|
* application when the engine is not initialized), 0 applies directly with
|
|
* no undo entry -- mirroring the dialog's two modes (SetUndoable()).
|
|
* Fields pass -1 (ints/rationals) or <= 0 / 0 (audio) to leave them
|
|
* unchanged; a call that changes nothing pushes no command and returns
|
|
* OAKENGINE_OK. The video channel count and the audio sample format are
|
|
* internal constants in the engine (VideoParams::k_internal_channel_count,
|
|
* ViewerOutput::k_default_sample_format) and are kept as-is.
|
|
*/
|
|
|
|
/**
|
|
* @brief Full read of the sequence's video parameters
|
|
* (ViewerOutput::get_video_params()). Any output pointer may be NULL.
|
|
* `fps_*` is the frame rate (the time base flipped), `format` a
|
|
* PixelFormat::Format value, `divider` the preview resolution divider.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_get_video_params_ex(
|
|
const OakEngineSequence *self, int *width, int *height, int *fps_num,
|
|
int *fps_den, int *par_num, int *par_den, int *interlacing, int *format,
|
|
int *divider);
|
|
|
|
/**
|
|
* @brief Write the sequence's video parameters (see the section comment
|
|
* for the undoable/unchanged conventions).
|
|
*
|
|
* -1 leaves a field unchanged; both fps and pixel-aspect must be given as
|
|
* num/den pairs (both -1 or both > 0). `interlacing` is a
|
|
* VideoParams::Interlacing value (0..2), `format` a PixelFormat::Format
|
|
* value (0..PixelFormat::count-1). Invalid values yield
|
|
* OAKENGINE_E_INVALID. The frame rate is stored as its flipped time base
|
|
* exactly like the application's dialog (VideoParams constructor), so the
|
|
* derived effective size and frame_rate stay in sync.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_set_video_params(
|
|
OakEngineSequence *self, int width, int height, int fps_num, int fps_den,
|
|
int par_num, int par_den, int interlacing, int format, int undoable);
|
|
|
|
/**
|
|
* @brief Sequence audio sample rate and channel layout
|
|
* (ViewerOutput::get_audio_params()). Any output pointer may be NULL.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_get_audio_params(
|
|
const OakEngineSequence *self, int *sample_rate,
|
|
uint64_t *channel_layout);
|
|
|
|
/**
|
|
* @brief Write the sequence's audio parameters (undoable flag as above).
|
|
* `sample_rate` <= 0 or `channel_layout` == 0 leaves the field unchanged.
|
|
* The sample format is kept unchanged (the dialog always uses
|
|
* ViewerOutput::k_default_sample_format).
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_set_audio_params(
|
|
OakEngineSequence *self, int sample_rate, uint64_t channel_layout,
|
|
int undoable);
|
|
|
|
/**
|
|
* @brief Preview resolution divider (VideoParams::divider()). 0 on a NULL
|
|
* handle.
|
|
*/
|
|
OAKENGINE_API int
|
|
oakengine_sequence_get_preview_divider(const OakEngineSequence *self);
|
|
|
|
/**
|
|
* @brief Set the preview resolution divider (undoable flag as above).
|
|
* `divider` < 1 yields OAKENGINE_E_INVALID.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_set_preview_divider(
|
|
OakEngineSequence *self, int divider, int undoable);
|
|
|
|
/**
|
|
* @brief 1 when video auto-cache is enabled
|
|
* (ViewerOutput::is_video_auto_cache_enabled()). 0 on a NULL handle.
|
|
*/
|
|
OAKENGINE_API int
|
|
oakengine_sequence_get_video_auto_cache(const OakEngineSequence *self);
|
|
|
|
/**
|
|
* @brief Enable or disable video auto-cache.
|
|
*
|
|
* The engine's auto-cache accessors are currently stubs (the read always
|
|
* reports 0, the write is ignored; the application's dialog has the
|
|
* checkbox TEMP-disabled for the same reason). This forwards to the stub
|
|
* without an undo command so the ABI is ready when the engine
|
|
* implementation lands. `undoable` is accepted for symmetry and ignored.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_set_video_auto_cache(
|
|
OakEngineSequence *self, int enabled, int undoable);
|
|
|
|
/**
|
|
* @brief Number of tracks per track type (Sequence::track_list(type)->
|
|
* get_track_count()). Any of `video`/`audio`/`subtitle` may be NULL.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_track_count(const OakEngineSequence *self,
|
|
int *video, int *audio,
|
|
int *subtitle);
|
|
|
|
/**
|
|
* @brief Playhead position as a timestamp in timebase units (frame number;
|
|
* ViewerOutput::get_playhead() rescaled to the frame-rate timebase).
|
|
*/
|
|
OAKENGINE_API int
|
|
oakengine_sequence_get_playhead(const OakEngineSequence *self,
|
|
int64_t *timestamp);
|
|
|
|
/**
|
|
* @brief Move the playhead to `timestamp` (frame number;
|
|
* ViewerOutput::set_playhead()).
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_set_playhead(OakEngineSequence *self,
|
|
int64_t timestamp);
|
|
|
|
/**
|
|
* @brief Playhead position in seconds.
|
|
*/
|
|
OAKENGINE_API int
|
|
oakengine_sequence_get_playhead_seconds(const OakEngineSequence *self,
|
|
double *seconds);
|
|
|
|
/**
|
|
* @brief 1 if the workarea (in/out range) is enabled
|
|
* (TimelineWorkArea::enabled()).
|
|
*/
|
|
OAKENGINE_API int
|
|
oakengine_sequence_workarea_is_enabled(const OakEngineSequence *self);
|
|
|
|
/**
|
|
* @brief Workarea in/out points as timestamps in timebase units
|
|
* (TimelineWorkArea::in()/out()). Either pointer may be NULL.
|
|
*/
|
|
OAKENGINE_API int
|
|
oakengine_sequence_get_workarea(const OakEngineSequence *self, int64_t *in,
|
|
int64_t *out);
|
|
|
|
/**
|
|
* @brief Set the workarea: enable flag plus in/out timestamps in timebase
|
|
* units (TimelineWorkArea::set_enabled()/set_range()).
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_set_workarea(OakEngineSequence *self,
|
|
int enabled, int64_t in,
|
|
int64_t out);
|
|
|
|
/**
|
|
* @brief Number of timeline markers (TimelineMarkerList::size()).
|
|
*/
|
|
OAKENGINE_API int
|
|
oakengine_sequence_marker_count(const OakEngineSequence *self);
|
|
|
|
/**
|
|
* @brief Marker at `index`: `time` receives its in-point as a timestamp in
|
|
* timebase units (may be NULL), `name` its label using the buf/size
|
|
* truncation convention (may be NULL to only fetch the time). Returns
|
|
* OAKENGINE_OK on success, OAKENGINE_E_NOT_FOUND for an out-of-range index.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_marker_at(const OakEngineSequence *self,
|
|
int index, int64_t *time,
|
|
char *name, int name_size);
|
|
|
|
/* ---- Timeline editing primitives ---------------------------------------- */
|
|
|
|
/**
|
|
* @brief Track types, matching olive::Track::Type.
|
|
*/
|
|
#define OAKENGINE_TRACK_TYPE_VIDEO 0
|
|
#define OAKENGINE_TRACK_TYPE_AUDIO 1
|
|
#define OAKENGINE_TRACK_TYPE_SUBTITLE 2
|
|
|
|
/**
|
|
* @brief Opaque clip handle (a ClipBlock on a track).
|
|
*
|
|
* Handles are borrowed from their owning project (QObject parent chain) and
|
|
* become invalid when the project is freed or the clip is removed (e.g. by
|
|
* undoing the add). There is no oakengine_clip_free().
|
|
*/
|
|
typedef struct OakEngineClip OakEngineClip;
|
|
|
|
/**
|
|
* @brief Human-readable reason for the last failed editing call on this
|
|
* thread (buf/size convention). Editing calls return NULL or a negative
|
|
* OAKENGINE_E_* code; the text explains why.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_last_error(char *buf, int buf_size);
|
|
|
|
/**
|
|
* @brief Append a track of `track_type` (OAKENGINE_TRACK_TYPE_*) to the
|
|
* sequence and return its index in that type's track list.
|
|
*
|
|
* Uses the engine's TimelineAddTrackCommand without auto-merge: the first
|
|
* video/audio track is connected straight to the sequence's texture/samples
|
|
* input (tracks beyond the first stay unconnected until a merge node is
|
|
* added -- multi-track compositing is a later milestone). The add is
|
|
* undoable like the other editing primitives. Returns the new track index
|
|
* (>= 0) or a negative OAKENGINE_E_* code.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_add_track(OakEngineSequence *self,
|
|
int track_type);
|
|
|
|
/**
|
|
* @brief Place a clip of `footage` on a track (undoable).
|
|
*
|
|
* Creates an olive::ClipBlock whose buffer input is fed by the footage node
|
|
* and places it on the track at `track_index` (within the track list of
|
|
* `track_type`, OAKENGINE_TRACK_TYPE_VIDEO or _AUDIO; subtitle clips are
|
|
* rejected with OAKENGINE_E_INVALID). The footage handle must be a borrowed
|
|
* import handle belonging to the same project as the sequence (probed
|
|
* handles carry no node and are rejected).
|
|
*
|
|
* `in`/`out` are the clip's timeline range and `media_in` the source in-
|
|
* point, all as frame timestamps in the sequence's frame-rate timebase
|
|
* (same convention as the rest of this family); `out` must be greater than
|
|
* `in` and `media_in` must be >= 0. No track is created implicitly: an
|
|
* out-of-range `track_index` fails with OAKENGINE_E_NOT_FOUND.
|
|
*
|
|
* The add mirrors the application's drop-import chain reduced to its
|
|
* editing core (NodeAddCommand + NodeEdgeAddCommand onto
|
|
* ClipBlock::k_buffer_in + TrackPlaceBlockCommand, pushed as one undoable
|
|
* MultiUndoCommand). Returns a borrowed clip handle, or NULL on failure
|
|
* (see oakengine_sequence_last_error()).
|
|
*/
|
|
OAKENGINE_API OakEngineClip *oakengine_sequence_add_footage_clip(
|
|
OakEngineSequence *seq, OakEngineFootage *footage, int track_type,
|
|
int track_index, int64_t in, int64_t out, int64_t media_in);
|
|
|
|
/**
|
|
* @brief Number of clips on the track at `track_index` (within the
|
|
* `track_type` list). Gap blocks are not clips and are not counted.
|
|
* Returns the count (>= 0) or a negative OAKENGINE_E_* code
|
|
* (OAKENGINE_E_NOT_FOUND when the track does not exist).
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_clip_count(OakEngineSequence *self,
|
|
int track_type,
|
|
int track_index);
|
|
|
|
/**
|
|
* @brief Borrowed handle of the clip at `clip_index` on the track (gap
|
|
* blocks are skipped), or NULL when out of range.
|
|
*/
|
|
OAKENGINE_API OakEngineClip *oakengine_sequence_clip_at(
|
|
OakEngineSequence *self, int track_type, int track_index, int clip_index);
|
|
|
|
/**
|
|
* @brief The clip's timeline range (`in`/`out`) and source in-point
|
|
* (`media_in`) as frame timestamps in the sequence's frame-rate timebase.
|
|
* Any pointer may be NULL.
|
|
*/
|
|
OAKENGINE_API int oakengine_clip_get_range(const OakEngineClip *self,
|
|
int64_t *in, int64_t *out,
|
|
int64_t *media_in);
|
|
|
|
/* ---- Editing primitives, round 2: split / ripple delete / trim / move ----
|
|
*
|
|
* All four are undoable like the other editing primitives and report
|
|
* failures through oakengine_sequence_last_error(). Clips are addressed by
|
|
* (track_type, track_index, clip_index) exactly like
|
|
* oakengine_sequence_clip_at() (gap blocks are skipped). All times are
|
|
* frame timestamps in the sequence's frame-rate timebase.
|
|
*/
|
|
|
|
/**
|
|
* @brief Split the addressed clip in two at timeline `time` (undoable;
|
|
* olive::BlockSplitCommand).
|
|
*
|
|
* `time` must lie strictly inside the clip's range. The left part keeps the
|
|
* clip's in-point, the right part starts at `time` with its media in-point
|
|
* advanced accordingly (the engine's split semantics). Returns OAKENGINE_OK
|
|
* or a negative code (OAKENGINE_E_NOT_FOUND for a missing clip,
|
|
* OAKENGINE_E_INVALID for a time outside the clip).
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_split_clip(OakEngineSequence *seq,
|
|
int track_type,
|
|
int track_index,
|
|
int clip_index, int64_t time);
|
|
|
|
/**
|
|
* @brief Delete the addressed clip and shift all following clips on the
|
|
* track left by its length (undoable;
|
|
* olive::TrackRippleRemoveAreaCommand).
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_ripple_delete_clip(OakEngineSequence *seq,
|
|
int track_type,
|
|
int track_index,
|
|
int clip_index);
|
|
|
|
/**
|
|
* @brief Change the clip's timeline range (undoable; olive::BlockTrimCommand,
|
|
* the application's trim command).
|
|
*
|
|
* Pass the current value for the end that should stay unchanged; changing
|
|
* both ends is applied as an in-trim followed by an out-trim in one
|
|
* undoable command. Requires new_out > new_in and new_in >= 0. When the
|
|
* in-point moves, the clip's media in-point moves with it (the engine's
|
|
* set_length_and_media_in() alignment); adjacent gaps absorb the difference
|
|
* (the engine's trim semantics, adjacent clips are not rolled). The clip
|
|
* handle must still be on a track.
|
|
*/
|
|
OAKENGINE_API int oakengine_clip_trim(OakEngineClip *clip, int64_t new_in,
|
|
int64_t new_out);
|
|
|
|
/**
|
|
* @brief Move the addressed clip to start at `new_in` on the same track
|
|
* (undoable).
|
|
*
|
|
* Length and media in-point are preserved; the old spot is filled with a
|
|
* gap (olive::TrackReplaceBlockWithGapCommand) and the clip is placed at
|
|
* the destination (olive::TrackPlaceBlockCommand, which ripples whatever
|
|
* was there). Moving across tracks is a later milestone. `new_in` must be
|
|
* >= 0.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_move_clip(OakEngineSequence *seq,
|
|
int track_type,
|
|
int track_index,
|
|
int clip_index,
|
|
int64_t new_in);
|
|
|
|
/* ---- Track structure and markers ------------------------------------------
|
|
*
|
|
* Track structure edits are undoable like the other editing primitives.
|
|
* Track height, mute and lock are NOT undoable in the engine (the
|
|
* application wires those buttons straight to the setters, see
|
|
* app/widget/timelinewidget/trackview/trackviewitem.cpp), and this family
|
|
* follows that behavior. Marker edits are undoable.
|
|
* All marker times are frame timestamps in the sequence's frame-rate
|
|
* timebase, like the rest of the family.
|
|
*/
|
|
|
|
/**
|
|
* @brief Remove a track and its content (undoable;
|
|
* olive::TimelineRemoveTrackCommand). OAKENGINE_E_NOT_FOUND when the track
|
|
* does not exist.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_remove_track(OakEngineSequence *seq,
|
|
int track_type,
|
|
int track_index);
|
|
|
|
/**
|
|
* @brief Move the track at `from_index` to `to_index` within the track
|
|
* list (undoable).
|
|
*
|
|
* Implemented as a true move (take out and re-insert, the tracks in
|
|
* between shift), assembled from the engine's edge commands. `from_index`
|
|
* == `to_index` is a no-op success; an out-of-range index fails with
|
|
* OAKENGINE_E_NOT_FOUND.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_move_track(OakEngineSequence *seq,
|
|
int track_type,
|
|
int from_index, int to_index);
|
|
|
|
/**
|
|
* @brief Track height in the engine's internal units
|
|
* (Track::get_track_height(); NOT undoable, see the section comment).
|
|
*/
|
|
OAKENGINE_API int oakengine_track_get_height(const OakEngineSequence *seq,
|
|
int track_type, int track_index,
|
|
double *height);
|
|
|
|
/**
|
|
* @brief Set the track height in internal units
|
|
* (Track::set_track_height(); NOT undoable). `height` must be > 0.
|
|
*/
|
|
OAKENGINE_API int oakengine_track_set_height(OakEngineSequence *seq,
|
|
int track_type, int track_index,
|
|
double height);
|
|
|
|
/**
|
|
* @brief 1 if the track is muted (Track::is_muted()).
|
|
*/
|
|
OAKENGINE_API int oakengine_track_is_muted(const OakEngineSequence *seq,
|
|
int track_type, int track_index);
|
|
|
|
/**
|
|
* @brief Mute or unmute the track (Track::set_muted(); NOT undoable).
|
|
*/
|
|
OAKENGINE_API int oakengine_track_set_muted(OakEngineSequence *seq,
|
|
int track_type, int track_index,
|
|
int muted);
|
|
|
|
/**
|
|
* @brief 1 if the track is locked (Track::is_locked()).
|
|
*/
|
|
OAKENGINE_API int oakengine_track_is_locked(const OakEngineSequence *seq,
|
|
int track_type, int track_index);
|
|
|
|
/**
|
|
* @brief Lock or unlock the track (Track::set_locked(); NOT undoable).
|
|
*/
|
|
OAKENGINE_API int oakengine_track_set_locked(OakEngineSequence *seq,
|
|
int track_type, int track_index,
|
|
int locked);
|
|
|
|
/**
|
|
* @brief Add a timeline marker at `time_ts` named `name` (undoable;
|
|
* olive::MarkerAddCommand).
|
|
*
|
|
* The engine does not allow two markers at the exact same time (its
|
|
* insertion asserts on it), so adding one fails with OAKENGINE_E_STATE.
|
|
* `name` may be NULL for an empty name.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_marker_add(OakEngineSequence *seq,
|
|
int64_t time_ts,
|
|
const char *name);
|
|
|
|
/**
|
|
* @brief Remove the (first) marker at `time_ts` (undoable;
|
|
* olive::MarkerRemoveCommand). OAKENGINE_E_NOT_FOUND when no marker exists
|
|
* at that exact time.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_marker_remove(OakEngineSequence *seq,
|
|
int64_t time_ts);
|
|
|
|
/**
|
|
* @brief Rename the (first) marker at `time_ts` (undoable;
|
|
* olive::MarkerChangeNameCommand). OAKENGINE_E_NOT_FOUND when no marker
|
|
* exists at that exact time.
|
|
*/
|
|
OAKENGINE_API int oakengine_sequence_marker_rename(OakEngineSequence *seq,
|
|
int64_t time_ts,
|
|
const char *name);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* OAKENGINE_TIMELINE_H */
|