annotate audio/AudioCallbackPlaySource.h @ 496:4f1d280903ad tony-2.0-integration

Update analysis stuff when recording starts (and when model is added) rather than when it ends. Not continuing to update during recording though...
author Chris Cannam
date Mon, 12 Oct 2015 17:10:43 +0100
parents f93820d36cb0
children cd9dec2f47e8
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@475 16 #ifndef AUDIO_CALLBACK_PLAY_SOURCE_H
Chris@475 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@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@43 42 class Model;
Chris@105 43 class ViewManagerBase;
Chris@43 44 class AudioGenerator;
Chris@43 45 class PlayParameters;
Chris@43 46 class RealTimePluginInstance;
Chris@91 47 class AudioCallbackPlayTarget;
Chris@43 48
Chris@43 49 /**
Chris@43 50 * AudioCallbackPlaySource manages audio data supply to callback-based
Chris@43 51 * audio APIs such as JACK or CoreAudio. It maintains one ring buffer
Chris@43 52 * per channel, filled during playback by a non-realtime thread, and
Chris@43 53 * provides a method for a realtime thread to pick up the latest
Chris@43 54 * available sample data from these buffers.
Chris@43 55 */
Chris@238 56 class AudioCallbackPlaySource : public QObject,
Chris@468 57 public AudioPlaySource,
Chris@468 58 public breakfastquay::ApplicationPlaybackSource
Chris@43 59 {
Chris@43 60 Q_OBJECT
Chris@43 61
Chris@43 62 public:
Chris@105 63 AudioCallbackPlaySource(ViewManagerBase *, QString clientName);
Chris@43 64 virtual ~AudioCallbackPlaySource();
Chris@43 65
Chris@43 66 /**
Chris@43 67 * Add a data model to be played from. The source can mix
Chris@43 68 * playback from a number of sources including dense and sparse
Chris@43 69 * models. The models must match in sample rate, but they don't
Chris@43 70 * have to have identical numbers of channels.
Chris@43 71 */
Chris@43 72 virtual void addModel(Model *model);
Chris@43 73
Chris@43 74 /**
Chris@43 75 * Remove a model.
Chris@43 76 */
Chris@43 77 virtual void removeModel(Model *model);
Chris@43 78
Chris@43 79 /**
Chris@43 80 * Remove all models. (Silence will ensue.)
Chris@43 81 */
Chris@43 82 virtual void clearModels();
Chris@43 83
Chris@43 84 /**
Chris@43 85 * Start making data available in the ring buffers for playback,
Chris@43 86 * from the given frame. If playback is already under way, reseek
Chris@43 87 * to the given frame and continue.
Chris@43 88 */
Chris@434 89 virtual void play(sv_frame_t startFrame);
Chris@43 90
Chris@43 91 /**
Chris@43 92 * Stop playback and ensure that no more data is returned.
Chris@43 93 */
Chris@43 94 virtual void stop();
Chris@43 95
Chris@43 96 /**
Chris@43 97 * Return whether playback is currently supposed to be happening.
Chris@43 98 */
Chris@43 99 virtual bool isPlaying() const { return m_playing; }
Chris@43 100
Chris@43 101 /**
Chris@43 102 * Return the frame number that is currently expected to be coming
Chris@43 103 * out of the speakers. (i.e. compensating for playback latency.)
Chris@43 104 */
Chris@434 105 virtual sv_frame_t getCurrentPlayingFrame();
Chris@93 106
Chris@93 107 /**
Chris@93 108 * Return the last frame that would come out of the speakers if we
Chris@93 109 * stopped playback right now.
Chris@93 110 */
Chris@434 111 virtual sv_frame_t getCurrentBufferedFrame();
Chris@43 112
Chris@43 113 /**
Chris@43 114 * Return the frame at which playback is expected to end (if not looping).
Chris@43 115 */
Chris@434 116 virtual sv_frame_t getPlayEndFrame() { return m_lastModelEndFrame; }
Chris@43 117
Chris@43 118 /**
Chris@468 119 * Set the playback target. This should be called by the target
Chris@468 120 * class.
Chris@43 121 */
Chris@468 122 virtual void setSystemPlaybackTarget(breakfastquay::SystemPlaybackTarget *);
Chris@468 123
Chris@468 124 /**
Chris@468 125 * Set the block size of the target audio device. This should be
Chris@468 126 * called by the target class.
Chris@468 127 */
Chris@468 128 virtual void setSystemPlaybackBlockSize(int blockSize);
Chris@43 129
Chris@43 130 /**
Chris@91 131 * Get the block size of the target audio device. This may be an
Chris@91 132 * estimate or upper bound, if the target has a variable block
Chris@91 133 * size; the source should behave itself even if this value turns
Chris@91 134 * out to be inaccurate.
Chris@43 135 */
Chris@366 136 int getTargetBlockSize() const;
Chris@43 137
Chris@43 138 /**
Chris@43 139 * Set the playback latency of the target audio device, in frames
Chris@43 140 * at the target sample rate. This is the difference between the
Chris@43 141 * frame currently "leaving the speakers" and the last frame (or
Chris@43 142 * highest last frame across all channels) requested via
Chris@43 143 * getSamples(). The default is zero.
Chris@43 144 */
Chris@468 145 void setSystemPlaybackLatency(int);
Chris@43 146
Chris@43 147 /**
Chris@43 148 * Get the playback latency of the target audio device.
Chris@43 149 */
Chris@434 150 sv_frame_t getTargetPlayLatency() const;
Chris@43 151
Chris@43 152 /**
Chris@43 153 * Specify that the target audio device has a fixed sample rate
Chris@43 154 * (i.e. cannot accommodate arbitrary sample rates based on the
Chris@43 155 * source). If the target sets this to something other than the
Chris@43 156 * source sample rate, this class will resample automatically to
Chris@43 157 * fit.
Chris@43 158 */
Chris@468 159 void setSystemPlaybackSampleRate(int);
Chris@43 160
Chris@43 161 /**
Chris@43 162 * Return the sample rate set by the target audio device (or the
Chris@43 163 * source sample rate if the target hasn't set one).
Chris@43 164 */
Chris@434 165 virtual sv_samplerate_t getTargetSampleRate() const;
Chris@43 166
Chris@43 167 /**
Chris@43 168 * Set the current output levels for metering (for call from the
Chris@43 169 * target)
Chris@43 170 */
Chris@43 171 void setOutputLevels(float left, float right);
Chris@43 172
Chris@43 173 /**
Chris@43 174 * Return the current (or thereabouts) output levels in the range
Chris@43 175 * 0.0 -> 1.0, for metering purposes.
Chris@43 176 */
Chris@43 177 virtual bool getOutputLevels(float &left, float &right);
Chris@43 178
Chris@43 179 /**
Chris@43 180 * Get the number of channels of audio that in the source models.
Chris@43 181 * This may safely be called from a realtime thread. Returns 0 if
Chris@43 182 * there is no source yet available.
Chris@43 183 */
Chris@366 184 int getSourceChannelCount() const;
Chris@43 185
Chris@43 186 /**
Chris@43 187 * Get the number of channels of audio that will be provided
Chris@43 188 * to the play target. This may be more than the source channel
Chris@43 189 * count: for example, a mono source will provide 2 channels
Chris@43 190 * after pan.
Chris@43 191 * This may safely be called from a realtime thread. Returns 0 if
Chris@43 192 * there is no source yet available.
Chris@43 193 */
Chris@366 194 int getTargetChannelCount() const;
Chris@43 195
Chris@43 196 /**
Chris@468 197 * ApplicationPlaybackSource equivalent of the above.
Chris@468 198 */
Chris@468 199 virtual int getApplicationChannelCount() const {
Chris@468 200 return getTargetChannelCount();
Chris@468 201 }
Chris@468 202
Chris@468 203 /**
Chris@43 204 * Get the actual sample rate of the source material. This may
Chris@43 205 * safely be called from a realtime thread. Returns 0 if there is
Chris@43 206 * no source yet available.
Chris@43 207 */
Chris@434 208 virtual sv_samplerate_t getSourceSampleRate() const;
Chris@43 209
Chris@43 210 /**
Chris@468 211 * ApplicationPlaybackSource equivalent of the above.
Chris@468 212 */
Chris@468 213 virtual int getApplicationSampleRate() const {
Chris@468 214 return int(round(getSourceSampleRate()));
Chris@468 215 }
Chris@468 216
Chris@468 217 /**
Chris@43 218 * Get "count" samples (at the target sample rate) of the mixed
Chris@43 219 * audio data, in all channels. This may safely be called from a
Chris@43 220 * realtime thread.
Chris@43 221 */
Chris@473 222 virtual int getSourceSamples(int count, float **buffer);
Chris@43 223
Chris@43 224 /**
Chris@91 225 * Set the time stretcher factor (i.e. playback speed).
Chris@43 226 */
Chris@436 227 void setTimeStretch(double factor);
Chris@43 228
Chris@43 229 /**
Chris@43 230 * Set the resampler quality, 0 - 2 where 0 is fastest and 2 is
Chris@43 231 * highest quality.
Chris@43 232 */
Chris@43 233 void setResampleQuality(int q);
Chris@43 234
Chris@43 235 /**
Chris@43 236 * Set a single real-time plugin as a processing effect for
Chris@43 237 * auditioning during playback.
Chris@43 238 *
Chris@43 239 * The plugin must have been initialised with
Chris@43 240 * getTargetChannelCount() channels and a getTargetBlockSize()
Chris@43 241 * sample frame processing block size.
Chris@43 242 *
Chris@43 243 * This playback source takes ownership of the plugin, which will
Chris@43 244 * be deleted at some point after the following call to
Chris@107 245 * setAuditioningEffect (depending on real-time constraints).
Chris@43 246 *
Chris@43 247 * Pass a null pointer to remove the current auditioning plugin,
Chris@43 248 * if any.
Chris@43 249 */
Chris@107 250 void setAuditioningEffect(Auditionable *plugin);
Chris@43 251
Chris@43 252 /**
Chris@43 253 * Specify that only the given set of models should be played.
Chris@43 254 */
Chris@43 255 void setSoloModelSet(std::set<Model *>s);
Chris@43 256
Chris@43 257 /**
Chris@43 258 * Specify that all models should be played as normal (if not
Chris@43 259 * muted).
Chris@43 260 */
Chris@43 261 void clearSoloModelSet();
Chris@43 262
Chris@468 263 std::string getClientName() const { return m_clientName; }
Chris@57 264
Chris@43 265 signals:
Chris@43 266 void modelReplaced();
Chris@43 267
Chris@43 268 void playStatusChanged(bool isPlaying);
Chris@43 269
Chris@436 270 void sampleRateMismatch(sv_samplerate_t requested,
Chris@436 271 sv_samplerate_t available,
Chris@436 272 bool willResample);
Chris@43 273
Chris@43 274 void audioOverloadPluginDisabled();
Chris@130 275 void audioTimeStretchMultiChannelDisabled();
Chris@43 276
Chris@158 277 void activity(QString);
Chris@158 278
Chris@43 279 public slots:
Chris@43 280 void audioProcessingOverload();
Chris@43 281
Chris@43 282 protected slots:
Chris@43 283 void selectionChanged();
Chris@43 284 void playLoopModeChanged();
Chris@43 285 void playSelectionModeChanged();
Chris@43 286 void playParametersChanged(PlayParameters *);
Chris@43 287 void preferenceChanged(PropertyContainer::PropertyName);
Chris@435 288 void modelChangedWithin(sv_frame_t startFrame, sv_frame_t endFrame);
Chris@43 289
Chris@43 290 protected:
Chris@105 291 ViewManagerBase *m_viewManager;
Chris@57 292 AudioGenerator *m_audioGenerator;
Chris@468 293 std::string m_clientName;
Chris@43 294
Chris@43 295 class RingBufferVector : public std::vector<RingBuffer<float> *> {
Chris@43 296 public:
Chris@43 297 virtual ~RingBufferVector() {
Chris@43 298 while (!empty()) {
Chris@43 299 delete *begin();
Chris@43 300 erase(begin());
Chris@43 301 }
Chris@43 302 }
Chris@43 303 };
Chris@43 304
Chris@43 305 std::set<Model *> m_models;
Chris@43 306 RingBufferVector *m_readBuffers;
Chris@43 307 RingBufferVector *m_writeBuffers;
Chris@436 308 sv_frame_t m_readBufferFill;
Chris@436 309 sv_frame_t m_writeBufferFill;
Chris@43 310 Scavenger<RingBufferVector> m_bufferScavenger;
Chris@366 311 int m_sourceChannelCount;
Chris@436 312 sv_frame_t m_blockSize;
Chris@434 313 sv_samplerate_t m_sourceSampleRate;
Chris@434 314 sv_samplerate_t m_targetSampleRate;
Chris@436 315 sv_frame_t m_playLatency;
Chris@468 316 breakfastquay::SystemPlaybackTarget *m_target;
Chris@91 317 double m_lastRetrievalTimestamp;
Chris@436 318 sv_frame_t m_lastRetrievedBlockSize;
Chris@102 319 bool m_trustworthyTimestamps;
Chris@434 320 sv_frame_t m_lastCurrentFrame;
Chris@43 321 bool m_playing;
Chris@43 322 bool m_exiting;
Chris@434 323 sv_frame_t m_lastModelEndFrame;
Chris@366 324 int m_ringBufferSize;
Chris@43 325 float m_outputLeft;
Chris@43 326 float m_outputRight;
Chris@43 327 RealTimePluginInstance *m_auditioningPlugin;
Chris@43 328 bool m_auditioningPluginBypassed;
Chris@43 329 Scavenger<RealTimePluginInstance> m_pluginScavenger;
Chris@434 330 sv_frame_t m_playStartFrame;
Chris@94 331 bool m_playStartFramePassed;
Chris@94 332 RealTime m_playStartedAt;
Chris@43 333
Chris@366 334 RingBuffer<float> *getWriteRingBuffer(int c) {
Chris@366 335 if (m_writeBuffers && c < (int)m_writeBuffers->size()) {
Chris@43 336 return (*m_writeBuffers)[c];
Chris@43 337 } else {
Chris@43 338 return 0;
Chris@43 339 }
Chris@43 340 }
Chris@43 341
Chris@366 342 RingBuffer<float> *getReadRingBuffer(int c) {
Chris@43 343 RingBufferVector *rb = m_readBuffers;
Chris@366 344 if (rb && c < (int)rb->size()) {
Chris@43 345 return (*rb)[c];
Chris@43 346 } else {
Chris@43 347 return 0;
Chris@43 348 }
Chris@43 349 }
Chris@43 350
Chris@366 351 void clearRingBuffers(bool haveLock = false, int count = 0);
Chris@43 352 void unifyRingBuffers();
Chris@43 353
Chris@62 354 RubberBand::RubberBandStretcher *m_timeStretcher;
Chris@130 355 RubberBand::RubberBandStretcher *m_monoStretcher;
Chris@436 356 double m_stretchRatio;
Chris@130 357 bool m_stretchMono;
Chris@91 358
Chris@436 359 int m_stretcherInputCount;
Chris@91 360 float **m_stretcherInputs;
Chris@436 361 sv_frame_t *m_stretcherInputSizes;
Chris@43 362
Chris@43 363 // Called from fill thread, m_playing true, mutex held
Chris@43 364 // Return true if work done
Chris@43 365 bool fillBuffers();
Chris@43 366
Chris@43 367 // Called from fillBuffers. Return the number of frames written,
Chris@43 368 // which will be count or fewer. Return in the frame argument the
Chris@43 369 // new buffered frame position (which may be earlier than the
Chris@43 370 // frame argument passed in, in the case of looping).
Chris@434 371 sv_frame_t mixModels(sv_frame_t &frame, sv_frame_t count, float **buffers);
Chris@43 372
Chris@43 373 // Called from getSourceSamples.
Chris@434 374 void applyAuditioningEffect(sv_frame_t count, float **buffers);
Chris@43 375
Chris@93 376 // Ranges of current selections, if play selection is active
Chris@93 377 std::vector<RealTime> m_rangeStarts;
Chris@93 378 std::vector<RealTime> m_rangeDurations;
Chris@93 379 void rebuildRangeLists();
Chris@93 380
Chris@434 381 sv_frame_t getCurrentFrame(RealTime outputLatency);
Chris@93 382
Chris@43 383 class FillThread : public Thread
Chris@43 384 {
Chris@43 385 public:
Chris@43 386 FillThread(AudioCallbackPlaySource &source) :
Chris@43 387 Thread(Thread::NonRTThread),
Chris@43 388 m_source(source) { }
Chris@43 389
Chris@43 390 virtual void run();
Chris@43 391
Chris@43 392 protected:
Chris@43 393 AudioCallbackPlaySource &m_source;
Chris@43 394 };
Chris@43 395
Chris@43 396 QMutex m_mutex;
Chris@43 397 QWaitCondition m_condition;
Chris@43 398 FillThread *m_fillThread;
Chris@43 399 SRC_STATE *m_converter;
Chris@43 400 SRC_STATE *m_crapConverter; // for use when playing very fast
Chris@43 401 int m_resampleQuality;
Chris@43 402 void initialiseConverter();
Chris@43 403 };
Chris@43 404
Chris@43 405 #endif
Chris@43 406
Chris@43 407