diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 18:37:05 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 18:37:05 +0000 |
commit | 145364a8af6a1fec06556221e66d4b724a62fc9a (patch) | |
tree | 53bd71a544008c518034f208d64c932dc2883f50 /src/sound/AudioProcess.h | |
download | rosegarden-145364a8af6a1fec06556221e66d4b724a62fc9a.tar.gz rosegarden-145364a8af6a1fec06556221e66d4b724a62fc9a.zip |
Added old abandoned KDE3 version of the RoseGarden MIDI tool
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/rosegarden@1097595 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/sound/AudioProcess.h')
-rw-r--r-- | src/sound/AudioProcess.h | 390 |
1 files changed, 390 insertions, 0 deletions
diff --git a/src/sound/AudioProcess.h b/src/sound/AudioProcess.h new file mode 100644 index 0000000..b517bc9 --- /dev/null +++ b/src/sound/AudioProcess.h @@ -0,0 +1,390 @@ +// -*- c-basic-offset: 4 -*- + +/* + Rosegarden + A sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral right of the authors to claim authorship of this work + has been asserted. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _AUDIO_PROCESS_H_ +#define _AUDIO_PROCESS_H_ + +#include "SoundDriver.h" +#include "Instrument.h" +#include "RealTime.h" +#include "RingBuffer.h" +#include "RunnablePluginInstance.h" +#include "AudioPlayQueue.h" +#include "RecordableAudioFile.h" + +namespace Rosegarden +{ + +class AudioThread +{ +public: + typedef float sample_t; + + AudioThread(std::string name, // for diagnostics + SoundDriver *driver, + unsigned int sampleRate); + + virtual ~AudioThread(); + + // This is to be called by the owning class after construction. + void run(); + + // This is to be called by the owning class to cause the thread to + // exit and clean up, before destruction. + void terminate(); + + bool running() const { return m_running; } + + int getLock(); + int tryLock(); + int releaseLock(); + void signal(); + +protected: + virtual void threadRun() = 0; + virtual int getPriority() { return 0; } + + std::string m_name; + + SoundDriver *m_driver; + unsigned int m_sampleRate; + + pthread_t m_thread; + pthread_mutex_t m_lock; + pthread_cond_t m_condition; + bool m_running; + volatile bool m_exiting; + +private: + static void *staticThreadRun(void *arg); + static void staticThreadCleanup(void *arg); +}; + + +class AudioInstrumentMixer; + +class AudioBussMixer : public AudioThread +{ +public: + AudioBussMixer(SoundDriver *driver, + AudioInstrumentMixer *instrumentMixer, + unsigned int sampleRate, + unsigned int blockSize); + + virtual ~AudioBussMixer(); + + void kick(bool wantLock = true, bool signalInstrumentMixer = true); + + /** + * Prebuffer. This should be called only when the transport is + * not running. This also calls fillBuffers on the instrument + * mixer. + */ + void fillBuffers(const RealTime ¤tTime); + + /** + * Empty and discard buffer contents. + */ + void emptyBuffers(); + + int getBussCount() { + return m_bussCount; + } + + /** + * A buss is "dormant" if every readable sample on every one of + * its buffers is zero. It can therefore be safely skipped during + * playback. + */ + bool isBussDormant(int buss) { + return m_bufferMap[buss].dormant; + } + + /** + * Busses are currently always stereo. + */ + RingBuffer<sample_t> *getRingBuffer(int buss, unsigned int channel) { + if (channel < m_bufferMap[buss].buffers.size()) { + return m_bufferMap[buss].buffers[channel]; + } else { + return 0; + } + } + + /// For call from MappedStudio. Pan is in range -100.0 -> 100.0 + void setBussLevels(int buss, float dB, float pan); + + /// For call regularly from anywhere in a non-RT thread + void updateInstrumentConnections(); + +protected: + virtual void threadRun(); + + void processBlocks(); + void generateBuffers(); + + AudioInstrumentMixer *m_instrumentMixer; + unsigned int m_blockSize; + int m_bussCount; + + std::vector<sample_t *> m_processBuffers; + + struct BufferRec + { + BufferRec() : dormant(true), buffers(), instruments(), + gainLeft(0.0), gainRight(0.0) { } + ~BufferRec(); + + bool dormant; + + std::vector<RingBuffer<sample_t> *> buffers; + std::vector<bool> instruments; // index is instrument id minus base + + float gainLeft; + float gainRight; + }; + + typedef std::map<int, BufferRec> BufferMap; + BufferMap m_bufferMap; +}; + + +class AudioFileReader; +class AudioFileWriter; + +class AudioInstrumentMixer : public AudioThread +{ +public: + typedef std::vector<RunnablePluginInstance *> PluginList; + typedef std::map<InstrumentId, PluginList> PluginMap; + typedef std::map<InstrumentId, RunnablePluginInstance *> SynthPluginMap; + + AudioInstrumentMixer(SoundDriver *driver, + AudioFileReader *fileReader, + unsigned int sampleRate, + unsigned int blockSize); + + virtual ~AudioInstrumentMixer(); + + void kick(bool wantLock = true); + + void setBussMixer(AudioBussMixer *mixer) { m_bussMixer = mixer; } + + void setPlugin(InstrumentId id, int position, QString identifier); + void removePlugin(InstrumentId id, int position); + void removeAllPlugins(); + + void setPluginPortValue(InstrumentId id, int position, + unsigned int port, float value); + float getPluginPortValue(InstrumentId id, int position, + unsigned int port); + + void setPluginBypass(InstrumentId, int position, bool bypass); + + QStringList getPluginPrograms(InstrumentId, int); + QString getPluginProgram(InstrumentId, int); + QString getPluginProgram(InstrumentId, int, int, int); + unsigned long getPluginProgram(InstrumentId, int, QString); + void setPluginProgram(InstrumentId, int, QString); + + QString configurePlugin(InstrumentId, int, QString, QString); + + void resetAllPlugins(bool discardEvents = false); + void discardPluginEvents(); + void destroyAllPlugins(); + + RunnablePluginInstance *getSynthPlugin(InstrumentId id) { return m_synths[id]; } + + /** + * Return the plugins intended for a particular buss. (By coincidence, + * this will also work for instruments, but it's not to be relied on.) + * It's purely by historical accident that the instrument mixer happens + * to hold buss plugins as well -- this could do with being refactored. + */ + PluginList &getBussPlugins(unsigned int bussId) { return m_plugins[bussId]; } + + /** + * Return the total of the plugin latencies for a given instrument + * or buss id. + */ + size_t getPluginLatency(unsigned int id); + + /** + * Prebuffer. This should be called only when the transport is + * not running. + */ + void fillBuffers(const RealTime ¤tTime); + + /** + * Ensure plugins etc have enough buffers. This is also done by + * fillBuffers and only needs to be called here if the extra work + * involved in fillBuffers is not desirable. + */ + void allocateBuffers(); + + /** + * Empty and discard buffer contents. + */ + void emptyBuffers(RealTime currentTime = RealTime::zeroTime); + + /** + * An instrument is "empty" if it has no audio files, synths or + * plugins assigned to it, and so cannot generate sound. Empty + * instruments can safely be ignored during playback. + */ + bool isInstrumentEmpty(InstrumentId id) { + return m_bufferMap[id].empty; + } + + /** + * An instrument is "dormant" if every readable sample on every + * one of its buffers is zero. Dormant instruments can safely be + * skipped rather than mixed during playback, but they should not + * be ignored (unless also empty). + */ + bool isInstrumentDormant(InstrumentId id) { + return m_bufferMap[id].dormant; + } + + /** + * We always have at least two channels (and hence buffers) by + * this point, because even on a mono instrument we still have a + * Pan setting which will have been applied by the time we get to + * these buffers. + */ + RingBuffer<sample_t, 2> *getRingBuffer(InstrumentId id, unsigned int channel) { + if (channel < m_bufferMap[id].buffers.size()) { + return m_bufferMap[id].buffers[channel]; + } else { + return 0; + } + } + + /// For call from MappedStudio. Pan is in range -100.0 -> 100.0 + void setInstrumentLevels(InstrumentId instrument, float dB, float pan); + + /// For call regularly from anywhere in a non-RT thread + void updateInstrumentMuteStates(); + +protected: + virtual void threadRun(); + + virtual int getPriority() { return 3; } + + void processBlocks(bool &readSomething); + void processEmptyBlocks(InstrumentId id); + bool processBlock(InstrumentId id, PlayableAudioFile **, size_t, bool &readSomething); + void generateBuffers(); + + AudioFileReader *m_fileReader; + AudioBussMixer *m_bussMixer; + unsigned int m_blockSize; + + // The plugin data structures will all be pre-sized and so of + // fixed size during normal run time; this will allow us to add + // and edit plugins without locking. + RunnablePluginInstance *getPluginInstance(InstrumentId, int); + PluginMap m_plugins; + SynthPluginMap m_synths; + + // maintain the same number of these as the maximum number of + // channels on any audio instrument + std::vector<sample_t *> m_processBuffers; + + struct BufferRec + { + BufferRec() : empty(true), dormant(true), zeroFrames(0), + filledTo(RealTime::zeroTime), channels(2), + buffers(), gainLeft(0.0), gainRight(0.0), volume(0.0), + muted(false) { } + ~BufferRec(); + + bool empty; + bool dormant; + size_t zeroFrames; + + RealTime filledTo; + size_t channels; + std::vector<RingBuffer<sample_t, 2> *> buffers; + + float gainLeft; + float gainRight; + float volume; + bool muted; + }; + + typedef std::map<InstrumentId, BufferRec> BufferMap; + BufferMap m_bufferMap; +}; + + +class AudioFileReader : public AudioThread +{ +public: + AudioFileReader(SoundDriver *driver, + unsigned int sampleRate); + + virtual ~AudioFileReader(); + + bool kick(bool wantLock = true); + + /** + * Prebuffer. This should be called only when the transport is + * not running. + */ + void fillBuffers(const RealTime ¤tTime); + +protected: + virtual void threadRun(); +}; + + +class AudioFileWriter : public AudioThread +{ +public: + AudioFileWriter(SoundDriver *driver, + unsigned int sampleRate); + + virtual ~AudioFileWriter(); + + void kick(bool wantLock = true); + + bool openRecordFile(InstrumentId id, const std::string &fileName); + bool closeRecordFile(InstrumentId id, AudioFileId &returnedId); + + bool haveRecordFileOpen(InstrumentId id); + bool haveRecordFilesOpen(); + + void write(InstrumentId id, const sample_t *, int channel, size_t samples); + +protected: + virtual void threadRun(); + + typedef std::pair<AudioFile *, RecordableAudioFile *> FilePair; + typedef std::map<InstrumentId, FilePair> FileMap; + FileMap m_files; +}; + + +} + +#endif + |