annotate audioio/AudioJACKTarget.cpp @ 16:ba31fa322f93

* Fix a crash in PortAudio output for mono data * Don't construct a chromagram in TonalChangeDetect plugin ctor * Update layer show/hide/dormancy for multi-view-capable layers -- the dormancy concept doesn't really work with these constraints any more
author Chris Cannam
date Fri, 03 Mar 2006 17:52:21 +0000
parents c2416d130d59
children c606d3ffa397
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 A waveform viewer and audio annotation editor.
Chris@2 5 Chris Cannam, Queen Mary University of London, 2005-2006
Chris@0 6
Chris@0 7 This is experimental software. Not for distribution.
Chris@0 8 */
Chris@0 9
Chris@0 10 #ifdef HAVE_JACK
Chris@0 11
Chris@0 12 #include "AudioJACKTarget.h"
Chris@0 13 #include "AudioCallbackPlaySource.h"
Chris@0 14
Chris@0 15 #include <iostream>
Martin@15 16 #include <cmath>
Chris@0 17
Chris@0 18 //#define DEBUG_AUDIO_JACK_TARGET 1
Chris@0 19
Chris@0 20 AudioJACKTarget::AudioJACKTarget(AudioCallbackPlaySource *source) :
Chris@0 21 AudioCallbackPlayTarget(source),
Chris@0 22 m_client(0),
Chris@0 23 m_bufferSize(0),
Chris@0 24 m_sampleRate(0)
Chris@0 25 {
Chris@0 26 char name[20];
Chris@0 27 strcpy(name, "Sonic Visualiser");
Chris@0 28 m_client = jack_client_new(name);
Chris@0 29
Chris@0 30 if (!m_client) {
Chris@0 31 sprintf(name, "Sonic Visualiser (%d)", (int)getpid());
Chris@0 32 m_client = jack_client_new(name);
Chris@0 33 if (!m_client) {
Chris@0 34 std::cerr
Chris@0 35 << "ERROR: AudioJACKTarget: Failed to connect to JACK server"
Chris@0 36 << std::endl;
Chris@0 37 }
Chris@0 38 }
Chris@0 39
Chris@0 40 if (!m_client) return;
Chris@0 41
Chris@0 42 m_bufferSize = jack_get_buffer_size(m_client);
Chris@0 43 m_sampleRate = jack_get_sample_rate(m_client);
Chris@0 44
Chris@0 45 jack_set_process_callback(m_client, processStatic, this);
Chris@0 46
Chris@0 47 if (jack_activate(m_client)) {
Chris@0 48 std::cerr << "ERROR: AudioJACKTarget: Failed to activate JACK client"
Chris@0 49 << std::endl;
Chris@0 50 }
Chris@0 51
Chris@0 52 if (m_source) {
Chris@0 53 sourceModelReplaced();
Chris@0 54 }
Chris@0 55 }
Chris@0 56
Chris@0 57 AudioJACKTarget::~AudioJACKTarget()
Chris@0 58 {
Chris@0 59 if (m_client) {
Chris@0 60 jack_deactivate(m_client);
Chris@0 61 jack_client_close(m_client);
Chris@0 62 }
Chris@0 63 }
Chris@0 64
Chris@0 65 bool
Chris@0 66 AudioJACKTarget::isOK() const
Chris@0 67 {
Chris@0 68 return (m_client != 0);
Chris@0 69 }
Chris@0 70
Chris@0 71 int
Chris@0 72 AudioJACKTarget::processStatic(jack_nframes_t nframes, void *arg)
Chris@0 73 {
Chris@0 74 return ((AudioJACKTarget *)arg)->process(nframes);
Chris@0 75 }
Chris@0 76
Chris@0 77 void
Chris@0 78 AudioJACKTarget::sourceModelReplaced()
Chris@0 79 {
Chris@0 80 m_mutex.lock();
Chris@0 81
Chris@0 82 m_source->setTargetBlockSize(m_bufferSize);
Chris@0 83 m_source->setTargetSampleRate(m_sampleRate);
Chris@0 84
Chris@0 85 size_t channels = m_source->getSourceChannelCount();
Chris@0 86
Chris@13 87 // Because we offer pan, we always want at least 2 channels
Chris@13 88 if (channels < 2) channels = 2;
Chris@13 89
Chris@0 90 if (channels == m_outputs.size() || !m_client) {
Chris@0 91 m_mutex.unlock();
Chris@0 92 return;
Chris@0 93 }
Chris@0 94
Chris@0 95 const char **ports =
Chris@0 96 jack_get_ports(m_client, NULL, NULL,
Chris@0 97 JackPortIsPhysical | JackPortIsInput);
Chris@0 98 size_t physicalPortCount = 0;
Chris@0 99 while (ports[physicalPortCount]) ++physicalPortCount;
Chris@0 100
Chris@0 101 #ifdef DEBUG_AUDIO_JACK_TARGET
Chris@0 102 std::cerr << "AudioJACKTarget::sourceModelReplaced: have " << channels << " channels and " << physicalPortCount << " physical ports" << std::endl;
Chris@0 103 #endif
Chris@0 104
Chris@0 105 while (m_outputs.size() < channels) {
Chris@0 106
Chris@0 107 char name[20];
Chris@0 108 jack_port_t *port;
Chris@0 109
Chris@0 110 sprintf(name, "out %d", m_outputs.size() + 1);
Chris@0 111
Chris@0 112 port = jack_port_register(m_client,
Chris@0 113 name,
Chris@0 114 JACK_DEFAULT_AUDIO_TYPE,
Chris@0 115 JackPortIsOutput,
Chris@0 116 0);
Chris@0 117
Chris@0 118 if (!port) {
Chris@0 119 std::cerr
Chris@0 120 << "ERROR: AudioJACKTarget: Failed to create JACK output port "
Chris@0 121 << m_outputs.size() << std::endl;
Chris@0 122 } else {
Chris@0 123 m_source->setTargetPlayLatency(jack_port_get_latency(port));
Chris@0 124 }
Chris@0 125
Chris@0 126 if (m_outputs.size() < physicalPortCount) {
Chris@0 127 jack_connect(m_client, jack_port_name(port), ports[m_outputs.size()]);
Chris@0 128 }
Chris@0 129
Chris@0 130 m_outputs.push_back(port);
Chris@0 131 }
Chris@0 132
Chris@0 133 while (m_outputs.size() > channels) {
Chris@0 134 std::vector<jack_port_t *>::iterator itr = m_outputs.end();
Chris@0 135 --itr;
Chris@0 136 jack_port_t *port = *itr;
Chris@0 137 if (port) jack_port_unregister(m_client, port);
Chris@0 138 m_outputs.erase(itr);
Chris@0 139 }
Chris@0 140
Chris@0 141 m_mutex.unlock();
Chris@0 142 }
Chris@0 143
Chris@0 144 int
Chris@0 145 AudioJACKTarget::process(jack_nframes_t nframes)
Chris@0 146 {
Chris@0 147 if (!m_mutex.tryLock()) {
Chris@0 148 return 0;
Chris@0 149 }
Chris@0 150
Chris@0 151 if (m_outputs.empty()) {
Chris@0 152 m_mutex.unlock();
Chris@0 153 return 0;
Chris@0 154 }
Chris@0 155
Chris@0 156 #ifdef DEBUG_AUDIO_JACK_TARGET
Chris@0 157 std::cout << "AudioJACKTarget::process(" << nframes << "): have a source" << std::endl;
Chris@0 158 #endif
Chris@0 159
Chris@0 160 #ifdef DEBUG_AUDIO_JACK_TARGET
Chris@0 161 if (m_bufferSize != nframes) {
Chris@0 162 std::cerr << "WARNING: m_bufferSize != nframes (" << m_bufferSize << " != " << nframes << ")" << std::endl;
Chris@0 163 }
Chris@0 164 #endif
Chris@0 165
Chris@0 166 float **buffers = (float **)alloca(m_outputs.size() * sizeof(float *));
Chris@0 167
Chris@0 168 for (size_t ch = 0; ch < m_outputs.size(); ++ch) {
Chris@0 169 buffers[ch] = (float *)jack_port_get_buffer(m_outputs[ch], nframes);
Chris@0 170 }
Chris@0 171
Chris@0 172 if (m_source) {
Chris@0 173 m_source->getSourceSamples(nframes, buffers);
Chris@0 174 } else {
Chris@0 175 for (size_t ch = 0; ch < m_outputs.size(); ++ch) {
Chris@0 176 for (size_t i = 0; i < nframes; ++i) {
Chris@0 177 buffers[ch][i] = 0.0;
Chris@0 178 }
Chris@0 179 }
Chris@0 180 }
Chris@0 181
Chris@0 182 float peakLeft = 0.0, peakRight = 0.0;
Chris@0 183
Chris@0 184 for (size_t ch = 0; ch < m_outputs.size(); ++ch) {
Chris@0 185
Chris@0 186 float peak = 0.0;
Chris@0 187
Chris@0 188 for (size_t i = 0; i < nframes; ++i) {
Chris@0 189 buffers[ch][i] *= m_outputGain;
Chris@0 190 float sample = fabsf(buffers[ch][i]);
Chris@0 191 if (sample > peak) peak = sample;
Chris@0 192 }
Chris@0 193
Chris@0 194 if (ch == 0) peakLeft = peak;
Chris@0 195 if (ch > 0 || m_outputs.size() == 1) peakRight = peak;
Chris@0 196 }
Chris@0 197
Chris@0 198 if (m_source) {
Chris@0 199 m_source->setOutputLevels(peakLeft, peakRight);
Chris@0 200 }
Chris@0 201
Chris@0 202 m_mutex.unlock();
Chris@0 203 return 0;
Chris@0 204 }
Chris@0 205
Chris@0 206
Chris@0 207 #ifdef INCLUDE_MOCFILES
Chris@0 208 #include "AudioJACKTarget.moc.cpp"
Chris@0 209 #endif
Chris@0 210
Chris@0 211 #endif /* HAVE_JACK */
Chris@0 212