diff options
-rw-r--r-- | src/engine/Engine.cpp | 3 | ||||
-rw-r--r-- | src/engine/JackDriver.cpp | 43 | ||||
-rw-r--r-- | src/engine/LearnRequest.cpp | 40 | ||||
-rw-r--r-- | src/engine/Machine.cpp | 5 | ||||
-rw-r--r-- | src/engine/Makefile.am | 3 | ||||
-rw-r--r-- | src/engine/machina/JackDriver.hpp | 6 | ||||
-rw-r--r-- | src/engine/machina/LearnRequest.hpp | 12 | ||||
-rw-r--r-- | src/gui/MachinaGUI.cpp | 8 | ||||
-rw-r--r-- | src/gui/machina.glade | 1 |
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> |