annotate audio/AudioCallbackPlaySource.h @ 725:16f6737fa557 spectrogram-export

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