summaryrefslogtreecommitdiffstats
path: root/src/sound/MappedEvent.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/sound/MappedEvent.h')
-rw-r--r--src/sound/MappedEvent.h546
1 files changed, 546 insertions, 0 deletions
diff --git a/src/sound/MappedEvent.h b/src/sound/MappedEvent.h
new file mode 100644
index 0000000..cc4e3f3
--- /dev/null
+++ b/src/sound/MappedEvent.h
@@ -0,0 +1,546 @@
+// -*- 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.
+*/
+
+#include <qdatastream.h>
+
+#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 QDataStream& operator>>(QDataStream &dS, MappedEvent *mE);
+ friend QDataStream& operator<<(QDataStream &dS, MappedEvent *mE);
+ friend QDataStream& operator>>(QDataStream &dS, MappedEvent &mE);
+ friend QDataStream& operator<<(QDataStream &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