annotate audioio/AudioCallbackPlaySource.h @ 25:e74f508db18c

* Add setRatio method to the time stretcher, and make it possible to change the ratio without having to construct and replace the time stretcher. This means we can do it seamlessly. Add a lot more ratios to the time stretch control in the main window
author Chris Cannam
date Fri, 15 Sep 2006 15:35:06 +0000
parents 3715efc38f95
children d88d117e0c34
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@0 7 This file copyright 2006 Chris Cannam.
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@0 21 #include "base/Scavenger.h"
Chris@0 22
Chris@0 23 #include <QObject>
Chris@0 24 #include <QMutex>
Chris@0 25 #include <QWaitCondition>
Chris@0 26
Chris@0 27 #include "base/Thread.h"
Chris@0 28
Chris@0 29 #include <samplerate.h>
Chris@0 30
Chris@0 31 #include <set>
Chris@0 32 #include <map>
Chris@0 33
Chris@0 34 class Model;
Chris@0 35 class ViewManager;
Chris@0 36 class AudioGenerator;
Chris@0 37 class PlayParameters;
Chris@14 38 class PhaseVocoderTimeStretcher;
Chris@0 39
Chris@0 40 /**
Chris@0 41 * AudioCallbackPlaySource manages audio data supply to callback-based
Chris@0 42 * audio APIs such as JACK or CoreAudio. It maintains one ring buffer
Chris@0 43 * per channel, filled during playback by a non-realtime thread, and
Chris@0 44 * provides a method for a realtime thread to pick up the latest
Chris@0 45 * available sample data from these buffers.
Chris@0 46 */
Chris@0 47 class AudioCallbackPlaySource : public virtual QObject,
Chris@0 48 public AudioPlaySource
Chris@0 49 {
Chris@0 50 Q_OBJECT
Chris@0 51
Chris@0 52 public:
Chris@0 53 AudioCallbackPlaySource(ViewManager *);
Chris@0 54 virtual ~AudioCallbackPlaySource();
Chris@0 55
Chris@0 56 /**
Chris@0 57 * Add a data model to be played from. The source can mix
Chris@0 58 * playback from a number of sources including dense and sparse
Chris@0 59 * models. The models must match in sample rate, but they don't
Chris@0 60 * have to have identical numbers of channels.
Chris@0 61 */
Chris@0 62 virtual void addModel(Model *model);
Chris@0 63
Chris@0 64 /**
Chris@0 65 * Remove a model.
Chris@0 66 */
Chris@0 67 virtual void removeModel(Model *model);
Chris@0 68
Chris@0 69 /**
Chris@0 70 * Remove all models. (Silence will ensue.)
Chris@0 71 */
Chris@0 72 virtual void clearModels();
Chris@0 73
Chris@0 74 /**
Chris@0 75 * Start making data available in the ring buffers for playback,
Chris@0 76 * from the given frame. If playback is already under way, reseek
Chris@0 77 * to the given frame and continue.
Chris@0 78 */
Chris@0 79 virtual void play(size_t startFrame);
Chris@0 80
Chris@0 81 /**
Chris@0 82 * Stop playback and ensure that no more data is returned.
Chris@0 83 */
Chris@0 84 virtual void stop();
Chris@0 85
Chris@0 86 /**
Chris@0 87 * Return whether playback is currently supposed to be happening.
Chris@0 88 */
Chris@0 89 virtual bool isPlaying() const { return m_playing; }
Chris@0 90
Chris@0 91 /**
Chris@0 92 * Return the frame number that is currently expected to be coming
Chris@0 93 * out of the speakers. (i.e. compensating for playback latency.)
Chris@0 94 */
Chris@0 95 virtual size_t getCurrentPlayingFrame();
Chris@0 96
Chris@0 97 /**
Chris@0 98 * Set the block size of the target audio device. This should
Chris@0 99 * be called by the target class.
Chris@0 100 */
Chris@0 101 void setTargetBlockSize(size_t);
Chris@0 102
Chris@0 103 /**
Chris@0 104 * Get the block size of the target audio device.
Chris@0 105 */
Chris@0 106 size_t getTargetBlockSize() const;
Chris@0 107
Chris@0 108 /**
Chris@0 109 * Set the playback latency of the target audio device, in frames
Chris@0 110 * at the target sample rate. This is the difference between the
Chris@0 111 * frame currently "leaving the speakers" and the last frame (or
Chris@0 112 * highest last frame across all channels) requested via
Chris@0 113 * getSamples(). The default is zero.
Chris@0 114 */
Chris@0 115 void setTargetPlayLatency(size_t);
Chris@0 116
Chris@0 117 /**
Chris@0 118 * Get the playback latency of the target audio device.
Chris@0 119 */
Chris@0 120 size_t getTargetPlayLatency() const;
Chris@0 121
Chris@0 122 /**
Chris@0 123 * Specify that the target audio device has a fixed sample rate
Chris@0 124 * (i.e. cannot accommodate arbitrary sample rates based on the
Chris@0 125 * source). If the target sets this to something other than the
Chris@0 126 * source sample rate, this class will resample automatically to
Chris@0 127 * fit.
Chris@0 128 */
Chris@0 129 void setTargetSampleRate(size_t);
Chris@0 130
Chris@0 131 /**
Chris@0 132 * Return the sample rate set by the target audio device (or the
Chris@0 133 * source sample rate if the target hasn't set one).
Chris@0 134 */
Chris@0 135 virtual size_t getTargetSampleRate() const;
Chris@0 136
Chris@0 137 /**
Chris@0 138 * Set the current output levels for metering (for call from the
Chris@0 139 * target)
Chris@0 140 */
Chris@0 141 void setOutputLevels(float left, float right);
Chris@0 142
Chris@0 143 /**
Chris@0 144 * Return the current (or thereabouts) output levels in the range
Chris@0 145 * 0.0 -> 1.0, for metering purposes.
Chris@0 146 */
Chris@0 147 virtual bool getOutputLevels(float &left, float &right);
Chris@0 148
Chris@0 149 /**
Chris@0 150 * Get the number of channels of audio that in the source models.
Chris@0 151 * This may safely be called from a realtime thread. Returns 0 if
Chris@0 152 * there is no source yet available.
Chris@0 153 */
Chris@0 154 size_t getSourceChannelCount() const;
Chris@0 155
Chris@0 156 /**
Chris@0 157 * Get the number of channels of audio that will be provided
Chris@0 158 * to the play target. This may be more than the source channel
Chris@0 159 * count: for example, a mono source will provide 2 channels
Chris@0 160 * after pan.
Chris@0 161 * This may safely be called from a realtime thread. Returns 0 if
Chris@0 162 * there is no source yet available.
Chris@0 163 */
Chris@0 164 size_t getTargetChannelCount() const;
Chris@0 165
Chris@0 166 /**
Chris@0 167 * Get the actual sample rate of the source material. This may
Chris@0 168 * safely be called from a realtime thread. Returns 0 if there is
Chris@0 169 * no source yet available.
Chris@0 170 */
Chris@0 171 size_t getSourceSampleRate() const;
Chris@0 172
Chris@0 173 /**
Chris@0 174 * Get "count" samples (at the target sample rate) of the mixed
Chris@0 175 * audio data, in all channels. This may safely be called from a
Chris@0 176 * realtime thread.
Chris@0 177 */
Chris@0 178 size_t getSourceSamples(size_t count, float **buffer);
Chris@0 179
Chris@16 180 void setSlowdownFactor(float factor, bool sharpen);
Chris@0 181
Chris@0 182 signals:
Chris@0 183 void modelReplaced();
Chris@0 184
Chris@0 185 void playStatusChanged(bool isPlaying);
Chris@0 186
Chris@0 187 void sampleRateMismatch(size_t requested, size_t available, bool willResample);
Chris@0 188
Chris@0 189 protected slots:
Chris@0 190 void selectionChanged();
Chris@0 191 void playLoopModeChanged();
Chris@0 192 void playSelectionModeChanged();
Chris@0 193 void playParametersChanged(PlayParameters *);
Chris@0 194
Chris@0 195 protected:
Chris@0 196 ViewManager *m_viewManager;
Chris@0 197 AudioGenerator *m_audioGenerator;
Chris@0 198
Chris@0 199 class RingBufferVector : public std::vector<RingBuffer<float> *> {
Chris@0 200 public:
Chris@0 201 virtual ~RingBufferVector() {
Chris@0 202 while (!empty()) {
Chris@0 203 delete *begin();
Chris@0 204 erase(begin());
Chris@0 205 }
Chris@0 206 }
Chris@0 207 };
Chris@0 208
Chris@0 209 std::set<Model *> m_models;
Chris@0 210 RingBufferVector *m_readBuffers;
Chris@0 211 RingBufferVector *m_writeBuffers;
Chris@0 212 size_t m_readBufferFill;
Chris@0 213 size_t m_writeBufferFill;
Chris@0 214 Scavenger<RingBufferVector> m_bufferScavenger;
Chris@0 215 size_t m_sourceChannelCount;
Chris@0 216 size_t m_blockSize;
Chris@0 217 size_t m_sourceSampleRate;
Chris@0 218 size_t m_targetSampleRate;
Chris@0 219 size_t m_playLatency;
Chris@0 220 bool m_playing;
Chris@0 221 bool m_exiting;
Chris@0 222 size_t m_lastModelEndFrame;
Chris@0 223 static const size_t m_ringBufferSize;
Chris@0 224 float m_outputLeft;
Chris@0 225 float m_outputRight;
Chris@0 226
Chris@0 227 RingBuffer<float> *getWriteRingBuffer(size_t c) {
Chris@0 228 if (m_writeBuffers && c < m_writeBuffers->size()) {
Chris@0 229 return (*m_writeBuffers)[c];
Chris@0 230 } else {
Chris@0 231 return 0;
Chris@0 232 }
Chris@0 233 }
Chris@0 234
Chris@0 235 RingBuffer<float> *getReadRingBuffer(size_t c) {
Chris@0 236 RingBufferVector *rb = m_readBuffers;
Chris@0 237 if (rb && c < rb->size()) {
Chris@0 238 return (*rb)[c];
Chris@0 239 } else {
Chris@0 240 return 0;
Chris@0 241 }
Chris@0 242 }
Chris@0 243
Chris@0 244 void clearRingBuffers(bool haveLock = false, size_t count = 0);
Chris@0 245 void unifyRingBuffers();
Chris@0 246
Chris@16 247 PhaseVocoderTimeStretcher *m_timeStretcher;
Chris@16 248 Scavenger<PhaseVocoderTimeStretcher> m_timeStretcherScavenger;
Chris@0 249
Chris@0 250 // Called from fill thread, m_playing true, mutex held
Chris@0 251 // Return true if work done
Chris@0 252 bool fillBuffers();
Chris@0 253
Chris@0 254 // Called from fillBuffers. Return the number of frames written,
Chris@0 255 // which will be count or fewer. Return in the frame argument the
Chris@0 256 // new buffered frame position (which may be earlier than the
Chris@0 257 // frame argument passed in, in the case of looping).
Chris@0 258 size_t mixModels(size_t &frame, size_t count, float **buffers);
Chris@0 259
Chris@0 260 class AudioCallbackPlaySourceFillThread : public Thread
Chris@0 261 {
Chris@0 262 public:
Chris@0 263 AudioCallbackPlaySourceFillThread(AudioCallbackPlaySource &source) :
Chris@0 264 Thread(Thread::NonRTThread),
Chris@0 265 m_source(source) { }
Chris@0 266
Chris@0 267 virtual void run();
Chris@0 268
Chris@0 269 protected:
Chris@0 270 AudioCallbackPlaySource &m_source;
Chris@0 271 };
Chris@0 272
Chris@0 273 QMutex m_mutex;
Chris@0 274 QWaitCondition m_condition;
Chris@0 275 AudioCallbackPlaySourceFillThread *m_fillThread;
Chris@0 276 SRC_STATE *m_converter;
Chris@0 277 };
Chris@0 278
Chris@0 279 #endif
Chris@0 280
Chris@0 281