annotate audioio/AudioJACKTarget.cpp @ 14:0f7997490bae

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