11/* * Example of setting reading MIDI Input via UART
2- *
32 *
43 * This can be used with any 5-pin DIN or TRS connector that has been wired up
54 * to one of the UART Rx pins on Daisy.
65 * This will use D14 as the UART 1 Rx pin
76 *
87 * This example will also log incoming messages to the serial port for general MIDI troubleshooting
8+ *
9+ * This includes a demonstration of managing System Realtime messages immediately via
10+ * an optional callback. This can be disabled by setting, `kUseRealtimeCallback` to false.
11+ * in which case all messages while run through the typical MIDI event queue.
912 */
1013#include " daisy_seed.h"
1114
1215/* * This prevents us from having to type "daisy::" in front of a lot of things. */
1316using namespace daisy ;
1417
18+ /* * Select whether to use the optional system realtime callback or not. */
19+ constexpr const bool kUseRealtimeCallback = true ;
20+
21+ /* * Indicates from where the MIDI Message was logged */
22+ enum class Source
23+ {
24+ Queue,
25+ RealtimeCb,
26+ Unknown,
27+ };
28+
29+ /* * Wrapper type that adds a timestamp and source to the MIDI event. */
30+ struct SourcedMidiEvent
31+ {
32+ MidiEvent message;
33+ Source src;
34+ uint32_t timestamp;
35+
36+ SourcedMidiEvent (MidiEvent e, Source s)
37+ {
38+ message = e;
39+ src = s;
40+ timestamp = System::GetNow ();
41+ }
42+
43+ SourcedMidiEvent () : src(Source::Unknown), timestamp(0xffffffff ) {}
44+ };
45+
1546/* * Global Hardware access */
1647DaisySeed hw;
1748MidiUartHandler midi;
1849
1950/* * FIFO to hold messages as we're ready to print them */
20- FIFO <MidiEvent, 128 > event_log;
51+ FIFO <SourcedMidiEvent, 128 > event_log;
52+
53+
54+ /* * Helper for getting human readable strings from realtime messages */
55+ const char * GetStringForRealTimeType (SystemRealTimeType type)
56+ {
57+ switch (type)
58+ {
59+ case SystemRealTimeType::TimingClock: return " Timing Clock" ;
60+ case SystemRealTimeType::SRTUndefined0: return " SRT Undefined0" ;
61+ case SystemRealTimeType::Start: return " Start" ;
62+ case SystemRealTimeType::Continue: return " Continue" ;
63+ case SystemRealTimeType::Stop: return " Stop" ;
64+ case SystemRealTimeType::SRTUndefined1: return " SRT Undefined1" ;
65+ case SystemRealTimeType::ActiveSensing: return " ActiveSensing" ;
66+ case SystemRealTimeType::Reset: return " Reset" ;
67+ default : return " Unknown Type..." ;
68+ }
69+ }
70+
71+ /* * Helper for getting a string for the source */
72+ const char * GetStringForSource (Source src)
73+ {
74+ switch (src)
75+ {
76+ case Source::Queue: return " Queue" ;
77+ case Source::RealtimeCb: return " Realtime Callback" ;
78+ case Source::Unknown:
79+ default : return " Unknown" ;
80+ }
81+ }
82+
83+ /* * Optional callback for synchronous realtime message handling
84+ *
85+ * Typically, you would handle your timing-sensitive behavior
86+ * right here to take advantage of the syncronous handling.
87+ * In this case, we're just going to forward this to the log
88+ * to make sure no messages are missed.
89+ */
90+ void MidiRealtimeCallback (MidiEvent& event)
91+ {
92+ auto ev = SourcedMidiEvent (event, Source::RealtimeCb);
93+ event_log.PushBack (ev);
94+ }
2195
2296int main (void )
2397{
@@ -29,7 +103,14 @@ int main(void)
29103 MidiUartHandler::Config midi_config;
30104 midi.Init (midi_config);
31105
32- midi.StartReceive ();
106+ if (kUseRealtimeCallback )
107+ {
108+ midi.StartReceiveRt (MidiRealtimeCallback);
109+ }
110+ else
111+ {
112+ midi.StartReceive ();
113+ }
33114
34115 uint32_t now = System::GetNow ();
35116 uint32_t log_time = System::GetNow ();
@@ -39,10 +120,10 @@ int main(void)
39120 {
40121 now = System::GetNow ();
41122
42- /* * Process MIDI in the background */
123+ /* * Monitor MIDI status, and trigger recovery of MIDI Rx if necessary */
43124 midi.Listen ();
44125
45- /* * Loop through any MIDI Events */
126+ /* * Loop through any MIDI Events in the queue */
46127 while (midi.HasEvents ())
47128 {
48129 MidiEvent msg = midi.PopEvent ();
@@ -56,16 +137,17 @@ int main(void)
56137 // Do something on Note On events
57138 {
58139 uint8_t bytes[3 ] = {0x90 , 0x00 , 0x00 };
59- bytes[1 ] = msg.data [0 ];
60- bytes[2 ] = msg.data [1 ];
140+ bytes[1 ] = msg.data [0 ];
141+ bytes[2 ] = msg.data [1 ];
61142 midi.SendMessage (bytes, 3 );
62143 }
63144 break ;
64145 default : break ;
65146 }
66147
67- /* * Regardless of message, let's add the message data to our queue to output */
68- event_log.PushBack (msg);
148+ /* * Regardless of message, let's add the message data to our queue to output to the log */
149+ auto ev = SourcedMidiEvent (msg, Source::Queue);
150+ event_log.PushBack (ev);
69151 }
70152
71153 /* * Now separately, every 5ms we'll print the top message in our queue if there is one */
@@ -74,17 +156,35 @@ int main(void)
74156 log_time = now;
75157 if (!event_log.IsEmpty ())
76158 {
77- auto msg = event_log.PopFront ();
78- char outstr[128 ];
159+ auto event = event_log.PopFront ();
160+ auto msg = event.message ;
161+ char outstr[128 ];
79162 const char * type_str = MidiEvent::GetTypeAsString (msg);
80- sprintf (outstr,
81- " time:\t %ld\t type: %s\t Channel: %d\t Data MSB: "
82- " %d\t Data LSB: %d\n " ,
83- now,
84- type_str,
85- msg.channel ,
86- msg.data [0 ],
87- msg.data [1 ]);
163+ if (msg.type == MidiMessageType::SystemRealTime)
164+ {
165+ const char * src_str = GetStringForSource (event.src );
166+ const char * desc_str
167+ = GetStringForRealTimeType (msg.srt_type );
168+ sprintf (outstr,
169+ " time:\t %ld\t type: %s - %s\t source: %s\n " ,
170+ event.timestamp ,
171+ type_str,
172+ desc_str,
173+ src_str);
174+ }
175+ else
176+ {
177+ // Only realtime messages are capable of hitting the realtime
178+ // callback so we do not need to include the source here.
179+ sprintf (outstr,
180+ " time:\t %ld\t type: %s\t Channel: %d\t Data MSB: "
181+ " %d\t Data LSB: %d\n " ,
182+ event.timestamp ,
183+ type_str,
184+ msg.channel ,
185+ msg.data [0 ],
186+ msg.data [1 ]);
187+ }
88188 hw.PrintLine (outstr);
89189 }
90190 }
0 commit comments