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/AlsaDriver.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/AlsaDriver.h')
-rw-r--r-- | src/sound/AlsaDriver.h | 561 |
1 files changed, 561 insertions, 0 deletions
diff --git a/src/sound/AlsaDriver.h b/src/sound/AlsaDriver.h new file mode 100644 index 0000000..e80e30f --- /dev/null +++ b/src/sound/AlsaDriver.h @@ -0,0 +1,561 @@ +// -*- c-indentation-style:"stroustrup" c-basic-offset: 4 -*- + +/* + 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. +*/ + +// Specialisation of SoundDriver to support ALSA (http://www.alsa-project.org) +// +// +#ifndef _ALSADRIVER_H_ +#define _ALSADRIVER_H_ + +#include <vector> +#include <set> +#include <map> + +#ifdef HAVE_ALSA + +#include <alsa/asoundlib.h> // ALSA + +#include "SoundDriver.h" +#include "Instrument.h" +#include "Device.h" +#include "AlsaPort.h" +#include "Scavenger.h" +#include "RunnablePluginInstance.h" + +#ifdef HAVE_LIBJACK +#include "JackDriver.h" +#endif + +namespace Rosegarden +{ + +class AlsaDriver : public SoundDriver +{ +public: + AlsaDriver(MappedStudio *studio); + virtual ~AlsaDriver(); + + // shutdown everything that's currently open + void shutdown(); + + virtual bool initialise(); + virtual void initialisePlayback(const RealTime &position); + virtual void stopPlayback(); + virtual void punchOut(); + virtual void resetPlayback(const RealTime &oldPosition, const RealTime &position); + virtual void allNotesOff(); + virtual void processNotesOff(const RealTime &time, bool now, bool everything = false); + + virtual RealTime getSequencerTime(); + + virtual MappedComposition *getMappedComposition(); + + virtual bool record(RecordStatus recordStatus, + const std::vector<InstrumentId> *armedInstruments = 0, + const std::vector<QString> *audioFileNames = 0); + + virtual void startClocks(); + virtual void startClocksApproved(); // called by JACK driver in sync mode + virtual void stopClocks(); + virtual bool areClocksRunning() const { return m_queueRunning; } + + virtual void processEventsOut(const MappedComposition &mC); + virtual void processEventsOut(const MappedComposition &mC, + const RealTime &sliceStart, + const RealTime &sliceEnd); + + // Return the sample rate + // + virtual unsigned int getSampleRate() const { +#ifdef HAVE_LIBJACK + if (m_jackDriver) return m_jackDriver->getSampleRate(); + else return 0; +#else + return 0; +#endif + } + + // Define here to catch this being reset + // + virtual void setMIDIClockInterval(RealTime interval); + + // initialise subsystems + // + bool initialiseMidi(); + void initialiseAudio(); + + // Some stuff to help us debug this + // + void getSystemInfo(); + void showQueueStatus(int queue); + + // Process pending + // + virtual void processPending(); + + // We can return audio control signals to the gui using MappedEvents. + // Meter levels or audio file completions can go in here. + // + void insertMappedEventForReturn(MappedEvent *mE); + + + virtual RealTime getAudioPlayLatency() { +#ifdef HAVE_LIBJACK + if (m_jackDriver) return m_jackDriver->getAudioPlayLatency(); +#endif + return RealTime::zeroTime; + } + + virtual RealTime getAudioRecordLatency() { +#ifdef HAVE_LIBJACK + if (m_jackDriver) return m_jackDriver->getAudioRecordLatency(); +#endif + return RealTime::zeroTime; + } + + virtual RealTime getInstrumentPlayLatency(InstrumentId id) { +#ifdef HAVE_LIBJACK + if (m_jackDriver) return m_jackDriver->getInstrumentPlayLatency(id); +#endif + return RealTime::zeroTime; + } + + virtual RealTime getMaximumPlayLatency() { +#ifdef HAVE_LIBJACK + if (m_jackDriver) return m_jackDriver->getMaximumPlayLatency(); +#endif + return RealTime::zeroTime; + } + + + // Plugin instance management + // + virtual void setPluginInstance(InstrumentId id, + QString identifier, + int position) { +#ifdef HAVE_LIBJACK + if (m_jackDriver) m_jackDriver->setPluginInstance(id, identifier, position); +#endif + } + + virtual void removePluginInstance(InstrumentId id, int position) { +#ifdef HAVE_LIBJACK + if (m_jackDriver) m_jackDriver->removePluginInstance(id, position); +#endif + } + + // Remove all plugin instances + // + virtual void removePluginInstances() { +#ifdef HAVE_LIBJACK + if (m_jackDriver) m_jackDriver->removePluginInstances(); +#endif + } + + virtual void setPluginInstancePortValue(InstrumentId id, + int position, + unsigned long portNumber, + float value) { +#ifdef HAVE_LIBJACK + if (m_jackDriver) m_jackDriver->setPluginInstancePortValue(id, position, portNumber, value); +#endif + } + + virtual float getPluginInstancePortValue(InstrumentId id, + int position, + unsigned long portNumber) { +#ifdef HAVE_LIBJACK + if (m_jackDriver) return m_jackDriver->getPluginInstancePortValue(id, position, portNumber); +#endif + return 0; + } + + virtual void setPluginInstanceBypass(InstrumentId id, + int position, + bool value) { +#ifdef HAVE_LIBJACK + if (m_jackDriver) m_jackDriver->setPluginInstanceBypass(id, position, value); +#endif + } + + virtual QStringList getPluginInstancePrograms(InstrumentId id, + int position) { +#ifdef HAVE_LIBJACK + if (m_jackDriver) return m_jackDriver->getPluginInstancePrograms(id, position); +#endif + return QStringList(); + } + + virtual QString getPluginInstanceProgram(InstrumentId id, + int position) { +#ifdef HAVE_LIBJACK + if (m_jackDriver) return m_jackDriver->getPluginInstanceProgram(id, position); +#endif + return QString(); + } + + virtual QString getPluginInstanceProgram(InstrumentId id, + int position, + int bank, + int program) { +#ifdef HAVE_LIBJACK + if (m_jackDriver) return m_jackDriver->getPluginInstanceProgram(id, position, bank, program); +#endif + return QString(); + } + + virtual unsigned long getPluginInstanceProgram(InstrumentId id, + int position, + QString name) { +#ifdef HAVE_LIBJACK + if (m_jackDriver) return m_jackDriver->getPluginInstanceProgram(id, position, name); +#endif + return 0; + } + + virtual void setPluginInstanceProgram(InstrumentId id, + int position, + QString program) { +#ifdef HAVE_LIBJACK + if (m_jackDriver) m_jackDriver->setPluginInstanceProgram(id, position, program); +#endif + } + + virtual QString configurePlugin(InstrumentId id, + int position, + QString key, + QString value) { +#ifdef HAVE_LIBJACK + if (m_jackDriver) return m_jackDriver->configurePlugin(id, position, key, value); +#endif + return QString(); + } + + virtual void setAudioBussLevels(int bussId, + float dB, + float pan) { +#ifdef HAVE_LIBJACK + if (m_jackDriver) m_jackDriver->setAudioBussLevels(bussId, dB, pan); +#endif + } + + virtual void setAudioInstrumentLevels(InstrumentId instrument, + float dB, + float pan) { +#ifdef HAVE_LIBJACK + if (m_jackDriver) m_jackDriver->setAudioInstrumentLevels(instrument, dB, pan); +#endif + } + + virtual void claimUnwantedPlugin(void *plugin); + virtual void scavengePlugins(); + + virtual bool checkForNewClients(); + + virtual void setLoop(const RealTime &loopStart, const RealTime &loopEnd); + + virtual void sleep(const RealTime &); + + // ----------------------- End of Virtuals ---------------------- + + // Create and send an MMC command + // + void sendMMC(MidiByte deviceId, + MidiByte instruction, + bool isCommand, + const std::string &data); + + // Check whether the given event is an MMC command we need to act on + // (and if so act on it) + // + bool testForMMCSysex(const snd_seq_event_t *event); + + // Create and enqueue a batch of MTC quarter-frame events + // + void insertMTCQFrames(RealTime sliceStart, RealTime sliceEnd); + + // Create and enqueue an MTC full-frame system exclusive event + // + void insertMTCFullFrame(RealTime time); + + // Parse and accept an incoming MTC quarter-frame event + // + void handleMTCQFrame(unsigned int data_byte, RealTime the_time); + + // Check whether the given event is an MTC sysex we need to act on + // (and if so act on it) + // + bool testForMTCSysex(const snd_seq_event_t *event); + + // Adjust the ALSA clock skew for MTC lock + // + void tweakSkewForMTC(int factor); + + // Recalibrate internal MTC factors + // + void calibrateMTC(); + + // Send a System message straight away + // + void sendSystemDirect(MidiByte command, int *arg); + + // Scheduled system message with arguments + // + void sendSystemQueued(MidiByte command, + const std::string &args, + const RealTime &time); + + // Set the record device + // + void setRecordDevice(DeviceId id, bool connectAction); + void unsetRecordDevices(); + + virtual bool canReconnect(Device::DeviceType type); + + virtual DeviceId addDevice(Device::DeviceType type, + MidiDevice::DeviceDirection direction); + virtual void removeDevice(DeviceId id); + virtual void renameDevice(DeviceId id, QString name); + + // Get available connections per device + // + virtual unsigned int getConnections(Device::DeviceType type, + MidiDevice::DeviceDirection direction); + virtual QString getConnection(Device::DeviceType type, + MidiDevice::DeviceDirection direction, + unsigned int connectionNo); + virtual void setConnection(DeviceId deviceId, QString connection); + virtual void setPlausibleConnection(DeviceId deviceId, QString connection); + + virtual unsigned int getTimers(); + virtual QString getTimer(unsigned int); + virtual QString getCurrentTimer(); + virtual void setCurrentTimer(QString); + + virtual void getAudioInstrumentNumbers(InstrumentId &audioInstrumentBase, + int &audioInstrumentCount) { + audioInstrumentBase = AudioInstrumentBase; +#ifdef HAVE_LIBJACK + audioInstrumentCount = AudioInstrumentCount; +#else + audioInstrumentCount = 0; +#endif + } + + virtual void getSoftSynthInstrumentNumbers(InstrumentId &ssInstrumentBase, + int &ssInstrumentCount) { + ssInstrumentBase = SoftSynthInstrumentBase; +#ifdef HAVE_DSSI + ssInstrumentCount = SoftSynthInstrumentCount; +#else + ssInstrumentCount = 0; +#endif + } + + virtual QString getStatusLog(); + + // To be called regularly from JACK driver when idle + void checkTimerSync(size_t frames); + + virtual void runTasks(); + + // Report a failure back to the GUI + // + virtual void reportFailure(MappedEvent::FailureCode code); + +protected: + typedef std::vector<AlsaPortDescription *> AlsaPortList; + + ClientPortPair getFirstDestination(bool duplex); + ClientPortPair getPairForMappedInstrument(InstrumentId id); + int getOutputPortForMappedInstrument(InstrumentId id); + std::map<unsigned int, std::map<unsigned int, MappedEvent*> > m_noteOnMap; + + /** + * Bring m_alsaPorts up-to-date; if newPorts is non-null, also + * return the new ports (not previously in m_alsaPorts) through it + */ + virtual void generatePortList(AlsaPortList *newPorts = 0); + virtual void generateInstruments(); + + virtual void generateTimerList(); + virtual std::string getAutoTimer(bool &wantTimerChecks); + + void addInstrumentsForDevice(MappedDevice *device); + MappedDevice *createMidiDevice(AlsaPortDescription *, + MidiDevice::DeviceDirection); + + virtual void processMidiOut(const MappedComposition &mC, + const RealTime &sliceStart, + const RealTime &sliceEnd); + + virtual void processSoftSynthEventOut(InstrumentId id, + const snd_seq_event_t *event, + bool now); + + virtual bool isRecording(AlsaPortDescription *port); + + virtual void processAudioQueue(bool /* now */) { } + + virtual void setConnectionToDevice(MappedDevice &device, QString connection); + virtual void setConnectionToDevice(MappedDevice &device, QString connection, + const ClientPortPair &pair); + +private: + RealTime getAlsaTime(); + + // Locally convenient to control our devices + // + void sendDeviceController(DeviceId device, + MidiByte byte1, + MidiByte byte2); + + int checkAlsaError(int rc, const char *message); + + AlsaPortList m_alsaPorts; + + // ALSA MIDI/Sequencer stuff + // + snd_seq_t *m_midiHandle; + int m_client; + + int m_inputPort; + + typedef std::map<DeviceId, int> DeviceIntMap; + DeviceIntMap m_outputPorts; + + int m_syncOutputPort; + int m_controllerPort; + + int m_queue; + int m_maxClients; + int m_maxPorts; + int m_maxQueues; + + // Because this can fail even if the driver's up (if + // another service is using the port say) + // + bool m_midiInputPortConnected; + + bool m_midiSyncAutoConnect; + + RealTime m_alsaPlayStartTime; + RealTime m_alsaRecordStartTime; + + RealTime m_loopStartTime; + RealTime m_loopEndTime; + + // MIDI Time Code handling: + + unsigned int m_eat_mtc; + // Received/emitted MTC data breakdown: + RealTime m_mtcReceiveTime; + RealTime m_mtcEncodedTime; + int m_mtcFrames; + int m_mtcSeconds; + int m_mtcMinutes; + int m_mtcHours; + int m_mtcSMPTEType; + + // Calculated MTC factors: + int m_mtcFirstTime; + RealTime m_mtcLastEncoded; + RealTime m_mtcLastReceive; + long long int m_mtcSigmaE; + long long int m_mtcSigmaC; + unsigned int m_mtcSkew; + + bool m_looping; + + bool m_haveShutdown; + +#ifdef HAVE_LIBJACK + JackDriver *m_jackDriver; +#endif + + Scavenger<RunnablePluginInstance> m_pluginScavenger; + + //!!! -- hoist to SoundDriver w/setter? + typedef std::set<InstrumentId> InstrumentSet; + InstrumentSet m_recordingInstruments; + + typedef std::map<DeviceId, ClientPortPair> DevicePortMap; + DevicePortMap m_devicePortMap; + + typedef std::map<ClientPortPair, DeviceId> PortDeviceMap; + PortDeviceMap m_suspendedPortMap; + + std::string getPortName(ClientPortPair port); + ClientPortPair getPortByName(std::string name); + + DeviceId getSpareDeviceId(); + + struct AlsaTimerInfo { + int clas; + int sclas; + int card; + int device; + int subdevice; + std::string name; + long resolution; + }; + std::vector<AlsaTimerInfo> m_timers; + std::string m_currentTimer; + + // This auxiliary queue is here as a hack, to avoid stuck notes if + // resetting playback while a note-off is currently in the ALSA + // queue. When playback is reset by ffwd or rewind etc, we drop + // all the queued events (which is generally what is desired, + // except for note offs) and reset the queue timer (so the note + // offs would have the wrong time stamps even if we hadn't dropped + // them). Thus, we need to re-send any recent note offs before + // continuing. This queue records which note offs have been + // added to the ALSA queue recently. + // + NoteOffQueue m_recentNoteOffs; + void pushRecentNoteOffs(); // move from recent to normal queue after reset + void cropRecentNoteOffs(const RealTime &t); // remove old note offs + void weedRecentNoteOffs(unsigned int pitch, MidiByte channel, + InstrumentId instrument); // on subsequent note on + + bool m_queueRunning; + + bool m_portCheckNeeded; + + enum { NeedNoJackStart, NeedJackReposition, NeedJackStart } m_needJackStart; + + bool m_doTimerChecks; + bool m_firstTimerCheck; + double m_timerRatio; + bool m_timerRatioCalculated; + + std::string getAlsaModuleVersionString(); + std::string getKernelVersionString(); + void extractVersion(std::string vstr, int &major, int &minor, int &subminor, std::string &suffix); + bool versionIsAtLeast(std::string vstr, int major, int minor, int subminor); +}; + +} + +#endif // HAVE_ALSA + +#endif // _ALSADRIVER_H_ + |