aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-02-22 04:16:05 +0000
committerDavid Robillard <d@drobilla.net>2007-02-22 04:16:05 +0000
commit8cc603cd24294c0d917b37ea0568d89962b5a74f (patch)
tree9bb04036640c853bb67492efa81322601ad5972f /src
parent1429e4b2279566384ec09bfe3bfe7d7e0f0f79eb (diff)
downloadmachina-8cc603cd24294c0d917b37ea0568d89962b5a74f.tar.gz
machina-8cc603cd24294c0d917b37ea0568d89962b5a74f.tar.bz2
machina-8cc603cd24294c0d917b37ea0568d89962b5a74f.zip
Machina quantization, various timing related fixes.
git-svn-id: http://svn.drobilla.net/lad/machina@326 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r--src/engine/Engine.cpp3
-rw-r--r--src/engine/JackDriver.cpp43
-rw-r--r--src/engine/LearnRequest.cpp40
-rw-r--r--src/engine/Machine.cpp5
-rw-r--r--src/engine/Makefile.am3
-rw-r--r--src/engine/machina/JackDriver.hpp6
-rw-r--r--src/engine/machina/LearnRequest.hpp12
-rw-r--r--src/gui/MachinaGUI.cpp8
-rw-r--r--src/gui/machina.glade1
9 files changed, 90 insertions, 31 deletions
diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp
index a621a8a..d659626 100644
--- a/src/engine/Engine.cpp
+++ b/src/engine/Engine.cpp
@@ -29,8 +29,9 @@ Engine::set_bpm(double bpm)
void
-Engine::set_quantization(double)
+Engine::set_quantization(double q)
{
+ _driver->set_quantization(q);
}
diff --git a/src/engine/JackDriver.cpp b/src/engine/JackDriver.cpp
index 9236fd9..404d972 100644
--- a/src/engine/JackDriver.cpp
+++ b/src/engine/JackDriver.cpp
@@ -30,6 +30,7 @@ JackDriver::JackDriver()
, _output_port(NULL)
, _cycle_time(1/48000.0, 120.0)
, _bpm(120.0)
+ , _quantization(120.0)
{
}
@@ -79,11 +80,15 @@ JackDriver::detach()
void
-JackDriver::process_input(jack_nframes_t nframes)
+JackDriver::process_input(const TimeSlice& time)
{
+ // We only actually read Jack input at the beginning of a cycle
+ assert(time.offset_ticks() == 0);
+
using namespace std;
//if (_learn_node) {
+ const jack_nframes_t nframes = time.length_ticks();
void* jack_buffer = jack_port_get_buffer(_input_port, nframes);
const jack_nframes_t event_count = jack_midi_get_event_count(jack_buffer, nframes);
@@ -92,25 +97,25 @@ JackDriver::process_input(jack_nframes_t nframes)
jack_midi_event_get(&ev, jack_buffer, i, nframes);
if (ev.buffer[0] == 0x90) {
- cerr << "NOTE ON\n";
const SharedPtr<LearnRequest> learn = _machine->pending_learn();
if (learn) {
learn->enter_action()->set_event(ev.size, ev.buffer);
cerr << "LEARN START\n";
- learn->start(jack_last_frame_time(_client) + ev.time);
+ learn->start(_quantization.get(),
+ time.ticks_to_beats(jack_last_frame_time(_client) + ev.time));
//LearnRecord learn = _machine->pop_learn();
}
} else if (ev.buffer[0] == 0x80) {
- cerr << "NOTE OFF\n";
const SharedPtr<LearnRequest> learn = _machine->pending_learn();
if (learn) {
if (learn->started()) {
learn->exit_action()->set_event(ev.size, ev.buffer);
- learn->finish(jack_last_frame_time(_client) + ev.time);
+ learn->finish(
+ time.ticks_to_beats(jack_last_frame_time(_client) + ev.time));
_machine->clear_pending_learn();
cerr << "LEARNED!\n";
}
@@ -130,15 +135,23 @@ JackDriver::write_event(Raul::BeatTime time,
const byte* event)
{
const TickCount nframes = _cycle_time.length_ticks();
- const TickCount offset = _cycle_time.offset_ticks()
- + _cycle_time.beats_to_ticks(time);
+ const TickCount offset = _cycle_time.beats_to_ticks(time)
+ + _cycle_time.offset_ticks() - _cycle_time.start_ticks();
assert(_output_port);
- assert(offset < nframes);
-
- jack_midi_event_write(
- jack_port_get_buffer(_output_port, nframes), offset,
- event, size, nframes);
+
+ if ( ! (offset < _cycle_time.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;
+ } else {
+ jack_midi_event_write(
+ jack_port_get_buffer(_output_port, nframes), offset,
+ event, size, nframes);
+ }
}
@@ -157,7 +170,7 @@ JackDriver::on_process(jack_nframes_t nframes)
assert(_output_port);
jack_midi_clear_buffer(jack_port_get_buffer(_output_port, nframes), nframes);
- process_input(nframes);
+ process_input(_cycle_time);
if (_machine->is_empty()) {
//cerr << "EMPTY\n";
@@ -179,12 +192,12 @@ JackDriver::on_process(jack_nframes_t nframes)
} else if (run_dur_ticks < _cycle_time.length_ticks()) {
const TickCount finish_offset = _cycle_time.offset_ticks() + run_dur_ticks;
assert(finish_offset < nframes);
+
+ _machine->reset();
_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 {
diff --git a/src/engine/LearnRequest.cpp b/src/engine/LearnRequest.cpp
new file mode 100644
index 0000000..6f311cb
--- /dev/null
+++ b/src/engine/LearnRequest.cpp
@@ -0,0 +1,40 @@
+/* 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 Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <raul/Quantizer.h>
+#include <machina/LearnRequest.hpp>
+
+namespace Machina {
+
+
+/** Add the learned actions to the node */
+void
+LearnRequest::finish(BeatTime time)
+{
+ _node->add_enter_action(_enter_action);
+ _node->add_exit_action(_exit_action);
+
+ double duration = Raul::Quantizer::quantize(_quantization, time - _start_time);
+
+ _node->set_duration(duration);
+ using namespace std;
+ cerr << "Q=" << _quantization << ", T=" << time << ", ST=" << _start_time << endl;
+ std::cerr << "LEARN DURATION: " << duration << std::endl;
+}
+
+
+}
diff --git a/src/engine/Machine.cpp b/src/engine/Machine.cpp
index bbe343c..7c522dd 100644
--- a/src/engine/Machine.cpp
+++ b/src/engine/Machine.cpp
@@ -158,7 +158,10 @@ Machine::run(const Raul::TimeSlice& time)
break;
// Earliest active state ends this cycle
- } else if (earliest->exit_time() < cycle_end) {
+ // Must do comparison in ticks here to avoid rounding up and executing
+ // an event outside the current cycle
+ } else if (time.beats_to_ticks(earliest->exit_time())
+ < time.beats_to_ticks(cycle_end)) {
this_time += earliest->exit_time() - _time;
_time = earliest->exit_time();
exit_node(earliest);
diff --git a/src/engine/Makefile.am b/src/engine/Makefile.am
index 833d39c..da594e8 100644
--- a/src/engine/Makefile.am
+++ b/src/engine/Makefile.am
@@ -14,4 +14,5 @@ libmachina_la_SOURCES = \
MidiAction.cpp \
JackDriver.h \
JackDriver.cpp \
- Engine.cpp
+ Engine.cpp \
+ LearnRequest.cpp
diff --git a/src/engine/machina/JackDriver.hpp b/src/engine/machina/JackDriver.hpp
index e52af88..1f9b197 100644
--- a/src/engine/machina/JackDriver.hpp
+++ b/src/engine/machina/JackDriver.hpp
@@ -51,10 +51,11 @@ public:
size_t size,
const unsigned char* event);
- void set_bpm(double bpm) { _bpm.set(bpm); }
+ void set_bpm(double bpm) { _bpm.set(bpm); }
+ void set_quantization(double quantization) { _quantization.set(quantization); }
private:
- void process_input(jack_nframes_t nframes);
+ void process_input(const Raul::TimeSlice& time);
virtual void on_process(jack_nframes_t nframes);
SharedPtr<Machine> _machine;
@@ -65,6 +66,7 @@ private:
Raul::TimeSlice _cycle_time;
Raul::DoubleBuffer<double> _bpm;
+ Raul::DoubleBuffer<double> _quantization;
};
diff --git a/src/engine/machina/LearnRequest.hpp b/src/engine/machina/LearnRequest.hpp
index f485560..9284e90 100644
--- a/src/engine/machina/LearnRequest.hpp
+++ b/src/engine/machina/LearnRequest.hpp
@@ -43,16 +43,9 @@ public:
return ret;
}
- // Add the learned actions to the node
- void finish(BeatTime time)
- {
- _node->add_enter_action(_enter_action);
- _node->add_exit_action(_exit_action);
- _node->set_duration(time - _start_time);
- std::cerr << "LEARN DURATION: " << _node->duration() << std::endl;
- }
+ void finish(BeatTime time);
- void start(BeatTime time) { _started = true; _start_time = time; }
+ void start(double q, BeatTime time) { _started = true; _start_time = time; _quantization = q; }
bool started() { return _started; }
const SharedPtr<Node>& node() { return _node; }
@@ -70,6 +63,7 @@ private:
bool _started;
BeatTime _start_time;
+ double _quantization;
SharedPtr<Node> _node;
SharedPtr<MidiAction> _enter_action;
SharedPtr<MidiAction> _exit_action;
diff --git a/src/gui/MachinaGUI.cpp b/src/gui/MachinaGUI.cpp
index 9fa0dbb..f1ec4f0 100644
--- a/src/gui/MachinaGUI.cpp
+++ b/src/gui/MachinaGUI.cpp
@@ -193,6 +193,7 @@ MachinaGUI::MachinaGUI(SharedPtr<Machina::Engine> engine)
_pane_closed = true;
_bpm_radiobutton->set_active(true);
+ _quantize_checkbutton->set_active(false);
// Idle callback to drive the maid (collect garbage)
Glib::signal_timeout().connect(
@@ -253,7 +254,12 @@ MachinaGUI::update_toolbar()
void
MachinaGUI::quantize_changed()
{
- _engine->set_quantization(1.0/(double)_quantize_spinbutton->get_value_as_int());
+ if (_quantize_checkbutton->get_active()) {
+ _engine->set_quantization(1/(double)_quantize_spinbutton->get_value_as_int());
+ } else {
+ _engine->set_quantization(0.0);
+ }
+ update_toolbar();
}
diff --git a/src/gui/machina.glade b/src/gui/machina.glade
index f255d9f..bdea253 100644
--- a/src/gui/machina.glade
+++ b/src/gui/machina.glade
@@ -303,7 +303,6 @@
<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>