Mercurial > hg > svapp
diff audioio/AudioJACKTarget.cpp @ 0:db6fcbd4405c
initial import
author | Chris Cannam |
---|---|
date | Tue, 10 Jan 2006 16:33:16 +0000 |
parents | |
children | df5923e33d01 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/audioio/AudioJACKTarget.cpp Tue Jan 10 16:33:16 2006 +0000 @@ -0,0 +1,208 @@ +/* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */ + +/* + A waveform viewer and audio annotation editor. + Chris Cannam, Queen Mary University of London, 2005 + + This is experimental software. Not for distribution. +*/ + +#ifdef HAVE_JACK + +#include "AudioJACKTarget.h" +#include "AudioCallbackPlaySource.h" + +#include <iostream> + +//#define DEBUG_AUDIO_JACK_TARGET 1 + +AudioJACKTarget::AudioJACKTarget(AudioCallbackPlaySource *source) : + AudioCallbackPlayTarget(source), + m_client(0), + m_bufferSize(0), + m_sampleRate(0) +{ + char name[20]; + strcpy(name, "Sonic Visualiser"); + m_client = jack_client_new(name); + + if (!m_client) { + sprintf(name, "Sonic Visualiser (%d)", (int)getpid()); + m_client = jack_client_new(name); + if (!m_client) { + std::cerr + << "ERROR: AudioJACKTarget: Failed to connect to JACK server" + << std::endl; + } + } + + if (!m_client) return; + + m_bufferSize = jack_get_buffer_size(m_client); + m_sampleRate = jack_get_sample_rate(m_client); + + jack_set_process_callback(m_client, processStatic, this); + + if (jack_activate(m_client)) { + std::cerr << "ERROR: AudioJACKTarget: Failed to activate JACK client" + << std::endl; + } + + if (m_source) { + sourceModelReplaced(); + } +} + +AudioJACKTarget::~AudioJACKTarget() +{ + if (m_client) { + jack_deactivate(m_client); + jack_client_close(m_client); + } +} + +bool +AudioJACKTarget::isOK() const +{ + return (m_client != 0); +} + +int +AudioJACKTarget::processStatic(jack_nframes_t nframes, void *arg) +{ + return ((AudioJACKTarget *)arg)->process(nframes); +} + +void +AudioJACKTarget::sourceModelReplaced() +{ + m_mutex.lock(); + + m_source->setTargetBlockSize(m_bufferSize); + m_source->setTargetSampleRate(m_sampleRate); + + size_t channels = m_source->getSourceChannelCount(); + + if (channels == m_outputs.size() || !m_client) { + m_mutex.unlock(); + return; + } + + const char **ports = + jack_get_ports(m_client, NULL, NULL, + JackPortIsPhysical | JackPortIsInput); + size_t physicalPortCount = 0; + while (ports[physicalPortCount]) ++physicalPortCount; + +#ifdef DEBUG_AUDIO_JACK_TARGET + std::cerr << "AudioJACKTarget::sourceModelReplaced: have " << channels << " channels and " << physicalPortCount << " physical ports" << std::endl; +#endif + + while (m_outputs.size() < channels) { + + char name[20]; + jack_port_t *port; + + sprintf(name, "out %d", m_outputs.size() + 1); + + port = jack_port_register(m_client, + name, + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsOutput, + 0); + + if (!port) { + std::cerr + << "ERROR: AudioJACKTarget: Failed to create JACK output port " + << m_outputs.size() << std::endl; + } else { + m_source->setTargetPlayLatency(jack_port_get_latency(port)); + } + + if (m_outputs.size() < physicalPortCount) { + jack_connect(m_client, jack_port_name(port), ports[m_outputs.size()]); + } + + m_outputs.push_back(port); + } + + while (m_outputs.size() > channels) { + std::vector<jack_port_t *>::iterator itr = m_outputs.end(); + --itr; + jack_port_t *port = *itr; + if (port) jack_port_unregister(m_client, port); + m_outputs.erase(itr); + } + + m_mutex.unlock(); +} + +int +AudioJACKTarget::process(jack_nframes_t nframes) +{ + if (!m_mutex.tryLock()) { + return 0; + } + + if (m_outputs.empty()) { + m_mutex.unlock(); + return 0; + } + +#ifdef DEBUG_AUDIO_JACK_TARGET + std::cout << "AudioJACKTarget::process(" << nframes << "): have a source" << std::endl; +#endif + +#ifdef DEBUG_AUDIO_JACK_TARGET + if (m_bufferSize != nframes) { + std::cerr << "WARNING: m_bufferSize != nframes (" << m_bufferSize << " != " << nframes << ")" << std::endl; + } +#endif + + float **buffers = (float **)alloca(m_outputs.size() * sizeof(float *)); + + for (size_t ch = 0; ch < m_outputs.size(); ++ch) { + buffers[ch] = (float *)jack_port_get_buffer(m_outputs[ch], nframes); + } + + if (m_source) { + m_source->getSourceSamples(nframes, buffers); + } else { + for (size_t ch = 0; ch < m_outputs.size(); ++ch) { + for (size_t i = 0; i < nframes; ++i) { + buffers[ch][i] = 0.0; + } + } + } + + float peakLeft = 0.0, peakRight = 0.0; + + for (size_t ch = 0; ch < m_outputs.size(); ++ch) { + + float peak = 0.0; + + for (size_t i = 0; i < nframes; ++i) { + buffers[ch][i] *= m_outputGain; + float sample = fabsf(buffers[ch][i]); + if (sample > peak) peak = sample; + } + + if (ch == 0) peakLeft = peak; + if (ch > 0 || m_outputs.size() == 1) peakRight = peak; + } + + if (m_source) { + m_source->setOutputLevels(peakLeft, peakRight); + } + + m_mutex.unlock(); + return 0; +} + + +#ifdef INCLUDE_MOCFILES +#include "AudioJACKTarget.moc.cpp" +#endif + +#endif /* HAVE_JACK */ +