annotate audioio/AudioJACKTarget.cpp @ 1:40116f709d3b

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