From ea7bc6c83e7e9131f6bfb799f4b8e5f864bd1d4f Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 11 Jan 2013 21:43:31 +0000 Subject: Move run context information to Context object and remove Machine::_forge. git-svn-id: http://svn.drobilla.net/lad/trunk/machina@4923 a436a847-0d15-0410-975c-d299462d15a1 --- src/engine/JackDriver.cpp | 108 +++++++++++++++++++++-------------------- src/engine/JackDriver.hpp | 4 +- src/engine/Loader.cpp | 2 +- src/engine/Machine.cpp | 35 +++++++------ src/engine/Recorder.cpp | 2 +- src/engine/SMFDriver.cpp | 11 +++-- src/engine/machina/Context.hpp | 44 +++++++++++++++++ src/engine/machina/Machine.hpp | 10 ++-- src/gui/main.cpp | 2 +- 9 files changed, 133 insertions(+), 85 deletions(-) create mode 100644 src/engine/machina/Context.hpp diff --git a/src/engine/JackDriver.cpp b/src/engine/JackDriver.cpp index bcde9ef..bc1e38e 100644 --- a/src/engine/JackDriver.cpp +++ b/src/engine/JackDriver.cpp @@ -18,9 +18,10 @@ #include #include -#include "machina_config.h" +#include "machina/Context.hpp" #include "machina/URIs.hpp" #include "machina/Updates.hpp" +#include "machina_config.h" #include "JackDriver.hpp" #include "LearnRequest.hpp" @@ -38,9 +39,9 @@ JackDriver::JackDriver(Raul::Forge& forge, SharedPtr machine) , _machine_changed(0) , _input_port(NULL) , _output_port(NULL) + , _context(forge, 48000, MACHINA_PPQN, 120.0) , _frames_unit(TimeUnit::FRAMES, 48000) , _beats_unit(TimeUnit::BEATS, 19200) - , _cycle_time(48000, MACHINA_PPQN, 120.0) , _bpm(120.0) , _quantization(0.0f) , _stop(0) @@ -77,28 +78,27 @@ JackDriver::attach(const std::string& client_name) if (jack_client()) { - //_cycle_time.set_tick_rate(1/(double)sample_rate()); + _context.time().set_tick_rate(sample_rate()); _input_port = jack_port_register(jack_client(), - "in", - JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, - 0); + "in", + JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, + 0); if (!_input_port) std:: cerr << "WARNING: Failed to create MIDI input port." << std::endl; _output_port = jack_port_register(jack_client(), - "out", - JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, - 0); + "out", + JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, + 0); if (!_output_port) std::cerr << "WARNING: Failed to create MIDI output port." << std::endl; if (!_machine) _machine = SharedPtr( - new Machine(_forge, - TimeUnit::frames(jack_get_sample_rate(jack_client())))); + new Machine(TimeUnit::frames(jack_get_sample_rate(jack_client())))); _machine->activate(); } @@ -205,8 +205,8 @@ JackDriver::process_input(SharedPtr machine, const Raul::TimeSlice& tim if (learn) { learn->enter_action()->set_event(ev.size, ev.buffer); learn->start(_quantization.get(), - TimeStamp(TimeUnit::frames(sample_rate()), - jack_last_frame_time(_client) + ev.time, 0)); + TimeStamp(TimeUnit::frames(sample_rate()), + jack_last_frame_time(_client) + ev.time, 0)); } } else if (ev.buffer[0] == 0x80) { @@ -218,7 +218,7 @@ JackDriver::process_input(SharedPtr machine, const Raul::TimeSlice& tim learn->exit_action()->set_event(ev.size, ev.buffer); learn->finish( TimeStamp(TimeUnit::frames(sample_rate()), - jack_last_frame_time(_client) + ev.time, 0)); + jack_last_frame_time(_client) + ev.time, 0)); const uint64_t id = Stateful::next_id(); write_set(_updates, id, @@ -248,39 +248,41 @@ JackDriver::write_event(Raul::TimeStamp time, if (!_output_port) return; - if (_cycle_time.beats_to_ticks(time) + _cycle_time.offset_ticks() < _cycle_time.start_ticks()) { + const Raul::TimeSlice& slice = _context.time(); + + if (slice.beats_to_ticks(time) + slice.offset_ticks() < slice.start_ticks()) { std::cerr << "ERROR: Missed event by " - << _cycle_time.start_ticks() - - (_cycle_time.beats_to_ticks(time) + _cycle_time.offset_ticks()) - << " ticks" - << "\n\tbpm: " << _cycle_time.bpm() - << "\n\tev time: " << _cycle_time.beats_to_ticks(time) - << "\n\tcycle_start: " << _cycle_time.start_ticks() - << "\n\tcycle_end: " << _cycle_time.start_ticks() + _cycle_time.length_ticks() - << "\n\tcycle_length: " << _cycle_time.length_ticks() << std::endl << std::endl; + << slice.start_ticks() + - (slice.beats_to_ticks(time) + slice.offset_ticks()) + << " ticks" + << "\n\tbpm: " << slice.bpm() + << "\n\tev time: " << slice.beats_to_ticks(time) + << "\n\tcycle_start: " << slice.start_ticks() + << "\n\tcycle_end: " << slice.start_ticks() + slice.length_ticks() + << "\n\tcycle_length: " << slice.length_ticks() << std::endl << std::endl; return; } - const TimeDuration nframes = _cycle_time.length_ticks(); - const TimeStamp offset = _cycle_time.beats_to_ticks(time) - + _cycle_time.offset_ticks() - _cycle_time.start_ticks(); + const TimeDuration nframes = slice.length_ticks(); + const TimeStamp offset = slice.beats_to_ticks(time) + + slice.offset_ticks() - slice.start_ticks(); - if ( ! (offset < _cycle_time.offset_ticks() + nframes)) { + if ( ! (offset < slice.offset_ticks() + nframes)) { std::cerr << "ERROR: Event offset " << offset << " outside cycle " - << "\n\tbpm: " << _cycle_time.bpm() - << "\n\tev time: " << _cycle_time.beats_to_ticks(time) - << "\n\tcycle_start: " << _cycle_time.start_ticks() - << "\n\tcycle_end: " << _cycle_time.start_ticks() + _cycle_time.length_ticks() - << "\n\tcycle_length: " << _cycle_time.length_ticks() << std::endl; + << "\n\tbpm: " << slice.bpm() + << "\n\tev time: " << slice.beats_to_ticks(time) + << "\n\tcycle_start: " << slice.start_ticks() + << "\n\tcycle_end: " << slice.start_ticks() + slice.length_ticks() + << "\n\tcycle_length: " << slice.length_ticks() << std::endl; } else { #ifdef JACK_MIDI_NEEDS_NFRAMES jack_midi_event_write( - jack_port_get_buffer(_output_port, nframes), offset, - event, size, nframes); + jack_port_get_buffer(_output_port, nframes), offset, + event, size, nframes); #else jack_midi_event_write( - jack_port_get_buffer(_output_port, nframes.ticks()), offset.ticks(), - event, size); + jack_port_get_buffer(_output_port, nframes.ticks()), offset.ticks(), + event, size); #endif } } @@ -288,7 +290,7 @@ JackDriver::write_event(Raul::TimeStamp time, void JackDriver::on_process(jack_nframes_t nframes) { - _cycle_time.set_bpm(_bpm.get()); + _context.time().set_bpm(_bpm.get()); assert(_output_port); #ifdef JACK_MIDI_NEEDS_NFRAMES @@ -297,11 +299,11 @@ JackDriver::on_process(jack_nframes_t nframes) jack_midi_clear_buffer(jack_port_get_buffer(_output_port, nframes)); #endif - TimeStamp length_ticks(TimeStamp(_cycle_time.ticks_unit(), nframes)); - TimeStamp length_beats(_cycle_time.ticks_to_beats(length_ticks)); + TimeStamp length_ticks(TimeStamp(_context.time().ticks_unit(), nframes)); + TimeStamp length_beats(_context.time().ticks_to_beats(length_ticks)); - _cycle_time.set_length(length_ticks); - _cycle_time.set_offset(TimeStamp(_cycle_time.ticks_unit(), 0, 0)); + _context.time().set_length(length_ticks); + _context.time().set_offset(TimeStamp(_context.time().ticks_unit(), 0, 0)); /* Take a reference to machine here and use only it during the process * cycle so _machine can be switched with set_machine during a cycle. */ @@ -326,35 +328,35 @@ JackDriver::on_process(jack_nframes_t nframes) machine->set_sink(shared_from_this()); if (_stop_flag) - machine->reset(_cycle_time.start_beats()); + machine->reset(_context.time().start_beats()); - process_input(machine, _cycle_time); + process_input(machine, _context.time()); if (machine->is_empty() || !machine->is_activated()) goto end; while (true) { - const uint32_t run_dur_frames = machine->run(_cycle_time, _updates); + const uint32_t run_dur_frames = machine->run(_context, _updates); if (run_dur_frames == 0) { // Machine didn't run at all (machine has no initial states) machine->reset(machine->time()); // Try again next cycle - _cycle_time.set_slice(TimeStamp(_frames_unit, 0, 0), - TimeStamp(_frames_unit, 0, 0)); + _context.time().set_slice(TimeStamp(_frames_unit, 0, 0), + TimeStamp(_frames_unit, 0, 0)); break; } else if (machine->is_finished()) { // Machine ran for portion of cycle and is finished machine->reset(machine->time()); - _cycle_time.set_slice(TimeStamp(_frames_unit, 0, 0), - TimeStamp(_frames_unit, nframes - run_dur_frames, 0)); - _cycle_time.set_offset(TimeStamp(_frames_unit, run_dur_frames, 0)); + _context.time().set_slice(TimeStamp(_frames_unit, 0, 0), + TimeStamp(_frames_unit, nframes - run_dur_frames, 0)); + _context.time().set_offset(TimeStamp(_frames_unit, run_dur_frames, 0)); } else { // Machine ran for entire cycle - _cycle_time.set_slice( - _cycle_time.start_ticks() + _cycle_time.length_ticks(), + _context.time().set_slice( + _context.time().start_ticks() + _context.time().length_ticks(), TimeStamp(_frames_unit, 0, 0)); break; } @@ -366,8 +368,8 @@ end: _last_machine = machine; if (_stop_flag) { - _cycle_time.set_slice(TimeStamp(_frames_unit, 0, 0), - TimeStamp(_frames_unit, 0, 0)); + _context.time().set_slice(TimeStamp(_frames_unit, 0, 0), + TimeStamp(_frames_unit, 0, 0)); _stop_flag = false; } } diff --git a/src/engine/JackDriver.hpp b/src/engine/JackDriver.hpp index 5e76f1a..f28e78d 100644 --- a/src/engine/JackDriver.hpp +++ b/src/engine/JackDriver.hpp @@ -29,6 +29,7 @@ #include "raul/Semaphore.hpp" #include "raul/SharedPtr.hpp" +#include "machina/Context.hpp" #include "machina/Driver.hpp" #include "machina/Machine.hpp" @@ -107,9 +108,10 @@ private: jack_port_t* _input_port; jack_port_t* _output_port; + Context _context; + Raul::TimeUnit _frames_unit; Raul::TimeUnit _beats_unit; - Raul::TimeSlice _cycle_time; Raul::DoubleBuffer _bpm; Raul::DoubleBuffer _quantization; diff --git a/src/engine/Loader.cpp b/src/engine/Loader.cpp index 0ee4f11..3baa5a0 100644 --- a/src/engine/Loader.cpp +++ b/src/engine/Loader.cpp @@ -69,7 +69,7 @@ Loader::load(const Glib::ustring& uri) cout << "[Loader] Loading " << document_uri << endl; machine = SharedPtr( - new Machine(_forge, TimeUnit::beats(MACHINA_PPQN))); + new Machine(TimeUnit::beats(MACHINA_PPQN))); typedef std::map > Created; Created created; diff --git a/src/engine/Machine.cpp b/src/engine/Machine.cpp index ce4d60f..24e6aaf 100644 --- a/src/engine/Machine.cpp +++ b/src/engine/Machine.cpp @@ -26,6 +26,7 @@ #include "machina/Machine.hpp" #include "machina/Updates.hpp" #include "machina/URIs.hpp" +#include "machina/Context.hpp" #include "Edge.hpp" #include "Node.hpp" @@ -37,9 +38,8 @@ using namespace Raul; namespace Machina { -Machine::Machine(Raul::Forge& forge, TimeUnit unit) +Machine::Machine(TimeUnit unit) : _active_nodes(MAX_ACTIVE_NODES, SharedPtr()) - , _forge(forge) , _is_activated(false) , _is_finished(false) , _time(unit, 0, 0) @@ -54,7 +54,6 @@ Machine::Machine(Raul::Forge& forge, TimeUnit unit) Machine::Machine(const Machine& copy) : Stateful() // don't copy RDF ID , _active_nodes(MAX_ACTIVE_NODES, SharedPtr()) - , _forge(copy._forge) , _is_activated(false) , _is_finished(false) , _time(copy.time()) @@ -212,7 +211,7 @@ Machine::earliest_node() const * Returns true if node was entered, or false if the maximum active nodes has been reached. */ bool -Machine::enter_node(SharedPtr sink, SharedPtr node, SharedPtr updates) +Machine::enter_node(Context& context, SharedPtr sink, SharedPtr node, SharedPtr updates) { assert(!node->is_active()); @@ -228,7 +227,7 @@ Machine::enter_node(SharedPtr sink, SharedPtr node, SharedPtrid(), URIs::instance().machina_active, - _forge.make(true)); + context.forge().make(true)); return true; } index = (index + 1) % MAX_ACTIVE_NODES; @@ -241,13 +240,13 @@ Machine::enter_node(SharedPtr sink, SharedPtr node, SharedPtr sink, SharedPtr node, SharedPtr updates) +Machine::exit_node(Context& context, SharedPtr sink, SharedPtr node, SharedPtr updates) { node->exit(sink, _time); write_set(updates, node->id(), URIs::instance().machina_active, - _forge.make(false)); + context.forge().make(false)); assert(!node->is_active()); @@ -270,7 +269,7 @@ Machine::exit_node(SharedPtr sink, SharedPtr node, SharedPtr range_min && rand_normal < range_min + (*s)->probability()) { - enter_node(sink, (*s)->head(), updates); + enter_node(context, sink, (*s)->head(), updates); break; } else { @@ -289,7 +288,7 @@ Machine::exit_node(SharedPtr sink, SharedPtr node, SharedPtr head = (*e)->head(); if ( ! head->is_active()) - enter_node(sink, head, updates); + enter_node(context, sink, head, updates); } } @@ -306,16 +305,15 @@ Machine::exit_node(SharedPtr sink, SharedPtr node, SharedPtr updates) +Machine::run(Context& context, SharedPtr updates) { if (_is_finished) return 0; - SharedPtr sink = _sink.lock(); - const TimeStamp cycle_end_frames = time.start_ticks() + time.length_ticks(); - const TimeStamp cycle_end = time.ticks_to_beats(cycle_end_frames); + const TimeStamp cycle_end_frames = context.time().start_ticks() + context.time().length_ticks(); + const TimeStamp cycle_end = context.time().ticks_to_beats(cycle_end_frames); assert(_is_activated); @@ -329,11 +327,11 @@ Machine::run(const Raul::TimeSlice& time, SharedPtr updates) write_set(updates, (*n)->id(), URIs::instance().machina_active, - _forge.make(false)); + context.forge().make(false)); } if ((*n)->is_initial()) { - if (enter_node(sink, (*n), updates)) + if (enter_node(context, sink, (*n), updates)) entered = true; } } @@ -357,10 +355,10 @@ Machine::run(const Raul::TimeSlice& time, SharedPtr updates) _is_finished = true; break; - } else if (time.beats_to_ticks(earliest->exit_time()) < cycle_end_frames) { + } else if (context.time().beats_to_ticks(earliest->exit_time()) < cycle_end_frames) { // Earliest active state ends this cycle _time = earliest->exit_time(); - exit_node(sink, earliest, updates); + exit_node(context, sink, earliest, updates); } else { // Earliest active state ends in the future, done this cycle @@ -370,7 +368,8 @@ Machine::run(const Raul::TimeSlice& time, SharedPtr updates) } - return time.beats_to_ticks(_time).ticks() - time.start_ticks().ticks(); + return context.time().beats_to_ticks(_time).ticks() + - context.time().start_ticks().ticks(); } /** Push a node onto the learn stack. diff --git a/src/engine/Recorder.cpp b/src/engine/Recorder.cpp index 9d8c4fe..4a67f65 100644 --- a/src/engine/Recorder.cpp +++ b/src/engine/Recorder.cpp @@ -35,7 +35,7 @@ Recorder::Recorder(Raul::Forge& forge, , _unit(unit) , _record_buffer(buffer_size) , _builder(new MachineBuilder( - SharedPtr(new Machine(forge, unit)), q, step)) + SharedPtr(new Machine(unit)), q, step)) { } diff --git a/src/engine/SMFDriver.cpp b/src/engine/SMFDriver.cpp index 000ce0e..757615b 100644 --- a/src/engine/SMFDriver.cpp +++ b/src/engine/SMFDriver.cpp @@ -22,6 +22,7 @@ #include "raul/SharedPtr.hpp" +#include "machina/Context.hpp" #include "machina/Machine.hpp" #include "Edge.hpp" @@ -51,7 +52,7 @@ SharedPtr SMFDriver::learn(const string& filename, unsigned track, double q, Raul::TimeDuration max_duration) { //assert(q.unit() == max_duration.unit()); - SharedPtr m(new Machine(_forge, max_duration.unit())); + SharedPtr m(new Machine(max_duration.unit())); SharedPtr builder = SharedPtr(new MachineBuilder(m, q, false)); SMFReader reader; @@ -80,7 +81,7 @@ SMFDriver::learn(const string& filename, unsigned track, double q, Raul::TimeDur SharedPtr SMFDriver::learn(const string& filename, double q, Raul::TimeStamp max_duration) { - SharedPtr m(new Machine(_forge, max_duration.unit())); + SharedPtr m(new Machine(max_duration.unit())); SharedPtr builder = SharedPtr(new MachineBuilder(m, q, false)); SMFReader reader; @@ -140,10 +141,10 @@ void SMFDriver::run(SharedPtr machine, Raul::TimeStamp max_time) { // FIXME: unit kludge (tempo only) - Raul::TimeSlice time(machine->time().unit().ppt(), _writer->unit().ppt(), 120.0); - time.set_slice(TimeStamp(max_time.unit(), 0, 0), time.beats_to_ticks(max_time)); + Context context(_forge, machine->time().unit().ppt(), _writer->unit().ppt(), 120.0); + context.time().set_slice(TimeStamp(max_time.unit(), 0, 0), context.time().beats_to_ticks(max_time)); machine->set_sink(shared_from_this()); - machine->run(time, SharedPtr()); + machine->run(context, SharedPtr()); } } // namespace Machina diff --git a/src/engine/machina/Context.hpp b/src/engine/machina/Context.hpp new file mode 100644 index 0000000..270ede7 --- /dev/null +++ b/src/engine/machina/Context.hpp @@ -0,0 +1,44 @@ +/* This file is part of Machina. + * Copyright 2007-2012 David Robillard + * + * Machina is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Machina is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Machina. If not, see . + */ + +#ifndef MACHINA_CONTEXT_HPP +#define MACHINA_CONTEXT_HPP + +#include "raul/Atom.hpp" +#include "raul/TimeSlice.hpp" + +namespace Machina { + +class Context { +public: + Context(Raul::Forge& forge, uint32_t rate, uint32_t ppqn, double bpm) + : _forge(forge) + , _time(rate, ppqn, bpm) + {} + + Raul::Forge& forge() { return _forge; } + const Raul::TimeSlice& time() const { return _time; } + Raul::TimeSlice& time() { return _time; } + +private: + Raul::Forge& _forge; + Raul::TimeSlice _time; +}; + +} // namespace Machina + +#endif // MACHINA_CONTEXT_HPP diff --git a/src/engine/machina/Machine.hpp b/src/engine/machina/Machine.hpp index d65b670..0109742 100644 --- a/src/engine/machina/Machine.hpp +++ b/src/engine/machina/Machine.hpp @@ -35,6 +35,7 @@ namespace Machina { +class Context; class Controller; class LearnRequest; @@ -42,7 +43,7 @@ class LearnRequest; */ class Machine : public Stateful { public: - Machine(Raul::Forge& forge, TimeUnit unit); + Machine(TimeUnit unit); Machine(const Machine& copy); Machine& operator=(const Machine& other); @@ -66,7 +67,7 @@ public: // Audio context void reset(Raul::TimeStamp time); - uint32_t run(const Raul::TimeSlice& time, SharedPtr updates); + uint32_t run(Context& context, SharedPtr updates); // Any context inline Raul::TimeStamp time() const { return _time; } @@ -87,13 +88,12 @@ private: // Audio context SharedPtr earliest_node() const; - bool enter_node(SharedPtr sink, SharedPtr node, SharedPtr updates); - void exit_node(SharedPtr sink, SharedPtr, SharedPtr updates); + bool enter_node(Context& context, SharedPtr sink, SharedPtr node, SharedPtr updates); + void exit_node(Context& context, SharedPtr sink, SharedPtr, SharedPtr updates); static const size_t MAX_ACTIVE_NODES = 128; std::vector< SharedPtr > _active_nodes; - Raul::Forge& _forge; bool _is_activated; bool _is_finished; Raul::TimeStamp _time; diff --git a/src/gui/main.cpp b/src/gui/main.cpp index 676e3b8..7a70250 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -68,7 +68,7 @@ main(int argc, char** argv) if (!machine) machine = SharedPtr( - new Machine(forge, TimeUnit(TimeUnit::BEATS, 19200))); + new Machine(TimeUnit(TimeUnit::BEATS, 19200))); std::string driver_name = "smf"; #ifdef HAVE_JACK -- cgit v1.2.1