diff --git a/Makefile b/Makefile index fc85366..04d08ce 100644 --- a/Makefile +++ b/Makefile @@ -554,3 +554,13 @@ test-next-daw: $(BUILD_DIR)/test_next_daw test: test-next-daw test-gui-next-daw: $(BUILD_DIR)/test_gui XTC_TEST_MODERN_EDITING_ONLY=1 XTC_TEST_NEXT_DAW_ONLY=1 xvfb-run -a -s "-screen 0 1280x800x24" ./$(BUILD_DIR)/test_gui + +# Optional documentation capture; requires Xvfb, ImageMagick import and xdotool. +$(BUILD_DIR)/capture_screenshots: $(BUILD_DIR)/tools/capture_screenshots.o $(BUILD_DIR)/src/gui/main_window.o $(BUILD_DIR)/src/gui/graph_widget.o $(BUILD_DIR)/src/gui/sequencer_widget.o $(BUILD_DIR)/src/gui/piano_roll.o $(BUILD_DIR)/src/gui/mixer_widget.o $(BUILD_DIR)/src/gui/plugin_dialog.o $(BUILD_DIR)/libxtc.a + $(CXX) $(LDFLAGS) -o $@ $^ $(FLTK_LIBS) $(JACK_LIBS) -lm -ldl + +.PHONY: screenshots +screenshots: $(BUILD_DIR)/capture_screenshots $(BUILD_DIR)/plugin-fixture.so $(BUILD_DIR)/clap-synth-fixture.clap $(BUILD_DIR)/vst2-synth-fixture.so $(BUILD_DIR)/vst3-synth-fixture.so + xvfb-run -a -s "-screen 0 1440x960x24" ./$(BUILD_DIR)/capture_screenshots "$(CURDIR)/screenshots" + +-include $(BUILD_DIR)/tools/capture_screenshots.d diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index f1ab13c..f777ca0 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -1673,6 +1673,12 @@ add no dependencies or callback I/O/allocation. See behavior. Human listening, physical hardware, arbitrary third-party plugins and feature parity with commercial DAWs remain unqualified. +All application screenshots were refreshed after Phase 68. The +[screenshot gallery](../screenshots/README.md) includes controls and results for +every phase from 58 through 68, plus refreshed existing views and detached +editors. The optional `make screenshots` target reproduces the captures using +real FLTK widgets and isolated demonstration data. + --- ## Recommended Execution Order diff --git a/screenshots/README.md b/screenshots/README.md index bc47be3..c1d0041 100644 --- a/screenshots/README.md +++ b/screenshots/README.md @@ -1,24 +1,49 @@ # xtc screenshots -Captured from the Phase 38 FLTK application on 2026-10-28, with Phase 39 -transport, mixer, arrangement and command captures refreshed on 2026-10-30 using -a virtual X11 screen. Images show actual rendered widgets, without mockups or image edits. +All captures refreshed from the Phase 68 FLTK application on 2026-11-06. +These are actual rendered application windows and menus on a 1440 × 960 virtual +X11 screen, without mockups, compositing or image edits. -![Overview of xtc screenshots](overview.png) +![Arrangement with named sections](overview.png) -Internal instrument dropdowns show Soft Keys and Sub Bass; internal delay and -reverb captures show the actual editable effect controls. +The temporary demonstration project starts from +`examples/projects/modern-session.xtc`, adding Intro/Verse/Chorus/Outro markers, +a routed music bus and gain automation. Editing results use the real control +APIs and GUI history/preparation paths. Original projects, media and user +configuration are not overwritten. Black margins are the virtual desktop; +floating views show the actual detached windows together. -The arrangement uses `examples/projects/modern-session.xtc`. Mixer captures add -a bus, routing, pan/level settings and automation. The playing view shows actual -JACK callback meters; additional captures show the minimum 1220 × 720 layout and -a larger session scrolled to its final channels, with the master monitor pinned. -The audio view adds a temporary generated waveform. Plugin views use the -repository's LADSPA, CLAP, VST2 and VST3 test fixtures; these are demonstration -plugins, not commercial instruments. Preferences show application defaults and -the staged loop. The command palette shows the available application actions. -The workspace now includes direct BPM editing, a live track inspector and -arrangement navigation. No user configuration or example project was overwritten. +## New arrangement and composition workflows + +| Phase | Feature | Captures | +| --- | --- | --- | +| 58 | Persistent named arrangement markers | [Ruler](arrangement-markers.png), [marker editor](marker-edit.png) | +| 59 | Section navigation and looping | [Current section loop](section-navigation.png) | +| 60 | Ripple time insertion/removal | [Controls](ripple-time.png), [inserted gap](ripple-result.png) | +| 61 | Complete track duplication | [Independent layered track](track-duplication.png) | +| 62 | Nondestructive MIDI splitting | [Split clip](midi-split.png) | +| 63 | MIDI clip consolidation | [Consolidated clip](midi-consolidation.png) | +| 64 | Seeded MIDI humanization | [Timing, velocity and seed](midi-humanize.png) | +| 65 | Chord construction | [Intervals](midi-chord-builder.png), [generated notes](midi-chords-result.png) | +| 66 | Offline arpeggio generation | [Step, gate and direction](midi-arpeggio.png), [written pattern](midi-arpeggio-result.png) | +| 67 | Audio peak normalization | [Target dBFS](audio-normalization.png), [normalized clip](audio-normalization-result.png) | +| 68 | Portable media collection | [New destination folder](project-collection.png) | + +Collection is also executed by the capture tool into its temporary directory; +the screenshot shows its destination prompt, not a file browser or progress UI. +See [COMPOSITION_WORKFLOWS.md](../docs/COMPOSITION_WORKFLOWS.md) for precise +behavior, limits and commands. The screenshots illustrate implemented workflows; +they do not establish feature parity with other DAWs. + +## Refreshed application views + +All pre-existing images below were recaptured. Mixer playback meters come from +real JACK callbacks. The minimum-size capture uses a 1220 × 720 main window; +the scrolled view adds twelve tracks. Audio views import the repository's +`original-pluck.wav` and apply clip gain/fades. Plugin views use repository test +fixtures, not commercial plugins. Internal instrument menus and delay/reverb +editors show the real available devices and controls. The command palette uses +the current application action list. - [Sequencer loop](sequencer-loop.png) - [Mixer automation](mixer-automation.png) @@ -55,5 +80,25 @@ arrangement navigation. No user configuration or example project was overwritten - [Detached mixer](mixer-detached.png) - [Workspace with transport and mixer detached](workspace-detached.png) + +- [Detached sequencer](sequencer-detached.png) +- [Detached modular graph](graph-detached.png) + Detach panels from the View menu; close a floating window or use its Dock button -to return it to the main window. The main arrangement uses the freed toolbar space. +to return it to the main window. + +## Reproduce the gallery + +From the repository root, run: + +```sh +make BUILD_DIR=build/next-daw screenshots +``` + +This optional documentation target requires the existing FLTK/JACK build +prerequisites, a running JACK server, Xvfb (`xvfb-run`), ImageMagick (`import`) and +`xdotool`. It builds the repository plugin fixtures, runs +[the capture tool](../tools/capture_screenshots.cpp), and replaces the gallery +PNGs. All demonstration edits and collection outputs use an automatically removed +temporary directory; no preferences are saved. It neither installs dependencies +nor starts/reconfigures the audio server. diff --git a/screenshots/about.png b/screenshots/about.png index 7ba2b14..7cf547a 100644 Binary files a/screenshots/about.png and b/screenshots/about.png differ diff --git a/screenshots/arrangement-markers.png b/screenshots/arrangement-markers.png new file mode 100644 index 0000000..b49f047 Binary files /dev/null and b/screenshots/arrangement-markers.png differ diff --git a/screenshots/audio-clip-properties.png b/screenshots/audio-clip-properties.png index 8cbae9a..f6729b6 100644 Binary files a/screenshots/audio-clip-properties.png and b/screenshots/audio-clip-properties.png differ diff --git a/screenshots/audio-normalization-result.png b/screenshots/audio-normalization-result.png new file mode 100644 index 0000000..ec1e7c8 Binary files /dev/null and b/screenshots/audio-normalization-result.png differ diff --git a/screenshots/audio-normalization.png b/screenshots/audio-normalization.png new file mode 100644 index 0000000..b777823 Binary files /dev/null and b/screenshots/audio-normalization.png differ diff --git a/screenshots/clap-instrument-descriptors.png b/screenshots/clap-instrument-descriptors.png index 7f23216..a761056 100644 Binary files a/screenshots/clap-instrument-descriptors.png and b/screenshots/clap-instrument-descriptors.png differ diff --git a/screenshots/commands.png b/screenshots/commands.png index 5b445cf..d306fe6 100644 Binary files a/screenshots/commands.png and b/screenshots/commands.png differ diff --git a/screenshots/graph-detached.png b/screenshots/graph-detached.png new file mode 100644 index 0000000..038336d Binary files /dev/null and b/screenshots/graph-detached.png differ diff --git a/screenshots/internal-delay.png b/screenshots/internal-delay.png index ec8f707..f54d8f8 100644 Binary files a/screenshots/internal-delay.png and b/screenshots/internal-delay.png differ diff --git a/screenshots/internal-instruments.png b/screenshots/internal-instruments.png index 1391085..7c9dc8c 100644 Binary files a/screenshots/internal-instruments.png and b/screenshots/internal-instruments.png differ diff --git a/screenshots/internal-reverb.png b/screenshots/internal-reverb.png index 3975a85..75b6817 100644 Binary files a/screenshots/internal-reverb.png and b/screenshots/internal-reverb.png differ diff --git a/screenshots/loop-range.png b/screenshots/loop-range.png index 007e4e3..051b236 100644 Binary files a/screenshots/loop-range.png and b/screenshots/loop-range.png differ diff --git a/screenshots/marker-edit.png b/screenshots/marker-edit.png new file mode 100644 index 0000000..7acdeed Binary files /dev/null and b/screenshots/marker-edit.png differ diff --git a/screenshots/midi-arpeggio-result.png b/screenshots/midi-arpeggio-result.png new file mode 100644 index 0000000..51c4d28 Binary files /dev/null and b/screenshots/midi-arpeggio-result.png differ diff --git a/screenshots/midi-arpeggio.png b/screenshots/midi-arpeggio.png new file mode 100644 index 0000000..2313027 Binary files /dev/null and b/screenshots/midi-arpeggio.png differ diff --git a/screenshots/midi-chord-builder.png b/screenshots/midi-chord-builder.png new file mode 100644 index 0000000..fb28f7e Binary files /dev/null and b/screenshots/midi-chord-builder.png differ diff --git a/screenshots/midi-chords-result.png b/screenshots/midi-chords-result.png new file mode 100644 index 0000000..7d66799 Binary files /dev/null and b/screenshots/midi-chords-result.png differ diff --git a/screenshots/midi-consolidation.png b/screenshots/midi-consolidation.png new file mode 100644 index 0000000..a1d75f0 Binary files /dev/null and b/screenshots/midi-consolidation.png differ diff --git a/screenshots/midi-controller-mapping.png b/screenshots/midi-controller-mapping.png index afbcea6..37232dc 100644 Binary files a/screenshots/midi-controller-mapping.png and b/screenshots/midi-controller-mapping.png differ diff --git a/screenshots/midi-humanize.png b/screenshots/midi-humanize.png new file mode 100644 index 0000000..d494204 Binary files /dev/null and b/screenshots/midi-humanize.png differ diff --git a/screenshots/midi-split.png b/screenshots/midi-split.png new file mode 100644 index 0000000..662fcad Binary files /dev/null and b/screenshots/midi-split.png differ diff --git a/screenshots/mixer-automation.png b/screenshots/mixer-automation.png index 47a9d5a..02df1e0 100644 Binary files a/screenshots/mixer-automation.png and b/screenshots/mixer-automation.png differ diff --git a/screenshots/mixer-detached.png b/screenshots/mixer-detached.png index 35a9aa1..5a96676 100644 Binary files a/screenshots/mixer-detached.png and b/screenshots/mixer-detached.png differ diff --git a/screenshots/mixer-minimum-size.png b/screenshots/mixer-minimum-size.png index 438c130..f02e624 100644 Binary files a/screenshots/mixer-minimum-size.png and b/screenshots/mixer-minimum-size.png differ diff --git a/screenshots/mixer-playing.png b/screenshots/mixer-playing.png index c078e2e..ce7c0be 100644 Binary files a/screenshots/mixer-playing.png and b/screenshots/mixer-playing.png differ diff --git a/screenshots/mixer-scrolled-session.png b/screenshots/mixer-scrolled-session.png index 2f42d00..27eb2d3 100644 Binary files a/screenshots/mixer-scrolled-session.png and b/screenshots/mixer-scrolled-session.png differ diff --git a/screenshots/modular-graph.png b/screenshots/modular-graph.png index 5add830..6c30106 100644 Binary files a/screenshots/modular-graph.png and b/screenshots/modular-graph.png differ diff --git a/screenshots/overview.png b/screenshots/overview.png index 224f5ff..b49f047 100644 Binary files a/screenshots/overview.png and b/screenshots/overview.png differ diff --git a/screenshots/piano-roll-velocity.png b/screenshots/piano-roll-velocity.png index 2126486..140c82f 100644 Binary files a/screenshots/piano-roll-velocity.png and b/screenshots/piano-roll-velocity.png differ diff --git a/screenshots/plugin-controls.png b/screenshots/plugin-controls.png index bef7e9e..41b3be4 100644 Binary files a/screenshots/plugin-controls.png and b/screenshots/plugin-controls.png differ diff --git a/screenshots/plugin-descriptors.png b/screenshots/plugin-descriptors.png index 9a5b959..4c8f82a 100644 Binary files a/screenshots/plugin-descriptors.png and b/screenshots/plugin-descriptors.png differ diff --git a/screenshots/plugin-library.png b/screenshots/plugin-library.png index 8fc02b4..8c4ca22 100644 Binary files a/screenshots/plugin-library.png and b/screenshots/plugin-library.png differ diff --git a/screenshots/preferences-audio.png b/screenshots/preferences-audio.png index c0b2101..9ff62d9 100644 Binary files a/screenshots/preferences-audio.png and b/screenshots/preferences-audio.png differ diff --git a/screenshots/preferences-editing.png b/screenshots/preferences-editing.png index 5545ed5..9f91374 100644 Binary files a/screenshots/preferences-editing.png and b/screenshots/preferences-editing.png differ diff --git a/screenshots/preferences-interface.png b/screenshots/preferences-interface.png index 76e751d..6c0e652 100644 Binary files a/screenshots/preferences-interface.png and b/screenshots/preferences-interface.png differ diff --git a/screenshots/preferences-plugins.png b/screenshots/preferences-plugins.png index 2ea9269..6c374d2 100644 Binary files a/screenshots/preferences-plugins.png and b/screenshots/preferences-plugins.png differ diff --git a/screenshots/preferences-project_defaults.png b/screenshots/preferences-project_defaults.png index 506147c..aad049b 100644 Binary files a/screenshots/preferences-project_defaults.png and b/screenshots/preferences-project_defaults.png differ diff --git a/screenshots/preferences-transport.png b/screenshots/preferences-transport.png index 2e75085..f4d9288 100644 Binary files a/screenshots/preferences-transport.png and b/screenshots/preferences-transport.png differ diff --git a/screenshots/project-collection.png b/screenshots/project-collection.png new file mode 100644 index 0000000..6acd41c Binary files /dev/null and b/screenshots/project-collection.png differ diff --git a/screenshots/ripple-result.png b/screenshots/ripple-result.png new file mode 100644 index 0000000..044ba7b Binary files /dev/null and b/screenshots/ripple-result.png differ diff --git a/screenshots/ripple-time.png b/screenshots/ripple-time.png new file mode 100644 index 0000000..5b930b4 Binary files /dev/null and b/screenshots/ripple-time.png differ diff --git a/screenshots/section-navigation.png b/screenshots/section-navigation.png new file mode 100644 index 0000000..b49f047 Binary files /dev/null and b/screenshots/section-navigation.png differ diff --git a/screenshots/sequencer-audio-waveform.png b/screenshots/sequencer-audio-waveform.png index cdc8a79..ec1e7c8 100644 Binary files a/screenshots/sequencer-audio-waveform.png and b/screenshots/sequencer-audio-waveform.png differ diff --git a/screenshots/sequencer-detached.png b/screenshots/sequencer-detached.png new file mode 100644 index 0000000..2ac7ae0 Binary files /dev/null and b/screenshots/sequencer-detached.png differ diff --git a/screenshots/sequencer-loop.png b/screenshots/sequencer-loop.png index 28befa6..b49f047 100644 Binary files a/screenshots/sequencer-loop.png and b/screenshots/sequencer-loop.png differ diff --git a/screenshots/track-duplication.png b/screenshots/track-duplication.png new file mode 100644 index 0000000..f2b44b4 Binary files /dev/null and b/screenshots/track-duplication.png differ diff --git a/screenshots/transport-detached.png b/screenshots/transport-detached.png index b137170..e103638 100644 Binary files a/screenshots/transport-detached.png and b/screenshots/transport-detached.png differ diff --git a/screenshots/vst2-instrument-descriptors.png b/screenshots/vst2-instrument-descriptors.png index 9924196..b924fcf 100644 Binary files a/screenshots/vst2-instrument-descriptors.png and b/screenshots/vst2-instrument-descriptors.png differ diff --git a/screenshots/vst3-instrument-descriptors.png b/screenshots/vst3-instrument-descriptors.png index 7403537..7bce34b 100644 Binary files a/screenshots/vst3-instrument-descriptors.png and b/screenshots/vst3-instrument-descriptors.png differ diff --git a/screenshots/workspace-detached.png b/screenshots/workspace-detached.png index 44dbebf..5f4b8b5 100644 Binary files a/screenshots/workspace-detached.png and b/screenshots/workspace-detached.png differ diff --git a/src/gui/main_window.cpp b/src/gui/main_window.cpp index f4671bc..ca4ea27 100644 --- a/src/gui/main_window.cpp +++ b/src/gui/main_window.cpp @@ -1207,7 +1207,7 @@ void MainWindow::view_callback(Fl_Widget *widget, void *view) */ void MainWindow::about_callback(Fl_Widget *, void *) { - fl_message("%s %s\nModular audio workstation\nPhase 12: timing, transitions and audio quality.", + fl_message("%s %s\nModular audio workstation\nArrangement markers, MIDI composition, audio editing and modular mixing.", XTC_PROJECT_NAME, XTC_VERSION_STRING); } diff --git a/tools/capture_screenshots.cpp b/tools/capture_screenshots.cpp new file mode 100644 index 0000000..aad8544 --- /dev/null +++ b/tools/capture_screenshots.cpp @@ -0,0 +1,96 @@ +/* Optional documentation tool: real FLTK widgets and real backend, isolated data. */ +#include "../src/gui/main_window.hpp" +#include "../src/gui/sequencer_widget.hpp" +#include "../src/gui/mixer_widget.hpp" +#include "../src/gui/piano_roll.hpp" +#include "../src/gui/plugin_dialog.hpp" +#include "../src/gui/plugin_library.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { +MainWindow *main_window; +std::string destination; +void check(xtc_result r) {if(r!=XTC_OK)throw std::runtime_error(xtc_result_string(r));} +void pump() {auto end=std::chrono::steady_clock::now()+std::chrono::milliseconds(180);while(std::chrono::steady_clock::now() T *first(Fl_Group &g) {for(int i=0;i(c))return t;if(auto *n=dynamic_cast(c))if(auto *t=first(*n))return t;}return nullptr;} +Fl_Widget *named(Fl_Group &g,const char *label) {for(int i=0;ilabel()&&!strcmp(c->label(),label))return c;if(auto *n=dynamic_cast(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(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);} +struct Modal {const char *name;const char *page;}; +void modal_capture(void *data) {auto *job=static_cast(data);auto *w=Fl::modal();if(!w||w==main_window)throw std::runtime_error("Expected a modal dialog");if(job->page){auto *tabs=first(*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 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(*main_window);const auto *item=bar->find_item(path);if(!item)throw std::runtime_error(path);bar->picked(item);} +void piano_view() { + check(main_window->open_piano_roll()); + auto *piano=main_window->piano_roll(); + if(auto *scroll=dynamic_cast(piano->parent()))scroll->scroll_to(0,50*16); + size_t count=0;check(xtc_project_note_count(piano->project(),&count)); + for(size_t i=0;iproject(),i,¬e));if(note.clip_id==piano->clip()){piano->select_note(note.id);break;}} + piano->redraw();pump(); +} +void button(const char *name) {auto *b=named(*main_window,name);if(!b)throw std::runtime_error(name);b->do_callback();pump();} +} +int main(int argc,char **argv) { + if(argc!=2){std::fprintf(stderr,"Usage: capture_screenshots OUTPUT_DIRECTORY (absolute, no apostrophes)\n");return 1;} + destination=argv[1];if(destination.empty()||destination[0]!='/'||destination.find('\'')!=std::string::npos)return 1; + try { + std::filesystem::create_directories(destination); + char temp[]="/tmp/xtc-screenshots-XXXXXX";if(!mkdtemp(temp))return 1;std::string root=temp; + struct Cleanup {std::string path;~Cleanup(){std::filesystem::remove_all(path);}} cleanup{root}; + xtc_project *p=nullptr;check(xtc_project_create(&p));check(xtc_project_load(p,"examples/projects/modern-session.xtc")); + for(auto pair:{std::pair{0,"Intro"},{3840,"Verse"},{7680,"Chorus"},{11520,"Outro"}})check(xtc_project_set_marker(p,pair.first,pair.second)); + uint64_t bus;check(xtc_project_add_bus(p,"Music bus",&bus));check(xtc_project_route_track(p,0,bus)); + xtc_automation_point a{0,0,XTC_AUTOMATION_GAIN,.65f,0};check(xtc_project_set_automation(p,&a));a.tick=3840;a.value=1;check(xtc_project_set_automation(p,&a));a.tick=7680;a.value=.8f;check(xtc_project_set_automation(p,&a)); + std::string project=root+"/composition.xtc";check(xtc_project_save(p,project.c_str()));xtc_project_destroy(p); + 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(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();}; + 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();}); + dialog("ripple-time",[&]{s->ripple_dialog(false);}); + s->position(7680);check(s->ripple_time(1920,false));capture("ripple-result");reset(); + check(s->duplicate_track("Keys layered"));capture("track-duplication");reset(); + s->position(1920);check(s->split_selection());capture("midi-split"); + s->select_all_clips(); // Consolidation requires one track; reset to just the two halves. + s->select(0,0);size_t tracks=0,clips=0;xtc_project_get_counts(s->project(),&tracks,&clips); + for(size_t i=0;iproject(),i,&c);if(c.track_id==0&&c.start_tick==1920)s->toggle_clip(c.id);} + check(s->merge_midi());capture("midi-consolidation");reset(); + dialog("midi-humanize",[&]{s->humanize_dialog();});dialog("midi-chord-builder",[&]{s->chord_dialog();});dialog("midi-arpeggio",[&]{s->arpeggio_dialog();}); + check(s->make_chord({4,7}));piano_view();capture("midi-chords-result");check(s->arpeggiate(240,70,false));piano_view();capture("midi-arpeggio-result");reset(); + piano_view();capture("piano-roll-velocity");window.detach_piano(false);reset(); + dialog("commands",[&]{window.show_commands();}); + tab("Mixer");capture("mixer-automation");button("Play");pump();capture("mixer-playing");button("Stop"); + window.resize(0,0,1220,720);pump();capture("mixer-minimum-size");window.resize(0,0,1400,900); + for(int i=0;i<12;++i){check(window.create_track(false));} + tab("Mixer");auto *scroll=first(*window.mixer());if(scroll)scroll->scroll_to(std::max(0,static_cast(window.mixer()->strip_count())*156-scroll->w()),0);pump();capture("mixer-scrolled-session");reset(); + tab("Modular Graph");capture("modular-graph");reset(); + 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("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");}); + for(const char *section:{"audio","plugins","interface","editing","project_defaults","transport"}){std::string file="preferences-"+std::string(section);for(char &c:file)if(c==' ')c='_';dialog(file.c_str(),[&]{window.show_preferences();},section);} + xtc_settings settings=window.settings();std::string fixtures=std::filesystem::canonical(argv[0]).parent_path().string();snprintf(settings.ladspa_paths,sizeof(settings.ladspa_paths),"%s",fixtures.c_str());settings.clap_paths[0]=settings.vst2_paths[0]=settings.vst3_paths[0]=0; + dialog("plugin-library",[&]{std::string path;xtc_choose_plugin_file(settings,path);}); + for(auto entry:{std::pair{"plugin-descriptors","plugin-fixture.so"},{"clap-instrument-descriptors","clap-synth-fixture.clap"},{"vst2-instrument-descriptors","vst2-synth-fixture.so"},{"vst3-instrument-descriptors","vst3-synth-fixture.so"}}){unsigned int index=0;dialog(entry.first,[&]{xtc_choose_plugin((fixtures+"/"+entry.second).c_str(),48000,index,strcmp(entry.first,"plugin-descriptors")!=0);});} + for(auto entry:{std::pair{"internal-delay",2},{"internal-reverb",3},{"plugin-controls",2}}){xtc_plugin_spec spec{},edited{};xtc_plugin_details details{};if(!strcmp(entry.first,"plugin-controls"))check(xtc_plugin_probe((fixtures+"/plugin-fixture.so").c_str(),0,48000,&spec));else check(xtc_plugin_probe_format(XTC_PLUGIN_BUILTIN,XTC_BUILTIN_PATH,entry.second,48000,&spec));check(xtc_plugin_describe(&spec,48000,&details));dialog(entry.first,[&]{xtc_edit_plugin(spec,details,edited);});} + reset();auto *choice=s->instrument_choice(0);if(!choice)throw std::runtime_error("Instrument menu missing");Fl::add_timeout(.3,[](void*){capture("internal-instruments");if(system("xdotool key Escape"))std::abort();});choice->menu()->pulldown(choice->x(),choice->y(),choice->w(),choice->h(),choice->mvalue(),choice); + window.do_callback();std::puts("All documentation captures completed.");return 0; + } catch(const std::exception &e){std::fprintf(stderr,"Screenshot capture failed: %s\n",e.what());return 1;} +}