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