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