annotate audioio/AudioCallbackPlaySource.h @ 122:ab861544f998

* Comment out problematic test -- sincerequest_t always seemed to be zero when this line was reached, so the pointer was often getting stuck if you asked to play a loop that had been drawn to the left of the position the pointer was at when you then tried to play it
author Chris Cannam
date Fri, 06 Jun 2008 10:32:50 +0000
parents 52af71802ffd
children 4c9c04645685
rev   line source
Chris@43 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@43 2
Chris@43 3 /*
Chris@43 4 Sonic Visualiser
Chris@43 5 An audio file viewer and annotation editor.
Chris@43 6 Centre for Digital Music, Queen Mary, University of London.
Chris@43 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@43 8
Chris@43 9 This program is free software; you can redistribute it and/or
Chris@43 10 modify it under the terms of the GNU General Public License as
Chris@43 11 published by the Free Software Foundation; either version 2 of the
Chris@43 12 License, or (at your option) any later version. See the file
Chris@43 13 COPYING included with this distribution for more information.
Chris@43 14 */
Chris@43 15
Chris@43 16 #ifndef _AUDIO_CALLBACK_PLAY_SOURCE_H_
Chris@43 17 #define _AUDIO_CALLBACK_PLAY_SOURCE_H_
Chris@43 18
Chris@43 19 #include "base/RingBuffer.h"
Chris@43 20 #include "base/AudioPlaySource.h"
Chris@43 21 #include "base/PropertyContainer.h"
Chris@43 22 #include "base/Scavenger.h"
Chris@43 23
Chris@43 24 #include <QObject>
Chris@43 25 #include <QMutex>
Chris@43 26 #include <QWaitCondition>
Chris@43 27
Chris@43 28 #include "base/Thread.h"
Chris@93 29 #include "base/RealTime.h"
Chris@43 30
Chris@43 31 #include <samplerate.h>
Chris@43 32
Chris@43 33 #include <set>
Chris@43 34 #include <map>
Chris@43 35
Chris@91 36 namespace RubberBand {
Chris@91 37 class RubberBandStretcher;
Chris@91 38 }
Chris@62 39
Chris@43 40 class Model;
Chris@105 41 class ViewManagerBase;
Chris@43 42 class AudioGenerator;
Chris@43 43 class PlayParameters;
Chris@43 44 class RealTimePluginInstance;
Chris@91 45 class AudioCallbackPlayTarget;
Chris@43 46
Chris@43 47 /**
Chris@43 48 * AudioCallbackPlaySource manages audio data supply to callback-based
Chris@43 49 * audio APIs such as JACK or CoreAudio. It maintains one ring buffer
Chris@43 50 * per channel, filled during playback by a non-realtime thread, and
Chris@43 51 * provides a method for a realtime thread to pick up the latest
Chris@43 52 * available sample data from these buffers.
Chris@43 53 */
Chris@43 54 class AudioCallbackPlaySource : public virtual QObject,
Chris@43 55 public AudioPlaySource
Chris@43 56 {
Chris@43 57 Q_OBJECT
Chris@43 58
Chris@43 59 public:
Chris@105 60 AudioCallbackPlaySource(ViewManagerBase *, QString clientName);
Chris@43 61 virtual ~AudioCallbackPlaySource();
Chris@43 62
Chris@43 63 /**
Chris@43 64 * Add a data model to be played from. The source can mix
Chris@43 65 * playback from a number of sources including dense and sparse
Chris@43 66 * models. The models must match in sample rate, but they don't
Chris@43 67 * have to have identical numbers of channels.
Chris@43 68 */
Chris@43 69 virtual void addModel(Model *model);
Chris@43 70
Chris@43 71 /**
Chris@43 72 * Remove a model.
Chris@43 73 */
Chris@43 74 virtual void removeModel(Model *model);
Chris@43 75
Chris@43 76 /**
Chris@43 77 * Remove all models. (Silence will ensue.)
Chris@43 78 */
Chris@43 79 virtual void clearModels();
Chris@43 80
Chris@43 81 /**
Chris@43 82 * Start making data available in the ring buffers for playback,
Chris@43 83 * from the given frame. If playback is already under way, reseek
Chris@43 84 * to the given frame and continue.
Chris@43 85 */
Chris@43 86 virtual void play(size_t startFrame);
Chris@43 87
Chris@43 88 /**
Chris@43 89 * Stop playback and ensure that no more data is returned.
Chris@43 90 */
Chris@43 91 virtual void stop();
Chris@43 92
Chris@43 93 /**
Chris@43 94 * Return whether playback is currently supposed to be happening.
Chris@43 95 */
Chris@43 96 virtual bool isPlaying() const { return m_playing; }
Chris@43 97
Chris@43 98 /**
Chris@43 99 * Return the frame number that is currently expected to be coming
Chris@43 100 * out of the speakers. (i.e. compensating for playback latency.)
Chris@43 101 */
Chris@43 102 virtual size_t getCurrentPlayingFrame();
Chris@93 103
Chris@93 104 /**
Chris@93 105 * Return the last frame that would come out of the speakers if we
Chris@93 106 * stopped playback right now.
Chris@93 107 */
Chris@93 108 virtual size_t getCurrentBufferedFrame();
Chris@43 109
Chris@43 110 /**
Chris@43 111 * Return the frame at which playback is expected to end (if not looping).
Chris@43 112 */
Chris@43 113 virtual size_t getPlayEndFrame() { return m_lastModelEndFrame; }
Chris@43 114
Chris@43 115 /**
Chris@91 116 * Set the target and the block size of the target audio device.
Chris@91 117 * This should be called by the target class.
Chris@43 118 */
Chris@91 119 void setTarget(AudioCallbackPlayTarget *, size_t blockSize);
Chris@43 120
Chris@43 121 /**
Chris@91 122 * Get the block size of the target audio device. This may be an
Chris@91 123 * estimate or upper bound, if the target has a variable block
Chris@91 124 * size; the source should behave itself even if this value turns
Chris@91 125 * out to be inaccurate.
Chris@43 126 */
Chris@43 127 size_t getTargetBlockSize() const;
Chris@43 128
Chris@43 129 /**
Chris@43 130 * Set the playback latency of the target audio device, in frames
Chris@43 131 * at the target sample rate. This is the difference between the
Chris@43 132 * frame currently "leaving the speakers" and the last frame (or
Chris@43 133 * highest last frame across all channels) requested via
Chris@43 134 * getSamples(). The default is zero.
Chris@43 135 */
Chris@43 136 void setTargetPlayLatency(size_t);
Chris@43 137
Chris@43 138 /**
Chris@43 139 * Get the playback latency of the target audio device.
Chris@43 140 */
Chris@43 141 size_t getTargetPlayLatency() const;
Chris@43 142
Chris@43 143 /**
Chris@43 144 * Specify that the target audio device has a fixed sample rate
Chris@43 145 * (i.e. cannot accommodate arbitrary sample rates based on the
Chris@43 146 * source). If the target sets this to something other than the
Chris@43 147 * source sample rate, this class will resample automatically to
Chris@43 148 * fit.
Chris@43 149 */
Chris@43 150 void setTargetSampleRate(size_t);
Chris@43 151
Chris@43 152 /**
Chris@43 153 * Return the sample rate set by the target audio device (or the
Chris@43 154 * source sample rate if the target hasn't set one).
Chris@43 155 */
Chris@43 156 virtual size_t getTargetSampleRate() const;
Chris@43 157
Chris@43 158 /**
Chris@43 159 * Set the current output levels for metering (for call from the
Chris@43 160 * target)
Chris@43 161 */
Chris@43 162 void setOutputLevels(float left, float right);
Chris@43 163
Chris@43 164 /**
Chris@43 165 * Return the current (or thereabouts) output levels in the range
Chris@43 166 * 0.0 -> 1.0, for metering purposes.
Chris@43 167 */
Chris@43 168 virtual bool getOutputLevels(float &left, float &right);
Chris@43 169
Chris@43 170 /**
Chris@43 171 * Get the number of channels of audio that in the source models.
Chris@43 172 * This may safely be called from a realtime thread. Returns 0 if
Chris@43 173 * there is no source yet available.
Chris@43 174 */
Chris@43 175 size_t getSourceChannelCount() const;
Chris@43 176
Chris@43 177 /**
Chris@43 178 * Get the number of channels of audio that will be provided
Chris@43 179 * to the play target. This may be more than the source channel
Chris@43 180 * count: for example, a mono source will provide 2 channels
Chris@43 181 * after pan.
Chris@43 182 * This may safely be called from a realtime thread. Returns 0 if
Chris@43 183 * there is no source yet available.
Chris@43 184 */
Chris@43 185 size_t getTargetChannelCount() const;
Chris@43 186
Chris@43 187 /**
Chris@43 188 * Get the actual sample rate of the source material. This may
Chris@43 189 * safely be called from a realtime thread. Returns 0 if there is
Chris@43 190 * no source yet available.
Chris@43 191 */
Chris@43 192 virtual size_t getSourceSampleRate() const;
Chris@43 193
Chris@43 194 /**
Chris@43 195 * Get "count" samples (at the target sample rate) of the mixed
Chris@43 196 * audio data, in all channels. This may safely be called from a
Chris@43 197 * realtime thread.
Chris@43 198 */
Chris@43 199 size_t getSourceSamples(size_t count, float **buffer);
Chris@43 200
Chris@43 201 /**
Chris@91 202 * Set the time stretcher factor (i.e. playback speed).
Chris@43 203 */
Chris@91 204 void setTimeStretch(float factor);
Chris@43 205
Chris@43 206 /**
Chris@43 207 * Set the resampler quality, 0 - 2 where 0 is fastest and 2 is
Chris@43 208 * highest quality.
Chris@43 209 */
Chris@43 210 void setResampleQuality(int q);
Chris@43 211
Chris@43 212 /**
Chris@43 213 * Set a single real-time plugin as a processing effect for
Chris@43 214 * auditioning during playback.
Chris@43 215 *
Chris@43 216 * The plugin must have been initialised with
Chris@43 217 * getTargetChannelCount() channels and a getTargetBlockSize()
Chris@43 218 * sample frame processing block size.
Chris@43 219 *
Chris@43 220 * This playback source takes ownership of the plugin, which will
Chris@43 221 * be deleted at some point after the following call to
Chris@107 222 * setAuditioningEffect (depending on real-time constraints).
Chris@43 223 *
Chris@43 224 * Pass a null pointer to remove the current auditioning plugin,
Chris@43 225 * if any.
Chris@43 226 */
Chris@107 227 void setAuditioningEffect(Auditionable *plugin);
Chris@43 228
Chris@43 229 /**
Chris@43 230 * Specify that only the given set of models should be played.
Chris@43 231 */
Chris@43 232 void setSoloModelSet(std::set<Model *>s);
Chris@43 233
Chris@43 234 /**
Chris@43 235 * Specify that all models should be played as normal (if not
Chris@43 236 * muted).
Chris@43 237 */
Chris@43 238 void clearSoloModelSet();
Chris@43 239
Chris@57 240 QString getClientName() const { return m_clientName; }
Chris@57 241
Chris@43 242 signals:
Chris@43 243 void modelReplaced();
Chris@43 244
Chris@43 245 void playStatusChanged(bool isPlaying);
Chris@43 246
Chris@43 247 void sampleRateMismatch(size_t requested, size_t available, bool willResample);
Chris@43 248
Chris@43 249 void audioOverloadPluginDisabled();
Chris@43 250
Chris@43 251 public slots:
Chris@43 252 void audioProcessingOverload();
Chris@43 253
Chris@43 254 protected slots:
Chris@43 255 void selectionChanged();
Chris@43 256 void playLoopModeChanged();
Chris@43 257 void playSelectionModeChanged();
Chris@43 258 void playParametersChanged(PlayParameters *);
Chris@43 259 void preferenceChanged(PropertyContainer::PropertyName);
Chris@43 260 void modelChanged(size_t startFrame, size_t endFrame);
Chris@43 261
Chris@43 262 protected:
Chris@105 263 ViewManagerBase *m_viewManager;
Chris@57 264 AudioGenerator *m_audioGenerator;
Chris@57 265 QString m_clientName;
Chris@43 266
Chris@43 267 class RingBufferVector : public std::vector<RingBuffer<float> *> {
Chris@43 268 public:
Chris@43 269 virtual ~RingBufferVector() {
Chris@43 270 while (!empty()) {
Chris@43 271 delete *begin();
Chris@43 272 erase(begin());
Chris@43 273 }
Chris@43 274 }
Chris@43 275 };
Chris@43 276
Chris@43 277 std::set<Model *> m_models;
Chris@43 278 RingBufferVector *m_readBuffers;
Chris@43 279 RingBufferVector *m_writeBuffers;
Chris@43 280 size_t m_readBufferFill;
Chris@43 281 size_t m_writeBufferFill;
Chris@43 282 Scavenger<RingBufferVector> m_bufferScavenger;
Chris@43 283 size_t m_sourceChannelCount;
Chris@43 284 size_t m_blockSize;
Chris@43 285 size_t m_sourceSampleRate;
Chris@43 286 size_t m_targetSampleRate;
Chris@43 287 size_t m_playLatency;
Chris@91 288 AudioCallbackPlayTarget *m_target;
Chris@91 289 double m_lastRetrievalTimestamp;
Chris@91 290 size_t m_lastRetrievedBlockSize;
Chris@102 291 bool m_trustworthyTimestamps;
Chris@102 292 size_t m_lastCurrentFrame;
Chris@43 293 bool m_playing;
Chris@43 294 bool m_exiting;
Chris@43 295 size_t m_lastModelEndFrame;
Chris@43 296 static const size_t m_ringBufferSize;
Chris@43 297 float m_outputLeft;
Chris@43 298 float m_outputRight;
Chris@43 299 RealTimePluginInstance *m_auditioningPlugin;
Chris@43 300 bool m_auditioningPluginBypassed;
Chris@43 301 Scavenger<RealTimePluginInstance> m_pluginScavenger;
Chris@94 302 size_t m_playStartFrame;
Chris@94 303 bool m_playStartFramePassed;
Chris@94 304 RealTime m_playStartedAt;
Chris@43 305
Chris@43 306 RingBuffer<float> *getWriteRingBuffer(size_t c) {
Chris@43 307 if (m_writeBuffers && c < m_writeBuffers->size()) {
Chris@43 308 return (*m_writeBuffers)[c];
Chris@43 309 } else {
Chris@43 310 return 0;
Chris@43 311 }
Chris@43 312 }
Chris@43 313
Chris@43 314 RingBuffer<float> *getReadRingBuffer(size_t c) {
Chris@43 315 RingBufferVector *rb = m_readBuffers;
Chris@43 316 if (rb && c < rb->size()) {
Chris@43 317 return (*rb)[c];
Chris@43 318 } else {
Chris@43 319 return 0;
Chris@43 320 }
Chris@43 321 }
Chris@43 322
Chris@43 323 void clearRingBuffers(bool haveLock = false, size_t count = 0);
Chris@43 324 void unifyRingBuffers();
Chris@43 325
Chris@62 326 RubberBand::RubberBandStretcher *m_timeStretcher;
Chris@91 327 float m_stretchRatio;
Chris@91 328
Chris@91 329 size_t m_stretcherInputCount;
Chris@91 330 float **m_stretcherInputs;
Chris@91 331 size_t *m_stretcherInputSizes;
Chris@43 332
Chris@43 333 // Called from fill thread, m_playing true, mutex held
Chris@43 334 // Return true if work done
Chris@43 335 bool fillBuffers();
Chris@43 336
Chris@43 337 // Called from fillBuffers. Return the number of frames written,
Chris@43 338 // which will be count or fewer. Return in the frame argument the
Chris@43 339 // new buffered frame position (which may be earlier than the
Chris@43 340 // frame argument passed in, in the case of looping).
Chris@43 341 size_t mixModels(size_t &frame, size_t count, float **buffers);
Chris@43 342
Chris@43 343 // Called from getSourceSamples.
Chris@43 344 void applyAuditioningEffect(size_t count, float **buffers);
Chris@43 345
Chris@93 346 // Ranges of current selections, if play selection is active
Chris@93 347 std::vector<RealTime> m_rangeStarts;
Chris@93 348 std::vector<RealTime> m_rangeDurations;
Chris@93 349 void rebuildRangeLists();
Chris@93 350
Chris@93 351 size_t getCurrentFrame(RealTime outputLatency);
Chris@93 352
Chris@43 353 class FillThread : public Thread
Chris@43 354 {
Chris@43 355 public:
Chris@43 356 FillThread(AudioCallbackPlaySource &source) :
Chris@43 357 Thread(Thread::NonRTThread),
Chris@43 358 m_source(source) { }
Chris@43 359
Chris@43 360 virtual void run();
Chris@43 361
Chris@43 362 protected:
Chris@43 363 AudioCallbackPlaySource &m_source;
Chris@43 364 };
Chris@43 365
Chris@43 366 QMutex m_mutex;
Chris@43 367 QWaitCondition m_condition;
Chris@43 368 FillThread *m_fillThread;
Chris@43 369 SRC_STATE *m_converter;
Chris@43 370 SRC_STATE *m_crapConverter; // for use when playing very fast
Chris@43 371 int m_resampleQuality;
Chris@43 372 void initialiseConverter();
Chris@43 373 };
Chris@43 374
Chris@43 375 #endif
Chris@43 376
Chris@43 377