feat: detect and slice audio attacks atomically and qualify sample editor workflows
This commit is contained in:
parent
edeeb8e8bb
commit
9e380d4dd0
20 changed files with 257 additions and 22 deletions
|
|
@ -1,5 +1,6 @@
|
|||
/* Optional documentation tool: real FLTK widgets and real backend, isolated data. */
|
||||
#include "../src/gui/main_window.hpp"
|
||||
#include "../src/gui/sample_editor.hpp"
|
||||
#include "../src/gui/sequencer_widget.hpp"
|
||||
#include "../src/gui/mixer_widget.hpp"
|
||||
#include "../src/gui/piano_roll.hpp"
|
||||
|
|
@ -29,9 +30,10 @@ void pump() {auto end=std::chrono::steady_clock::now()+std::chrono::milliseconds
|
|||
template<class T> T *first(Fl_Group &g) {for(int i=0;i<g.children();++i){auto *c=g.child(i);if(auto *t=dynamic_cast<T *>(c))return t;if(auto *n=dynamic_cast<Fl_Group *>(c))if(auto *t=first<T>(*n))return t;}return nullptr;}
|
||||
Fl_Widget *named(Fl_Group &g,const char *label) {for(int i=0;i<g.children();++i){auto *c=g.child(i);if(c->label()&&!strcmp(c->label(),label))return c;if(auto *n=dynamic_cast<Fl_Group *>(c))if(auto *w=named(*n,label))return w;}return nullptr;}
|
||||
void tab(const char *label) {auto *page=named(*main_window,label);if(!page)throw std::runtime_error(label);auto *tabs=dynamic_cast<Fl_Tabs *>(page->parent());if(!tabs)throw std::runtime_error("Tab parent");tabs->value(page);tabs->redraw();pump();}
|
||||
void capture(const char *name) {Fl::flush();pump();std::string command="import -window root '"+destination+"/"+name+".png'";if(system(command.c_str()))throw std::runtime_error("ImageMagick capture failed");std::printf("Captured %s\n",name);std::fflush(stdout);}
|
||||
void capture(const char *name) {if(std::getenv("XTC_CAPTURE_SAMPLE_ONLY")&&std::strncmp(name,"sample-",7))return;Fl::flush();pump();std::string command="import -window root '"+destination+"/"+name+".png'";if(system(command.c_str()))throw std::runtime_error("ImageMagick capture failed");std::printf("Captured %s\n",name);std::fflush(stdout);}
|
||||
struct Modal {const char *name;const char *page;};
|
||||
void modal_capture(void *data) {auto *job=static_cast<Modal *>(data);auto *w=Fl::modal();if(!w||w==main_window)throw std::runtime_error("Expected a modal dialog");if(job->page){auto *tabs=first<Fl_Tabs>(*w);auto *page=named(*w,job->page);if(!tabs||!page)throw std::runtime_error(job->page);tabs->value(page);tabs->redraw();}capture(job->name);auto *cancel=named(*w,"Cancel");if(!cancel)cancel=named(*w,"Close");if(!cancel)cancel=named(*w,"OK");if(cancel)cancel->do_callback();else w->do_callback();}
|
||||
void modal_capture(void *data) {auto *job=static_cast<Modal *>(data);auto *w=Fl::modal();if(!w||w==main_window)throw std::runtime_error("Expected a modal dialog");if(auto *editor=dynamic_cast<SampleEditor *>(w)){editor->select(2400,std::min(size_t(12000),editor->frames()));if(!strcmp(job->name,"sample-transients")){editor->select(0,editor->frames());check(editor->detect_attacks(.05,2400));}}
|
||||
if(job->page){auto *tabs=first<Fl_Tabs>(*w);auto *page=named(*w,job->page);if(!tabs||!page)throw std::runtime_error(job->page);tabs->value(page);tabs->redraw();}capture(job->name);auto *cancel=named(*w,"Cancel");if(!cancel)cancel=named(*w,"Close");if(!cancel)cancel=named(*w,"OK");if(cancel)cancel->do_callback();else w->do_callback();}
|
||||
void dialog(const char *name,std::function<void()> action,const char *page=nullptr) {Modal job{name,page};Fl::add_timeout(.3,modal_capture,&job);action();Fl::remove_timeout(modal_capture,&job);pump();}
|
||||
void menu(const char *path) {auto *bar=first<Fl_Menu_Bar>(*main_window);const auto *item=bar->find_item(path);if(!item)throw std::runtime_error(path);bar->picked(item);}
|
||||
void piano_view() {
|
||||
|
|
@ -59,6 +61,12 @@ int main(int argc,char **argv) {
|
|||
MainWindow window(false,"");main_window=&window;window.resize(0,0,1400,900);window.show();check(window.open_project(project.c_str()));pump();
|
||||
auto *s=first<SequencerWidget>(window);if(!s)throw std::runtime_error("Sequencer missing");
|
||||
auto reset=[&](){window.reset_layout();check(window.open_project(project.c_str()));window.resize(0,20,1400,900);tab("Sequencer");s->select(0,0);s->position(0);check(window.set_loop(3840,7680,true));window.fit_song();pump();};
|
||||
if(std::getenv("XTC_CAPTURE_SAMPLE_ONLY")) {
|
||||
reset();char source[4096];if(!realpath("examples/projects/original-pluck.wav",source))throw std::runtime_error("Missing sample WAV");
|
||||
check(window.create_track(false));check(window.import_audio(source));
|
||||
dialog("sample-editor",[&]{check(window.open_sample_editor());});dialog("sample-transients",[&]{check(window.open_sample_editor());});
|
||||
window.do_callback();std::puts("Sample-editor captures completed.");return 0;
|
||||
}
|
||||
reset();capture("overview");capture("sequencer-loop");capture("arrangement-markers");
|
||||
s->position(4800);check(window.loop_section());capture("section-navigation");
|
||||
dialog("marker-edit",[&]{s->marker_dialog();});
|
||||
|
|
@ -82,6 +90,7 @@ int main(int argc,char **argv) {
|
|||
window.detach_transport(true);pump();capture("transport-detached");window.detach_mixer(true);pump();capture("workspace-detached");capture("mixer-detached");reset();
|
||||
window.detach_editor(0,true);pump();capture("sequencer-detached");reset();tab("Modular Graph");window.detach_editor(1,true);pump();capture("graph-detached");reset();
|
||||
char wave[4096];if(!realpath("examples/projects/original-pluck.wav",wave))throw std::runtime_error("Missing WAV");check(window.create_track(false));check(window.import_audio(wave));check(s->set_zoom(192));check(s->audio_properties(.8f,240,480));pump();capture("sequencer-audio-waveform");
|
||||
dialog("sample-editor",[&]{check(window.open_sample_editor());});dialog("sample-transients",[&]{check(window.open_sample_editor());});
|
||||
dialog("audio-clip-properties",[&]{s->audio_properties_dialog();});dialog("audio-normalization",[&]{s->normalize_dialog();});check(s->normalize_audio(.25f));capture("audio-normalization-result");
|
||||
dialog("project-collection",[&]{menu("File/Collect project media...");});check(window.collect_project((root+"/portable").c_str()));
|
||||
dialog("loop-range",[&]{button("Loop range...");});dialog("midi-controller-mapping",[&]{menu("Audio/MIDI controller mapping");});dialog("about",[&]{menu("Help/About");});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue