Mercurial > hg > svapp
comparison audio/AudioCallbackPlaySource.h @ 468:56acd9368532 bqaudioio
Initial work toward switching to bqaudioio library (so as to get I/O, not just O)
author | Chris Cannam |
---|---|
date | Tue, 04 Aug 2015 13:27:42 +0100 |
parents | audioio/AudioCallbackPlaySource.h@72c662fe7ea3 |
children | 0d725dd7f99c |
comparison
equal
deleted
inserted
replaced
466:45054b36ddbf | 468:56acd9368532 |
---|---|
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 <bqaudioio/ApplicationPlaybackSource.h> | |
25 | |
26 #include <QObject> | |
27 #include <QMutex> | |
28 #include <QWaitCondition> | |
29 | |
30 #include "base/Thread.h" | |
31 #include "base/RealTime.h" | |
32 | |
33 #include <samplerate.h> | |
34 | |
35 #include <set> | |
36 #include <map> | |
37 | |
38 namespace RubberBand { | |
39 class RubberBandStretcher; | |
40 } | |
41 | |
42 class Model; | |
43 class ViewManagerBase; | |
44 class AudioGenerator; | |
45 class PlayParameters; | |
46 class RealTimePluginInstance; | |
47 class AudioCallbackPlayTarget; | |
48 | |
49 /** | |
50 * AudioCallbackPlaySource manages audio data supply to callback-based | |
51 * audio APIs such as JACK or CoreAudio. It maintains one ring buffer | |
52 * per channel, filled during playback by a non-realtime thread, and | |
53 * provides a method for a realtime thread to pick up the latest | |
54 * available sample data from these buffers. | |
55 */ | |
56 class AudioCallbackPlaySource : public QObject, | |
57 public AudioPlaySource, | |
58 public breakfastquay::ApplicationPlaybackSource | |
59 { | |
60 Q_OBJECT | |
61 | |
62 public: | |
63 AudioCallbackPlaySource(ViewManagerBase *, QString clientName); | |
64 virtual ~AudioCallbackPlaySource(); | |
65 | |
66 /** | |
67 * Add a data model to be played from. The source can mix | |
68 * playback from a number of sources including dense and sparse | |
69 * models. The models must match in sample rate, but they don't | |
70 * have to have identical numbers of channels. | |
71 */ | |
72 virtual void addModel(Model *model); | |
73 | |
74 /** | |
75 * Remove a model. | |
76 */ | |
77 virtual void removeModel(Model *model); | |
78 | |
79 /** | |
80 * Remove all models. (Silence will ensue.) | |
81 */ | |
82 virtual void clearModels(); | |
83 | |
84 /** | |
85 * Start making data available in the ring buffers for playback, | |
86 * from the given frame. If playback is already under way, reseek | |
87 * to the given frame and continue. | |
88 */ | |
89 virtual void play(sv_frame_t startFrame); | |
90 | |
91 /** | |
92 * Stop playback and ensure that no more data is returned. | |
93 */ | |
94 virtual void stop(); | |
95 | |
96 /** | |
97 * Return whether playback is currently supposed to be happening. | |
98 */ | |
99 virtual bool isPlaying() const { return m_playing; } | |
100 | |
101 /** | |
102 * Return the frame number that is currently expected to be coming | |
103 * out of the speakers. (i.e. compensating for playback latency.) | |
104 */ | |
105 virtual sv_frame_t getCurrentPlayingFrame(); | |
106 | |
107 /** | |
108 * Return the last frame that would come out of the speakers if we | |
109 * stopped playback right now. | |
110 */ | |
111 virtual sv_frame_t getCurrentBufferedFrame(); | |
112 | |
113 /** | |
114 * Return the frame at which playback is expected to end (if not looping). | |
115 */ | |
116 virtual sv_frame_t getPlayEndFrame() { return m_lastModelEndFrame; } | |
117 | |
118 /** | |
119 * Set the playback target. This should be called by the target | |
120 * class. | |
121 */ | |
122 virtual void setSystemPlaybackTarget(breakfastquay::SystemPlaybackTarget *); | |
123 | |
124 /** | |
125 * Set the block size of the target audio device. This should be | |
126 * called by the target class. | |
127 */ | |
128 virtual void setSystemPlaybackBlockSize(int blockSize); | |
129 | |
130 /** | |
131 * Get the block size of the target audio device. This may be an | |
132 * estimate or upper bound, if the target has a variable block | |
133 * size; the source should behave itself even if this value turns | |
134 * out to be inaccurate. | |
135 */ | |
136 int getTargetBlockSize() const; | |
137 | |
138 /** | |
139 * Set the playback latency of the target audio device, in frames | |
140 * at the target sample rate. This is the difference between the | |
141 * frame currently "leaving the speakers" and the last frame (or | |
142 * highest last frame across all channels) requested via | |
143 * getSamples(). The default is zero. | |
144 */ | |
145 void setSystemPlaybackLatency(int); | |
146 | |
147 /** | |
148 * Get the playback latency of the target audio device. | |
149 */ | |
150 sv_frame_t getTargetPlayLatency() const; | |
151 | |
152 /** | |
153 * Specify that the target audio device has a fixed sample rate | |
154 * (i.e. cannot accommodate arbitrary sample rates based on the | |
155 * source). If the target sets this to something other than the | |
156 * source sample rate, this class will resample automatically to | |
157 * fit. | |
158 */ | |
159 void setSystemPlaybackSampleRate(int); | |
160 | |
161 /** | |
162 * Return the sample rate set by the target audio device (or the | |
163 * source sample rate if the target hasn't set one). | |
164 */ | |
165 virtual sv_samplerate_t getTargetSampleRate() const; | |
166 | |
167 /** | |
168 * Set the current output levels for metering (for call from the | |
169 * target) | |
170 */ | |
171 void setOutputLevels(float left, float right); | |
172 | |
173 /** | |
174 * Return the current (or thereabouts) output levels in the range | |
175 * 0.0 -> 1.0, for metering purposes. | |
176 */ | |
177 virtual bool getOutputLevels(float &left, float &right); | |
178 | |
179 /** | |
180 * Get the number of channels of audio that in the source models. | |
181 * This may safely be called from a realtime thread. Returns 0 if | |
182 * there is no source yet available. | |
183 */ | |
184 int getSourceChannelCount() const; | |
185 | |
186 /** | |
187 * Get the number of channels of audio that will be provided | |
188 * to the play target. This may be more than the source channel | |
189 * count: for example, a mono source will provide 2 channels | |
190 * after pan. | |
191 * This may safely be called from a realtime thread. Returns 0 if | |
192 * there is no source yet available. | |
193 */ | |
194 int getTargetChannelCount() const; | |
195 | |
196 /** | |
197 * ApplicationPlaybackSource equivalent of the above. | |
198 */ | |
199 virtual int getApplicationChannelCount() const { | |
200 return getTargetChannelCount(); | |
201 } | |
202 | |
203 /** | |
204 * Get the actual sample rate of the source material. This may | |
205 * safely be called from a realtime thread. Returns 0 if there is | |
206 * no source yet available. | |
207 */ | |
208 virtual sv_samplerate_t getSourceSampleRate() const; | |
209 | |
210 /** | |
211 * ApplicationPlaybackSource equivalent of the above. | |
212 */ | |
213 virtual int getApplicationSampleRate() const { | |
214 return int(round(getSourceSampleRate())); | |
215 } | |
216 | |
217 /** | |
218 * Get "count" samples (at the target sample rate) of the mixed | |
219 * audio data, in all channels. This may safely be called from a | |
220 * realtime thread. | |
221 */ | |
222 virtual void getSourceSamples(int count, float **buffer); | |
223 | |
224 /** | |
225 * Set the time stretcher factor (i.e. playback speed). | |
226 */ | |
227 void setTimeStretch(double factor); | |
228 | |
229 /** | |
230 * Set the resampler quality, 0 - 2 where 0 is fastest and 2 is | |
231 * highest quality. | |
232 */ | |
233 void setResampleQuality(int q); | |
234 | |
235 /** | |
236 * Set a single real-time plugin as a processing effect for | |
237 * auditioning during playback. | |
238 * | |
239 * The plugin must have been initialised with | |
240 * getTargetChannelCount() channels and a getTargetBlockSize() | |
241 * sample frame processing block size. | |
242 * | |
243 * This playback source takes ownership of the plugin, which will | |
244 * be deleted at some point after the following call to | |
245 * setAuditioningEffect (depending on real-time constraints). | |
246 * | |
247 * Pass a null pointer to remove the current auditioning plugin, | |
248 * if any. | |
249 */ | |
250 void setAuditioningEffect(Auditionable *plugin); | |
251 | |
252 /** | |
253 * Specify that only the given set of models should be played. | |
254 */ | |
255 void setSoloModelSet(std::set<Model *>s); | |
256 | |
257 /** | |
258 * Specify that all models should be played as normal (if not | |
259 * muted). | |
260 */ | |
261 void clearSoloModelSet(); | |
262 | |
263 std::string getClientName() const { return m_clientName; } | |
264 | |
265 signals: | |
266 void modelReplaced(); | |
267 | |
268 void playStatusChanged(bool isPlaying); | |
269 | |
270 void sampleRateMismatch(sv_samplerate_t requested, | |
271 sv_samplerate_t available, | |
272 bool willResample); | |
273 | |
274 void audioOverloadPluginDisabled(); | |
275 void audioTimeStretchMultiChannelDisabled(); | |
276 | |
277 void activity(QString); | |
278 | |
279 public slots: | |
280 void audioProcessingOverload(); | |
281 | |
282 protected slots: | |
283 void selectionChanged(); | |
284 void playLoopModeChanged(); | |
285 void playSelectionModeChanged(); | |
286 void playParametersChanged(PlayParameters *); | |
287 void preferenceChanged(PropertyContainer::PropertyName); | |
288 void modelChangedWithin(sv_frame_t startFrame, sv_frame_t endFrame); | |
289 | |
290 protected: | |
291 ViewManagerBase *m_viewManager; | |
292 AudioGenerator *m_audioGenerator; | |
293 std::string m_clientName; | |
294 | |
295 class RingBufferVector : public std::vector<RingBuffer<float> *> { | |
296 public: | |
297 virtual ~RingBufferVector() { | |
298 while (!empty()) { | |
299 delete *begin(); | |
300 erase(begin()); | |
301 } | |
302 } | |
303 }; | |
304 | |
305 std::set<Model *> m_models; | |
306 RingBufferVector *m_readBuffers; | |
307 RingBufferVector *m_writeBuffers; | |
308 sv_frame_t m_readBufferFill; | |
309 sv_frame_t m_writeBufferFill; | |
310 Scavenger<RingBufferVector> m_bufferScavenger; | |
311 int m_sourceChannelCount; | |
312 sv_frame_t m_blockSize; | |
313 sv_samplerate_t m_sourceSampleRate; | |
314 sv_samplerate_t m_targetSampleRate; | |
315 sv_frame_t m_playLatency; | |
316 breakfastquay::SystemPlaybackTarget *m_target; | |
317 double m_lastRetrievalTimestamp; | |
318 sv_frame_t m_lastRetrievedBlockSize; | |
319 bool m_trustworthyTimestamps; | |
320 sv_frame_t m_lastCurrentFrame; | |
321 bool m_playing; | |
322 bool m_exiting; | |
323 sv_frame_t m_lastModelEndFrame; | |
324 int m_ringBufferSize; | |
325 float m_outputLeft; | |
326 float m_outputRight; | |
327 RealTimePluginInstance *m_auditioningPlugin; | |
328 bool m_auditioningPluginBypassed; | |
329 Scavenger<RealTimePluginInstance> m_pluginScavenger; | |
330 sv_frame_t m_playStartFrame; | |
331 bool m_playStartFramePassed; | |
332 RealTime m_playStartedAt; | |
333 | |
334 RingBuffer<float> *getWriteRingBuffer(int c) { | |
335 if (m_writeBuffers && c < (int)m_writeBuffers->size()) { | |
336 return (*m_writeBuffers)[c]; | |
337 } else { | |
338 return 0; | |
339 } | |
340 } | |
341 | |
342 RingBuffer<float> *getReadRingBuffer(int c) { | |
343 RingBufferVector *rb = m_readBuffers; | |
344 if (rb && c < (int)rb->size()) { | |
345 return (*rb)[c]; | |
346 } else { | |
347 return 0; | |
348 } | |
349 } | |
350 | |
351 void clearRingBuffers(bool haveLock = false, int count = 0); | |
352 void unifyRingBuffers(); | |
353 | |
354 RubberBand::RubberBandStretcher *m_timeStretcher; | |
355 RubberBand::RubberBandStretcher *m_monoStretcher; | |
356 double m_stretchRatio; | |
357 bool m_stretchMono; | |
358 | |
359 int m_stretcherInputCount; | |
360 float **m_stretcherInputs; | |
361 sv_frame_t *m_stretcherInputSizes; | |
362 | |
363 // Called from fill thread, m_playing true, mutex held | |
364 // Return true if work done | |
365 bool fillBuffers(); | |
366 | |
367 // Called from fillBuffers. Return the number of frames written, | |
368 // which will be count or fewer. Return in the frame argument the | |
369 // new buffered frame position (which may be earlier than the | |
370 // frame argument passed in, in the case of looping). | |
371 sv_frame_t mixModels(sv_frame_t &frame, sv_frame_t count, float **buffers); | |
372 | |
373 // Called from getSourceSamples. | |
374 void applyAuditioningEffect(sv_frame_t count, float **buffers); | |
375 | |
376 // Ranges of current selections, if play selection is active | |
377 std::vector<RealTime> m_rangeStarts; | |
378 std::vector<RealTime> m_rangeDurations; | |
379 void rebuildRangeLists(); | |
380 | |
381 sv_frame_t getCurrentFrame(RealTime outputLatency); | |
382 | |
383 class FillThread : public Thread | |
384 { | |
385 public: | |
386 FillThread(AudioCallbackPlaySource &source) : | |
387 Thread(Thread::NonRTThread), | |
388 m_source(source) { } | |
389 | |
390 virtual void run(); | |
391 | |
392 protected: | |
393 AudioCallbackPlaySource &m_source; | |
394 }; | |
395 | |
396 QMutex m_mutex; | |
397 QWaitCondition m_condition; | |
398 FillThread *m_fillThread; | |
399 SRC_STATE *m_converter; | |
400 SRC_STATE *m_crapConverter; // for use when playing very fast | |
401 int m_resampleQuality; | |
402 void initialiseConverter(); | |
403 }; | |
404 | |
405 #endif | |
406 | |
407 |