You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
529 lines
17 KiB
529 lines
17 KiB
/*
|
|
Rosegarden
|
|
A sequencer and musical notation editor.
|
|
|
|
This program is Copyright 2000-2008
|
|
Guillaume Laurent <glaurent@telegraph-road.org>,
|
|
Chris Cannam <cannam@all-day-breakfast.com>,
|
|
Richard Bown <bownie@bownie.com>
|
|
|
|
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 <tqstringlist.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<TQString> *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,
|
|
TQString 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 TQStringList getPluginInstancePrograms(InstrumentId id,
|
|
int position) = 0;
|
|
|
|
virtual TQString getPluginInstanceProgram(InstrumentId id,
|
|
int position) = 0;
|
|
|
|
virtual TQString getPluginInstanceProgram(InstrumentId id,
|
|
int position,
|
|
int bank,
|
|
int program) = 0;
|
|
|
|
virtual unsigned long getPluginInstanceProgram(InstrumentId id,
|
|
int position,
|
|
TQString name) = 0;
|
|
|
|
virtual void setPluginInstanceProgram(InstrumentId id,
|
|
int position,
|
|
TQString program) = 0;
|
|
|
|
virtual TQString configurePlugin(InstrumentId id,
|
|
int position,
|
|
TQString key,
|
|
TQString 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 TQString 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, TQString) { }
|
|
|
|
virtual unsigned int getConnections(Device::DeviceType,
|
|
MidiDevice::DeviceDirection) { return 0; }
|
|
virtual TQString getConnection(Device::DeviceType,
|
|
MidiDevice::DeviceDirection,
|
|
unsigned int) { return ""; }
|
|
virtual void setConnection(DeviceId, TQString) { }
|
|
virtual void setPlausibleConnection(DeviceId id, TQString c) { setConnection(id, c); }
|
|
|
|
virtual unsigned int getTimers() { return 0; }
|
|
virtual TQString getTimer(unsigned int) { return ""; }
|
|
virtual TQString getCurrentTimer() { return ""; }
|
|
virtual void setCurrentTimer(TQString) { }
|
|
|
|
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_
|
|
|