annotate audioio/AudioCallbackPlaySource.h @ 180:84b2c1a4984a

* Offer the user a chance to answer our survey (only once, and only after several runs of the program, and only if the survey is known to be live on the website)
author Chris Cannam
date Thu, 27 Aug 2009 16:31:45 +0000
parents 72495c4cd315
children 0b3aa9b702bb
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@130 250 void audioTimeStretchMultiChannelDisabled();
Chris@43 251
Chris@158 252 void activity(QString);
Chris@158 253
Chris@43 254 public slots:
Chris@43 255 void audioProcessingOverload();
Chris@43 256
Chris@43 257 protected slots:
Chris@43 258 void selectionChanged();
Chris@43 259 void playLoopModeChanged();
Chris@43 260 void playSelectionModeChanged();
Chris@43 261 void playParametersChanged(PlayParameters *);
Chris@43 262 void preferenceChanged(PropertyContainer::PropertyName);
Chris@43 263 void modelChanged(size_t startFrame, size_t endFrame);
Chris@43 264
Chris@43 265 protected:
Chris@105 266 ViewManagerBase *m_viewManager;
Chris@57 267 AudioGenerator *m_audioGenerator;
Chris@57 268 QString m_clientName;
Chris@43 269
Chris@43 270 class RingBufferVector : public std::vector<RingBuffer<float> *> {
Chris@43 271 public:
Chris@43 272 virtual ~RingBufferVector() {
Chris@43 273 while (!empty()) {
Chris@43 274 delete *begin();
Chris@43 275 erase(begin());
Chris@43 276 }
Chris@43 277 }
Chris@43 278 };
Chris@43 279
Chris@43 280 std::set<Model *> m_models;
Chris@43 281 RingBufferVector *m_readBuffers;
Chris@43 282 RingBufferVector *m_writeBuffers;
Chris@43 283 size_t m_readBufferFill;
Chris@43 284 size_t m_writeBufferFill;
Chris@43 285 Scavenger<RingBufferVector> m_bufferScavenger;
Chris@43 286 size_t m_sourceChannelCount;
Chris@43 287 size_t m_blockSize;
Chris@43 288 size_t m_sourceSampleRate;
Chris@43 289 size_t m_targetSampleRate;
Chris@43 290 size_t m_playLatency;
Chris@91 291 AudioCallbackPlayTarget *m_target;
Chris@91 292 double m_lastRetrievalTimestamp;
Chris@91 293 size_t m_lastRetrievedBlockSize;
Chris@102 294 bool m_trustworthyTimestamps;
Chris@102 295 size_t m_lastCurrentFrame;
Chris@43 296 bool m_playing;
Chris@43 297 bool m_exiting;
Chris@43 298 size_t m_lastModelEndFrame;
Chris@43 299 static const size_t m_ringBufferSize;
Chris@43 300 float m_outputLeft;
Chris@43 301 float m_outputRight;
Chris@43 302 RealTimePluginInstance *m_auditioningPlugin;
Chris@43 303 bool m_auditioningPluginBypassed;
Chris@43 304 Scavenger<RealTimePluginInstance> m_pluginScavenger;
Chris@94 305 size_t m_playStartFrame;
Chris@94 306 bool m_playStartFramePassed;
Chris@94 307 RealTime m_playStartedAt;
Chris@43 308
Chris@43 309 RingBuffer<float> *getWriteRingBuffer(size_t c) {
Chris@43 310 if (m_writeBuffers && c < m_writeBuffers->size()) {
Chris@43 311 return (*m_writeBuffers)[c];
Chris@43 312 } else {
Chris@43 313 return 0;
Chris@43 314 }
Chris@43 315 }
Chris@43 316
Chris@43 317 RingBuffer<float> *getReadRingBuffer(size_t c) {
Chris@43 318 RingBufferVector *rb = m_readBuffers;
Chris@43 319 if (rb && c < rb->size()) {
Chris@43 320 return (*rb)[c];
Chris@43 321 } else {
Chris@43 322 return 0;
Chris@43 323 }
Chris@43 324 }
Chris@43 325
Chris@43 326 void clearRingBuffers(bool haveLock = false, size_t count = 0);
Chris@43 327 void unifyRingBuffers();
Chris@43 328
Chris@62 329 RubberBand::RubberBandStretcher *m_timeStretcher;
Chris@130 330 RubberBand::RubberBandStretcher *m_monoStretcher;
Chris@91 331 float m_stretchRatio;
Chris@130 332 bool m_stretchMono;
Chris@91 333
Chris@91 334 size_t m_stretcherInputCount;
Chris@91 335 float **m_stretcherInputs;
Chris@91 336 size_t *m_stretcherInputSizes;
Chris@43 337
Chris@43 338 // Called from fill thread, m_playing true, mutex held
Chris@43 339 // Return true if work done
Chris@43 340 bool fillBuffers();
Chris@43 341
Chris@43 342 // Called from fillBuffers. Return the number of frames written,
Chris@43 343 // which will be count or fewer. Return in the frame argument the
Chris@43 344 // new buffered frame position (which may be earlier than the
Chris@43 345 // frame argument passed in, in the case of looping).
Chris@43 346 size_t mixModels(size_t &frame, size_t count, float **buffers);
Chris@43 347
Chris@43 348 // Called from getSourceSamples.
Chris@43 349 void applyAuditioningEffect(size_t count, float **buffers);
Chris@43 350
Chris@93 351 // Ranges of current selections, if play selection is active
Chris@93 352 std::vector<RealTime> m_rangeStarts;
Chris@93 353 std::vector<RealTime> m_rangeDurations;
Chris@93 354 void rebuildRangeLists();
Chris@93 355
Chris@93 356 size_t getCurrentFrame(RealTime outputLatency);
Chris@93 357
Chris@43 358 class FillThread : public Thread
Chris@43 359 {
Chris@43 360 public:
Chris@43 361 FillThread(AudioCallbackPlaySource &source) :
Chris@43 362 Thread(Thread::NonRTThread),
Chris@43 363 m_source(source) { }
Chris@43 364
Chris@43 365 virtual void run();
Chris@43 366
Chris@43 367 protected:
Chris@43 368 AudioCallbackPlaySource &m_source;
Chris@43 369 };
Chris@43 370
Chris@43 371 QMutex m_mutex;
Chris@43 372 QWaitCondition m_condition;
Chris@43 373 FillThread *m_fillThread;
Chris@43 374 SRC_STATE *m_converter;
Chris@43 375 SRC_STATE *m_crapConverter; // for use when playing very fast
Chris@43 376 int m_resampleQuality;
Chris@43 377 void initialiseConverter();
Chris@43 378 };
Chris@43 379
Chris@43 380 #endif
Chris@43 381
Chris@43 382