diff options
author | David Robillard <d@drobilla.net> | 2007-02-10 07:30:56 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2007-02-10 07:30:56 +0000 |
commit | cee33ba4c0859b117be94df6ccbf3eb756a850af (patch) | |
tree | e7e69de57c531538b2ded16bac31c2c705bc0fa6 /src | |
parent | 87c0a475bd76ca33883eeafc2a86bc89a84eec2f (diff) | |
download | machina-cee33ba4c0859b117be94df6ccbf3eb756a850af.tar.gz machina-cee33ba4c0859b117be94df6ccbf3eb756a850af.tar.bz2 machina-cee33ba4c0859b117be94df6ccbf3eb756a850af.zip |
Finished MIDI genericification.
Work on MIDI learn.
git-svn-id: http://svn.drobilla.net/lad/machina@299 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r-- | src/engine/JackDriver.cpp | 59 | ||||
-rw-r--r-- | src/engine/JackNodeFactory.cpp | 17 | ||||
-rw-r--r-- | src/engine/Machine.cpp | 16 | ||||
-rw-r--r-- | src/engine/Makefile.am | 2 | ||||
-rw-r--r-- | src/engine/MidiAction.cpp | 101 | ||||
-rw-r--r-- | src/engine/MidiActions.cpp | 60 | ||||
-rw-r--r-- | src/engine/machina/Action.hpp | 4 | ||||
-rw-r--r-- | src/engine/machina/JackDriver.hpp | 34 | ||||
-rw-r--r-- | src/engine/machina/Machine.hpp | 5 | ||||
-rw-r--r-- | src/engine/machina/MidiAction.hpp | 18 | ||||
-rw-r--r-- | src/engine/machina/types.hpp | 1 |
11 files changed, 223 insertions, 94 deletions
diff --git a/src/engine/JackDriver.cpp b/src/engine/JackDriver.cpp index f6f0ea6..ff78520 100644 --- a/src/engine/JackDriver.cpp +++ b/src/engine/JackDriver.cpp @@ -15,15 +15,16 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "machina/JackDriver.hpp" - #include <iostream> +#include "machina/JackDriver.hpp" +#include "machina/MidiAction.hpp" namespace Machina { JackDriver::JackDriver() - : _output_port(NULL) + : _input_port(NULL) + , _output_port(NULL) , _current_cycle_start(0) , _current_cycle_nframes(0) { @@ -36,6 +37,11 @@ JackDriver::attach(const std::string& client_name) Raul::JackDriver::attach(client_name, "debug"); if (jack_client()) { + _input_port = jack_port_register(jack_client(), + "out", + JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, + 0); + _output_port = jack_port_register(jack_client(), "out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, @@ -47,7 +53,9 @@ JackDriver::attach(const std::string& client_name) void JackDriver::detach() { + jack_port_unregister(jack_client(), _input_port); jack_port_unregister(jack_client(), _output_port); + _input_port = NULL; _output_port = NULL; Raul::JackDriver::detach(); @@ -66,6 +74,47 @@ JackDriver::stamp_to_offset(Timestamp stamp) void +JackDriver::learn(SharedPtr<Node> node) +{ + _learn_enter_action = SharedPtr<MidiAction>(new MidiAction(shared_from_this(), 4, NULL)); + _learn_exit_action = SharedPtr<MidiAction>(new MidiAction(shared_from_this(), 4, NULL)); + _learn_node = node; +} + + +void +JackDriver::process_input(jack_nframes_t nframes) +{ + //if (_learn_node) { + void* jack_buffer = jack_port_get_buffer(_input_port, nframes); + const jack_nframes_t event_count = jack_midi_get_event_count(jack_buffer, nframes); + + for (jack_nframes_t i=0; i < event_count; ++i) { + jack_midi_event_t ev; + jack_midi_event_get(&ev, jack_buffer, i, nframes); + + std::cerr << "EVENT: " << (char)ev.buffer[0] << "\n"; + + } + //} +} + + +void +JackDriver::write_event(Timestamp time, + size_t size, + const byte* event) +{ + const FrameCount nframes = _current_cycle_nframes; + const FrameCount offset = stamp_to_offset(time); + + jack_midi_event_write( + jack_port_get_buffer(_output_port, nframes), offset, + event, size, nframes); +} + + +void JackDriver::on_process(jack_nframes_t nframes) { //std::cerr << "======================================================\n"; @@ -79,10 +128,8 @@ JackDriver::on_process(jack_nframes_t nframes) bool machine_done = ! _machine->run(_current_cycle_nframes); - if (machine_done && _machine->time() == 0) { - _machine->reset(); + if (machine_done && _machine->is_finished()) return; - } if (!machine_done) { _current_cycle_start += _current_cycle_nframes; diff --git a/src/engine/JackNodeFactory.cpp b/src/engine/JackNodeFactory.cpp index 09670e1..ac99422 100644 --- a/src/engine/JackNodeFactory.cpp +++ b/src/engine/JackNodeFactory.cpp @@ -16,20 +16,27 @@ */ #include "machina/JackNodeFactory.hpp" -#include "machina/JackActions.hpp" +#include "machina/MidiAction.hpp" #include "machina/Node.hpp" +#include "machina/JackDriver.hpp" namespace Machina { SharedPtr<Node> -JackNodeFactory::create_node(Node::ID, unsigned char note, FrameCount duration) +JackNodeFactory::create_node(Node::ID, byte note, FrameCount duration) { - // FIXME: leaks like a sieve, obviously + // 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); - JackNoteOnAction* a_enter = new JackNoteOnAction(_driver, note); - JackNoteOffAction* a_exit = new JackNoteOffAction(_driver, note); + MidiAction* a_enter = new MidiAction(_driver, event_size, note_on); + + + static const byte note_off[3] = { 0x90, note, 0x40 }; + MidiAction* a_exit = new MidiAction(_driver, event_size, note_off); n->add_enter_action(a_enter); n->add_exit_action(a_exit); diff --git a/src/engine/Machine.cpp b/src/engine/Machine.cpp index 5cc54ee..3f28414 100644 --- a/src/engine/Machine.cpp +++ b/src/engine/Machine.cpp @@ -125,15 +125,19 @@ Machine::run(FrameCount nframes) // Initial run, enter all initial states if (_time == 0) { bool entered = false; - for (Nodes::const_iterator n = _nodes.begin(); n != _nodes.end(); ++n) { - if ((*n)->is_initial()) { - (*n)->enter(0); - entered = true; + if ( ! _nodes.empty()) { + for (Nodes::const_iterator n = _nodes.begin(); n != _nodes.end(); ++n) { + if ((*n)->is_initial()) { + (*n)->enter(0); + entered = true; + } else { + (*n)->exit(0); + } } } if (!entered) { - _is_finished = true; - return false; + _is_finished = false; // run next time + return false; // but done this cycle } } diff --git a/src/engine/Makefile.am b/src/engine/Makefile.am index b8f248c..c21935f 100644 --- a/src/engine/Makefile.am +++ b/src/engine/Makefile.am @@ -11,7 +11,7 @@ libmachina_la_SOURCES = \ Machine.cpp \ Loader.h \ Loader.cpp \ - MidiActions.cpp \ + MidiAction.cpp \ JackDriver.h \ JackDriver.cpp \ JackNodeFactory.cpp diff --git a/src/engine/MidiAction.cpp b/src/engine/MidiAction.cpp new file mode 100644 index 0000000..9d30151 --- /dev/null +++ b/src/engine/MidiAction.cpp @@ -0,0 +1,101 @@ +/* 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 <iostream> +#include <raul/SharedPtr.h> +#include "machina/MidiAction.hpp" +#include "machina/MidiDriver.hpp" + +namespace Machina { + + +/** Create a MIDI action. + * + * Creating a NULL MIDIAction is okay, pass event=NULL and + * the action will simply do nothing until a set_event (for MIDI learning). + * + * Memory management of @event is the caller's responsibility + * (ownership is not taken). + */ +MidiAction::MidiAction(WeakPtr<MidiDriver> driver, + size_t size, + const byte* event) + : _driver(driver) + , _size(0) + , _max_size(size) +{ + _event = new byte[_max_size]; + set_event(size, event); +} + + +MidiAction::~MidiAction() +{ + if (_event.get()) + delete _event.get(); +} + + +/** Set the MIDI event to be emitted when the action executes. + * + * Returns pointer to old event (caller's responsibility to free if non-NULL). + * Safe to call concurrently with execute. + * + * Returns true on success. + */ +bool +MidiAction::set_event(size_t size, const byte* new_event) +{ + byte* const event = _event.get(); + if (size <= _max_size) { + _event = NULL; + if (size > 0) + memcpy(event, new_event, size); + _size = size; + _event = event; + return true; + } else { + return false; + } +} + + +/** Execute the action. + * + * Safe to call concurrently with set_event. + */ +void +MidiAction::execute(Timestamp time) +{ + const byte* const event = _event.get(); + + using namespace std; + + if (event) { + cerr << "MIDI FIRING"; + SharedPtr<MidiDriver> driver = _driver.lock(); + if (driver) + driver->write_event(time, _size, event); + } else { + cerr << "NULL MIDI ACTION"; + } +} + + +} // namespace Machina + + diff --git a/src/engine/MidiActions.cpp b/src/engine/MidiActions.cpp deleted file mode 100644 index 8d07c3a..0000000 --- a/src/engine/MidiActions.cpp +++ /dev/null @@ -1,60 +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 <iostream> -#include "machina/MidiAction.hpp" -#include "machina/MidiDriver.hpp" - -namespace Machina { - - -/* NOTE ON */ - -MidiAction(WeakPtr<JackDriver> driver, - size_t size, - unsigned char* event) - : _driver(driver) - , _size(size) - , _event(event) -{ -} - - -void -MidiAction::execute(Timestamp time) -{ - SharedPtr<MidiDriver> driver = _driver.lock(); - if (!driver) - return; - - const FrameCount nframes = driver->current_cycle_nframes(); - const FrameCount offset = driver->stamp_to_offset(time); - - //std::cerr << offset << " \tMIDI @ " << time << std::endl; - - //jack_midi_data_t ev[] = { 0x80, _note_num, 0x40 }; note on - //jack_midi_data_t ev[] = { 0x90, _note_num, 0x40 }; note off - - jack_midi_event_write( - jack_port_get_buffer(driver->output_port(), nframes), - offset, ev, _size, _event); -} - - -} // namespace Machina - - diff --git a/src/engine/machina/Action.hpp b/src/engine/machina/Action.hpp index ffee5b1..feb0e0b 100644 --- a/src/engine/machina/Action.hpp +++ b/src/engine/machina/Action.hpp @@ -25,6 +25,10 @@ namespace Machina { +/** An Action, executed on entering or exiting of a state. + * + * Actions do not have time as a property. + */ struct Action { virtual ~Action() {} diff --git a/src/engine/machina/JackDriver.hpp b/src/engine/machina/JackDriver.hpp index bae3ab2..9a72a62 100644 --- a/src/engine/machina/JackDriver.hpp +++ b/src/engine/machina/JackDriver.hpp @@ -23,16 +23,21 @@ #include <jack/midiport.h> #include "Machine.hpp" #include "MidiDriver.hpp" +#include <boost/enable_shared_from_this.hpp> namespace Machina { +class MidiAction; +class Node; + /** Realtime JACK Driver. * * "Ticks" are individual frames when running under this driver, and all code * in the processing context must be realtime safe (non-blocking). */ -class JackDriver : public Raul::JackDriver, public Machina::MidiDriver { +class JackDriver : public Raul::JackDriver, public Machina::MidiDriver, + public boost::enable_shared_from_this<JackDriver> { public: JackDriver(); @@ -45,18 +50,31 @@ public: Timestamp cycle_start() { return _current_cycle_start; } FrameCount cycle_length() { return _current_cycle_nframes; } + void learn(SharedPtr<Node> node); + + void write_event(Timestamp time, + size_t size, + const unsigned char* event); + private: // Audio context - Timestamp subcycle_offset() { return _current_cycle_offset; } - jack_port_t* output_port() { return _output_port; } - virtual void on_process(jack_nframes_t nframes); + Timestamp subcycle_offset() { return _current_cycle_offset; } Timestamp stamp_to_offset(Timestamp stamp); + + void process_input(jack_nframes_t nframes); + virtual void on_process(jack_nframes_t nframes); + SharedPtr<Machine> _machine; - jack_port_t* _output_port; - Timestamp _current_cycle_start; - Timestamp _current_cycle_offset; ///< for split cycles - FrameCount _current_cycle_nframes; + SharedPtr<Node> _learn_node; + SharedPtr<MidiAction> _learn_enter_action; + SharedPtr<MidiAction> _learn_exit_action; + + jack_port_t* _input_port; + jack_port_t* _output_port; + Timestamp _current_cycle_start; + Timestamp _current_cycle_offset; ///< for split cycles + FrameCount _current_cycle_nframes; }; diff --git a/src/engine/machina/Machine.hpp b/src/engine/machina/Machine.hpp index 5d16a4e..4036ef3 100644 --- a/src/engine/machina/Machine.hpp +++ b/src/engine/machina/Machine.hpp @@ -20,7 +20,8 @@ #include <vector> #include <map> -#include "raul/SharedPtr.h" +#include <raul/SharedPtr.h> +#include <raul/List.h> #include "types.hpp" #include "Node.hpp" @@ -48,7 +49,7 @@ public: FrameCount time() { return _time; } private: - typedef std::vector<SharedPtr<Node> > Nodes; + typedef Raul::List<SharedPtr<Node> > Nodes; // Audio context SharedPtr<Node> earliest_node() const; diff --git a/src/engine/machina/MidiAction.hpp b/src/engine/machina/MidiAction.hpp index 2e1d1fc..d362a63 100644 --- a/src/engine/machina/MidiAction.hpp +++ b/src/engine/machina/MidiAction.hpp @@ -19,6 +19,7 @@ #define MACHINA_MIDIACTION_HPP #include <raul/WeakPtr.h> +#include <raul/AtomicPtr.h> #include "types.hpp" #include "Action.hpp" @@ -29,16 +30,21 @@ class MidiDriver; class MidiAction : public Action { public: - JackNoteOnAction(WeakPtr<MidiDriver> driver, - size_t size, - unsigned char* event); + MidiAction(WeakPtr<MidiDriver> driver, + size_t size, + const unsigned char* event); + + ~MidiAction(); + + bool set_event(size_t size, const byte* event); void execute(Timestamp time); private: - WeakPtr<MidiDriver> _driver; - size_t _size; - unsigned char* _event; + WeakPtr<MidiDriver> _driver; + size_t _size; + const size_t _max_size; + Raul::AtomicPtr<byte> _event; }; diff --git a/src/engine/machina/types.hpp b/src/engine/machina/types.hpp index db36901..1236f65 100644 --- a/src/engine/machina/types.hpp +++ b/src/engine/machina/types.hpp @@ -26,6 +26,7 @@ namespace Machina { typedef jack_nframes_t FrameCount; typedef jack_nframes_t Timestamp; +typedef unsigned char byte; } // namespace Machina |