feat(inserts): add bulk enable, bypass and clear actions (phase 95)
This commit is contained in:
parent
c65ac61a98
commit
924821738d
7 changed files with 48 additions and 6 deletions
|
|
@ -44,3 +44,11 @@ transport when recalled, following the existing safe insert-edit workflow.
|
|||
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.
|
||||
|
||||
## Bulk rack actions
|
||||
|
||||
**Enable all effects**, **Bypass all effects**, and **Clear chain** each prepare
|
||||
one undoable edit. Enabling all intentionally enables every slot, including
|
||||
previously bypassed effects; Undo restores the previous mixed bypass state.
|
||||
Clear removes slots while preserving chain output gain. No plugin resources
|
||||
are released in the audio callback. Empty racks return a no-result error.
|
||||
|
|
|
|||
|
|
@ -2133,12 +2133,12 @@ Implemented: Slapback, Dub Echo and Ambient Space templates use original interna
|
|||
Enable all inserts, bypass all inserts or clear a chain as single undoable prepared edits, retaining output gain and respecting recording/error restrictions.
|
||||
|
||||
### 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: bounded C99 enable-all, bypass-all and clear transforms preserve output gain and support in-place metadata use. Rack actions prepare one undoable replacement; failed enable preparation preserves the old chain. Core metadata/invalid-action checks and GUI bypass/enable/clear/undo/rollback checks passed.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -36,14 +36,18 @@ typedef struct {
|
|||
#define XTC_TRACK_INSERTS 8U
|
||||
typedef struct { xtc_plugin_spec plugin; unsigned int enabled; float wet; } xtc_track_insert;
|
||||
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);
|
||||
/* Copies the selected slot immediately after itself, preserving all metadata.
|
||||
* Input/output may alias; errors preserve output. */
|
||||
xtc_result xtc_track_chain_duplicate(const xtc_track_chain *chain,size_t index,xtc_track_chain *out);
|
||||
/* Pure metadata operations, preserving output gain; aliases accepted and errors
|
||||
* preserve out. Enabling missing plugins can fail later at plan preparation. */
|
||||
typedef enum {XTC_CHAIN_ENABLE_ALL,XTC_CHAIN_BYPASS_ALL,XTC_CHAIN_CLEAR} xtc_chain_action;
|
||||
xtc_result xtc_track_chain_bulk(const xtc_track_chain *chain,xtc_chain_action action,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);
|
||||
/* Metadata only; control thread. Empty chain has unity output. No module is
|
||||
|
|
|
|||
|
|
@ -58,6 +58,9 @@ class TrackInsertsPanel : public Fl_Group {
|
|||
gain_=new Fl_Value_Input(x+360,y+52,100,26,"Chain gain");gain_->bounds(0,4);gain_->step(.01);gain_->when(FL_WHEN_RELEASE);
|
||||
for(auto *input:{wet_,gain_})input->callback([](Fl_Widget *,void *c){auto *p=static_cast<TrackInsertsPanel *>(c);p->result(p->set_mix(p->wet_->value(),p->gain_->value()));},this);
|
||||
actions_=new Fl_Menu_Button(x+486,y+52,150,26,"Rack actions");
|
||||
actions_->add("Enable all effects",0,[](Fl_Widget *,void *c){auto *p=static_cast<TrackInsertsPanel *>(c);p->result(p->bulk(XTC_CHAIN_ENABLE_ALL));},this);
|
||||
actions_->add("Bypass all effects",0,[](Fl_Widget *,void *c){auto *p=static_cast<TrackInsertsPanel *>(c);p->result(p->bulk(XTC_CHAIN_BYPASS_ALL));},this);
|
||||
actions_->add("Clear chain",0,[](Fl_Widget *,void *c){auto *p=static_cast<TrackInsertsPanel *>(c);p->result(p->bulk(XTC_CHAIN_CLEAR));},this);
|
||||
actions_->add("Compare/Capture A",0,[](Fl_Widget *,void *c){auto *p=static_cast<TrackInsertsPanel *>(c);p->result(p->comparison(0,true));},this);
|
||||
actions_->add("Compare/Recall A",0,[](Fl_Widget *,void *c){auto *p=static_cast<TrackInsertsPanel *>(c);p->result(p->comparison(0,false));},this,FL_MENU_INACTIVE);
|
||||
actions_->add("Compare/Capture B",0,[](Fl_Widget *,void *c){auto *p=static_cast<TrackInsertsPanel *>(c);p->result(p->comparison(1,true));},this);
|
||||
|
|
@ -77,6 +80,12 @@ 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 bulk(xtc_chain_action action) {
|
||||
xtc_track_chain chain{};auto r=xtc_project_get_chain(owner_->project_.get(),track_,&chain);
|
||||
if(r==XTC_OK && !chain.count)return XTC_ERR_NOT_FOUND;
|
||||
if(r==XTC_OK)r=xtc_track_chain_bulk(&chain,action,&chain);
|
||||
return r==XTC_OK ? owner_->set_track_chain(track_,chain) : r;
|
||||
}
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -31,3 +31,13 @@ xtc_result xtc_track_chain_template(unsigned int index,unsigned int tempo,xtc_tr
|
|||
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;
|
||||
}
|
||||
|
||||
xtc_result xtc_track_chain_bulk(const xtc_track_chain *chain,xtc_chain_action action,xtc_track_chain *out)
|
||||
{
|
||||
xtc_track_chain copy;size_t i;
|
||||
if(!out || xtc_track_chain_validate(chain)!=XTC_OK || action<XTC_CHAIN_ENABLE_ALL || action>XTC_CHAIN_CLEAR)return XTC_ERR_INVALID_ARGUMENT;
|
||||
copy=*chain;
|
||||
if(action==XTC_CHAIN_CLEAR){copy.count=0;for(i=0;i<XTC_TRACK_INSERTS;++i)copy.slots[i]=(xtc_track_insert){0};}
|
||||
else for(i=0;i<copy.count;++i)copy.slots[i].enabled=action==XTC_CHAIN_ENABLE_ALL;
|
||||
*out=copy;return XTC_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -250,6 +250,12 @@ int creative_workflow_tests()
|
|||
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(panel->apply_template(1)==XTC_OK && panel->bulk(XTC_CHAIN_BYPASS_ALL)==XTC_OK);
|
||||
CHECK(xtc_project_get_chain(s->project(),second_track,&chain)==XTC_OK && !chain.slots[0].enabled && !chain.slots[1].enabled);
|
||||
submit_result=XTC_ERR_INVALID_STATE;unchanged=s->project();CHECK(panel->bulk(XTC_CHAIN_ENABLE_ALL)==XTC_ERR_INVALID_STATE && s->project()==unchanged);submit_result=XTC_OK;
|
||||
CHECK(panel->bulk(XTC_CHAIN_ENABLE_ALL)==XTC_OK && panel->bulk(XTC_CHAIN_CLEAR)==XTC_OK);
|
||||
CHECK(xtc_project_get_chain(s->project(),second_track,&chain)==XTC_OK && chain.count==0 && chain.output_gain==.8f);
|
||||
CHECK(window.undo()==XTC_OK);panel->refresh(true);CHECK(xtc_project_get_chain(s->project(),second_track,&chain)==XTC_OK && chain.count==2);
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -25,5 +25,10 @@ int main(void)
|
|||
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)));
|
||||
assert(xtc_track_chain_template(1,120000,&c)==XTC_OK);
|
||||
assert(xtc_track_chain_bulk(&c,XTC_CHAIN_BYPASS_ALL,&c)==XTC_OK && !c.slots[0].enabled && !c.slots[1].enabled && c.output_gain==.8f);
|
||||
assert(xtc_track_chain_bulk(&c,XTC_CHAIN_ENABLE_ALL,&c)==XTC_OK && c.slots[0].enabled && c.slots[1].enabled);
|
||||
out=c;assert(xtc_track_chain_bulk(&c,(xtc_chain_action)99,&c)==XTC_ERR_INVALID_ARGUMENT && !memcmp(&c,&out,sizeof(c)));
|
||||
assert(xtc_track_chain_bulk(&c,XTC_CHAIN_CLEAR,&c)==XTC_OK && c.count==0 && c.output_gain==.8f && !c.slots[0].plugin.path[0]);
|
||||
puts("Creative editing core checks passed.");return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue