diff options
Diffstat (limited to 'src/engine/JackAudioDriver.cpp')
-rw-r--r-- | src/engine/JackAudioDriver.cpp | 373 |
1 files changed, 0 insertions, 373 deletions
diff --git a/src/engine/JackAudioDriver.cpp b/src/engine/JackAudioDriver.cpp deleted file mode 100644 index 0f5e3b1a..00000000 --- a/src/engine/JackAudioDriver.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/* This file is part of Om. Copyright (C) 2006 Dave Robillard. - * - * Om 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. - * - * Om 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., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "JackAudioDriver.h" -#include "config.h" -#include "tuning.h" -#include <iostream> -#include <cstdlib> -#include "Om.h" -#include "OmApp.h" -#include "util.h" -#include "Event.h" -#include "QueuedEvent.h" -#include "EventSource.h" -#include "PostProcessor.h" -#include "util/Queue.h" -#include "Node.h" -#include "Patch.h" -#include "Port.h" -#include "PortInfo.h" -#include "MidiDriver.h" -#include "List.h" -#include "PortBase.h" -#ifdef HAVE_LASH -#include "LashDriver.h" -#endif - -using std::cout; using std::cerr; using std::endl; - - -namespace Om { - - -//// JackAudioPort //// - -JackAudioPort::JackAudioPort(JackAudioDriver* driver, PortBase<sample>* patch_port) -: DriverPort(), - ListNode<JackAudioPort*>(this), - m_driver(driver), - m_jack_port(NULL), - m_jack_buffer(NULL), - m_patch_port(patch_port) -{ - assert(patch_port->tied_port() != NULL); - assert(patch_port->poly() == 1); - - m_jack_port = jack_port_register(m_driver->jack_client(), - patch_port->path().c_str(), JACK_DEFAULT_AUDIO_TYPE, - (patch_port->port_info()->is_input()) ? JackPortIsInput : JackPortIsOutput, - 0); - - m_jack_buffer = new DriverBuffer<jack_sample_t>(driver->buffer_size()); - - patch_port->fixed_buffers(true); -} - - -JackAudioPort::~JackAudioPort() -{ - jack_port_unregister(m_driver->jack_client(), m_jack_port); -} - - -void -JackAudioPort::add_to_driver() -{ - m_driver->add_port(this); -} - - -void -JackAudioPort::remove_from_driver() -{ - m_driver->remove_port(this); -} - -void -JackAudioPort::prepare_buffer(jack_nframes_t nframes) -{ - // Technically this doesn't need to be done every time for output ports - m_jack_buffer->set_data((jack_default_audio_sample_t*) - jack_port_get_buffer(m_jack_port, nframes)); - - assert(m_patch_port->tied_port() != NULL); - - // FIXME: fixed_buffers switch on/off thing can be removed once this shit - // gets figured out and assertions can go away - m_patch_port->fixed_buffers(false); - m_patch_port->buffer(0)->join(m_jack_buffer); - m_patch_port->tied_port()->buffer(0)->join(m_jack_buffer); - - m_patch_port->fixed_buffers(true); - - assert(m_patch_port->buffer(0)->data() == m_patch_port->tied_port()->buffer(0)->data()); - assert(m_patch_port->buffer(0)->data() == m_jack_buffer->data()); -} - - -//// JackAudioDriver //// - -JackAudioDriver::JackAudioDriver() -: m_client(NULL), - m_buffer_size(0), - m_sample_rate(0), - m_is_activated(false), - m_local_client(true), - m_root_patch(NULL), - m_start_of_current_cycle(0), - m_start_of_last_cycle(0) -{ - m_client = jack_client_new("Om"); - if (m_client == NULL) { - cerr << "[JackAudioDriver] Unable to connect to Jack. Exiting." << endl; - exit(EXIT_FAILURE); - } - - jack_on_shutdown(m_client, shutdown_cb, this); - - m_buffer_size = jack_get_buffer_size(m_client); - m_sample_rate = jack_get_sample_rate(m_client); - - jack_set_sample_rate_callback(m_client, sample_rate_cb, this); - jack_set_buffer_size_callback(m_client, buffer_size_cb, this); -} - -JackAudioDriver::JackAudioDriver(jack_client_t* jack_client) -: m_client(jack_client), - m_buffer_size(jack_get_buffer_size(jack_client)), - m_sample_rate(jack_get_sample_rate(jack_client)), - m_is_activated(false), - m_local_client(false), - m_start_of_current_cycle(0), - m_start_of_last_cycle(0) -{ - jack_on_shutdown(m_client, shutdown_cb, this); - - jack_set_sample_rate_callback(m_client, sample_rate_cb, this); - jack_set_buffer_size_callback(m_client, buffer_size_cb, this); -} - - -JackAudioDriver::~JackAudioDriver() -{ - deactivate(); - - if (m_local_client) - jack_client_close(m_client); -} - - -void -JackAudioDriver::activate() -{ - if (m_is_activated) { - cerr << "[JackAudioDriver] Jack driver already activated." << endl; - return; - } - - jack_set_process_callback(m_client, process_cb, this); - - m_is_activated = true; - - if (jack_activate(m_client)) { - cerr << "[JackAudioDriver] Could not activate Jack client, aborting." << endl; - exit(EXIT_FAILURE); - } else { - cout << "[JackAudioDriver] Activated Jack client." << endl; -#ifdef HAVE_LASH - lash_driver->set_jack_client_name("Om"); // FIXME: unique name -#endif - } -} - - -void -JackAudioDriver::deactivate() -{ - if (m_is_activated) { - // FIXME - reinterpret_cast<EventSource*>(om->osc_receiver())->stop(); - - jack_deactivate(m_client); - m_is_activated = false; - - for (List<JackAudioPort*>::iterator i = m_ports.begin(); i != m_ports.end(); ++i) - jack_port_unregister(m_client, (*i)->jack_port()); - - m_ports.clear(); - - cout << "[JackAudioDriver] Deactivated Jack client." << endl; - - om->post_processor()->stop(); - } -} - - -/** Add a Jack port. - * - * Realtime safe, this is to be called at the beginning of a process cycle to - * insert (and actually begin using) a new port. - * - * See create_port() and remove_port(). - */ -void -JackAudioDriver::add_port(JackAudioPort* port) -{ - m_ports.push_back(port); -} - - -/** Remove a Jack port. - * - * Realtime safe. This is to be called at the beginning of a process cycle to - * remove the port from the lists read by the audio thread, so the port - * will no longer be used and can be removed afterwards. - * - * It is the callers responsibility to delete the returned port. - */ -JackAudioPort* -JackAudioDriver::remove_port(JackAudioPort* port) -{ - for (List<JackAudioPort*>::iterator i = m_ports.begin(); i != m_ports.end(); ++i) - if ((*i) == port) - return m_ports.remove(i)->elem(); - - cerr << "[JackAudioDriver::remove_port] WARNING: Failed to find Jack port to remove!" << endl; - return NULL; -} - - -DriverPort* -JackAudioDriver::create_port(PortBase<sample>* patch_port) -{ - if (patch_port->buffer_size() == m_buffer_size) - return new JackAudioPort(this, patch_port); - else - return NULL; -} - - -/** Process all the pending events for this cycle. - * - * Called from the realtime thread once every process cycle. - */ -void -JackAudioDriver::process_events(jack_nframes_t block_start, jack_nframes_t block_end) -{ - Event* ev = NULL; - - /* Limit the maximum number of queued events to process per cycle. This - * makes the process callback truly realtime-safe by preventing being - * choked by events coming in faster than they can be processed. - * FIXME: run the math on this and figure out a good value */ - const int MAX_SLOW_EVENTS = m_buffer_size / 100; - - int num_events_processed = 0; - int offset = 0; - - // Process the "slow" events first, because it's possible some of the - // RT events depend on them - - // FIXME - while ((ev = reinterpret_cast<EventSource*>(om->osc_receiver()) - ->pop_earliest_event_before(block_end)) != NULL) { - ev->execute(0); // QueuedEvents are not sample accurate - om->post_processor()->push(ev); - if (++num_events_processed > MAX_SLOW_EVENTS) - break; - } - - while (!om->event_queue()->is_empty() - && om->event_queue()->front()->time_stamp() < block_end) { - ev = om->event_queue()->pop(); - offset = ev->time_stamp() - block_start; - if (offset < 0) offset = 0; // this can happen if we miss a cycle - ev->execute(offset); - om->post_processor()->push(ev); - ++num_events_processed; - } - - if (num_events_processed > 0) - om->post_processor()->signal(); -} - - - -/**** Jack Callbacks ****/ - - - -/** Jack process callback, drives entire audio thread. - * - * \callgraph - */ -int -JackAudioDriver::m_process_cb(jack_nframes_t nframes) -{ - // FIXME: support nframes != buffer_size, even though that never damn well happens - assert(nframes == m_buffer_size); - - // Note that jack can elect to not call this function for a cycle, if things aren't - // keeping up - m_start_of_current_cycle = jack_last_frame_time(m_client); - m_start_of_last_cycle = m_start_of_current_cycle - nframes; - - assert(m_start_of_current_cycle - m_start_of_last_cycle == nframes); - - m_transport_state = jack_transport_query(m_client, &m_position); - - process_events(m_start_of_last_cycle, m_start_of_current_cycle); - om->midi_driver()->prepare_block(m_start_of_last_cycle, m_start_of_current_cycle); - - // Set buffers of patch ports to Jack port buffers (zero-copy processing) - for (List<JackAudioPort*>::iterator i = m_ports.begin(); i != m_ports.end(); ++i) - (*i)->prepare_buffer(nframes); - - // Run root patch - assert(m_root_patch != NULL); - m_root_patch->run(nframes); - - return 0; -} - - -void -JackAudioDriver::m_shutdown_cb() -{ - cout << "[JackAudioDriver] Jack shutdown. Exiting." << endl; - om->quit(); -} - - -int -JackAudioDriver::m_sample_rate_cb(jack_nframes_t nframes) -{ - if (m_is_activated) { - cerr << "[JackAudioDriver] Om does not support changing sample rate on the fly (yet). Aborting." << endl; - exit(EXIT_FAILURE); - } else { - m_sample_rate = nframes; - } - return 0; -} - - -int -JackAudioDriver::m_buffer_size_cb(jack_nframes_t nframes) -{ - if (m_is_activated) { - cerr << "[JackAudioDriver] Om does not support chanding buffer size on the fly (yet). Aborting." << endl; - exit(EXIT_FAILURE); - } else { - m_buffer_size = nframes; - } - return 0; -} - - -} // namespace Om - |