1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Rosegarden
5     A MIDI and audio sequencer and musical notation editor.
6     Copyright 2000-2021 the Rosegarden development team.
7 
8     This program is free software; you can redistribute it and/or
9     modify it under the terms of the GNU General Public License as
10     published by the Free Software Foundation; either version 2 of the
11     License, or (at your option) any later version.  See the file
12     COPYING included with this distribution for more information.
13 */
14 
15 #ifndef RG_MAPPEDEVENT_H
16 #define RG_MAPPEDEVENT_H
17 
18 #include <QDataStream>
19 
20 #include "base/RealTime.h"
21 #include "base/Track.h"
22 #include "base/Event.h"
23 
24 
25 namespace Rosegarden
26 {
27 class MappedEvent;
28 
29 /// Used for storing data blocks for SysEx messages.
30 /**
31  *  @see MappedEvent::m_dataBlockId
32  */
33 class DataBlockRepository
34 {
35 public:
36     friend class MappedEvent;
37     typedef unsigned long blockid;
38 
39     static DataBlockRepository* getInstance();
40     static std::string getDataBlockForEvent(const MappedEvent*);
41     static void setDataBlockForEvent(MappedEvent*, const std::string&,
42                                      bool extend = false);
43     /**
44      * Clear all block files
45      */
46     static void clear();
47     bool hasDataBlock(blockid);
48 
49 protected:
50     DataBlockRepository();
51 
52     std::string getDataBlock(blockid);
53 
54     blockid registerDataBlock(const std::string&);
55     void unregisterDataBlock(blockid);
56 
57     void registerDataBlockForEvent(const std::string&, MappedEvent*);
58     void unregisterDataBlockForEvent(MappedEvent*);
59 
60 
61     //--------------- Data members ---------------------------------
62 
63     static DataBlockRepository* m_instance;
64 };
65 
66 /// A MIDI event that is ready for playback
67 /**
68  *  Here, the term "Mapped" refers to the conversion of an Event in a Segment
69  *  to something (a MappedEvent) that is closer to what is needed to send
70  *  to ALSA for playback.
71  *
72  *  Used as a transformation stage between Composition, Events and output
73  *  at the Sequencer this class and MidiComposition eliminate the notion
74  *  of the Segment and Track for ease of Event access.  The MappedEvents
75  *  are ready for playing or routing through an Instrument or Effects
76  *  boxes.
77  *
78  *  MappedEvents can also represent instructions for playback of audio
79  *  samples - if the m_type is Audio then the sequencer will attempt to
80  *  map the Pitch (m_data1) to the audio id.  Note that this limits us
81  *  to 256 audio files in the Composition unless we use a different
82  *  parameter for storing these IDs.
83  *
84  *  The MappedEvent/Instrument relationship is interesting - we don't
85  *  want to duplicate the entire Instrument at the Sequencer level as
86  *  it'd be messy and unnecessary.  Instead we use a MappedInstrument
87  *  which is just a very cut down Sequencer-side version of an Instrument.
88  *
89  *  Some of these Events are unidirectional, some are bidirectional -
90  *  that is they only have a meaning in one direction (they are still
91  *  legal at either end).  They are broadcast in both directions using
92  *  the "getSequencerSlice" and "processAsync/Recorded" interfaces on
93  *  which the control messages can piggyback and eventually stripped out.
94  */
95 class MappedEvent
96 {
97 public:
98     typedef enum
99     {
100         // INVALID
101         //
102         InvalidMappedEvent       = 0,
103 
104         // Keep the MidiNotes bit flaggable so that filtering works
105         //
106         MidiNote                 = 1 << 0,
107         MidiNoteOneShot          = 1 << 1,  // doesn't need NOTE OFFs
108         MidiProgramChange        = 1 << 2,
109         MidiKeyPressure          = 1 << 3,
110         MidiChannelPressure      = 1 << 4,
111         MidiPitchBend            = 1 << 5,
112         MidiController           = 1 << 6,
113         MidiSystemMessage        = 1 << 7,
114 
115         // Sent from the gui to play an audio file
116         Audio                    = 1 << 8,
117         // Sent from gui to cancel playing an audio file
118         AudioCancel              = 1 << 9,
119         // Sent to the gui with audio level on Instrument
120         AudioLevel               = 1 << 10,
121         // Sent to the gui to inform an audio file stopped
122         AudioStopped             = 1 << 11,
123         // The gui is clear to generate a preview for a new audio file
124         AudioGeneratePreview     = 1 << 12,
125 
126         // Update Instruments - new ALSA client detected
127         SystemUpdateInstruments  = 1 << 13,
128         // Set RG as JACK source/follower
129         SystemJackTransport      = 1 << 14,
130         // Set RG as MMC source/follower
131         SystemMMCTransport       = 1 << 15,
132         // Set System Messages and MIDI Clock
133         SystemMIDIClock          = 1 << 16,
134         // Set Record device -- no longer used (all input devices are set)
135         // Set Metronome device
136         SystemMetronomeDevice    = 1 << 18,
137         // Set Audio inputs/outputs: data1 num inputs, data2 num submasters
138         SystemAudioPortCounts    = 1 << 19,
139         // Set whether we create various Audio ports (data1 is an AudioOutMask)
140         SystemAudioPorts         = 1 << 20,
141         // Some failure has occurred: data1 contains FailureCode
142         SystemFailure            = 1 << 21,
143 
144         // Time sig. event (from time sig. composition reference segment)
145         TimeSignature            = 1 << 22,
146         // Tempo event (from tempo composition reference segment)
147         Tempo                    = 1 << 23,
148 
149         // Panic function
150         Panic                    = 1 << 24,
151 
152         // Set RG as MTC source/follower
153         SystemMTCTransport       = 1 << 25,
154         // Auto-connect sync outputs
155         SystemMIDISyncAuto       = 1 << 26,
156         // File format used for audio recording (data1 is 0=PCM,1=float)
157         SystemAudioFileFormat    = 1 << 27,
158 
159         // An alsa sequencer port-connection was established or removed
160         //AlsaSeqPortConnectionChanged = 1 << 28   // not required, handled with SystemUpdateInstruments event
161 
162         // Marker (for MIDI export, not sound)
163         Marker                   = 1 << 28,
164         // Text (for MIDI export, not sound)
165         Text                     = 1 << 29,
166         // Key signature (for MIDI export, not sound)
167         KeySignature             = 1 << 30
168 
169     } MappedEventType;
170 
171     typedef enum
172     {
173         // These values are OR'd to produce the data2 field in a
174         // SystemAudioPorts event.
175         FaderOuts                = 1 << 0,
176         SubmasterOuts            = 1 << 1
177 
178     } MappedEventAudioOutMask;
179 
180     typedef enum
181     {
182         // JACK is having some xruns - warn the user maybe
183         FailureXRuns             = 0,
184         // JACK has died or kicked us out
185         FailureJackDied          = 1,
186         // Audio subsystem failed to read from disc fast enough
187         FailureDiscUnderrun      = 2,
188         // Audio subsystem failed to write to disc fast enough
189         FailureDiscOverrun       = 3,
190         // Audio subsystem failed to mix busses fast enough
191         FailureBussMixUnderrun   = 4,
192         // Audio subsystem failed to mix instruments fast enough
193         FailureMixUnderrun       = 5,
194         // Using a timer that has too low a resolution (e.g. 100Hz system timer)
195         WarningImpreciseTimer    = 6,
196         // Too much CPU time spent in audio processing -- risk of xruns and lockup
197         FailureCPUOverload       = 7,
198         // JACK kicked us out, but we've reconnected
199         FailureJackRestart       = 8,
200         // JACK kicked us out, and now the reconnection has failed
201         FailureJackRestartFailed = 9,
202         // A necessary ALSA call has returned an error code
203         FailureALSACallFailed    = 10,
204         // Using a timer that has too low a resolution, but RTC might work
205         WarningImpreciseTimerTryRTC = 11
206     } FailureCode;
207 
MappedEvent()208     MappedEvent(): m_trackId((int)NoTrack),
209                    m_instrument(0),
210                    m_type(InvalidMappedEvent),
211                    m_data1(0),
212                    m_data2(0),
213                    m_eventTime(0, 0),
214                    m_duration(0, 0),
215                    m_audioStartMarker(0, 0),
216                    m_dataBlockId(0),
217                    m_runtimeSegmentId(-1),
218                    m_autoFade(false),
219                    m_fadeInTime(RealTime::zeroTime),
220                    m_fadeOutTime(RealTime::zeroTime),
221                    m_recordedChannel(0),
222                    m_recordedDevice(0) {}
223 
224     // Construct from Events to Internal (MIDI) type MappedEvent
225     //
226     MappedEvent(const Event &e);
227 
228     // Another Internal constructor from Events
229     MappedEvent(InstrumentId id,
230                 const Event &e,
231                 const RealTime &eventTime,
232                 const RealTime &duration);
233 
234     // A general MappedEvent constructor for any MappedEvent type
235     //
MappedEvent(InstrumentId id,MappedEventType type,MidiByte pitch,MidiByte velocity,const RealTime & absTime,const RealTime & duration,const RealTime & audioStartMarker)236     MappedEvent(InstrumentId id,
237                 MappedEventType type,
238                 MidiByte pitch,
239                 MidiByte velocity,
240                 const RealTime &absTime,
241                 const RealTime &duration,
242                 const RealTime &audioStartMarker):
243         m_trackId((int)NoTrack),
244         m_instrument(id),
245         m_type(type),
246         m_data1(pitch),
247         m_data2(velocity),
248         m_eventTime(absTime),
249         m_duration(duration),
250         m_audioStartMarker(audioStartMarker),
251         m_dataBlockId(0),
252         m_runtimeSegmentId(-1),
253         m_autoFade(false),
254         m_fadeInTime(RealTime::zeroTime),
255         m_fadeOutTime(RealTime::zeroTime),
256         m_recordedChannel(0),
257         m_recordedDevice(0) {}
258 
259     // Audio MappedEvent shortcut constructor
260     //
MappedEvent(InstrumentId id,unsigned short audioID,const RealTime & eventTime,const RealTime & duration,const RealTime & audioStartMarker)261     MappedEvent(InstrumentId id,
262                 unsigned short audioID,
263                 const RealTime &eventTime,
264                 const RealTime &duration,
265                 const RealTime &audioStartMarker):
266          m_trackId((int)NoTrack),
267          m_instrument(id),
268          m_type(Audio),
269          m_data1(audioID % 256),
270          m_data2(audioID / 256),
271          m_eventTime(eventTime),
272          m_duration(duration),
273          m_audioStartMarker(audioStartMarker),
274          m_dataBlockId(0),
275          m_runtimeSegmentId(-1),
276          m_autoFade(false),
277          m_fadeInTime(RealTime::zeroTime),
278          m_fadeOutTime(RealTime::zeroTime),
279          m_recordedChannel(0),
280          m_recordedDevice(0) {}
281 
282     // More generalised MIDI event containers for
283     // large and small events (one param, two param)
284     //
MappedEvent(InstrumentId id,MappedEventType type,MidiByte data1,MidiByte data2)285     MappedEvent(InstrumentId id,
286                 MappedEventType type,
287                 MidiByte data1,
288                 MidiByte data2):
289          m_trackId((int)NoTrack),
290          m_instrument(id),
291          m_type(type),
292          m_data1(data1),
293          m_data2(data2),
294          m_eventTime(RealTime(0, 0)),
295          m_duration(RealTime(0, 0)),
296          m_audioStartMarker(RealTime(0, 0)),
297          m_dataBlockId(0),
298          m_runtimeSegmentId(-1),
299          m_autoFade(false),
300          m_fadeInTime(RealTime::zeroTime),
301          m_fadeOutTime(RealTime::zeroTime),
302          m_recordedChannel(0),
303          m_recordedDevice(0) {}
304 
305     /**
306      * For SysEx...
307      *   - Set instrumentId to NoInstrument.
308      *   - Set type to MidiSystemMessage.
309      *   - Set data1 to MIDI_SYSTEM_EXCLUSIVE.
310      *   - Set recorded device with the destination device.
311      *   - Call addDataString() to add the SysEx data.
312      */
MappedEvent(InstrumentId id,MappedEventType type,MidiByte data1)313     MappedEvent(InstrumentId id,
314                 MappedEventType type,
315                 MidiByte data1):
316         m_trackId((int)NoTrack),
317         m_instrument(id),
318         m_type(type),
319         m_data1(data1),
320         m_data2(0),
321         m_eventTime(RealTime(0, 0)),
322         m_duration(RealTime(0, 0)),
323         m_audioStartMarker(RealTime(0, 0)),
324         m_dataBlockId(0),
325         m_runtimeSegmentId(-1),
326         m_autoFade(false),
327         m_fadeInTime(RealTime::zeroTime),
328         m_fadeOutTime(RealTime::zeroTime),
329         m_recordedChannel(0),
330         m_recordedDevice(0) {}
331 
MappedEvent(InstrumentId instrumentId,MappedEventType type)332     MappedEvent(InstrumentId instrumentId,
333                 MappedEventType type):
334         m_trackId((int)NoTrack),
335         m_instrument(instrumentId),
336         m_type(type),
337         m_data1(0),
338         m_data2(0),
339         m_eventTime(RealTime(0, 0)),
340         m_duration(RealTime(0, 0)),
341         m_audioStartMarker(RealTime(0, 0)),
342         m_dataBlockId(0),
343         m_runtimeSegmentId(-1),
344         m_autoFade(false),
345         m_fadeInTime(RealTime::zeroTime),
346         m_fadeOutTime(RealTime::zeroTime),
347         m_recordedChannel(0),
348         m_recordedDevice(0) {}
349 
350     // Copy constructor
351     //
352     // Fix for 674731 by Pedro Lopez-Cabanillas (20030531)
MappedEvent(const MappedEvent & mE)353     MappedEvent(const MappedEvent &mE):
354         m_trackId(mE.getTrackId()),
355         m_instrument(mE.getInstrument()),
356         m_type(mE.getType()),
357         m_data1(mE.getData1()),
358         m_data2(mE.getData2()),
359         m_eventTime(mE.getEventTime()),
360         m_duration(mE.getDuration()),
361         m_audioStartMarker(mE.getAudioStartMarker()),
362         m_dataBlockId(mE.getDataBlockId()),
363         m_runtimeSegmentId(mE.getRuntimeSegmentId()),
364         m_autoFade(mE.isAutoFading()),
365         m_fadeInTime(mE.getFadeInTime()),
366         m_fadeOutTime(mE.getFadeOutTime()),
367         m_recordedChannel(mE.getRecordedChannel()),
368         m_recordedDevice(mE.getRecordedDevice()) {}
369 
370     // Copy from pointer
371     // Fix for 674731 by Pedro Lopez-Cabanillas (20030531)
MappedEvent(MappedEvent * mE)372     MappedEvent(MappedEvent *mE):
373         m_trackId(mE->getTrackId()),
374         m_instrument(mE->getInstrument()),
375         m_type(mE->getType()),
376         m_data1(mE->getData1()),
377         m_data2(mE->getData2()),
378         m_eventTime(mE->getEventTime()),
379         m_duration(mE->getDuration()),
380         m_audioStartMarker(mE->getAudioStartMarker()),
381         m_dataBlockId(mE->getDataBlockId()),
382         m_runtimeSegmentId(mE->getRuntimeSegmentId()),
383         m_autoFade(mE->isAutoFading()),
384         m_fadeInTime(mE->getFadeInTime()),
385         m_fadeOutTime(mE->getFadeOutTime()),
386         m_recordedChannel(mE->getRecordedChannel()),
387         m_recordedDevice(mE->getRecordedDevice()) {}
388 
389     // Construct perhaps without initialising, for placement new or equivalent
MappedEvent(bool initialise)390     MappedEvent(bool initialise) {
391         if (initialise) *this = MappedEvent();
392     }
393 
isValid()394     bool isValid() const { return m_type != InvalidMappedEvent; }
395     // Event time
396     //
setEventTime(const RealTime & a)397     void setEventTime(const RealTime &a) { m_eventTime = a; }
getEventTime()398     RealTime getEventTime() const { return m_eventTime; }
399 
400     // Duration
401     //
setDuration(const RealTime & d)402     void setDuration(const RealTime &d) { m_duration = d; }
getDuration()403     RealTime getDuration() const { return m_duration; }
404 
405     // Instrument
setInstrument(InstrumentId id)406     void setInstrument(InstrumentId id) { m_instrument = id; }
getInstrument()407     InstrumentId getInstrument() const { return m_instrument; }
408 
409     // Track
setTrackId(TrackId id)410     void setTrackId(TrackId id) { m_trackId = id; }
getTrackId()411     TrackId getTrackId() const { return m_trackId; }
412 
getPitch()413     MidiByte getPitch() const { return m_data1; }
414 
415     // Keep pitch within MIDI limits
416     //
setPitch(MidiByte p)417     void setPitch(MidiByte p)
418     {
419         m_data1 = p;
420         if (m_data1 > MidiMaxValue) m_data1 = MidiMaxValue;
421     }
422 
setVelocity(MidiByte v)423     void setVelocity(MidiByte v) { m_data2 = v; }
getVelocity()424     MidiByte getVelocity() const { return m_data2; }
425 
426     // And the trendy names for them
427     //
getData1()428     MidiByte getData1() const { return m_data1; }
getData2()429     MidiByte getData2() const { return m_data2; }
setData1(MidiByte d1)430     void setData1(MidiByte d1) { m_data1 = d1; }
setData2(MidiByte d2)431     void setData2(MidiByte d2) { m_data2 = d2; }
432 
setAudioID(unsigned short id)433     void setAudioID(unsigned short id) { m_data1 = id % 256; m_data2 = id / 256; }
getAudioID()434     int getAudioID() const { return m_data1 + 256 * m_data2; }
435 
436     // A sample doesn't have to be played from the beginning.  When
437     // passing an Audio event this value may be set to indicate from
438     // where in the sample it should be played.  Duration is measured
439     // against total sounding length (not absolute position).
440     //
setAudioStartMarker(const RealTime & aS)441     void setAudioStartMarker(const RealTime &aS)
442         { m_audioStartMarker = aS; }
getAudioStartMarker()443     RealTime getAudioStartMarker() const
444         { return m_audioStartMarker; }
445 
getType()446     MappedEventType getType() const { return m_type; }
setType(const MappedEventType & value)447     void setType(const MappedEventType &value) { m_type = value; }
448 
449     // Data block id
450     //
getDataBlockId()451     DataBlockRepository::blockid getDataBlockId() const { return m_dataBlockId; }
setDataBlockId(DataBlockRepository::blockid dataBlockId)452     void setDataBlockId(DataBlockRepository::blockid dataBlockId) { m_dataBlockId = dataBlockId; }
453 
454     // Whether the event is all done sounding at time t.
455     /**
456      * Zero-duration events at exactly time t are not all done, but
457      * non-zeroes that end at exactly time t are.
458      */
EndedBefore(RealTime t)459     bool EndedBefore(RealTime t)
460     {
461         return
462             ((getEventTime() + getDuration() <= t) &&
463              (getDuration() != RealTime::zeroTime ||
464               getEventTime() != t));
465     }
466 
467     // How MappedEvents are ordered in the MappedEventList
468     //
469     struct MappedEventCmp
470     {
operatorMappedEventCmp471         bool operator()(const MappedEvent *mE1, const MappedEvent *mE2) const
472         {
473             return *mE1 < *mE2;
474         }
475     };
476 
477     friend bool operator<(const MappedEvent &a, const MappedEvent &b);
478 
479     MappedEvent& operator=(const MappedEvent &mE);
480 
481     /// Add several raw bytes to the event's SysEx datablock.
482     /*
483      * If the block doesn't exist, it is created.
484      *
485      * To set up a SysEx message, see the comments on the ctor that
486      * takes three parameters.
487      *
488      * DO NOT include the F0/F7 SOX/EOX in the block.  Those will be
489      * added by AlsaDriver::processMidiOut().
490      */
491     void addDataString(const std::string &rawData);
492 
493     /// Size of a MappedEvent in a stream
494     static const size_t streamedSize;
495 
496     // The runtime segment id of an audio file
497     //
getRuntimeSegmentId()498     int getRuntimeSegmentId() const { return m_runtimeSegmentId; }
setRuntimeSegmentId(int id)499     void setRuntimeSegmentId(int id) { m_runtimeSegmentId = id; }
500 
isAutoFading()501     bool isAutoFading() const { return m_autoFade; }
setAutoFade(bool value)502     void setAutoFade(bool value) { m_autoFade = value; }
503 
getFadeInTime()504     RealTime getFadeInTime() const { return m_fadeInTime; }
setFadeInTime(const RealTime & time)505     void setFadeInTime(const RealTime &time)
506             { m_fadeInTime = time; }
507 
getFadeOutTime()508     RealTime getFadeOutTime() const { return m_fadeOutTime; }
setFadeOutTime(const RealTime & time)509     void setFadeOutTime(const RealTime &time)
510             { m_fadeOutTime = time; }
511 
512     // Original event input channel as it was recorded
513     //
getRecordedChannel()514     unsigned int getRecordedChannel() const { return m_recordedChannel; }
setRecordedChannel(const unsigned int channel)515     void setRecordedChannel(const unsigned int channel)
516             { m_recordedChannel = channel; }
517 
518     // Original event record device as it was recorded
519     //
getRecordedDevice()520     unsigned int getRecordedDevice() const { return m_recordedDevice; }
setRecordedDevice(const unsigned int device)521     void setRecordedDevice(const unsigned int device) { m_recordedDevice = device; }
522 
523 private:
524     TrackId          m_trackId;
525     InstrumentId     m_instrument;
526     MappedEventType  m_type;
527     MidiByte         m_data1;
528     MidiByte         m_data2;
529     RealTime         m_eventTime;
530     RealTime         m_duration;
531     RealTime         m_audioStartMarker;
532 
533     // Use this when we want to store something in addition to the
534     // other bytes in this type, e.g. System Exclusive.
535     //
536     DataBlockRepository::blockid m_dataBlockId;
537 
538     // Id of the segment that this (audio) event is derived from
539     //
540     int              m_runtimeSegmentId;
541 
542     // Audio autofading
543     //
544     bool                  m_autoFade;
545     RealTime  m_fadeInTime;
546     RealTime  m_fadeOutTime;
547 
548     // For input events, original data, stored as it was recorded.
549     // For output events, channel to play on.  m_recordedDevice is not
550     // used for output.
551     unsigned int          m_recordedChannel;
552     unsigned int          m_recordedDevice;
553 
554     friend QDebug &operator<<(QDebug &, const MappedEvent &);
555 };
556 
557 QDebug &operator<<(QDebug &, const MappedEvent &);
558 
559 
560 }
561 
562 #endif
563