revise audio sync, audio beat, add break beat mode, improve auto fx / freeze mode, add/revise sync modes #399, udpate core components to faciliate new functionality

This commit is contained in:
niels
2026-06-16 01:56:48 +02:00
parent 4d56ef3f24
commit 55e131a855
9 changed files with 7967 additions and 2283 deletions
@@ -477,8 +477,7 @@ static inline double vj_runtime_tempo_follow_correction(video_playback_setup *se
return 1.0;
mode = atomic_load_int(&settings->audio_sync.mode);
if(mode != VJ_AUDIO_SYNC_MODE_TEMPO_FOLLOW &&
mode != VJ_AUDIO_SYNC_MODE_TEMPO_BRIDGE)
if(mode != VJ_AUDIO_SYNC_MODE_TEMPO_FOLLOW)
return 1.0;
if(!vj_audio_sync_is_enabled(&settings->audio_sync))
@@ -510,13 +509,15 @@ static inline double vj_runtime_tempo_follow_correction(video_playback_setup *se
return correction;
}
#endif
static inline double vj_runtime_target_time_s(video_playback_setup *settings, long long frame)
static inline double vj_runtime_effective_spvf(video_playback_setup *settings)
{
double epoch_s = atomic_load_double(&settings->fps_epoch_s);
long long epoch_frame = atomic_load_long_long(&settings->fps_epoch_frame);
double spvf = settings->spvf;
double spvf;
if (spvf <= 0.0)
if(!settings)
return 1.0 / 25.0;
spvf = settings->spvf;
if(spvf <= 0.0)
spvf = 1.0 / 25.0;
#ifdef HAVE_JACK
@@ -527,6 +528,18 @@ static inline double vj_runtime_target_time_s(video_playback_setup *settings, lo
}
#endif
if(spvf <= 0.0)
spvf = 1.0 / 25.0;
return spvf;
}
static inline double vj_runtime_target_time_s(video_playback_setup *settings, long long frame)
{
double epoch_s = atomic_load_double(&settings->fps_epoch_s);
long long epoch_frame = atomic_load_long_long(&settings->fps_epoch_frame);
double spvf = vj_runtime_effective_spvf(settings);
if (epoch_s <= 0.0) {
double anchor = atomic_load_double(&settings->audio_start_offset);
epoch_s = (anchor > 0.0) ? anchor : monotonic_now_s();
@@ -561,19 +574,10 @@ static void vj_runtime_reanchor_clock(veejay_t *info,
master_frame = atomic_load_long_long(&settings->master_frame_num);
master_s = vj_runtime_master_clock_now_s(info, &using_audio_clock);
anchor_frame = requested_frame;
if(using_audio_clock && master_frame >= 0)
anchor_frame = master_frame;
anchor_frame = (master_frame >= 0) ? master_frame : requested_frame;
atomic_store_double(&settings->fps_epoch_s, master_s);
atomic_store_long_long(&settings->fps_epoch_frame, anchor_frame);
veejay_msg(VEEJAY_MSG_DEBUG,
"[CLOCK] transport clock re-anchored at frame %lld requested=%lld reason=%s domain=%s",
anchor_frame,
requested_frame,
reason ? reason : "transport-discontinuity",
using_audio_clock ? "jack-audio" : "monotonic");
}
static void vj_runtime_update_frame_fps(veejay_t *info, float fps)
@@ -1612,6 +1616,32 @@ static inline void safe_join(pthread_t *t, const char *name)
}
}
static void veejay_wake_playback_waiters(veejay_t *info)
{
if (!info || !info->settings)
return;
video_playback_setup *settings = (video_playback_setup*) info->settings;
atomic_store_int(&settings->first_audio_frame_ready, 1);
atomic_store_int(&info->audio_running, 0);
#ifdef HAVE_JACK
vj_audio_beat_request_stop(&settings->audio_beat);
vj_audio_sync_request_stop(&settings->audio_sync);
#endif
pthread_mutex_lock(&settings->mutex);
pthread_cond_broadcast(&settings->producer_wait_cv);
pthread_cond_broadcast(&settings->renderer_wait_cv);
pthread_cond_broadcast(&settings->data_ready_cv);
pthread_mutex_unlock(&settings->mutex);
pthread_mutex_lock(&settings->start_mutex);
pthread_cond_broadcast(&settings->start_cond);
pthread_mutex_unlock(&settings->start_mutex);
}
void veejay_busy(veejay_t * info)
{
if (!info || !info->settings) {
@@ -1621,10 +1651,8 @@ void veejay_busy(veejay_t * info)
video_playback_setup *settings = (video_playback_setup*)(info->settings);
veejay_msg(VEEJAY_MSG_DEBUG, "Waiting for threads to finish...");
#ifdef HAVE_JACK
vj_audio_beat_request_stop(&settings->audio_beat);
vj_audio_sync_request_stop(&settings->audio_sync);
#endif
veejay_change_state(info, LAVPLAY_STATE_STOP);
veejay_wake_playback_waiters(info);
safe_join(&settings->renderer_thread, "Renderer");
safe_join(&settings->producer_thread, "Producer");
@@ -1639,7 +1667,8 @@ void veejay_busy(veejay_t * info)
void veejay_quit(veejay_t * info)
{
veejay_change_state(info, LAVPLAY_STATE_STOP);
veejay_change_state(info, LAVPLAY_STATE_STOP);
veejay_wake_playback_waiters(info);
}
@@ -1867,8 +1896,6 @@ void veejay_set_framerate( veejay_t *info , float fps )
vj_audio_sync_set_track_align_video_fps(&settings->audio_sync,
veejay_track_align_media_fps(info));
#endif
veejay_msg(VEEJAY_MSG_INFO, "Playback engine is now playing at %.2f FPS", fps);
}
@@ -2397,6 +2424,22 @@ void veejay_stop_sampling(veejay_t * info)
info->current_edit_list = info->edit_list;
}
static int veejay_cond_wait_stop_poll(video_playback_setup *settings, pthread_cond_t *cv)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
ts.tv_nsec += 50000000L;
if (ts.tv_nsec >= 1000000000L) {
ts.tv_nsec -= 1000000000L;
ts.tv_sec++;
}
pthread_cond_timedwait(cv, &settings->mutex, &ts);
return atomic_load_int(&settings->state) == LAVPLAY_STATE_STOP;
}
VJFrame *veejay_video_queue_reserve_buffer(veejay_t *info)
{
video_playback_setup *settings = info->settings;
@@ -2416,7 +2459,10 @@ VJFrame *veejay_video_queue_reserve_buffer(veejay_t *info)
pthread_mutex_unlock(&settings->mutex);
return NULL;
}
pthread_cond_wait(&settings->producer_wait_cv, &settings->mutex);
if (veejay_cond_wait_stop_poll(settings, &settings->producer_wait_cv)) {
pthread_mutex_unlock(&settings->mutex);
return NULL;
}
}
settings->states[idx] = BUFFER_RESERVED;
@@ -2458,8 +2504,10 @@ VJFrame *veejay_video_queue_get_frame(veejay_t *info)
pthread_mutex_unlock(&settings->mutex);
return NULL;
}
// wait is here
pthread_cond_wait(&settings->renderer_wait_cv, &settings->mutex);
if (veejay_cond_wait_stop_poll(settings, &settings->renderer_wait_cv)) {
pthread_mutex_unlock(&settings->mutex);
return NULL;
}
}
settings->states[idx] = BUFFER_IN_RENDER;
@@ -2673,7 +2721,13 @@ static char *veejay_pipe_append_audio_beat_status(veejay_t *info, char *ptr)
ptr = vj_sprintf(ptr, ok ? AB_POS(snap.sample_rate) : 0); /* 53 */
ptr = vj_sprintf(ptr, ok ? AB_POS(snap.hit_seq) : 0); /* 54 */
ptr = vj_sprintf(ptr, audio_mute); /* 55 */
ptr = vj_sprintf(ptr, record_audio_source);
ptr = vj_sprintf(ptr, record_audio_source); /* 56 */
{
int action = ok ? vj_audio_beat_get_action(&info->settings->audio_beat) : 0;
if(action < 0 || action > 4)
action = 0;
ptr = vj_sprintf(ptr, action); /* 57 */
}
#undef AB_POS
#undef AB_AGE
#undef AB_BPM10
@@ -2697,7 +2751,8 @@ static char *veejay_pipe_append_audio_beat_status(veejay_t *info, char *ptr)
ptr = vj_sprintf(ptr, 0); /* 53 sample_rate */
ptr = vj_sprintf(ptr, 0); /* 54 hit_seq */
ptr = vj_sprintf(ptr, 1); /* 55 muted */
ptr = vj_sprintf(ptr, record_audio_source);
ptr = vj_sprintf(ptr, record_audio_source); /* 56 */
ptr = vj_sprintf(ptr, 0); /* 57 action */
#endif
return ptr;
@@ -2727,32 +2782,31 @@ static char *veejay_pipe_append_audio_sync_status(veejay_t *info, char *ptr)
#define AS_CORR100(v_) \
((int)((((v_) < 0.0) ? 0.0 : (((v_) > 9.999) ? 9.999 : (v_))) * 100.0) + 0.5)
ptr = vj_sprintf(ptr, ok ? snap.enabled : 0); /* 57 */
ptr = vj_sprintf(ptr, ok ? snap.open : 0); /* 58 */
ptr = vj_sprintf(ptr, ok ? snap.running : 0); /* 59 */
ptr = vj_sprintf(ptr, ok ? snap.mode : 0); /* 60 */
ptr = vj_sprintf(ptr, ok ? snap.source : 0); /* 61 */
ptr = vj_sprintf(ptr, ok ? AS_POS(snap.channels) : 0); /* 62 */
ptr = vj_sprintf(ptr, ok ? AS_POS(snap.sample_rate) : 0); /* 63 */
ptr = vj_sprintf(ptr, ok ? AS_PCT(snap.level) : 0); /* 64 */
ptr = vj_sprintf(ptr, ok ? AS_PCT(snap.transient) : 0); /* 65 */
ptr = vj_sprintf(ptr, ok ? AS_BPM10(snap.bpm) : 0); /* 66 */
ptr = vj_sprintf(ptr, ok ? AS_PCT(snap.beat_phase) : 0); /* 67 */
ptr = vj_sprintf(ptr, ok ? AS_PCT(snap.confidence) : 0); /* 68 */
ptr = vj_sprintf(ptr, ok ? (((snap.mode == VJ_AUDIO_SYNC_MODE_TEMPO_BRIDGE ||
snap.mode == VJ_AUDIO_SYNC_MODE_MONITOR) && snap.open) ? 1 : 0) : 0); /* 69 external playback active */
ptr = vj_sprintf(ptr, ok ? AS_RATIO1000(snap.bridge_ratio) : 1000); /* 70 */
ptr = vj_sprintf(ptr, ok ? AS_CORR100(snap.bridge_correction) : 100); /* 71 */
ptr = vj_sprintf(ptr, ok ? snap.target_mode : 0); /* 72 */
ptr = vj_sprintf(ptr, ok ? AS_BPM10(snap.target_bpm) : 0); /* 73 */
ptr = vj_sprintf(ptr, ok ? AS_PCT(snap.target_confidence) : 0); /* 74 */
ptr = vj_sprintf(ptr, ok ? AS_POS(snap.max_correction_pct) : 0); /* 75 */
ptr = vj_sprintf(ptr, ok ? AS_POS(snap.bridge_state) : 0); /* 76 */
ptr = vj_sprintf(ptr, ok ? AS_POS(snap.track_align_locked) : 0); /* 77 */
ptr = vj_sprintf(ptr, ok ? snap.track_align_offset_ms : 0); /* 78 */
ptr = vj_sprintf(ptr, ok ? AS_POS(snap.track_align_confidence_pct) : 0); /* 79 */
ptr = vj_sprintf(ptr, ok ? snap.track_align_correction_ppm : 0); /* 80 */
ptr = vj_sprintf(ptr, ok ? AS_POS(snap.track_align_state) : 0); /* 81 */
ptr = vj_sprintf(ptr, ok ? snap.enabled : 0); /* 58 */
ptr = vj_sprintf(ptr, ok ? snap.open : 0); /* 59 */
ptr = vj_sprintf(ptr, ok ? snap.running : 0); /* 60 */
ptr = vj_sprintf(ptr, ok ? snap.mode : 0); /* 61 */
ptr = vj_sprintf(ptr, ok ? snap.source : 0); /* 62 */
ptr = vj_sprintf(ptr, ok ? AS_POS(snap.channels) : 0); /* 63 */
ptr = vj_sprintf(ptr, ok ? AS_POS(snap.sample_rate) : 0); /* 64 */
ptr = vj_sprintf(ptr, ok ? AS_PCT(snap.level) : 0); /* 65 */
ptr = vj_sprintf(ptr, ok ? AS_PCT(snap.transient) : 0); /* 66 */
ptr = vj_sprintf(ptr, ok ? AS_BPM10(snap.bpm) : 0); /* 67 */
ptr = vj_sprintf(ptr, ok ? AS_PCT(snap.beat_phase) : 0); /* 68 */
ptr = vj_sprintf(ptr, ok ? AS_PCT(snap.confidence) : 0); /* 69 */
ptr = vj_sprintf(ptr, ok ? ((snap.mode != VJ_AUDIO_SYNC_MODE_TEMPO_FOLLOW && vj_audio_sync_mode_uses_external_playback(snap.mode) && snap.open) ? 1 : 0) : 0); /* 70 external playback active */
ptr = vj_sprintf(ptr, ok ? AS_RATIO1000(snap.bridge_ratio) : 1000); /* 71 */
ptr = vj_sprintf(ptr, ok ? AS_CORR100(snap.bridge_correction) : 100); /* 72 */
ptr = vj_sprintf(ptr, ok ? snap.target_mode : 0); /* 73 */
ptr = vj_sprintf(ptr, ok ? AS_BPM10(snap.target_bpm) : 0); /* 74 */
ptr = vj_sprintf(ptr, ok ? AS_PCT(snap.target_confidence) : 0); /* 75 */
ptr = vj_sprintf(ptr, ok ? AS_POS(snap.max_correction_pct) : 0); /* 76 */
ptr = vj_sprintf(ptr, ok ? AS_POS(snap.bridge_state) : 0); /* 77 */
ptr = vj_sprintf(ptr, ok ? AS_POS(snap.track_align_locked) : 0); /* 78 */
ptr = vj_sprintf(ptr, ok ? snap.track_align_offset_ms : 0); /* 79 */
ptr = vj_sprintf(ptr, ok ? AS_POS(snap.track_align_confidence_pct) : 0); /* 80 */
ptr = vj_sprintf(ptr, ok ? snap.track_align_correction_ppm : 0); /* 81 */
ptr = vj_sprintf(ptr, ok ? AS_POS(snap.track_align_state) : 0); /* 82 */
#undef AS_CORR100
#undef AS_RATIO1000
@@ -2819,21 +2873,21 @@ static char *veejay_pipe_append_chain_entry_status(veejay_t *info, char *ptr)
else if(num_params > VJ_STATUS_CHAIN_ENTRY_PARAMETERS)
num_params = VJ_STATUS_CHAIN_ENTRY_PARAMETERS;
ptr = vj_sprintf(ptr, effect_id); /* 82 */
ptr = vj_sprintf(ptr, is_video); /* 83 */
ptr = vj_sprintf(ptr, num_params); /* 84 */
ptr = vj_sprintf(ptr, entry->kf_type); /* 85 */
ptr = vj_sprintf(ptr, entry->kf_status); /* 86 */
ptr = vj_sprintf(ptr, 0); /* 87 transition enabled */
ptr = vj_sprintf(ptr, 0); /* 88 transition loop */
ptr = vj_sprintf(ptr, entry->source_type); /* 89 */
ptr = vj_sprintf(ptr, entry->channel); /* 90 */
ptr = vj_sprintf(ptr, entry->e_flag); /* 91 */
ptr = vj_sprintf(ptr, entry->beat_flag); /* 92 */
ptr = vj_sprintf(ptr, entry->is_rendering); /* 93 */
ptr = vj_sprintf(ptr, effect_id); /* 83 */
ptr = vj_sprintf(ptr, is_video); /* 84 */
ptr = vj_sprintf(ptr, num_params); /* 85 */
ptr = vj_sprintf(ptr, entry->kf_type); /* 86 */
ptr = vj_sprintf(ptr, entry->kf_status); /* 87 */
ptr = vj_sprintf(ptr, 0); /* 88 transition enabled */
ptr = vj_sprintf(ptr, 0); /* 89 transition loop */
ptr = vj_sprintf(ptr, entry->source_type); /* 90 */
ptr = vj_sprintf(ptr, entry->channel); /* 91 */
ptr = vj_sprintf(ptr, entry->e_flag); /* 92 */
ptr = vj_sprintf(ptr, entry->beat_flag); /* 93 */
ptr = vj_sprintf(ptr, entry->is_rendering); /* 94 */
for(int i = 0; i < VJ_STATUS_CHAIN_ENTRY_PARAMETERS; i++)
ptr = vj_sprintf(ptr, (i < num_params) ? entry->arg[i] : 0); /* 94..109 */
ptr = vj_sprintf(ptr, (i < num_params) ? entry->arg[i] : 0); /* 95..110 */
return ptr;
}
@@ -2992,8 +3046,8 @@ static void veejay_pipe_write_status(veejay_t * info)
{
if(!status_packet_warned) {
veejay_msg(VEEJAY_MSG_WARNING,
"Status packet base mismatch: got %d fields, expected %d; padding fixed 110-token packet",
base_tokens, VJ_STATUS_BASE_TOKENS);
"Status packet base mismatch: got %d fields, expected %d; padding fixed %d-token packet",
base_tokens, VJ_STATUS_BASE_TOKENS, VIMS_STATUS_TOKENS);
status_packet_warned = 1;
}
@@ -3200,6 +3254,10 @@ void veejay_handle_signal(int sig, siginfo_t *si, void *unused)
case SIGINT:
case SIGQUIT:
veejay_change_state(info, LAVPLAY_STATE_STOP);
if (info && info->settings) {
atomic_store_int(&info->audio_running, 0);
atomic_store_int(&info->settings->first_audio_frame_ready, 1);
}
break;
case SIGSEGV:
@@ -3614,7 +3672,7 @@ void *veejay_display_renderer_thread(void *arg)
}
double audio_master = atomic_load_double(&settings->audio_master_s);
double spvf = settings->spvf;
double spvf = vj_runtime_effective_spvf(settings);
double target_time_s = vj_runtime_target_time_s(settings, frame->frame_num);
double delay_s = target_time_s - audio_master;
@@ -3723,11 +3781,14 @@ int veejay_open(veejay_t * info)
int i;
pthread_mutex_init(&(settings->control_mutex), NULL);
pthread_mutex_init(&(settings->start_mutex), NULL);
pthread_mutex_init(&settings->mutex, NULL);
pthread_cond_init(&settings->producer_wait_cv, NULL);
pthread_cond_init(&settings->producer_wait_cv, &attr);
pthread_cond_init(&settings->renderer_wait_cv, &attr);
pthread_cond_init(&settings->data_ready_cv, &attr);
pthread_cond_init(&settings->data_ready_cv, &attr);
pthread_cond_init(&settings->start_cond, &attr);
pthread_condattr_destroy(&attr);
settings->producer_index = 0;
settings->renderer_index = 0;
@@ -3804,15 +3865,7 @@ int veejay_close(veejay_t *info)
int success = 1;
veejay_change_state_save(info, LAVPLAY_STATE_STOP);
#ifdef HAVE_JACK
vj_audio_beat_request_stop(&settings->audio_beat);
vj_audio_sync_request_stop(&settings->audio_sync);
#endif
pthread_mutex_lock(&settings->mutex);
pthread_cond_broadcast(&settings->producer_wait_cv);
pthread_cond_broadcast(&settings->renderer_wait_cv);
pthread_mutex_unlock(&settings->mutex);
veejay_wake_playback_waiters(info);
safe_join(&settings->renderer_thread, "Renderer");
safe_join(&settings->producer_thread, "Producer");
@@ -3824,8 +3877,12 @@ int veejay_close(veejay_t *info)
#endif
pthread_mutex_destroy(&settings->mutex);
pthread_mutex_destroy(&settings->control_mutex);
pthread_mutex_destroy(&settings->start_mutex);
pthread_cond_destroy(&settings->producer_wait_cv);
pthread_cond_destroy(&settings->renderer_wait_cv);
pthread_cond_destroy(&settings->data_ready_cv);
pthread_cond_destroy(&settings->start_cond);
for (int i = 0; i < VIDEO_QUEUE_LEN; i++)
if (settings->buffers[i]) veejay_free_frame_buffer(settings->buffers[i]);
@@ -4746,7 +4803,7 @@ static inline double vj_audio_producer_pace_sleep_s(long client_rate,
settings,
budget);
}
static inline int vj_audio_is_external_jack_monitor_source(
static inline int vj_audio_uses_external_audio_playback_source(
video_playback_setup *settings,
int audio_source,
int sync_mode,
@@ -4757,9 +4814,10 @@ static inline int vj_audio_is_external_jack_monitor_source(
if(!settings || !sync_enabled)
return 0;
if(sync_mode != VJ_AUDIO_SYNC_MODE_MONITOR &&
sync_mode != VJ_AUDIO_SYNC_MODE_TEMPO_BRIDGE &&
sync_mode != VJ_AUDIO_SYNC_MODE_TRACK_ALIGN)
if(sync_mode == VJ_AUDIO_SYNC_MODE_TEMPO_FOLLOW)
return 0;
if(!vj_audio_sync_mode_uses_external_playback(sync_mode))
return 0;
source = atomic_load_int(&settings->audio_sync.source);
@@ -4798,7 +4856,7 @@ static int vj_tempo_bridge_reverse_should_reanchor(
if(!vj_audio_sync_is_enabled(&settings->audio_sync))
return 0;
if(!vj_audio_is_external_jack_monitor_source(
if(!vj_audio_uses_external_audio_playback_source(
settings,
atomic_load_int(&settings->record_audio_source),
sync_mode,
@@ -4896,7 +4954,7 @@ static inline int vj_audio_should_pace_direct_jack_monitor(
if(!settings)
return 0;
external_monitor = vj_audio_is_external_jack_monitor_source(
external_monitor = vj_audio_uses_external_audio_playback_source(
settings, audio_source, sync_mode, sync_enabled
);
@@ -4907,7 +4965,10 @@ static inline int vj_audio_should_pace_direct_jack_monitor(
mute = atomic_load_int(&settings->audio_mute);
external_tape = external_monitor && !mute &&
(sync_mode == VJ_AUDIO_SYNC_MODE_TEMPO_BRIDGE || !neutral);
vj_audio_sync_mode_uses_transport_driven_playback(sync_mode) &&
(sync_mode == VJ_AUDIO_SYNC_MODE_TEMPO_BRIDGE ||
sync_mode == VJ_AUDIO_SYNC_MODE_MONITOR_TRICKPLAY ||
!neutral);
if(external_tape_source)
*external_tape_source = external_tape;
@@ -5380,7 +5441,7 @@ void *veejay_audio_producer_thread(void *arg)
sfd_dbg
);
int external_monitor_audio =
vj_audio_is_external_jack_monitor_source(
vj_audio_uses_external_audio_playback_source(
settings,
audio_source_dbg,
audio_sync_mode_dbg,
@@ -5388,7 +5449,9 @@ void *veejay_audio_producer_thread(void *arg)
);
external_tape_source_dbg =
external_monitor_audio &&
vj_audio_sync_mode_uses_transport_driven_playback(audio_sync_mode_dbg) &&
(audio_sync_mode_dbg == VJ_AUDIO_SYNC_MODE_TEMPO_BRIDGE ||
audio_sync_mode_dbg == VJ_AUDIO_SYNC_MODE_MONITOR_TRICKPLAY ||
!external_tape_neutral_dbg);
int external_live_source_dbg =
external_monitor_audio && !external_tape_source_dbg;
@@ -5883,13 +5946,16 @@ void *veejay_audio_producer_thread(void *arg)
} else {
#endif
double spvf = settings->spvf;
double spvf = vj_runtime_effective_spvf(settings);
const double next_frame_target = vj_runtime_target_time_s(settings, (long long)(loop_count + 1));
double now = monotonic_now_s();
double remaining_s = next_frame_target - now;
if (remaining_s > 0.0) {
if (remaining_s > spvf)
remaining_s = spvf;
usleep_hybrid((long long)(remaining_s * 1e6), settings);
}
@@ -5993,7 +6059,8 @@ static void veejay_producer_thread_audio_startup(veejay_t *info)
return;
}
while (!atomic_load_int(&info->audio_running))
while (!atomic_load_int(&info->audio_running) &&
atomic_load_int(&settings->state) != LAVPLAY_STATE_STOP)
usleep_accurate(200,settings);
}
@@ -6060,9 +6127,9 @@ static void veejay_audio_sync_thread_startup(veejay_t *info)
static int veejay_audio_sync_mode_is_playback(int mode)
{
return mode == VJ_AUDIO_SYNC_MODE_TEMPO_BRIDGE ||
mode == VJ_AUDIO_SYNC_MODE_TRACK_ALIGN ||
mode == VJ_AUDIO_SYNC_MODE_MONITOR;
if(mode == VJ_AUDIO_SYNC_MODE_TEMPO_FOLLOW)
return 0;
return vj_audio_sync_mode_uses_external_playback(mode);
}
static int veejay_audio_threads_disabled(video_playback_setup *settings)
@@ -6237,7 +6304,8 @@ int veejay_audio_sync_set_mode_control(veejay_t *info, int mode)
vj_audio_sync_set_mode(&settings->audio_sync, mode);
if(mode == VJ_AUDIO_SYNC_MODE_TRACK_ALIGN ||
mode == VJ_AUDIO_SYNC_MODE_TEMPO_FOLLOW)
mode == VJ_AUDIO_SYNC_MODE_TEMPO_FOLLOW ||
mode == VJ_AUDIO_SYNC_MODE_TEMPO_BRIDGE)
vj_audio_sync_set_target_mode(&settings->audio_sync,
VJ_AUDIO_SYNC_TARGET_CURRENT_CLIP);
@@ -6430,12 +6498,7 @@ static void veejay_audio_beat_prepare_sync_source(veejay_t *info)
current_channels = atomic_load_int(&settings->audio_sync.input_channels_request);
record_source = atomic_load_int(&settings->record_audio_source);
external_mode =
(mode == VJ_AUDIO_SYNC_MODE_LIVE_EXTERNAL ||
mode == VJ_AUDIO_SYNC_MODE_MONITOR ||
mode == VJ_AUDIO_SYNC_MODE_TEMPO_BRIDGE ||
mode == VJ_AUDIO_SYNC_MODE_TRACK_ALIGN ||
mode == VJ_AUDIO_SYNC_MODE_TEMPO_FOLLOW);
external_mode = vj_audio_sync_mode_is_audio_sync_family(mode);
use_push_source = 0;
if(record_source == VJ_RECORD_AUDIO_SOURCE_ORIGINAL)
@@ -6737,27 +6800,39 @@ static void *veejay_producer_thread_loop(void *ptr)
sigaddset(&mask, SIGPIPE);
pthread_sigmask(SIG_BLOCK, &mask, NULL);
while (atomic_load_int(&settings->warmup_active)) {
while (atomic_load_int(&settings->warmup_active) &&
atomic_load_int(&settings->state) != LAVPLAY_STATE_STOP) {
usleep_accurate(100, settings);
}
if (atomic_load_int(&settings->state) == LAVPLAY_STATE_STOP)
pthread_exit(NULL);
atomic_store_long_long(&settings->current_frame_num, -1);
atomic_store_int(&settings->audio_mode, AUDIO_MODE_SILENCE_FILL);
if(info->audio) {
#ifdef HAVE_JACK
veejay_msg(VEEJAY_MSG_DEBUG, "[PRODUCER] waiting for audio anchor");
while (atomic_load_double(&settings->audio_start_offset) <= 0.0) {
while (atomic_load_double(&settings->audio_start_offset) <= 0.0 &&
atomic_load_int(&settings->state) != LAVPLAY_STATE_STOP) {
usleep_accurate(100, settings);
}
if (atomic_load_int(&settings->state) == LAVPLAY_STATE_STOP)
pthread_exit(NULL);
#endif
}
veejay_msg(VEEJAY_MSG_DEBUG, "[PRODUCER] waiting for first audio frame ready");
while (atomic_load_int(&settings->first_audio_frame_ready) == 0) {
while (atomic_load_int(&settings->first_audio_frame_ready) == 0 &&
atomic_load_int(&settings->state) != LAVPLAY_STATE_STOP) {
usleep_accurate(100, settings);
}
if (atomic_load_int(&settings->state) == LAVPLAY_STATE_STOP)
pthread_exit(NULL);
veejay_msg(VEEJAY_MSG_DEBUG, "[PRODUCER] Wait for playback to reach anchor");
veejay_set_speed(info, 1, 0);
@@ -6790,7 +6865,8 @@ static void *veejay_producer_thread_loop(void *ptr)
int beat_action = vj_audio_beat_get_action(&settings->audio_beat);
if(beat_action == VJ_AUDIO_BEAT_ACTION_FREEZE ||
beat_action == VJ_AUDIO_BEAT_ACTION_FREEZE_AND_AUTO_FX)
beat_action == VJ_AUDIO_BEAT_ACTION_FREEZE_AND_AUTO_FX ||
beat_action == VJ_AUDIO_BEAT_ACTION_BREAK_BEAT)
{
vj_audio_beat_consume(info, &settings->audio_beat);
}
@@ -7377,10 +7453,14 @@ int veejay_main(veejay_t *info)
veejay_producer_thread_audio_startup(info);
while (atomic_load_int(&settings->first_audio_frame_ready) == 0) {
while (atomic_load_int(&settings->first_audio_frame_ready) == 0 &&
atomic_load_int(&settings->state) != LAVPLAY_STATE_STOP) {
usleep_accurate(5000, settings);
}
if (atomic_load_int(&settings->state) == LAVPLAY_STATE_STOP)
return 0;
Welcome(info);
return 1;
@@ -7985,10 +8065,18 @@ int veejay_audio_sync_set_external_wav(veejay_t *info, const char *path, int loo
mode > VJ_AUDIO_SYNC_MODE_MAX)
{
veejay_msg(VEEJAY_MSG_WARNING,
"[AUDIO-SYNC][WAV] invalid mode=%d, forcing external-analysis(%d)",
"[AUDIO-SYNC][WAV] invalid mode=%d, forcing clean monitor(%d)",
mode,
VJ_AUDIO_SYNC_MODE_LIVE_EXTERNAL);
mode = VJ_AUDIO_SYNC_MODE_LIVE_EXTERNAL;
VJ_AUDIO_SYNC_MODE_MONITOR);
mode = VJ_AUDIO_SYNC_MODE_MONITOR;
}
if(!vj_audio_sync_mode_supports_wav_master(mode)) {
veejay_msg(VEEJAY_MSG_WARNING,
"[AUDIO-SYNC][WAV] mode=%d does not support a WAV master, forcing clean monitor(%d)",
mode,
VJ_AUDIO_SYNC_MODE_MONITOR);
mode = VJ_AUDIO_SYNC_MODE_MONITOR;
}
loop = loop ? 1 : 0;
File diff suppressed because it is too large Load Diff
@@ -24,21 +24,18 @@
#ifdef HAVE_JACK
/* Keep this public header independent from vj-lib.h and vj-audio-sync.h.
* Only pointer types are used here, so forward declarations are enough.
* The complete vj_audio_beat_shared_t and veejay_t definitions live in
* vj-lib.h; vj_audio_sync_shared_t lives in vj-audio-sync.h.
*/
typedef struct vj_audio_beat_shared_t vj_audio_beat_shared_t;
typedef struct vj_audio_sync_shared_t vj_audio_sync_shared_t;
typedef struct veejay_t veejay_t;
typedef struct sample_eff_t sample_eff_chain;
typedef enum
{
VJ_AUDIO_BEAT_ACTION_NONE = 0,
VJ_AUDIO_BEAT_ACTION_FREEZE = 1,
VJ_AUDIO_BEAT_ACTION_AUTO_FX = 2,
VJ_AUDIO_BEAT_ACTION_FREEZE_AND_AUTO_FX = 3
VJ_AUDIO_BEAT_ACTION_FREEZE_AND_AUTO_FX = 3,
VJ_AUDIO_BEAT_ACTION_BREAK_BEAT = 4
} vj_audio_beat_action_t;
typedef enum
@@ -131,6 +128,7 @@ typedef struct
typedef int (*vj_audio_beat_get_fx_id_func)(void *ctx, int chain_pos);
typedef int (*vj_audio_beat_get_fx_arg_func)(void *ctx, int chain_pos, int param_nr);
typedef int (*vj_audio_beat_set_fx_arg_func)(void *ctx, int chain_pos, int param_nr, int value);
typedef sample_eff_chain *(*vj_audio_beat_get_fx_entry_func)(void *ctx, int chain_pos);
void vj_audio_beat_init(vj_audio_beat_shared_t *s, int input_channels);
void vj_audio_beat_bind_sync(vj_audio_beat_shared_t *s, vj_audio_sync_shared_t *sync);
@@ -147,6 +145,9 @@ int vj_audio_beat_is_enabled(vj_audio_beat_shared_t *s);
int vj_audio_beat_is_running(vj_audio_beat_shared_t *s);
int vj_audio_beat_is_open(vj_audio_beat_shared_t *s);
int vj_audio_beat_is_paused_by_beat(vj_audio_beat_shared_t *s);
int vj_audio_beat_transport_is_internal(vj_audio_beat_shared_t *s);
void vj_audio_beat_user_transport_override(veejay_t *v, vj_audio_beat_shared_t *s,
int requested_speed);
void vj_audio_beat_set_freeze_ms(vj_audio_beat_shared_t *s, int ms);
void vj_audio_beat_set_cooldown_ms(vj_audio_beat_shared_t *s, int ms);
@@ -170,6 +171,23 @@ int vj_audio_beat_auto_apply_chain(
vj_audio_beat_get_fx_arg_func get_arg,
vj_audio_beat_set_fx_arg_func set_arg
);
int vj_audio_beat_auto_apply_chain_ex(
vj_audio_beat_shared_t *s,
void *ctx,
int chain_len,
vj_audio_beat_get_fx_id_func get_fx_id,
vj_audio_beat_get_fx_arg_func get_arg,
vj_audio_beat_set_fx_arg_func set_arg,
vj_audio_beat_get_fx_entry_func get_entry
);
int vj_audio_beat_auto_modulate_args(
vj_audio_beat_shared_t *s,
sample_eff_chain *entry,
int effect_id,
int *args,
int n_params,
long long n_frame
);
int vj_audio_beat_copy_record_audio(
vj_audio_beat_shared_t *s,
@@ -190,6 +208,12 @@ int vj_audio_beat_get_snapshot(vj_audio_beat_shared_t *s, vj_audio_beat_snapshot
float vj_audio_beat_get_signal(vj_audio_beat_shared_t *s, int signal);
int vj_audio_beat_map_signal(vj_audio_beat_shared_t *s, int signal, int min_value, int max_value, int invert);
int vj_audio_beat_disable_for_transport(veejay_t *v, vj_audio_beat_shared_t *s);
int vj_audio_beat_release_transport(veejay_t *v, vj_audio_beat_shared_t *s);
void vj_audio_beat_set_action_for_transport(veejay_t *v,
vj_audio_beat_shared_t *s,
int action);
#endif
#endif
File diff suppressed because it is too large Load Diff
@@ -32,19 +32,52 @@
#define VJ_AUDIO_SYNC_ALIGN_FEATURES 4096
static inline int vj_audio_sync_mode_is_control_only(int mode)
{
return mode == VJ_AUDIO_SYNC_MODE_LIVE_EXTERNAL;
}
static inline int vj_audio_sync_mode_is_tempo_follow(int mode)
{
return mode == VJ_AUDIO_SYNC_MODE_TEMPO_FOLLOW;
}
#define VJ_AUDIO_SYNC_TRACK_STATE_IDLE 0
#define VJ_AUDIO_SYNC_TRACK_STATE_WAIT_SOURCE 1
#define VJ_AUDIO_SYNC_TRACK_STATE_WAIT_TARGET 2
#define VJ_AUDIO_SYNC_TRACK_STATE_SEARCHING 3
#define VJ_AUDIO_SYNC_TRACK_STATE_LOCKED 4
#define VJ_AUDIO_SYNC_TRACK_STATE_HOLD 5
#define VJ_AUDIO_SYNC_TRACK_STATE_FALLBACK 6
static inline int vj_audio_sync_mode_is_clean_monitor(int mode)
{
return mode == VJ_AUDIO_SYNC_MODE_MONITOR;
}
#ifndef VJ_AUDIO_SYNC_MODE_MAX
#define VJ_AUDIO_SYNC_MODE_MAX VJ_AUDIO_SYNC_MODE_TEMPO_FOLLOW
#endif
static inline int vj_audio_sync_mode_is_trickplay_monitor(int mode)
{
return mode == VJ_AUDIO_SYNC_MODE_MONITOR_TRICKPLAY;
}
static inline int vj_audio_sync_mode_uses_external_playback(int mode)
{
return mode == VJ_AUDIO_SYNC_MODE_MONITOR ||
mode == VJ_AUDIO_SYNC_MODE_MONITOR_TRICKPLAY ||
mode == VJ_AUDIO_SYNC_MODE_TEMPO_BRIDGE ||
mode == VJ_AUDIO_SYNC_MODE_TRACK_ALIGN;
}
static inline int vj_audio_sync_mode_uses_transport_driven_playback(int mode)
{
return mode == VJ_AUDIO_SYNC_MODE_MONITOR_TRICKPLAY ||
mode == VJ_AUDIO_SYNC_MODE_TEMPO_BRIDGE ||
mode == VJ_AUDIO_SYNC_MODE_TRACK_ALIGN;
}
static inline int vj_audio_sync_mode_supports_wav_master(int mode)
{
return vj_audio_sync_mode_uses_external_playback(mode);
}
static inline int vj_audio_sync_mode_is_audio_sync_family(int mode)
{
return mode == VJ_AUDIO_SYNC_MODE_LIVE_EXTERNAL ||
mode == VJ_AUDIO_SYNC_MODE_TEMPO_FOLLOW ||
vj_audio_sync_mode_uses_external_playback(mode);
}
typedef struct
{
@@ -97,20 +130,12 @@ typedef struct
int track_align_correction_ppm;
int track_align_state;
/* Internal wide-search snap suggestion, consumed by the playback loop.
* Not part of the public status token contract.
*/
int track_align_snap_pending;
int track_align_snap_delta_frames;
int track_align_snap_confidence_pct;
} vj_audio_sync_snapshot_t;
/* Full shared state is intentionally defined here because video_playback_setup
* embeds vj_audio_sync_shared_t directly. Do not include vj-lib.h from the
* audio synchronizer: modules that only need pointers can forward-declare this
* typedef, while vj-lib.h includes this header to get the complete size.
*/
typedef struct vj_audio_sync_shared_t
{
volatile int initialized;
@@ -186,10 +211,6 @@ typedef struct vj_audio_sync_shared_t
long bridge_latch_updated_ms;
volatile int bridge_state;
/* Tempo Bridge transport clock.
* Keep BPM estimates latched and slow-moving so the audible read-head
* behaves like a stable transport, not like a phase-chasing cassette motor.
*/
double bridge_source_bpm_latched;
double bridge_target_bpm_latched;
int bridge_bpm_latch_valid;
@@ -201,10 +222,6 @@ typedef struct vj_audio_sync_shared_t
int bridge_stretch_segment_len;
int bridge_stretch_overlap;
/* Track Align / waveform sync feature rings.
* Source = external master track; target = current clip/original audio.
* Features are low-rate onset/envelope values, updated by capture/push paths.
*/
float align_source_feat[VJ_AUDIO_SYNC_ALIGN_FEATURES];
float align_target_feat[VJ_AUDIO_SYNC_ALIGN_FEATURES];
int align_source_pos;
@@ -227,7 +244,6 @@ typedef struct vj_audio_sync_shared_t
int align_snap_cooldown_ms;
volatile int align_video_fps_x1000;
/* Worker-thread live snap consensus state. */
int align_live_candidate_delta;
int align_live_candidate_conf_min;
int align_live_candidate_conf_sum;
@@ -236,28 +252,20 @@ typedef struct vj_audio_sync_shared_t
long align_live_last_snap_ms;
int align_live_last_snap_delta;
/* Rough, non-authoritative live basin exported to performer wide search. */
int align_rough_hint_offset_ms;
int align_rough_hint_conf;
int align_rough_hint_count;
long align_rough_hint_ms;
/* Current-clip target audio queue. Producer enqueues PCM cheaply;
* audio_sync_thread drains it and runs target clock/Track Align analysis.
*/
uint8_t *target_ring;
int target_ring_frames;
int target_ring_write_frame;
long long target_write_frame_abs;
/* Oldest retained target frame in the ring. This is no longer the
* worker consume cursor: Track Align needs retained target history for
* stable correlation, while the worker still needs to process each
* target block exactly once.
*/
long long target_read_frame_abs;
/* Next target frame the sync worker must process into clock/features. */
long long target_process_frame_abs;
int target_channels;
@@ -280,16 +288,18 @@ typedef struct vj_audio_sync_shared_t
volatile int wav_limit_ms;
volatile int wav_silence_after_eof;
/* PLAIN+WAV Track Align cache. Once a strong WAV/video lock is found,
* replay can snap immediately without re-running wide target analysis.
* The cache is generation-bound, so changing the WAV path/source clears it.
*/
volatile int wav_plain_lock_valid;
volatile int wav_plain_lock_generation;
volatile int wav_plain_lock_delta_frames;
volatile int wav_plain_lock_confidence_pct;
/* internal source detector state; only sync thread / push path writes it */
volatile int jack_connect_failures;
volatile int jack_connect_giveup;
volatile long jack_connect_first_fail_ms;
volatile long jack_connect_next_retry_ms;
volatile long jack_connect_last_log_ms;
double fast_energy;
double slow_energy;
double envelope;
@@ -297,7 +307,6 @@ typedef struct vj_audio_sync_shared_t
double beat_period_ms;
long last_analysis_ms;
/* internal target-clock detector state for current-clip auto target */
double target_fast_energy;
double target_slow_energy;
double target_envelope;
@@ -371,10 +380,7 @@ void vj_audio_sync_track_align_reset_acquisition(vj_audio_sync_shared_t *s);
int vj_audio_sync_track_align_source_ready(vj_audio_sync_shared_t *s, int min_source_features);
int vj_audio_sync_track_align_last_snap(vj_audio_sync_shared_t *s, long *snap_ms, int *delta_frames);
/* Wide waveform snap support.
* Probe candidate original-audio windows against the recent external master
* feature window, then offer/consume a one-shot video-frame snap.
*/
int vj_audio_sync_track_align_probe_target_audio(vj_audio_sync_shared_t *s,
const uint8_t *src,
int frames,
@@ -56,6 +56,9 @@
#include <libveejay/vj-jack.h>
#include <libveejay/vj-audio-beat.h>
#include <libveejay/vj-audio-sync.h>
#ifndef VJ_AUDIO_BEAT_ACTION_BREAK_BEAT
#define VJ_AUDIO_BEAT_ACTION_BREAK_BEAT 4
#endif
#endif
#include <libstream/vj-tag.h>
#include <libstream/vj-vloopback.h>
@@ -8670,6 +8673,8 @@ static const char *vj_audio_beat_event_action_name(int action)
return "auto-fx";
case VJ_AUDIO_BEAT_ACTION_FREEZE_AND_AUTO_FX:
return "freeze+auto-fx";
case VJ_AUDIO_BEAT_ACTION_BREAK_BEAT:
return "break-beat";
default:
return "unknown";
}
@@ -9229,7 +9234,7 @@ void vj_event_audio_beat_ui_config(void *ptr, const char format[], va_list ap)
if(!vj_event_audio_beat_ready(v))
return;
args[1] = vj_audio_beat_event_clampi(args[1], VJ_AUDIO_BEAT_ACTION_NONE, VJ_AUDIO_BEAT_ACTION_FREEZE_AND_AUTO_FX);
args[1] = vj_audio_beat_event_clampi(args[1], VJ_AUDIO_BEAT_ACTION_NONE, VJ_AUDIO_BEAT_ACTION_BREAK_BEAT);
args[8] = vj_audio_beat_event_clampi(args[8], VJ_AUDIO_BEAT_AUTO_OFF, VJ_AUDIO_BEAT_AUTO_CHAOS);
args[9] = vj_audio_beat_event_clampi(args[9], 0, 100);
@@ -9405,7 +9410,7 @@ void vj_event_audio_beat_action(void *ptr, const char format[], va_list ap)
args[0] = vj_audio_beat_event_clampi(args[0],
VJ_AUDIO_BEAT_ACTION_NONE,
VJ_AUDIO_BEAT_ACTION_FREEZE_AND_AUTO_FX);
VJ_AUDIO_BEAT_ACTION_BREAK_BEAT);
{
int freeze = -1;
@@ -2362,7 +2362,7 @@ void vj_init_vevo_events(void)
vj_event_audio_beat_action,
1,
VIMS_REQUIRE_ALL_PARAMS,
"Action: 0=none, 1=freeze, 2=auto-fx, 3=freeze+auto-fx",
"Action: 0=none, 1=freeze, 2=auto-fx, 3=freeze+auto-fx, 4=break-beat",
2,
NULL );
@@ -2428,7 +2428,7 @@ void vj_init_vevo_events(void)
VIMS_REQUIRE_ALL_PARAMS,
"Enabled state, 0 or 1",
1,
"Action: 0=none, 1=freeze, 2=auto-fx, 3=freeze+auto-fx",
"Action: 0=none, 1=freeze, 2=auto-fx, 3=freeze+auto-fx, 4=break-beat",
2,
"Freeze duration in milliseconds",
90,
+26 -25
View File
@@ -44,7 +44,6 @@ enum {
LAVPLAY_STATE_PLAYING = 2 /* speed != 0 */
};
/* nmacro recorder, 5 lines code for play back of what you changed at navigation */
enum {
VJ_MACRO_PLAIN_RECORD = 0,
VJ_MACRO_PLAIN_PLAY = 1,
@@ -56,10 +55,6 @@ enum {
#define AUDIO_MODE_SILENCE_FILL 0
#define AUDIO_MODE_CONTENT 1
/* Coherent recording audio source selection.
* AUTO follows the active audible external path when one is selected,
* otherwise it records the original media audio.
*/
#define VJ_RECORD_AUDIO_SOURCE_AUTO 0
#define VJ_RECORD_AUDIO_SOURCE_ORIGINAL 1
#define VJ_RECORD_AUDIO_SOURCE_BEAT_JACK 2
@@ -70,7 +65,6 @@ enum {
#define DUMMY_DEFAULT_HEIGHT 288
#define DUMMY_DEFAULT_FPS 25
/* Video Playback Setup, necessary items for reading and playing video */
struct mjpeg_sync
{
unsigned long frame; /* Frame (0 - n) for double buffer */
@@ -225,16 +219,35 @@ typedef struct vj_audio_beat_shared_t
volatile long record_underruns;
#ifdef HAVE_JACK
/*
* External capture/clock provider.
* Beat consumes this instead of owning JACK input directly.
* NULL keeps legacy direct-JACK capture alive during transition.
*/
vj_audio_sync_shared_t *sync;
#endif
} vj_audio_beat_shared_t;
#define VJ_SCENE_ANALYSIS_MAX_SIDE 64
#define VJ_SCENE_ANALYSIS_MAX_PIXELS (VJ_SCENE_ANALYSIS_MAX_SIDE * VJ_SCENE_ANALYSIS_MAX_SIDE)
typedef struct vj_scene_detect_t
{
volatile int valid;
volatile long long frame;
volatile int scene_id;
volatile long long last_cut_frame;
volatile int scene_age_frames;
volatile int hard_cut;
volatile int cut_score_q15;
volatile int diff_q15;
volatile int mean_q15;
volatile int analysis_w;
volatile int analysis_h;
int prev_ready;
double diff_ema;
double diff_var;
double mean_ema;
uint8_t prev[VJ_SCENE_ANALYSIS_MAX_PIXELS];
} vj_scene_detect_t;
typedef struct vj_audio_clock_osd_t {
volatile long long prod_loops;
volatile long long prod_anomalies;
@@ -298,6 +311,7 @@ typedef struct {
vj_audio_sync_shared_t audio_sync;
#endif
vj_audio_beat_shared_t audio_beat;
vj_scene_detect_t scene_detect;
volatile int audio_mode;
volatile int state;
@@ -310,13 +324,6 @@ typedef struct {
volatile double runtime_playback_rate;
volatile long long anchor_frame;
#ifdef HAVE_JACK
/* Track Align re-anchor bookkeeping. When the user scratches, reverses,
* pauses, or changes runtime FPS, the external JACK/master track keeps
* moving forward. On return to normal +1 playback we can estimate the
* expected media frame linearly from the audio clock, then let waveform
* align fine-tune it. track_align_reacquire_seq lets performer-side wide
* acquisition clear stale buckets without coupling libveejay to performer_t.
*/
volatile int track_align_reacquire_seq;
volatile int track_align_linear_active;
volatile long long track_align_linear_anchor_frame;
@@ -326,13 +333,7 @@ typedef struct {
volatile double track_align_linear_frame_accum;
volatile int track_align_linear_mode;
volatile int track_align_linear_id;
/* Track Align correction edge handling.
* Current Track Align corrections use the normal AUDIO_EDGE_JUMP
* crossfade/declick path for arbitrary corrected seeks. AUDIO_EDGE_RESET
* stays reserved for real reset boundaries such as sample start/min-frame
* handling. These fields are kept for ABI/source compatibility with earlier
* experimental builds; playback no longer mutes on track_align_audio_guard.
*/
volatile int track_align_force_audio_edge_reset;
volatile long long track_align_audio_guard_until_ms;
#endif
File diff suppressed because it is too large Load Diff