feat(presets): add creative internal effect chain templates (phase 94)
This commit is contained in:
parent
c6f384a623
commit
c65ac61a98
7 changed files with 62 additions and 4 deletions
|
|
@ -35,3 +35,12 @@ copies metadata without affecting undo or loading modules. Recall prepares a
|
|||
fresh chain and is undoable; histories and opaque plugin states are excluded.
|
||||
The two comparison slots clear on successful New/Open. Comparisons stop
|
||||
transport when recalled, following the existing safe insert-edit workflow.
|
||||
|
||||
## Creative starting points
|
||||
|
||||
**Add effect → Templates (replace)** offers Slapback (80 ms delay), Dub Echo
|
||||
(375 ms feedback delay into a short reverb), and Ambient Space (long reverb into
|
||||
500 ms delay). They replace the current chain in one undoable edit and require
|
||||
no external plugins. All controls remain editable. Times are milliseconds;
|
||||
feedback and wet levels are deliberate starting points, without automatic
|
||||
loudness matching or a claim that the presets suit every source.
|
||||
|
|
|
|||
|
|
@ -2118,12 +2118,12 @@ Implemented: two independent track-bound chain comparison slots, with disabled R
|
|||
Offer original dependency-free Slapback, Dub Echo and Ambient Space starting points using internal devices, including safe replacement and editable controls.
|
||||
|
||||
### Tasks and acceptance criteria
|
||||
- [ ] Implement the workflow with bounded validation, safe preparation and documented limits.
|
||||
- [ ] Pass meaningful core and/or GUI checks, including error and undo behavior.
|
||||
- [ ] Document results and commit this phase separately.
|
||||
- [x] Implement the workflow with bounded validation, safe preparation and documented limits.
|
||||
- [x] Pass meaningful core and/or GUI checks, including error and undo behavior.
|
||||
- [x] Document results and commit this phase separately.
|
||||
|
||||
### Implementation status
|
||||
Planned.
|
||||
Implemented: Slapback, Dub Echo and Ambient Space templates use original internal Delay/Reverb configurations with editable controls and explicit chain replacement. C99 generation validates tempo/index, preserves errors and loads no external modules. All templates compile/render finite nonzero output; GUI template adoption and undo checks passed.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,11 @@ typedef struct { xtc_plugin_spec plugin; unsigned int enabled; float wet; } xtc_
|
|||
typedef struct { size_t count; float output_gain; xtc_track_insert slots[XTC_TRACK_INSERTS]; } xtc_track_chain;
|
||||
/* Copies the selected slot immediately after itself, preserving all metadata.
|
||||
* Input/output may alias; errors preserve output. */
|
||||
/* Original internal-device starting points: 0 Slapback, 1 Dub Echo,
|
||||
* 2 Ambient Space. Name returns NULL for an unknown index. No modules opened;
|
||||
* template errors preserve out. Delay times are milliseconds, not beat sync. */
|
||||
const char *xtc_track_chain_template_name(unsigned int index);
|
||||
xtc_result xtc_track_chain_template(unsigned int index,unsigned int tempo,xtc_track_chain *out);
|
||||
xtc_result xtc_track_chain_duplicate(const xtc_track_chain *chain,size_t index,xtc_track_chain *out);
|
||||
xtc_result xtc_track_chain_preset_save(const xtc_track_chain *chain,const char *path);
|
||||
xtc_result xtc_track_chain_preset_load(const char *path,xtc_track_chain *out);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@ class TrackInsertsPanel : public Fl_Group {
|
|||
add->add("Internal Delay",0,[](Fl_Widget *,void *c){static_cast<TrackInsertsPanel *>(c)->add(XTC_BUILTIN_PATH,2);},this);
|
||||
add->add("Internal Reverb",0,[](Fl_Widget *,void *c){static_cast<TrackInsertsPanel *>(c)->add(XTC_BUILTIN_PATH,3);},this);
|
||||
add->add("Plugin library...",0,[](Fl_Widget *,void *c){auto *p=static_cast<TrackInsertsPanel *>(c);std::string file;if(!xtc_choose_plugin_file(p->owner_->settings(),file))return;unsigned int index=0;if(xtc_choose_plugin(file.c_str(),p->owner_->sample_rate(),index))p->add(file.c_str(),index);},this);
|
||||
for(unsigned int preset=0;preset<3;++preset) {
|
||||
std::string label=std::string("Templates (replace)/")+xtc_track_chain_template_name(preset);
|
||||
add->add(label.c_str(),0,[](Fl_Widget *w,void *c){auto *p=static_cast<TrackInsertsPanel *>(c);auto *menu=static_cast<Fl_Menu_Button *>(w);unsigned int index=0;for(;index<3;++index)if(!strcmp(menu->mvalue()->label(),xtc_track_chain_template_name(index)))break;p->result(p->apply_template(index));},this);
|
||||
}
|
||||
struct Action {const char *name;int command;};
|
||||
int left=x+486;
|
||||
for(const auto &action:{Action{"Up",-1},Action{"Down",1},Action{"Bypass",2},Action{"Remove",3}}) {
|
||||
|
|
@ -73,6 +77,11 @@ class TrackInsertsPanel : public Fl_Group {
|
|||
void select_track(uint64_t id) {track_=id;refresh(true);}
|
||||
const xtc_graph *graph() const {return model_;}
|
||||
void add(const char *file,unsigned int index) { result(owner_->add_track_effect(track_,file,index)); }
|
||||
xtc_result apply_template(unsigned int index) {
|
||||
xtc_track_chain chain{};auto r=xtc_track_chain_template(index,xtc_project_tempo(owner_->project_.get()),&chain);
|
||||
if(r==XTC_OK)r=owner_->set_track_chain(track_,chain);
|
||||
return r;
|
||||
}
|
||||
void clear_session() {clipboard_={};clipboard_ready_=false;for(auto &slot:comparisons_)slot=Comparison{};update_actions();}
|
||||
bool clipboard_ready() const {return clipboard_ready_;}
|
||||
bool comparison_ready(unsigned int slot) const {return slot<2 && comparisons_[slot].ready && comparisons_[slot].track==track_;}
|
||||
|
|
|
|||
|
|
@ -9,3 +9,25 @@ xtc_result xtc_track_chain_duplicate(const xtc_track_chain *chain,size_t index,x
|
|||
for(i=copy.count;i>index+1;--i)copy.slots[i]=copy.slots[i-1];
|
||||
copy.slots[index+1]=copy.slots[index];++copy.count;*out=copy;return XTC_OK;
|
||||
}
|
||||
|
||||
const char *xtc_track_chain_template_name(unsigned int index)
|
||||
{
|
||||
static const char *names[]={"Slapback","Dub Echo","Ambient Space"};
|
||||
return index<3 ? names[index] : NULL;
|
||||
}
|
||||
xtc_result xtc_track_chain_template(unsigned int index,unsigned int tempo,xtc_track_chain *out)
|
||||
{
|
||||
xtc_track_chain c={0};size_t i;xtc_result r=XTC_OK;
|
||||
if(!out || index>=3 || tempo<20000 || tempo>300000)return XTC_ERR_INVALID_ARGUMENT;
|
||||
c.output_gain=index ? .8f : 1;c.count=index ? 2 : 1;
|
||||
for(i=0;r==XTC_OK && i<c.count;++i) {
|
||||
unsigned int device=index==2 ? (i ? 2U : 3U) : (i ? 3U : 2U);
|
||||
r=xtc_plugin_probe_format(XTC_PLUGIN_BUILTIN,XTC_BUILTIN_PATH,device,48000,&c.slots[i].plugin);
|
||||
c.slots[i].enabled=1;c.slots[i].wet=1;c.slots[i].plugin.tempo=tempo;
|
||||
}
|
||||
if(r!=XTC_OK)return r;
|
||||
if(index==0){c.slots[0].plugin.values[0]=80;c.slots[0].plugin.values[1]=.1f;c.slots[0].plugin.values[2]=.3f;}
|
||||
if(index==1){c.slots[0].plugin.values[0]=375;c.slots[0].plugin.values[1]=.65f;c.slots[0].plugin.values[2]=.4f;c.slots[1].plugin.values[0]=.55f;c.slots[1].plugin.values[1]=.5f;c.slots[1].plugin.values[2]=.15f;}
|
||||
if(index==2){c.slots[0].plugin.values[0]=.88f;c.slots[0].plugin.values[1]=.6f;c.slots[0].plugin.values[2]=.6f;c.slots[1].plugin.values[0]=500;c.slots[1].plugin.values[1]=.35f;c.slots[1].plugin.values[2]=.25f;}
|
||||
r=xtc_track_chain_validate(&c);if(r==XTC_OK)*out=c;return r;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -247,6 +247,9 @@ int creative_workflow_tests()
|
|||
CHECK(window.undo()==XTC_OK);panel->refresh(true);
|
||||
CHECK(xtc_project_get_chain(s->project(),first_track,&chain)==XTC_OK && chain.output_gain==.6f);
|
||||
panel->select_track(second_track);CHECK(!panel->comparison_ready(0) && panel->comparison(0,false)==XTC_ERR_NOT_FOUND);
|
||||
CHECK(panel->apply_template(1)==XTC_OK);
|
||||
CHECK(xtc_project_get_chain(s->project(),second_track,&chain)==XTC_OK && chain.count==2 && chain.slots[0].plugin.values[0]==375);
|
||||
CHECK(window.undo()==XTC_OK);panel->refresh(true);CHECK(xtc_project_get_chain(s->project(),second_track,&chain)==XTC_OK && chain.count==0);
|
||||
CHECK(window.new_project()==XTC_OK && !panel->clipboard_ready() && panel->paste_chain()==XTC_ERR_NOT_FOUND);
|
||||
CHECK(!panel->comparison_ready(0) && !panel->comparison_ready(1));
|
||||
window.do_callback();puts("Creative workflow GUI checks passed.");return failures ? 1 : 0;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
int main(void)
|
||||
{
|
||||
xtc_track_chain c={0},out={0};
|
||||
|
|
@ -15,5 +16,14 @@ int main(void)
|
|||
for(size_t i=3;i<XTC_TRACK_INSERTS;++i)out.slots[i]=out.slots[0];
|
||||
out.count=XTC_TRACK_INSERTS;c=out;
|
||||
assert(xtc_track_chain_duplicate(&out,0,&out)==XTC_ERR_CAPACITY && !memcmp(&c,&out,sizeof(c)));
|
||||
for(unsigned int preset=0;preset<3;++preset) {
|
||||
xtc_graph *g=NULL;xtc_plan *plan=NULL;float input[512]={1},output[512];double energy=0;
|
||||
assert(xtc_track_chain_template_name(preset) && xtc_track_chain_template(preset,135000,&c)==XTC_OK && xtc_track_chain_validate(&c)==XTC_OK);
|
||||
assert(c.slots[0].plugin.tempo==135000 && xtc_track_chain_graph(&c,&g)==XTC_OK && xtc_graph_compile(g,8000,512,&plan)==XTC_OK);
|
||||
assert(xtc_plan_process(plan,input,output,512)==XTC_OK);
|
||||
for(size_t i=0;i<512;++i){assert(isfinite(output[i]));energy+=output[i]*output[i];}assert(energy>0);
|
||||
xtc_plan_destroy(plan);xtc_graph_destroy(g);
|
||||
}
|
||||
out=c;assert(!xtc_track_chain_template_name(3) && xtc_track_chain_template(3,120000,&c)==XTC_ERR_INVALID_ARGUMENT && !memcmp(&out,&c,sizeof(c)));
|
||||
puts("Creative editing core checks passed.");return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue