annotate audioio/AudioPortAudioTarget.cpp @ 45:6b6bca31ad53

* When setting a new model on a layer, don't delete the old one until after the new one has been set (a layer's setModel may want to compare against the old one, as WaveformLayer does)
author Chris Cannam
date Thu, 05 Oct 2006 11:00:59 +0000
parents cd5d7ff8ef38
children 52409ab73526
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@0 36 err = Pa_Initialize();
Chris@0 37 if (err != paNoError) {
Chris@0 38 std::cerr << "ERROR: AudioPortAudioTarget: Failed to initialize PortAudio" << std::endl;
Chris@0 39 return;
Chris@0 40 }
Chris@0 41
Chris@0 42 m_bufferSize = 1024;
Chris@0 43 m_sampleRate = 44100;
Chris@0 44 if (m_source && (m_source->getSourceSampleRate() != 0)) {
Chris@0 45 m_sampleRate = m_source->getSourceSampleRate();
Chris@0 46 }
Chris@0 47
Chris@0 48 m_latency = Pa_GetMinNumBuffers(m_bufferSize, m_sampleRate) * m_bufferSize;
Chris@0 49
Chris@0 50 std::cerr << "\n\n\nLATENCY= " << m_latency << std::endl;
Chris@0 51
Chris@0 52 err = Pa_OpenDefaultStream(&m_stream, 0, 2, paFloat32,
Chris@0 53 m_sampleRate, m_bufferSize, 0,
Chris@0 54 processStatic, this);
Chris@0 55
Chris@0 56 if (err != paNoError) {
Chris@0 57 std::cerr << "ERROR: AudioPortAudioTarget: Failed to open PortAudio stream" << std::endl;
Chris@0 58 m_stream = 0;
Chris@0 59 Pa_Terminate();
Chris@0 60 return;
Chris@0 61 }
Chris@0 62
Chris@0 63 err = Pa_StartStream(m_stream);
Chris@0 64
Chris@0 65 if (err != paNoError) {
Chris@0 66 std::cerr << "ERROR: AudioPortAudioTarget: Failed to start PortAudio stream" << std::endl;
Chris@0 67 Pa_CloseStream(m_stream);
Chris@0 68 m_stream = 0;
Chris@0 69 Pa_Terminate();
Chris@0 70 return;
Chris@0 71 }
Chris@0 72
Chris@0 73 if (m_source) {
Chris@0 74 std::cerr << "AudioPortAudioTarget: block size " << m_bufferSize << std::endl;
Chris@0 75 m_source->setTargetBlockSize(m_bufferSize);
Chris@0 76 m_source->setTargetSampleRate(m_sampleRate);
Chris@0 77 m_source->setTargetPlayLatency(m_latency);
Chris@0 78 }
Chris@0 79 }
Chris@0 80
Chris@0 81 AudioPortAudioTarget::~AudioPortAudioTarget()
Chris@0 82 {
Chris@0 83 if (m_stream) {
Chris@0 84 PaError err;
Chris@0 85 err = Pa_CloseStream(m_stream);
Chris@0 86 if (err != paNoError) {
Chris@0 87 std::cerr << "ERROR: AudioPortAudioTarget: Failed to close PortAudio stream" << std::endl;
Chris@0 88 }
Chris@0 89 Pa_Terminate();
Chris@0 90 }
Chris@0 91 }
Chris@0 92
Chris@0 93 bool
Chris@0 94 AudioPortAudioTarget::isOK() const
Chris@0 95 {
Chris@0 96 return (m_stream != 0);
Chris@0 97 }
Chris@0 98
Chris@0 99 int
Chris@0 100 AudioPortAudioTarget::processStatic(void *input, void *output,
Chris@0 101 unsigned long nframes,
Chris@0 102 PaTimestamp outTime, void *data)
Chris@0 103 {
Chris@0 104 return ((AudioPortAudioTarget *)data)->process(input, output,
Chris@0 105 nframes, outTime);
Chris@0 106 }
Chris@0 107
Chris@0 108 void
Chris@0 109 AudioPortAudioTarget::sourceModelReplaced()
Chris@0 110 {
Chris@0 111 m_source->setTargetSampleRate(m_sampleRate);
Chris@0 112 }
Chris@0 113
Chris@0 114 int
Chris@0 115 AudioPortAudioTarget::process(void *inputBuffer, void *outputBuffer,
Chris@0 116 unsigned long nframes,
Chris@0 117 PaTimestamp)
Chris@0 118 {
Chris@0 119 #ifdef DEBUG_AUDIO_PORT_AUDIO_TARGET
Chris@0 120 std::cout << "AudioPortAudioTarget::process(" << nframes << ")" << std::endl;
Chris@0 121 #endif
Chris@0 122
Chris@0 123 if (!m_source) return 0;
Chris@0 124
Chris@0 125 float *output = (float *)outputBuffer;
Chris@0 126
Chris@0 127 assert(nframes <= m_bufferSize);
Chris@0 128
Chris@0 129 static float **tmpbuf = 0;
Chris@0 130 static size_t tmpbufch = 0;
Chris@0 131 static size_t tmpbufsz = 0;
Chris@0 132
Chris@0 133 size_t sourceChannels = m_source->getSourceChannelCount();
Chris@0 134
Chris@0 135 // Because we offer pan, we always want at least 2 channels
Chris@0 136 if (sourceChannels < 2) sourceChannels = 2;
Chris@0 137
Chris@0 138 if (!tmpbuf || tmpbufch != sourceChannels || tmpbufsz < m_bufferSize) {
Chris@0 139
Chris@0 140 if (tmpbuf) {
Chris@0 141 for (size_t i = 0; i < tmpbufch; ++i) {
Chris@0 142 delete[] tmpbuf[i];
Chris@0 143 }
Chris@0 144 delete[] tmpbuf;
Chris@0 145 }
Chris@0 146
Chris@0 147 tmpbufch = sourceChannels;
Chris@0 148 tmpbufsz = m_bufferSize;
Chris@0 149 tmpbuf = new float *[tmpbufch];
Chris@0 150
Chris@0 151 for (size_t i = 0; i < tmpbufch; ++i) {
Chris@0 152 tmpbuf[i] = new float[tmpbufsz];
Chris@0 153 }
Chris@0 154 }
Chris@0 155
Chris@0 156 m_source->getSourceSamples(nframes, tmpbuf);
Chris@0 157
Chris@0 158 float peakLeft = 0.0, peakRight = 0.0;
Chris@0 159
Chris@0 160 for (size_t ch = 0; ch < 2; ++ch) {
Chris@0 161
Chris@0 162 float peak = 0.0;
Chris@0 163
Chris@0 164 if (ch < sourceChannels) {
Chris@0 165
Chris@0 166 // PortAudio samples are interleaved
Chris@0 167 for (size_t i = 0; i < nframes; ++i) {
Chris@0 168 output[i * 2 + ch] = tmpbuf[ch][i] * m_outputGain;
Chris@0 169 float sample = fabsf(output[i * 2 + ch]);
Chris@0 170 if (sample > peak) peak = sample;
Chris@0 171 }
Chris@0 172
Chris@0 173 } else if (ch == 1 && sourceChannels == 1) {
Chris@0 174
Chris@0 175 for (size_t i = 0; i < nframes; ++i) {
Chris@0 176 output[i * 2 + ch] = tmpbuf[0][i] * m_outputGain;
Chris@0 177 float sample = fabsf(output[i * 2 + ch]);
Chris@0 178 if (sample > peak) peak = sample;
Chris@0 179 }
Chris@0 180
Chris@0 181 } else {
Chris@0 182 for (size_t i = 0; i < nframes; ++i) {
Chris@0 183 output[i * 2 + ch] = 0;
Chris@0 184 }
Chris@0 185 }
Chris@0 186
Chris@0 187 if (ch == 0) peakLeft = peak;
Chris@0 188 if (ch > 0 || sourceChannels == 1) peakRight = peak;
Chris@0 189 }
Chris@0 190
Chris@0 191 m_source->setOutputLevels(peakLeft, peakRight);
Chris@0 192
Chris@0 193 return 0;
Chris@0 194 }
Chris@0 195
Chris@0 196 #ifdef INCLUDE_MOCFILES
Chris@0 197 #include "AudioPortAudioTarget.moc.cpp"
Chris@0 198 #endif
Chris@0 199
Chris@0 200 #endif /* HAVE_PORTAUDIO */
Chris@0 201