annotate audio/AudioCallbackPlaySource.h @ 588:d122d3595a32

Store aggregate models in the document and release them when they are invalidated (because their components have been released). They're no longer leaked, but we still don't save them in the session file.
author Chris Cannam
date Mon, 27 Feb 2017 16:26:37 +0000
parents 298d864113f0
children b23bebfdfaba
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@574 16 #ifndef SV_AUDIO_CALLBACK_PLAY_SOURCE_H
Chris@574 17 #define SV_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@468 24 #include <bqaudioio/ApplicationPlaybackSource.h>
Chris@468 25
Chris@43 26 #include <QObject>
Chris@43 27 #include <QMutex>
Chris@43 28 #include <QWaitCondition>
Chris@43 29
Chris@43 30 #include "base/Thread.h"
Chris@93 31 #include "base/RealTime.h"
Chris@43 32
Chris@43 33 #include <samplerate.h>
Chris@43 34
Chris@43 35 #include <set>
Chris@43 36 #include <map>
Chris@43 37
Chris@91 38 namespace RubberBand {
Chris@91 39 class RubberBandStretcher;
Chris@91 40 }
Chris@62 41
Chris@544 42 namespace breakfastquay {
Chris@551 43 class ResamplerWrapper;
Chris@544 44 }
Chris@544 45
Chris@43 46 class Model;
Chris@105 47 class ViewManagerBase;
Chris@43 48 class AudioGenerator;
Chris@43 49 class PlayParameters;
Chris@43 50 class RealTimePluginInstance;
Chris@91 51 class AudioCallbackPlayTarget;
Chris@43 52
Chris@43 53 /**
Chris@43 54 * AudioCallbackPlaySource manages audio data supply to callback-based
Chris@43 55 * audio APIs such as JACK or CoreAudio. It maintains one ring buffer
Chris@43 56 * per channel, filled during playback by a non-realtime thread, and
Chris@43 57 * provides a method for a realtime thread to pick up the latest
Chris@43 58 * available sample data from these buffers.
Chris@43 59 */
Chris@238 60 class AudioCallbackPlaySource : public QObject,
Chris@468 61 public AudioPlaySource,
Chris@468 62 public breakfastquay::ApplicationPlaybackSource
Chris@43 63 {
Chris@43 64 Q_OBJECT
Chris@43 65
Chris@43 66 public:
Chris@105 67 AudioCallbackPlaySource(ViewManagerBase *, QString clientName);
Chris@43 68 virtual ~AudioCallbackPlaySource();
Chris@43 69
Chris@43 70 /**
Chris@43 71 * Add a data model to be played from. The source can mix
Chris@43 72 * playback from a number of sources including dense and sparse
Chris@43 73 * models. The models must match in sample rate, but they don't
Chris@43 74 * have to have identical numbers of channels.
Chris@43 75 */
Chris@43 76 virtual void addModel(Model *model);
Chris@43 77
Chris@43 78 /**
Chris@43 79 * Remove a model.
Chris@43 80 */
Chris@43 81 virtual void removeModel(Model *model);
Chris@43 82
Chris@43 83 /**
Chris@43 84 * Remove all models. (Silence will ensue.)
Chris@43 85 */
Chris@43 86 virtual void clearModels();
Chris@43 87
Chris@43 88 /**
Chris@43 89 * Start making data available in the ring buffers for playback,
Chris@43 90 * from the given frame. If playback is already under way, reseek
Chris@43 91 * to the given frame and continue.
Chris@43 92 */
Chris@559 93 virtual void play(sv_frame_t startFrame) override;
Chris@43 94
Chris@43 95 /**
Chris@43 96 * Stop playback and ensure that no more data is returned.
Chris@43 97 */
Chris@559 98 virtual void stop() override;
Chris@43 99
Chris@43 100 /**
Chris@43 101 * Return whether playback is currently supposed to be happening.
Chris@43 102 */
Chris@559 103 virtual bool isPlaying() const override { return m_playing; }
Chris@43 104
Chris@43 105 /**
Chris@43 106 * Return the frame number that is currently expected to be coming
Chris@43 107 * out of the speakers. (i.e. compensating for playback latency.)
Chris@43 108 */
Chris@559 109 virtual sv_frame_t getCurrentPlayingFrame() override;
Chris@93 110
Chris@93 111 /**
Chris@93 112 * Return the last frame that would come out of the speakers if we
Chris@93 113 * stopped playback right now.
Chris@93 114 */
Chris@434 115 virtual sv_frame_t getCurrentBufferedFrame();
Chris@43 116
Chris@43 117 /**
Chris@43 118 * Return the frame at which playback is expected to end (if not looping).
Chris@43 119 */
Chris@434 120 virtual sv_frame_t getPlayEndFrame() { return m_lastModelEndFrame; }
Chris@43 121
Chris@43 122 /**
Chris@498 123 * Set the playback target.
Chris@43 124 */
Chris@468 125 virtual void setSystemPlaybackTarget(breakfastquay::SystemPlaybackTarget *);
Chris@468 126
Chris@468 127 /**
Chris@551 128 * Set the resampler wrapper, if one is in use.
Chris@551 129 */
Chris@551 130 virtual void setResamplerWrapper(breakfastquay::ResamplerWrapper *);
Chris@551 131
Chris@551 132 /**
Chris@468 133 * Set the block size of the target audio device. This should be
Chris@468 134 * called by the target class.
Chris@468 135 */
Chris@559 136 virtual void setSystemPlaybackBlockSize(int blockSize) override;
Chris@43 137
Chris@43 138 /**
Chris@91 139 * Get the block size of the target audio device. This may be an
Chris@91 140 * estimate or upper bound, if the target has a variable block
Chris@91 141 * size; the source should behave itself even if this value turns
Chris@91 142 * out to be inaccurate.
Chris@43 143 */
cannam@561 144 virtual int getTargetBlockSize() const override;
Chris@43 145
Chris@43 146 /**
Chris@43 147 * Set the playback latency of the target audio device, in frames
Chris@553 148 * at the device sample rate. This is the difference between the
Chris@43 149 * frame currently "leaving the speakers" and the last frame (or
Chris@43 150 * highest last frame across all channels) requested via
Chris@43 151 * getSamples(). The default is zero.
Chris@43 152 */
Chris@559 153 virtual void setSystemPlaybackLatency(int) override;
Chris@43 154
Chris@43 155 /**
Chris@43 156 * Get the playback latency of the target audio device.
Chris@43 157 */
Chris@434 158 sv_frame_t getTargetPlayLatency() const;
Chris@43 159
Chris@43 160 /**
Chris@43 161 * Specify that the target audio device has a fixed sample rate
Chris@43 162 * (i.e. cannot accommodate arbitrary sample rates based on the
Chris@43 163 * source). If the target sets this to something other than the
Chris@43 164 * source sample rate, this class will resample automatically to
Chris@43 165 * fit.
Chris@43 166 */
Chris@559 167 virtual void setSystemPlaybackSampleRate(int) override;
Chris@43 168
Chris@43 169 /**
Chris@43 170 * Return the sample rate set by the target audio device (or the
Chris@43 171 * source sample rate if the target hasn't set one).
Chris@43 172 */
cannam@561 173 virtual sv_samplerate_t getDeviceSampleRate() const override;
Chris@43 174
Chris@43 175 /**
Chris@546 176 * Indicate how many channels the target audio device was opened
Chris@546 177 * with. Note that the target device does channel mixing in the
Chris@559 178 * case where our requested channel count does not match its, so
Chris@559 179 * long as we provide the number of channels we specified when the
Chris@559 180 * target was started in getApplicationChannelCount().
Chris@546 181 */
Chris@559 182 virtual void setSystemPlaybackChannelCount(int) override;
Chris@546 183
Chris@546 184 /**
Chris@43 185 * Set the current output levels for metering (for call from the
Chris@43 186 * target)
Chris@43 187 */
cannam@561 188 virtual void setOutputLevels(float left, float right) override;
Chris@43 189
Chris@43 190 /**
Chris@580 191 * Return the current output levels in the range 0.0 -> 1.0, for
Chris@580 192 * metering purposes. The values returned are the peak values
Chris@580 193 * since the last time this function was called (after which they
Chris@580 194 * are reset to zero until setOutputLevels is called again by the
Chris@580 195 * driver).
Chris@580 196 *
Chris@580 197 * Return true if the values have been set since this function was
Chris@580 198 * last called (i.e. if they are meaningful). Return false if they
Chris@580 199 * have not been set (in which case both will be zero).
Chris@43 200 */
cannam@561 201 virtual bool getOutputLevels(float &left, float &right) override;
Chris@43 202
Chris@43 203 /**
Chris@43 204 * Get the number of channels of audio that in the source models.
Chris@43 205 * This may safely be called from a realtime thread. Returns 0 if
Chris@43 206 * there is no source yet available.
Chris@43 207 */
Chris@366 208 int getSourceChannelCount() const;
Chris@43 209
Chris@43 210 /**
Chris@43 211 * Get the number of channels of audio that will be provided
Chris@43 212 * to the play target. This may be more than the source channel
Chris@43 213 * count: for example, a mono source will provide 2 channels
Chris@43 214 * after pan.
Chris@552 215 *
Chris@43 216 * This may safely be called from a realtime thread. Returns 0 if
Chris@43 217 * there is no source yet available.
Chris@552 218 *
Chris@552 219 * override from AudioPlaySource
Chris@43 220 */
Chris@552 221 virtual int getTargetChannelCount() const override;
Chris@43 222
Chris@43 223 /**
Chris@559 224 * Get the number of channels of audio the device is
Chris@559 225 * expecting. Equal to whatever getTargetChannelCount() was
Chris@559 226 * returning at the time the device was initialised.
Chris@559 227 */
Chris@559 228 int getDeviceChannelCount() const;
Chris@559 229
Chris@559 230 /**
Chris@468 231 * ApplicationPlaybackSource equivalent of the above.
Chris@552 232 *
Chris@552 233 * override from breakfastquay::ApplicationPlaybackSource
Chris@468 234 */
Chris@552 235 virtual int getApplicationChannelCount() const override {
Chris@468 236 return getTargetChannelCount();
Chris@468 237 }
Chris@468 238
Chris@468 239 /**
Chris@552 240 * Get the actual sample rate of the source material (the main
Chris@552 241 * model). This may safely be called from a realtime thread.
Chris@552 242 * Returns 0 if there is no source yet available.
Chris@552 243 *
Chris@552 244 * When this changes, the AudioCallbackPlaySource notifies its
Chris@552 245 * ResamplerWrapper of the new sample rate so that it can resample
Chris@552 246 * correctly on the way to the device (which is opened at a fixed
Chris@552 247 * rate, see getApplicationSampleRate).
Chris@43 248 */
Chris@552 249 virtual sv_samplerate_t getSourceSampleRate() const override;
Chris@43 250
Chris@43 251 /**
Chris@552 252 * ApplicationPlaybackSource interface method: get the sample rate
Chris@552 253 * at which the application wants the device to be opened. We
Chris@552 254 * always allow the device to open at its default rate, and then
Chris@552 255 * we resample if the audio is at a different rate. This avoids
Chris@552 256 * having to close and re-open the device to obtain consistent
Chris@552 257 * behaviour for consecutive sessions with different source rates.
Chris@468 258 */
Chris@552 259 virtual int getApplicationSampleRate() const override {
Chris@552 260 return 0;
Chris@468 261 }
Chris@468 262
Chris@468 263 /**
Chris@43 264 * Get "count" samples (at the target sample rate) of the mixed
Chris@43 265 * audio data, in all channels. This may safely be called from a
Chris@43 266 * realtime thread.
Chris@43 267 */
Chris@559 268 virtual int getSourceSamples(float *const *buffer, int nchannels, int count) override;
Chris@43 269
Chris@43 270 /**
Chris@91 271 * Set the time stretcher factor (i.e. playback speed).
Chris@43 272 */
Chris@436 273 void setTimeStretch(double factor);
Chris@43 274
Chris@43 275 /**
Chris@43 276 * Set a single real-time plugin as a processing effect for
Chris@43 277 * auditioning during playback.
Chris@43 278 *
Chris@43 279 * The plugin must have been initialised with
Chris@43 280 * getTargetChannelCount() channels and a getTargetBlockSize()
Chris@43 281 * sample frame processing block size.
Chris@43 282 *
Chris@43 283 * This playback source takes ownership of the plugin, which will
Chris@43 284 * be deleted at some point after the following call to
Chris@107 285 * setAuditioningEffect (depending on real-time constraints).
Chris@43 286 *
Chris@43 287 * Pass a null pointer to remove the current auditioning plugin,
Chris@43 288 * if any.
Chris@43 289 */
cannam@561 290 virtual void setAuditioningEffect(Auditionable *plugin) override;
Chris@43 291
Chris@43 292 /**
Chris@43 293 * Specify that only the given set of models should be played.
Chris@43 294 */
Chris@43 295 void setSoloModelSet(std::set<Model *>s);
Chris@43 296
Chris@43 297 /**
Chris@43 298 * Specify that all models should be played as normal (if not
Chris@43 299 * muted).
Chris@43 300 */
Chris@43 301 void clearSoloModelSet();
Chris@43 302
cannam@561 303 virtual std::string getClientName() const override {
cannam@561 304 return m_clientName;
cannam@561 305 }
Chris@57 306
Chris@43 307 signals:
Chris@43 308 void playStatusChanged(bool isPlaying);
Chris@43 309
Chris@436 310 void sampleRateMismatch(sv_samplerate_t requested,
Chris@436 311 sv_samplerate_t available,
Chris@436 312 bool willResample);
Chris@43 313
Chris@570 314 void channelCountIncreased(int count); // target channel count (see getTargetChannelCount())
Chris@559 315
Chris@43 316 void audioOverloadPluginDisabled();
Chris@130 317 void audioTimeStretchMultiChannelDisabled();
Chris@43 318
Chris@158 319 void activity(QString);
Chris@158 320
Chris@43 321 public slots:
cannam@561 322 void audioProcessingOverload() override;
Chris@43 323
Chris@43 324 protected slots:
Chris@43 325 void selectionChanged();
Chris@43 326 void playLoopModeChanged();
Chris@43 327 void playSelectionModeChanged();
Chris@43 328 void playParametersChanged(PlayParameters *);
Chris@43 329 void preferenceChanged(PropertyContainer::PropertyName);
Chris@435 330 void modelChangedWithin(sv_frame_t startFrame, sv_frame_t endFrame);
Chris@43 331
Chris@43 332 protected:
Chris@105 333 ViewManagerBase *m_viewManager;
Chris@57 334 AudioGenerator *m_audioGenerator;
Chris@468 335 std::string m_clientName;
Chris@43 336
Chris@43 337 class RingBufferVector : public std::vector<RingBuffer<float> *> {
Chris@43 338 public:
Chris@43 339 virtual ~RingBufferVector() {
Chris@43 340 while (!empty()) {
Chris@43 341 delete *begin();
Chris@43 342 erase(begin());
Chris@43 343 }
Chris@43 344 }
Chris@43 345 };
Chris@43 346
Chris@43 347 std::set<Model *> m_models;
Chris@43 348 RingBufferVector *m_readBuffers;
Chris@43 349 RingBufferVector *m_writeBuffers;
Chris@436 350 sv_frame_t m_readBufferFill;
Chris@436 351 sv_frame_t m_writeBufferFill;
Chris@43 352 Scavenger<RingBufferVector> m_bufferScavenger;
Chris@366 353 int m_sourceChannelCount;
Chris@436 354 sv_frame_t m_blockSize;
Chris@434 355 sv_samplerate_t m_sourceSampleRate;
Chris@553 356 sv_samplerate_t m_deviceSampleRate;
Chris@559 357 int m_deviceChannelCount;
Chris@436 358 sv_frame_t m_playLatency;
Chris@468 359 breakfastquay::SystemPlaybackTarget *m_target;
Chris@91 360 double m_lastRetrievalTimestamp;
Chris@436 361 sv_frame_t m_lastRetrievedBlockSize;
Chris@102 362 bool m_trustworthyTimestamps;
Chris@434 363 sv_frame_t m_lastCurrentFrame;
Chris@43 364 bool m_playing;
Chris@43 365 bool m_exiting;
Chris@434 366 sv_frame_t m_lastModelEndFrame;
Chris@366 367 int m_ringBufferSize;
Chris@43 368 float m_outputLeft;
Chris@43 369 float m_outputRight;
Chris@580 370 bool m_levelsSet;
Chris@43 371 RealTimePluginInstance *m_auditioningPlugin;
Chris@43 372 bool m_auditioningPluginBypassed;
Chris@43 373 Scavenger<RealTimePluginInstance> m_pluginScavenger;
Chris@434 374 sv_frame_t m_playStartFrame;
Chris@94 375 bool m_playStartFramePassed;
Chris@94 376 RealTime m_playStartedAt;
Chris@43 377
Chris@366 378 RingBuffer<float> *getWriteRingBuffer(int c) {
Chris@366 379 if (m_writeBuffers && c < (int)m_writeBuffers->size()) {
Chris@43 380 return (*m_writeBuffers)[c];
Chris@43 381 } else {
Chris@43 382 return 0;
Chris@43 383 }
Chris@43 384 }
Chris@43 385
Chris@366 386 RingBuffer<float> *getReadRingBuffer(int c) {
Chris@43 387 RingBufferVector *rb = m_readBuffers;
Chris@366 388 if (rb && c < (int)rb->size()) {
Chris@43 389 return (*rb)[c];
Chris@43 390 } else {
Chris@43 391 return 0;
Chris@43 392 }
Chris@43 393 }
Chris@43 394
Chris@366 395 void clearRingBuffers(bool haveLock = false, int count = 0);
Chris@43 396 void unifyRingBuffers();
Chris@43 397
Chris@62 398 RubberBand::RubberBandStretcher *m_timeStretcher;
Chris@130 399 RubberBand::RubberBandStretcher *m_monoStretcher;
Chris@436 400 double m_stretchRatio;
Chris@130 401 bool m_stretchMono;
Chris@91 402
Chris@436 403 int m_stretcherInputCount;
Chris@91 404 float **m_stretcherInputs;
Chris@436 405 sv_frame_t *m_stretcherInputSizes;
Chris@43 406
Chris@43 407 // Called from fill thread, m_playing true, mutex held
Chris@43 408 // Return true if work done
Chris@43 409 bool fillBuffers();
Chris@43 410
Chris@43 411 // Called from fillBuffers. Return the number of frames written,
Chris@43 412 // which will be count or fewer. Return in the frame argument the
Chris@43 413 // new buffered frame position (which may be earlier than the
Chris@43 414 // frame argument passed in, in the case of looping).
Chris@434 415 sv_frame_t mixModels(sv_frame_t &frame, sv_frame_t count, float **buffers);
Chris@43 416
Chris@43 417 // Called from getSourceSamples.
Chris@559 418 void applyAuditioningEffect(sv_frame_t count, float *const *buffers);
Chris@43 419
Chris@93 420 // Ranges of current selections, if play selection is active
Chris@93 421 std::vector<RealTime> m_rangeStarts;
Chris@93 422 std::vector<RealTime> m_rangeDurations;
Chris@93 423 void rebuildRangeLists();
Chris@93 424
Chris@434 425 sv_frame_t getCurrentFrame(RealTime outputLatency);
Chris@93 426
Chris@43 427 class FillThread : public Thread
Chris@43 428 {
Chris@43 429 public:
Chris@43 430 FillThread(AudioCallbackPlaySource &source) :
Chris@43 431 Thread(Thread::NonRTThread),
Chris@43 432 m_source(source) { }
Chris@43 433
Chris@43 434 virtual void run();
Chris@43 435
Chris@43 436 protected:
Chris@43 437 AudioCallbackPlaySource &m_source;
Chris@43 438 };
Chris@43 439
Chris@43 440 QMutex m_mutex;
Chris@43 441 QWaitCondition m_condition;
Chris@43 442 FillThread *m_fillThread;
Chris@551 443 breakfastquay::ResamplerWrapper *m_resamplerWrapper; // I don't own this
Chris@43 444 };
Chris@43 445
Chris@43 446 #endif
Chris@43 447
Chris@43 448