annotate audioio/AudioCallbackPlaySource.h @ 140:9ccaa8fd9b9f

* Add code to identify (usually) the type of an XML file that contains either SV session or layer data, and use it to permit loading files with plain .xml extension that contain complete uncompression sessions
author Chris Cannam
date Thu, 20 Nov 2008 10:59:14 +0000
parents 4c9c04645685
children 72495c4cd315
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@43 54 class AudioCallbackPlaySource : public virtual 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@43 86 virtual void play(size_t 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@43 102 virtual size_t 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@93 108 virtual size_t 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@43 113 virtual size_t 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@91 119 void setTarget(AudioCallbackPlayTarget *, size_t 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@43 127 size_t 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@43 136 void setTargetPlayLatency(size_t);
Chris@43 137
Chris@43 138 /**
Chris@43 139 * Get the playback latency of the target audio device.
Chris@43 140 */
Chris@43 141 size_t 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@43 150 void setTargetSampleRate(size_t);
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@43 156 virtual size_t 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@43 175 size_t 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@43 185 size_t 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@43 192 virtual size_t 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@43 199 size_t getSourceSamples(size_t 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@43 247 void sampleRateMismatch(size_t requested, size_t available, bool willResample);
Chris@43 248
Chris@43 249 void audioOverloadPluginDisabled();
Chris@130 250 void audioTimeStretchMultiChannelDisabled();
Chris@43 251
Chris@43 252 public slots:
Chris@43 253 void audioProcessingOverload();
Chris@43 254
Chris@43 255 protected slots:
Chris@43 256 void selectionChanged();
Chris@43 257 void playLoopModeChanged();
Chris@43 258 void playSelectionModeChanged();
Chris@43 259 void playParametersChanged(PlayParameters *);
Chris@43 260 void preferenceChanged(PropertyContainer::PropertyName);
Chris@43 261 void modelChanged(size_t startFrame, size_t endFrame);
Chris@43 262
Chris@43 263 protected:
Chris@105 264 ViewManagerBase *m_viewManager;
Chris@57 265 AudioGenerator *m_audioGenerator;
Chris@57 266 QString m_clientName;
Chris@43 267
Chris@43 268 class RingBufferVector : public std::vector<RingBuffer<float> *> {
Chris@43 269 public:
Chris@43 270 virtual ~RingBufferVector() {
Chris@43 271 while (!empty()) {
Chris@43 272 delete *begin();
Chris@43 273 erase(begin());
Chris@43 274 }
Chris@43 275 }
Chris@43 276 };
Chris@43 277
Chris@43 278 std::set<Model *> m_models;
Chris@43 279 RingBufferVector *m_readBuffers;
Chris@43 280 RingBufferVector *m_writeBuffers;
Chris@43 281 size_t m_readBufferFill;
Chris@43 282 size_t m_writeBufferFill;
Chris@43 283 Scavenger<RingBufferVector> m_bufferScavenger;
Chris@43 284 size_t m_sourceChannelCount;
Chris@43 285 size_t m_blockSize;
Chris@43 286 size_t m_sourceSampleRate;
Chris@43 287 size_t m_targetSampleRate;
Chris@43 288 size_t m_playLatency;
Chris@91 289 AudioCallbackPlayTarget *m_target;
Chris@91 290 double m_lastRetrievalTimestamp;
Chris@91 291 size_t m_lastRetrievedBlockSize;
Chris@102 292 bool m_trustworthyTimestamps;
Chris@102 293 size_t m_lastCurrentFrame;
Chris@43 294 bool m_playing;
Chris@43 295 bool m_exiting;
Chris@43 296 size_t m_lastModelEndFrame;
Chris@43 297 static const size_t m_ringBufferSize;
Chris@43 298 float m_outputLeft;
Chris@43 299 float m_outputRight;
Chris@43 300 RealTimePluginInstance *m_auditioningPlugin;
Chris@43 301 bool m_auditioningPluginBypassed;
Chris@43 302 Scavenger<RealTimePluginInstance> m_pluginScavenger;
Chris@94 303 size_t m_playStartFrame;
Chris@94 304 bool m_playStartFramePassed;
Chris@94 305 RealTime m_playStartedAt;
Chris@43 306
Chris@43 307 RingBuffer<float> *getWriteRingBuffer(size_t c) {
Chris@43 308 if (m_writeBuffers && c < m_writeBuffers->size()) {
Chris@43 309 return (*m_writeBuffers)[c];
Chris@43 310 } else {
Chris@43 311 return 0;
Chris@43 312 }
Chris@43 313 }
Chris@43 314
Chris@43 315 RingBuffer<float> *getReadRingBuffer(size_t c) {
Chris@43 316 RingBufferVector *rb = m_readBuffers;
Chris@43 317 if (rb && c < rb->size()) {
Chris@43 318 return (*rb)[c];
Chris@43 319 } else {
Chris@43 320 return 0;
Chris@43 321 }
Chris@43 322 }
Chris@43 323
Chris@43 324 void clearRingBuffers(bool haveLock = false, size_t count = 0);
Chris@43 325 void unifyRingBuffers();
Chris@43 326
Chris@62 327 RubberBand::RubberBandStretcher *m_timeStretcher;
Chris@130 328 RubberBand::RubberBandStretcher *m_monoStretcher;
Chris@91 329 float m_stretchRatio;
Chris@130 330 bool m_stretchMono;
Chris@91 331
Chris@91 332 size_t m_stretcherInputCount;
Chris@91 333 float **m_stretcherInputs;
Chris@91 334 size_t *m_stretcherInputSizes;
Chris@43 335
Chris@43 336 // Called from fill thread, m_playing true, mutex held
Chris@43 337 // Return true if work done
Chris@43 338 bool fillBuffers();
Chris@43 339
Chris@43 340 // Called from fillBuffers. Return the number of frames written,
Chris@43 341 // which will be count or fewer. Return in the frame argument the
Chris@43 342 // new buffered frame position (which may be earlier than the
Chris@43 343 // frame argument passed in, in the case of looping).
Chris@43 344 size_t mixModels(size_t &frame, size_t count, float **buffers);
Chris@43 345
Chris@43 346 // Called from getSourceSamples.
Chris@43 347 void applyAuditioningEffect(size_t count, float **buffers);
Chris@43 348
Chris@93 349 // Ranges of current selections, if play selection is active
Chris@93 350 std::vector<RealTime> m_rangeStarts;
Chris@93 351 std::vector<RealTime> m_rangeDurations;
Chris@93 352 void rebuildRangeLists();
Chris@93 353
Chris@93 354 size_t getCurrentFrame(RealTime outputLatency);
Chris@93 355
Chris@43 356 class FillThread : public Thread
Chris@43 357 {
Chris@43 358 public:
Chris@43 359 FillThread(AudioCallbackPlaySource &source) :
Chris@43 360 Thread(Thread::NonRTThread),
Chris@43 361 m_source(source) { }
Chris@43 362
Chris@43 363 virtual void run();
Chris@43 364
Chris@43 365 protected:
Chris@43 366 AudioCallbackPlaySource &m_source;
Chris@43 367 };
Chris@43 368
Chris@43 369 QMutex m_mutex;
Chris@43 370 QWaitCondition m_condition;
Chris@43 371 FillThread *m_fillThread;
Chris@43 372 SRC_STATE *m_converter;
Chris@43 373 SRC_STATE *m_crapConverter; // for use when playing very fast
Chris@43 374 int m_resampleQuality;
Chris@43 375 void initialiseConverter();
Chris@43 376 };
Chris@43 377
Chris@43 378 #endif
Chris@43 379
Chris@43 380