annotate audioio/AudioPortAudioTarget.cpp @ 248:ecbf3b75c562

Debug output only
author Chris Cannam
date Fri, 07 Oct 2011 17:06:08 +0100
parents a9f1850b873d
children 0136555495ae 068235cf5bf7
rev   line source
Chris@59 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@59 2
Chris@59 3 /*
Chris@59 4 Sonic Visualiser
Chris@59 5 An audio file viewer and annotation editor.
Chris@59 6 Centre for Digital Music, Queen Mary, University of London.
Chris@59 7 This file copyright 2006 Chris Cannam.
Chris@59 8
Chris@59 9 This program is free software; you can redistribute it and/or
Chris@59 10 modify it under the terms of the GNU General Public License as
Chris@59 11 published by the Free Software Foundation; either version 2 of the
Chris@59 12 License, or (at your option) any later version. See the file
Chris@59 13 COPYING included with this distribution for more information.
Chris@59 14 */
Chris@59 15
Chris@114 16 #ifdef HAVE_PORTAUDIO_2_0
Chris@59 17
Chris@59 18 #include "AudioPortAudioTarget.h"
Chris@59 19 #include "AudioCallbackPlaySource.h"
Chris@59 20
Chris@59 21 #include <iostream>
Chris@59 22 #include <cassert>
Chris@59 23 #include <cmath>
Chris@59 24
Chris@182 25 #ifndef _WIN32
Chris@182 26 #include <pthread.h>
Chris@182 27 #endif
Chris@182 28
Chris@59 29 //#define DEBUG_AUDIO_PORT_AUDIO_TARGET 1
Chris@59 30
Chris@59 31 AudioPortAudioTarget::AudioPortAudioTarget(AudioCallbackPlaySource *source) :
Chris@59 32 AudioCallbackPlayTarget(source),
Chris@59 33 m_stream(0),
Chris@59 34 m_bufferSize(0),
Chris@59 35 m_sampleRate(0),
Chris@70 36 m_latency(0),
Chris@182 37 m_prioritySet(false),
Chris@70 38 m_done(false)
Chris@59 39 {
Chris@59 40 PaError err;
Chris@59 41
Chris@59 42 #ifdef DEBUG_AUDIO_PORT_AUDIO_TARGET
Chris@59 43 std::cerr << "AudioPortAudioTarget: Initialising for PortAudio v19" << std::endl;
Chris@59 44 #endif
Chris@59 45
Chris@59 46 err = Pa_Initialize();
Chris@59 47 if (err != paNoError) {
Chris@59 48 std::cerr << "ERROR: AudioPortAudioTarget: Failed to initialize PortAudio: " << Pa_GetErrorText(err) << std::endl;
Chris@59 49 return;
Chris@59 50 }
Chris@59 51
Chris@80 52 m_bufferSize = 2048;
Chris@59 53 m_sampleRate = 44100;
Chris@59 54 if (m_source && (m_source->getSourceSampleRate() != 0)) {
Chris@59 55 m_sampleRate = m_source->getSourceSampleRate();
Chris@59 56 }
Chris@59 57
Chris@81 58 PaStreamParameters op;
Chris@96 59 op.device = Pa_GetDefaultOutputDevice();
Chris@81 60 op.channelCount = 2;
Chris@81 61 op.sampleFormat = paFloat32;
Chris@245 62 op.suggestedLatency = 0.2;
Chris@81 63 op.hostApiSpecificStreamInfo = 0;
Chris@91 64 err = Pa_OpenStream(&m_stream, 0, &op, m_sampleRate,
Chris@91 65 paFramesPerBufferUnspecified,
Chris@81 66 paNoFlag, processStatic, this);
Chris@59 67
Chris@95 68 if (err != paNoError) {
Chris@95 69
Chris@95 70 std::cerr << "WARNING: AudioPortAudioTarget: Failed to open PortAudio stream with default frames per buffer, trying again with fixed frames per buffer..." << std::endl;
Chris@95 71
Chris@95 72 err = Pa_OpenStream(&m_stream, 0, &op, m_sampleRate,
Chris@95 73 1024,
Chris@95 74 paNoFlag, processStatic, this);
Chris@96 75 m_bufferSize = 1024;
Chris@95 76 }
Chris@95 77
Chris@59 78 if (err != paNoError) {
Chris@59 79 std::cerr << "ERROR: AudioPortAudioTarget: Failed to open PortAudio stream: " << Pa_GetErrorText(err) << std::endl;
Chris@195 80 std::cerr << "Note: device ID was " << op.device << std::endl;
Chris@59 81 m_stream = 0;
Chris@59 82 Pa_Terminate();
Chris@59 83 return;
Chris@59 84 }
Chris@59 85
Chris@59 86 const PaStreamInfo *info = Pa_GetStreamInfo(m_stream);
Chris@59 87 m_latency = int(info->outputLatency * m_sampleRate + 0.001);
Chris@96 88 if (m_bufferSize < m_latency) m_bufferSize = m_latency;
Chris@59 89
Chris@59 90 std::cerr << "PortAudio latency = " << m_latency << " frames" << std::endl;
Chris@59 91
Chris@59 92 err = Pa_StartStream(m_stream);
Chris@59 93
Chris@59 94 if (err != paNoError) {
Chris@59 95 std::cerr << "ERROR: AudioPortAudioTarget: Failed to start PortAudio stream: " << Pa_GetErrorText(err) << std::endl;
Chris@59 96 Pa_CloseStream(m_stream);
Chris@59 97 m_stream = 0;
Chris@59 98 Pa_Terminate();
Chris@59 99 return;
Chris@59 100 }
Chris@59 101
Chris@59 102 if (m_source) {
Chris@59 103 std::cerr << "AudioPortAudioTarget: block size " << m_bufferSize << std::endl;
Chris@91 104 m_source->setTarget(this, m_bufferSize);
Chris@59 105 m_source->setTargetSampleRate(m_sampleRate);
Chris@59 106 m_source->setTargetPlayLatency(m_latency);
Chris@59 107 }
Chris@59 108
Chris@59 109 #ifdef DEBUG_PORT_AUDIO_TARGET
Chris@59 110 std::cerr << "AudioPortAudioTarget: initialised OK" << std::endl;
Chris@59 111 #endif
Chris@59 112 }
Chris@59 113
Chris@59 114 AudioPortAudioTarget::~AudioPortAudioTarget()
Chris@59 115 {
Chris@233 116 SVDEBUG << "AudioPortAudioTarget::~AudioPortAudioTarget()" << endl;
Chris@70 117
Chris@91 118 if (m_source) {
Chris@91 119 m_source->setTarget(0, m_bufferSize);
Chris@91 120 }
Chris@91 121
Chris@70 122 shutdown();
Chris@70 123
Chris@59 124 if (m_stream) {
Chris@70 125
Chris@233 126 SVDEBUG << "closing stream" << endl;
Chris@70 127
Chris@59 128 PaError err;
Chris@59 129 err = Pa_CloseStream(m_stream);
Chris@59 130 if (err != paNoError) {
Chris@59 131 std::cerr << "ERROR: AudioPortAudioTarget: Failed to close PortAudio stream: " << Pa_GetErrorText(err) << std::endl;
Chris@59 132 }
Chris@70 133
Chris@70 134 std::cerr << "terminating" << std::endl;
Chris@70 135
Chris@59 136 err = Pa_Terminate();
Chris@59 137 if (err != paNoError) {
Chris@59 138 std::cerr << "ERROR: AudioPortAudioTarget: Failed to terminate PortAudio: " << Pa_GetErrorText(err) << std::endl;
Chris@59 139 }
Chris@59 140 }
Chris@70 141
Chris@70 142 m_stream = 0;
Chris@70 143
Chris@233 144 SVDEBUG << "AudioPortAudioTarget::~AudioPortAudioTarget() done" << endl;
Chris@70 145 }
Chris@70 146
Chris@70 147 void
Chris@70 148 AudioPortAudioTarget::shutdown()
Chris@70 149 {
Chris@177 150 #ifdef DEBUG_PORT_AUDIO_TARGET
Chris@233 151 SVDEBUG << "AudioPortAudioTarget::shutdown" << endl;
Chris@177 152 #endif
Chris@70 153 m_done = true;
Chris@59 154 }
Chris@59 155
Chris@59 156 bool
Chris@59 157 AudioPortAudioTarget::isOK() const
Chris@59 158 {
Chris@59 159 return (m_stream != 0);
Chris@59 160 }
Chris@59 161
Chris@91 162 double
Chris@91 163 AudioPortAudioTarget::getCurrentTime() const
Chris@91 164 {
Chris@91 165 if (!m_stream) return 0.0;
Chris@91 166 else return Pa_GetStreamTime(m_stream);
Chris@91 167 }
Chris@91 168
Chris@59 169 int
Chris@59 170 AudioPortAudioTarget::processStatic(const void *input, void *output,
Chris@59 171 unsigned long nframes,
Chris@59 172 const PaStreamCallbackTimeInfo *timeInfo,
Chris@59 173 PaStreamCallbackFlags flags, void *data)
Chris@59 174 {
Chris@59 175 return ((AudioPortAudioTarget *)data)->process(input, output,
Chris@59 176 nframes, timeInfo,
Chris@59 177 flags);
Chris@59 178 }
Chris@59 179
Chris@59 180 void
Chris@59 181 AudioPortAudioTarget::sourceModelReplaced()
Chris@59 182 {
Chris@59 183 m_source->setTargetSampleRate(m_sampleRate);
Chris@59 184 }
Chris@59 185
Chris@59 186 int
Chris@59 187 AudioPortAudioTarget::process(const void *, void *outputBuffer,
Chris@59 188 unsigned long nframes,
Chris@59 189 const PaStreamCallbackTimeInfo *,
Chris@59 190 PaStreamCallbackFlags)
Chris@59 191 {
Chris@59 192 #ifdef DEBUG_AUDIO_PORT_AUDIO_TARGET
Chris@233 193 SVDEBUG << "AudioPortAudioTarget::process(" << nframes << ")" << endl;
Chris@59 194 #endif
Chris@59 195
Chris@177 196 if (!m_source || m_done) {
Chris@177 197 #ifdef DEBUG_AUDIO_PORT_AUDIO_TARGET
Chris@233 198 SVDEBUG << "AudioPortAudioTarget::process: Doing nothing, no source or application done" << endl;
Chris@177 199 #endif
Chris@177 200 return 0;
Chris@177 201 }
Chris@59 202
Chris@182 203 if (!m_prioritySet) {
Chris@182 204 #ifndef _WIN32
Chris@182 205 sched_param param;
Chris@182 206 param.sched_priority = 20;
Chris@182 207 if (pthread_setschedparam(pthread_self(), SCHED_RR, &param)) {
Chris@233 208 SVDEBUG << "AudioPortAudioTarget: NOTE: couldn't set RT scheduling class" << endl;
Chris@182 209 } else {
Chris@233 210 SVDEBUG << "AudioPortAudioTarget: NOTE: successfully set RT scheduling class" << endl;
Chris@182 211 }
Chris@182 212 #endif
Chris@182 213 m_prioritySet = true;
Chris@182 214 }
Chris@182 215
Chris@59 216 float *output = (float *)outputBuffer;
Chris@59 217
Chris@59 218 assert(nframes <= m_bufferSize);
Chris@59 219
Chris@59 220 static float **tmpbuf = 0;
Chris@59 221 static size_t tmpbufch = 0;
Chris@59 222 static size_t tmpbufsz = 0;
Chris@59 223
Chris@59 224 size_t sourceChannels = m_source->getSourceChannelCount();
Chris@59 225
Chris@59 226 // Because we offer pan, we always want at least 2 channels
Chris@59 227 if (sourceChannels < 2) sourceChannels = 2;
Chris@59 228
Chris@59 229 if (!tmpbuf || tmpbufch != sourceChannels || int(tmpbufsz) < m_bufferSize) {
Chris@59 230
Chris@59 231 if (tmpbuf) {
Chris@59 232 for (size_t i = 0; i < tmpbufch; ++i) {
Chris@59 233 delete[] tmpbuf[i];
Chris@59 234 }
Chris@59 235 delete[] tmpbuf;
Chris@59 236 }
Chris@59 237
Chris@59 238 tmpbufch = sourceChannels;
Chris@59 239 tmpbufsz = m_bufferSize;
Chris@59 240 tmpbuf = new float *[tmpbufch];
Chris@59 241
Chris@59 242 for (size_t i = 0; i < tmpbufch; ++i) {
Chris@59 243 tmpbuf[i] = new float[tmpbufsz];
Chris@59 244 }
Chris@59 245 }
Chris@59 246
Chris@59 247 size_t received = m_source->getSourceSamples(nframes, tmpbuf);
Chris@59 248
Chris@59 249 float peakLeft = 0.0, peakRight = 0.0;
Chris@59 250
Chris@59 251 for (size_t ch = 0; ch < 2; ++ch) {
Chris@59 252
Chris@59 253 float peak = 0.0;
Chris@59 254
Chris@59 255 if (ch < sourceChannels) {
Chris@59 256
Chris@59 257 // PortAudio samples are interleaved
Chris@59 258 for (size_t i = 0; i < nframes; ++i) {
Chris@59 259 if (i < received) {
Chris@59 260 output[i * 2 + ch] = tmpbuf[ch][i] * m_outputGain;
Chris@59 261 float sample = fabsf(output[i * 2 + ch]);
Chris@59 262 if (sample > peak) peak = sample;
Chris@59 263 } else {
Chris@59 264 output[i * 2 + ch] = 0;
Chris@59 265 }
Chris@59 266 }
Chris@59 267
Chris@59 268 } else if (ch == 1 && sourceChannels == 1) {
Chris@59 269
Chris@59 270 for (size_t i = 0; i < nframes; ++i) {
Chris@59 271 if (i < received) {
Chris@59 272 output[i * 2 + ch] = tmpbuf[0][i] * m_outputGain;
Chris@59 273 float sample = fabsf(output[i * 2 + ch]);
Chris@59 274 if (sample > peak) peak = sample;
Chris@59 275 } else {
Chris@59 276 output[i * 2 + ch] = 0;
Chris@59 277 }
Chris@59 278 }
Chris@59 279
Chris@59 280 } else {
Chris@59 281 for (size_t i = 0; i < nframes; ++i) {
Chris@59 282 output[i * 2 + ch] = 0;
Chris@59 283 }
Chris@59 284 }
Chris@59 285
Chris@59 286 if (ch == 0) peakLeft = peak;
Chris@59 287 if (ch > 0 || sourceChannels == 1) peakRight = peak;
Chris@59 288 }
Chris@59 289
Chris@59 290 m_source->setOutputLevels(peakLeft, peakRight);
Chris@59 291
Chris@130 292 if (Pa_GetStreamCpuLoad(m_stream) > 0.7) {
Chris@130 293 if (m_source) m_source->audioProcessingOverload();
Chris@130 294 }
Chris@130 295
Chris@59 296 return 0;
Chris@59 297 }
Chris@59 298
Chris@59 299 #endif /* HAVE_PORTAUDIO */
Chris@59 300