Audacity 3.2.0
MIDIPlay.h
Go to the documentation of this file.
1/*!********************************************************************
2
3Audacity: A Digital Audio Editor
4
5@file MIDIPlay.h
6@brief Inject added MIDI playback capability into Audacity's audio engine
7
8Paul Licameli split from AudIOBase.h
9
10**********************************************************************/
11
12#ifndef __AUDACITY_MIDI_PLAY__
13#define __AUDACITY_MIDI_PLAY__
14
15#include "AudioIOExt.h"
16#include <optional>
17#include "WrapAllegro.h"
18
19typedef void PmStream;
20typedef int32_t PmTimestamp;
21class Alg_event;
22class Alg_iterator;
23class NoteTrack;
24using NoteTrackConstArray = std::vector < std::shared_ptr< const NoteTrack > >;
25
26// This workaround makes pause and stop work when output is to GarageBand,
27// which seems not to implement the notes-off message correctly.
28#define AUDIO_IO_GB_MIDI_WORKAROUND
29
30#include "NoteTrack.h"
31#include "PlaybackSchedule.h"
32
33namespace {
34
35struct MIDIPlay;
36
37Alg_update gAllNotesOff; // special event for loop ending
38// the fields of this event are never used, only the address is important
39
40struct Iterator {
42 const PlaybackSchedule &schedule, MIDIPlay &midiPlay,
43 NoteTrackConstArray &midiPlaybackTracks,
44 double startTime, double offset, bool send );
45 ~Iterator();
46
47 void Prime(bool send, double startTime);
48
49 double GetNextEventTime() const;
50
51 // Compute nondecreasing real time stamps, accounting for pauses, but not the
52 // synth latency.
53 double UncorrectedMidiEventTime(double pauseTime);
54
55 bool Unmuted(bool hasSolo) const;
56
57 // Returns true after outputting all-notes-off
58 bool OutputEvent(double pauseTime,
61 bool sendMidiState,
62 bool hasSolo);
63 void GetNextEvent();
64
67 Alg_iterator it{ nullptr, false };
69 Alg_event *mNextEvent = nullptr;
70
72 NoteTrack *mNextEventTrack = nullptr;
73
75 bool mNextIsNoteOn = false;
76
77private:
80 double mNextEventTime = 0;
81};
82
84{
85 explicit MIDIPlay(const PlaybackSchedule &schedule);
86 ~MIDIPlay() override;
87
88 double AudioTime(double rate) const
89 { return mPlaybackSchedule.mT0 + mNumFrames / rate; }
90
93
96
98 static bool mMidiStreamActive;
99
100 PmStream *mMidiStream = nullptr;
101 int mLastPmError = 0;
102
104 long mSynthLatency = MIDISynthLatency_ms.GetDefault();
105
106 // These fields are used to synchronize MIDI with audio:
107
109 long mNumFrames = 0;
111 int mMidiLoopPasses = 0;
112 //
113 inline double MidiLoopOffset() {
114 return mMidiLoopPasses * (mPlaybackSchedule.mT1 - mPlaybackSchedule.mT0);
115 }
116
117 long mAudioFramesPerBuffer = 0;
120 bool mMidiPaused = false;
123 PmTimestamp mMaxMidiTimestamp = 0;
124
128 double mSystemMinusAudioTime = 0.0;
131 double mAudioOutLatency = 0.0;
132
133 // Next two are used to adjust the previous two, if
134 // PortAudio does not provide the info (using ALSA):
135
138 double mStartTime = 0.0;
140 long mCallbackCount = 0;
141
142 double mSystemMinusAudioTimePlusLatency = 0.0;
143
144 std::optional<Iterator> mIterator;
145
146#ifdef AUDIO_IO_GB_MIDI_WORKAROUND
147 std::vector< std::pair< int, int > > mPendingNotesOff;
148#endif
149
150 void PrepareMidiIterator(bool send, double startTime, double offset);
151 bool StartPortMidiStream(double rate);
152 double PauseTime(double rate, unsigned long pauseFrames);
153 void AllNotesOff(bool looping = false);
154
160
161 bool mUsingAlsa = false;
162
163 static bool IsActive();
164 bool IsOtherStreamActive() const override;
165
166 void ComputeOtherTimings(double rate, bool paused,
167 const PaStreamCallbackTimeInfo *timeInfo,
168 unsigned long framesPerBuffer) override;
169 void SignalOtherCompletion() override;
170 unsigned CountOtherSolo() const override;
171
172 bool StartOtherStream(const TransportSequences &tracks,
173 const PaStreamInfo* info, double startTime, double rate) override;
174 void AbortOtherStream() override;
175 void FillOtherBuffers(double rate, unsigned long pauseFrames,
176 bool paused, bool hasSolo) override;
177 void StopOtherStream() override;
178
179 AudioIODiagnostics Dump() const override;
180};
181
182}
183
184#endif
Abstract base class for hooks into audio playback procedures.
std::vector< std::shared_ptr< const NoteTrack > > NoteTrackConstArray
Definition: MIDIPlay.cpp:369
void PmStream
Definition: MIDIPlay.h:19
int32_t PmTimestamp
Definition: MIDIPlay.h:20
IntSetting MIDISynthLatency_ms
Definition: NoteTrack.cpp:985
const auto tracks
A Track that is used for Midi notes. (Somewhat old code).
Definition: NoteTrack.h:78
const T & GetDefault() const
Definition: Prefs.h:199
PmTimestamp MidiTime(void *pInfo)
Definition: MIDIPlay.cpp:608
double mT0
Playback starts at offset of mT0, which is measured in seconds.
double mT1
Playback ends at offset of mT1, which is measured in seconds. Note that mT1 may be less than mT0 duri...
const PlaybackSchedule & mPlaybackSchedule
Definition: MIDIPlay.h:65
std::optional< Iterator > mIterator
Definition: MIDIPlay.h:144
std::vector< std::pair< int, int > > mPendingNotesOff
Definition: MIDIPlay.h:147
NoteTrackConstArray mMidiPlaybackTracks
Definition: MIDIPlay.h:92
static bool mMidiStreamActive
mMidiStreamActive tells when mMidiStream is open for output
Definition: MIDIPlay.h:98
const PlaybackSchedule & mPlaybackSchedule
Definition: MIDIPlay.h:91
static bool mMidiOutputComplete
True when output reaches mT1.
Definition: MIDIPlay.h:95
double AudioTime(double rate) const
Definition: MIDIPlay.h:88