xtc/src/mixer/track_fx.c

101 lines
4.6 KiB
C
Raw Normal View History

#include "track_fx.h"
#include "../project/project_internal.h"
#include "xtc/xtc_dsp.h"
#include <stdlib.h>
#include <string.h>
struct xtc_track_fx {
xtc_plan *plans[XTC_PROJECT_MAX_TRACKS];
float *raw[XTC_PROJECT_MAX_TRACKS];
uint64_t next;
float scratch[256];
};
/* Public metadata graph: the graph displayed by the editor is also compiled. */
xtc_result xtc_track_chain_graph(const xtc_track_chain *c,xtc_graph **out)
{
xtc_graph *g=NULL;size_t previous=0,output=0,i;xtc_result r;
if(!out || xtc_track_chain_validate(c)!=XTC_OK)return XTC_ERR_INVALID_ARGUMENT;
r=xtc_graph_create(64,&g);
if(r==XTC_OK)r=xtc_graph_add_gain(g,1,&previous);
for(i=0;r==XTC_OK && i<c->count;++i) {
const xtc_track_insert *s=c->slots+i;size_t plugin=0,wet=0,dry=0,sum=0;
if(!s->enabled || s->wet==0)continue;
r=xtc_graph_add_plugin(g,&s->plugin,&plugin);
if(r==XTC_OK)r=xtc_graph_connect(g,previous,plugin);
if(s->wet==1){previous=plugin;continue;}
if(r==XTC_OK)r=xtc_graph_add_gain(g,s->wet,&wet);
if(r==XTC_OK)r=xtc_graph_add_gain(g,1-s->wet,&dry);
if(r==XTC_OK)r=xtc_graph_add_gain(g,1,&sum);
if(r==XTC_OK)r=xtc_graph_connect(g,plugin,wet);
if(r==XTC_OK)r=xtc_graph_connect(g,previous,dry);
if(r==XTC_OK)r=xtc_graph_connect(g,wet,sum);
if(r==XTC_OK)r=xtc_graph_connect(g,dry,sum);
previous=sum;
}
if(r==XTC_OK)r=xtc_graph_add_gain(g,c->output_gain,&output);
if(r==XTC_OK)r=xtc_graph_connect(g,previous,output);
previous=output;
if(r==XTC_OK)r=xtc_graph_add_output(g,&output);
if(r==XTC_OK)r=xtc_graph_connect(g,previous,output);
if(r!=XTC_OK){xtc_graph_destroy(g);return r;}
*out=g;return XTC_OK;
}
void xtc_track_fx_destroy(xtc_track_fx *f)
{
size_t i;if(!f)return;
for(i=0;i<XTC_PROJECT_MAX_TRACKS;++i){xtc_plan_destroy(f->plans[i]);free(f->raw[i]);}
free(f);
}
xtc_result xtc_track_fx_create(const xtc_project *p,unsigned int rate,int midi,xtc_track_fx **out)
{
size_t i,j;xtc_track_fx *f=NULL;xtc_result r=XTC_OK;int needed=0;
if(!p || !out || !rate)return XTC_ERR_INVALID_ARGUMENT;
*out=NULL;
for(i=0;i<p->track_count;++i)if(p->chains[i].count || p->chains[i].output_gain!=1)needed=1;
if(!needed)return XTC_OK;
f=calloc(1,sizeof(*f));if(!f)return XTC_ERR_OUT_OF_MEMORY;f->next=UINT64_MAX;
for(i=0;r==XTC_OK && i<p->track_count;++i) {
const xtc_track_chain *c=p->chains+i;xtc_graph *g=NULL;
int has_midi=p->instruments[i].instrument || p->live_instrument==p->tracks[i].id,has_audio=0;
if(!c->count && c->output_gain==1)continue;
for(j=0;j<p->clip_count;++j)if(p->clips[j].track_id==p->tracks[i].id) {
if(p->clips[j].midi)has_midi=1;else if(p->clips[j].asset_path[0])has_audio=1;
}
if(p->tracks[i].is_bus || (has_midi && has_audio)){r=XTC_ERR_UNSUPPORTED;break;}
if(has_midi!=midi)continue;
r=xtc_track_chain_graph(c,&g);
if(r==XTC_OK)r=xtc_graph_compile(g,rate,256,&f->plans[i]);
xtc_graph_destroy(g);
if(r==XTC_OK){f->raw[i]=calloc(65536,sizeof(float));if(!f->raw[i])r=XTC_ERR_OUT_OF_MEMORY;}
}
if(r!=XTC_OK){xtc_track_fx_destroy(f);return r;}
*out=f;return XTC_OK;
}
void xtc_track_fx_begin(xtc_track_fx *f,uint64_t position,size_t frames)
{
size_t i;if(!f)return;
for(i=0;i<XTC_PROJECT_MAX_TRACKS;++i)if(f->raw[i]) {
memset(f->raw[i],0,frames*sizeof(float));
if(f->next!=position)xtc_plan_reset_history(f->plans[i]);
}
}
int xtc_track_fx_add(xtc_track_fx *f,size_t track,size_t frame,float sample)
{
if(!f || track>=XTC_PROJECT_MAX_TRACKS || !f->raw[track] || frame>=65536)return 0;
f->raw[track][frame]+=sample;return 1;
}
xtc_result xtc_track_fx_finish(xtc_track_fx *f,const xtc_mix_snapshot *mix,uint64_t position,float *left,float *right,size_t frames,float *monitor,size_t stride)
{
size_t i,offset,j;if(!f)return XTC_OK;
for(i=0;i<mix->count;++i)if(f->raw[i])for(offset=0;offset<frames;offset+=256) {
size_t n=frames-offset<256 ? frames-offset : 256;xtc_result r=xtc_plan_position(f->plans[i],position+offset);
if(r==XTC_OK)r=xtc_plan_process(f->plans[i],f->raw[i]+offset,f->scratch,n);
if(r!=XTC_OK)return r;
for(j=0;j<n;++j) {
size_t frame=offset+j;float sample=xtc_dsp_finite(f->scratch[j]);
if(monitor)xtc_mix_monitor(mix,monitor,stride,i,position+frame,frame,sample,right!=NULL);
left[frame]+=sample*xtc_mix_level(mix,i,position+frame,right ? 0U : 2U);
if(right)right[frame]+=sample*xtc_mix_level(mix,i,position+frame,1);
}
}
f->next=position+frames;return XTC_OK;
}