diff options
author | David Robillard <d@drobilla.net> | 2007-02-21 02:30:09 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2007-02-21 02:30:09 +0000 |
commit | 1429e4b2279566384ec09bfe3bfe7d7e0f0f79eb (patch) | |
tree | 9f0fb4eed56bacf52e738cd13029ec2683ee56e2 /src | |
parent | a865ddb5043c4dc094b8f64d2cae60e0df16b8ac (diff) | |
download | machina-1429e4b2279566384ec09bfe3bfe7d7e0f0f79eb.tar.gz machina-1429e4b2279566384ec09bfe3bfe7d7e0f0f79eb.tar.bz2 machina-1429e4b2279566384ec09bfe3bfe7d7e0f0f79eb.zip |
Tempo based time in Machina (and related utilities added to Raul).
git-svn-id: http://svn.drobilla.net/lad/machina@324 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
27 files changed, 426 insertions, 265 deletions
diff --git a/src/engine/machina/Machina.hpp b/src/engine/Engine.cpp index 6cefcc5..a621a8a 100644 --- a/src/engine/machina/Machina.hpp +++ b/src/engine/Engine.cpp @@ -15,14 +15,25 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include <list> +#include "machina/Engine.hpp" +#include "machina/JackDriver.hpp" namespace Machina { -class Machina { -private: - std::list<Node> _nodes; -}; + +void +Engine::set_bpm(double bpm) +{ + _driver->set_bpm(bpm); +} + + +void +Engine::set_quantization(double) +{ +} } // namespace Machina + + diff --git a/src/engine/JackDriver.cpp b/src/engine/JackDriver.cpp index 6dc2153..9236fd9 100644 --- a/src/engine/JackDriver.cpp +++ b/src/engine/JackDriver.cpp @@ -20,14 +20,16 @@ #include "machina/JackDriver.hpp" #include "machina/MidiAction.hpp" +using namespace Raul; + namespace Machina { JackDriver::JackDriver() : _input_port(NULL) , _output_port(NULL) - , _current_cycle_start(0) - , _current_cycle_nframes(0) + , _cycle_time(1/48000.0, 120.0) + , _bpm(120.0) { } @@ -38,6 +40,9 @@ JackDriver::attach(const std::string& client_name) Raul::JackDriver::attach(client_name); if (jack_client()) { + + _cycle_time.set_tick_rate(1/(double)sample_rate()); + _input_port = jack_port_register(jack_client(), "in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, @@ -73,17 +78,6 @@ JackDriver::detach() } -Timestamp -JackDriver::stamp_to_offset(Timestamp stamp) -{ - assert(stamp >= _current_cycle_start); - - Timestamp ret = stamp - _current_cycle_start + _current_cycle_offset; - assert(ret < _current_cycle_offset + _current_cycle_nframes); - return ret; -} - - void JackDriver::process_input(jack_nframes_t nframes) { @@ -131,14 +125,17 @@ JackDriver::process_input(jack_nframes_t nframes) void -JackDriver::write_event(Timestamp time, - size_t size, - const byte* event) +JackDriver::write_event(Raul::BeatTime time, + size_t size, + const byte* event) { - const FrameCount nframes = _current_cycle_nframes; - const FrameCount offset = stamp_to_offset(time); + const TickCount nframes = _cycle_time.length_ticks(); + const TickCount offset = _cycle_time.offset_ticks() + + _cycle_time.beats_to_ticks(time); assert(_output_port); + assert(offset < nframes); + jack_midi_event_write( jack_port_get_buffer(_output_port, nframes), offset, event, size, nframes); @@ -151,8 +148,11 @@ JackDriver::on_process(jack_nframes_t nframes) using namespace std; //std::cerr << "> ======================================================\n"; - _current_cycle_offset = 0; - _current_cycle_nframes = nframes; + _cycle_time.set_bpm(_bpm.get()); + + // Start time set at end of previous cycle + _cycle_time.set_offset(0); + _cycle_time.set_length(nframes); assert(_output_port); jack_midi_clear_buffer(jack_port_get_buffer(_output_port, nframes), nframes); @@ -166,34 +166,36 @@ JackDriver::on_process(jack_nframes_t nframes) while (true) { - const FrameCount run_duration = _machine->run(_current_cycle_nframes); + const BeatCount run_dur_beats = _machine->run(_cycle_time); + const TickCount run_dur_ticks = _cycle_time.beats_to_ticks(run_dur_beats); // Machine didn't run at all (empty, or no initial states) - if (run_duration == 0) { + if (run_dur_ticks == 0) { _machine->reset(); // Try again next cycle - _current_cycle_start = 0; + _cycle_time.set_start(0); return; - } - // Machine ran for portion of cycle - else if (run_duration < _current_cycle_nframes) { - const Timestamp finish_time = _machine->time(); - const FrameCount finish_offset = stamp_to_offset(finish_time); - - if (finish_offset >= _current_cycle_nframes) - break; - - _current_cycle_offset = stamp_to_offset(finish_time); - _current_cycle_nframes -= _current_cycle_offset; - _current_cycle_start = 0; + // Machine ran for portion of cycle (finished) + } else if (run_dur_ticks < _cycle_time.length_ticks()) { + const TickCount finish_offset = _cycle_time.offset_ticks() + run_dur_ticks; + assert(finish_offset < nframes); + + _cycle_time.set_start(0); + _cycle_time.set_length(nframes - finish_offset); + _cycle_time.set_offset(finish_offset); + _machine->reset(); // Machine ran for entire cycle } else { - if (_machine->is_finished()) + if (_machine->is_finished()) { _machine->reset(); + _cycle_time.set_start(0); + } else { + _cycle_time.set_start( + _cycle_time.start_ticks() + _cycle_time.length_ticks()); + } - _current_cycle_start += _current_cycle_nframes; break; } } diff --git a/src/engine/JackNodeFactory.cpp b/src/engine/JackNodeFactory.cpp deleted file mode 100644 index 826d205..0000000 --- a/src/engine/JackNodeFactory.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* This file is part of Machina. - * Copyright (C) 2007 Dave Robillard <http://drobilla.net> - * - * 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 2 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "machina/JackNodeFactory.hpp" -#include "machina/MidiAction.hpp" -#include "machina/Node.hpp" -#include "machina/JackDriver.hpp" - -namespace Machina { - - -SharedPtr<Node> -JackNodeFactory::create_node(Node::ID, byte /*note*/, FrameCount duration) -{ - // FIXME: obviously leaks like a sieve - - //size_t event_size = 3; - //static const byte note_on[3] = { 0x80, note, 0x40 }; - - Node* n = new Node(duration); - /*SharedPtr<MidiAction> a_enter = MidiAction::create(event_size, note_on); - - - static const byte note_off[3] = { 0x90, note, 0x40 }; - SharedPtr<MidiAction> a_exit = MidiAction::create(event_size, note_off); - - n->add_enter_action(a_enter); - n->add_exit_action(a_exit); -*/ - return SharedPtr<Node>(n); -} - - -} // namespace Machina - diff --git a/src/engine/Loader.cpp b/src/engine/Loader.cpp index 3b58537..ec884eb 100644 --- a/src/engine/Loader.cpp +++ b/src/engine/Loader.cpp @@ -25,7 +25,6 @@ #include "machina/Node.hpp" #include "machina/Edge.hpp" #include "machina/Machine.hpp" -#include "machina/NodeFactory.hpp" using namespace Raul; using std::cerr; using std::cout; using std::endl; @@ -33,29 +32,8 @@ using std::cerr; using std::cout; using std::endl; namespace Machina { -/* -// FIXME: remove -Node* create_debug_node(const Node::ID& id, FrameCount duration) -{ - // leaks like a sieve, obviously - - Node* n = new Node(duration); - PrintAction* a_enter = new PrintAction(string("\t> ") + id); - PrintAction* a_exit = new PrintAction(string("\t< ") + id); - - n->add_enter_action(a_enter); - n->add_exit_action(a_exit); - - cerr << "dur: " << duration << endl; - - return n; -} -*/ - -Loader::Loader(SharedPtr<NodeFactory> node_factory, - SharedPtr<Namespaces> namespaces) - : _node_factory(node_factory) - , _namespaces(namespaces) +Loader::Loader(SharedPtr<Namespaces> namespaces) + : _namespaces(namespaces) { if (!_namespaces) _namespaces = SharedPtr<Namespaces>(new Namespaces()); @@ -123,16 +101,19 @@ Loader::load(const Glib::ustring& filename) //cout << "Initial: " << node_name << ": " << midi_note << " - " << duration << endl; + cerr << "FIXME: load\n"; +/* SharedPtr<Node> node = SharedPtr<Node>(_node_factory->create_node( node_name, strtol(midi_note.c_str(), NULL, 10), strtol(duration.c_str(), NULL, 10))); - + node->set_initial(true); //machine->add_node(string(node_name).substr(1), node); // (chop leading "#") machine->add_node(node); created.insert(std::make_pair(node_uri.collate_key(), node)); + */ raptor_free_uri(node_raptor_uri); free(node_name); @@ -163,18 +144,21 @@ Loader::load(const Glib::ustring& filename) raptor_uri_to_relative_uri_string(document_raptor_uri, node_raptor_uri); + cerr << "FIXME: load (2)\n"; + /* SharedPtr<Node> node = SharedPtr<Node>(_node_factory->create_node( node_name, strtol(midi_note.c_str(), NULL, 10), strtol(duration.c_str(), NULL, 10))); + if (created.find(node_uri) == created.end()) { //cout << "Node: " << node_name << ": " << midi_note << " - " << duration << endl; //machine->add_node(string(node_name).substr(1), node); // (chop leading "#") machine->add_node(node); created.insert(std::make_pair(node_uri.collate_key(), node)); } - + */ raptor_free_uri(node_raptor_uri); free(node_name); } diff --git a/src/engine/Machine.cpp b/src/engine/Machine.cpp index 142ea37..bbe343c 100644 --- a/src/engine/Machine.cpp +++ b/src/engine/Machine.cpp @@ -110,8 +110,8 @@ Machine::exit_node(const SharedPtr<Node> node) * machine actually finished on (so it can be restarted immediately * with sample accuracy if necessary). */ -FrameCount -Machine::run(FrameCount nframes) +BeatCount +Machine::run(const Raul::TimeSlice& time) { using namespace std; if (_is_finished) { @@ -119,7 +119,7 @@ Machine::run(FrameCount nframes) return 0; } - const FrameCount cycle_end = _time + nframes; + const BeatCount cycle_end = _time + time.length_beats(); //std::cerr << "Start: " << _time << std::endl; @@ -146,7 +146,7 @@ Machine::run(FrameCount nframes) } } - FrameCount this_time = 0; + BeatCount this_time = 0; while (true) { @@ -166,7 +166,7 @@ Machine::run(FrameCount nframes) // Earliest active state ends in the future, done this cycle } else { _time = cycle_end; - this_time = nframes; // ran the entire cycle + this_time = time.length_beats(); // ran the entire cycle break; } @@ -174,7 +174,7 @@ Machine::run(FrameCount nframes) //std::cerr << "Done: " << this_time << std::endl; - assert(this_time <= nframes); + assert(this_time <= time.length_beats()); return this_time; } diff --git a/src/engine/Makefile.am b/src/engine/Makefile.am index c21935f..833d39c 100644 --- a/src/engine/Makefile.am +++ b/src/engine/Makefile.am @@ -14,4 +14,4 @@ libmachina_la_SOURCES = \ MidiAction.cpp \ JackDriver.h \ JackDriver.cpp \ - JackNodeFactory.cpp + Engine.cpp diff --git a/src/engine/MidiAction.cpp b/src/engine/MidiAction.cpp index aca4b75..b1dfa95 100644 --- a/src/engine/MidiAction.cpp +++ b/src/engine/MidiAction.cpp @@ -91,18 +91,16 @@ MidiAction::set_event(size_t size, const byte* new_event) * Safe to call concurrently with set_event. */ void -MidiAction::execute(Timestamp time) +MidiAction::execute(Raul::BeatTime time) { const byte* const event = _event.get(); - using namespace std; - if (event) { SharedPtr<MidiDriver> driver = _driver.lock(); if (driver) driver->write_event(time, _size, event); } else { - cerr << "NULL MIDI ACTION"; + std::cerr << "NULL MIDI ACTION"; } } diff --git a/src/engine/Node.cpp b/src/engine/Node.cpp index c0e0ce6..a7aa453 100644 --- a/src/engine/Node.cpp +++ b/src/engine/Node.cpp @@ -23,7 +23,7 @@ namespace Machina { -Node::Node(FrameCount duration, bool initial) +Node::Node(BeatCount duration, bool initial) : _is_initial(initial) , _is_active(false) , _enter_time(0) @@ -63,7 +63,7 @@ Node::remove_exit_action(SharedPtr<Action> /*action*/) //using namespace std; void -Node::enter(Timestamp time) +Node::enter(BeatTime time) { //cerr << "ENTER " << time << endl; _is_active = true; @@ -74,7 +74,7 @@ Node::enter(Timestamp time) void -Node::exit(Timestamp time) +Node::exit(BeatTime time) { //cerr << "EXIT " << time << endl; if (_exit_action) @@ -111,7 +111,7 @@ Node::write_state(Raul::RDFWriter& writer) writer.write(_id, RdfId(RdfId::RESOURCE, "machina:duration"), - Raul::Atom((int)_duration)); + Raul::Atom((float)_duration)); } diff --git a/src/engine/machina/Action.hpp b/src/engine/machina/Action.hpp index 984a1a0..2bffaa3 100644 --- a/src/engine/machina/Action.hpp +++ b/src/engine/machina/Action.hpp @@ -21,17 +21,16 @@ #include <string> #include <iostream> #include <raul/Deletable.h> +#include <raul/TimeSlice.h> #include "types.hpp" namespace Machina { /** An Action, executed on entering or exiting of a state. - * - * Actions do not have time as a property. */ struct Action : public Raul::Deletable { - virtual void execute(Timestamp /*time*/) {} + virtual void execute(Raul::BeatTime /*time*/) {} }; @@ -39,7 +38,8 @@ class PrintAction : public Action { public: PrintAction(const std::string& msg) : _msg(msg) {} - void execute(Timestamp time) { std::cout << "t=" << time << ": " << _msg << std::endl; } + void execute(Raul::BeatTime time) + { std::cout << "t=" << time << ": " << _msg << std::endl; } private: std::string _msg; diff --git a/src/engine/machina/JackNodeFactory.hpp b/src/engine/machina/Engine.hpp index 017cc6d..fcb75d3 100644 --- a/src/engine/machina/JackNodeFactory.hpp +++ b/src/engine/machina/Engine.hpp @@ -12,32 +12,40 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#ifndef MACHINA_JACKNODEFACTORY_HPP -#define MACHINA_JACKNODEFACTORY_HPP +#ifndef MACHINA_ENGINE_HPP +#define MACHINA_ENGINE_HPP -#include <raul/WeakPtr.h> -#include "NodeFactory.hpp" +#include <raul/SharedPtr.h> namespace Machina { +class Machine; class JackDriver; -class JackNodeFactory : public NodeFactory { +class Engine { public: - JackNodeFactory(WeakPtr<JackDriver> driver) : _driver(driver) {} + Engine(SharedPtr<JackDriver> driver, SharedPtr<Machine> machine) + : _driver(driver) + , _machine(machine) + {} + + SharedPtr<JackDriver> driver() { return _driver; } + SharedPtr<Machine> machine() { return _machine; } + + void set_bpm(double bpm); + + void set_quantization(double beat_fraction); - SharedPtr<Node> create_node(Node::ID id, - unsigned char note, - FrameCount duration); private: - WeakPtr<JackDriver> _driver; + SharedPtr<JackDriver> _driver; + SharedPtr<Machine> _machine; }; } // namespace Machina -#endif // MACHINA_JACKNODEFACTORY_HPP +#endif // MACHINA_ENGINE_HPP diff --git a/src/engine/machina/JackDriver.hpp b/src/engine/machina/JackDriver.hpp index e1f809f..e52af88 100644 --- a/src/engine/machina/JackDriver.hpp +++ b/src/engine/machina/JackDriver.hpp @@ -20,6 +20,7 @@ #include <raul/JackDriver.h> #include <raul/SharedPtr.h> +#include <raul/DoubleBuffer.h> #include <jack/midiport.h> #include "Machine.hpp" #include "MidiDriver.hpp" @@ -46,19 +47,13 @@ public: void set_machine(SharedPtr<Machine> machine) { _machine = machine; } - // Audio context - Timestamp cycle_start() { return _current_cycle_start; } - FrameCount cycle_length() { return _current_cycle_nframes; } - - void write_event(Timestamp time, + void write_event(Raul::BeatTime time, size_t size, const unsigned char* event); -private: - // Audio context - Timestamp subcycle_offset() { return _current_cycle_offset; } - Timestamp stamp_to_offset(Timestamp stamp); + void set_bpm(double bpm) { _bpm.set(bpm); } +private: void process_input(jack_nframes_t nframes); virtual void on_process(jack_nframes_t nframes); @@ -66,9 +61,10 @@ private: jack_port_t* _input_port; jack_port_t* _output_port; - Timestamp _current_cycle_start; ///< in machine relative time - Timestamp _current_cycle_offset; ///< for split cycles - FrameCount _current_cycle_nframes; + + Raul::TimeSlice _cycle_time; + + Raul::DoubleBuffer<double> _bpm; }; diff --git a/src/engine/machina/LearnRequest.hpp b/src/engine/machina/LearnRequest.hpp index 60f1b27..f485560 100644 --- a/src/engine/machina/LearnRequest.hpp +++ b/src/engine/machina/LearnRequest.hpp @@ -44,7 +44,7 @@ public: } // Add the learned actions to the node - void finish(Timestamp time) + void finish(BeatTime time) { _node->add_enter_action(_enter_action); _node->add_exit_action(_exit_action); @@ -52,8 +52,8 @@ public: std::cerr << "LEARN DURATION: " << _node->duration() << std::endl; } - void start(Timestamp time) { _started = true; _start_time = time; } - bool started() { return _started; } + void start(BeatTime time) { _started = true; _start_time = time; } + bool started() { return _started; } const SharedPtr<Node>& node() { return _node; } const SharedPtr<MidiAction>& enter_action() { return _enter_action; } @@ -69,7 +69,7 @@ private: } bool _started; - Timestamp _start_time; + BeatTime _start_time; SharedPtr<Node> _node; SharedPtr<MidiAction> _enter_action; SharedPtr<MidiAction> _exit_action; diff --git a/src/engine/machina/Loader.hpp b/src/engine/machina/Loader.hpp index c3ce013..af35c56 100644 --- a/src/engine/machina/Loader.hpp +++ b/src/engine/machina/Loader.hpp @@ -28,18 +28,15 @@ using Raul::Namespaces; namespace Machina { class Machine; -class NodeFactory; class Loader { public: - Loader(SharedPtr<NodeFactory> node_factory, - SharedPtr<Namespaces> = SharedPtr<Namespaces>()); + Loader(SharedPtr<Namespaces> = SharedPtr<Namespaces>()); SharedPtr<Machine> load(const Glib::ustring& filename); private: - SharedPtr<NodeFactory> _node_factory; SharedPtr<Namespaces> _namespaces; }; diff --git a/src/engine/machina/Machine.hpp b/src/engine/machina/Machine.hpp index 3e63530..a7b92c8 100644 --- a/src/engine/machina/Machine.hpp +++ b/src/engine/machina/Machine.hpp @@ -21,6 +21,7 @@ #include <raul/SharedPtr.h> #include <raul/List.h> #include <raul/RDFWriter.h> +#include <raul/TimeSlice.h> #include "types.hpp" #include "LearnRequest.hpp" #include "Node.hpp" @@ -46,12 +47,11 @@ public: void write_state(Raul::RDFWriter& writer); // Audio context - void reset(); - FrameCount run(FrameCount nframes); + void reset(); + BeatCount run(const Raul::TimeSlice& time); // Any context - FrameCount time() { return _time; } - + Raul::BeatTime time() { return _time; } //LearnRequest pop_learn() { return _pending_learns.pop_front(); } //SharedPtr<LearnRequest> first_learn() { return *_pending_learns.begin(); } @@ -65,10 +65,10 @@ private: SharedPtr<Node> earliest_node() const; void exit_node(const SharedPtr<Node>); - bool _is_activated; - bool _is_finished; - FrameCount _time; - Nodes _nodes; + bool _is_activated; + bool _is_finished; + Raul::BeatTime _time; + Nodes _nodes; //Raul::List<SharedPtr<LearnRequest> > _pending_learns; SharedPtr<LearnRequest> _pending_learn; diff --git a/src/engine/machina/Makefile.am b/src/engine/machina/Makefile.am index 7bdd1fd..1e8c6c3 100644 --- a/src/engine/machina/Makefile.am +++ b/src/engine/machina/Makefile.am @@ -7,8 +7,7 @@ libmachinainclude_HEADERS = \ Machine.hpp \ Loader.hpp \ JackDriver.hpp \ - NodeFactory.hpp \ - JackNodeFactory.hpp \ MidiAction.hpp \ MidiDriver.hpp \ - LearnRequest.hpp + LearnRequest.hpp \ + Engine.hpp diff --git a/src/engine/machina/MidiAction.hpp b/src/engine/machina/MidiAction.hpp index 7dff692..6467659 100644 --- a/src/engine/machina/MidiAction.hpp +++ b/src/engine/machina/MidiAction.hpp @@ -21,6 +21,7 @@ #include <raul/Maid.h> #include <raul/WeakPtr.h> #include <raul/AtomicPtr.h> +#include <raul/TimeSlice.h> #include "types.hpp" #include "Action.hpp" @@ -46,7 +47,7 @@ public: bool set_event(size_t size, const byte* event); - void execute(Timestamp time); + void execute(Raul::BeatTime time); private: MidiAction(size_t size, diff --git a/src/engine/machina/MidiDriver.hpp b/src/engine/machina/MidiDriver.hpp index 7f6dca1..a4d9f51 100644 --- a/src/engine/machina/MidiDriver.hpp +++ b/src/engine/machina/MidiDriver.hpp @@ -30,20 +30,20 @@ public: virtual ~MidiDriver() {} /** Emit a MIDI event at the given time */ - virtual void write_event(Timestamp time, + virtual void write_event(Raul::BeatTime time, size_t size, const unsigned char* event) = 0; /** Beginning of current cycle in absolute time. */ - virtual Timestamp cycle_start() = 0; + //virtual Raul::TickTime cycle_start() = 0; /** Length of current cycle in ticks. * * A "tick" is the smallest recognizable unit of (discrete) time. * Ticks could be single audio frames, MIDI clock at a certain ppqn, etc. */ - virtual FrameCount cycle_length() = 0; + //virtual Raul::TickCount cycle_length() = 0; }; diff --git a/src/engine/machina/Node.hpp b/src/engine/machina/Node.hpp index 10d4ed4..c4d9dee 100644 --- a/src/engine/machina/Node.hpp +++ b/src/engine/machina/Node.hpp @@ -22,12 +22,14 @@ #include <raul/SharedPtr.h> #include <raul/List.h> #include <raul/Stateful.h> -#include "types.hpp" +#include <raul/TimeSlice.h> #include "Action.hpp" namespace Machina { class Edge; +using Raul::BeatCount; +using Raul::BeatTime; /** A node is a state (as in a FSM diagram), or "note". @@ -42,7 +44,7 @@ class Node : public Raul::Stateful, public boost::noncopyable { public: typedef std::string ID; - Node(FrameCount duration=0, bool initial=false); + Node(BeatCount duration=0, bool initial=false); void add_enter_action(SharedPtr<Action> action); void remove_enter_action(SharedPtr<Action> action); @@ -50,21 +52,21 @@ public: void add_exit_action(SharedPtr<Action> action); void remove_exit_action(SharedPtr<Action> action); - void enter(Timestamp time); - void exit(Timestamp time); + void enter(BeatTime time); + void exit(BeatTime time); void add_outgoing_edge(SharedPtr<Edge> edge); void remove_outgoing_edge(SharedPtr<Edge> edge); void write_state(Raul::RDFWriter& writer); - bool is_initial() const { return _is_initial; } - void set_initial(bool i) { _is_initial = i; } - bool is_active() const { return _is_active; } - Timestamp enter_time() const { return _enter_time; } - Timestamp exit_time() const { return _enter_time + _duration; } - FrameCount duration() { return _duration; } - void set_duration(FrameCount d) { _duration = d; } + bool is_initial() const { return _is_initial; } + void set_initial(bool i) { _is_initial = i; } + bool is_active() const { return _is_active; } + BeatTime enter_time() const { return _enter_time; } + BeatTime exit_time() const { return _enter_time + _duration; } + BeatCount duration() { return _duration; } + void set_duration(BeatCount d) { _duration = d; } typedef Raul::List<SharedPtr<Edge> > EdgeList; const EdgeList& outgoing_edges() const { return _outgoing_edges; } @@ -72,8 +74,8 @@ public: private: bool _is_initial; bool _is_active; - Timestamp _enter_time; ///< valid iff _is_active - FrameCount _duration; + BeatTime _enter_time; ///< valid iff _is_active + BeatCount _duration; SharedPtr<Action> _enter_action; SharedPtr<Action> _exit_action; EdgeList _outgoing_edges; diff --git a/src/engine/machina/NodeFactory.hpp b/src/engine/machina/NodeFactory.hpp deleted file mode 100644 index f38fd92..0000000 --- a/src/engine/machina/NodeFactory.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* This file is part of Machina. - * Copyright (C) 2007 Dave Robillard <http://drobilla.net> - * - * 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 2 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef MACHINA_NODEFACTORY_HPP -#define MACHINA_NODEFACTORY_HPP - -#include <raul/SharedPtr.h> -#include "types.hpp" -#include "Node.hpp" - -namespace Machina { - - -class NodeFactory { -public: - virtual ~NodeFactory() {} - - virtual SharedPtr<Node> create_node(Node::ID id, - unsigned char note, - FrameCount duration) = 0; -}; - - -} // namespace Machina - -#endif // MACHINA_NODEFACTORY_HPP diff --git a/src/engine/machina/types.hpp b/src/engine/machina/types.hpp index 1236f65..70eae7d 100644 --- a/src/engine/machina/types.hpp +++ b/src/engine/machina/types.hpp @@ -23,8 +23,8 @@ namespace Machina { -typedef jack_nframes_t FrameCount; -typedef jack_nframes_t Timestamp; +//typedef jack_nframes_t FrameCount; +//typedef jack_nframes_t Timestamp; typedef unsigned char byte; diff --git a/src/gui/EdgeView.cpp b/src/gui/EdgeView.cpp index e681f26..3b5b8ec 100644 --- a/src/gui/EdgeView.cpp +++ b/src/gui/EdgeView.cpp @@ -62,6 +62,5 @@ EdgeView::on_event(GdkEvent* ev) } } - cerr << "NO BUTTON\n"; return false; } diff --git a/src/gui/MachinaCanvas.cpp b/src/gui/MachinaCanvas.cpp index 5029682..26ce935 100644 --- a/src/gui/MachinaCanvas.cpp +++ b/src/gui/MachinaCanvas.cpp @@ -93,7 +93,7 @@ MachinaCanvas::canvas_event(GdkEvent* event) if (event->button.button == 1) { string name = string("Note")+(char)(last++ +'0'); - SharedPtr<Machina::Node> node(new Machina::Node(1024*10, false)); + SharedPtr<Machina::Node> node(new Machina::Node(1.0, false)); //node->add_enter_action(SharedPtr<Machina::Action>(new Machina::PrintAction(name))); SharedPtr<NodeView> view(new NodeView(node, shared_from_this(), name, x, y)); diff --git a/src/gui/MachinaGUI.cpp b/src/gui/MachinaGUI.cpp index 546bf7d..9fa0dbb 100644 --- a/src/gui/MachinaGUI.cpp +++ b/src/gui/MachinaGUI.cpp @@ -68,12 +68,12 @@ gtkmm_set_width_for_given_text (Gtk::Widget &w, const gchar *text, -MachinaGUI::MachinaGUI(SharedPtr<Machina::Machine> machine) +MachinaGUI::MachinaGUI(SharedPtr<Machina::Engine> engine) : _pane_closed(false), _update_pane_position(true), _user_pane_position(0), _refresh(false), - _machine(machine), + _engine(engine), _maid(new Raul::Maid(32)) { /*_settings_filename = getenv("HOME"); @@ -109,10 +109,12 @@ MachinaGUI::MachinaGUI(SharedPtr<Machina::Machine> machine) xml->get_widget("machina_win", _main_window); xml->get_widget("about_win", _about_window); xml->get_widget("help_dialog", _help_dialog); + xml->get_widget("toolbar", _toolbar); xml->get_widget("open_menuitem", _menu_file_open); xml->get_widget("save_menuitem", _menu_file_save); xml->get_widget("save_as_menuitem", _menu_file_save_as); xml->get_widget("quit_menuitem", _menu_file_quit); + xml->get_widget("view_toolbar_menuitem", _menu_view_toolbar); xml->get_widget("view_refresh_menuitem", _menu_view_refresh); xml->get_widget("view_messages_menuitem", _menu_view_messages); xml->get_widget("help_about_menuitem", _menu_help_about); @@ -121,6 +123,11 @@ MachinaGUI::MachinaGUI(SharedPtr<Machina::Machine> machine) xml->get_widget("status_text", _status_text); xml->get_widget("main_paned", _main_paned); xml->get_widget("messages_expander", _messages_expander); + xml->get_widget("slave_radiobutton", _slave_radiobutton); + xml->get_widget("bpm_radiobutton", _bpm_radiobutton); + xml->get_widget("bpm_spinbutton", _bpm_spinbutton); + xml->get_widget("quantize_checkbutton", _quantize_checkbutton); + xml->get_widget("quantize_spinbutton", _quantize_spinbutton); xml->get_widget("zoom_full_but", _zoom_full_button); xml->get_widget("zoom_normal_but", _zoom_normal_button); @@ -136,14 +143,32 @@ MachinaGUI::MachinaGUI(SharedPtr<Machina::Machine> machine) _zoom_full_button->signal_clicked().connect(sigc::mem_fun(_canvas.get(), &MachinaCanvas::zoom_full)); - _menu_file_open->signal_activate().connect( sigc::mem_fun(this, &MachinaGUI::menu_file_open)); - _menu_file_save->signal_activate().connect( sigc::mem_fun(this, &MachinaGUI::menu_file_save)); - _menu_file_save_as->signal_activate().connect( sigc::mem_fun(this, &MachinaGUI::menu_file_save_as)); - _menu_file_quit->signal_activate().connect( sigc::mem_fun(this, &MachinaGUI::menu_file_quit)); - _menu_view_refresh->signal_activate().connect( sigc::mem_fun(this, &MachinaGUI::menu_view_refresh)); - _menu_view_messages->signal_toggled().connect( sigc::mem_fun(this, &MachinaGUI::show_messages_toggled)); - _menu_help_about->signal_activate().connect( sigc::mem_fun(this, &MachinaGUI::menu_help_about)); - _menu_help_help->signal_activate().connect( sigc::mem_fun(this, &MachinaGUI::menu_help_help)); + _menu_file_open->signal_activate().connect( + sigc::mem_fun(this, &MachinaGUI::menu_file_open)); + _menu_file_save->signal_activate().connect( + sigc::mem_fun(this, &MachinaGUI::menu_file_save)); + _menu_file_save_as->signal_activate().connect( + sigc::mem_fun(this, &MachinaGUI::menu_file_save_as)); + _menu_file_quit->signal_activate().connect( + sigc::mem_fun(this, &MachinaGUI::menu_file_quit)); + _menu_view_refresh->signal_activate().connect( + sigc::mem_fun(this, &MachinaGUI::menu_view_refresh)); + _menu_view_toolbar->signal_toggled().connect( + sigc::mem_fun(this, &MachinaGUI::show_toolbar_toggled)); + _menu_view_messages->signal_toggled().connect( + sigc::mem_fun(this, &MachinaGUI::show_messages_toggled)); + _menu_help_about->signal_activate().connect( + sigc::mem_fun(this, &MachinaGUI::menu_help_about)); + _menu_help_help->signal_activate().connect( + sigc::mem_fun(this, &MachinaGUI::menu_help_help)); + _slave_radiobutton->signal_toggled().connect( + sigc::mem_fun(this, &MachinaGUI::tempo_changed)); + _bpm_radiobutton->signal_toggled().connect( + sigc::mem_fun(this, &MachinaGUI::tempo_changed)); + _bpm_spinbutton->signal_changed().connect( + sigc::mem_fun(this, &MachinaGUI::tempo_changed)); + _quantize_checkbutton->signal_toggled().connect( + sigc::mem_fun(this, &MachinaGUI::quantize_changed)); connect_widgets(); @@ -167,6 +192,8 @@ MachinaGUI::MachinaGUI(SharedPtr<Machina::Machine> machine) _update_pane_position = true; _pane_closed = true; + _bpm_radiobutton->set_active(true); + // Idle callback to drive the maid (collect garbage) Glib::signal_timeout().connect( sigc::bind_return( @@ -216,6 +243,28 @@ MachinaGUI::idle_callback() void +MachinaGUI::update_toolbar() +{ + _bpm_spinbutton->set_sensitive(_bpm_radiobutton->get_active()); + _quantize_spinbutton->set_sensitive(_quantize_checkbutton->get_active()); +} + + +void +MachinaGUI::quantize_changed() +{ + _engine->set_quantization(1.0/(double)_quantize_spinbutton->get_value_as_int()); +} + + +void +MachinaGUI::tempo_changed() +{ + _engine->set_bpm(_bpm_spinbutton->get_value_as_int()); +} + + +void MachinaGUI::zoom(double z) { _canvas->set_zoom(z); @@ -308,7 +357,7 @@ MachinaGUI::menu_file_save() Raul::RDFWriter writer; writer.start_to_filename("test.machina.ttl"); - _machine->write_state(writer); + machine()->write_state(writer); writer.finish();} @@ -379,6 +428,16 @@ MachinaGUI::show_messages_toggled() void +MachinaGUI::show_toolbar_toggled() +{ + if (_menu_view_toolbar->get_active()) + _toolbar->show(); + else + _toolbar->hide(); +} + + +void MachinaGUI::menu_view_refresh() { assert(_canvas); diff --git a/src/gui/MachinaGUI.hpp b/src/gui/MachinaGUI.hpp index a9ae5e5..ccf7557 100644 --- a/src/gui/MachinaGUI.hpp +++ b/src/gui/MachinaGUI.hpp @@ -22,21 +22,22 @@ #include <raul/SharedPtr.h> #include <raul/Maid.h> #include <libgnomecanvasmm.h> +#include <machina/Engine.hpp> using namespace std; -namespace Machina { class Machine; } +namespace Machina { class Machine; class Engine; } class MachinaCanvas; class MachinaGUI { public: - MachinaGUI(SharedPtr<Machina::Machine> machine); + MachinaGUI(SharedPtr<Machina::Engine> engine); ~MachinaGUI(); boost::shared_ptr<MachinaCanvas> canvas() { return _canvas; } - boost::shared_ptr<Machina::Machine> machine() { return _machine; } + boost::shared_ptr<Machina::Machine> machine() { return _engine->machine(); } SharedPtr<Raul::Maid> maid() { return _maid; } @@ -59,15 +60,20 @@ protected: void menu_file_save(); void menu_file_save_as(); void show_messages_toggled(); + void show_toolbar_toggled(); void menu_view_refresh(); void menu_help_about(); void menu_help_help(); void zoom(double z); void zoom_changed(); bool idle_callback(); + void update_toolbar(); void on_pane_position_changed(); void on_messages_expander_changed(); + + void quantize_changed(); + void tempo_changed(); bool _pane_closed; bool _update_pane_position; @@ -75,8 +81,8 @@ protected: bool _refresh; - boost::shared_ptr<MachinaCanvas> _canvas; - boost::shared_ptr<Machina::Machine> _machine; + boost::shared_ptr<MachinaCanvas> _canvas; + boost::shared_ptr<Machina::Engine> _engine; SharedPtr<Raul::Maid> _maid; @@ -85,11 +91,13 @@ protected: Gtk::Window* _main_window; Gtk::Dialog* _help_dialog; Gtk::AboutDialog* _about_window; + Gtk::Toolbar* _toolbar; Gtk::MenuItem* _menu_file_open; Gtk::MenuItem* _menu_file_save; Gtk::MenuItem* _menu_file_save_as; Gtk::MenuItem* _menu_file_quit; Gtk::MenuItem* _menu_help_about; + Gtk::CheckMenuItem* _menu_view_toolbar; Gtk::CheckMenuItem* _menu_view_messages; Gtk::MenuItem* _menu_view_refresh; Gtk::MenuItem* _menu_help_help; @@ -97,6 +105,11 @@ protected: Gtk::TextView* _status_text; Gtk::Paned* _main_paned; Gtk::Expander* _messages_expander; + Gtk::RadioButton* _slave_radiobutton; + Gtk::RadioButton* _bpm_radiobutton; + Gtk::SpinButton* _bpm_spinbutton; + Gtk::CheckButton* _quantize_checkbutton; + Gtk::SpinButton* _quantize_spinbutton; Gtk::ToolButton* _zoom_normal_button; Gtk::ToolButton* _zoom_full_button; }; diff --git a/src/gui/machina.glade b/src/gui/machina.glade index b319dab..f255d9f 100644 --- a/src/gui/machina.glade +++ b/src/gui/machina.glade @@ -99,6 +99,17 @@ <widget class="GtkMenu" id="view_menu_menu"> <child> + <widget class="GtkCheckMenuItem" id="view_toolbar_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Toolbar</property> + <property name="use_underline">True</property> + <property name="active">False</property> + <signal name="activate" handler="on_toolbar2_activate" last_modification_time="Tue, 20 Feb 2007 22:56:06 GMT"/> + <accelerator key="T" modifiers="GDK_CONTROL_MASK" signal="activate"/> + </widget> + </child> + + <child> <widget class="GtkCheckMenuItem" id="view_messages_menuitem"> <property name="visible">True</property> <property name="tooltip" translatable="yes">View "console" messages</property> @@ -175,7 +186,7 @@ </child> <child> - <widget class="GtkToolbar" id="toolbar1"> + <widget class="GtkToolbar" id="toolbar"> <property name="visible">True</property> <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property> <property name="toolbar_style">GTK_TOOLBAR_BOTH_HORIZ</property> @@ -183,8 +194,177 @@ <property name="show_arrow">True</property> <child> + <widget class="GtkToolItem" id="toolitem1"> + <property name="visible">True</property> + <property name="visible_horizontal">True</property> + <property name="visible_vertical">True</property> + <property name="is_important">False</property> + + <child> + <widget class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="slave_radiobutton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Slave</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="bpm_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">BPM: </property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">True</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">slave_radiobutton</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="bpm_spinbutton"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Set internal tempo</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">120 1 640 1 10 10</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> + </child> + + <child> + <widget class="GtkSeparatorToolItem" id="separatortoolitem2"> + <property name="visible">True</property> + <property name="draw">True</property> + <property name="visible_horizontal">True</property> + <property name="visible_vertical">True</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> + </child> + + <child> + <widget class="GtkToolItem" id="toolitem2"> + <property name="visible">True</property> + <property name="visible_horizontal">True</property> + <property name="visible_vertical">True</property> + <property name="is_important">False</property> + + <child> + <widget class="GtkHBox" id="hbox2"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkCheckButton" id="quantize_checkbutton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Quantize: 1/</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="quantize_spinbutton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 1 99 1 4 4</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> + </child> + + <child> + <widget class="GtkSeparatorToolItem" id="separatortoolitem3"> + <property name="visible">True</property> + <property name="draw">True</property> + <property name="visible_horizontal">True</property> + <property name="visible_vertical">True</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> + </child> + + <child> <widget class="GtkToolButton" id="zoom_normal_but"> <property name="visible">True</property> + <property name="tooltip" translatable="yes">Zoom to normal size</property> <property name="stock_id">gtk-zoom-100</property> <property name="visible_horizontal">True</property> <property name="visible_vertical">True</property> @@ -199,6 +379,7 @@ <child> <widget class="GtkToolButton" id="zoom_full_but"> <property name="visible">True</property> + <property name="tooltip" translatable="yes">Zoom to fit entire machine</property> <property name="stock_id">gtk-zoom-fit</property> <property name="visible_horizontal">True</property> <property name="visible_vertical">True</property> @@ -226,6 +407,8 @@ <child> <widget class="GtkScrolledWindow" id="canvas_scrolledwindow"> <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> <property name="can_focus">True</property> <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property> <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property> diff --git a/src/gui/main.cpp b/src/gui/main.cpp index 364fe17..d6c846e 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -15,15 +15,12 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -//#include "../../config.h" - #include <signal.h> #include <iostream> #include <libgnomecanvasmm.h> #include "machina/Loader.hpp" #include "machina/JackDriver.hpp" -#include "machina/JackNodeFactory.hpp" #include "MachinaGUI.hpp" @@ -46,6 +43,7 @@ main(int argc, char** argv) driver->set_machine(m); driver->attach("machina"); + SharedPtr<Engine> engine(new Engine(driver, m)); // Launch GUI try { @@ -53,7 +51,7 @@ main(int argc, char** argv) Gnome::Canvas::init(); Gtk::Main app(argc, argv); - MachinaGUI gui(m); + MachinaGUI gui(engine); app.run(*gui.window()); } catch (std::string msg) { diff --git a/src/main.cpp b/src/main.cpp index d3a0e57..4284456 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,13 +17,13 @@ #include <iostream> #include <signal.h> +#include "machina/Engine.hpp" #include "machina/Machine.hpp" #include "machina/Node.hpp" #include "machina/Action.hpp" #include "machina/Edge.hpp" #include "machina/Loader.hpp" #include "machina/JackDriver.hpp" -#include "machina/JackNodeFactory.hpp" #include "machina/MidiAction.hpp" using namespace std; @@ -54,16 +54,16 @@ main(int argc, char** argv) } SharedPtr<JackDriver> driver(new JackDriver()); - SharedPtr<NodeFactory> factory(new JackNodeFactory(driver)); - MidiAction::set_driver(driver); - Loader l(factory); + Loader l; SharedPtr<Machine> m = l.load(argv[1]); m->activate(); + Engine engine(driver, m); + driver->set_machine(m); driver->attach("machina"); |