aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-02-10 07:30:56 +0000
committerDavid Robillard <d@drobilla.net>2007-02-10 07:30:56 +0000
commitcee33ba4c0859b117be94df6ccbf3eb756a850af (patch)
treee7e69de57c531538b2ded16bac31c2c705bc0fa6 /src
parent87c0a475bd76ca33883eeafc2a86bc89a84eec2f (diff)
downloadmachina-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.cpp59
-rw-r--r--src/engine/JackNodeFactory.cpp17
-rw-r--r--src/engine/Machine.cpp16
-rw-r--r--src/engine/Makefile.am2
-rw-r--r--src/engine/MidiAction.cpp101
-rw-r--r--src/engine/MidiActions.cpp60
-rw-r--r--src/engine/machina/Action.hpp4
-rw-r--r--src/engine/machina/JackDriver.hpp34
-rw-r--r--src/engine/machina/Machine.hpp5
-rw-r--r--src/engine/machina/MidiAction.hpp18
-rw-r--r--src/engine/machina/types.hpp1
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