annotate audioio/AudioCallbackPlaySource.h @ 193:4e030ebb6b36

* Make it possible to drop audio files, layer files, session files and images onto SV panes. Need to do a bit more work on where we expect the dropped file to go, particularly in the case of audio files -- at the moment they're always opened in new panes, but it may be better to by default replace whatever is in the target pane.
author Chris Cannam
date Wed, 10 Oct 2007 15:18:02 +0000
parents 98ba77e0d897
children
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 Sonic Visualiser
Chris@0 5 An audio file viewer and annotation editor.
Chris@0 6 Centre for Digital Music, Queen Mary, University of London.
Chris@77 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@0 8
Chris@0 9 This program is free software; you can redistribute it and/or
Chris@0 10 modify it under the terms of the GNU General Public License as
Chris@0 11 published by the Free Software Foundation; either version 2 of the
Chris@0 12 License, or (at your option) any later version. See the file
Chris@0 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #ifndef _AUDIO_CALLBACK_PLAY_SOURCE_H_
Chris@0 17 #define _AUDIO_CALLBACK_PLAY_SOURCE_H_
Chris@0 18
Chris@0 19 #include "base/RingBuffer.h"
Chris@0 20 #include "base/AudioPlaySource.h"
Chris@32 21 #include "base/PropertyContainer.h"
Chris@0 22 #include "base/Scavenger.h"
Chris@0 23
Chris@0 24 #include <QObject>
Chris@0 25 #include <QMutex>
Chris@0 26 #include <QWaitCondition>
Chris@0 27
Chris@0 28 #include "base/Thread.h"
Chris@0 29
Chris@0 30 #include <samplerate.h>
Chris@0 31
Chris@0 32 #include <set>
Chris@0 33 #include <map>
Chris@0 34
Chris@0 35 class Model;
Chris@0 36 class ViewManager;
Chris@0 37 class AudioGenerator;
Chris@0 38 class PlayParameters;
Chris@14 39 class PhaseVocoderTimeStretcher;
Chris@41 40 class RealTimePluginInstance;
Chris@0 41
Chris@0 42 /**
Chris@0 43 * AudioCallbackPlaySource manages audio data supply to callback-based
Chris@0 44 * audio APIs such as JACK or CoreAudio. It maintains one ring buffer
Chris@0 45 * per channel, filled during playback by a non-realtime thread, and
Chris@0 46 * provides a method for a realtime thread to pick up the latest
Chris@0 47 * available sample data from these buffers.
Chris@0 48 */
Chris@0 49 class AudioCallbackPlaySource : public virtual QObject,
Chris@0 50 public AudioPlaySource
Chris@0 51 {
Chris@0 52 Q_OBJECT
Chris@0 53
Chris@0 54 public:
Chris@0 55 AudioCallbackPlaySource(ViewManager *);
Chris@0 56 virtual ~AudioCallbackPlaySource();
Chris@0 57
Chris@0 58 /**
Chris@0 59 * Add a data model to be played from. The source can mix
Chris@0 60 * playback from a number of sources including dense and sparse
Chris@0 61 * models. The models must match in sample rate, but they don't
Chris@0 62 * have to have identical numbers of channels.
Chris@0 63 */
Chris@0 64 virtual void addModel(Model *model);
Chris@0 65
Chris@0 66 /**
Chris@0 67 * Remove a model.
Chris@0 68 */
Chris@0 69 virtual void removeModel(Model *model);
Chris@0 70
Chris@0 71 /**
Chris@0 72 * Remove all models. (Silence will ensue.)
Chris@0 73 */
Chris@0 74 virtual void clearModels();
Chris@0 75
Chris@0 76 /**
Chris@0 77 * Start making data available in the ring buffers for playback,
Chris@0 78 * from the given frame. If playback is already under way, reseek
Chris@0 79 * to the given frame and continue.
Chris@0 80 */
Chris@0 81 virtual void play(size_t startFrame);
Chris@0 82
Chris@0 83 /**
Chris@0 84 * Stop playback and ensure that no more data is returned.
Chris@0 85 */
Chris@0 86 virtual void stop();
Chris@0 87
Chris@0 88 /**
Chris@0 89 * Return whether playback is currently supposed to be happening.
Chris@0 90 */
Chris@0 91 virtual bool isPlaying() const { return m_playing; }
Chris@0 92
Chris@0 93 /**
Chris@0 94 * Return the frame number that is currently expected to be coming
Chris@0 95 * out of the speakers. (i.e. compensating for playback latency.)
Chris@0 96 */
Chris@0 97 virtual size_t getCurrentPlayingFrame();
Chris@0 98
Chris@0 99 /**
Chris@116 100 * Return the frame at which playback is expected to end (if not looping).
Chris@116 101 */
Chris@116 102 virtual size_t getPlayEndFrame() { return m_lastModelEndFrame; }
Chris@116 103
Chris@116 104 /**
Chris@0 105 * Set the block size of the target audio device. This should
Chris@0 106 * be called by the target class.
Chris@0 107 */
Chris@0 108 void setTargetBlockSize(size_t);
Chris@0 109
Chris@0 110 /**
Chris@0 111 * Get the block size of the target audio device.
Chris@0 112 */
Chris@0 113 size_t getTargetBlockSize() const;
Chris@0 114
Chris@0 115 /**
Chris@0 116 * Set the playback latency of the target audio device, in frames
Chris@0 117 * at the target sample rate. This is the difference between the
Chris@0 118 * frame currently "leaving the speakers" and the last frame (or
Chris@0 119 * highest last frame across all channels) requested via
Chris@0 120 * getSamples(). The default is zero.
Chris@0 121 */
Chris@0 122 void setTargetPlayLatency(size_t);
Chris@0 123
Chris@0 124 /**
Chris@0 125 * Get the playback latency of the target audio device.
Chris@0 126 */
Chris@0 127 size_t getTargetPlayLatency() const;
Chris@0 128
Chris@0 129 /**
Chris@0 130 * Specify that the target audio device has a fixed sample rate
Chris@0 131 * (i.e. cannot accommodate arbitrary sample rates based on the
Chris@0 132 * source). If the target sets this to something other than the
Chris@0 133 * source sample rate, this class will resample automatically to
Chris@0 134 * fit.
Chris@0 135 */
Chris@0 136 void setTargetSampleRate(size_t);
Chris@0 137
Chris@0 138 /**
Chris@0 139 * Return the sample rate set by the target audio device (or the
Chris@0 140 * source sample rate if the target hasn't set one).
Chris@0 141 */
Chris@0 142 virtual size_t getTargetSampleRate() const;
Chris@0 143
Chris@0 144 /**
Chris@0 145 * Set the current output levels for metering (for call from the
Chris@0 146 * target)
Chris@0 147 */
Chris@0 148 void setOutputLevels(float left, float right);
Chris@0 149
Chris@0 150 /**
Chris@0 151 * Return the current (or thereabouts) output levels in the range
Chris@0 152 * 0.0 -> 1.0, for metering purposes.
Chris@0 153 */
Chris@0 154 virtual bool getOutputLevels(float &left, float &right);
Chris@0 155
Chris@0 156 /**
Chris@0 157 * Get the number of channels of audio that in the source models.
Chris@0 158 * This may safely be called from a realtime thread. Returns 0 if
Chris@0 159 * there is no source yet available.
Chris@0 160 */
Chris@0 161 size_t getSourceChannelCount() const;
Chris@0 162
Chris@0 163 /**
Chris@0 164 * Get the number of channels of audio that will be provided
Chris@0 165 * to the play target. This may be more than the source channel
Chris@0 166 * count: for example, a mono source will provide 2 channels
Chris@0 167 * after pan.
Chris@0 168 * This may safely be called from a realtime thread. Returns 0 if
Chris@0 169 * there is no source yet available.
Chris@0 170 */
Chris@0 171 size_t getTargetChannelCount() const;
Chris@0 172
Chris@0 173 /**
Chris@0 174 * Get the actual sample rate of the source material. This may
Chris@0 175 * safely be called from a realtime thread. Returns 0 if there is
Chris@0 176 * no source yet available.
Chris@0 177 */
Chris@118 178 virtual size_t getSourceSampleRate() const;
Chris@0 179
Chris@0 180 /**
Chris@0 181 * Get "count" samples (at the target sample rate) of the mixed
Chris@0 182 * audio data, in all channels. This may safely be called from a
Chris@0 183 * realtime thread.
Chris@0 184 */
Chris@0 185 size_t getSourceSamples(size_t count, float **buffer);
Chris@0 186
Chris@32 187 /**
Chris@32 188 * Set the time stretcher factor (i.e. playback speed). Also
Chris@32 189 * specify whether the time stretcher will be variable rate
Chris@32 190 * (sharpening transients), and whether time stretching will be
Chris@32 191 * carried out on data mixed down to mono for speed.
Chris@32 192 */
Chris@26 193 void setTimeStretch(float factor, bool sharpen, bool mono);
Chris@0 194
Chris@32 195 /**
Chris@32 196 * Set the resampler quality, 0 - 2 where 0 is fastest and 2 is
Chris@32 197 * highest quality.
Chris@32 198 */
Chris@32 199 void setResampleQuality(int q);
Chris@32 200
Chris@41 201 /**
Chris@41 202 * Set a single real-time plugin as a processing effect for
Chris@41 203 * auditioning during playback.
Chris@41 204 *
Chris@41 205 * The plugin must have been initialised with
Chris@41 206 * getTargetChannelCount() channels and a getTargetBlockSize()
Chris@41 207 * sample frame processing block size.
Chris@41 208 *
Chris@41 209 * This playback source takes ownership of the plugin, which will
Chris@41 210 * be deleted at some point after the following call to
Chris@41 211 * setAuditioningPlugin (depending on real-time constraints).
Chris@41 212 *
Chris@41 213 * Pass a null pointer to remove the current auditioning plugin,
Chris@41 214 * if any.
Chris@41 215 */
Chris@41 216 void setAuditioningPlugin(RealTimePluginInstance *plugin);
Chris@41 217
Chris@180 218 /**
Chris@180 219 * Specify that only the given set of models should be played.
Chris@180 220 */
Chris@180 221 void setSoloModelSet(std::set<Model *>s);
Chris@180 222
Chris@180 223 /**
Chris@180 224 * Specify that all models should be played as normal (if not
Chris@180 225 * muted).
Chris@180 226 */
Chris@180 227 void clearSoloModelSet();
Chris@180 228
Chris@0 229 signals:
Chris@0 230 void modelReplaced();
Chris@0 231
Chris@0 232 void playStatusChanged(bool isPlaying);
Chris@0 233
Chris@0 234 void sampleRateMismatch(size_t requested, size_t available, bool willResample);
Chris@0 235
Chris@42 236 void audioOverloadPluginDisabled();
Chris@42 237
Chris@42 238 public slots:
Chris@42 239 void audioProcessingOverload();
Chris@42 240
Chris@0 241 protected slots:
Chris@0 242 void selectionChanged();
Chris@0 243 void playLoopModeChanged();
Chris@0 244 void playSelectionModeChanged();
Chris@0 245 void playParametersChanged(PlayParameters *);
Chris@32 246 void preferenceChanged(PropertyContainer::PropertyName);
Chris@148 247 void modelChanged(size_t startFrame, size_t endFrame);
Chris@0 248
Chris@0 249 protected:
Chris@0 250 ViewManager *m_viewManager;
Chris@0 251 AudioGenerator *m_audioGenerator;
Chris@0 252
Chris@0 253 class RingBufferVector : public std::vector<RingBuffer<float> *> {
Chris@0 254 public:
Chris@0 255 virtual ~RingBufferVector() {
Chris@0 256 while (!empty()) {
Chris@0 257 delete *begin();
Chris@0 258 erase(begin());
Chris@0 259 }
Chris@0 260 }
Chris@0 261 };
Chris@0 262
Chris@41 263 std::set<Model *> m_models;
Chris@41 264 RingBufferVector *m_readBuffers;
Chris@41 265 RingBufferVector *m_writeBuffers;
Chris@41 266 size_t m_readBufferFill;
Chris@41 267 size_t m_writeBufferFill;
Chris@41 268 Scavenger<RingBufferVector> m_bufferScavenger;
Chris@41 269 size_t m_sourceChannelCount;
Chris@41 270 size_t m_blockSize;
Chris@41 271 size_t m_sourceSampleRate;
Chris@41 272 size_t m_targetSampleRate;
Chris@41 273 size_t m_playLatency;
Chris@41 274 bool m_playing;
Chris@41 275 bool m_exiting;
Chris@41 276 size_t m_lastModelEndFrame;
Chris@41 277 static const size_t m_ringBufferSize;
Chris@41 278 float m_outputLeft;
Chris@41 279 float m_outputRight;
Chris@41 280 RealTimePluginInstance *m_auditioningPlugin;
Chris@42 281 bool m_auditioningPluginBypassed;
Chris@41 282 Scavenger<RealTimePluginInstance> m_pluginScavenger;
Chris@0 283
Chris@0 284 RingBuffer<float> *getWriteRingBuffer(size_t c) {
Chris@0 285 if (m_writeBuffers && c < m_writeBuffers->size()) {
Chris@0 286 return (*m_writeBuffers)[c];
Chris@0 287 } else {
Chris@0 288 return 0;
Chris@0 289 }
Chris@0 290 }
Chris@0 291
Chris@0 292 RingBuffer<float> *getReadRingBuffer(size_t c) {
Chris@0 293 RingBufferVector *rb = m_readBuffers;
Chris@0 294 if (rb && c < rb->size()) {
Chris@0 295 return (*rb)[c];
Chris@0 296 } else {
Chris@0 297 return 0;
Chris@0 298 }
Chris@0 299 }
Chris@0 300
Chris@0 301 void clearRingBuffers(bool haveLock = false, size_t count = 0);
Chris@0 302 void unifyRingBuffers();
Chris@0 303
Chris@16 304 PhaseVocoderTimeStretcher *m_timeStretcher;
Chris@16 305 Scavenger<PhaseVocoderTimeStretcher> m_timeStretcherScavenger;
Chris@0 306
Chris@0 307 // Called from fill thread, m_playing true, mutex held
Chris@0 308 // Return true if work done
Chris@0 309 bool fillBuffers();
Chris@0 310
Chris@0 311 // Called from fillBuffers. Return the number of frames written,
Chris@0 312 // which will be count or fewer. Return in the frame argument the
Chris@0 313 // new buffered frame position (which may be earlier than the
Chris@0 314 // frame argument passed in, in the case of looping).
Chris@0 315 size_t mixModels(size_t &frame, size_t count, float **buffers);
Chris@0 316
Chris@41 317 // Called from getSourceSamples.
Chris@41 318 void applyAuditioningEffect(size_t count, float **buffers);
Chris@41 319
Chris@127 320 class FillThread : public Thread
Chris@0 321 {
Chris@0 322 public:
Chris@127 323 FillThread(AudioCallbackPlaySource &source) :
Chris@0 324 Thread(Thread::NonRTThread),
Chris@0 325 m_source(source) { }
Chris@0 326
Chris@0 327 virtual void run();
Chris@0 328
Chris@0 329 protected:
Chris@0 330 AudioCallbackPlaySource &m_source;
Chris@0 331 };
Chris@0 332
Chris@0 333 QMutex m_mutex;
Chris@0 334 QWaitCondition m_condition;
Chris@127 335 FillThread *m_fillThread;
Chris@0 336 SRC_STATE *m_converter;
Chris@32 337 SRC_STATE *m_crapConverter; // for use when playing very fast
Chris@32 338 int m_resampleQuality;
Chris@32 339 void initialiseConverter();
Chris@0 340 };
Chris@0 341
Chris@0 342 #endif
Chris@0 343
Chris@0 344