feat(plugins): search and filter the installed plugin library (phase 84)
This commit is contained in:
parent
e3c27d6aae
commit
2ecc9df343
4 changed files with 57 additions and 26 deletions
|
|
@ -1940,12 +1940,12 @@ Implemented: Ctrl+4 opens the track insert rack and actual generated modular gra
|
|||
Make LADSPA, VST2, VST3 and CLAP effects easy to find and add, including Linux VST3 bundles, format filters and clear compatibility errors.
|
||||
|
||||
### Tasks and acceptance criteria
|
||||
- [ ] Implement the described workflow with validated errors and safe ownership.
|
||||
- [ ] Pass relevant core and/or GUI tests.
|
||||
- [ ] Document behavior and limitations; commit this phase separately.
|
||||
- [x] Implement the described workflow with validated errors and safe ownership.
|
||||
- [x] Pass relevant core and/or GUI tests.
|
||||
- [x] Document behavior and limitations; commit this phase separately.
|
||||
|
||||
### Implementation status
|
||||
Planned.
|
||||
Implemented: case-insensitive path/name search and All/LADSPA/VST2/VST3/CLAP filters in the shared plugin library, with recursive Linux VST3 bundle discovery, deduplication and bounded traversal. Listing executes no module code; inspection checks ABI/layout. Ambiguous .so candidates appear in both LADSPA and VST2 filters. Warning-enabled GUI build and focused discovery-filter/adoption tests passed.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -34,3 +34,8 @@ the graph displays the actual generated graph compiled by playback. Wiring in
|
|||
this view is read-only: edit the rack to preserve the serial chain. The global
|
||||
Modular Graph remains independent. A failed plugin probe or playback preparation
|
||||
preserves the current project; successful additions are undoable.
|
||||
|
||||
The library searches configured Preferences paths recursively (including VST3
|
||||
bundle contents), with case-insensitive search and format filters. LADSPA and
|
||||
VST2 both use `.so`, so those filters share candidates until inspection identifies
|
||||
the ABI. Listing files executes no plugin code. Only inspect trusted binaries.
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@
|
|||
#include <FL/Fl_Double_Window.H>
|
||||
#include <FL/Fl_Hold_Browser.H>
|
||||
#include <FL/Fl_Box.H>
|
||||
#include <FL/Fl_Input.H>
|
||||
#include <FL/Fl_Choice.H>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <FL/Fl_Native_File_Chooser.H>
|
||||
#include <filesystem>
|
||||
#include <set>
|
||||
|
|
@ -42,33 +46,50 @@ inline std::vector<std::string> xtc_plugin_files(const xtc_settings &settings)
|
|||
}
|
||||
return {files.begin(),files.end()};
|
||||
}
|
||||
/* Paths are a discovery hint, never a compatibility claim. Ambiguous .so files
|
||||
* remain visible under both LADSPA and VST2; probing identifies the real ABI. */
|
||||
inline bool xtc_plugin_file_matches(const std::string &file,const std::string &query,int format)
|
||||
{
|
||||
auto lower=[](std::string value){for(char &c:value)c=static_cast<char>(std::tolower(static_cast<unsigned char>(c)));return value;};
|
||||
const auto name=lower(file);bool vst3=name.find(".vst3/")!=std::string::npos;
|
||||
bool clap=std::filesystem::path(name).extension()==".clap";
|
||||
if(format==3 && !vst3)return false;
|
||||
if(format==4 && !clap)return false;
|
||||
if((format==1 || format==2) && (vst3 || clap))return false;
|
||||
return name.find(lower(query))!=std::string::npos;
|
||||
}
|
||||
inline bool xtc_choose_plugin_file(const xtc_settings &settings,std::string &path)
|
||||
{
|
||||
struct Library : Fl_Double_Window {
|
||||
bool accepted=false,browse=false;
|
||||
Library():Fl_Double_Window(900,520,"Plugin library — trusted binaries") {set_modal();}
|
||||
} dialog;
|
||||
auto files=xtc_plugin_files(settings);
|
||||
auto *hint=new Fl_Box(16,10,868,44,"Files from Preferences search paths. Select a trusted binary to inspect its plugins.\nNo module code is executed while listing. Browse can select another binary.");
|
||||
hint->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
|
||||
auto *list=new Fl_Hold_Browser(16,62,868,370); list->format_char(0);
|
||||
for(const auto &file:files) list->add(file.c_str());
|
||||
if(!files.empty()) list->select(1);
|
||||
auto *browse=new Fl_Button(16,462,130,32,"Browse files...");
|
||||
browse->callback([](Fl_Widget *,void *c){auto *d=static_cast<Library *>(c);d->browse=true;d->hide();},&dialog);
|
||||
auto *cancel=new Fl_Button(650,462,100,32,"Cancel");
|
||||
cancel->callback([](Fl_Widget *,void *c){static_cast<Library *>(c)->hide();},&dialog);
|
||||
auto *choose=new Fl_Button(764,462,120,32,"Inspect plugin");
|
||||
choose->callback([](Fl_Widget *,void *c){auto *d=static_cast<Library *>(c);d->accepted=true;d->hide();},&dialog);
|
||||
if(files.empty()) choose->deactivate();
|
||||
dialog.callback([](Fl_Widget *,void *c){static_cast<Library *>(c)->hide();},&dialog);
|
||||
dialog.end(); xtc_ui::style(&dialog); dialog.show(); while(dialog.shown()) Fl::wait();
|
||||
Fl_Input *search;Fl_Choice *format;Fl_Hold_Browser *list;
|
||||
Fl_Button *choose;std::vector<std::string> files,visible;
|
||||
explicit Library(const xtc_settings &settings):Fl_Double_Window(900,560,"Plugin library — effects and instruments"),files(xtc_plugin_files(settings)) {
|
||||
set_modal();
|
||||
auto *hint=new Fl_Box(16,8,868,42,"Search installed binaries; VST3 bundles are discovered recursively. Modules load only when inspected.\nLADSPA/VST2 share .so candidates; inspection verifies the format and compatible mono layout.");hint->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
|
||||
search=new Fl_Input(78,60,510,28,"Search");search->when(FL_WHEN_CHANGED);
|
||||
format=new Fl_Choice(666,60,218,28,"Format");format->add("All formats|LADSPA|VST2|VST3|CLAP");format->value(0);
|
||||
for(auto *w:{static_cast<Fl_Widget *>(search),static_cast<Fl_Widget *>(format)})w->callback([](Fl_Widget *,void *c){static_cast<Library *>(c)->filter();},this);
|
||||
list=new Fl_Hold_Browser(16,102,868,370);list->format_char(0);
|
||||
auto *browse_button=new Fl_Button(16,506,130,32,"Browse files...");browse_button->callback([](Fl_Widget *,void *c){auto *d=static_cast<Library *>(c);d->browse=true;d->hide();},this);
|
||||
auto *cancel=new Fl_Button(650,506,100,32,"Cancel");cancel->callback([](Fl_Widget *,void *c){static_cast<Library *>(c)->hide();},this);
|
||||
choose=new Fl_Button(764,506,120,32,"Inspect plugin");choose->callback([](Fl_Widget *,void *c){auto *d=static_cast<Library *>(c);d->accepted=true;d->hide();},this);
|
||||
callback([](Fl_Widget *,void *c){static_cast<Library *>(c)->hide();},this);
|
||||
end();filter();xtc_ui::style(this);
|
||||
}
|
||||
void filter() {
|
||||
list->clear();visible.clear();
|
||||
for(const auto &file:files)if(xtc_plugin_file_matches(file,search->value(),format->value())){visible.push_back(file);list->add(file.c_str());}
|
||||
if(visible.empty())choose->deactivate();else{choose->activate();list->select(1);}
|
||||
}
|
||||
} dialog(settings);
|
||||
dialog.show();while(dialog.shown())Fl::wait();
|
||||
if(dialog.browse) {
|
||||
Fl_Native_File_Chooser chooser; chooser.title("Choose trusted plugin binary"); chooser.filter("Plugin binaries\t*.{so,clap}\nAll files\t*");
|
||||
if(chooser.show()!=0 || !chooser.filename()) return false;
|
||||
path=chooser.filename(); return true;
|
||||
Fl_Native_File_Chooser chooser;chooser.title("Choose trusted plugin binary");chooser.filter("Plugin binaries\t*.{so,clap}\nAll files\t*");
|
||||
if(chooser.show()!=0 || !chooser.filename())return false;
|
||||
path=chooser.filename();return true;
|
||||
}
|
||||
if(!dialog.accepted || list->value()<1) return false;
|
||||
path=files[static_cast<size_t>(list->value()-1)]; return true;
|
||||
if(!dialog.accepted || dialog.list->value()<1)return false;
|
||||
path=dialog.visible[static_cast<size_t>(dialog.list->value()-1)];return true;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -218,6 +218,11 @@ static int sample_editor_tests()
|
|||
}
|
||||
int track_insert_tests()
|
||||
{
|
||||
CHECK(xtc_plugin_file_matches("/usr/lib/vst3/ZamEQ2.vst3/Contents/x86_64-linux/ZamEQ2.so","zameq",3));
|
||||
CHECK(!xtc_plugin_file_matches("/usr/lib/vst3/ZamEQ2.vst3/Contents/x86_64-linux/ZamEQ2.so","zameq",4));
|
||||
CHECK(xtc_plugin_file_matches("/usr/lib/clap/room.clap","ROOM",4));
|
||||
CHECK(xtc_plugin_file_matches("/usr/lib/ladspa/gain.so","gain",1) && xtc_plugin_file_matches("/usr/lib/vst/gain.so","gain",2));
|
||||
CHECK(!xtc_plugin_file_matches("/usr/lib/vst/gain.so","absent",0));
|
||||
reset();MainWindow window(false,"");window.show();pump();auto *s=timeline(&window);
|
||||
CHECK(window.create_track(false)==XTC_OK);auto track=s->selected_track();auto *panel=window.track_inserts();CHECK(panel);
|
||||
panel->select_track(track);CHECK(panel->selected_track()==track && panel->graph());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue