/* Rosegarden A sequencer and musical notation editor. This program is Copyright 2000-2008 Guillaume Laurent , Chris Cannam , Richard Bown 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 #include "Composition.h" // for RealTime #include "Event.h" #ifndef _MAPPEDEVENT_H_ #define _MAPPEDEVENT_H_ // Used as a transformation stage between Composition, Events and output // at the Sequencer this class and MidiComposition eliminate the notion // of the Segment and Track for ease of Event access. The MappedEvents // are ready for playing or routing through an Instrument or Effects // boxes. // // MappedEvents can also represent instructions for playback of audio // samples - if the m_type is Audio then the sequencer will attempt to // map the Pitch (m_data1) to the audio id. Note that this limits us // to 256 audio files in the Composition unless we use a different // parameter for storing these IDs. // // The MappedEvent/Instrument relationship is interesting - we don't // want to duplicate the entire Instrument at the Sequencer level as // it'd be messy and unnecessary. Instead we use a MappedInstrument // which is just a very cut down Sequencer-side version of an Instrument. // // Some of these Events are unidirectional, some are bidirectional - // that is they only have a meaning in one direction (they are still // legal at either end). They are broadcast in both directions using // the "getSequencerSlice" and "processAsync/Recorded" interfaces on // which the control messages can piggyback and eventually stripped out. // namespace Rosegarden { class MappedEvent; class DataBlockRepository { public: friend class MappedEvent; typedef unsigned long blockid; static DataBlockRepository* getInstance(); static std::string getDataBlockForEvent(MappedEvent*); static void setDataBlockForEvent(MappedEvent*, const std::string&); /** * Clear all block files */ static void clear(); bool hasDataBlock(blockid); protected: DataBlockRepository(); std::string getDataBlock(blockid); void addDataByteForEvent(MidiByte byte, MappedEvent*); void addDataStringForEvent(const std::string&, MappedEvent*); blockid registerDataBlock(const std::string&); void unregisterDataBlock(blockid); void registerDataBlockForEvent(const std::string&, MappedEvent*); void unregisterDataBlockForEvent(MappedEvent*); //--------------- Data members --------------------------------- static DataBlockRepository* m_instance; }; class MappedEvent { public: typedef enum { // INVALID // InvalidMappedEvent = 0, // Keep the MidiNotes bit flaggable so that filtering works // MidiNote = 1 << 0, MidiNoteOneShot = 1 << 1, // doesn't need NOTE OFFs MidiProgramChange = 1 << 2, MidiKeyPressure = 1 << 3, MidiChannelPressure = 1 << 4, MidiPitchBend = 1 << 5, MidiController = 1 << 6, MidiSystemMessage = 1 << 7, // Sent from the gui to play an audio file Audio = 1 << 8, // Sent from gui to cancel playing an audio file AudioCancel = 1 << 9, // Sent to the gui with audio level on Instrument AudioLevel = 1 << 10, // Sent to the gui to inform an audio file stopped AudioStopped = 1 << 11, // The gui is clear to generate a preview for a new audio file AudioGeneratePreview = 1 << 12, // Update Instruments - new ALSA client detected SystemUpdateInstruments = 1 << 13, // Set RG as JACK master/slave SystemJackTransport = 1 << 14, // Set RG as MMC master/slave SystemMMCTransport = 1 << 15, // Set System Messages and MIDI Clock SystemMIDIClock = 1 << 16, // Set Record device SystemRecordDevice = 1 << 17, // Set Metronome device SystemMetronomeDevice = 1 << 18, // Set Audio inputs/outputs: data1 num inputs, data2 num submasters SystemAudioPortCounts = 1 << 19, // Set whether we create various Audio ports (data1 is an AudioOutMask) SystemAudioPorts = 1 << 20, // Some failure has occurred: data1 contains FailureCode SystemFailure = 1 << 21, // Time sig. event (from time sig. composition reference segment) TimeSignature = 1 << 22, // Tempo event (from tempo composition reference segment) Tempo = 1 << 23, // Panic function Panic = 1 << 24, // Set RG as MTC master/slave SystemMTCTransport = 1 << 25, // Auto-connect sync outputs SystemMIDISyncAuto = 1 << 26, // File format used for audio recording (data1 is 0=PCM,1=float) SystemAudioFileFormat = 1 << 27 } MappedEventType; typedef enum { // These values are OR'd to produce the data2 field in a // SystemAudioPorts event. FaderOuts = 1 << 0, SubmasterOuts = 1 << 1 } MappedEventAudioOutMask; typedef enum { // JACK is having some xruns - warn the user maybe FailureXRuns = 0, // JACK has died or kicked us out FailureJackDied = 1, // Audio subsystem failed to read from disc fast enough FailureDiscUnderrun = 2, // Audio subsystem failed to write to disc fast enough FailureDiscOverrun = 3, // Audio subsystem failed to mix busses fast enough FailureBussMixUnderrun = 4, // Audio subsystem failed to mix instruments fast enough FailureMixUnderrun = 5, // Using a timer that has too low a resolution (e.g. 100Hz system timer) WarningImpreciseTimer = 6, // Too much CPU time spent in audio processing -- risk of xruns and lockup FailureCPUOverload = 7, // JACK kicked us out, but we've reconnected FailureJackRestart = 8, // JACK kicked us out, and now the reconnection has failed FailureJackRestartFailed = 9, // A necessary ALSA call has returned an error code FailureALSACallFailed = 10, // Using a timer that has too low a resolution, but RTC might work WarningImpreciseTimerTryRTC = 11, } FailureCode; MappedEvent(): m_trackId(0), m_instrument(0), m_type(MidiNote), m_data1(0), m_data2(0), m_eventTime(0, 0), m_duration(0, 0), m_audioStartMarker(0, 0), m_dataBlockId(0), m_isPersistent(false), m_runtimeSegmentId(-1), m_autoFade(false), m_fadeInTime(RealTime::zeroTime), m_fadeOutTime(RealTime::zeroTime), m_recordedChannel(0), m_recordedDevice(0) {} // Construct from Events to Internal (MIDI) type MappedEvent // MappedEvent(const Event &e); // Another Internal constructor from Events MappedEvent(InstrumentId id, const Event &e, const RealTime &eventTime, const RealTime &duration); // A general MappedEvent constructor for any MappedEvent type // MappedEvent(InstrumentId id, MappedEventType type, MidiByte pitch, MidiByte velocity, const RealTime &absTime, const RealTime &duration, const RealTime &audioStartMarker): m_trackId(0), m_instrument(id), m_type(type), m_data1(pitch), m_data2(velocity), m_eventTime(absTime), m_duration(duration), m_audioStartMarker(audioStartMarker), m_dataBlockId(0), m_isPersistent(false), m_runtimeSegmentId(-1), m_autoFade(false), m_fadeInTime(RealTime::zeroTime), m_fadeOutTime(RealTime::zeroTime), m_recordedChannel(0), m_recordedDevice(0) {} // Audio MappedEvent shortcut constructor // MappedEvent(InstrumentId id, unsigned short audioID, const RealTime &eventTime, const RealTime &duration, const RealTime &audioStartMarker): m_trackId(0), m_instrument(id), m_type(Audio), m_data1(audioID % 256), m_data2(audioID / 256), m_eventTime(eventTime), m_duration(duration), m_audioStartMarker(audioStartMarker), m_dataBlockId(0), m_isPersistent(false), m_runtimeSegmentId(-1), m_autoFade(false), m_fadeInTime(RealTime::zeroTime), m_fadeOutTime(RealTime::zeroTime), m_recordedChannel(0), m_recordedDevice(0) {} // More generalised MIDI event containers for // large and small events (one param, two param) // MappedEvent(InstrumentId id, MappedEventType type, MidiByte data1, MidiByte data2): m_trackId(0), m_instrument(id), m_type(type), m_data1(data1), m_data2(data2), m_eventTime(RealTime(0, 0)), m_duration(RealTime(0, 0)), m_audioStartMarker(RealTime(0, 0)), m_dataBlockId(0), m_isPersistent(false), m_runtimeSegmentId(-1), m_autoFade(false), m_fadeInTime(RealTime::zeroTime), m_fadeOutTime(RealTime::zeroTime), m_recordedChannel(0), m_recordedDevice(0) {} MappedEvent(InstrumentId id, MappedEventType type, MidiByte data1): m_trackId(0), m_instrument(id), m_type(type), m_data1(data1), m_data2(0), m_eventTime(RealTime(0, 0)), m_duration(RealTime(0, 0)), m_audioStartMarker(RealTime(0, 0)), m_dataBlockId(0), m_isPersistent(false), m_runtimeSegmentId(-1), m_autoFade(false), m_fadeInTime(RealTime::zeroTime), m_fadeOutTime(RealTime::zeroTime), m_recordedChannel(0), m_recordedDevice(0) {} // Construct SysExs say // MappedEvent(InstrumentId id, MappedEventType type): m_trackId(0), m_instrument(id), m_type(type), m_data1(0), m_data2(0), m_eventTime(RealTime(0, 0)), m_duration(RealTime(0, 0)), m_audioStartMarker(RealTime(0, 0)), m_dataBlockId(0), m_isPersistent(false), m_runtimeSegmentId(-1), m_autoFade(false), m_fadeInTime(RealTime::zeroTime), m_fadeOutTime(RealTime::zeroTime), m_recordedChannel(0), m_recordedDevice(0) {} // Copy constructor // // Fix for 674731 by Pedro Lopez-Cabanillas (20030531) MappedEvent(const MappedEvent &mE): m_trackId(mE.getTrackId()), m_instrument(mE.getInstrument()), m_type(mE.getType()), m_data1(mE.getData1()), m_data2(mE.getData2()), m_eventTime(mE.getEventTime()), m_duration(mE.getDuration()), m_audioStartMarker(mE.getAudioStartMarker()), m_dataBlockId(mE.getDataBlockId()), m_isPersistent(false), m_runtimeSegmentId(mE.getRuntimeSegmentId()), m_autoFade(mE.isAutoFading()), m_fadeInTime(mE.getFadeInTime()), m_fadeOutTime(mE.getFadeOutTime()), m_recordedChannel(mE.getRecordedChannel()), m_recordedDevice(mE.getRecordedDevice()) {} // Copy from pointer // Fix for 674731 by Pedro Lopez-Cabanillas (20030531) MappedEvent(MappedEvent *mE): m_trackId(mE->getTrackId()), m_instrument(mE->getInstrument()), m_type(mE->getType()), m_data1(mE->getData1()), m_data2(mE->getData2()), m_eventTime(mE->getEventTime()), m_duration(mE->getDuration()), m_audioStartMarker(mE->getAudioStartMarker()), m_dataBlockId(mE->getDataBlockId()), m_isPersistent(false), m_runtimeSegmentId(mE->getRuntimeSegmentId()), m_autoFade(mE->isAutoFading()), m_fadeInTime(mE->getFadeInTime()), m_fadeOutTime(mE->getFadeOutTime()), m_recordedChannel(mE->getRecordedChannel()), m_recordedDevice(mE->getRecordedDevice()) {} // Construct perhaps without initialising, for placement new or equivalent MappedEvent(bool initialise) { if (initialise) *this = MappedEvent(); } // Event time // void setEventTime(const RealTime &a) { m_eventTime = a; } RealTime getEventTime() const { return m_eventTime; } // Duration // void setDuration(const RealTime &d) { m_duration = d; } RealTime getDuration() const { return m_duration; } // Instrument void setInstrument(InstrumentId id) { m_instrument = id; } InstrumentId getInstrument() const { return m_instrument; } // Track void setTrackId(TrackId id) { m_trackId = id; } TrackId getTrackId() const { return m_trackId; } MidiByte getPitch() const { return m_data1; } // Keep pitch within MIDI limits // void setPitch(MidiByte p) { m_data1 = p; if (m_data1 > MidiMaxValue) m_data1 = MidiMaxValue; } void setVelocity(MidiByte v) { m_data2 = v; } MidiByte getVelocity() const { return m_data2; } // And the trendy names for them // MidiByte getData1() const { return m_data1; } MidiByte getData2() const { return m_data2; } void setData1(MidiByte d1) { m_data1 = d1; } void setData2(MidiByte d2) { m_data2 = d2; } void setAudioID(unsigned short id) { m_data1 = id % 256; m_data2 = id / 256; } int getAudioID() const { return m_data1 + 256 * m_data2; } // A sample doesn't have to be played from the beginning. When // passing an Audio event this value may be set to indicate from // where in the sample it should be played. Duration is measured // against total sounding length (not absolute position). // void setAudioStartMarker(const RealTime &aS) { m_audioStartMarker = aS; } RealTime getAudioStartMarker() const { return m_audioStartMarker; } MappedEventType getType() const { return m_type; } void setType(const MappedEventType &value) { m_type = value; } // Data block id // DataBlockRepository::blockid getDataBlockId() const { return m_dataBlockId; } void setDataBlockId(DataBlockRepository::blockid dataBlockId) { m_dataBlockId = dataBlockId; } // How MappedEvents are ordered in the MappedComposition // struct MappedEventCmp { bool operator()(const MappedEvent *mE1, const MappedEvent *mE2) const { return *mE1 < *mE2; } }; friend bool operator<(const MappedEvent &a, const MappedEvent &b); MappedEvent& operator=(const MappedEvent &mE); friend TQDataStream& operator>>(TQDataStream &dS, MappedEvent *mE); friend TQDataStream& operator<<(TQDataStream &dS, MappedEvent *mE); friend TQDataStream& operator>>(TQDataStream &dS, MappedEvent &mE); friend TQDataStream& operator<<(TQDataStream &dS, const MappedEvent &mE); /// Add a single byte to the event's datablock (for SysExs) void addDataByte(MidiByte byte); /// Add several bytes to the event's datablock void addDataString(const std::string& data); void setPersistent(bool value) { m_isPersistent = value; } bool isPersistent() const { return m_isPersistent; } /// Size of a MappedEvent in a stream static const size_t streamedSize; // The runtime segment id of an audio file // int getRuntimeSegmentId() const { return m_runtimeSegmentId; } void setRuntimeSegmentId(int id) { m_runtimeSegmentId = id; } bool isAutoFading() const { return m_autoFade; } void setAutoFade(bool value) { m_autoFade = value; } RealTime getFadeInTime() const { return m_fadeInTime; } void setFadeInTime(const RealTime &time) { m_fadeInTime = time; } RealTime getFadeOutTime() const { return m_fadeOutTime; } void setFadeOutTime(const RealTime &time) { m_fadeOutTime = time; } // Original event input channel as it was recorded // unsigned int getRecordedChannel() const { return m_recordedChannel; } void setRecordedChannel(const unsigned int channel) { m_recordedChannel = channel; } // Original event record device as it was recorded // unsigned int getRecordedDevice() const { return m_recordedDevice; } void setRecordedDevice(const unsigned int device) { m_recordedDevice = device; } private: TrackId m_trackId; InstrumentId m_instrument; MappedEventType m_type; MidiByte m_data1; MidiByte m_data2; RealTime m_eventTime; RealTime m_duration; RealTime m_audioStartMarker; // Use this when we want to store something in addition to the // other bytes in this type, e.g. System Exclusive. // DataBlockRepository::blockid m_dataBlockId; // Should a MappedComposition try and delete this MappedEvent or // if it persistent? // bool m_isPersistent; // Id of the segment that this (audio) event is derived from // int m_runtimeSegmentId; // Audio autofading // bool m_autoFade; RealTime m_fadeInTime; RealTime m_fadeOutTime; // input event original data, // stored as it was recorded // unsigned int m_recordedChannel; unsigned int m_recordedDevice; }; } #endif