@@ -7,7 +7,7 @@ void Performance::Setup() {
77}
88
99void Performance::Loop () {
10- if (stfuTimer.Tick (10 ))
10+ if (stfu && stfuTimer.Tick (10 ))
1111 { stfuScan (); }
1212
1313 struct KeyEvent keyEvent;
@@ -16,20 +16,24 @@ void Performance::Loop() {
1616
1717 struct MidiPacket midiPacket;
1818 while (MatrixOS::MIDI::Get (&midiPacket))
19- { MidiEventHandler (midiPacket, true ); }
19+ { MidiEventHandler (midiPacket); }
2020}
2121
22- void Performance::MidiEventHandler (MidiPacket midiPacket, bool renderOnActive ) {
22+ void Performance::MidiEventHandler (MidiPacket midiPacket) {
2323 // MatrixOS::Logging::LogDebug("Performance", "Midi Recived %d %d %d %d", midiPacket.status, midiPacket.data[0],
2424 // midiPacket.data[1], midiPacket.data[2]);
2525 switch (midiPacket.status )
2626 {
2727 case NoteOn:
2828 case ControlChange:
29- NoteHandler (midiPacket.channel (), midiPacket.note (), midiPacket.velocity (), renderOnActive );
29+ NoteHandler (midiPacket.channel (), midiPacket.note (), midiPacket.velocity ());
3030 break ;
3131 case NoteOff:
32- NoteHandler (midiPacket.channel (), midiPacket.note (), 0 , renderOnActive);
32+ NoteHandler (midiPacket.channel (), midiPacket.note (), 0 );
33+ break ;
34+ case SysExData:
35+ case SysExEnd:
36+ SysExHandler (midiPacket);
3337 break ;
3438 default :
3539 break ;
@@ -95,7 +99,7 @@ int8_t Performance::XYToNote(Point xy) {
9599 return -1 ;
96100}
97101
98- void Performance::NoteHandler (uint8_t channel, uint8_t note, uint8_t velocity, bool renderOnActive ) {
102+ void Performance::NoteHandler (uint8_t channel, uint8_t note, uint8_t velocity) {
99103 // MatrixOS::Logging::LogDebug("Performance", "Midi Recivied %#02X %#02X %#02X", channel, note, velocity);
100104 Point xy = NoteToXY (note);
101105
@@ -104,20 +108,13 @@ void Performance::NoteHandler(uint8_t channel, uint8_t note, uint8_t velocity, b
104108 channel = 1 ; // So it will use legacy palette
105109 }
106110
111+
107112 if (xy && !(velocity == 0 && stfu))
108113 {
109114 // MatrixOS::Logging::LogDebug("Performance", "Set LED");
110- MatrixOS::LED::SetColor (xy, palette[channel % 2 ][velocity], renderOnActive? 0 : canvasLedLayer );
115+ MatrixOS::LED::SetColor (xy, palette[channel % 2 ][velocity], uiOpened ? canvasLedLayer : 0 );
111116 }
112- // else if(!xy)
113- // {
114- // MatrixOS::Logging::LogDebug("Performance", "XY incorrect");
115- // }
116- // else if((velocity == 0 && stfu))
117- // {
118- // MatrixOS::Logging::LogDebug("Performance", "STFU");
119- // }
120- if (stfu)
117+ else if (stfu)
121118 {
122119 if (velocity == 0 )
123120 { stfuMap[note] = stfu; }
@@ -126,6 +123,156 @@ void Performance::NoteHandler(uint8_t channel, uint8_t note, uint8_t velocity, b
126123 }
127124}
128125
126+ vector<uint8_t > sysExBuffer;
127+ void Performance::SysExHandler (MidiPacket midiPacket)
128+ {
129+ // New SysEx, clear buffer
130+ if (sysExBuffer.empty ())
131+ {
132+ sysExBuffer.reserve (400 );
133+ }
134+
135+ // Insert data to buffer
136+ sysExBuffer.insert (sysExBuffer.end (), midiPacket.data , midiPacket.data + midiPacket.Length ());
137+
138+ // If not end of sysex, return, do not parse
139+ if (midiPacket.status != SysExEnd)
140+ { return ; }
141+
142+ // Get rid of the 0xF7 ending byte
143+ sysExBuffer.pop_back ();
144+
145+ // Parsing because sysex is completed
146+ switch (sysExBuffer[0 ])
147+ {
148+ case 0x5f : // Apollo batch fill - https://github.com/mat1jaczyyy/lpp-performance-cfw/blob/0c2ec2a71030306ab7e5491bd49d72440d8c0199/src/sysex/sysex.c#L54-L120
149+ {
150+ // MatrixOS::Logging::LogDebug("Performance", "Apollo batch Fill");
151+ if (sysExBuffer.size () < 5 ) { return ; }
152+
153+ uint8_t targetLayer = uiOpened ? canvasLedLayer : 0 ;
154+
155+ uint16_t ptr = 1 ; // Index 0 is the command 0x5f, we start ptr at 1
156+ while (ptr < sysExBuffer.size ())
157+ {
158+ // Extract the color data
159+ uint8_t colorR = (sysExBuffer[ptr] & 0x3F );
160+ uint8_t colorG = (sysExBuffer[ptr + 1 ] & 0x3F );
161+ uint8_t colorB = (sysExBuffer[ptr + 2 ] & 0x3F );
162+
163+ // Remapped color from 6 bit to 8 bit
164+ colorR = (colorR << 2 ) + (colorR >> 4 );
165+ colorG = (colorG << 2 ) + (colorG >> 4 );
166+ colorB = (colorB << 2 ) + (colorB >> 4 );
167+
168+ // Create the color
169+ Color color = Color (colorR, colorG, colorB);
170+
171+ // Get how many NN (Note Numbers) follows
172+ uint8_t n_count = ((sysExBuffer[ptr] & 0x40 ) >> 4 ) | ((sysExBuffer[ptr + 1 ] & 0x40 ) >> 5 ) | ((sysExBuffer[ptr + 2 ] & 0x40 ) >> 6 );
173+
174+ ptr += 3 ; // We finish reading the first 3 bit, inc the ptr by 3
175+
176+ // If nums of NN is 0, then the next byte is the number of NN
177+ if (n_count == 0 ) { n_count = sysExBuffer[ptr++]; } // If all 3 bits are 0, then it's 64 (0b111111
178+
179+ // MatrixOS::Logging::LogDebug("Performance", "Color: #%.2X%.2X%.2X, NN count: %d", color.R, color.G, color.B, n_count);
180+
181+ // Goes through all N
182+ for (uint16_t n = 0 ; n < n_count; n++)
183+ {
184+ if (sysExBuffer[ptr] == 0 ) // Global full
185+ { MatrixOS::LED::Fill (color, targetLayer); }
186+ else if (sysExBuffer[ptr] < 99 ) // Grid
187+ {
188+ Point xy = Point (sysExBuffer[ptr] % 10 - 1 , 8 - (sysExBuffer[ptr] / 10 ));
189+ // MatrixOS::Logging::LogDebug("Performance", "Grid %d %d", xy.x, xy.y);
190+ MatrixOS::LED::SetColor (xy, color, targetLayer);
191+ }
192+ else if (sysExBuffer[ptr] == 99 ) // Mode Light
193+ {
194+ // Not implemented - Maybe a TODO
195+ }
196+ else if (sysExBuffer[ptr] < 110 ) // Row Fill
197+ {
198+ int8_t row = 108 - sysExBuffer[ptr];
199+ for (int8_t x = 0 ; x < 10 ; x++)
200+ { MatrixOS::LED::SetColor (Point (x, row), color, targetLayer); }
201+ }
202+ else if (sysExBuffer[ptr] < 120 ) // Column Fill
203+ {
204+ int8_t column = sysExBuffer[ptr] - 111 ;
205+ for (int8_t y = 0 ; y < 10 ; y++)
206+ { MatrixOS::LED::SetColor (Point (column, y), color, targetLayer); }
207+ }
208+ ptr++; // Since ptr is the pointer of in vector, we need to read the next NN, inc the ptr by 1
209+ }
210+ }
211+ break ;
212+ }
213+ case 0x5e : // Apollo regular fill - https://github.com/mat1jaczyyy/lpp-performance-cfw/blob/0c2ec2a71030306ab7e5491bd49d72440d8c0199/src/sysex/sysex.c#L115
214+ {
215+ // MatrixOS::Logging::LogDebug("Performance", "Apollo batch Fill");
216+ if (sysExBuffer.size () < 5 ) { return ; }
217+
218+ uint8_t targetLayer = uiOpened ? canvasLedLayer : 0 ;
219+
220+ uint16_t ptr = 1 ; // Index 0 is the command 0x5f, we start ptr at 1
221+ while (ptr < sysExBuffer.size ())
222+ {
223+ // Extract the color data
224+ uint8_t index = sysExBuffer[ptr];
225+ uint8_t colorR = (sysExBuffer[ptr + 1 ] & 0x3F );
226+ uint8_t colorG = (sysExBuffer[ptr + 2 ] & 0x3F );
227+ uint8_t colorB = (sysExBuffer[ptr + 3 ] & 0x3F );
228+
229+ // Remapped color from 6 bit to 8 bit
230+ colorR = (colorR << 2 ) + (colorR >> 4 );
231+ colorG = (colorG << 2 ) + (colorG >> 4 );
232+ colorB = (colorB << 2 ) + (colorB >> 4 );
233+
234+ // Create the color
235+ Color color = Color (colorR, colorG, colorB);
236+
237+ ptr += 4 ; // We finish reading the first 3 bit, inc the ptr by 3
238+
239+ // MatrixOS::Logging::LogDebug("Performance", "Color: #%.2X%.2X%.2X, NN count: %d", color.R, color.G, color.B, n_count);
240+
241+ if (index == 0 ) // Global full
242+ { MatrixOS::LED::Fill (color, targetLayer); }
243+ else if (index < 99 ) // Grid
244+ {
245+ Point xy = Point (index % 10 - 1 , 8 - (index / 10 ));
246+ MatrixOS::LED::SetColor (xy, color, targetLayer);
247+ }
248+ else if (index == 99 ) // Mode Light
249+ {
250+ // Not implemented - Maybe a TODO
251+ }
252+ else if (index < 110 ) // Row Fill
253+ {
254+ int8_t row = 108 - index;
255+ for (int8_t x = 0 ; x < 10 ; x++)
256+ { MatrixOS::LED::SetColor (Point (x, row), color, targetLayer); }
257+ }
258+ else if (index < 120 ) // Column Fill
259+ {
260+ int8_t column = index - 111 ;
261+ for (int8_t y = 0 ; y < 10 ; y++)
262+ { MatrixOS::LED::SetColor (Point (column, y), color, targetLayer); }
263+ }
264+ }
265+ break ;
266+ }
267+
268+ default :
269+ break ;
270+ }
271+
272+ // Clear buffer since we are done parsing SysEx
273+ sysExBuffer.clear ();
274+ }
275+
129276void Performance::KeyEventHandler (uint16_t KeyID, KeyInfo* keyInfo) {
130277 Point xy = MatrixOS::KEYPAD::ID2XY (KeyID);
131278 if (xy) // IF XY is vaild, means it's on the main grid
@@ -154,6 +301,7 @@ void Performance::IDKeyEvent(uint16_t keyID, KeyInfo* keyInfo) {
154301 if (keyID == 0 && keyInfo->state == (menuLock ? HOLD : PRESSED))
155302 {
156303 // MatrixOS::LED::CopyLayer(0, canvasLedLayer);
304+ MatrixOS::MIDI::Send (MidiPacket (0 , ControlChange, 0 , 121 , 0 )); // For Apollo Clearing
157305 ActionMenu ();
158306 }
159307}
@@ -237,7 +385,7 @@ void Performance::ActionMenu() {
237385 actionMenu.SetLoopFunc ([&]() -> void { // Keep buffer updated even when action menu is currently open
238386 struct MidiPacket midiPacket;
239387 while (MatrixOS::MIDI::Get (&midiPacket))
240- { MidiEventHandler (midiPacket, false ); }
388+ { MidiEventHandler (midiPacket); }
241389 });
242390
243391 actionMenu.SetKeyEventHandler ([&](KeyEvent* keyEvent) -> bool {
@@ -252,7 +400,11 @@ void Performance::ActionMenu() {
252400 return false ;
253401 });
254402
403+ MatrixOS::LED::CopyLayer (canvasLedLayer, 0 );
404+
405+ uiOpened = true ;
255406 actionMenu.Start ();
407+ uiOpened = false ;
256408
257409 MatrixOS::Logging::LogDebug (name, " Exit Action Menu" );
258410}
0 commit comments