2026-11-06 00:29:48 +01:00
|
|
|
#define _POSIX_C_SOURCE 200809L
|
|
|
|
|
#include "xtc/xtc_editing.h"
|
|
|
|
|
#include "xtc/xtc_mixer.h"
|
|
|
|
|
#include "xtc/xtc_audio.h"
|
2026-11-06 00:33:58 +01:00
|
|
|
#include "xtc/xtc_plugin.h"
|
2026-11-06 00:29:48 +01:00
|
|
|
#include <assert.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <unistd.h>
|
2026-11-06 00:49:37 +01:00
|
|
|
#include <sys/stat.h>
|
2026-11-06 00:46:14 +01:00
|
|
|
#include <math.h>
|
2026-11-06 00:29:48 +01:00
|
|
|
|
2026-11-06 00:46:14 +01:00
|
|
|
static void put32(unsigned char *p,uint32_t value){p[0]=(unsigned char)value;p[1]=(unsigned char)(value>>8);p[2]=(unsigned char)(value>>16);p[3]=(unsigned char)(value>>24);}
|
|
|
|
|
static void test_wave(const char *path,float amplitude)
|
|
|
|
|
{
|
|
|
|
|
unsigned char h[44]={0},bytes[4];FILE *f=fopen(path,"wb");assert(f);
|
|
|
|
|
memcpy(h,"RIFF",4);put32(h+4,52);memcpy(h+8,"WAVEfmt ",8);put32(h+16,16);h[20]=3;h[22]=1;put32(h+24,1000);put32(h+28,4000);h[32]=4;h[34]=32;memcpy(h+36,"data",4);put32(h+40,16);
|
|
|
|
|
assert(fwrite(h,1,44,f)==44);for(size_t i=0;i<4;++i){uint32_t bits;float v=i%2 ? -amplitude*.5f : amplitude;memcpy(&bits,&v,4);put32(bytes,bits);assert(fwrite(bytes,1,4,f)==4);}assert(fclose(f)==0);
|
|
|
|
|
}
|
2026-11-06 00:29:48 +01:00
|
|
|
static void markers(void)
|
|
|
|
|
{
|
|
|
|
|
xtc_project *p=NULL,*q=NULL;xtc_marker m;size_t count;char path[]="/tmp/xtc-sections-XXXXXX";
|
|
|
|
|
int fd=mkstemp(path);assert(fd>=0 && close(fd)==0);
|
|
|
|
|
assert(xtc_project_create(&p)==XTC_OK && xtc_project_create(&q)==XTC_OK);
|
|
|
|
|
assert(xtc_project_set_marker(p,3840,"Chorus")==XTC_OK);
|
|
|
|
|
assert(xtc_project_set_marker(p,0,"Intro")==XTC_OK);
|
|
|
|
|
assert(xtc_project_set_marker(p,0,"Intro ä")==XTC_OK);
|
|
|
|
|
assert(xtc_project_get_marker(p,0,&m)==XTC_OK && !strcmp(m.name,"Intro ä"));
|
|
|
|
|
assert(xtc_project_set_marker(p,1,"Bad\n")==XTC_ERR_INVALID_ARGUMENT);
|
|
|
|
|
assert(xtc_project_save(p,path)==XTC_OK && xtc_project_load(q,path)==XTC_OK);
|
|
|
|
|
assert(xtc_project_marker_count(q,&count)==XTC_OK && count==2);
|
|
|
|
|
assert(xtc_project_get_marker(q,1,&m)==XTC_OK && m.tick==3840 && !strcmp(m.name,"Chorus"));
|
|
|
|
|
assert(xtc_project_remove_marker(q,0)==XTC_OK && xtc_project_remove_marker(q,0)==XTC_ERR_NOT_FOUND);
|
|
|
|
|
for(size_t i=1;i<127;++i)assert(xtc_project_set_marker(p,i,"M")==XTC_OK);
|
|
|
|
|
assert(xtc_project_set_marker(p,999,"Full")==XTC_ERR_CAPACITY);
|
|
|
|
|
/* Malformed marker ordering rejects transactionally. */
|
|
|
|
|
{FILE *f=fopen(path,"r");char data[32768];size_t n;assert(f);n=fread(data,1,sizeof(data)-1,f);data[n]=0;fclose(f);
|
|
|
|
|
char *at=strstr(data,"MARKER 3840");assert(at);memcpy(at+7,"0000",4);
|
|
|
|
|
f=fopen(path,"w");assert(f && fwrite(data,1,n,f)==n && fclose(f)==0);
|
|
|
|
|
assert(xtc_project_load(q,path)==XTC_ERR_FORMAT);assert(xtc_project_marker_count(q,&count)==XTC_OK && count==1);}
|
|
|
|
|
xtc_project_destroy(p);xtc_project_destroy(q);assert(unlink(path)==0);
|
|
|
|
|
}
|
2026-11-06 00:31:08 +01:00
|
|
|
static void sections(void)
|
|
|
|
|
{
|
|
|
|
|
xtc_project *p=NULL;uint64_t t,c,begin=999,end=999;xtc_marker m={0};
|
|
|
|
|
assert(xtc_project_create(&p)==XTC_OK && xtc_project_add_track(p,"Track",&t)==XTC_OK);
|
|
|
|
|
assert(xtc_project_add_clip(p,t,"Song",0,7680,&c)==XTC_OK);
|
|
|
|
|
assert(xtc_project_set_marker(p,960,"A")==XTC_OK && xtc_project_set_marker(p,3840,"B")==XTC_OK);
|
|
|
|
|
assert(xtc_project_section(p,0,&begin,&end)==XTC_ERR_NOT_FOUND && begin==999);
|
|
|
|
|
assert(xtc_project_section(p,960,&begin,&end)==XTC_OK && begin==960 && end==3840);
|
|
|
|
|
assert(xtc_project_section(p,5000,&begin,&end)==XTC_OK && begin==3840 && end==7680);
|
|
|
|
|
assert(xtc_project_adjacent_marker(p,960,1,&m)==XTC_OK && m.tick==3840);
|
|
|
|
|
assert(xtc_project_adjacent_marker(p,3840,-1,&m)==XTC_OK && m.tick==960);
|
|
|
|
|
assert(xtc_project_adjacent_marker(p,960,-1,&m)==XTC_ERR_NOT_FOUND && m.tick==960);
|
|
|
|
|
assert(xtc_project_set_marker(p,9000,"Empty")==XTC_OK && xtc_project_section(p,9000,&begin,&end)==XTC_ERR_INVALID_STATE);
|
|
|
|
|
xtc_project_destroy(p);
|
|
|
|
|
}
|
2026-11-06 00:32:33 +01:00
|
|
|
static void ripple(void)
|
|
|
|
|
{
|
|
|
|
|
xtc_project *p=NULL;uint64_t t,c,a;xtc_clip_info clip;xtc_marker m;xtc_automation_point point;
|
|
|
|
|
assert(xtc_project_create(&p)==XTC_OK && xtc_project_add_track(p,"Track",&t)==XTC_OK);
|
|
|
|
|
assert(xtc_project_add_clip(p,t,"A",0,960,&a)==XTC_OK && xtc_project_add_clip(p,t,"B",1920,960,&c)==XTC_OK);
|
|
|
|
|
point=(xtc_automation_point){t,1920,XTC_AUTOMATION_GAIN,.5f,0};assert(xtc_project_set_automation(p,&point)==XTC_OK);
|
|
|
|
|
assert(xtc_project_set_marker(p,1920,"B")==XTC_OK);
|
|
|
|
|
assert(xtc_project_ripple_time(p,480,960,0)==XTC_ERR_INVALID_STATE);
|
|
|
|
|
assert(xtc_project_ripple_time(p,960,960,0)==XTC_OK);
|
|
|
|
|
assert(xtc_project_find_clip(p,c,&clip)==XTC_OK && clip.start_tick==2880);
|
|
|
|
|
assert(xtc_project_get_marker(p,0,&m)==XTC_OK && m.tick==2880);
|
|
|
|
|
assert(xtc_project_get_automation(p,0,&point)==XTC_OK && point.tick==2880);
|
|
|
|
|
assert(xtc_project_ripple_time(p,960,1920,1)==XTC_OK);
|
|
|
|
|
assert(xtc_project_find_clip(p,c,&clip)==XTC_OK && clip.start_tick==960);
|
|
|
|
|
assert(xtc_project_ripple_time(p,0,960,1)==XTC_OK && xtc_project_find_clip(p,a,&clip)==XTC_ERR_NOT_FOUND);
|
|
|
|
|
assert(xtc_project_find_clip(p,c,&clip)==XTC_OK && clip.start_tick==0);
|
|
|
|
|
xtc_project_destroy(p);
|
|
|
|
|
}
|
2026-11-06 00:33:58 +01:00
|
|
|
static void duplicate_track(void)
|
|
|
|
|
{
|
|
|
|
|
xtc_project *p=NULL;uint64_t t,b,c,n,id=999;xtc_track_info track;xtc_plugin_spec spec,actual;size_t count;
|
|
|
|
|
assert(xtc_project_create(&p)==XTC_OK && xtc_project_add_track(p,"Keys",&t)==XTC_OK);
|
|
|
|
|
assert(xtc_project_add_bus(p,"Bus",&b)==XTC_OK && xtc_project_route_track(p,t,b)==XTC_OK);
|
|
|
|
|
assert(xtc_project_add_midi_clip(p,t,960,1920,&c)==XTC_OK && xtc_project_add_note(p,c,240,120,60,90,1,&n)==XTC_OK);
|
|
|
|
|
assert(xtc_plugin_probe_format(XTC_PLUGIN_BUILTIN,XTC_BUILTIN_PATH,0,48000,&spec)==XTC_OK && xtc_project_set_instrument(p,t,&spec)==XTC_OK);
|
|
|
|
|
assert(xtc_project_set_mix(p,t,.5f,-.5f,1,0)==XTC_OK);
|
|
|
|
|
{xtc_automation_point a={t,960,XTC_AUTOMATION_GAIN,.75f,0};assert(xtc_project_set_automation(p,&a)==XTC_OK);}
|
|
|
|
|
assert(xtc_project_duplicate_track(p,b,"Bus copy",&id)==XTC_ERR_INVALID_STATE && id==999);
|
|
|
|
|
assert(xtc_project_duplicate_track(p,t,"Keys copy",&id)==XTC_OK && id!=t);
|
|
|
|
|
assert(xtc_project_get_track(p,1,&track)==XTC_OK && track.id==id && track.gain==.5f && track.mute && track.bus_id==b);
|
|
|
|
|
assert(xtc_project_get_instrument(p,id,&actual)==XTC_OK && actual.index==spec.index);
|
|
|
|
|
assert(xtc_project_note_count(p,&count)==XTC_OK && count==2);
|
|
|
|
|
assert(xtc_project_automation_count(p,&count)==XTC_OK && count==2);
|
|
|
|
|
xtc_project_destroy(p);
|
|
|
|
|
}
|
2026-11-06 00:36:04 +01:00
|
|
|
static void split_midi(void)
|
|
|
|
|
{
|
|
|
|
|
xtc_project *p=NULL;xtc_midi_plan *before=NULL,*after=NULL;uint64_t t,c,n,right=999;xtc_clip_info slice;float a[512],b[512];
|
|
|
|
|
assert(xtc_project_create(&p)==XTC_OK && xtc_project_add_track(p,"Track",&t)==XTC_OK);
|
|
|
|
|
assert(xtc_project_add_midi_clip(p,t,0,960,&c)==XTC_OK && xtc_project_add_note(p,c,0,960,60,90,0,&n)==XTC_OK);
|
|
|
|
|
assert(xtc_midi_plan_create(p,48000,&before)==XTC_OK);
|
|
|
|
|
assert(xtc_project_split_midi(p,c,0,&right)==XTC_ERR_INVALID_ARGUMENT && right==999);
|
|
|
|
|
assert(xtc_project_split_midi(p,c,480,&right)==XTC_OK && right!=c);
|
|
|
|
|
assert(xtc_project_find_clip(p,right,&slice)==XTC_OK && slice.offset_tick==480 && slice.length_tick==480);
|
|
|
|
|
assert(xtc_midi_plan_create(p,48000,&after)==XTC_OK);
|
|
|
|
|
assert(xtc_midi_plan_render(before,11800,NULL,0,a,512)==XTC_OK && xtc_midi_plan_render(after,11800,NULL,0,b,512)==XTC_OK);
|
|
|
|
|
assert(!memcmp(a,b,sizeof(a)));xtc_midi_plan_destroy(before);xtc_midi_plan_destroy(after);xtc_project_destroy(p);
|
|
|
|
|
}
|
2026-11-06 00:38:13 +01:00
|
|
|
static void merge_midi(void)
|
|
|
|
|
{
|
|
|
|
|
xtc_project *p=NULL;uint64_t t,ids[2],n,out=999;xtc_note_info note;size_t count;
|
|
|
|
|
assert(xtc_project_create(&p)==XTC_OK && xtc_project_add_track(p,"Track",&t)==XTC_OK);
|
|
|
|
|
assert(xtc_project_add_midi_clip(p,t,960,960,&ids[0])==XTC_OK && xtc_project_add_midi_clip(p,t,1920,960,&ids[1])==XTC_OK);
|
|
|
|
|
assert(xtc_project_add_note(p,ids[0],0,240,60,90,0,&n)==XTC_OK);
|
|
|
|
|
assert(xtc_project_add_note(p,ids[0],600,240,64,100,1,&n)==XTC_OK);
|
|
|
|
|
assert(xtc_project_add_note(p,ids[1],0,480,67,110,2,&n)==XTC_OK);
|
|
|
|
|
assert(xtc_project_edit_clip(p,ids[0],t,960,480,240)==XTC_OK && xtc_project_edit_clip(p,ids[1],t,1920,480,240)==XTC_OK);
|
|
|
|
|
assert(xtc_project_merge_midi(p,ids,1,&out)==XTC_ERR_INVALID_ARGUMENT && out==999);
|
|
|
|
|
assert(xtc_project_merge_midi(p,ids,2,&out)==XTC_OK);
|
|
|
|
|
assert(xtc_project_note_count(p,&count)==XTC_OK && count==2);
|
|
|
|
|
assert(xtc_project_get_note(p,0,¬e)==XTC_OK && note.start_tick==360 && note.length_tick==120 && note.pitch==64 && note.channel==1);
|
|
|
|
|
assert(xtc_project_get_note(p,1,¬e)==XTC_OK && note.start_tick==960 && note.length_tick==240 && note.pitch==67);
|
|
|
|
|
xtc_project_destroy(p);
|
|
|
|
|
}
|
2026-11-06 00:39:19 +01:00
|
|
|
static void humanize(void)
|
|
|
|
|
{
|
|
|
|
|
xtc_project *p=NULL,*q=NULL;uint64_t t,c,n;xtc_note_info a,b;xtc_midi_transform edit={0};
|
|
|
|
|
assert(xtc_project_create(&p)==XTC_OK && xtc_project_add_track(p,"Track",&t)==XTC_OK);
|
|
|
|
|
assert(xtc_project_add_midi_clip(p,t,0,1920,&c)==XTC_OK && xtc_project_add_note(p,c,480,120,60,100,0,&n)==XTC_OK);
|
|
|
|
|
assert(xtc_project_clone(p,&q)==XTC_OK);
|
|
|
|
|
edit.type=XTC_MIDI_TRANSFORM_HUMANIZE;edit.seed=42;edit.timing_variation=30;edit.velocity_variation=12;
|
|
|
|
|
assert(xtc_project_transform_midi(p,&c,1,&edit)==XTC_OK && xtc_project_transform_midi(q,&c,1,&edit)==XTC_OK);
|
|
|
|
|
assert(xtc_project_get_note(p,0,&a)==XTC_OK && xtc_project_get_note(q,0,&b)==XTC_OK && !memcmp(&a,&b,sizeof(a)));
|
|
|
|
|
assert(a.start_tick>=450 && a.start_tick<=510 && a.velocity>=88 && a.velocity<=112 && a.id==n);
|
|
|
|
|
assert(xtc_project_edit_note(p,n,0,1920,60,100,0)==XTC_OK);edit.timing_variation=960;
|
|
|
|
|
assert(xtc_project_transform_midi(p,&c,1,&edit)==XTC_ERR_INVALID_ARGUMENT);
|
|
|
|
|
assert(xtc_project_get_note(p,0,&a)==XTC_OK && a.start_tick==0 && a.velocity==100);
|
|
|
|
|
xtc_project_destroy(p);xtc_project_destroy(q);
|
|
|
|
|
}
|
2026-11-06 00:40:48 +01:00
|
|
|
static void chords(void)
|
|
|
|
|
{
|
|
|
|
|
xtc_project *p=NULL;uint64_t t,c,n;size_t count;xtc_note_info note;int intervals[2]={4,7};
|
|
|
|
|
assert(xtc_project_create(&p)==XTC_OK && xtc_project_add_track(p,"Track",&t)==XTC_OK);
|
|
|
|
|
assert(xtc_project_add_midi_clip(p,t,0,1920,&c)==XTC_OK && xtc_project_add_note(p,c,480,120,60,100,2,&n)==XTC_OK);
|
|
|
|
|
assert(xtc_project_chordify(p,&c,1,intervals,2)==XTC_OK && xtc_project_note_count(p,&count)==XTC_OK && count==3);
|
|
|
|
|
assert(xtc_project_get_note(p,2,¬e)==XTC_OK && note.pitch==67 && note.start_tick==480 && note.channel==2 && note.id!=n);
|
|
|
|
|
assert(xtc_project_add_note(p,c,0,120,125,100,0,&n)==XTC_OK);
|
|
|
|
|
assert(xtc_project_chordify(p,&c,1,intervals,2)==XTC_ERR_INVALID_ARGUMENT);
|
|
|
|
|
assert(xtc_project_note_count(p,&count)==XTC_OK && count==4);
|
|
|
|
|
intervals[1]=4;assert(xtc_project_chordify(p,&c,1,intervals,2)==XTC_ERR_INVALID_ARGUMENT);
|
|
|
|
|
while(count<XTC_PROJECT_MAX_NOTES){assert(xtc_project_add_note(p,c,0,1,60,100,0,&n)==XTC_OK);++count;}
|
|
|
|
|
intervals[0]=1;assert(xtc_project_chordify(p,&c,1,intervals,1)==XTC_ERR_CAPACITY);
|
|
|
|
|
assert(xtc_project_note_count(p,&count)==XTC_OK && count==XTC_PROJECT_MAX_NOTES);
|
|
|
|
|
xtc_project_destroy(p);
|
|
|
|
|
}
|
2026-11-06 00:42:33 +01:00
|
|
|
static void arpeggio(void)
|
|
|
|
|
{
|
|
|
|
|
xtc_project *p=NULL,*q=NULL;uint64_t t,c,n;size_t count;xtc_note_info note;int intervals[2]={4,7};
|
|
|
|
|
assert(xtc_project_create(&p)==XTC_OK && xtc_project_add_track(p,"Track",&t)==XTC_OK);
|
|
|
|
|
assert(xtc_project_add_midi_clip(p,t,0,960,&c)==XTC_OK && xtc_project_add_note(p,c,0,960,60,100,0,&n)==XTC_OK);
|
|
|
|
|
assert(xtc_project_chordify(p,&c,1,intervals,2)==XTC_OK);
|
|
|
|
|
assert(xtc_project_clone(p,&q)==XTC_OK && xtc_project_arpeggiate(q,&c,1,240,50,1)==XTC_OK);
|
|
|
|
|
assert(xtc_project_get_note(q,0,¬e)==XTC_OK && note.pitch==67);xtc_project_destroy(q);
|
|
|
|
|
assert(xtc_project_arpeggiate(p,&c,1,240,50,0)==XTC_OK);
|
|
|
|
|
assert(xtc_project_note_count(p,&count)==XTC_OK && count==4);
|
|
|
|
|
assert(xtc_project_get_note(p,1,¬e)==XTC_OK && note.start_tick==240 && note.pitch==64 && note.length_tick==120);
|
|
|
|
|
assert(xtc_project_get_note(p,3,¬e)==XTC_OK && note.start_tick==720 && note.pitch==60);
|
|
|
|
|
assert(xtc_project_arpeggiate(p,&c,1,1,100,0)==XTC_OK);
|
|
|
|
|
assert(xtc_project_note_count(p,&count)==XTC_OK && count==480);
|
|
|
|
|
assert(xtc_project_arpeggiate(p,&c,1,0,100,0)==XTC_ERR_INVALID_ARGUMENT);
|
|
|
|
|
xtc_project_destroy(p);p=NULL;
|
|
|
|
|
assert(xtc_project_create(&p)==XTC_OK && xtc_project_add_track(p,"Track",&t)==XTC_OK);
|
|
|
|
|
assert(xtc_project_add_midi_clip(p,t,0,XTC_PROJECT_MAX_TICK,&c)==XTC_OK && xtc_project_add_note(p,c,0,XTC_PROJECT_MAX_TICK,60,100,0,&n)==XTC_OK);
|
|
|
|
|
assert(xtc_project_arpeggiate(p,&c,1,1,100,0)==XTC_ERR_CAPACITY);
|
|
|
|
|
assert(xtc_project_note_count(p,&count)==XTC_OK && count==1);xtc_project_destroy(p);
|
|
|
|
|
}
|
2026-11-06 00:46:14 +01:00
|
|
|
static void normalize(void)
|
|
|
|
|
{
|
|
|
|
|
xtc_project *p=NULL;uint64_t t,ids[2];xtc_clip_info c;char dir[]="/tmp/xtc-normal-XXXXXX",path[512];
|
|
|
|
|
assert(mkdtemp(dir));snprintf(path,sizeof(path),"%s/source.wav",dir);test_wave(path,.5f);
|
|
|
|
|
assert(xtc_project_create(&p)==XTC_OK && xtc_project_add_track(p,"Track",&t)==XTC_OK);
|
|
|
|
|
assert(xtc_project_import_audio(p,t,path,0,&ids[0])==XTC_OK);
|
|
|
|
|
assert(xtc_project_normalize_audio(p,ids,1,.25f)==XTC_OK);
|
|
|
|
|
assert(xtc_project_find_clip(p,ids[0],&c)==XTC_OK && c.gain==.5f);
|
|
|
|
|
assert(xtc_project_edit_clip(p,ids[0],t,0,2,2)==XTC_OK);
|
|
|
|
|
assert(xtc_project_normalize_audio(p,ids,1,.25f)==XTC_OK);
|
|
|
|
|
assert(xtc_project_find_clip(p,ids[0],&c)==XTC_OK && c.gain==1);
|
|
|
|
|
assert(xtc_project_edit_clip(p,ids[0],t,0,8,0)==XTC_OK && xtc_project_set_clip_audio(p,ids[0],.5f,0,0)==XTC_OK);
|
|
|
|
|
assert(xtc_project_add_clip(p,t,"Missing",100,960,&ids[1])==XTC_OK && xtc_project_set_clip_asset(p,ids[1],"/nonexistent/xtc.wav")==XTC_OK);
|
|
|
|
|
assert(xtc_project_normalize_audio(p,ids,2,1)!=XTC_OK);
|
|
|
|
|
assert(xtc_project_find_clip(p,ids[0],&c)==XTC_OK && c.gain==.5f);
|
|
|
|
|
test_wave(path,.001f);assert(xtc_project_normalize_audio(p,ids,1,1)==XTC_ERR_CAPACITY);
|
|
|
|
|
test_wave(path,0);assert(xtc_project_normalize_audio(p,ids,1,1)==XTC_ERR_INVALID_STATE);
|
|
|
|
|
assert(xtc_project_normalize_audio(p,ids,1,NAN)==XTC_ERR_INVALID_ARGUMENT);
|
|
|
|
|
xtc_project_destroy(p);assert(unlink(path)==0 && rmdir(dir)==0);
|
|
|
|
|
}
|
2026-11-06 00:49:37 +01:00
|
|
|
static void collect(void)
|
|
|
|
|
{
|
|
|
|
|
xtc_project *p=NULL,*q=NULL;xtc_audio_plan *audio=NULL;xtc_midi_plan *midi=NULL;xtc_plugin_spec spec;
|
|
|
|
|
uint64_t t,c,n;xtc_clip_info original,loaded;char root[]="/tmp/xtc-collect-XXXXXX",source[512],dest[512],moved[512],project[512],media[512],failed[512];
|
|
|
|
|
assert(mkdtemp(root));snprintf(source,sizeof(source),"%s/source.wav",root);test_wave(source,.5f);
|
|
|
|
|
snprintf(dest,sizeof(dest),"%s/collected",root);snprintf(moved,sizeof(moved),"%s/moved",root);snprintf(failed,sizeof(failed),"%s/failed",root);
|
|
|
|
|
assert(xtc_project_create(&p)==XTC_OK && xtc_project_create(&q)==XTC_OK && xtc_project_add_track(p,"Track",&t)==XTC_OK);
|
|
|
|
|
assert(xtc_project_import_audio(p,t,source,0,&c)==XTC_OK && xtc_project_find_clip(p,c,&original)==XTC_OK);
|
|
|
|
|
assert(xtc_project_add_midi_clip(p,t,960,960,&n)==XTC_OK);
|
|
|
|
|
assert(xtc_plugin_probe_format(XTC_PLUGIN_BUILTIN,XTC_BUILTIN_PATH,4,48000,&spec)==XTC_OK);strcpy(spec.sample_path,source);
|
|
|
|
|
assert(xtc_project_set_instrument(p,t,&spec)==XTC_OK);
|
|
|
|
|
{char large[512];uint64_t extra;FILE *f;
|
|
|
|
|
snprintf(large,sizeof(large),"%s/large.wav",root);f=fopen(large,"wb");assert(f && ftruncate(fileno(f),268435457)==0 && fclose(f)==0);
|
|
|
|
|
assert(xtc_project_add_clip(p,t,"Oversized",1920,960,&extra)==XTC_OK && xtc_project_set_clip_asset(p,extra,large)==XTC_OK);
|
|
|
|
|
assert(xtc_project_collect(p,failed)==XTC_ERR_CAPACITY && access(failed,F_OK)!=0);
|
|
|
|
|
assert(unlink(large)==0 && mkfifo(large,0600)==0);
|
|
|
|
|
assert(xtc_project_collect(p,failed)==XTC_ERR_IO && access(failed,F_OK)!=0);
|
|
|
|
|
assert(xtc_project_remove_clip(p,extra)==XTC_OK && unlink(large)==0);}
|
|
|
|
|
assert(xtc_project_collect(p,dest)==XTC_OK && xtc_project_collect(p,dest)==XTC_ERR_IO);
|
|
|
|
|
assert(xtc_project_find_clip(p,c,&loaded)==XTC_OK && !strcmp(loaded.asset_path,original.asset_path));
|
|
|
|
|
assert(rename(dest,moved)==0 && unlink(source)==0);
|
|
|
|
|
snprintf(project,sizeof(project),"%s/moved/project.xtc",root);snprintf(media,sizeof(media),"%s/moved/media-000.wav",root);
|
|
|
|
|
assert(xtc_project_load(q,project)==XTC_OK && xtc_project_find_clip(q,c,&loaded)==XTC_OK && !strcmp(loaded.asset_path,media));
|
|
|
|
|
assert(xtc_project_get_instrument(q,t,&spec)==XTC_OK && !strcmp(spec.sample_path,media));
|
|
|
|
|
assert(xtc_audio_plan_create(q,48000,&audio)==XTC_OK && xtc_audio_plan_issues(audio,NULL)==0);
|
|
|
|
|
{float sample=0;assert(xtc_audio_plan_render(audio,0,&sample,1)==XTC_OK && fabsf(sample-.5f)<.00001f);}
|
|
|
|
|
assert(xtc_midi_plan_create(q,48000,&midi)==XTC_OK && xtc_midi_plan_asset_issues(midi)==0);
|
|
|
|
|
assert(xtc_project_collect(p,failed)==XTC_ERR_IO && access(failed,F_OK)!=0);
|
|
|
|
|
xtc_audio_plan_destroy(audio);xtc_midi_plan_destroy(midi);xtc_project_destroy(p);xtc_project_destroy(q);
|
|
|
|
|
assert(unlink(project)==0 && unlink(media)==0 && rmdir(moved)==0 && rmdir(root)==0);
|
|
|
|
|
}
|
|
|
|
|
int main(void){markers();sections();ripple();duplicate_track();split_midi();merge_midi();humanize();chords();arpeggio();normalize();collect();puts("Next DAW workflow tests passed.");return 0;}
|