diff options
Diffstat (limited to 'src/sound/SoundDriver.h')
-rw-r--r-- | src/sound/SoundDriver.h | 529 |
1 files changed, 529 insertions, 0 deletions
diff --git a/src/sound/SoundDriver.h b/src/sound/SoundDriver.h new file mode 100644 index 0000000..fabbaef --- /dev/null +++ b/src/sound/SoundDriver.h @@ -0,0 +1,529 @@ +// -*- c-indentation-style:"stroustrup" 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. +*/ + +#include <string> +#include <vector> +#include <list> +#include <qstringlist.h> + +#include "Device.h" +#include "MappedComposition.h" +#include "MappedInstrument.h" +#include "MappedDevice.h" +#include "SequencerDataBlock.h" +#include "PlayableAudioFile.h" +#include "Scavenger.h" +#include "RIFFAudioFile.h" // for SubFormat enum + +// Abstract base to support SoundDrivers, such as ALSA. +// +// This base class provides the generic driver support for +// these drivers with the Sequencer class owning an instance +// of a sub class of this class and directing it and required +// by the rosegardensequencer itself. +// +// + +#ifndef _SOUNDDRIVER_H_ +#define _SOUNDDRIVER_H_ + +namespace Rosegarden +{ + +// Current recording status - whether we're monitoring anything +// or recording. +// +typedef enum +{ + RECORD_OFF, + RECORD_ON, +} RecordStatus; + + +// Status of a SoundDriver - whether we're got an audio and +// MIDI subsystem or not. This is reported right up to the +// gui. +// +typedef enum +{ + NO_DRIVER = 0x00, // Nothing's OK + AUDIO_OK = 0x01, // AUDIO's OK + MIDI_OK = 0x02, // MIDI's OK + VERSION_OK = 0x04 // GUI and sequencer versions match +} SoundDriverStatus; + + +// Used for MMC and MTC, not for JACK transport +// +typedef enum +{ + TRANSPORT_OFF, + TRANSPORT_MASTER, + TRANSPORT_SLAVE +} TransportSyncStatus; + + +// The NoteOffQueue holds a time ordered set of +// pending MIDI NOTE OFF events. +// +class NoteOffEvent +{ +public: + NoteOffEvent() {;} + NoteOffEvent(const RealTime &realTime, + unsigned int pitch, + MidiByte channel, + InstrumentId instrument): + m_realTime(realTime), + m_pitch(pitch), + m_channel(channel), + m_instrument(instrument) {;} + ~NoteOffEvent() {;} + + struct NoteOffEventCmp + { + bool operator()(NoteOffEvent *nO1, NoteOffEvent *nO2) + { + return nO1->getRealTime() < nO2->getRealTime(); + } + }; + + void setRealTime(const RealTime &time) { m_realTime = time; } + RealTime getRealTime() const { return m_realTime; } + + MidiByte getPitch() const { return m_pitch; } + MidiByte getChannel() const { return m_channel; } + InstrumentId getInstrument() const { return m_instrument; } + +private: + RealTime m_realTime; + MidiByte m_pitch; + MidiByte m_channel; + InstrumentId m_instrument; + +}; + + +// The queue itself +// +class NoteOffQueue : public std::multiset<NoteOffEvent *, + NoteOffEvent::NoteOffEventCmp> +{ +public: + NoteOffQueue() {;} + ~NoteOffQueue() {;} +private: +}; + + +class MappedStudio; +class ExternalTransport; +class AudioPlayQueue; + +typedef std::vector<PlayableAudioFile *> PlayableAudioFileList; + +// The abstract SoundDriver +// +// +class SoundDriver +{ +public: + SoundDriver(MappedStudio *studio, const std::string &name); + virtual ~SoundDriver(); + + virtual bool initialise() = 0; + virtual void shutdown() { } + + virtual void initialisePlayback(const RealTime &position) = 0; + virtual void stopPlayback() = 0; + virtual void punchOut() = 0; // stop recording, continue playing + virtual void resetPlayback(const RealTime &oldPosition, const RealTime &position) = 0; + virtual void allNotesOff() = 0; + + virtual RealTime getSequencerTime() = 0; + + virtual MappedComposition *getMappedComposition() = 0; + + virtual void startClocks() { } + virtual void stopClocks() { } + + // Process some asynchronous events + // + virtual void processEventsOut(const MappedComposition &mC) = 0; + + // Process some scheduled events on the output queue. The + // slice times are here so that the driver can interleave + // note-off events as appropriate. + // + virtual void processEventsOut(const MappedComposition &mC, + const RealTime &sliceStart, + const RealTime &sliceEnd) = 0; + + // Activate a recording state. armedInstruments and audioFileNames + // can be NULL if no audio tracks recording. + // + virtual bool record(RecordStatus recordStatus, + const std::vector<InstrumentId> *armedInstruments = 0, + const std::vector<QString> *audioFileNames = 0) = 0; + + // Process anything that's pending + // + virtual void processPending() = 0; + + // Get the driver's operating sample rate + // + virtual unsigned int getSampleRate() const = 0; + + // Plugin instance management + // + virtual void setPluginInstance(InstrumentId id, + QString identifier, + int position) = 0; + + virtual void removePluginInstance(InstrumentId id, + int position) = 0; + + // Clear down and remove all plugin instances + // + virtual void removePluginInstances() = 0; + + virtual void setPluginInstancePortValue(InstrumentId id, + int position, + unsigned long portNumber, + float value) = 0; + + virtual float getPluginInstancePortValue(InstrumentId id, + int position, + unsigned long portNumber) = 0; + + virtual void setPluginInstanceBypass(InstrumentId id, + int position, + bool value) = 0; + + virtual QStringList getPluginInstancePrograms(InstrumentId id, + int position) = 0; + + virtual QString getPluginInstanceProgram(InstrumentId id, + int position) = 0; + + virtual QString getPluginInstanceProgram(InstrumentId id, + int position, + int bank, + int program) = 0; + + virtual unsigned long getPluginInstanceProgram(InstrumentId id, + int position, + QString name) = 0; + + virtual void setPluginInstanceProgram(InstrumentId id, + int position, + QString program) = 0; + + virtual QString configurePlugin(InstrumentId id, + int position, + QString key, + QString value) = 0; + + virtual void setAudioBussLevels(int bussId, + float dB, + float pan) = 0; + + virtual void setAudioInstrumentLevels(InstrumentId id, + float dB, + float pan) = 0; + + // Poll for new clients (for new Devices/Instruments) + // + virtual bool checkForNewClients() = 0; + + // Set a loop position at the driver (used for transport) + // + virtual void setLoop(const RealTime &loopStart, const RealTime &loopEnd) + = 0; + + virtual void sleep(const RealTime &rt); + + virtual QString getStatusLog() { return ""; } + + // Mapped Instruments + // + void setMappedInstrument(MappedInstrument *mI); + MappedInstrument* getMappedInstrument(InstrumentId id); + + // Return the current status of the driver + // + unsigned int getStatus() const { return m_driverStatus; } + + // Are we playing? + // + bool isPlaying() const { return m_playing; } + + // Are we counting? By default a subclass probably wants to + // return true, if it doesn't know better. + // + virtual bool areClocksRunning() const = 0; + + RealTime getStartPosition() const { return m_playStartPosition; } + RecordStatus getRecordStatus() const { return m_recordStatus; } + + // Return a MappedDevice full of the Instrument mappings + // that the driver has discovered. The gui can then use + // this list (complete with names) to generate its proper + // Instruments under the MidiDevice and AudioDevice. + // + MappedDevice getMappedDevice(DeviceId id); + + // Return the number of devices we've found + // + unsigned int getDevices(); + + virtual bool canReconnect(Device::DeviceType) { return false; } + + virtual DeviceId addDevice(Device::DeviceType, + MidiDevice::DeviceDirection) { + return Device::NO_DEVICE; + } + virtual void removeDevice(DeviceId) { } + virtual void renameDevice(DeviceId, QString) { } + + virtual unsigned int getConnections(Device::DeviceType, + MidiDevice::DeviceDirection) { return 0; } + virtual QString getConnection(Device::DeviceType, + MidiDevice::DeviceDirection, + unsigned int) { return ""; } + virtual void setConnection(DeviceId, QString) { } + virtual void setPlausibleConnection(DeviceId id, QString c) { setConnection(id, c); } + + virtual unsigned int getTimers() { return 0; } + virtual QString getTimer(unsigned int) { return ""; } + virtual QString getCurrentTimer() { return ""; } + virtual void setCurrentTimer(QString) { } + + virtual void getAudioInstrumentNumbers(InstrumentId &, int &) = 0; + virtual void getSoftSynthInstrumentNumbers(InstrumentId &, int &) = 0; + + // Plugin management -- SoundDrivers should maintain a plugin + // scavenger which the audio process code can use for defunct + // plugins. Ownership of plugin is passed to the SoundDriver. + // + virtual void claimUnwantedPlugin(void *plugin) = 0; + + // This causes all scavenged plugins to be destroyed. It + // should only be called in non-RT contexts. + // + virtual void scavengePlugins() = 0; + + // Handle audio file references + // + void clearAudioFiles(); + bool addAudioFile(const std::string &fileName, unsigned int id); + bool removeAudioFile(unsigned int id); + + void initialiseAudioQueue(const std::vector<MappedEvent> &audioEvents); + void clearAudioQueue(); + const AudioPlayQueue *getAudioQueue() const; + + RIFFAudioFile::SubFormat getAudioRecFileFormat() const { return m_audioRecFileFormat; } + + + // Latencies + // + virtual RealTime getAudioPlayLatency() { return RealTime::zeroTime; } + virtual RealTime getAudioRecordLatency() { return RealTime::zeroTime; } + virtual RealTime getInstrumentPlayLatency(InstrumentId) { return RealTime::zeroTime; } + virtual RealTime getMaximumPlayLatency() { return RealTime::zeroTime; } + + // Buffer sizes + // + void setAudioBufferSizes(RealTime mix, RealTime read, RealTime write, + int smallFileSize) { + m_audioMixBufferLength = mix; + m_audioReadBufferLength = read; + m_audioWriteBufferLength = write; + m_smallFileSize = smallFileSize; + } + + RealTime getAudioMixBufferLength() { return m_audioMixBufferLength; } + RealTime getAudioReadBufferLength() { return m_audioReadBufferLength; } + RealTime getAudioWriteBufferLength() { return m_audioWriteBufferLength; } + int getSmallFileSize() { return m_smallFileSize; } + + void setLowLatencyMode(bool ll) { m_lowLatencyMode = ll; } + bool getLowLatencyMode() const { return m_lowLatencyMode; } + + // Cancel the playback of an audio file - either by instrument and audio file id + // or by audio segment id. + // + void cancelAudioFile(MappedEvent *mE); + + // Studio linkage + // + MappedStudio* getMappedStudio() { return m_studio; } + void setMappedStudio(MappedStudio *studio) { m_studio = studio; } + + // Modify MIDI record device + // + void setMidiRecordDevice(DeviceId id) { m_midiRecordDevice = id; } + DeviceId getMIDIRecordDevice() const { return m_midiRecordDevice; } + + // MIDI Realtime Sync setting + // + TransportSyncStatus getMIDISyncStatus() const { return m_midiSyncStatus; } + void setMIDISyncStatus(TransportSyncStatus status) { m_midiSyncStatus = status; } + + // MMC master/slave setting + // + TransportSyncStatus getMMCStatus() const { return m_mmcStatus; } + void setMMCStatus(TransportSyncStatus status) { m_mmcStatus = status; } + + // MTC master/slave setting + // + TransportSyncStatus getMTCStatus() const { return m_mtcStatus; } + void setMTCStatus(TransportSyncStatus status) { m_mtcStatus = status; } + + // MMC Id + // + int getMMCId() const { return ((int)(m_mmcId)); } + void setMMCId(int id) { m_mmcId = (MidiByte)(id); } + + // Set MIDI clock interval - allow redefinition above to ensure + // we handle this reset correctly. + // + virtual void setMIDIClockInterval(RealTime interval) + { m_midiClockInterval = interval; } + + // Get and set the mapper which may optionally be used to + // store recording levels etc for communication back to the GUI. + // (If a subclass wants this and finds it's not there, it should + // simply continue without.) + // + SequencerDataBlock *getSequencerDataBlock() { return m_sequencerDataBlock; } + void setSequencerDataBlock(SequencerDataBlock *d) { m_sequencerDataBlock = d; } + + ExternalTransport *getExternalTransportControl() const { + return m_externalTransport; + } + void setExternalTransportControl(ExternalTransport *transport) { + m_externalTransport = transport; + } + + // Do any bits and bobs of work that need to be done continuously + // (this is called repeatedly whether playing or not). + // + virtual void runTasks() { } + + // Report a failure back to the GUI - ideally. Default does nothing. + // + virtual void reportFailure(MappedEvent::FailureCode) { } + +protected: + // Helper functions to be implemented by subclasses + // + virtual void processMidiOut(const MappedComposition &mC, + const RealTime &sliceStart, + const RealTime &sliceEnd) = 0; + virtual void generateInstruments() = 0; + + // Audio + // + AudioFile* getAudioFile(unsigned int id); + + std::string m_name; + unsigned int m_driverStatus; + RealTime m_playStartPosition; + bool m_startPlayback; + bool m_playing; + + // MIDI Note-off handling + // + NoteOffQueue m_noteOffQueue; + + // This is our driver's own list of MappedInstruments and MappedDevices. + // These are uncoupled at this level - the Instruments and Devices float + // free and only index each other - the Devices hold information only like + // name, id and if the device is duplex capable. + // + typedef std::vector<MappedInstrument*> MappedInstrumentList; + MappedInstrumentList m_instruments; + + typedef std::vector<MappedDevice*> MappedDeviceList; + MappedDeviceList m_devices; + + DeviceId m_midiRecordDevice; + + MappedComposition m_recordComposition; + MappedComposition m_returnComposition; + RecordStatus m_recordStatus; + + + InstrumentId m_midiRunningId; + InstrumentId m_audioRunningId; + + // Subclass _MUST_ scavenge this regularly: + Scavenger<AudioPlayQueue> m_audioQueueScavenger; + AudioPlayQueue *m_audioQueue; + + // A list of AudioFiles that we can play. + // + std::vector<AudioFile*> m_audioFiles; + + RealTime m_audioMixBufferLength; + RealTime m_audioReadBufferLength; + RealTime m_audioWriteBufferLength; + int m_smallFileSize; + bool m_lowLatencyMode; + + RIFFAudioFile::SubFormat m_audioRecFileFormat; + + // Virtual studio hook + // + MappedStudio *m_studio; + + // Sequencer data block for communication back to GUI + // + SequencerDataBlock *m_sequencerDataBlock; + + // Controller to make externally originated transport requests on + // + ExternalTransport *m_externalTransport; + + // MMC and MTC status and ID + // + TransportSyncStatus m_midiSyncStatus; + TransportSyncStatus m_mmcStatus; + TransportSyncStatus m_mtcStatus; + MidiByte m_mmcId; // device id + + // MIDI clock interval + // + bool m_midiClockEnabled; + RealTime m_midiClockInterval; + RealTime m_midiClockSendTime; + + // MIDI Song Position pointer + // + long m_midiSongPositionPointer; + +}; + +} + +#endif // _SOUNDDRIVER_H_ + |