annotate audioio/AudioCallbackPlaySource.h @ 403:eb84b06301da

Restore the old prev/next layer commands (that were never enabled because they didn't work) using the new fixed order layer list (so they now do work)
author Chris Cannam
date Tue, 02 Sep 2014 16:06:41 +0100
parents 1e4fa2007e61
children dee4aceb131c
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@238 54 class AudioCallbackPlaySource : public 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@366 86 virtual void play(int 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@366 102 virtual int 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@366 108 virtual int 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@366 113 virtual int 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@366 119 void setTarget(AudioCallbackPlayTarget *, int 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@366 127 int 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@366 136 void setTargetPlayLatency(int);
Chris@43 137
Chris@43 138 /**
Chris@43 139 * Get the playback latency of the target audio device.
Chris@43 140 */
Chris@366 141 int 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@366 150 void setTargetSampleRate(int);
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@366 156 virtual int 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@366 175 int 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@366 185 int 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@366 192 virtual int 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@366 199 int getSourceSamples(int 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@366 247 void sampleRateMismatch(int requested, int 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@367 263 void modelChangedWithin(int startFrame, int 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@366 283 int m_readBufferFill;
Chris@366 284 int m_writeBufferFill;
Chris@43 285 Scavenger<RingBufferVector> m_bufferScavenger;
Chris@366 286 int m_sourceChannelCount;
Chris@366 287 int m_blockSize;
Chris@366 288 int m_sourceSampleRate;
Chris@366 289 int m_targetSampleRate;
Chris@366 290 int m_playLatency;
Chris@91 291 AudioCallbackPlayTarget *m_target;
Chris@91 292 double m_lastRetrievalTimestamp;
Chris@366 293 int m_lastRetrievedBlockSize;
Chris@102 294 bool m_trustworthyTimestamps;
Chris@366 295 int m_lastCurrentFrame;
Chris@43 296 bool m_playing;
Chris@43 297 bool m_exiting;
Chris@366 298 int m_lastModelEndFrame;
Chris@366 299 int 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@366 305 int m_playStartFrame;
Chris@94 306 bool m_playStartFramePassed;
Chris@94 307 RealTime m_playStartedAt;
Chris@43 308
Chris@366 309 RingBuffer<float> *getWriteRingBuffer(int c) {
Chris@366 310 if (m_writeBuffers && c < (int)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@366 317 RingBuffer<float> *getReadRingBuffer(int c) {
Chris@43 318 RingBufferVector *rb = m_readBuffers;
Chris@366 319 if (rb && c < (int)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@366 326 void clearRingBuffers(bool haveLock = false, int 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@366 334 int m_stretcherInputCount;
Chris@91 335 float **m_stretcherInputs;
Chris@366 336 int *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@366 346 int mixModels(int &frame, int count, float **buffers);
Chris@43 347
Chris@43 348 // Called from getSourceSamples.
Chris@366 349 void applyAuditioningEffect(int 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@366 356 int 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