Phase 5: Add project persistence and sequencer foundation
This commit is contained in:
parent
5c41d7f6da
commit
65640c4aad
28 changed files with 1307 additions and 84 deletions
|
|
@ -1,5 +1,7 @@
|
|||
#include "../../src/gui/main_window.hpp"
|
||||
#include "../../src/gui/graph_widget.hpp"
|
||||
#include "../../src/gui/sequencer_widget.hpp"
|
||||
#include <unistd.h>
|
||||
#include <FL/Fl.H>
|
||||
#include <FL/Fl_Box.H>
|
||||
#include <FL/Fl_Button.H>
|
||||
|
|
@ -49,6 +51,24 @@ bool contains(Fl_Group *group, const char *text)
|
|||
}
|
||||
return false;
|
||||
}
|
||||
SequencerWidget *timeline(Fl_Group *group)
|
||||
{
|
||||
for (int i = 0; i < group->children(); ++i) {
|
||||
if (auto *s = dynamic_cast<SequencerWidget *>(group->child(i))) return s;
|
||||
if (auto *g = dynamic_cast<Fl_Group *>(group->child(i))) if (auto *s = timeline(g)) return s;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
void gesture(SequencerWidget *s, int left, int top, int dx, int dy)
|
||||
{
|
||||
int old_x = Fl::e_x, old_y = Fl::e_y, old_key = Fl::e_keysym;
|
||||
Fl::e_x = s->x() + left; Fl::e_y = s->y() + top; Fl::e_keysym = FL_Button + FL_LEFT_MOUSE;
|
||||
CHECK(s->handle(FL_PUSH) == 1);
|
||||
Fl::e_x += dx; Fl::e_y += dy;
|
||||
CHECK(s->handle(FL_DRAG) == 1);
|
||||
CHECK(s->handle(FL_RELEASE) == 1);
|
||||
Fl::e_x = old_x; Fl::e_y = old_y; Fl::e_keysym = old_key;
|
||||
}
|
||||
void press(Fl_Widget *widget)
|
||||
{
|
||||
CHECK(widget != nullptr);
|
||||
|
|
@ -92,6 +112,8 @@ xtc_result xtc_backend_get_status(const xtc_backend *backend, xtc_backend_status
|
|||
status->running = handle.running && !status->server_lost;
|
||||
return status_result;
|
||||
}
|
||||
xtc_result xtc_backend_seek(xtc_backend *, uint64_t sample)
|
||||
{ engine_status.sample_position = sample; return handle.running ? XTC_ERR_INVALID_STATE : XTC_OK; }
|
||||
xtc_result xtc_backend_submit(xtc_backend *backend, const xtc_graph *graph)
|
||||
{
|
||||
CHECK(backend == &handle && graph != nullptr);
|
||||
|
|
@ -111,7 +133,7 @@ int main(int argc, char **argv)
|
|||
{
|
||||
reset();
|
||||
{
|
||||
MainWindow window;
|
||||
MainWindow window(false);
|
||||
window.show(argc, argv);
|
||||
auto *play = find(&window, "Play");
|
||||
auto *stop = find(&window, "Stop");
|
||||
|
|
@ -216,6 +238,37 @@ int main(int argc, char **argv)
|
|||
for (size_t id : {0U, 2U, 3U, 5U}) { CHECK(canvas->select_node(id)); CHECK(canvas->delete_selected() == XTC_OK); }
|
||||
CHECK(xtc_graph_get_counts(canvas->graph(), &nodes, &edges) == XTC_OK && nodes == 0U && edges == 0U);
|
||||
CHECK(xtc_plan_process(handle.plan, nullptr, rendered, 32U) == XTC_OK && rendered[1] == 0.0f);
|
||||
auto *sequence = timeline(&window);
|
||||
CHECK(sequence != nullptr);
|
||||
char directory[] = "/tmp/xtc-gui-XXXXXX"; CHECK(mkdtemp(directory) != nullptr);
|
||||
std::string filename = std::string(directory) + "/song.xtc";
|
||||
press(find(&window, "Add track")); press(find(&window, "Add region"));
|
||||
size_t track_count, clip_count;
|
||||
CHECK(xtc_project_get_counts(sequence->project(), &track_count, &clip_count) == XTC_OK && track_count == 1 && clip_count == 1);
|
||||
xtc_clip_info region{};
|
||||
CHECK(xtc_project_get_clip(sequence->project(), 0, ®ion) == XTC_OK);
|
||||
gesture(sequence, 150, 50, 144, 0); // Move by three beats.
|
||||
gesture(sequence, 265, 50, 48, 0); // Trim left edge by one beat.
|
||||
CHECK(xtc_project_get_clip(sequence->project(), 0, ®ion) == XTC_OK &&
|
||||
region.start_tick == 3840 && region.length_tick == 2880 && region.offset_tick == 960);
|
||||
int width = sequence->w();
|
||||
press(find(&window, "Zoom +")); CHECK(sequence->w() > width);
|
||||
press(find(&window, "Zoom -")); CHECK(sequence->w() == width);
|
||||
CHECK(window.save_project(filename.c_str()) == XTC_OK);
|
||||
const xtc_project *retained = sequence->project();
|
||||
CHECK(window.open_project("/missing/xtc-project") == XTC_ERR_IO && sequence->project() == retained);
|
||||
submit_result = XTC_ERR_CAPACITY;
|
||||
CHECK(window.open_project(filename.c_str()) == XTC_ERR_CAPACITY && sequence->project() == retained);
|
||||
submit_result = XTC_OK;
|
||||
press(find(&window, "Delete region/track"));
|
||||
CHECK(window.open_project(filename.c_str()) == XTC_OK);
|
||||
CHECK(xtc_project_get_clip(sequence->project(), 0, ®ion) == XTC_OK && region.start_tick == 3840 && region.offset_tick == 960);
|
||||
engine_status.sample_position = 48000; pump();
|
||||
CHECK(sequence->position() == 1920);
|
||||
CHECK(canvas->add_node(XTC_NODE_GAIN) == XTC_OK);
|
||||
CHECK(sequence->position() == 1920); // Graph edits preserve the transport.
|
||||
engine_status.sample_position = 0;
|
||||
CHECK(unlink(filename.c_str()) == 0 && rmdir(directory) == 0);
|
||||
engine_status.xruns = 3U;
|
||||
engine_status.processed_blocks = 123U;
|
||||
pump();
|
||||
|
|
@ -250,7 +303,7 @@ int main(int argc, char **argv)
|
|||
for (xtc_result failure : {XTC_ERR_IO, XTC_ERR_UNSUPPORTED}) {
|
||||
reset();
|
||||
open_result = failure;
|
||||
MainWindow window;
|
||||
MainWindow window(false);
|
||||
window.show(argc, argv);
|
||||
CHECK(contains(&window, "Open JACK failed") && !find(&window, "Play")->active());
|
||||
open_result = XTC_OK;
|
||||
|
|
@ -264,14 +317,14 @@ int main(int argc, char **argv)
|
|||
partial_open = true;
|
||||
open_result = XTC_ERR_IO;
|
||||
{
|
||||
MainWindow window;
|
||||
MainWindow window(false);
|
||||
CHECK(alive == 1U && !find(&window, "Play")->active());
|
||||
window.do_callback(); // Partially initialized handles are closed only.
|
||||
CHECK(alive == 0U);
|
||||
}
|
||||
reset();
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
MainWindow window;
|
||||
MainWindow window(false);
|
||||
press(find(&window, "Play"));
|
||||
window.do_callback();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue