annotate audio/AudioCallbackPlaySource.h @ 744:36772d79cf44 pitch-align

Move Align to new align directory
author Chris Cannam
date Fri, 03 Apr 2020 10:17:46 +0100
parents 497d80d3b9c4
children 48001ed9143b
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@737 374 bool m_auditioningPluginFailed;
Chris@43 375 Scavenger<RealTimePluginInstance> m_pluginScavenger;
Chris@434 376 sv_frame_t m_playStartFrame;
Chris@94 377 bool m_playStartFramePassed;
Chris@94 378 RealTime m_playStartedAt;
Chris@43 379
Chris@366 380 RingBuffer<float> *getWriteRingBuffer(int c) {
Chris@595 381 if (m_writeBuffers && c < (int)m_writeBuffers->size()) {
Chris@595 382 return (*m_writeBuffers)[c];
Chris@595 383 } else {
Chris@595 384 return 0;
Chris@595 385 }
Chris@43 386 }
Chris@43 387
Chris@366 388 RingBuffer<float> *getReadRingBuffer(int c) {
Chris@595 389 RingBufferVector *rb = m_readBuffers;
Chris@595 390 if (rb && c < (int)rb->size()) {
Chris@595 391 return (*rb)[c];
Chris@595 392 } else {
Chris@595 393 return 0;
Chris@595 394 }
Chris@43 395 }
Chris@43 396
Chris@366 397 void clearRingBuffers(bool haveLock = false, int count = 0);
Chris@43 398 void unifyRingBuffers();
Chris@43 399
Chris@62 400 RubberBand::RubberBandStretcher *m_timeStretcher;
Chris@130 401 RubberBand::RubberBandStretcher *m_monoStretcher;
Chris@436 402 double m_stretchRatio;
Chris@130 403 bool m_stretchMono;
Chris@91 404
Chris@436 405 int m_stretcherInputCount;
Chris@91 406 float **m_stretcherInputs;
Chris@436 407 sv_frame_t *m_stretcherInputSizes;
Chris@43 408
Chris@43 409 // Called from fill thread, m_playing true, mutex held
Chris@43 410 // Return true if work done
Chris@43 411 bool fillBuffers();
Chris@43 412
Chris@43 413 // Called from fillBuffers. Return the number of frames written,
Chris@43 414 // which will be count or fewer. Return in the frame argument the
Chris@43 415 // new buffered frame position (which may be earlier than the
Chris@43 416 // frame argument passed in, in the case of looping).
Chris@434 417 sv_frame_t mixModels(sv_frame_t &frame, sv_frame_t count, float **buffers);
Chris@43 418
Chris@43 419 // Called from getSourceSamples.
Chris@559 420 void applyAuditioningEffect(sv_frame_t count, float *const *buffers);
Chris@43 421
Chris@93 422 // Ranges of current selections, if play selection is active
Chris@93 423 std::vector<RealTime> m_rangeStarts;
Chris@93 424 std::vector<RealTime> m_rangeDurations;
Chris@93 425 void rebuildRangeLists();
Chris@93 426
Chris@434 427 sv_frame_t getCurrentFrame(RealTime outputLatency);
Chris@93 428
Chris@43 429 class FillThread : public Thread
Chris@43 430 {
Chris@43 431 public:
Chris@595 432 FillThread(AudioCallbackPlaySource &source) :
Chris@43 433 Thread(Thread::NonRTThread),
Chris@595 434 m_source(source) { }
Chris@43 435
Chris@634 436 void run() override;
Chris@43 437
Chris@43 438 protected:
Chris@595 439 AudioCallbackPlaySource &m_source;
Chris@43 440 };
Chris@43 441
Chris@43 442 QMutex m_mutex;
Chris@43 443 QWaitCondition m_condition;
Chris@43 444 FillThread *m_fillThread;
Chris@551 445 breakfastquay::ResamplerWrapper *m_resamplerWrapper; // I don't own this
Chris@43 446 };
Chris@43 447
Chris@43 448 #endif
Chris@43 449
Chris@43 450