@@ -81,6 +81,23 @@ void FMIDIPacket::Advance(int32 InNumFrames)
81
81
mFrame -= InNumFrames;
82
82
}
83
83
84
+ bool FMIDIPacket::IsNoteOff (uint8_t chan, uint8_t num) const
85
+ {
86
+ return mLength == 3 && mData [0 ] == (chan | 0x80 ) && mData [1 ] == num;
87
+ }
88
+
89
+ bool FMIDIPacket::IsNoteOn (uint8_t chan, uint8_t num) const
90
+ {
91
+ return mLength == 3 && mData [0 ] == (chan | 0x90 ) && mData [1 ] == num;
92
+ }
93
+
94
+ FMIDIPacket FMIDIPacket::CloneTo (int32 frame) const
95
+ {
96
+ FMIDIPacket r = *this ;
97
+ r.mFrame = frame;
98
+ return r;
99
+ }
100
+
84
101
FMIDIBuffer::FMIDIBuffer (const Metasound::FOperatorSettings& InSettings)
85
102
: NumFramesPerBlock (InSettings.GetNumFramesPerBlock ())
86
103
{
@@ -142,6 +159,70 @@ void FMIDIBuffer::Push(FMIDIPacket packet)
142
159
}
143
160
}
144
161
162
+ void FMIDIBuffer::PushNote (int32 start, int32 dur, uint8_t chan, uint8_t note, uint8_t onvel, uint8_t offvel)
163
+ {
164
+ /* situations where we have to move an OFF
165
+ * 1. Our new note happens inside another scheduled duration
166
+ * * off after our off without an on after our off, move old off right before our new on
167
+ * 2. Our new note spans the off of another note
168
+ * * off between our on and our off, move old off to right before our new on
169
+ * 3. Our new note spans the an entire note
170
+ * * on and off come between our new on and off, move old off right before our new on
171
+ *
172
+ */
173
+ const auto count = Packets.Num ();
174
+ const auto end = start + dur;
175
+ for (auto i = 0 ; i < count; i++) {
176
+ auto & p = Packets[i];
177
+ const auto f = p.Frame ();
178
+ if (f < start) {
179
+ continue ;
180
+ }
181
+ // in range
182
+ if (p.IsNoteOn (chan, note)) {
183
+ // existing note starts before our note ends, we need to shorten our note
184
+ if (f < end) {
185
+ // insert our Off before the existing On, updated time
186
+ Packets.Insert (FMIDIPacket::NoteOff (f, note, offvel, chan), i);
187
+ // adjust count
188
+ if (f < NumFramesPerBlock) {
189
+ CountInBlock++;
190
+ }
191
+ // push our on after so we don't screw up above index
192
+ Push (FMIDIPacket::NoteOn (start, note, onvel, chan));
193
+ return ;
194
+ }
195
+ else {
196
+ break ;
197
+ }
198
+ }
199
+ else if (p.IsNoteOff (chan, note) && f > start) {
200
+ // should only hit this case if a note on isn't found either within the new note bounds or after it.
201
+ // our new note either spans the off of an existing on note or is contained within an existing note
202
+ // move the off just before our on
203
+ auto off = p.CloneTo (start);
204
+ Packets.RemoveAt (i);
205
+
206
+ // adjust count
207
+ if (f < NumFramesPerBlock) {
208
+ CountInBlock--; // will get incremented in the Push below
209
+ }
210
+ // adjust last frame
211
+ if (Packets.Num () > 0 ) {
212
+ LastFrame = Packets.Last (0 ).Frame ();
213
+ }
214
+ else {
215
+ LastFrame = -1 ;
216
+ }
217
+ Push (off); // XXX assumes there isn't another matching On at the exact time
218
+ break ;
219
+ }
220
+ }
221
+
222
+ Push (FMIDIPacket::NoteOn (start, note, onvel, chan));
223
+ Push (FMIDIPacket::NoteOff (end, note, offvel, chan));
224
+ }
225
+
145
226
void FMIDIBuffer::Reset ()
146
227
{
147
228
Packets.Reset ();
0 commit comments