annotate audioio/AudioPortAudioTarget.cpp @ 92:52409ab73526

* Add support for PortAudio v19 * Add ladspa.cat file to provide categories if unavailable through LRDF
author Chris Cannam
date Thu, 25 Jan 2007 12:02:44 +0000
parents cd5d7ff8ef38
children 5828afd1d229
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_PORTAUDIO
Chris@0 17
Chris@0 18 #include "AudioPortAudioTarget.h"
Chris@0 19 #include "AudioCallbackPlaySource.h"
Chris@0 20
Chris@0 21 #include <iostream>
Chris@0 22 #include <cassert>
Chris@0 23 #include <cmath>
Chris@0 24
Chris@0 25 //#define DEBUG_AUDIO_PORT_AUDIO_TARGET 1
Chris@0 26
Chris@0 27 AudioPortAudioTarget::AudioPortAudioTarget(AudioCallbackPlaySource *source) :
Chris@0 28 AudioCallbackPlayTarget(source),
Chris@0 29 m_stream(0),
Chris@0 30 m_bufferSize(0),
Chris@0 31 m_sampleRate(0),
Chris@0 32 m_latency(0)
Chris@0 33 {
Chris@0 34 PaError err;
Chris@0 35
Chris@92 36 #ifdef DEBUG_AUDIO_PORT_AUDIO_TARGET
Chris@92 37 #ifdef HAVE_PORTAUDIO_v18
Chris@92 38 std::cerr << "AudioPortAudioTarget: Initialising for PortAudio v18" << std::endl;
Chris@92 39 #else
Chris@92 40 std::cerr << "AudioPortAudioTarget: Initialising for PortAudio v19" << std::endl;
Chris@92 41 #endif
Chris@92 42 #endif
Chris@92 43
Chris@0 44 err = Pa_Initialize();
Chris@0 45 if (err != paNoError) {
Chris@92 46 std::cerr << "ERROR: AudioPortAudioTarget: Failed to initialize PortAudio: " << Pa_GetErrorText(err) << std::endl;
Chris@0 47 return;
Chris@0 48 }
Chris@0 49
Chris@0 50 m_bufferSize = 1024;
Chris@0 51 m_sampleRate = 44100;
Chris@0 52 if (m_source && (m_source->getSourceSampleRate() != 0)) {
Chris@0 53 m_sampleRate = m_source->getSourceSampleRate();
Chris@0 54 }
Chris@0 55
Chris@92 56 #ifdef HAVE_PORTAUDIO_v18
Chris@0 57 m_latency = Pa_GetMinNumBuffers(m_bufferSize, m_sampleRate) * m_bufferSize;
Chris@92 58 #endif
Chris@0 59
Chris@92 60 #ifdef HAVE_PORTAUDIO_v18
Chris@0 61 err = Pa_OpenDefaultStream(&m_stream, 0, 2, paFloat32,
Chris@0 62 m_sampleRate, m_bufferSize, 0,
Chris@0 63 processStatic, this);
Chris@92 64 #else
Chris@92 65 err = Pa_OpenDefaultStream(&m_stream, 0, 2, paFloat32,
Chris@92 66 m_sampleRate, m_bufferSize,
Chris@92 67 processStatic, this);
Chris@92 68 #endif
Chris@0 69
Chris@0 70 if (err != paNoError) {
Chris@92 71 std::cerr << "ERROR: AudioPortAudioTarget: Failed to open PortAudio stream: " << Pa_GetErrorText(err) << std::endl;
Chris@0 72 m_stream = 0;
Chris@0 73 Pa_Terminate();
Chris@0 74 return;
Chris@0 75 }
Chris@0 76
Chris@92 77 #ifndef HAVE_PORTAUDIO_v18
Chris@92 78 const PaStreamInfo *info = Pa_GetStreamInfo(m_stream);
Chris@92 79 m_latency = int(info->outputLatency * m_sampleRate + 0.001);
Chris@92 80 #endif
Chris@92 81
Chris@92 82 std::cerr << "PortAudio latency = " << m_latency << " frames" << std::endl;
Chris@92 83
Chris@0 84 err = Pa_StartStream(m_stream);
Chris@0 85
Chris@0 86 if (err != paNoError) {
Chris@92 87 std::cerr << "ERROR: AudioPortAudioTarget: Failed to start PortAudio stream: " << Pa_GetErrorText(err) << std::endl;
Chris@0 88 Pa_CloseStream(m_stream);
Chris@0 89 m_stream = 0;
Chris@0 90 Pa_Terminate();
Chris@0 91 return;
Chris@0 92 }
Chris@0 93
Chris@0 94 if (m_source) {
Chris@0 95 std::cerr << "AudioPortAudioTarget: block size " << m_bufferSize << std::endl;
Chris@0 96 m_source->setTargetBlockSize(m_bufferSize);
Chris@0 97 m_source->setTargetSampleRate(m_sampleRate);
Chris@0 98 m_source->setTargetPlayLatency(m_latency);
Chris@0 99 }
Chris@0 100 }
Chris@0 101
Chris@0 102 AudioPortAudioTarget::~AudioPortAudioTarget()
Chris@0 103 {
Chris@0 104 if (m_stream) {
Chris@0 105 PaError err;
Chris@0 106 err = Pa_CloseStream(m_stream);
Chris@0 107 if (err != paNoError) {
Chris@92 108 std::cerr << "ERROR: AudioPortAudioTarget: Failed to close PortAudio stream: " << Pa_GetErrorText(err) << std::endl;
Chris@0 109 }
Chris@92 110 err = Pa_Terminate();
Chris@92 111 if (err != paNoError) {
Chris@92 112 std::cerr << "ERROR: AudioPortAudioTarget: Failed to terminate PortAudio: " << Pa_GetErrorText(err) << std::endl;
Chris@92 113 }
Chris@0 114 }
Chris@0 115 }
Chris@0 116
Chris@0 117 bool
Chris@0 118 AudioPortAudioTarget::isOK() const
Chris@0 119 {
Chris@0 120 return (m_stream != 0);
Chris@0 121 }
Chris@0 122
Chris@92 123 #ifdef HAVE_PORTAUDIO_v18
Chris@0 124 int
Chris@0 125 AudioPortAudioTarget::processStatic(void *input, void *output,
Chris@0 126 unsigned long nframes,
Chris@0 127 PaTimestamp outTime, void *data)
Chris@0 128 {
Chris@0 129 return ((AudioPortAudioTarget *)data)->process(input, output,
Chris@0 130 nframes, outTime);
Chris@0 131 }
Chris@92 132 #else
Chris@92 133 int
Chris@92 134 AudioPortAudioTarget::processStatic(const void *input, void *output,
Chris@92 135 unsigned long nframes,
Chris@92 136 const PaStreamCallbackTimeInfo *timeInfo,
Chris@92 137 PaStreamCallbackFlags flags, void *data)
Chris@92 138 {
Chris@92 139 return ((AudioPortAudioTarget *)data)->process(input, output,
Chris@92 140 nframes, timeInfo,
Chris@92 141 flags);
Chris@92 142 }
Chris@92 143 #endif
Chris@0 144
Chris@0 145 void
Chris@0 146 AudioPortAudioTarget::sourceModelReplaced()
Chris@0 147 {
Chris@0 148 m_source->setTargetSampleRate(m_sampleRate);
Chris@0 149 }
Chris@0 150
Chris@92 151 #ifdef HAVE_PORTAUDIO_v18
Chris@0 152 int
Chris@0 153 AudioPortAudioTarget::process(void *inputBuffer, void *outputBuffer,
Chris@0 154 unsigned long nframes,
Chris@0 155 PaTimestamp)
Chris@92 156 #else
Chris@92 157 int
Chris@92 158 AudioPortAudioTarget::process(const void *inputBuffer, void *outputBuffer,
Chris@92 159 unsigned long nframes,
Chris@92 160 const PaStreamCallbackTimeInfo *,
Chris@92 161 PaStreamCallbackFlags)
Chris@92 162 #endif
Chris@0 163 {
Chris@0 164 #ifdef DEBUG_AUDIO_PORT_AUDIO_TARGET
Chris@0 165 std::cout << "AudioPortAudioTarget::process(" << nframes << ")" << std::endl;
Chris@0 166 #endif
Chris@0 167
Chris@0 168 if (!m_source) return 0;
Chris@0 169
Chris@0 170 float *output = (float *)outputBuffer;
Chris@0 171
Chris@0 172 assert(nframes <= m_bufferSize);
Chris@0 173
Chris@0 174 static float **tmpbuf = 0;
Chris@0 175 static size_t tmpbufch = 0;
Chris@0 176 static size_t tmpbufsz = 0;
Chris@0 177
Chris@0 178 size_t sourceChannels = m_source->getSourceChannelCount();
Chris@0 179
Chris@0 180 // Because we offer pan, we always want at least 2 channels
Chris@0 181 if (sourceChannels < 2) sourceChannels = 2;
Chris@0 182
Chris@0 183 if (!tmpbuf || tmpbufch != sourceChannels || tmpbufsz < m_bufferSize) {
Chris@0 184
Chris@0 185 if (tmpbuf) {
Chris@0 186 for (size_t i = 0; i < tmpbufch; ++i) {
Chris@0 187 delete[] tmpbuf[i];
Chris@0 188 }
Chris@0 189 delete[] tmpbuf;
Chris@0 190 }
Chris@0 191
Chris@0 192 tmpbufch = sourceChannels;
Chris@0 193 tmpbufsz = m_bufferSize;
Chris@0 194 tmpbuf = new float *[tmpbufch];
Chris@0 195
Chris@0 196 for (size_t i = 0; i < tmpbufch; ++i) {
Chris@0 197 tmpbuf[i] = new float[tmpbufsz];
Chris@0 198 }
Chris@0 199 }
Chris@0 200
Chris@0 201 m_source->getSourceSamples(nframes, tmpbuf);
Chris@0 202
Chris@0 203 float peakLeft = 0.0, peakRight = 0.0;
Chris@0 204
Chris@0 205 for (size_t ch = 0; ch < 2; ++ch) {
Chris@0 206
Chris@0 207 float peak = 0.0;
Chris@0 208
Chris@0 209 if (ch < sourceChannels) {
Chris@0 210
Chris@0 211 // PortAudio samples are interleaved
Chris@0 212 for (size_t i = 0; i < nframes; ++i) {
Chris@0 213 output[i * 2 + ch] = tmpbuf[ch][i] * m_outputGain;
Chris@0 214 float sample = fabsf(output[i * 2 + ch]);
Chris@0 215 if (sample > peak) peak = sample;
Chris@0 216 }
Chris@0 217
Chris@0 218 } else if (ch == 1 && sourceChannels == 1) {
Chris@0 219
Chris@0 220 for (size_t i = 0; i < nframes; ++i) {
Chris@0 221 output[i * 2 + ch] = tmpbuf[0][i] * m_outputGain;
Chris@0 222 float sample = fabsf(output[i * 2 + ch]);
Chris@0 223 if (sample > peak) peak = sample;
Chris@0 224 }
Chris@0 225
Chris@0 226 } else {
Chris@0 227 for (size_t i = 0; i < nframes; ++i) {
Chris@0 228 output[i * 2 + ch] = 0;
Chris@0 229 }
Chris@0 230 }
Chris@0 231
Chris@0 232 if (ch == 0) peakLeft = peak;
Chris@0 233 if (ch > 0 || sourceChannels == 1) peakRight = peak;
Chris@0 234 }
Chris@0 235
Chris@0 236 m_source->setOutputLevels(peakLeft, peakRight);
Chris@0 237
Chris@0 238 return 0;
Chris@0 239 }
Chris@0 240
Chris@0 241 #ifdef INCLUDE_MOCFILES
Chris@0 242 #include "AudioPortAudioTarget.moc.cpp"
Chris@0 243 #endif
Chris@0 244
Chris@0 245 #endif /* HAVE_PORTAUDIO */
Chris@0 246