feat(audio): crossfade overlapping clips in one undoable edit (phase 98)

This commit is contained in:
Johannes Findeisen 2026-11-06 02:10:11 +01:00
commit 083ac05ae6
10 changed files with 82 additions and 6 deletions

View file

@ -266,6 +266,10 @@ int creative_workflow_tests()
CHECK(find(&window,"Tap"));CHECK(window.tap_tempo(0)==XTC_ERR_NOT_FOUND && window.tap_tempo(.4)==XTC_OK);
CHECK(xtc_project_tempo(s->project())==150000 && window.undo()==XTC_OK && xtc_project_tempo(s->project())==120000);
CHECK(window.new_project()==XTC_OK && window.tap_tempo(.9)==XTC_ERR_NOT_FOUND);
CHECK(window.create_track(false)==XTC_OK);auto audio_track=s->selected_track();s->position(0);CHECK(s->add_region()==XTC_OK);auto left_clip=s->selected_clip();
engine_status.sample_position=48000;s->position(1920);CHECK(s->add_region()==XTC_OK);auto right_clip=s->selected_clip();CHECK(s->select(audio_track,left_clip) && s->toggle_clip(right_clip));
CHECK(s->crossfade_selection()==XTC_OK);xtc_clip_info audio{};CHECK(xtc_project_find_clip(s->project(),left_clip,&audio)==XTC_OK && audio.fade_out_tick==1920);
CHECK(window.undo()==XTC_OK && xtc_project_find_clip(s->project(),left_clip,&audio)==XTC_OK && !audio.fade_out_tick);
CHECK(!panel->comparison_ready(0) && !panel->comparison_ready(1));
window.do_callback();puts("Creative workflow GUI checks passed.");return failures ? 1 : 0;
}

View file

@ -1,5 +1,10 @@
#define _POSIX_C_SOURCE 200809L
#include "xtc/xtc_plugin.h"
#include "xtc/xtc_tempo.h"
#include "xtc/xtc_editing.h"
#include "xtc/xtc_audio.h"
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
@ -18,9 +23,31 @@ static void tap_tests(void)
assert(xtc_tap_tempo_push(&s,10.25,&tempo)==XTC_OK && tempo==240000);
xtc_tap_tempo_reset(&s);assert(!s.started && !s.count);
}
static void crossfade_tests(void)
{
xtc_project *p=NULL;xtc_recorder *rec=NULL;xtc_audio_plan *plan=NULL;uint64_t track,a,b;xtc_clip_info left,right,before;
char wave[]="/tmp/xtc-crossfade-XXXXXX";int fd=mkstemp(wave);float ones[1000],output[32];assert(fd>=0);close(fd);unlink(wave);
for(size_t i=0;i<1000;++i)ones[i]=1;
assert(xtc_recorder_create(wave,8000,8000,&rec)==XTC_OK);
for(size_t i=0;i<8;++i)xtc_recorder_push(rec,ones,1000);
assert(xtc_recorder_finish(rec)==XTC_OK);xtc_recorder_destroy(rec);
assert(xtc_project_create(&p)==XTC_OK && xtc_project_add_track(p,"Audio",&track)==XTC_OK);
assert(xtc_project_add_clip(p,track,"Left",0,1920,&a)==XTC_OK && xtc_project_add_clip(p,track,"Right",960,1920,&b)==XTC_OK);
assert(xtc_project_set_clip_asset(p,a,wave)==XTC_OK && xtc_project_set_clip_asset(p,b,wave)==XTC_OK);
assert(xtc_project_set_clip_audio(p,a,1,16,0)==XTC_OK && xtc_project_set_clip_audio(p,b,1,0,16)==XTC_OK);
assert(xtc_project_crossfade(p,b,a)==XTC_OK && xtc_project_find_clip(p,a,&left)==XTC_OK && xtc_project_find_clip(p,b,&right)==XTC_OK);
assert(left.fade_in_tick==16 && left.fade_out_tick==960 && right.fade_in_tick==960 && right.fade_out_tick==16);
assert(xtc_audio_plan_create(p,8000,&plan)==XTC_OK && xtc_audio_plan_set_fade_frames(plan,0)==XTC_OK && xtc_audio_plan_render(plan,4000,output,32)==XTC_OK);
for(size_t i=0;i<32;++i)assert(fabsf(output[i]-.99975f)<.00001f);
xtc_audio_plan_destroy(plan);before=left;
assert(xtc_project_crossfade(p,a,a)==XTC_ERR_INVALID_ARGUMENT && xtc_project_find_clip(p,a,&left)==XTC_OK && !memcmp(&before,&left,sizeof(left)));
assert(xtc_project_edit_clip(p,b,track,1920,1920,0)==XTC_OK && xtc_project_crossfade(p,a,b)==XTC_ERR_INVALID_ARGUMENT);
assert(xtc_project_find_clip(p,a,&left)==XTC_OK && !memcmp(&before,&left,sizeof(left)));
xtc_project_destroy(p);unlink(wave);
}
int main(void)
{
tap_tests();
tap_tests();crossfade_tests();
xtc_track_chain c={0},out={0};
c.output_gain=.8f;c.count=1;c.slots[0].enabled=1;c.slots[0].wet=.4f;
assert(xtc_plugin_probe_format(XTC_PLUGIN_BUILTIN,XTC_BUILTIN_PATH,2,48000,&c.slots[0].plugin)==XTC_OK);