00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #ifdef HAVE_PORTAUDIO
00017
00018 #include "AudioPortAudioTarget.h"
00019 #include "AudioCallbackPlaySource.h"
00020
00021 #include <iostream>
00022 #include <cassert>
00023 #include <cmath>
00024
00025
00026
00027 AudioPortAudioTarget::AudioPortAudioTarget(AudioCallbackPlaySource *source) :
00028 AudioCallbackPlayTarget(source),
00029 m_stream(0),
00030 m_bufferSize(0),
00031 m_sampleRate(0),
00032 m_latency(0),
00033 m_done(false)
00034 {
00035 PaError err;
00036
00037 #ifdef DEBUG_AUDIO_PORT_AUDIO_TARGET
00038 #ifdef HAVE_PORTAUDIO_V18
00039 std::cerr << "AudioPortAudioTarget: Initialising for PortAudio v18" << std::endl;
00040 #else
00041 std::cerr << "AudioPortAudioTarget: Initialising for PortAudio v19" << std::endl;
00042 #endif
00043 #endif
00044
00045 err = Pa_Initialize();
00046 if (err != paNoError) {
00047 std::cerr << "ERROR: AudioPortAudioTarget: Failed to initialize PortAudio: " << Pa_GetErrorText(err) << std::endl;
00048 return;
00049 }
00050
00051 m_bufferSize = 2048;
00052 m_sampleRate = 44100;
00053 if (m_source && (m_source->getSourceSampleRate() != 0)) {
00054 m_sampleRate = m_source->getSourceSampleRate();
00055 }
00056
00057 #ifdef HAVE_PORTAUDIO_V18
00058 m_latency = Pa_GetMinNumBuffers(m_bufferSize, m_sampleRate) * m_bufferSize;
00059 #endif
00060
00061 #ifdef HAVE_PORTAUDIO_V18
00062 err = Pa_OpenDefaultStream(&m_stream, 0, 2, paFloat32,
00063 m_sampleRate, m_bufferSize, 0,
00064 processStatic, this);
00065 #else
00066 PaStreamParameters op;
00067 op.device = Pa_GetDefaultOutputDevice();
00068 op.channelCount = 2;
00069 op.sampleFormat = paFloat32;
00070 op.suggestedLatency = 0.2;
00071 op.hostApiSpecificStreamInfo = 0;
00072 err = Pa_OpenStream(&m_stream, 0, &op, m_sampleRate,
00073 paFramesPerBufferUnspecified,
00074 paNoFlag, processStatic, this);
00075 #endif
00076
00077 #ifndef HAVE_PORTAUDIO_V18
00078 if (err != paNoError) {
00079
00080 std::cerr << "WARNING: AudioPortAudioTarget: Failed to open PortAudio stream with default frames per buffer, trying again with fixed frames per buffer..." << std::endl;
00081
00082 err = Pa_OpenStream(&m_stream, 0, &op, m_sampleRate,
00083 1024,
00084 paNoFlag, processStatic, this);
00085 m_bufferSize = 1024;
00086 }
00087 #endif
00088
00089 if (err != paNoError) {
00090 std::cerr << "ERROR: AudioPortAudioTarget: Failed to open PortAudio stream: " << Pa_GetErrorText(err) << std::endl;
00091 m_stream = 0;
00092 Pa_Terminate();
00093 return;
00094 }
00095
00096 #ifndef HAVE_PORTAUDIO_V18
00097 const PaStreamInfo *info = Pa_GetStreamInfo(m_stream);
00098 m_latency = int(info->outputLatency * m_sampleRate + 0.001);
00099 if (m_bufferSize < m_latency) m_bufferSize = m_latency;
00100 #endif
00101
00102 std::cerr << "PortAudio latency = " << m_latency << " frames" << std::endl;
00103
00104 err = Pa_StartStream(m_stream);
00105
00106 if (err != paNoError) {
00107 std::cerr << "ERROR: AudioPortAudioTarget: Failed to start PortAudio stream: " << Pa_GetErrorText(err) << std::endl;
00108 Pa_CloseStream(m_stream);
00109 m_stream = 0;
00110 Pa_Terminate();
00111 return;
00112 }
00113
00114 if (m_source) {
00115 std::cerr << "AudioPortAudioTarget: block size " << m_bufferSize << std::endl;
00116 m_source->setTarget(this, m_bufferSize);
00117 m_source->setTargetSampleRate(m_sampleRate);
00118 m_source->setTargetPlayLatency(m_latency);
00119 }
00120
00121 #ifdef DEBUG_PORT_AUDIO_TARGET
00122 std::cerr << "AudioPortAudioTarget: initialised OK" << std::endl;
00123 #endif
00124 }
00125
00126 AudioPortAudioTarget::~AudioPortAudioTarget()
00127 {
00128 std::cerr << "AudioPortAudioTarget::~AudioPortAudioTarget()" << std::endl;
00129
00130 if (m_source) {
00131 m_source->setTarget(0, m_bufferSize);
00132 }
00133
00134 shutdown();
00135
00136 if (m_stream) {
00137
00138 std::cerr << "closing stream" << std::endl;
00139
00140 PaError err;
00141 err = Pa_CloseStream(m_stream);
00142 if (err != paNoError) {
00143 std::cerr << "ERROR: AudioPortAudioTarget: Failed to close PortAudio stream: " << Pa_GetErrorText(err) << std::endl;
00144 }
00145
00146 std::cerr << "terminating" << std::endl;
00147
00148 err = Pa_Terminate();
00149 if (err != paNoError) {
00150 std::cerr << "ERROR: AudioPortAudioTarget: Failed to terminate PortAudio: " << Pa_GetErrorText(err) << std::endl;
00151 }
00152 }
00153
00154 m_stream = 0;
00155
00156 std::cerr << "AudioPortAudioTarget::~AudioPortAudioTarget() done" << std::endl;
00157 }
00158
00159 void
00160 AudioPortAudioTarget::shutdown()
00161 {
00162 m_done = true;
00163 }
00164
00165 bool
00166 AudioPortAudioTarget::isOK() const
00167 {
00168 return (m_stream != 0);
00169 }
00170
00171 double
00172 AudioPortAudioTarget::getCurrentTime() const
00173 {
00174 if (!m_stream) return 0.0;
00175 else return Pa_GetStreamTime(m_stream);
00176 }
00177
00178 #ifdef HAVE_PORTAUDIO_V18
00179 int
00180 AudioPortAudioTarget::processStatic(void *input, void *output,
00181 unsigned long nframes,
00182 PaTimestamp outTime, void *data)
00183 {
00184 return ((AudioPortAudioTarget *)data)->process(input, output,
00185 nframes, outTime);
00186 }
00187 #else
00188 int
00189 AudioPortAudioTarget::processStatic(const void *input, void *output,
00190 unsigned long nframes,
00191 const PaStreamCallbackTimeInfo *timeInfo,
00192 PaStreamCallbackFlags flags, void *data)
00193 {
00194 return ((AudioPortAudioTarget *)data)->process(input, output,
00195 nframes, timeInfo,
00196 flags);
00197 }
00198 #endif
00199
00200 void
00201 AudioPortAudioTarget::sourceModelReplaced()
00202 {
00203 m_source->setTargetSampleRate(m_sampleRate);
00204 }
00205
00206 #ifdef HAVE_PORTAUDIO_V18
00207 int
00208 AudioPortAudioTarget::process(void *inputBuffer, void *outputBuffer,
00209 unsigned long nframes,
00210 PaTimestamp)
00211 #else
00212 int
00213 AudioPortAudioTarget::process(const void *, void *outputBuffer,
00214 unsigned long nframes,
00215 const PaStreamCallbackTimeInfo *,
00216 PaStreamCallbackFlags)
00217 #endif
00218 {
00219 #ifdef DEBUG_AUDIO_PORT_AUDIO_TARGET
00220 std::cout << "AudioPortAudioTarget::process(" << nframes << ")" << std::endl;
00221 #endif
00222
00223 if (!m_source || m_done) return 0;
00224
00225 float *output = (float *)outputBuffer;
00226
00227 assert(nframes <= m_bufferSize);
00228
00229 static float **tmpbuf = 0;
00230 static size_t tmpbufch = 0;
00231 static size_t tmpbufsz = 0;
00232
00233 size_t sourceChannels = m_source->getSourceChannelCount();
00234
00235
00236 if (sourceChannels < 2) sourceChannels = 2;
00237
00238 if (!tmpbuf || tmpbufch != sourceChannels || int(tmpbufsz) < m_bufferSize) {
00239
00240 if (tmpbuf) {
00241 for (size_t i = 0; i < tmpbufch; ++i) {
00242 delete[] tmpbuf[i];
00243 }
00244 delete[] tmpbuf;
00245 }
00246
00247 tmpbufch = sourceChannels;
00248 tmpbufsz = m_bufferSize;
00249 tmpbuf = new float *[tmpbufch];
00250
00251 for (size_t i = 0; i < tmpbufch; ++i) {
00252 tmpbuf[i] = new float[tmpbufsz];
00253 }
00254 }
00255
00256 size_t received = m_source->getSourceSamples(nframes, tmpbuf);
00257
00258 float peakLeft = 0.0, peakRight = 0.0;
00259
00260 for (size_t ch = 0; ch < 2; ++ch) {
00261
00262 float peak = 0.0;
00263
00264 if (ch < sourceChannels) {
00265
00266
00267 for (size_t i = 0; i < nframes; ++i) {
00268 if (i < received) {
00269 output[i * 2 + ch] = tmpbuf[ch][i] * m_outputGain;
00270 float sample = fabsf(output[i * 2 + ch]);
00271 if (sample > peak) peak = sample;
00272 } else {
00273 output[i * 2 + ch] = 0;
00274 }
00275 }
00276
00277 } else if (ch == 1 && sourceChannels == 1) {
00278
00279 for (size_t i = 0; i < nframes; ++i) {
00280 if (i < received) {
00281 output[i * 2 + ch] = tmpbuf[0][i] * m_outputGain;
00282 float sample = fabsf(output[i * 2 + ch]);
00283 if (sample > peak) peak = sample;
00284 } else {
00285 output[i * 2 + ch] = 0;
00286 }
00287 }
00288
00289 } else {
00290 for (size_t i = 0; i < nframes; ++i) {
00291 output[i * 2 + ch] = 0;
00292 }
00293 }
00294
00295 if (ch == 0) peakLeft = peak;
00296 if (ch > 0 || sourceChannels == 1) peakRight = peak;
00297 }
00298
00299 m_source->setOutputLevels(peakLeft, peakRight);
00300
00301 return 0;
00302 }
00303
00304 #endif
00305