// -*- c-basic-offset: 4 -*- /* Rosegarden A sequencer and musical notation editor. This program is Copyright 2000-2008 Guillaume Laurent , Chris Cannam , Richard Bown The moral right of the authors to claim authorship of this work has been asserted. This program 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. See the file COPYING included with this distribution for more information. */ #include "JackDriver.h" #include "AlsaDriver.h" #include "MappedStudio.h" #include "AudioProcess.h" #include "Profiler.h" #include "AudioLevel.h" #include "Audit.h" #include "PluginFactory.h" #ifdef HAVE_ALSA #ifdef HAVE_LIBJACK //#define DEBUG_JACK_DRIVER 1 //#define DEBUG_JACK_TRANSPORT 1 //#define DEBUG_JACK_PROCESS 1 //#define DEBUG_JACK_XRUN 1 namespace Rosegarden { #if (defined(DEBUG_JACK_DRIVER) || defined(DEBUG_JACK_PROCESS) || defined(DEBUG_JACK_TRANSPORT)) static unsigned long framesThisPlay = 0; static RealTime startTime; #endif JackDriver::JackDriver(AlsaDriver *alsaDriver) : m_client(0), m_bufferSize(0), m_sampleRate(0), m_tempOutBuffer(0), m_jackTransportEnabled(false), m_jackTransportMaster(false), m_waiting(false), m_waitingState(JackTransportStopped), m_waitingToken(0), m_ignoreProcessTransportCount(0), m_bussMixer(0), m_instrumentMixer(0), m_fileReader(0), m_fileWriter(0), m_alsaDriver(alsaDriver), m_masterLevel(1.0), m_directMasterAudioInstruments(0L), m_directMasterSynthInstruments(0L), m_haveAsyncAudioEvent(false), m_kickedOutAt(0), m_framesProcessed(0), m_ok(false) { assert(sizeof(sample_t) == sizeof(float)); initialise(); } JackDriver::~JackDriver() { #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::~JackDriver" << std::endl; #endif m_ok = false; // prevent any more work in process() if (m_client) { #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::shutdown - deactivating JACK client" << std::endl; #endif if (jack_deactivate(m_client)) { std::cerr << "JackDriver::shutdown - deactivation failed" << std::endl; } } #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::~JackDriver: terminating buss mixer" << std::endl; #endif AudioBussMixer *bussMixer = m_bussMixer; m_bussMixer = 0; if (bussMixer) bussMixer->terminate(); #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::~JackDriver: terminating instrument mixer" << std::endl; #endif AudioInstrumentMixer *instrumentMixer = m_instrumentMixer; m_instrumentMixer = 0; if (instrumentMixer) { instrumentMixer->terminate(); instrumentMixer->destroyAllPlugins(); } #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::~JackDriver: terminating file reader" << std::endl; #endif AudioFileReader *reader = m_fileReader; m_fileReader = 0; if (reader) reader->terminate(); #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::~JackDriver: terminating file writer" << std::endl; #endif AudioFileWriter *writer = m_fileWriter; m_fileWriter = 0; if (writer) writer->terminate(); if (m_client) { #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::shutdown - tearing down JACK client" << std::endl; #endif for (unsigned int i = 0; i < m_inputPorts.size(); ++i) { #ifdef DEBUG_JACK_DRIVER std::cerr << "unregistering input " << i << std::endl; #endif if (jack_port_unregister(m_client, m_inputPorts[i])) { std::cerr << "JackDriver::shutdown - " << "can't unregister input port " << i + 1 << std::endl; } } for (unsigned int i = 0; i < m_outputSubmasters.size(); ++i) { #ifdef DEBUG_JACK_DRIVER std::cerr << "unregistering output sub " << i << std::endl; #endif if (jack_port_unregister(m_client, m_outputSubmasters[i])) { std::cerr << "JackDriver::shutdown - " << "can't unregister output submaster " << i + 1 << std::endl; } } for (unsigned int i = 0; i < m_outputMonitors.size(); ++i) { #ifdef DEBUG_JACK_DRIVER std::cerr << "unregistering output mon " << i << std::endl; #endif if (jack_port_unregister(m_client, m_outputMonitors[i])) { std::cerr << "JackDriver::shutdown - " << "can't unregister output monitor " << i + 1 << std::endl; } } for (unsigned int i = 0; i < m_outputMasters.size(); ++i) { #ifdef DEBUG_JACK_DRIVER std::cerr << "unregistering output master " << i << std::endl; #endif if (jack_port_unregister(m_client, m_outputMasters[i])) { std::cerr << "JackDriver::shutdown - " << "can't unregister output master " << i + 1 << std::endl; } } #ifdef DEBUG_JACK_DRIVER std::cerr << "closing client" << std::endl; #endif jack_client_close(m_client); std::cerr << "done" << std::endl; m_client = 0; } #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver: deleting mixers etc" << std::endl; #endif delete bussMixer; delete instrumentMixer; delete reader; delete writer; #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::~JackDriver exiting" << std::endl; #endif } void JackDriver::initialise(bool reinitialise) { m_ok = false; Audit audit; audit << std::endl; std::string jackClientName = "rosegarden"; // attempt connection to JACK server // if ((m_client = jack_client_new(jackClientName.c_str())) == 0) { audit << "JackDriver::initialiseAudio - " << "JACK server not running" << std::endl; return ; } InstrumentId instrumentBase; int instrumentCount; m_alsaDriver->getAudioInstrumentNumbers(instrumentBase, instrumentCount); for (InstrumentId id = instrumentBase; id < instrumentBase + instrumentCount; ++id) { // prefill so that we can refer to the map without a lock (as // the number of instruments won't change) m_recordInputs[id] = RecordInputDesc(1000, -1, 0.0); } // set callbacks // jack_set_process_callback(m_client, jackProcessStatic, this); jack_set_buffer_size_callback(m_client, jackBufferSize, this); jack_set_sample_rate_callback(m_client, jackSampleRate, this); jack_on_shutdown(m_client, jackShutdown, this); jack_set_xrun_callback(m_client, jackXRun, this); jack_set_sync_callback(m_client, jackSyncCallback, this); // get and report the sample rate and buffer size // m_sampleRate = jack_get_sample_rate(m_client); m_bufferSize = jack_get_buffer_size(m_client); audit << "JackDriver::initialiseAudio - JACK sample rate = " << m_sampleRate << "Hz, buffer size = " << m_bufferSize << std::endl; PluginFactory::setSampleRate(m_sampleRate); // Get the initial buffer size before we activate the client // if (!reinitialise) { // create processing buffer(s) // m_tempOutBuffer = new sample_t[m_bufferSize]; audit << "JackDriver::initialiseAudio - " << "creating disk thread" << std::endl; m_fileReader = new AudioFileReader(m_alsaDriver, m_sampleRate); m_fileWriter = new AudioFileWriter(m_alsaDriver, m_sampleRate); m_instrumentMixer = new AudioInstrumentMixer (m_alsaDriver, m_fileReader, m_sampleRate, m_bufferSize); m_bussMixer = new AudioBussMixer (m_alsaDriver, m_instrumentMixer, m_sampleRate, m_bufferSize); m_instrumentMixer->setBussMixer(m_bussMixer); // We run the file reader whatever, but we only run the other // threads (instrument mixer, buss mixer, file writer) when we // actually need them. (See updateAudioData and createRecordFile.) m_fileReader->run(); } // Create and connect the default numbers of ports. We always create // one stereo pair each of master and monitor outs, and then we create // record ins, fader outs and submaster outs according to the user's // preferences. Since we don't know the user's preferences yet, we'll // start by creating one pair of record ins and no fader or submaster // outs. // m_outputMasters.clear(); m_outputMonitors.clear(); m_outputSubmasters.clear(); m_outputInstruments.clear(); m_inputPorts.clear(); if (!createMainOutputs()) { // one stereo pair master, one pair monitor audit << "JackDriver::initialise - " << "failed to create main outputs!" << std::endl; return ; } if (!createRecordInputs(1)) { audit << "JackDriver::initialise - " << "failed to create record inputs!" << std::endl; return ; } if (jack_activate(m_client)) { audit << "JackDriver::initialise - " << "client activation failed" << std::endl; return ; } // Now set up the default connections. std::string playback_1, playback_2; const char **ports = jack_get_ports(m_client, NULL, NULL, JackPortIsPhysical | JackPortIsInput); if (ports) { if (ports[0]) playback_1 = std::string(ports[0]); if (ports[1]) playback_2 = std::string(ports[1]); // count ports unsigned int i = 0; for (i = 0; ports[i]; i++) ; audit << "JackDriver::initialiseAudio - " << "found " << i << " JACK physical outputs" << std::endl; } else audit << "JackDriver::initialiseAudio - " << "no JACK physical outputs found" << std::endl; free(ports); if (playback_1 != "") { audit << "JackDriver::initialiseAudio - " << "connecting from " << "\"" << jack_port_name(m_outputMasters[0]) << "\" to \"" << playback_1.c_str() << "\"" << std::endl; // connect our client up to the ALSA ports - first left output // if (jack_connect(m_client, jack_port_name(m_outputMasters[0]), playback_1.c_str())) { audit << "JackDriver::initialiseAudio - " << "cannot connect to JACK output port" << std::endl; return ; } /* if (jack_connect(m_client, jack_port_name(m_outputMonitors[0]), playback_1.c_str())) { audit << "JackDriver::initialiseAudio - " << "cannot connect to JACK output port" << std::endl; return; } */ } if (playback_2 != "") { audit << "JackDriver::initialiseAudio - " << "connecting from " << "\"" << jack_port_name(m_outputMasters[1]) << "\" to \"" << playback_2.c_str() << "\"" << std::endl; if (jack_connect(m_client, jack_port_name(m_outputMasters[1]), playback_2.c_str())) { audit << "JackDriver::initialiseAudio - " << "cannot connect to JACK output port" << std::endl; } /* if (jack_connect(m_client, jack_port_name(m_outputMonitors[1]), playback_2.c_str())) { audit << "JackDriver::initialiseAudio - " << "cannot connect to JACK output port" << std::endl; } */ } std::string capture_1, capture_2; ports = jack_get_ports(m_client, NULL, NULL, JackPortIsPhysical | JackPortIsOutput); if (ports) { if (ports[0]) capture_1 = std::string(ports[0]); if (ports[1]) capture_2 = std::string(ports[1]); // count ports unsigned int i = 0; for (i = 0; ports[i]; i++) ; audit << "JackDriver::initialiseAudio - " << "found " << i << " JACK physical inputs" << std::endl; } else audit << "JackDriver::initialiseAudio - " << "no JACK physical inputs found" << std::endl; free(ports); if (capture_1 != "") { audit << "JackDriver::initialiseAudio - " << "connecting from " << "\"" << capture_1.c_str() << "\" to \"" << jack_port_name(m_inputPorts[0]) << "\"" << std::endl; if (jack_connect(m_client, capture_1.c_str(), jack_port_name(m_inputPorts[0]))) { audit << "JackDriver::initialiseAudio - " << "cannot connect to JACK input port" << std::endl; } } if (capture_2 != "") { audit << "JackDriver::initialiseAudio - " << "connecting from " << "\"" << capture_2.c_str() << "\" to \"" << jack_port_name(m_inputPorts[1]) << "\"" << std::endl; if (jack_connect(m_client, capture_2.c_str(), jack_port_name(m_inputPorts[1]))) { audit << "JackDriver::initialiseAudio - " << "cannot connect to JACK input port" << std::endl; } } audit << "JackDriver::initialiseAudio - " << "initialised JACK audio subsystem" << std::endl; m_ok = true; } bool JackDriver::createMainOutputs() { if (!m_client) return false; jack_port_t *port = jack_port_register (m_client, "master out L", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (!port) return false; m_outputMasters.push_back(port); port = jack_port_register (m_client, "master out R", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (!port) return false; m_outputMasters.push_back(port); port = jack_port_register (m_client, "record monitor out L", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (!port) return false; m_outputMonitors.push_back(port); port = jack_port_register (m_client, "record monitor out R", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (!port) return false; m_outputMonitors.push_back(port); return true; } bool JackDriver::createFaderOutputs(int audioPairs, int synthPairs) { if (!m_client) return false; int pairs = audioPairs + synthPairs; int pairsNow = m_outputInstruments.size() / 2; if (pairs == pairsNow) return true; for (int i = pairsNow; i < pairs; ++i) { char namebuffer[22]; jack_port_t *port; if (i < audioPairs) { snprintf(namebuffer, 21, "audio fader %d out L", i + 1); } else { snprintf(namebuffer, 21, "synth fader %d out L", i - audioPairs + 1); } port = jack_port_register(m_client, namebuffer, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (!port) return false; m_outputInstruments.push_back(port); if (i < audioPairs) { snprintf(namebuffer, 21, "audio fader %d out R", i + 1); } else { snprintf(namebuffer, 21, "synth fader %d out R", i - audioPairs + 1); } port = jack_port_register(m_client, namebuffer, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (!port) return false; m_outputInstruments.push_back(port); } while ((int)m_outputInstruments.size() > pairs * 2) { std::vector::iterator itr = m_outputInstruments.end(); --itr; jack_port_unregister(m_client, *itr); m_outputInstruments.erase(itr); } return true; } bool JackDriver::createSubmasterOutputs(int pairs) { if (!m_client) return false; int pairsNow = m_outputSubmasters.size() / 2; if (pairs == pairsNow) return true; for (int i = pairsNow; i < pairs; ++i) { char namebuffer[22]; jack_port_t *port; snprintf(namebuffer, 21, "submaster %d out L", i + 1); port = jack_port_register(m_client, namebuffer, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (!port) return false; m_outputSubmasters.push_back(port); snprintf(namebuffer, 21, "submaster %d out R", i + 1); port = jack_port_register(m_client, namebuffer, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (!port) return false; m_outputSubmasters.push_back(port); } while ((int)m_outputSubmasters.size() > pairs * 2) { std::vector::iterator itr = m_outputSubmasters.end(); --itr; jack_port_unregister(m_client, *itr); m_outputSubmasters.erase(itr); } return true; } bool JackDriver::createRecordInputs(int pairs) { if (!m_client) return false; int pairsNow = m_inputPorts.size() / 2; if (pairs == pairsNow) return true; for (int i = pairsNow; i < pairs; ++i) { char namebuffer[22]; jack_port_t *port; snprintf(namebuffer, 21, "record in %d L", i + 1); port = jack_port_register(m_client, namebuffer, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); if (!port) return false; m_inputPorts.push_back(port); snprintf(namebuffer, 21, "record in %d R", i + 1); port = jack_port_register(m_client, namebuffer, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); if (!port) return false; m_inputPorts.push_back(port); } while ((int)m_outputSubmasters.size() > pairs * 2) { std::vector::iterator itr = m_outputSubmasters.end(); --itr; jack_port_unregister(m_client, *itr); m_outputSubmasters.erase(itr); } return true; } void JackDriver::setAudioPorts(bool faderOuts, bool submasterOuts) { if (!m_client) return ; Audit audit; #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::setAudioPorts(" << faderOuts << "," << submasterOuts << ")" << std::endl; #endif if (!m_client) { std::cerr << "JackDriver::setAudioPorts(" << faderOuts << "," << submasterOuts << "): no client yet" << std::endl; return ; } if (faderOuts) { InstrumentId instrumentBase; int audioInstruments; int synthInstruments; m_alsaDriver->getAudioInstrumentNumbers(instrumentBase, audioInstruments); m_alsaDriver->getSoftSynthInstrumentNumbers(instrumentBase, synthInstruments); if (!createFaderOutputs(audioInstruments, synthInstruments)) { m_ok = false; audit << "Failed to create fader outs!" << std::endl; return ; } } else { createFaderOutputs(0, 0); } if (submasterOuts) { // one fewer than returned here, because the master has a buss object too if (!createSubmasterOutputs (m_alsaDriver->getMappedStudio()->getObjectCount (MappedObject::AudioBuss) - 1)) { m_ok = false; audit << "Failed to create submaster outs!" << std::endl; return ; } } else { createSubmasterOutputs(0); } } RealTime JackDriver::getAudioPlayLatency() const { if (!m_client) return RealTime::zeroTime; jack_nframes_t latency = jack_port_get_total_latency(m_client, m_outputMasters[0]); return RealTime::frame2RealTime(latency, m_sampleRate); } RealTime JackDriver::getAudioRecordLatency() const { if (!m_client) return RealTime::zeroTime; jack_nframes_t latency = jack_port_get_total_latency(m_client, m_inputPorts[0]); return RealTime::frame2RealTime(latency, m_sampleRate); } RealTime JackDriver::getInstrumentPlayLatency(InstrumentId id) const { if (m_instrumentLatencies.find(id) == m_instrumentLatencies.end()) { return RealTime::zeroTime; } else { return m_instrumentLatencies.find(id)->second; } } RealTime JackDriver::getMaximumPlayLatency() const { return m_maxInstrumentLatency; } int JackDriver::jackProcessStatic(jack_nframes_t nframes, void *arg) { JackDriver *inst = static_cast(arg); if (inst) return inst->jackProcess(nframes); else return 0; } int JackDriver::jackProcess(jack_nframes_t nframes) { if (!m_ok || !m_client) { #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcess: not OK" << std::endl; #endif return 0; } if (!m_bussMixer) { #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcess: no buss mixer" << std::endl; #endif return jackProcessEmpty(nframes); } if (m_alsaDriver->areClocksRunning()) { m_alsaDriver->checkTimerSync(m_framesProcessed); } else { m_alsaDriver->checkTimerSync(0); } bool lowLatencyMode = m_alsaDriver->getLowLatencyMode(); bool clocksRunning = m_alsaDriver->areClocksRunning(); bool playing = m_alsaDriver->isPlaying(); bool asyncAudio = m_haveAsyncAudioEvent; #ifdef DEBUG_JACK_PROCESS Profiler profiler("jackProcess", true); #else #ifdef DEBUG_JACK_XRUN Profiler profiler("jackProcess", false); #endif #endif if (lowLatencyMode) { if (clocksRunning) { if (playing || asyncAudio) { if (m_instrumentMixer->tryLock() == 0) { m_instrumentMixer->kick(false); m_instrumentMixer->releaseLock(); //#ifdef DEBUG_JACK_PROCESS } else { std::cerr << "JackDriver::jackProcess: no instrument mixer lock available" << std::endl; //#endif } if (m_bussMixer->getBussCount() > 0) { if (m_bussMixer->tryLock() == 0) { m_bussMixer->kick(false, false); m_bussMixer->releaseLock(); //#ifdef DEBUG_JACK_PROCESS } else { std::cerr << "JackDriver::jackProcess: no buss mixer lock available" << std::endl; //#endif } } } } } if (jack_cpu_load(m_client) > 97.0) { reportFailure(MappedEvent::FailureCPUOverload); return jackProcessEmpty(nframes); } #ifdef DEBUG_JACK_PROCESS Profiler profiler2("jackProcess post mix", true); #else #ifdef DEBUG_JACK_XRUN Profiler profiler2("jackProcess post mix", false); #endif #endif SequencerDataBlock *sdb = m_alsaDriver->getSequencerDataBlock(); jack_position_t position; jack_transport_state_t state = JackTransportRolling; bool doneRecord = false; int ignoreCount = m_ignoreProcessTransportCount; if (ignoreCount > 0) --m_ignoreProcessTransportCount; InstrumentId audioInstrumentBase; int audioInstruments; m_alsaDriver->getAudioInstrumentNumbers(audioInstrumentBase, audioInstruments); if (m_jackTransportEnabled) { state = jack_transport_query(m_client, &position); #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcess: JACK transport state is " << state << std::endl; #endif if (state == JackTransportStopped) { if (playing && clocksRunning && !m_waiting) { ExternalTransport *transport = m_alsaDriver->getExternalTransportControl(); if (transport) { #ifdef DEBUG_JACK_TRANSPORT std::cerr << "JackDriver::jackProcess: JACK transport stopped externally at " << position.frame << std::endl; #endif m_waitingToken = transport->transportJump (ExternalTransport::TransportStopAtTime, RealTime::frame2RealTime(position.frame, position.frame_rate)); } } else if (clocksRunning) { if (!asyncAudio) { #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcess: no interesting async events" << std::endl; #endif // do this before record monitor, otherwise we lose monitor out jackProcessEmpty(nframes); } // for monitoring: int rv = 0; for (InstrumentId id = audioInstrumentBase; id < audioInstrumentBase + audioInstruments; ++id) { int irv = jackProcessRecord(id, nframes, 0, 0, clocksRunning); if (irv != 0) rv = irv; } doneRecord = true; if (!asyncAudio) { return rv; } } else { return jackProcessEmpty(nframes); } } else if (state == JackTransportStarting) { return jackProcessEmpty(nframes); } else if (state != JackTransportRolling) { std::cerr << "JackDriver::jackProcess: unexpected JACK transport state " << state << std::endl; } } if (state == JackTransportRolling) { // also covers not-on-transport case if (m_waiting) { if (ignoreCount > 0) { #ifdef DEBUG_JACK_TRANSPORT std::cerr << "JackDriver::jackProcess: transport rolling, but we're ignoring it (count = " << ignoreCount << ")" << std::endl; #endif } else { #ifdef DEBUG_JACK_TRANSPORT std::cerr << "JackDriver::jackProcess: transport rolling, telling ALSA driver to go!" << std::endl; #endif m_alsaDriver->startClocksApproved(); m_waiting = false; } } #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcess (rolling or not on JACK transport)" << std::endl; #endif if (!clocksRunning) { #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcess: clocks stopped" << std::endl; #endif return jackProcessEmpty(nframes); } else if (!playing) { #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcess: not playing" << std::endl; #endif if (!asyncAudio) { #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcess: no interesting async events" << std::endl; #endif // do this before record monitor, otherwise we lose monitor out jackProcessEmpty(nframes); } // for monitoring: int rv = 0; for (InstrumentId id = audioInstrumentBase; id < audioInstrumentBase + audioInstruments; ++id) { int irv = jackProcessRecord(id, nframes, 0, 0, clocksRunning); if (irv != 0) rv = irv; } doneRecord = true; if (!asyncAudio) { return rv; } } } #ifdef DEBUG_JACK_PROCESS Profiler profiler3("jackProcess post transport", true); #else #ifdef DEBUG_JACK_XRUN Profiler profiler3("jackProcess post transport", false); #endif #endif InstrumentId synthInstrumentBase; int synthInstruments; m_alsaDriver->getSoftSynthInstrumentNumbers(synthInstrumentBase, synthInstruments); // We always have the master out sample_t *master[2] = { static_cast (jack_port_get_buffer(m_outputMasters[0], nframes)), static_cast (jack_port_get_buffer(m_outputMasters[1], nframes)) }; memset(master[0], 0, nframes * sizeof(sample_t)); memset(master[1], 0, nframes * sizeof(sample_t)); // Reset monitor outs (if present) here prior to mixing if (m_outputMonitors.size() > 0) { sample_t *buffer = static_cast (jack_port_get_buffer(m_outputMonitors[0], nframes)); if (buffer) memset(buffer, 0, nframes * sizeof(sample_t)); } if (m_outputMonitors.size() > 1) { sample_t *buffer = static_cast (jack_port_get_buffer(m_outputMonitors[1], nframes)); if (buffer) memset(buffer, 0, nframes * sizeof(sample_t)); } int bussCount = m_bussMixer->getBussCount(); // If we have any busses, then we just mix from them (but we still // need to keep ourselves up to date by reading and monitoring the // instruments). If we have no busses, mix direct from instruments. for (int buss = 0; buss < bussCount; ++buss) { sample_t *submaster[2] = { 0, 0 }; sample_t peak[2] = { 0.0, 0.0 }; if ((int)m_outputSubmasters.size() > buss * 2 + 1) { submaster[0] = static_cast (jack_port_get_buffer(m_outputSubmasters[buss * 2], nframes)); submaster[1] = static_cast (jack_port_get_buffer(m_outputSubmasters[buss * 2 + 1], nframes)); } if (!submaster[0]) submaster[0] = m_tempOutBuffer; if (!submaster[1]) submaster[1] = m_tempOutBuffer; for (int ch = 0; ch < 2; ++ch) { RingBuffer *rb = m_bussMixer->getRingBuffer(buss, ch); if (!rb || m_bussMixer->isBussDormant(buss)) { if (rb) rb->skip(nframes); if (submaster[ch]) memset(submaster[ch], 0, nframes * sizeof(sample_t)); } else { size_t actual = rb->read(submaster[ch], nframes); if (actual < nframes) { reportFailure(MappedEvent::FailureBussMixUnderrun); } for (size_t i = 0; i < nframes; ++i) { sample_t sample = submaster[ch][i]; if (sample > peak[ch]) peak[ch] = sample; master[ch][i] += sample; } } } if (sdb) { LevelInfo info; info.level = AudioLevel::multiplier_to_fader (peak[0], 127, AudioLevel::LongFader); info.levelRight = AudioLevel::multiplier_to_fader (peak[1], 127, AudioLevel::LongFader); sdb->setSubmasterLevel(buss, info); } for (InstrumentId id = audioInstrumentBase; id < audioInstrumentBase + audioInstruments; ++id) { if (buss + 1 == m_recordInputs[id].input) { jackProcessRecord(id, nframes, submaster[0], submaster[1], clocksRunning); } } } #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcess: have " << audioInstruments << " audio and " << synthInstruments << " synth instruments and " << bussCount << " busses" << std::endl; #endif bool allInstrumentsDormant = true; static RealTime dormantTime = RealTime::zeroTime; for (int i = 0; i < audioInstruments + synthInstruments; ++i) { InstrumentId id; if (i < audioInstruments) id = audioInstrumentBase + i; else id = synthInstrumentBase + (i - audioInstruments); if (m_instrumentMixer->isInstrumentEmpty(id)) continue; sample_t *instrument[2] = { 0, 0 }; sample_t peak[2] = { 0.0, 0.0 }; if (int(m_outputInstruments.size()) > i * 2 + 1) { instrument[0] = static_cast (jack_port_get_buffer(m_outputInstruments[i * 2], nframes)); instrument[1] = static_cast (jack_port_get_buffer(m_outputInstruments[i * 2 + 1], nframes)); } if (!instrument[0]) instrument[0] = m_tempOutBuffer; if (!instrument[1]) instrument[1] = m_tempOutBuffer; for (int ch = 0; ch < 2; ++ch) { // We always need to read from an instrument's ring buffer // to keep the instrument moving along, as well as for // monitoring. If the instrument is connected straight to // the master, then we also need to mix from it. (We have // that information cached courtesy of updateAudioData.) bool directToMaster = false; if (i < audioInstruments) { directToMaster = (m_directMasterAudioInstruments & (1 << i)); } else { directToMaster = (m_directMasterSynthInstruments & (1 << (i - audioInstruments))); } #ifdef DEBUG_JACK_PROCESS if (id == 1000 || id == 10000) { std::cerr << "JackDriver::jackProcess: instrument id " << id << ", base " << audioInstrumentBase << ", direct masters " << m_directMasterAudioInstruments << ": " << directToMaster << std::endl; } #endif RingBuffer *rb = m_instrumentMixer->getRingBuffer(id, ch); if (!rb || m_instrumentMixer->isInstrumentDormant(id)) { #ifdef DEBUG_JACK_PROCESS if (id == 1000 || id == 10000) { if (rb) { std::cerr << "JackDriver::jackProcess: instrument " << id << " dormant" << std::endl; } else { std::cerr << "JackDriver::jackProcess: instrument " << id << " has no ring buffer for channel " << ch << std::endl; } } #endif if (rb) rb->skip(nframes); if (instrument[ch]) memset(instrument[ch], 0, nframes * sizeof(sample_t)); } else { allInstrumentsDormant = false; size_t actual = rb->read(instrument[ch], nframes); #ifdef DEBUG_JACK_PROCESS if (id == 1000) { std::cerr << "JackDriver::jackProcess: read " << actual << " of " << nframes << " frames for instrument " << id << " channel " << ch << std::endl; } #endif if (actual < nframes) { std::cerr << "JackDriver::jackProcess: read " << actual << " of " << nframes << " frames for " << id << " ch " << ch << " (pl " << playing << ", cl " << clocksRunning << ", aa " << asyncAudio << ")" << std::endl; reportFailure(MappedEvent::FailureMixUnderrun); } for (size_t f = 0; f < nframes; ++f) { sample_t sample = instrument[ch][f]; if (sample > peak[ch]) peak[ch] = sample; if (directToMaster) master[ch][f] += sample; } } // If the instrument is connected straight to master we // also need to skip() on the buss mixer's reader for it, // otherwise it'll block because the buss mixer isn't // needing to read it. if (rb && directToMaster) { rb->skip(nframes, 1); // 1 is the buss mixer's reader (magic) } } if (sdb) { LevelInfo info; info.level = AudioLevel::multiplier_to_fader (peak[0], 127, AudioLevel::LongFader); info.levelRight = AudioLevel::multiplier_to_fader (peak[1], 127, AudioLevel::LongFader); sdb->setInstrumentLevel(id, info); } } if (asyncAudio) { if (!allInstrumentsDormant) { dormantTime = RealTime::zeroTime; } else { dormantTime = dormantTime + RealTime::frame2RealTime(m_bufferSize, m_sampleRate); if (dormantTime > RealTime(10, 0)) { std::cerr << "JackDriver: dormantTime = " << dormantTime << ", resetting m_haveAsyncAudioEvent" << std::endl; m_haveAsyncAudioEvent = false; } } } // Get master fader levels. There's no pan on the master. float gain = AudioLevel::dB_to_multiplier(m_masterLevel); float masterPeak[2] = { 0.0, 0.0 }; for (int ch = 0; ch < 2; ++ch) { for (size_t i = 0; i < nframes; ++i) { sample_t sample = master[ch][i] * gain; if (sample > masterPeak[ch]) masterPeak[ch] = sample; master[ch][i] = sample; } } if (sdb) { LevelInfo info; info.level = AudioLevel::multiplier_to_fader (masterPeak[0], 127, AudioLevel::LongFader); info.levelRight = AudioLevel::multiplier_to_fader (masterPeak[1], 127, AudioLevel::LongFader); sdb->setMasterLevel(info); } for (InstrumentId id = audioInstrumentBase; id < audioInstrumentBase + audioInstruments; ++id) { if (m_recordInputs[id].input == 0) { jackProcessRecord(id, nframes, master[0], master[1], clocksRunning); } else if (m_recordInputs[id].input < 1000) { // buss, already done // nothing } else if (!doneRecord) { jackProcessRecord(id, nframes, 0, 0, clocksRunning); } } if (playing) { if (!lowLatencyMode) { if (m_bussMixer->getBussCount() == 0) { m_instrumentMixer->signal(); } else { m_bussMixer->signal(); } } } m_framesProcessed += nframes; #if (defined(DEBUG_JACK_DRIVER) || defined(DEBUG_JACK_PROCESS) || defined(DEBUG_JACK_TRANSPORT)) framesThisPlay += nframes; //!!! #endif #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcess: " << nframes << " frames, " << framesThisPlay << " this play, " << m_framesProcessed << " total" << std::endl; #endif return 0; } int JackDriver::jackProcessEmpty(jack_nframes_t nframes) { sample_t *buffer; #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcessEmpty" << std::endl; #endif buffer = static_cast (jack_port_get_buffer(m_outputMasters[0], nframes)); if (buffer) memset(buffer, 0, nframes * sizeof(sample_t)); buffer = static_cast (jack_port_get_buffer(m_outputMasters[1], nframes)); if (buffer) memset(buffer, 0, nframes * sizeof(sample_t)); buffer = static_cast (jack_port_get_buffer(m_outputMonitors[0], nframes)); if (buffer) memset(buffer, 0, nframes * sizeof(sample_t)); buffer = static_cast (jack_port_get_buffer(m_outputMonitors[1], nframes)); if (buffer) memset(buffer, 0, nframes * sizeof(sample_t)); for (unsigned int i = 0; i < m_outputSubmasters.size(); ++i) { buffer = static_cast (jack_port_get_buffer(m_outputSubmasters[i], nframes)); if (buffer) memset(buffer, 0, nframes * sizeof(sample_t)); } for (unsigned int i = 0; i < m_outputInstruments.size(); ++i) { buffer = static_cast (jack_port_get_buffer(m_outputInstruments[i], nframes)); if (buffer) memset(buffer, 0, nframes * sizeof(sample_t)); } m_framesProcessed += nframes; #if (defined(DEBUG_JACK_DRIVER) || defined(DEBUG_JACK_PROCESS) || defined(DEBUG_JACK_TRANSPORT)) framesThisPlay += nframes; #endif #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcess: " << nframes << " frames, " << framesThisPlay << " this play, " << m_framesProcessed << " total" << std::endl; #endif return 0; } int JackDriver::jackProcessRecord(InstrumentId id, jack_nframes_t nframes, sample_t *sourceBufferLeft, sample_t *sourceBufferRight, bool clocksRunning) { #ifdef DEBUG_JACK_PROCESS Profiler profiler("jackProcessRecord", true); #else #ifdef DEBUG_JACK_XRUN Profiler profiler("jackProcessRecord", false); #endif #endif SequencerDataBlock *sdb = m_alsaDriver->getSequencerDataBlock(); bool wroteSomething = false; sample_t peakLeft = 0.0, peakRight = 0.0; #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcessRecord(" << id << "): clocksRunning " << clocksRunning << std::endl; #endif // Get input buffers // sample_t *inputBufferLeft = 0, *inputBufferRight = 0; int recInput = m_recordInputs[id].input; int channel = m_recordInputs[id].channel; int channels = (channel == -1 ? 2 : 1); if (channels == 2) channel = 0; float level = m_recordInputs[id].level; if (sourceBufferLeft) { #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcessRecord(" << id << "): buss input provided" << std::endl; #endif inputBufferLeft = sourceBufferLeft; if (sourceBufferRight) inputBufferRight = sourceBufferRight; } else if (recInput < 1000) { #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcessRecord(" << id << "): no known input" << std::endl; #endif return 0; } else { #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcessRecord(" << id << "): record input " << recInput << std::endl; #endif int input = recInput - 1000; int port = input * channels + channel; int portRight = input * channels + 1; if (port < int(m_inputPorts.size())) { inputBufferLeft = static_cast (jack_port_get_buffer(m_inputPorts[port], nframes)); } if (channels == 2 && portRight < int(m_inputPorts.size())) { inputBufferRight = static_cast (jack_port_get_buffer(m_inputPorts[portRight], nframes)); } } float gain = AudioLevel::dB_to_multiplier(level); if (m_alsaDriver->getRecordStatus() == RECORD_ON && clocksRunning && m_fileWriter->haveRecordFileOpen(id)) { #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcessRecord(" << id << "): recording" << std::endl; #endif memset(m_tempOutBuffer, 0, nframes * sizeof(sample_t)); if (inputBufferLeft) { for (size_t i = 0; i < nframes; ++i) { sample_t sample = inputBufferLeft[i] * gain; if (sample > peakLeft) peakLeft = sample; m_tempOutBuffer[i] = sample; } if (m_outputMonitors.size() > 0) { sample_t *buf = static_cast (jack_port_get_buffer(m_outputMonitors[0], nframes)); if (buf) { for (size_t i = 0; i < nframes; ++i) { buf[i] += m_tempOutBuffer[i]; } } } m_fileWriter->write(id, m_tempOutBuffer, 0, nframes); } if (channels == 2) { if (inputBufferRight) { for (size_t i = 0; i < nframes; ++i) { sample_t sample = inputBufferRight[i] * gain; if (sample > peakRight) peakRight = sample; m_tempOutBuffer[i] = sample; } if (m_outputMonitors.size() > 1) { sample_t *buf = static_cast (jack_port_get_buffer(m_outputMonitors[1], nframes)); if (buf) { for (size_t i = 0; i < nframes; ++i) { buf[i] += m_tempOutBuffer[i]; } } } } m_fileWriter->write(id, m_tempOutBuffer, 1, nframes); } wroteSomething = true; } else { // want peak levels and monitors anyway, even if not recording #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::jackProcessRecord(" << id << "): monitoring only" << std::endl; #endif if (inputBufferLeft) { sample_t *buf = 0; if (m_outputMonitors.size() > 0) { buf = static_cast (jack_port_get_buffer(m_outputMonitors[0], nframes)); } for (size_t i = 0; i < nframes; ++i) { sample_t sample = inputBufferLeft[i] * gain; if (sample > peakLeft) peakLeft = sample; if (buf) buf[i] = sample; } if (channels == 2 && inputBufferRight) { buf = 0; if (m_outputMonitors.size() > 1) { buf = static_cast (jack_port_get_buffer(m_outputMonitors[1], nframes)); } for (size_t i = 0; i < nframes; ++i) { sample_t sample = inputBufferRight[i] * gain; if (sample > peakRight) peakRight = sample; if (buf) buf[i] = sample; } } } } if (channels < 2) peakRight = peakLeft; if (sdb) { LevelInfo info; info.level = AudioLevel::multiplier_to_fader (peakLeft, 127, AudioLevel::LongFader); info.levelRight = AudioLevel::multiplier_to_fader (peakRight, 127, AudioLevel::LongFader); sdb->setInstrumentRecordLevel(id, info); } if (wroteSomething) { m_fileWriter->signal(); } return 0; } int JackDriver::jackSyncCallback(jack_transport_state_t state, jack_position_t *position, void *arg) { JackDriver *inst = (JackDriver *)arg; if (!inst) return true; // or rather, return "huh?" inst->m_alsaDriver->checkTimerSync(0); // reset, as not processing if (!inst->m_jackTransportEnabled) return true; // ignore ExternalTransport *transport = inst->m_alsaDriver->getExternalTransportControl(); if (!transport) return true; #ifdef DEBUG_JACK_TRANSPORT std::cerr << "JackDriver::jackSyncCallback: state " << state << " [" << (state == 0 ? "stopped" : state == 1 ? "rolling" : state == 2 ? "looping" : state == 3 ? "starting" : "unknown") << "], frame " << position->frame << ", waiting " << inst->m_waiting << ", playing " << inst->m_alsaDriver->isPlaying() << std::endl; std::cerr << "JackDriver::jackSyncCallback: m_waitingState " << inst->m_waitingState << ", unique_1 " << position->unique_1 << ", unique_2 " << position->unique_2 << std::endl; std::cerr << "JackDriver::jackSyncCallback: rate " << position->frame_rate << ", bar " << position->bar << ", beat " << position->beat << ", tick " << position->tick << ", bpm " << position->beats_per_minute << std::endl; #endif ExternalTransport::TransportRequest request = ExternalTransport::TransportNoChange; if (inst->m_alsaDriver->isPlaying()) { if (state == JackTransportStarting) { request = ExternalTransport::TransportJumpToTime; } else if (state == JackTransportStopped) { request = ExternalTransport::TransportStop; } } else { if (state == JackTransportStarting) { request = ExternalTransport::TransportStartAtTime; } else if (state == JackTransportStopped) { request = ExternalTransport::TransportNoChange; } } if (!inst->m_waiting || inst->m_waitingState != state) { if (request == ExternalTransport::TransportJumpToTime || request == ExternalTransport::TransportStartAtTime) { RealTime rt = RealTime::frame2RealTime(position->frame, position->frame_rate); #ifdef DEBUG_JACK_TRANSPORT std::cerr << "JackDriver::jackSyncCallback: Requesting jump to " << rt << std::endl; #endif inst->m_waitingToken = transport->transportJump(request, rt); #ifdef DEBUG_JACK_TRANSPORT std::cerr << "JackDriver::jackSyncCallback: My token is " << inst->m_waitingToken << std::endl; #endif } else if (request == ExternalTransport::TransportStop) { #ifdef DEBUG_JACK_TRANSPORT std::cerr << "JackDriver::jackSyncCallback: Requesting state change to " << request << std::endl; #endif inst->m_waitingToken = transport->transportChange(request); #ifdef DEBUG_JACK_TRANSPORT std::cerr << "JackDriver::jackSyncCallback: My token is " << inst->m_waitingToken << std::endl; #endif } else if (request == ExternalTransport::TransportNoChange) { #ifdef DEBUG_JACK_TRANSPORT std::cerr << "JackDriver::jackSyncCallback: Requesting no state change!" << std::endl; #endif inst->m_waitingToken = transport->transportChange(request); #ifdef DEBUG_JACK_TRANSPORT std::cerr << "JackDriver::jackSyncCallback: My token is " << inst->m_waitingToken << std::endl; #endif } inst->m_waiting = true; inst->m_waitingState = state; #ifdef DEBUG_JACK_TRANSPORT std::cerr << "JackDriver::jackSyncCallback: Setting waiting to " << inst->m_waiting << " and waiting state to " << inst->m_waitingState << " (request was " << request << ")" << std::endl; #endif return 0; } else { if (transport->isTransportSyncComplete(inst->m_waitingToken)) { #ifdef DEBUG_JACK_TRANSPORT std::cerr << "JackDriver::jackSyncCallback: Sync complete" << std::endl; #endif return 1; } else { #ifdef DEBUG_JACK_TRANSPORT std::cerr << "JackDriver::jackSyncCallback: Sync not complete" << std::endl; #endif return 0; } } } bool JackDriver::relocateTransportInternal(bool alsoStart) { if (!m_client) return true; #ifdef DEBUG_JACK_TRANSPORT const char *fn = (alsoStart ? "JackDriver::startTransport" : "JackDriver::relocateTransport"); #endif #ifdef DEBUG_JACK_TRANSPORT std::cerr << fn << std::endl; #else #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::relocateTransportInternal" << std::endl; #endif #endif // m_waiting is true if we are waiting for the JACK transport // to finish a change of state. if (m_jackTransportEnabled) { // If on the transport, we never return true here -- instead // the JACK process calls startClocksApproved() to signal to // the ALSA driver that it's time to go. But we do use this // to manage our JACK transport state requests. // Where did this request come from? Are we just responding // to an external sync? ExternalTransport *transport = m_alsaDriver->getExternalTransportControl(); if (transport) { if (transport->isTransportSyncComplete(m_waitingToken)) { // Nope, this came from Rosegarden #ifdef DEBUG_JACK_TRANSPORT std::cerr << fn << ": asking JACK transport to start, setting wait state" << std::endl; #endif m_waiting = true; m_waitingState = JackTransportStarting; long frame = RealTime::realTime2Frame (m_alsaDriver->getSequencerTime(), m_sampleRate); if (frame < 0) { // JACK Transport doesn't support preroll and // can't set transport position to before zero // (frame count is unsigned), so there's no very // satisfactory fix for what to do for count-in // bars. Let's just start at zero instead. jack_transport_locate(m_client, 0); } else { jack_transport_locate(m_client, frame); } if (alsoStart) { jack_transport_start(m_client); m_ignoreProcessTransportCount = 1; } else { m_ignoreProcessTransportCount = 2; } } else { #ifdef DEBUG_JACK_TRANSPORT std::cerr << fn << ": waiting already" << std::endl; #endif } } return false; } #if (defined(DEBUG_JACK_DRIVER) || defined(DEBUG_JACK_PROCESS) || defined(DEBUG_JACK_TRANSPORT)) framesThisPlay = 0; //!!! struct timeval tv; (void)gettimeofday(&tv, 0); startTime = RealTime(tv.tv_sec, tv.tv_usec * 1000); //!!! #endif #ifdef DEBUG_JACK_TRANSPORT std::cerr << fn << ": not on JACK transport, accepting right away" << std::endl; #endif return true; } bool JackDriver::startTransport() { return relocateTransportInternal(true); } bool JackDriver::relocateTransport() { return relocateTransportInternal(false); } void JackDriver::stopTransport() { if (!m_client) return ; std::cerr << "JackDriver::stopTransport: resetting m_haveAsyncAudioEvent" << std::endl; m_haveAsyncAudioEvent = false; #ifdef DEBUG_JACK_TRANSPORT struct timeval tv; (void)gettimeofday(&tv, 0); RealTime endTime = RealTime(tv.tv_sec, tv.tv_usec * 1000); //!!! std::cerr << "\nJackDriver::stop: frames this play: " << framesThisPlay << ", elapsed " << (endTime - startTime) << std::endl; #endif if (m_jackTransportEnabled) { // Where did this request come from? Is this a result of our // sync to a transport that has in fact already stopped? ExternalTransport *transport = m_alsaDriver->getExternalTransportControl(); if (transport) { if (transport->isTransportSyncComplete(m_waitingToken)) { // No, we have no outstanding external requests; this // must have genuinely been requested from within // Rosegarden, so: #ifdef DEBUG_JACK_TRANSPORT std::cerr << "JackDriver::stop: internal request, asking JACK transport to stop" << std::endl; #endif jack_transport_stop(m_client); } else { // Nothing to do #ifdef DEBUG_JACK_TRANSPORT std::cerr << "JackDriver::stop: external request, JACK transport is already stopped" << std::endl; #endif } } } if (m_instrumentMixer) m_instrumentMixer->resetAllPlugins(true); // discard events too } // Pick up any change of buffer size // int JackDriver::jackBufferSize(jack_nframes_t nframes, void *arg) { JackDriver *inst = static_cast(arg); #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::jackBufferSize - buffer size changed to " << nframes << std::endl; #endif inst->m_bufferSize = nframes; // Recreate our temporary mix buffers to the new size // //!!! need buffer size change callbacks on plugins (so long as they // have internal buffers) and the mix manager, with locks acquired // appropriately delete [] inst->m_tempOutBuffer; inst->m_tempOutBuffer = new sample_t[inst->m_bufferSize]; return 0; } // Sample rate change // int JackDriver::jackSampleRate(jack_nframes_t nframes, void *arg) { JackDriver *inst = static_cast(arg); #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::jackSampleRate - sample rate changed to " << nframes << std::endl; #endif inst->m_sampleRate = nframes; return 0; } void JackDriver::jackShutdown(void *arg) { #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::jackShutdown() - callback received - " << "informing GUI" << std::endl; #endif #ifdef DEBUG_JACK_XRUN std::cerr << "JackDriver::jackShutdown" << std::endl; Profiles::getInstance()->dump(); #endif JackDriver *inst = static_cast(arg); inst->m_ok = false; inst->m_kickedOutAt = time(0); inst->reportFailure(MappedEvent::FailureJackDied); } int JackDriver::jackXRun(void *arg) { #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::jackXRun" << std::endl; #endif #ifdef DEBUG_JACK_XRUN std::cerr << "JackDriver::jackXRun" << std::endl; Profiles::getInstance()->dump(); #endif // Report to GUI // JackDriver *inst = static_cast(arg); inst->reportFailure(MappedEvent::FailureXRuns); return 0; } void JackDriver::restoreIfRestorable() { if (m_kickedOutAt == 0) return ; if (m_client) { jack_client_close(m_client); std::cerr << "closed client" << std::endl; m_client = 0; } time_t now = time(0); if (now < m_kickedOutAt || now >= m_kickedOutAt + 3) { if (m_instrumentMixer) m_instrumentMixer->resetAllPlugins(true); std::cerr << "reset plugins" << std::endl; initialise(true); if (m_ok) { reportFailure(MappedEvent::FailureJackRestart); } else { reportFailure(MappedEvent::FailureJackRestartFailed); } m_kickedOutAt = 0; } } void JackDriver::prepareAudio() { if (!m_instrumentMixer) return ; // This is used when restarting clocks after repositioning, but // when not actually playing (yet). We need to do things like // regenerating the processing buffers here. prebufferAudio() // also does all of this, but rather more besides. m_instrumentMixer->allocateBuffers(); m_instrumentMixer->resetAllPlugins(false); } void JackDriver::prebufferAudio() { if (!m_instrumentMixer) return ; // We want this to happen when repositioning during playback, and // stopTransport no longer happens then, so we call it from here. // NB. Don't want to discard events here as this is called after // pushing events to the soft synth queues at startup m_instrumentMixer->resetAllPlugins(false); #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::prebufferAudio: sequencer time is " << m_alsaDriver->getSequencerTime() << std::endl; #endif RealTime sliceStart = getNextSliceStart(m_alsaDriver->getSequencerTime()); m_fileReader->fillBuffers(sliceStart); if (m_bussMixer->getBussCount() > 0) { m_bussMixer->fillBuffers(sliceStart); // also calls on m_instrumentMixer } else { m_instrumentMixer->fillBuffers(sliceStart); } } void JackDriver::kickAudio() { #ifdef DEBUG_JACK_PROCESS std::cerr << "JackDriver::kickAudio" << std::endl; #endif if (m_fileReader) m_fileReader->kick(); if (m_instrumentMixer) m_instrumentMixer->kick(); if (m_bussMixer) m_bussMixer->kick(); if (m_fileWriter) m_fileWriter->kick(); } void JackDriver::updateAudioData() { if (!m_ok || !m_client) return ; #ifdef DEBUG_JACK_DRIVER // std::cerr << "JackDriver::updateAudioData starting" << std::endl; #endif MappedAudioBuss *mbuss = m_alsaDriver->getMappedStudio()->getAudioBuss(0); if (mbuss) { float level = 0.0; (void)mbuss->getProperty(MappedAudioBuss::Level, level); m_masterLevel = level; } unsigned long directMasterAudioInstruments = 0L; unsigned long directMasterSynthInstruments = 0L; InstrumentId audioInstrumentBase; int audioInstruments; m_alsaDriver->getAudioInstrumentNumbers(audioInstrumentBase, audioInstruments); InstrumentId synthInstrumentBase; int synthInstruments; m_alsaDriver->getSoftSynthInstrumentNumbers(synthInstrumentBase, synthInstruments); RealTime jackLatency = getAudioPlayLatency(); RealTime maxLatency = RealTime::zeroTime; for (int i = 0; i < audioInstruments + synthInstruments; ++i) { InstrumentId id; if (i < audioInstruments) id = audioInstrumentBase + i; else id = synthInstrumentBase + (i - audioInstruments); MappedAudioFader *fader = m_alsaDriver->getMappedStudio()->getAudioFader(id); if (!fader) continue; float f = 2; (void)fader->getProperty(MappedAudioFader::Channels, f); int channels = (int)f; int inputChannel = -1; if (channels == 1) { float f = 0; (void)fader->getProperty(MappedAudioFader::InputChannel, f); inputChannel = (int)f; } float level = 0.0; (void)fader->getProperty(MappedAudioFader::FaderRecordLevel, level); // Like in base/Instrument.h, we use numbers < 1000 to // mean buss numbers and >= 1000 to mean record ins // when recording the record input number. MappedObjectValueList connections = fader->getConnections (MappedConnectableObject::In); int input = 1000; if (connections.empty()) { std::cerr << "No connections in for record instrument " << (id) << " (mapped id " << fader->getId() << ")" << std::endl; // oh dear. input = 1000; } else if (*connections.begin() == mbuss->getId()) { input = 0; } else { MappedObject *obj = m_alsaDriver->getMappedStudio()-> getObjectById(MappedObjectId(*connections.begin())); if (!obj) { std::cerr << "No such object as " << *connections.begin() << std::endl; input = 1000; } else if (obj->getType() == MappedObject::AudioBuss) { input = (int)((MappedAudioBuss *)obj)->getBussId(); } else if (obj->getType() == MappedObject::AudioInput) { input = (int)((MappedAudioInput *)obj)->getInputNumber() + 1000; } else { std::cerr << "Object " << *connections.begin() << " is not buss or input" << std::endl; input = 1000; } } if (m_recordInputs[id].input != input) { std::cerr << "Changing record input for instrument " << id << " to " << input << std::endl; } m_recordInputs[id] = RecordInputDesc(input, inputChannel, level); size_t pluginLatency = 0; bool empty = m_instrumentMixer->isInstrumentEmpty(id); if (!empty) { pluginLatency = m_instrumentMixer->getPluginLatency(id); } // If we find the object is connected to no output, or to buss // number 0 (the master), then we set the bit appropriately. connections = fader->getConnections(MappedConnectableObject::Out); if (connections.empty() || (*connections.begin() == mbuss->getId())) { if (i < audioInstruments) { directMasterAudioInstruments |= (1 << i); } else { directMasterSynthInstruments |= (1 << (i - audioInstruments)); } } else if (!empty) { pluginLatency += m_instrumentMixer->getPluginLatency((unsigned int) * connections.begin()); } if (empty) { m_instrumentLatencies[id] = RealTime::zeroTime; } else { m_instrumentLatencies[id] = jackLatency + RealTime::frame2RealTime(pluginLatency, m_sampleRate); if (m_instrumentLatencies[id] > maxLatency) { maxLatency = m_instrumentLatencies[id]; } } } m_maxInstrumentLatency = maxLatency; m_directMasterAudioInstruments = directMasterAudioInstruments; m_directMasterSynthInstruments = directMasterSynthInstruments; m_maxInstrumentLatency = maxLatency; int inputs = m_alsaDriver->getMappedStudio()-> getObjectCount(MappedObject::AudioInput); if (m_client) { // this will return with no work if the inputs are already correct: createRecordInputs(inputs); } m_bussMixer->updateInstrumentConnections(); m_instrumentMixer->updateInstrumentMuteStates(); if (m_bussMixer->getBussCount() == 0 || m_alsaDriver->getLowLatencyMode()) { if (m_bussMixer->running()) { m_bussMixer->terminate(); } } else { if (!m_bussMixer->running()) { m_bussMixer->run(); } } if (m_alsaDriver->getLowLatencyMode()) { if (m_instrumentMixer->running()) { m_instrumentMixer->terminate(); } } else { if (!m_instrumentMixer->running()) { m_instrumentMixer->run(); } } #ifdef DEBUG_JACK_DRIVER // std::cerr << "JackDriver::updateAudioData exiting" << std::endl; #endif } void JackDriver::setAudioBussLevels(int bussNo, float dB, float pan) { if (m_bussMixer) { m_bussMixer->setBussLevels(bussNo, dB, pan); } } void JackDriver::setAudioInstrumentLevels(InstrumentId instrument, float dB, float pan) { if (m_instrumentMixer) { m_instrumentMixer->setInstrumentLevels(instrument, dB, pan); } } RealTime JackDriver::getNextSliceStart(const RealTime &now) const { jack_nframes_t frame; bool neg = false; if (now < RealTime::zeroTime) { neg = true; frame = RealTime::realTime2Frame(RealTime::zeroTime - now, m_sampleRate); } else { frame = RealTime::realTime2Frame(now, m_sampleRate); } jack_nframes_t rounded = frame; rounded /= m_bufferSize; rounded *= m_bufferSize; RealTime roundrt; if (rounded == frame) roundrt = RealTime::frame2RealTime(rounded, m_sampleRate); else if (neg) roundrt = RealTime::frame2RealTime(rounded - m_bufferSize, m_sampleRate); else roundrt = RealTime::frame2RealTime(rounded + m_bufferSize, m_sampleRate); if (neg) roundrt = RealTime::zeroTime - roundrt; return roundrt; } int JackDriver::getAudioQueueLocks() { // We have to lock the mixers first, because the mixers can try to // lock the disk manager from within a locked section -- so if we // locked the disk manager first we would risk deadlock when // trying to acquire the instrument mixer lock int rv = 0; if (m_bussMixer) { #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::getAudioQueueLocks: trying to lock buss mixer" << std::endl; #endif rv = m_bussMixer->getLock(); if (rv) return rv; } if (m_instrumentMixer) { #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::getAudioQueueLocks: ok, now trying for instrument mixer" << std::endl; #endif rv = m_instrumentMixer->getLock(); if (rv) return rv; } if (m_fileReader) { #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::getAudioQueueLocks: ok, now trying for disk reader" << std::endl; #endif rv = m_fileReader->getLock(); if (rv) return rv; } if (m_fileWriter) { #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::getAudioQueueLocks: ok, now trying for disk writer" << std::endl; #endif rv = m_fileWriter->getLock(); } #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::getAudioQueueLocks: ok" << std::endl; #endif return rv; } int JackDriver::tryAudioQueueLocks() { int rv = 0; if (m_bussMixer) { rv = m_bussMixer->tryLock(); if (rv) return rv; } if (m_instrumentMixer) { rv = m_instrumentMixer->tryLock(); if (rv) { if (m_bussMixer) { m_bussMixer->releaseLock(); } } } if (m_fileReader) { rv = m_fileReader->tryLock(); if (rv) { if (m_instrumentMixer) { m_instrumentMixer->releaseLock(); } if (m_bussMixer) { m_bussMixer->releaseLock(); } } } if (m_fileWriter) { rv = m_fileWriter->tryLock(); if (rv) { if (m_fileReader) { m_fileReader->releaseLock(); } if (m_instrumentMixer) { m_instrumentMixer->releaseLock(); } if (m_bussMixer) { m_bussMixer->releaseLock(); } } } return rv; } int JackDriver::releaseAudioQueueLocks() { int rv = 0; #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::releaseAudioQueueLocks" << std::endl; #endif if (m_fileWriter) rv = m_fileWriter->releaseLock(); if (m_fileReader) rv = m_fileReader->releaseLock(); if (m_instrumentMixer) rv = m_instrumentMixer->releaseLock(); if (m_bussMixer) rv = m_bussMixer->releaseLock(); return rv; } void JackDriver::setPluginInstance(InstrumentId id, TQString identifier, int position) { if (m_instrumentMixer) { m_instrumentMixer->setPlugin(id, position, identifier); } if (!m_alsaDriver->isPlaying()) { prebufferAudio(); // to ensure the plugin's ringbuffers are generated } } void JackDriver::removePluginInstance(InstrumentId id, int position) { if (m_instrumentMixer) m_instrumentMixer->removePlugin(id, position); } void JackDriver::removePluginInstances() { if (m_instrumentMixer) m_instrumentMixer->removeAllPlugins(); } void JackDriver::setPluginInstancePortValue(InstrumentId id, int position, unsigned long portNumber, float value) { if (m_instrumentMixer) m_instrumentMixer->setPluginPortValue(id, position, portNumber, value); } float JackDriver::getPluginInstancePortValue(InstrumentId id, int position, unsigned long portNumber) { if (m_instrumentMixer) return m_instrumentMixer->getPluginPortValue(id, position, portNumber); return 0; } void JackDriver::setPluginInstanceBypass(InstrumentId id, int position, bool value) { if (m_instrumentMixer) m_instrumentMixer->setPluginBypass(id, position, value); } TQStringList JackDriver::getPluginInstancePrograms(InstrumentId id, int position) { if (m_instrumentMixer) return m_instrumentMixer->getPluginPrograms(id, position); return TQStringList(); } TQString JackDriver::getPluginInstanceProgram(InstrumentId id, int position) { if (m_instrumentMixer) return m_instrumentMixer->getPluginProgram(id, position); return TQString(); } TQString JackDriver::getPluginInstanceProgram(InstrumentId id, int position, int bank, int program) { if (m_instrumentMixer) return m_instrumentMixer->getPluginProgram(id, position, bank, program); return TQString(); } unsigned long JackDriver::getPluginInstanceProgram(InstrumentId id, int position, TQString name) { if (m_instrumentMixer) return m_instrumentMixer->getPluginProgram(id, position, name); return 0; } void JackDriver::setPluginInstanceProgram(InstrumentId id, int position, TQString program) { if (m_instrumentMixer) m_instrumentMixer->setPluginProgram(id, position, program); } TQString JackDriver::configurePlugin(InstrumentId id, int position, TQString key, TQString value) { if (m_instrumentMixer) return m_instrumentMixer->configurePlugin(id, position, key, value); return TQString(); } RunnablePluginInstance * JackDriver::getSynthPlugin(InstrumentId id) { if (m_instrumentMixer) return m_instrumentMixer->getSynthPlugin(id); else return 0; } void JackDriver::clearSynthPluginEvents() { if (!m_instrumentMixer) return; #ifdef DEBUG_JACK_DRIVER std::cerr << "JackDriver::clearSynthPluginEvents" << std::endl; #endif m_instrumentMixer->discardPluginEvents(); } bool JackDriver::openRecordFile(InstrumentId id, const std::string &filename) { if (m_fileWriter) { if (!m_fileWriter->running()) { m_fileWriter->run(); } return m_fileWriter->openRecordFile(id, filename); } else { std::cerr << "JackDriver::openRecordFile: No file writer available!" << std::endl; return false; } } bool JackDriver::closeRecordFile(InstrumentId id, AudioFileId &returnedId) { if (m_fileWriter) { return m_fileWriter->closeRecordFile(id, returnedId); if (m_fileWriter->running() && !m_fileWriter->haveRecordFilesOpen()) { m_fileWriter->terminate(); } } else return false; } void JackDriver::reportFailure(MappedEvent::FailureCode code) { if (m_alsaDriver) m_alsaDriver->reportFailure(code); } } #endif // HAVE_LIBJACK #endif // HAVE_ALSA