annotate audioio/AudioJACKSource.cpp @ 4:f0e9092bd3e4

...
author cannam
date Mon, 06 Nov 2006 14:41:46 +0000
parents a6020bf991cd
children df33703ace3b
rev   line source
cannam@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@0 2
cannam@0 3 #ifdef HAVE_JACK
cannam@0 4
cannam@0 5 #include "AudioJACKSource.h"
cannam@0 6 #include "AudioCallbackRecordTarget.h"
cannam@0 7
cannam@0 8 #include <iostream>
cannam@0 9 #include <cmath>
cannam@0 10
cannam@0 11 //#define DEBUG_AUDIO_JACK_SOURCE 1
cannam@0 12
cannam@0 13 #ifdef BUILD_STATIC
cannam@0 14 #ifdef Q_OS_LINUX
cannam@0 15
cannam@0 16 // Some lunacy to enable JACK support in static builds. JACK isn't
cannam@0 17 // supposed to be linked statically, because it depends on a
cannam@0 18 // consistent shared memory layout between client library and daemon,
cannam@0 19 // so it's very fragile in the face of version mismatches.
cannam@0 20 //
cannam@0 21 // Therefore for static builds on Linux we avoid linking against JACK
cannam@0 22 // at all during the build, instead using dlopen and runtime symbol
cannam@0 23 // lookup to switch on JACK support at runtime. The following big
cannam@0 24 // mess (down to the #endifs) is the code that implements this.
cannam@0 25
cannam@0 26 static void *symbol(const char *name)
cannam@0 27 {
cannam@0 28 static bool attempted = false;
cannam@0 29 static void *library = 0;
cannam@0 30 static std::map<const char *, void *> symbols;
cannam@0 31 if (symbols.find(name) != symbols.end()) return symbols[name];
cannam@0 32 if (!library) {
cannam@0 33 if (!attempted) {
cannam@0 34 library = ::dlopen("libjack.so.1", RTLD_NOW);
cannam@0 35 if (!library) library = ::dlopen("libjack.so.0", RTLD_NOW);
cannam@0 36 if (!library) library = ::dlopen("libjack.so", RTLD_NOW);
cannam@0 37 if (!library) {
cannam@0 38 std::cerr << "WARNING: AudioJACKSource: Failed to load JACK library: "
cannam@0 39 << ::dlerror() << " (tried .so, .so.0, .so.1)"
cannam@0 40 << std::endl;
cannam@0 41 }
cannam@0 42 attempted = true;
cannam@0 43 }
cannam@0 44 if (!library) return 0;
cannam@0 45 }
cannam@0 46 void *symbol = ::dlsym(library, name);
cannam@0 47 if (!symbol) {
cannam@0 48 std::cerr << "WARNING: AudioJACKSource: Failed to locate symbol "
cannam@0 49 << name << ": " << ::dlerror() << std::endl;
cannam@0 50 }
cannam@0 51 symbols[name] = symbol;
cannam@0 52 return symbol;
cannam@0 53 }
cannam@0 54
cannam@0 55 static int dynamic_jack_set_process_callback(jack_client_t *client,
cannam@0 56 JackProcessCallback process_callback,
cannam@0 57 void *arg)
cannam@0 58 {
cannam@0 59 typedef int (*func)(jack_client_t *client,
cannam@0 60 JackProcessCallback process_callback,
cannam@0 61 void *arg);
cannam@0 62 void *s = symbol("jack_set_process_callback");
cannam@0 63 if (!s) return 1;
cannam@0 64 func f = (func)s;
cannam@0 65 return f(client, process_callback, arg);
cannam@0 66 }
cannam@0 67
cannam@0 68 static int dynamic_jack_set_xrun_callback(jack_client_t *client,
cannam@0 69 JackXRunCallback xrun_callback,
cannam@0 70 void *arg)
cannam@0 71 {
cannam@0 72 typedef int (*func)(jack_client_t *client,
cannam@0 73 JackXRunCallback xrun_callback,
cannam@0 74 void *arg);
cannam@0 75 void *s = symbol("jack_set_xrun_callback");
cannam@0 76 if (!s) return 1;
cannam@0 77 func f = (func)s;
cannam@0 78 return f(client, xrun_callback, arg);
cannam@0 79 }
cannam@0 80
cannam@0 81 static const char **dynamic_jack_get_ports(jack_client_t *client,
cannam@0 82 const char *port_name_pattern,
cannam@0 83 const char *type_name_pattern,
cannam@0 84 unsigned long flags)
cannam@0 85 {
cannam@0 86 typedef const char **(*func)(jack_client_t *client,
cannam@0 87 const char *port_name_pattern,
cannam@0 88 const char *type_name_pattern,
cannam@0 89 unsigned long flags);
cannam@0 90 void *s = symbol("jack_get_ports");
cannam@0 91 if (!s) return 0;
cannam@0 92 func f = (func)s;
cannam@0 93 return f(client, port_name_pattern, type_name_pattern, flags);
cannam@0 94 }
cannam@0 95
cannam@0 96 static jack_port_t *dynamic_jack_port_register(jack_client_t *client,
cannam@0 97 const char *port_name,
cannam@0 98 const char *port_type,
cannam@0 99 unsigned long flags,
cannam@0 100 unsigned long buffer_size)
cannam@0 101 {
cannam@0 102 typedef jack_port_t *(*func)(jack_client_t *client,
cannam@0 103 const char *port_name,
cannam@0 104 const char *port_type,
cannam@0 105 unsigned long flags,
cannam@0 106 unsigned long buffer_size);
cannam@0 107 void *s = symbol("jack_port_register");
cannam@0 108 if (!s) return 0;
cannam@0 109 func f = (func)s;
cannam@0 110 return f(client, port_name, port_type, flags, buffer_size);
cannam@0 111 }
cannam@0 112
cannam@0 113 static int dynamic_jack_connect(jack_client_t *client,
cannam@0 114 const char *source,
cannam@0 115 const char *dest)
cannam@0 116 {
cannam@0 117 typedef int (*func)(jack_client_t *client,
cannam@0 118 const char *source,
cannam@0 119 const char *dest);
cannam@0 120 void *s = symbol("jack_connect");
cannam@0 121 if (!s) return 1;
cannam@0 122 func f = (func)s;
cannam@0 123 return f(client, source, dest);
cannam@0 124 }
cannam@0 125
cannam@0 126 static void *dynamic_jack_port_get_buffer(jack_port_t *port,
cannam@0 127 jack_nframes_t sz)
cannam@0 128 {
cannam@0 129 typedef void *(*func)(jack_port_t *, jack_nframes_t);
cannam@0 130 void *s = symbol("jack_port_get_buffer");
cannam@0 131 if (!s) return 0;
cannam@0 132 func f = (func)s;
cannam@0 133 return f(port, sz);
cannam@0 134 }
cannam@0 135
cannam@0 136 static int dynamic_jack_port_unregister(jack_client_t *client,
cannam@0 137 jack_port_t *port)
cannam@0 138 {
cannam@0 139 typedef int(*func)(jack_client_t *, jack_port_t *);
cannam@0 140 void *s = symbol("jack_port_unregister");
cannam@0 141 if (!s) return 0;
cannam@0 142 func f = (func)s;
cannam@0 143 return f(client, port);
cannam@0 144 }
cannam@0 145
cannam@0 146 #define dynamic1(rv, name, argtype, failval) \
cannam@0 147 static rv dynamic_##name(argtype arg) { \
cannam@0 148 typedef rv (*func) (argtype); \
cannam@0 149 void *s = symbol(#name); \
cannam@0 150 if (!s) return failval; \
cannam@0 151 func f = (func) s; \
cannam@0 152 return f(arg); \
cannam@0 153 }
cannam@0 154
cannam@0 155 dynamic1(jack_client_t *, jack_client_new, const char *, 0);
cannam@0 156 dynamic1(jack_nframes_t, jack_get_buffer_size, jack_client_t *, 0);
cannam@0 157 dynamic1(jack_nframes_t, jack_get_sample_rate, jack_client_t *, 0);
cannam@0 158 dynamic1(int, jack_activate, jack_client_t *, 1);
cannam@0 159 dynamic1(int, jack_deactivate, jack_client_t *, 1);
cannam@0 160 dynamic1(int, jack_client_close, jack_client_t *, 1);
cannam@0 161 dynamic1(jack_nframes_t, jack_port_get_latency, jack_port_t *, 0);
cannam@0 162 dynamic1(const char *, jack_port_name, const jack_port_t *, 0);
cannam@0 163
cannam@0 164 #define jack_client_new dynamic_jack_client_new
cannam@0 165 #define jack_get_buffer_size dynamic_jack_get_buffer_size
cannam@0 166 #define jack_get_sample_rate dynamic_jack_get_sample_rate
cannam@0 167 #define jack_set_process_callback dynamic_jack_set_process_callback
cannam@0 168 #define jack_set_xrun_callback dynamic_jack_set_xrun_callback
cannam@0 169 #define jack_activate dynamic_jack_activate
cannam@0 170 #define jack_deactivate dynamic_jack_deactivate
cannam@0 171 #define jack_client_close dynamic_jack_client_close
cannam@0 172 #define jack_get_ports dynamic_jack_get_ports
cannam@0 173 #define jack_port_register dynamic_jack_port_register
cannam@0 174 #define jack_port_unregister dynamic_jack_port_unregister
cannam@0 175 #define jack_port_get_latency dynamic_jack_port_get_latency
cannam@0 176 #define jack_port_name dynamic_jack_port_name
cannam@0 177 #define jack_connect dynamic_jack_connect
cannam@0 178 #define jack_port_get_buffer dynamic_jack_port_get_buffer
cannam@0 179
cannam@0 180 #endif
cannam@0 181 #endif
cannam@0 182
cannam@0 183 AudioJACKSource::AudioJACKSource(AudioCallbackRecordTarget *target) :
cannam@0 184 AudioCallbackRecordSource(target),
cannam@0 185 m_client(0),
cannam@0 186 m_bufferSize(0),
cannam@0 187 m_sampleRate(0)
cannam@0 188 {
cannam@0 189 char name[20];
cannam@0 190 strcpy(name, "vamp-live-host");
cannam@0 191 m_client = jack_client_new(name);
cannam@0 192
cannam@0 193 if (!m_client) {
cannam@0 194 sprintf(name, "vamp-live-host (%d)", (int)getpid());
cannam@0 195 m_client = jack_client_new(name);
cannam@0 196 if (!m_client) {
cannam@0 197 std::cerr
cannam@0 198 << "ERROR: AudioJACKSource: Failed to connect to JACK server"
cannam@0 199 << std::endl;
cannam@0 200 }
cannam@0 201 }
cannam@0 202
cannam@0 203 if (!m_client) return;
cannam@0 204
cannam@0 205 m_bufferSize = jack_get_buffer_size(m_client);
cannam@0 206 m_sampleRate = jack_get_sample_rate(m_client);
cannam@0 207
cannam@0 208 jack_set_xrun_callback(m_client, xrunStatic, this);
cannam@0 209 jack_set_process_callback(m_client, processStatic, this);
cannam@0 210
cannam@0 211 if (jack_activate(m_client)) {
cannam@0 212 std::cerr << "ERROR: AudioJACKSource: Failed to activate JACK client"
cannam@0 213 << std::endl;
cannam@0 214 }
cannam@0 215
cannam@0 216 m_target->setSourceBlockSize(m_bufferSize);
cannam@0 217 m_target->setSourceSampleRate(m_sampleRate);
cannam@0 218
cannam@0 219 size_t channels = m_target->getChannelCount();
cannam@0 220
cannam@0 221 while (m_inputs.size() < channels) {
cannam@0 222
cannam@0 223 char name[20];
cannam@0 224 jack_port_t *port;
cannam@0 225
cannam@0 226 sprintf(name, "in %d", m_inputs.size() + 1);
cannam@0 227
cannam@0 228 port = jack_port_register(m_client,
cannam@0 229 name,
cannam@0 230 JACK_DEFAULT_AUDIO_TYPE,
cannam@0 231 JackPortIsInput,
cannam@0 232 0);
cannam@0 233
cannam@0 234 if (!port) {
cannam@0 235 std::cerr
cannam@0 236 << "ERROR: AudioJACKSource: Failed to create JACK input port "
cannam@0 237 << m_inputs.size() << std::endl;
cannam@0 238 } else {
cannam@0 239 m_target->setSourceRecordLatency(jack_port_get_latency(port));
cannam@0 240 }
cannam@0 241
cannam@0 242 m_inputs.push_back(port);
cannam@0 243 }
cannam@0 244 }
cannam@0 245
cannam@0 246 AudioJACKSource::~AudioJACKSource()
cannam@0 247 {
cannam@0 248 if (m_client) {
cannam@0 249 jack_deactivate(m_client);
cannam@0 250 jack_client_close(m_client);
cannam@0 251 }
cannam@0 252 }
cannam@0 253
cannam@0 254 bool
cannam@0 255 AudioJACKSource::isOK() const
cannam@0 256 {
cannam@0 257 return (m_client != 0);
cannam@0 258 }
cannam@0 259
cannam@0 260 int
cannam@0 261 AudioJACKSource::processStatic(jack_nframes_t nframes, void *arg)
cannam@0 262 {
cannam@0 263 return ((AudioJACKSource *)arg)->process(nframes);
cannam@0 264 }
cannam@0 265
cannam@0 266 int
cannam@0 267 AudioJACKSource::xrunStatic(void *arg)
cannam@0 268 {
cannam@0 269 return ((AudioJACKSource *)arg)->xrun();
cannam@0 270 }
cannam@0 271
cannam@0 272 int
cannam@0 273 AudioJACKSource::process(jack_nframes_t nframes)
cannam@0 274 {
cannam@0 275 if (m_inputs.size() < m_target->getChannelCount()) {
cannam@0 276 return 0;
cannam@0 277 }
cannam@0 278
cannam@0 279 #ifdef DEBUG_AUDIO_JACK_SOURCE
cannam@0 280 std::cout << "AudioJACKSource::process(" << nframes << "), have " << m_inputs.size() << " inputs" << std::endl;
cannam@0 281 #endif
cannam@0 282
cannam@0 283 #ifdef DEBUG_AUDIO_JACK_SOURCE
cannam@0 284 if (m_bufferSize != nframes) {
cannam@0 285 std::cerr << "WARNING: m_bufferSize != nframes (" << m_bufferSize << " != " << nframes << ")" << std::endl;
cannam@0 286 }
cannam@0 287 #endif
cannam@0 288
cannam@0 289 float **buffers = (float **)alloca(m_inputs.size() * sizeof(float *));
cannam@0 290
cannam@0 291 for (size_t ch = 0; ch < m_inputs.size(); ++ch) {
cannam@0 292 buffers[ch] = (float *)jack_port_get_buffer(m_inputs[ch], nframes);
cannam@0 293 }
cannam@0 294
cannam@0 295 if (m_target) {
cannam@0 296 m_target->putSamples(nframes, buffers);
cannam@0 297 }
cannam@0 298
cannam@0 299 float peakLeft = 0.0, peakRight = 0.0;
cannam@0 300
cannam@0 301 for (size_t ch = 0; ch < m_inputs.size(); ++ch) {
cannam@0 302
cannam@0 303 float peak = 0.0;
cannam@0 304
cannam@0 305 for (size_t i = 0; i < nframes; ++i) {
cannam@0 306 float sample = fabsf(buffers[ch][i]);
cannam@0 307 if (sample > peak) peak = sample;
cannam@0 308 }
cannam@0 309
cannam@0 310 if (ch == 0) peakLeft = peak;
cannam@0 311 if (ch > 0 || m_inputs.size() == 1) peakRight = peak;
cannam@0 312 }
cannam@0 313
cannam@0 314 if (m_target) {
cannam@0 315 m_target->setInputLevels(peakLeft, peakRight);
cannam@0 316 }
cannam@0 317
cannam@0 318 return 0;
cannam@0 319 }
cannam@0 320
cannam@0 321 int
cannam@0 322 AudioJACKSource::xrun()
cannam@0 323 {
cannam@0 324 std::cerr << "AudioJACKSource: xrun!" << std::endl;
cannam@0 325 if (m_target) m_target->audioProcessingOverload();
cannam@0 326 return 0;
cannam@0 327 }
cannam@0 328
cannam@0 329 #endif /* HAVE_JACK */
cannam@0 330