VCV Rack API v2
Loading...
Searching...
No Matches
midi.hpp
Go to the documentation of this file.
1#pragma once
2#include <dsp/common.hpp>
3#include <dsp/filter.hpp>
4#include <dsp/digital.hpp>
5#include <midi.hpp>
6#include <jansson.h>
7
8
9namespace rack {
10namespace dsp {
11
12
16template <int CHANNELS>
18 int8_t vels[CHANNELS];
19 int8_t notes[CHANNELS];
20 bool gates[CHANNELS];
21 int8_t keyPressures[CHANNELS];
23 int8_t ccs[128];
24 int16_t pw;
25 bool clk;
26 bool start;
27 bool stop;
28 bool cont;
29 int64_t frame = -1;
30
32 reset();
33 }
34
35 void reset() {
36 for (int c = 0; c < CHANNELS; c++) {
37 vels[c] = 100;
38 notes[c] = 60;
39 gates[c] = false;
40 keyPressures[c] = -1;
41 }
42 channelPressure = -1;
43 for (int i = 0; i < 128; i++) {
44 ccs[i] = -1;
45 }
46 pw = 0x2000;
47 clk = false;
48 start = false;
49 stop = false;
50 cont = false;
51 }
52
53 void panic() {
54 reset();
55 // Send all note off commands
56 for (int note = 0; note <= 127; note++) {
57 // Note off
59 m.setStatus(0x8);
60 m.setNote(note);
61 m.setValue(0);
62 m.setFrame(frame);
63 onMessage(m);
64 }
65 }
66
68 void setVelocity(int8_t vel, int c) {
69 vels[c] = vel;
70 }
71
72 void setNoteGate(int8_t note, bool gate, int c) {
73 bool changedNote = gate && gates[c] && (note != notes[c]);
74 bool enabledGate = gate && !gates[c];
75 bool disabledGate = !gate && gates[c];
76 if (changedNote || disabledGate) {
77 // Note off
79 m.setStatus(0x8);
80 m.setNote(notes[c]);
81 m.setValue(vels[c]);
82 m.setFrame(frame);
83 onMessage(m);
84 }
85 if (changedNote || enabledGate) {
86 // Note on
88 m.setStatus(0x9);
89 m.setNote(note);
90 m.setValue(vels[c]);
91 m.setFrame(frame);
92 onMessage(m);
93 }
94 notes[c] = note;
95 gates[c] = gate;
96 }
97
98 void setKeyPressure(int8_t val, int c) {
99 if (keyPressures[c] == val)
100 return;
101 keyPressures[c] = val;
102 // Polyphonic key pressure
104 m.setStatus(0xa);
105 m.setNote(notes[c]);
106 m.setValue(val);
107 m.setFrame(frame);
108 onMessage(m);
109 }
110
111 void setChannelPressure(int8_t val) {
112 if (channelPressure == val)
113 return;
114 channelPressure = val;
115 // Channel pressure
117 m.setSize(2);
118 m.setStatus(0xd);
119 m.setNote(val);
120 m.setFrame(frame);
121 onMessage(m);
122 }
123
124 void setCc(int8_t cc, int id) {
125 if (ccs[id] == cc)
126 return;
127 ccs[id] = cc;
128 // Continuous controller
130 m.setStatus(0xb);
131 m.setNote(id);
132 m.setValue(cc);
133 m.setFrame(frame);
134 onMessage(m);
135 }
136
137 void setModWheel(int8_t cc) {
138 setCc(cc, 0x01);
139 }
140
141 void setVolume(int8_t cc) {
142 setCc(cc, 0x07);
143 }
144
145 void setBalance(int8_t cc) {
146 setCc(cc, 0x08);
147 }
148
149 void setPan(int8_t cc) {
150 setCc(cc, 0x0a);
151 }
152
153 void setSustainPedal(int8_t cc) {
154 setCc(cc, 0x40);
155 }
156
157 void setPitchWheel(int16_t pw) {
158 if (this->pw == pw)
159 return;
160 this->pw = pw;
161 // Pitch wheel
163 m.setStatus(0xe);
164 m.setNote(pw & 0x7f);
165 m.setValue((pw >> 7) & 0x7f);
166 m.setFrame(frame);
167 onMessage(m);
168 }
169
170 void setClock(bool clk) {
171 if (this->clk == clk)
172 return;
173 this->clk = clk;
174 if (clk) {
175 // Timing clock
177 m.setSize(1);
178 m.setStatus(0xf);
179 m.setChannel(0x8);
180 m.setFrame(frame);
181 onMessage(m);
182 }
183 }
184
185 void setStart(bool start) {
186 if (this->start == start)
187 return;
188 this->start = start;
189 if (start) {
190 // Start
192 m.setSize(1);
193 m.setStatus(0xf);
194 m.setChannel(0xa);
195 m.setFrame(frame);
196 onMessage(m);
197 }
198 }
199
200 void setContinue(bool cont) {
201 if (this->cont == cont)
202 return;
203 this->cont = cont;
204 if (cont) {
205 // Continue
207 m.setSize(1);
208 m.setStatus(0xf);
209 m.setChannel(0xb);
210 m.setFrame(frame);
211 onMessage(m);
212 }
213 }
214
215 void setStop(bool stop) {
216 if (this->stop == stop)
217 return;
218 this->stop = stop;
219 if (stop) {
220 // Stop
222 m.setSize(1);
223 m.setStatus(0xf);
224 m.setChannel(0xc);
225 m.setFrame(frame);
226 onMessage(m);
227 }
228 }
229
230 void setFrame(int64_t frame) {
231 this->frame = frame;
232 }
233
234 virtual void onMessage(const midi::Message& message) {}
235};
236
237
241template <uint8_t MAX_CHANNELS>
243 // Settings
244
246 float pwRange;
247
249 bool smooth;
250
253
255 uint8_t channels;
256
266
267 // States
268
270 int64_t clock;
271
273 bool pedal;
274
275 uint8_t notes[MAX_CHANNELS];
276 bool gates[MAX_CHANNELS];
277 uint8_t velocities[MAX_CHANNELS];
278 uint8_t aftertouches[MAX_CHANNELS];
279 std::vector<uint8_t> heldNotes;
281
285 int16_t pws[MAX_CHANNELS];
288 uint8_t mods[MAX_CHANNELS];
292
299
301 heldNotes.reserve(128);
302 reset();
303 }
304
306 void reset() {
307 clock = 0;
308 smooth = true;
309 channels = 1;
311 pwRange = 2.f;
312 clockDivision = 24;
313 setFilterLambda(30.f);
314 panic();
315 }
316
318 void panic() {
319 for (uint8_t c = 0; c < MAX_CHANNELS; c++) {
320 // Middle C
321 notes[c] = 60;
322 gates[c] = false;
323 velocities[c] = 0;
324 aftertouches[c] = 0;
325 pws[c] = 0;
326 mods[c] = 0;
327 pwFilters[c].reset();
328 modFilters[c].reset();
329 }
330 pedal = false;
331 rotateIndex = -1;
332 heldNotes.clear();
333 }
334
335 void processFilters(float deltaTime) {
336 uint8_t wheelChannels = getWheelChannels();
337 for (uint8_t c = 0; c < wheelChannels; c++) {
338 float pw = pws[c] / 8191.f;
339 pw = math::clamp(pw, -1.f, 1.f);
340 if (smooth)
341 pw = pwFilters[c].process(deltaTime, pw);
342 else
343 pwFilters[c].out = pw;
344
345 float mod = mods[c] / 127.f;
346 mod = math::clamp(mod, 0.f, 1.f);
347 if (smooth)
348 mod = modFilters[c].process(deltaTime, mod);
349 else
350 modFilters[c].out = mod;
351 }
352 }
353
354 void processPulses(float deltaTime) {
355 clockPulse.process(deltaTime);
356 clockDividerPulse.process(deltaTime);
357 startPulse.process(deltaTime);
358 stopPulse.process(deltaTime);
359 continuePulse.process(deltaTime);
360 for (uint8_t c = 0; c < channels; c++) {
361 retriggerPulses[c].process(deltaTime);
362 }
363 }
364
365 void processMessage(const midi::Message& msg) {
366 // DEBUG("MIDI: %ld %s", msg.getFrame(), msg.toString().c_str());
367
368 switch (msg.getStatus()) {
369 // note off
370 case 0x8: {
371 releaseNote(msg.getNote());
372 } break;
373 // note on
374 case 0x9: {
375 if (msg.getValue() > 0) {
376 uint8_t c = msg.getChannel();
377 c = pressNote(msg.getNote(), c);
378 velocities[c] = msg.getValue();
379 }
380 else {
381 // Note-on event with velocity 0 is an alternative for note-off event.
382 releaseNote(msg.getNote());
383 }
384 } break;
385 // key pressure
386 case 0xa: {
387 // Set the aftertouches with the same note
388 // TODO Should we handle the MPE case differently?
389 for (uint8_t c = 0; c < MAX_CHANNELS; c++) {
390 if (notes[c] == msg.getNote())
391 aftertouches[c] = msg.getValue();
392 }
393 } break;
394 // cc
395 case 0xb: {
396 processCC(msg);
397 } break;
398 // channel pressure
399 case 0xd: {
400 if (polyMode == MPE_MODE) {
401 // Set the channel aftertouch
402 aftertouches[msg.getChannel()] = msg.getNote();
403 }
404 else {
405 // Set all aftertouches
406 for (uint8_t c = 0; c < MAX_CHANNELS; c++) {
407 aftertouches[c] = msg.getNote();
408 }
409 }
410 } break;
411 // pitch wheel
412 case 0xe: {
413 uint8_t c = (polyMode == MPE_MODE) ? msg.getChannel() : 0;
414 int16_t pw = msg.getValue();
415 pw <<= 7;
416 pw |= msg.getNote();
417 pw -= 8192;
418 pws[c] = pw;
419 } break;
420 case 0xf: {
421 processSystem(msg);
422 } break;
423 default: break;
424 }
425 }
426
427 void processCC(const midi::Message& msg) {
428 switch (msg.getNote()) {
429 // mod
430 case 0x01: {
431 uint8_t c = (polyMode == MPE_MODE) ? msg.getChannel() : 0;
432 mods[c] = msg.getValue();
433 } break;
434 // sustain
435 case 0x40: {
436 if (msg.getValue() >= 64)
437 pressPedal();
438 else
439 releasePedal();
440 } break;
441 // all notes off (panic)
442 case 0x7b: {
443 if (msg.getValue() == 0) {
444 panic();
445 }
446 } break;
447 default: break;
448 }
449 }
450
451 void processSystem(const midi::Message& msg) {
452 switch (msg.getChannel()) {
453 // Song Position Pointer
454 case 0x2: {
455 int64_t pos = int64_t(msg.getNote()) | (int64_t(msg.getValue()) << 7);
456 clock = pos * 6;
457 } break;
458 // Timing
459 case 0x8: {
460 clockPulse.trigger(1e-3);
461 if (clock % clockDivision == 0) {
463 }
464 clock++;
465 } break;
466 // Start
467 case 0xa: {
468 startPulse.trigger(1e-3);
469 clock = 0;
470 } break;
471 // Continue
472 case 0xb: {
474 } break;
475 // Stop
476 case 0xc: {
477 stopPulse.trigger(1e-3);
478 } break;
479 default: break;
480 }
481 }
482
483 uint8_t assignChannel(uint8_t note) {
484 if (channels == 1)
485 return 0;
486
487 switch (polyMode) {
488 case REUSE_MODE: {
489 // Find channel with the same note
490 for (uint8_t c = 0; c < channels; c++) {
491 if (notes[c] == note)
492 return c;
493 }
494 } // fallthrough
495
496 case ROTATE_MODE: {
497 // Find next available channel
498 for (uint8_t i = 0; i < channels; i++) {
499 rotateIndex++;
500 if (rotateIndex >= channels)
501 rotateIndex = 0;
502 if (!gates[rotateIndex])
503 return rotateIndex;
504 }
505 // No notes are available. Advance rotateIndex once more.
506 rotateIndex++;
507 if (rotateIndex >= channels)
508 rotateIndex = 0;
509 return rotateIndex;
510 } break;
511
512 case RESET_MODE: {
513 for (uint8_t c = 0; c < channels; c++) {
514 if (!gates[c])
515 return c;
516 }
517 return channels - 1;
518 } break;
519
520 case MPE_MODE: {
521 // This case is handled by querying the MIDI message channel.
522 return 0;
523 } break;
524
525 default: return 0;
526 }
527 }
528
530 uint8_t pressNote(uint8_t note, uint8_t channel) {
531 // Remove existing similar note
532 auto it = std::find(heldNotes.begin(), heldNotes.end(), note);
533 if (it != heldNotes.end())
534 heldNotes.erase(it);
535 // Push note
536 heldNotes.push_back(note);
537 // Determine actual channel
538 if (polyMode == MPE_MODE) {
539 // Channel is already decided for us
540 }
541 else {
542 channel = assignChannel(note);
543 }
544 // Set note
545 notes[channel] = note;
546 gates[channel] = true;
547 retriggerPulses[channel].trigger(1e-3);
548 return channel;
549 }
550
551 void releaseNote(uint8_t note) {
552 // Remove the note
553 auto it = std::find(heldNotes.begin(), heldNotes.end(), note);
554 if (it != heldNotes.end())
555 heldNotes.erase(it);
556 // Hold note if pedal is pressed
557 if (pedal)
558 return;
559 // Turn off gate of all channels with note
560 for (uint8_t c = 0; c < channels; c++) {
561 if (notes[c] == note) {
562 gates[c] = false;
563 }
564 }
565 // Set last note if monophonic
566 if (channels == 1) {
567 if (note == notes[0] && !heldNotes.empty()) {
568 uint8_t lastNote = heldNotes.back();
569 notes[0] = lastNote;
570 gates[0] = true;
571 return;
572 }
573 }
574 }
575
576 void pressPedal() {
577 if (pedal)
578 return;
579 pedal = true;
580 }
581
583 if (!pedal)
584 return;
585 pedal = false;
586 // Set last note if monophonic
587 if (channels == 1) {
588 if (!heldNotes.empty()) {
589 // Replace note with last held note
590 uint8_t lastNote = heldNotes.back();
591 notes[0] = lastNote;
592 }
593 else {
594 // Disable gate
595 gates[0] = false;
596 }
597 }
598 // Clear notes that are not held if polyphonic
599 else {
600 for (uint8_t c = 0; c < channels; c++) {
601 if (!gates[c])
602 continue;
603 // Disable all gates
604 gates[c] = false;
605 // Re-enable gate if channel's note is still held
606 for (uint8_t note : heldNotes) {
607 if (notes[c] == note) {
608 gates[c] = true;
609 break;
610 }
611 }
612 }
613 }
614 }
615
616 uint8_t getChannels() {
617 return channels;
618 }
619
620 void setChannels(uint8_t channels) {
621 if (channels == this->channels)
622 return;
623 this->channels = channels;
624 panic();
625 }
626
628 if (polyMode == this->polyMode)
629 return;
630 this->polyMode = polyMode;
631 panic();
632 }
633
634 float getPitchVoltage(uint8_t channel) {
635 uint8_t wheelChannel = (polyMode == MPE_MODE) ? channel : 0;
636 return (notes[channel] - 60.f + pwFilters[wheelChannel].out * pwRange) / 12.f;
637 }
638
640 void setFilterLambda(float lambda) {
641 for (uint8_t c = 0; c < MAX_CHANNELS; c++) {
642 pwFilters[c].setLambda(lambda);
643 modFilters[c].setLambda(lambda);
644 }
645 }
646
648 float getPw(uint8_t channel) {
649 return pwFilters[channel].out;
650 }
651
653 float getMod(uint8_t channel) {
654 return modFilters[channel].out;
655 }
656
659 return (polyMode == MPE_MODE) ? MAX_CHANNELS : 1;
660 }
661
662 json_t* toJson() {
663 json_t* rootJ = json_object();
664 json_object_set_new(rootJ, "pwRange", json_real(pwRange));
665 json_object_set_new(rootJ, "smooth", json_boolean(smooth));
666 json_object_set_new(rootJ, "channels", json_integer(channels));
667 json_object_set_new(rootJ, "polyMode", json_integer(polyMode));
668 json_object_set_new(rootJ, "clockDivision", json_integer(clockDivision));
669 // Saving/restoring pitch and mod doesn't make much sense for MPE.
670 if (polyMode != MPE_MODE) {
671 json_object_set_new(rootJ, "lastPw", json_integer(pws[0]));
672 json_object_set_new(rootJ, "lastMod", json_integer(mods[0]));
673 }
674 // Assume all filter lambdas are the same
675 json_object_set_new(rootJ, "filterLambda", json_real(pwFilters[0].lambda));
676 return rootJ;
677 }
678
679 void fromJson(json_t* rootJ) {
680 json_t* pwRangeJ = json_object_get(rootJ, "pwRange");
681 if (pwRangeJ)
682 pwRange = json_number_value(pwRangeJ);
683
684 json_t* smoothJ = json_object_get(rootJ, "smooth");
685 if (smoothJ)
686 smooth = json_boolean_value(smoothJ);
687
688 json_t* channelsJ = json_object_get(rootJ, "channels");
689 if (channelsJ)
690 setChannels(json_integer_value(channelsJ));
691
692 json_t* polyModeJ = json_object_get(rootJ, "polyMode");
693 if (polyModeJ)
694 polyMode = (PolyMode) json_integer_value(polyModeJ);
695
696 json_t* clockDivisionJ = json_object_get(rootJ, "clockDivision");
697 if (clockDivisionJ)
698 clockDivision = json_integer_value(clockDivisionJ);
699
700 json_t* lastPwJ = json_object_get(rootJ, "lastPw");
701 if (lastPwJ)
702 pws[0] = json_integer_value(lastPwJ);
703
704 // In Rack <2.5.3, `lastPitch` was used from 0 to 16383.
705 json_t* lastPitchJ = json_object_get(rootJ, "lastPitch");
706 if (lastPitchJ)
707 pws[0] = json_integer_value(lastPitchJ) - 8192;
708
709 json_t* lastModJ = json_object_get(rootJ, "lastMod");
710 if (lastModJ)
711 mods[0] = json_integer_value(lastModJ);
712
713 // Added in Rack 2.5.3
714 json_t* filterLambdaJ = json_object_get(rootJ, "filterLambda");
715 if (filterLambdaJ)
716 setFilterLambda(json_number_value(filterLambdaJ));
717 }
718};
719
720
721} // namespace dsp
722} // namespace rack
int clamp(int x, int a, int b)
Limits x between a and b.
Definition math.hpp:32
Root namespace for the Rack API.
Definition AudioDisplay.hpp:9
Converts gates and CV to MIDI messages.
Definition midi.hpp:17
bool gates[CHANNELS]
Definition midi.hpp:20
void reset()
Definition midi.hpp:35
void setSustainPedal(int8_t cc)
Definition midi.hpp:153
void setChannelPressure(int8_t val)
Definition midi.hpp:111
void setContinue(bool cont)
Definition midi.hpp:200
void panic()
Definition midi.hpp:53
bool stop
Definition midi.hpp:27
bool cont
Definition midi.hpp:28
MidiGenerator()
Definition midi.hpp:31
void setPitchWheel(int16_t pw)
Definition midi.hpp:157
void setCc(int8_t cc, int id)
Definition midi.hpp:124
void setBalance(int8_t cc)
Definition midi.hpp:145
bool start
Definition midi.hpp:26
void setPan(int8_t cc)
Definition midi.hpp:149
int8_t notes[CHANNELS]
Definition midi.hpp:19
int16_t pw
Definition midi.hpp:24
void setNoteGate(int8_t note, bool gate, int c)
Definition midi.hpp:72
void setClock(bool clk)
Definition midi.hpp:170
void setFrame(int64_t frame)
Definition midi.hpp:230
void setVelocity(int8_t vel, int c)
Must be called before setNoteGate().
Definition midi.hpp:68
int8_t channelPressure
Definition midi.hpp:22
void setStop(bool stop)
Definition midi.hpp:215
bool clk
Definition midi.hpp:25
void setVolume(int8_t cc)
Definition midi.hpp:141
void setKeyPressure(int8_t val, int c)
Definition midi.hpp:98
int8_t ccs[128]
Definition midi.hpp:23
void setModWheel(int8_t cc)
Definition midi.hpp:137
int8_t keyPressures[CHANNELS]
Definition midi.hpp:21
void setStart(bool start)
Definition midi.hpp:185
int64_t frame
Definition midi.hpp:29
int8_t vels[CHANNELS]
Definition midi.hpp:18
virtual void onMessage(const midi::Message &message)
Definition midi.hpp:234
Converts MIDI note and transport messages to gates, CV, and other states.
Definition midi.hpp:242
dsp::PulseGenerator retriggerPulses[MAX_CHANNELS]
Definition midi.hpp:295
uint8_t velocities[MAX_CHANNELS]
Definition midi.hpp:277
bool smooth
Enables pitch-wheel and mod-wheel exponential smoothing.
Definition midi.hpp:249
void setFilterLambda(float lambda)
Sets exponential smoothing filter lambda speed.
Definition midi.hpp:640
void setChannels(uint8_t channels)
Definition midi.hpp:620
bool gates[MAX_CHANNELS]
Definition midi.hpp:276
uint8_t channels
Actual number of polyphonic channels.
Definition midi.hpp:255
void releasePedal()
Definition midi.hpp:582
dsp::PulseGenerator clockDividerPulse
Definition midi.hpp:294
float getPw(uint8_t channel)
Returns pitch wheel value, from -1 to 1.
Definition midi.hpp:648
dsp::PulseGenerator stopPulse
Definition midi.hpp:297
uint8_t pressNote(uint8_t note, uint8_t channel)
Returns actual assigned channel.
Definition midi.hpp:530
uint8_t getWheelChannels()
Returns number of polyphonic channels for pitch and mod wheels.
Definition midi.hpp:658
dsp::ExponentialFilter pwFilters[MAX_CHANNELS]
Smoothing filters for wheel values.
Definition midi.hpp:290
void setPolyMode(PolyMode polyMode)
Definition midi.hpp:627
uint8_t assignChannel(uint8_t note)
Definition midi.hpp:483
PolyMode polyMode
Definition midi.hpp:265
uint8_t aftertouches[MAX_CHANNELS]
Definition midi.hpp:278
int64_t clock
Clock index from song start.
Definition midi.hpp:270
float getMod(uint8_t channel)
Returns mod wheel value, from 0 to 1.
Definition midi.hpp:653
float getPitchVoltage(uint8_t channel)
Definition midi.hpp:634
dsp::PulseGenerator startPulse
Definition midi.hpp:296
void panic()
Resets performance state.
Definition midi.hpp:318
std::vector< uint8_t > heldNotes
Definition midi.hpp:279
bool pedal
Whether sustain pedal is held.
Definition midi.hpp:273
void processFilters(float deltaTime)
Definition midi.hpp:335
MidiParser()
Definition midi.hpp:300
json_t * toJson()
Definition midi.hpp:662
float pwRange
Number of semitones to bend up/down by pitch wheel.
Definition midi.hpp:246
dsp::PulseGenerator clockPulse
Definition midi.hpp:293
uint8_t mods[MAX_CHANNELS]
Mod wheel values, from 0 to 127.
Definition midi.hpp:288
dsp::PulseGenerator continuePulse
Definition midi.hpp:298
int16_t pws[MAX_CHANNELS]
Pitch wheel values, from -8192 to 8191.
Definition midi.hpp:285
uint32_t clockDivision
Number of 24 PPQN clocks between clock divider pulses.
Definition midi.hpp:252
void pressPedal()
Definition midi.hpp:576
int8_t rotateIndex
Definition midi.hpp:280
dsp::ExponentialFilter modFilters[MAX_CHANNELS]
Definition midi.hpp:291
uint8_t notes[MAX_CHANNELS]
Definition midi.hpp:275
PolyMode
Method for assigning notes to polyphony channels.
Definition midi.hpp:258
@ ROTATE_MODE
Definition midi.hpp:259
@ REUSE_MODE
Definition midi.hpp:260
@ RESET_MODE
Definition midi.hpp:261
@ NUM_POLY_MODES
Definition midi.hpp:263
@ MPE_MODE
Definition midi.hpp:262
void processCC(const midi::Message &msg)
Definition midi.hpp:427
void processMessage(const midi::Message &msg)
Definition midi.hpp:365
void reset()
Resets settings and performance state.
Definition midi.hpp:306
void processPulses(float deltaTime)
Definition midi.hpp:354
void fromJson(json_t *rootJ)
Definition midi.hpp:679
void processSystem(const midi::Message &msg)
Definition midi.hpp:451
void releaseNote(uint8_t note)
Definition midi.hpp:551
uint8_t getChannels()
Definition midi.hpp:616
When triggered, holds a high value for a specified time before going low again.
Definition digital.hpp:167
void trigger(float duration=1e-3f)
Begins a trigger with the given duration.
Definition digital.hpp:189
bool process(float deltaTime)
Advances the state by deltaTime.
Definition digital.hpp:176
Applies exponential smoothing to a signal with the ODE .
Definition filter.hpp:59
T process(T deltaTime, T in)
Definition filter.hpp:76
void setLambda(T lambda)
Definition filter.hpp:67
void reset()
Definition filter.hpp:63
T out
Definition filter.hpp:60
Definition midi.hpp:16
void setSize(int size)
Definition midi.hpp:31
void setFrame(int64_t frame)
Definition midi.hpp:85
void setValue(uint8_t value)
Definition midi.hpp:73
void setStatus(uint8_t status)
Definition midi.hpp:51
uint8_t getNote() const
Definition midi.hpp:57
void setNote(uint8_t note)
Definition midi.hpp:62
void setChannel(uint8_t channel)
Definition midi.hpp:40
uint8_t getChannel() const
Definition midi.hpp:35
uint8_t getStatus() const
Definition midi.hpp:46
uint8_t getValue() const
Definition midi.hpp:68