aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-04-04 18:01:08 +0000
committerDavid Robillard <d@drobilla.net>2007-04-04 18:01:08 +0000
commit74688702fa060fb6aaa413b06deceec6c78d74a6 (patch)
tree5e4093659298a52d3fba49c379c0692f5328fc77
parentdb6f6e87dc4ff620f399597913f14a3b4eda277f (diff)
downloadmachina-74688702fa060fb6aaa413b06deceec6c78d74a6.tar.gz
machina-74688702fa060fb6aaa413b06deceec6c78d74a6.tar.bz2
machina-74688702fa060fb6aaa413b06deceec6c78d74a6.zip
Quantization while recording.
git-svn-id: http://svn.drobilla.net/lad/machina@393 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r--src/engine/JackDriver.cpp4
-rw-r--r--src/engine/Loader.cpp8
-rw-r--r--src/engine/MachineBuilder.cpp243
-rw-r--r--src/engine/Recorder.cpp5
-rw-r--r--src/engine/SMFDriver.cpp4
-rw-r--r--src/engine/machina/MachineBuilder.hpp6
-rw-r--r--src/engine/machina/Recorder.hpp2
-rw-r--r--src/gui/MachinaGUI.cpp2
8 files changed, 170 insertions, 104 deletions
diff --git a/src/engine/JackDriver.cpp b/src/engine/JackDriver.cpp
index 3493105..25ff496 100644
--- a/src/engine/JackDriver.cpp
+++ b/src/engine/JackDriver.cpp
@@ -32,7 +32,7 @@ JackDriver::JackDriver(SharedPtr<Machine> machine)
, _output_port(NULL)
, _cycle_time(1/48000.0, 120.0)
, _bpm(120.0)
- , _quantization(120.0)
+ , _quantization(0.0)
, _recording(0)
{
if (!_machine)
@@ -309,7 +309,7 @@ JackDriver::start_record()
{
std::cerr << "START RECORD" << std::endl;
// FIXME: hardcoded size
- _recorder = SharedPtr<Recorder>(new Recorder(1024, (1.0/(double)sample_rate()) * (_bpm.get() / 60.0)));
+ _recorder = SharedPtr<Recorder>(new Recorder(1024, (1.0/(double)sample_rate()) * (_bpm.get() / 60.0), _quantization.get()));
_recorder->start();
_record_time = 0;
_recording = 1;
diff --git a/src/engine/Loader.cpp b/src/engine/Loader.cpp
index b3e4c81..57905ba 100644
--- a/src/engine/Loader.cpp
+++ b/src/engine/Loader.cpp
@@ -125,7 +125,7 @@ Loader::load(const Glib::ustring& uri)
const Glib::ustring& node_id = (*i)["node"];
const Glib::ustring& duration = (*i)["duration"];
- cout << "Node: " << node_id << " - " << duration << endl;
+ //cout << "Node: " << node_id << " - " << duration << endl;
if (created.find(node_id.collate_key()) == created.end()) {
SharedPtr<Node> node(new Node(strtod(duration.c_str(), NULL), false));
@@ -137,9 +137,9 @@ Loader::load(const Glib::ustring& uri)
}
- for (Created::iterator n = created.begin(); n != created.end(); ++n) {
+ /*for (Created::iterator n = created.begin(); n != created.end(); ++n) {
cout << "NODE: " << n->first << endl;
- }
+ }*/
/* Get note actions */
@@ -157,7 +157,7 @@ Loader::load(const Glib::ustring& uri)
const Glib::ustring& node_id = (*i)["node"];
const Glib::ustring& note = (*i)["note"];
- cerr << "NOTE: " << node_id << " = " << note << endl;
+ //cerr << "NOTE: " << node_id << " = " << note << endl;
Created::iterator node_i = created.find(node_id);
if (node_i != created.end()) {
diff --git a/src/engine/MachineBuilder.cpp b/src/engine/MachineBuilder.cpp
index c8ad273..03d20b9 100644
--- a/src/engine/MachineBuilder.cpp
+++ b/src/engine/MachineBuilder.cpp
@@ -17,18 +17,21 @@
#include <algorithm>
#include <raul/midi_events.h>
+#include <raul/Quantizer.h>
#include "machina/MachineBuilder.hpp"
#include "machina/Machine.hpp"
#include "machina/Node.hpp"
#include "machina/Edge.hpp"
using namespace std;
+using namespace Raul;
namespace Machina {
-MachineBuilder::MachineBuilder(SharedPtr<Machine> machine)
- : _time(0)
+MachineBuilder::MachineBuilder(SharedPtr<Machine> machine, Raul::BeatTime q)
+ : _quantization(q)
+ , _time(0)
, _machine(machine)
, _initial_node(new Node())
, _connect_node(_initial_node)
@@ -109,118 +112,163 @@ MachineBuilder::event(Raul::BeatTime time_offset,
{
Raul::BeatTime t = _time + time_offset;
+ if (ev_size == 0)
+ return;
+
//cerr << "t = " << t << endl;
-
- if (ev_size > 0) {
- if ((buf[0] & 0xF0) == MIDI_CMD_NOTE_ON) {
- //cerr << "NOTE ON: " << (int)buf[1] << ", channel = " << (int)(buf[0] & 0x0F) << endl;
- SharedPtr<Node> node(new Node());
-
- node->set_enter_action(SharedPtr<Action>(new MidiAction(ev_size, buf)));
-
- SharedPtr<Node> delay_node = connect_nodes(_machine,
- _connect_node, _connect_node_end_time, node, t);
-
- /*if (delay_node) {
- _connect_node = delay_node;
- _connect_node_end_time = t;
- }*/
-
- node->enter(SharedPtr<Raul::MIDISink>(), t);
- _active_nodes.push_back(node);
-
- } else if ((buf[0] & 0xF0) == MIDI_CMD_NOTE_OFF) {
- //cerr << "NOTE OFF: " << (int)buf[1] << endl;
- for (ActiveList::iterator i = _active_nodes.begin(); i != _active_nodes.end(); ++i) {
- SharedPtr<MidiAction> action = PtrCast<MidiAction>((*i)->enter_action());
- if (!action)
- continue;
-
- const size_t ev_size = action->event_size();
- const unsigned char* ev = action->event();
- if (ev_size == 3 && (ev[0] & 0xF0) == MIDI_CMD_NOTE_ON
- && (ev[0] & 0x0F) == (buf[0] & 0x0F) // same channel
- && ev[1] == buf[1]) // same note
- {
- //cerr << "FOUND MATCHING NOTE OFF!\n";
-
- SharedPtr<Node> resolved = *i;
-
- resolved->set_exit_action(SharedPtr<Action>(new MidiAction(ev_size, buf)));
- resolved->set_duration(t - resolved->enter_time());
-
- if (_active_nodes.size() == 1) {
-
- //cerr << "{ RESOLVING, t= " << t << "\n";
-
- _connect_node_end_time = t;
-
- if (_poly_nodes.size() > 0) {
- _connect_node = SharedPtr<Node>(new Node());
- _machine->add_node(_connect_node);
+ if ((buf[0] & 0xF0) == MIDI_CMD_NOTE_ON) {
+ //cerr << "NOTE ON: " << (int)buf[1] << ", channel = " << (int)(buf[0] & 0x0F) << endl;
+
+ SharedPtr<Node> node(new Node());
+ node->set_enter_action(SharedPtr<Action>(new MidiAction(ev_size, buf)));
+
+ SharedPtr<Node> this_connect_node;
+ Raul::BeatTime this_connect_node_end_time;
+
+ // If currently polyphonic, use a poly node with no successors as connect node
+ // Results in patterns closes to what a human would choose
+ if ( ! _poly_nodes.empty()) {
+ for (PolyList::iterator j = _poly_nodes.begin(); j != _poly_nodes.end(); ++j) {
+ if (j->second->outgoing_edges().empty()) {
+ this_connect_node = j->second;
+ this_connect_node_end_time = j->first + j->second->duration();
+ cerr << "POLY CONNECT!\n";
+ break;
+ }
+ }
+ }
+
+ // Currently monophonic, or didn't find a poly node, so use _connect_node
+ // which is maintained below on note off events.
+ if ( ! this_connect_node) {
+ cerr << "NO POLY CONNECT\n";
+ this_connect_node = _connect_node;
+ this_connect_node_end_time = _connect_node_end_time;
+ }
+
+
+ SharedPtr<Node> delay_node = connect_nodes(_machine,
+ this_connect_node, this_connect_node_end_time, node, t);
+
+ if (delay_node)
+ cerr << "XXXXXXXXXXXXXX NOTE ON DELAY NODE\n";
+
+ if (delay_node) {
+ _connect_node = delay_node;
+ _connect_node_end_time = t;
+ }
+
+ node->enter(SharedPtr<Raul::MIDISink>(), t);
+ _active_nodes.push_back(node);
+
+ } else if ((buf[0] & 0xF0) == MIDI_CMD_NOTE_OFF) {
+ //cerr << "NOTE OFF: " << (int)buf[1] << endl;
+ for (ActiveList::iterator i = _active_nodes.begin(); i != _active_nodes.end(); ++i) {
+ SharedPtr<MidiAction> action = PtrCast<MidiAction>((*i)->enter_action());
+ if (!action)
+ continue;
+
+ const size_t ev_size = action->event_size();
+ const unsigned char* ev = action->event();
+
+ if (ev_size == 3 && (ev[0] & 0xF0) == MIDI_CMD_NOTE_ON
+ && (ev[0] & 0x0F) == (buf[0] & 0x0F) // same channel
+ && ev[1] == buf[1]) // same note
+ {
+ //cerr << "FOUND MATCHING NOTE OFF!\n";
- connect_nodes(_machine, resolved, t, _connect_node, t);
+ SharedPtr<Node> resolved = *i;
- for (PolyList::iterator j = _poly_nodes.begin();
- j != _poly_nodes.end(); ++j) {
- _machine->add_node(j->second);
+ resolved->set_exit_action(SharedPtr<Action>(new MidiAction(ev_size, buf)));
+ resolved->set_duration(t - resolved->enter_time());
+
+ // Last active note
+ if (_active_nodes.size() == 1) {
+
+ cerr << "{ RESOLVING, t= " << t << "\n";
+
+ _connect_node_end_time = t;
+
+ // Finish a polyphonic section
+ if (_poly_nodes.size() > 0) {
+
+ cerr << "POLY\n";
+
+ _connect_node = SharedPtr<Node>(new Node());
+ _machine->add_node(_connect_node);
+
+ connect_nodes(_machine, resolved, t, _connect_node, t);
+
+ for (PolyList::iterator j = _poly_nodes.begin(); j != _poly_nodes.end(); ++j) {
+ _machine->add_node(j->second);
+ if (j->second->outgoing_edges().size() == 0)
connect_nodes(_machine, j->second, j->first + j->second->duration(),
_connect_node, t);
- }
- _poly_nodes.clear();
-
- _machine->add_node(resolved);
+ }
+ _poly_nodes.clear();
- } else {
- // Trim useless delay node, if possible
- // (these happen after polyphonic sections)
- if (is_delay_node(_connect_node) && _connect_node->duration() == 0
- && _connect_node->outgoing_edges().size() == 1
- && (*_connect_node->outgoing_edges().begin())->head() == resolved) {
- //cerr << "TRIMMING\n";
- _connect_node->outgoing_edges().clear();
- assert(_connect_node->outgoing_edges().empty());
- _connect_node->set_enter_action(resolved->enter_action());
- _connect_node->set_exit_action(resolved->exit_action());
- resolved->remove_enter_action();
- resolved->remove_exit_action();
- _connect_node->set_duration(resolved->duration());
- resolved = _connect_node;
- if (_machine->nodes().find(_connect_node) == _machine->nodes().end())
- _machine->add_node(_connect_node);
- } else {
- //cerr << "RESOLVED\n";
- _connect_node = resolved;
- _machine->add_node(resolved);
- }
- }
-
- //cerr << "}";
+ _machine->add_node(resolved);
+ // Just monophonic
} else {
- //cerr << "ADDING POLY\n";
- _poly_nodes.push_back(make_pair(resolved->enter_time(), resolved));
- }
+
+ cerr << "NO POLY\n";
+
+ // Trim useless delay node if possible (these appear after poly sections)
+ if (is_delay_node(_connect_node) && _connect_node->duration() == 0
+ && _connect_node->outgoing_edges().size() == 1
+ && (*_connect_node->outgoing_edges().begin())->head() == resolved) {
+
+ cerr << "TRIMMING\n";
+ _connect_node->outgoing_edges().clear();
+ assert(_connect_node->outgoing_edges().empty());
+ _connect_node->set_enter_action(resolved->enter_action());
+ _connect_node->set_exit_action(resolved->exit_action());
+ resolved->remove_enter_action();
+ resolved->remove_exit_action();
+ _connect_node->set_duration(resolved->duration());
+ resolved = _connect_node;
+ if (_machine->nodes().find(_connect_node) == _machine->nodes().end())
+ _machine->add_node(_connect_node);
+
+ } else {
- if (resolved->is_active())
- resolved->exit(SharedPtr<Raul::MIDISink>(), t);
+ cerr << "RESOLVED\n";
+ _connect_node = resolved;
+ _machine->add_node(resolved);
+ }
+ }
- _active_nodes.erase(i);
+ cerr << "}";
- break;
+ // Polyphonic, add this state to poly list
+ } else {
+ cerr << "ADDING POLY\n";
+ _poly_nodes.push_back(make_pair(resolved->enter_time(), resolved));
+ _connect_node = resolved;
+ _connect_node_end_time = t;
}
+
+ if (resolved->is_active())
+ resolved->exit(SharedPtr<Raul::MIDISink>(), t);
+
+ _active_nodes.erase(i);
+
+ break;
}
}
}
}
-/** Resolve any stuck notes.
+/** Finish the constructed machine and prepare it for use.
+ * Resolve any stuck notes, quantize, etc.
*/
void
MachineBuilder::resolve()
{
+ // Resolve stuck notes
if ( ! _active_nodes.empty()) {
for (list<SharedPtr<Node> >::iterator i = _active_nodes.begin(); i != _active_nodes.end(); ++i) {
cerr << "WARNING: Resolving stuck note." << endl;
@@ -241,9 +289,22 @@ MachineBuilder::resolve()
_active_nodes.clear();
}
+ // Add initial note if necessary
if (_machine->nodes().size() > 0
&& _machine->nodes().find(_initial_node) == _machine->nodes().end())
_machine->add_node(_initial_node);
+
+ // Quantize
+ if (_quantization > 0) {
+ for (Machine::Nodes::iterator i = _machine->nodes().begin();
+ i != _machine->nodes().end(); ++i) {
+ Raul::BeatTime q_dur = Quantizer::quantize(_quantization, (*i)->duration());
+
+ // Never quantize a note to duration 0
+ if (q_dur > 0 || ( !(*i)->enter_action() && !(*i)->exit_action() ))
+ (*i)->set_duration(q_dur);
+ }
+ }
}
diff --git a/src/engine/Recorder.cpp b/src/engine/Recorder.cpp
index 78eafe6..c6130ab 100644
--- a/src/engine/Recorder.cpp
+++ b/src/engine/Recorder.cpp
@@ -26,11 +26,12 @@ using namespace Raul;
namespace Machina {
-Recorder::Recorder(size_t buffer_size, double tick_rate)
+Recorder::Recorder(size_t buffer_size, double tick_rate, double q)
: _tick_rate(tick_rate)
, _record_buffer(buffer_size)
- , _builder(new MachineBuilder(SharedPtr<Machine>(new Machine())))
+ , _builder(new MachineBuilder(SharedPtr<Machine>(new Machine()), q))
{
+ cerr << "XXXXXXXXXXXX new recorder, q=" << q << endl;
}
diff --git a/src/engine/SMFDriver.cpp b/src/engine/SMFDriver.cpp
index dc7ca59..0283288 100644
--- a/src/engine/SMFDriver.cpp
+++ b/src/engine/SMFDriver.cpp
@@ -49,7 +49,7 @@ SharedPtr<Machine>
SMFDriver::learn(const string& filename, unsigned track, double q, Raul::BeatTime max_duration)
{
SharedPtr<Machine> m(new Machine());
- SharedPtr<MachineBuilder> builder = SharedPtr<MachineBuilder>(new MachineBuilder(m));
+ SharedPtr<MachineBuilder> builder = SharedPtr<MachineBuilder>(new MachineBuilder(m, q));
Raul::SMFReader reader;
if (!reader.open(filename)) {
@@ -79,7 +79,7 @@ SharedPtr<Machine>
SMFDriver::learn(const string& filename, double q, Raul::BeatTime max_duration)
{
SharedPtr<Machine> m(new Machine());
- SharedPtr<MachineBuilder> builder = SharedPtr<MachineBuilder>(new MachineBuilder(m));
+ SharedPtr<MachineBuilder> builder = SharedPtr<MachineBuilder>(new MachineBuilder(m, q));
Raul::SMFReader reader;
if (!reader.open(filename)) {
diff --git a/src/engine/machina/MachineBuilder.hpp b/src/engine/machina/MachineBuilder.hpp
index a01ebd2..ac446c9 100644
--- a/src/engine/machina/MachineBuilder.hpp
+++ b/src/engine/machina/MachineBuilder.hpp
@@ -30,7 +30,8 @@ class Node;
class MachineBuilder {
public:
- MachineBuilder(SharedPtr<Machine> machine);
+ MachineBuilder(SharedPtr<Machine> machine,
+ Raul::BeatTime quantization);
void set_time(Raul::BeatTime time) { _time = time; }
@@ -54,7 +55,8 @@ private:
typedef std::list<std::pair<Raul::BeatTime, SharedPtr<Node> > > PolyList;
PolyList _poly_nodes;
-
+
+ Raul::BeatTime _quantization;
Raul::BeatTime _time;
SharedPtr<Machine> _machine;
diff --git a/src/engine/machina/Recorder.hpp b/src/engine/machina/Recorder.hpp
index b969df0..1bc07c3 100644
--- a/src/engine/machina/Recorder.hpp
+++ b/src/engine/machina/Recorder.hpp
@@ -31,7 +31,7 @@ class MachineBuilder;
class Recorder : public Raul::Slave {
public:
- Recorder(size_t buffer_size, double tick_rate);
+ Recorder(size_t buffer_size, double tick_rate, double q);
inline void write(Raul::TickTime time, size_t size, const unsigned char* buf) {
_record_buffer.write(time, size, buf);
diff --git a/src/gui/MachinaGUI.cpp b/src/gui/MachinaGUI.cpp
index 4098ff8..3cf38bd 100644
--- a/src/gui/MachinaGUI.cpp
+++ b/src/gui/MachinaGUI.cpp
@@ -133,6 +133,8 @@ MachinaGUI::MachinaGUI(SharedPtr<Machina::Engine> engine)
sigc::mem_fun(this, &MachinaGUI::tempo_changed));
_quantize_checkbutton->signal_toggled().connect(
sigc::mem_fun(this, &MachinaGUI::quantize_changed));
+ _quantize_spinbutton->signal_changed().connect(
+ sigc::mem_fun(this, &MachinaGUI::quantize_changed));
connect_widgets();