Files
Mike-Solar e9f173916f engine: complete C ABI facade (liboakengine oakengine_* surface)
The full pure-C facade used by the app: node/project/timeline/viewer/
undo/task/events/serializer/playback/preview/renderer/gizmo/color/
audio/footage/proxy/encoding/exporter/config/disk/ipc/plugin/worker
families, plus undo-group semantics, display renderer handles,
NodeFactory accessors, and per-family pure-C engine tests.
2026-07-26 22:43:00 +08:00

138 lines
5.5 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_SYNC_H
#define OAKENGINE_SYNC_H
#include "export.h"
#include "timeline.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file sync.h
* @brief C ABI for waveform-based audio synchronization estimation
*
* Wraps the engine's AudioWaveformSync estimators
* (engine/audio/audiowaveformsync.h): the full audio of two clips is
* rendered through the renderer family and cross-correlated, yielding
* the time offset that aligns the target clip with the reference clip
* (the application's timeline "synchronize clips by waveform" feature).
*
* Both estimators validate first and change nothing on failure (these
* are pure measurements). They return OAKENGINE_OK when the correlation
* is conclusive (OffsetResult::valid), OAKENGINE_E_STATE when it is
* inconclusive -- in that case `out_confidence` is still written so the
* caller can compare it against a fallback estimator, and the offset
* outputs are set to 0 / the stretch output to 1. OAKENGINE_E_INVALID
* covers NULL handles, clips without an on-track range, and sequences
* without audio; estimation itself requires the engine initialized
* with OAKENGINE_INIT_RENDER (OAKENGINE_E_STATE as well).
*
* Note this family renders audio freshly per call (no waveform-cache
* dependency); the application keeps its cache-envelope path for the
* envelope source and uses these functions for the estimation step.
* Errors follow the family model: per-thread human-readable reason via
* oakengine_sync_last_error().
*/
/**
* @brief Estimate the time offset aligning `target` to `reference`
* (AudioWaveformSync::estimate_envelope_offset).
*
* `out_offset_seconds` receives the signed offset in seconds: the
* shift to ADD to the target's timeline position so it aligns with the
* reference (negative = move the target earlier -- e.g. the
* application's AudioSynchronizer adds it to the reference in-point).
* The estimate is quantized to the RMS envelope window
* (sample_rate/20 seconds), so callers should expect up to one window
* of quantization error. `out_confidence` receives the correlation
* confidence in [0, 1] and is always written. Any output pointer may
* be NULL. Search bounds mirror the application (sample_rate/20
* window, 10-minute maximum offset).
*/
OAKENGINE_API int oakengine_sync_estimate_offset(
OakEngineSequence *seq, OakEngineClip *reference, OakEngineClip *target,
double *out_offset_seconds, double *out_confidence);
/**
* @brief Estimate a playback-rate change plus offset aligning `target`
* to `reference` (AudioWaveformSync::estimate_stretch_and_offset).
*
* `out_stretch` receives the rate the target must be played at to
* align (> 1 = the target runs slower and must be sped up; the search
* range mirrors the application: 0.75..1.34 in 0.005 steps, 30-second
* offset radius). `out_offset_seconds` and `out_confidence` behave
* like oakengine_sync_estimate_offset(). Any output pointer may be
* NULL.
*/
OAKENGINE_API int oakengine_sync_estimate_stretch_offset(
OakEngineSequence *seq, OakEngineClip *reference, OakEngineClip *target,
double *out_stretch, double *out_offset_seconds,
double *out_confidence);
/**
* @brief Human-readable reason for the last failed sync call on this
* thread (buf/size convention). Empty when the last call succeeded.
*/
OAKENGINE_API int oakengine_sync_last_error(char *buf, int buf_size);
/* ---- Place by source time / waveform offset (replaces AudioSynchronizer) - */
/** @brief POD for sync placement result (timeline_in rational). */
typedef struct oak_sync_placement {
int64_t timeline_in_num;
int64_t timeline_in_den;
} oak_sync_placement;
/**
* @brief Place a clip by source time (AudioSynchronizer::place_by_source_time).
*
* Computes: timeline_in = anchor_in + (cand_source_start + cand_media_in)
* - (ref_source_start + ref_media_in)
* Returns OAKENGINE_OK and fills `out`, or OAKENGINE_E_INVALID on NaN input.
*/
OAKENGINE_API int oakengine_sync_place_by_source_time(
int64_t ref_source_start_num, int64_t ref_source_start_den,
int64_t ref_media_in_num, int64_t ref_media_in_den,
int64_t cand_source_start_num, int64_t cand_source_start_den,
int64_t cand_media_in_num, int64_t cand_media_in_den,
int64_t anchor_num, int64_t anchor_den,
oak_sync_placement *out);
/**
* @brief Place a clip by waveform offset (AudioSynchronizer::place_by_waveform_offset).
*
* Computes: timeline_in = ref_timeline_in + candidate_offset_samples / sample_rate
* Returns OAKENGINE_OK and fills `out`, or OAKENGINE_E_INVALID when sample_rate <= 0.
*/
OAKENGINE_API int oakengine_sync_place_by_waveform_offset(
int64_t ref_timeline_in_num, int64_t ref_timeline_in_den,
int64_t candidate_offset_samples, int sample_rate,
oak_sync_placement *out);
#ifdef __cplusplus
}
#endif
#endif /* OAKENGINE_SYNC_H */