Mercurial > hg > svapp
diff audioio/AudioCallbackPlaySource.h @ 0:db6fcbd4405c
initial import
author | Chris Cannam |
---|---|
date | Tue, 10 Jan 2006 16:33:16 +0000 |
parents | |
children | df5923e33d01 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/audioio/AudioCallbackPlaySource.h Tue Jan 10 16:33:16 2006 +0000 @@ -0,0 +1,242 @@ +/* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */ + +/* + A waveform viewer and audio annotation editor. + Chris Cannam, Queen Mary University of London, 2005 + + This is experimental software. Not for distribution. +*/ + +#ifndef _AUDIO_CALLBACK_PLAY_SOURCE_H_ +#define _AUDIO_CALLBACK_PLAY_SOURCE_H_ + +#include "base/RingBuffer.h" +#include "base/AudioPlaySource.h" +#include "base/Scavenger.h" + +#include <QObject> +#include <QMutex> +#include <QWaitCondition> +#include <QThread> + +#include <samplerate.h> + +#include <set> +#include <map> + +class Model; +class ViewManager; +class AudioGenerator; +class IntegerTimeStretcher; + +/** + * AudioCallbackPlaySource manages audio data supply to callback-based + * audio APIs such as JACK or CoreAudio. It maintains one ring buffer + * per channel, filled during playback by a non-realtime thread, and + * provides a method for a realtime thread to pick up the latest + * available sample data from these buffers. + */ +class AudioCallbackPlaySource : public virtual QObject, + public AudioPlaySource +{ + Q_OBJECT + +public: + AudioCallbackPlaySource(ViewManager *); + virtual ~AudioCallbackPlaySource(); + + /** + * Add a data model to be played from. The source can mix + * playback from a number of sources including dense and sparse + * models. The models must match in sample rate, but they don't + * have to have identical numbers of channels. + */ + virtual void addModel(Model *model); + + /** + * Remove a model. + */ + virtual void removeModel(Model *model); + + /** + * Remove all models. (Silence will ensue.) + */ + virtual void clearModels(); + + /** + * Start making data available in the ring buffers for playback, + * from the given frame. If playback is already under way, reseek + * to the given frame and continue. + */ + virtual void play(size_t startFrame); + + /** + * Stop playback and ensure that no more data is returned. + */ + virtual void stop(); + + /** + * Return whether playback is currently supposed to be happening. + */ + virtual bool isPlaying() const { return m_playing; } + + /** + * Return the frame number that is currently expected to be coming + * out of the speakers. (i.e. compensating for playback latency.) + */ + virtual size_t getCurrentPlayingFrame(); + + /** + * Set the block size of the target audio device. This should + * be called by the target class. + */ + void setTargetBlockSize(size_t); + + /** + * Get the block size of the target audio device. + */ + size_t getTargetBlockSize() const; + + /** + * Set the playback latency of the target audio device, in frames + * at the target sample rate. This is the difference between the + * frame currently "leaving the speakers" and the last frame (or + * highest last frame across all channels) requested via + * getSamples(). The default is zero. + */ + void setTargetPlayLatency(size_t); + + /** + * Get the playback latency of the target audio device. + */ + size_t getTargetPlayLatency() const; + + /** + * Specify that the target audio device has a fixed sample rate + * (i.e. cannot accommodate arbitrary sample rates based on the + * source). If the target sets this to something other than the + * source sample rate, this class will resample automatically to + * fit. + */ + void setTargetSampleRate(size_t); + + /** + * Return the sample rate set by the target audio device (or the + * source sample rate if the target hasn't set one). + */ + size_t getTargetSampleRate() const; + + /** + * Set the current output levels for metering (for call from the + * target) + */ + void setOutputLevels(float left, float right); + + /** + * Return the current (or thereabouts) output levels in the range + * 0.0 -> 1.0, for metering purposes. + */ + virtual bool getOutputLevels(float &left, float &right); + + /** + * Get the number of channels of audio that will be available. + * This may safely be called from a realtime thread. Returns 0 if + * there is no source yet available. + */ + size_t getSourceChannelCount() const; + + /** + * Get the actual sample rate of the source material. This may + * safely be called from a realtime thread. Returns 0 if there is + * no source yet available. + */ + size_t getSourceSampleRate() const; + + /** + * Get "count" samples (at the target sample rate) of the mixed + * audio data, in all channels. This may safely be called from a + * realtime thread. + */ + size_t getSourceSamples(size_t count, float **buffer); + + void setSlowdownFactor(size_t factor); + +signals: + void modelReplaced(); + + /// Just a warning + void sampleRateMismatch(size_t requested, size_t available); + +protected: + ViewManager *m_viewManager; + AudioGenerator *m_audioGenerator; + + std::set<Model *> m_models; + std::vector<RingBuffer<float> *> m_buffers; + size_t m_bufferCount; + size_t m_blockSize; + size_t m_sourceSampleRate; + size_t m_targetSampleRate; + size_t m_playLatency; + bool m_playing; + bool m_exiting; + size_t m_bufferedToFrame; + static const size_t m_ringBufferSize; + float m_outputLeft; + float m_outputRight; + + RingBuffer<float> &getRingBuffer(size_t c) { + return *m_buffers[c]; + } + + class TimeStretcherData + { + public: + TimeStretcherData(size_t channels, size_t factor, size_t blockSize); + ~TimeStretcherData(); + + size_t getFactor() const { return m_factor; } + IntegerTimeStretcher *getStretcher(size_t channel); + double *getOutputBuffer(size_t channel); + double *getInputBuffer(); + + void run(size_t channel); + + protected: + TimeStretcherData(const TimeStretcherData &); // not provided + TimeStretcherData &operator=(const TimeStretcherData &); // not provided + + typedef std::pair<IntegerTimeStretcher *, double *> StretcherBuffer; + std::map<size_t, StretcherBuffer> m_stretcher; + double *m_stretchInputBuffer; + size_t m_factor; + size_t m_blockSize; + }; + + size_t m_slowdownCounter; + TimeStretcherData *m_timeStretcher; + Scavenger<TimeStretcherData> m_timeStretcherScavenger; + + void fillBuffers(); // Called from fill thread, m_playing true, mutex held + + class AudioCallbackPlaySourceFillThread : public QThread + { + public: + AudioCallbackPlaySourceFillThread(AudioCallbackPlaySource &source) : + m_source(source) { } + + virtual void run(); + + protected: + AudioCallbackPlaySource &m_source; + }; + + QMutex m_mutex; + QWaitCondition m_condition; + AudioCallbackPlaySourceFillThread *m_fillThread; + SRC_STATE *m_converter; +}; + +#endif + +