annotate audioio/AudioCallbackPlaySource.h @ 38:54287e5e7451 sv1-v0.9rc1 sv1-v0.9rc2

* Make vertical scale alignment modes work in note layer as well as time-value layer, and several significant fixes to it * Make it possible to draw notes properly on the note layer * Show units (and frequencies etc in note layer's case) in the time-value and note layer description boxes * Minor fix to item edit dialog layout * Some minor menu rearrangement * Comment out a lot of debug output * Add SV website and reference URLs to Help menu, and add code to (attempt to) open them in the user's preferred browser
author Chris Cannam
date Fri, 12 May 2006 14:40:43 +0000
parents 37e3c693af0c
children 4ed2448582cc
rev   line source
Chris@19 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@21 4 Sonic Visualiser
Chris@21 5 An audio file viewer and annotation editor.
Chris@21 6 Centre for Digital Music, Queen Mary, University of London.
Chris@21 7 This file copyright 2006 Chris Cannam.
Chris@0 8
Chris@21 9 This program is free software; you can redistribute it and/or
Chris@21 10 modify it under the terms of the GNU General Public License as
Chris@21 11 published by the Free Software Foundation; either version 2 of the
Chris@21 12 License, or (at your option) any later version. See the file
Chris@21 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@35 26
Chris@35 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@12 37 class PlayParameters;
Chris@0 38 class IntegerTimeStretcher;
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@17 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@13 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@13 157 * Get the number of channels of audio that will be provided
Chris@13 158 * to the play target. This may be more than the source channel
Chris@13 159 * count: for example, a mono source will provide 2 channels
Chris@13 160 * after pan.
Chris@13 161 * This may safely be called from a realtime thread. Returns 0 if
Chris@13 162 * there is no source yet available.
Chris@13 163 */
Chris@13 164 size_t getTargetChannelCount() const;
Chris@13 165
Chris@13 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@0 180 void setSlowdownFactor(size_t factor);
Chris@0 181
Chris@0 182 signals:
Chris@0 183 void modelReplaced();
Chris@0 184
Chris@4 185 void playStatusChanged(bool isPlaying);
Chris@4 186
Chris@25 187 void sampleRateMismatch(size_t requested, size_t available, bool willResample);
Chris@0 188
Chris@3 189 protected slots:
Chris@3 190 void selectionChanged();
Chris@3 191 void playLoopModeChanged();
Chris@3 192 void playSelectionModeChanged();
Chris@12 193 void playParametersChanged(PlayParameters *);
Chris@3 194
Chris@0 195 protected:
Chris@0 196 ViewManager *m_viewManager;
Chris@0 197 AudioGenerator *m_audioGenerator;
Chris@0 198
Chris@6 199 class RingBufferVector : public std::vector<RingBuffer<float> *> {
Chris@6 200 public:
Chris@6 201 virtual ~RingBufferVector() {
Chris@6 202 while (!empty()) {
Chris@6 203 delete *begin();
Chris@6 204 erase(begin());
Chris@6 205 }
Chris@6 206 }
Chris@6 207 };
Chris@6 208
Chris@0 209 std::set<Model *> m_models;
Chris@6 210 RingBufferVector *m_readBuffers;
Chris@6 211 RingBufferVector *m_writeBuffers;
Chris@13 212 size_t m_readBufferFill;
Chris@13 213 size_t m_writeBufferFill;
Chris@6 214 Scavenger<RingBufferVector> m_bufferScavenger;
Chris@6 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@4 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@6 227 RingBuffer<float> *getWriteRingBuffer(size_t c) {
Chris@6 228 if (m_writeBuffers && c < m_writeBuffers->size()) {
Chris@6 229 return (*m_writeBuffers)[c];
Chris@6 230 } else {
Chris@6 231 return 0;
Chris@6 232 }
Chris@0 233 }
Chris@0 234
Chris@6 235 RingBuffer<float> *getReadRingBuffer(size_t c) {
Chris@6 236 RingBufferVector *rb = m_readBuffers;
Chris@6 237 if (rb && c < rb->size()) {
Chris@6 238 return (*rb)[c];
Chris@6 239 } else {
Chris@6 240 return 0;
Chris@6 241 }
Chris@6 242 }
Chris@6 243
Chris@6 244 void clearRingBuffers(bool haveLock = false, size_t count = 0);
Chris@13 245 void unifyRingBuffers();
Chris@6 246
Chris@0 247 class TimeStretcherData
Chris@0 248 {
Chris@0 249 public:
Chris@0 250 TimeStretcherData(size_t channels, size_t factor, size_t blockSize);
Chris@0 251 ~TimeStretcherData();
Chris@0 252
Chris@0 253 size_t getFactor() const { return m_factor; }
Chris@0 254 IntegerTimeStretcher *getStretcher(size_t channel);
Chris@0 255 double *getOutputBuffer(size_t channel);
Chris@0 256 double *getInputBuffer();
Chris@0 257
Chris@0 258 void run(size_t channel);
Chris@0 259
Chris@0 260 protected:
Chris@0 261 TimeStretcherData(const TimeStretcherData &); // not provided
Chris@0 262 TimeStretcherData &operator=(const TimeStretcherData &); // not provided
Chris@0 263
Chris@0 264 typedef std::pair<IntegerTimeStretcher *, double *> StretcherBuffer;
Chris@0 265 std::map<size_t, StretcherBuffer> m_stretcher;
Chris@0 266 double *m_stretchInputBuffer;
Chris@0 267 size_t m_factor;
Chris@0 268 size_t m_blockSize;
Chris@0 269 };
Chris@0 270
Chris@0 271 size_t m_slowdownCounter;
Chris@0 272 TimeStretcherData *m_timeStretcher;
Chris@0 273 Scavenger<TimeStretcherData> m_timeStretcherScavenger;
Chris@0 274
Chris@4 275 // Called from fill thread, m_playing true, mutex held
Chris@7 276 // Return true if work done
Chris@7 277 bool fillBuffers();
Chris@4 278
Chris@6 279 // Called from fillBuffers. Return the number of frames written,
Chris@6 280 // which will be count or fewer. Return in the frame argument the
Chris@6 281 // new buffered frame position (which may be earlier than the
Chris@6 282 // frame argument passed in, in the case of looping).
Chris@6 283 size_t mixModels(size_t &frame, size_t count, float **buffers);
Chris@0 284
Chris@35 285 class AudioCallbackPlaySourceFillThread : public Thread
Chris@0 286 {
Chris@0 287 public:
Chris@0 288 AudioCallbackPlaySourceFillThread(AudioCallbackPlaySource &source) :
Chris@35 289 Thread(Thread::NonRTThread),
Chris@0 290 m_source(source) { }
Chris@0 291
Chris@0 292 virtual void run();
Chris@0 293
Chris@0 294 protected:
Chris@0 295 AudioCallbackPlaySource &m_source;
Chris@0 296 };
Chris@0 297
Chris@0 298 QMutex m_mutex;
Chris@0 299 QWaitCondition m_condition;
Chris@0 300 AudioCallbackPlaySourceFillThread *m_fillThread;
Chris@0 301 SRC_STATE *m_converter;
Chris@0 302 };
Chris@0 303
Chris@0 304 #endif
Chris@0 305
Chris@0 306