QC

DIY USB MIDI DAW Controller

USB MIDI controller to FULLY control the functions and interface of your DAW tracks (auto-mapped in ABLETON)

Devices and components

Arduino due

Rotary encoder buttons

12mm push buttons

Fader Potentiometer 10kOhm Linear (88mm)

Crius TRX Control PCB v1.0

Crius TRX Control v1.0 3D Printed Case

M3 screw 10mm

Branch Wiring Kit, 22 AWG

20mm rotary encoders

Fader potentiometer button

MCP23017 I/O Expansion [DIP 28]

2.8mm flat connectors

2.54mm Pitch 8P PCB Screw Terminal Block Connector

HC4067E analog multiplexer [DIP24]

LED strip WS2812B (60LEDs/m) IP30

SSD1306 SPI OLED Displays (7 pin)

2.54mm Pitch 4P PCB Screw Terminal Block Connector

2.54mm Pitch 3P PCB Screw Terminal Block Connector

5 Way Navigation Button Switch Module

2.54mm Pitch 5P PCB Screw Terminal Block Connector

Micro USB Male Connector to Micro USB Female Extension Cable

Materials and tools

Thread cutter

Stripping pliers

Soldering iron (generic)

Soldering Wire

small Phillips screwdriver

tweezers

Software and tools

Arduino IDE

Fusion360

Project description

The Crius “TRX Control” MIDI DAW controller consists of:

16 rotary encoders

40 buttons

4 OLED screens

1 five-way switch joystick

and 1 linear fader

TRACK VOLUME (for 8 tracks + master volume)

PAN (for 8 tracks)

MUTE (for 8 tracks)

SOLO (for 8 tracks)

REC ARM (for 8 tracks)

RECORD

Fast forward

Rewind

Punch In/Punch Out

Crius TRX Control v1.0

1#include <Wire.h>
2#include <FastLED.h>
3#include <Control_Surface.h>
4
5#include <AH/Hardware/MCP23017Encoders.hpp>
6
7// Include the display interface you'd like to use
8#include <Display/DisplayInterfaces/DisplayInterfaceSSD1306.hpp>
9
10
11// ----------------------------- MIDI Interface ----------------------------- //
12// ========================================================================== //
13/*
14 Instantiate a MIDI interface to use for the Control Surface.
15*/
16
17// Instantiate a MIDI over USB interface.
18USBMIDI_Interface midi;
19
20// ----------------------------- Display setup ------------------------------ //
21// ========================================================================== //
22/*
23 Instantiate and initialize the SSD1306 OLED display
24*/
25
26constexpr uint8_t SCREEN_WIDTH = 128;
27constexpr uint8_t SCREEN_HEIGHT = 64;
28
29constexpr int8_t OLED_CLK_1_2 = 7; //D0 pin on OLED Display PCB
30constexpr int8_t OLED_CLK_3_4 = 7;
31constexpr int8_t OLED_CLK_5_6 = 7;
32constexpr int8_t OLED_CLK_7_8 = 7;
33
34constexpr int8_t OLED_MOSI_1_2 = 8; //D1 pin on OLED Display PCB
35constexpr int8_t OLED_MOSI_3_4 = 8;
36constexpr int8_t OLED_MOSI_5_6 = 8;
37constexpr int8_t OLED_MOSI_7_8 = 8;
38
39constexpr int8_t OLED_reset_1_2 = -1; //RES (Reset) pin on OLED Display PCB
40constexpr int8_t OLED_reset_3_4 = -1;
41constexpr int8_t OLED_reset_5_6 = -1;
42constexpr int8_t OLED_reset_7_8 = -1;
43
44constexpr int8_t OLED_DC_1_2 = 10; //DC (Data/Command) pin on OLED Display PCB
45constexpr int8_t OLED_DC_3_4 = 10;
46constexpr int8_t OLED_DC_5_6 = 10;
47constexpr int8_t OLED_DC_7_8 = 10;
48
49constexpr int8_t OLED_CS_1_2 = 11; //CS (Chip Select) pin on OLED Display PCB
50constexpr int8_t OLED_CS_3_4 = 12;
51constexpr int8_t OLED_CS_5_6 = 9;
52constexpr int8_t OLED_CS_7_8 = 6;
53
54constexpr uint32_t SPI_Frequency = SPI_MAX_SPEED;
55
56
57// Instantiate the displays
58Adafruit_SSD1306 ssd1306Display_1_2(SCREEN_WIDTH, SCREEN_HEIGHT,
59 OLED_MOSI_1_2, OLED_CLK_1_2, OLED_DC_1_2, OLED_reset_1_2, OLED_CS_1_2);
60
61Adafruit_SSD1306 ssd1306Display_3_4(SCREEN_WIDTH, SCREEN_HEIGHT,
62 OLED_MOSI_3_4, OLED_CLK_3_4, OLED_DC_3_4, OLED_reset_3_4, OLED_CS_3_4);
63
64Adafruit_SSD1306 ssd1306Display_5_6(SCREEN_WIDTH, SCREEN_HEIGHT,
65 OLED_MOSI_5_6, OLED_CLK_5_6, OLED_DC_5_6, OLED_reset_5_6, OLED_CS_5_6);
66
67Adafruit_SSD1306 ssd1306Display_7_8(SCREEN_WIDTH, SCREEN_HEIGHT,
68 OLED_MOSI_7_8, OLED_CLK_7_8, OLED_DC_7_8, OLED_reset_7_8, OLED_CS_7_8);
69
70
71// --------------------------- Display interface ---------------------------- //
72// ========================================================================== //
73
74#if defined(ADAFRUIT_SSD1306_HAS_SETBUFFER) && ADAFRUIT_SSD1306_HAS_SETBUFFER
75// We'll use a static buffer to avoid dynamic memory usage, and to allow
76// multiple displays to reuse one single buffer.
77static uint8_t buffer[(SCREEN_WIDTH * SCREEN_HEIGHT + 7) / 8];
78#endif
79
80
81// Implement the display interface, specifically, the begin and drawBackground
82// methods.
83class MySSD1306_DisplayInterface : public SSD1306_DisplayInterface {
84 public:
85 MySSD1306_DisplayInterface(Adafruit_SSD1306 &display)
86 : SSD1306_DisplayInterface(display) {}
87
88 void begin() override {
89#if defined(ADAFRUIT_SSD1306_HAS_SETBUFFER) && ADAFRUIT_SSD1306_HAS_SETBUFFER
90 disp.setBuffer(buffer);
91#endif
92 // Initialize the Adafruit_SSD1306 display
93 if (!disp.begin())
94 FATAL_ERROR(F("SSD1306 initialization failed."), 0x1306);
95
96 // If you override the begin method, remember to call the super class method
97 SSD1306_DisplayInterface::begin();
98 }
99
100 void drawBackground() override {
101 disp.drawLine(1, 8, 126, 8, WHITE);
102 }
103
104} display_1_2 = ssd1306Display_1_2, display_3_4 = ssd1306Display_3_4, display_5_6 = ssd1306Display_5_6, display_7_8 = ssd1306Display_7_8;
105
106
107// ------------------------------- Bank setup ------------------------------- //
108// ========================================================================== //
109/*
110 Create a bank and a bank selector to change its setting.
111*/
112
113Bank<1> bank(8); // Create a new bank with two tracks per bank
114
115// -------------------------- MIDI Input Elements --------------------------- //
116// ========================================================================== //
117/*
118 Define all elements that listen for MIDI messages.
119*/
120
121// Main MCU LCD screen, used to get track names
122MCU::LCD<> lcd {};
123
124// Time display keeps track of the bar counter
125MCU::TimeDisplay timedisplay {};
126
127// Play / Record
128NoteValue play {MCU::PLAY};
129NoteValue record {MCU::RECORD};
130
131// Mute
132Bankable::NoteValue<1> mute[] {
133 {bank, MCU::MUTE_1},
134 {bank, MCU::MUTE_2},
135 {bank, MCU::MUTE_3},
136 {bank, MCU::MUTE_4},
137 {bank, MCU::MUTE_5},
138 {bank, MCU::MUTE_6},
139 {bank, MCU::MUTE_7},
140 {bank, MCU::MUTE_8},
141};
142
143// Solo
144Bankable::NoteValue<1> solo[] {
145 {bank, MCU::SOLO_1},
146 {bank, MCU::SOLO_2},
147 {bank, MCU::SOLO_3},
148 {bank, MCU::SOLO_4},
149 {bank, MCU::SOLO_5},
150 {bank, MCU::SOLO_6},
151 {bank, MCU::SOLO_7},
152 {bank, MCU::SOLO_8},
153};
154
155NoteValue rudeSolo {MCU::RUDE_SOLO};
156
157// Record arm / ready
158Bankable::NoteValue<1> recrdy[] {
159 {bank, MCU::REC_RDY_1},
160 {bank, MCU::REC_RDY_2},
161 {bank, MCU::REC_RDY_3},
162 {bank, MCU::REC_RDY_4},
163 {bank, MCU::REC_RDY_5},
164 {bank, MCU::REC_RDY_6},
165 {bank, MCU::REC_RDY_7},
166 {bank, MCU::REC_RDY_8},
167};
168
169
170// VU meters
171MCU::Bankable::VU<1> vu[] {
172 {bank, 1, MCU::VUDecay::Hold},
173 {bank, 2, MCU::VUDecay::Hold},
174 {bank, 3, MCU::VUDecay::Hold},
175 {bank, 4, MCU::VUDecay::Hold},
176 {bank, 5, MCU::VUDecay::Hold},
177 {bank, 6, MCU::VUDecay::Hold},
178 {bank, 7, MCU::VUDecay::Hold},
179 {bank, 8, MCU::VUDecay::Hold},
180};
181
182// VPot rings
183MCU::Bankable::VPotRing<1> vpot[] {
184 {bank, 1},
185 {bank, 2},
186 {bank, 3},
187 {bank, 4},
188 {bank, 5},
189 {bank, 6},
190 {bank, 7},
191 {bank, 8},
192};
193
194
195// ---------------------------- Display Elements ---------------------------- //
196// ========================================================================== //
197/*
198 Define all display elements that display the state of the input elements.
199*/
200
201// Track names
202MCU::LCDDisplay lcddisps[] {
203 // track (1), position (0, 40), font size (1)
204 {display_1_2, lcd, bank, 1, {0, 40}, 1, WHITE},
205 {display_1_2, lcd, bank, 2, {64, 40}, 1, WHITE},
206 {display_3_4, lcd, bank, 3, {0, 40}, 1, WHITE},
207 {display_3_4, lcd, bank, 4, {64, 40}, 1, WHITE},
208 {display_5_6, lcd, bank, 5, {0, 40}, 1, WHITE},
209 {display_5_6, lcd, bank, 6, {64, 40}, 1, WHITE},
210 {display_7_8, lcd, bank, 7, {0, 40}, 1, WHITE},
211 {display_7_8, lcd, bank, 8, {64, 40}, 1, WHITE},
212};
213
214// Time display
215MCU::TimeDisplayDisplay timedisplaydisplay {
216 // position (0, 0), font size (1)
217 display_1_2, timedisplay, {0, 0}, 1, WHITE,
218};
219
220// Play / Record
221BitmapDisplay<> playDisp {
222 display_1_2, play, XBM::play_7, {16 + 64, 0}, WHITE,
223};
224BitmapDisplay<> recordDisp {
225 display_1_2, record, XBM::record_7, {26 + 64, 0}, WHITE,
226};
227
228// Mute
229BitmapDisplay<> muteDisp[] {
230 {display_1_2, mute[0], XBM::mute_10B, {14, 50}, WHITE},
231 {display_1_2, mute[1], XBM::mute_10B, {14 + 64, 50}, WHITE},
232 {display_3_4, mute[2], XBM::mute_10B, {14, 50}, WHITE},
233 {display_3_4, mute[3], XBM::mute_10B, {14 + 64, 50}, WHITE},
234 {display_5_6, mute[4], XBM::mute_10B, {14, 50}, WHITE},
235 {display_5_6, mute[5], XBM::mute_10B, {14 + 64, 50}, WHITE},
236 {display_7_8, mute[6], XBM::mute_10B, {14, 50}, WHITE},
237 {display_7_8, mute[7], XBM::mute_10B, {14 + 64, 50}, WHITE},
238};
239
240// Solo
241BitmapDisplay<> soloDisp[] {
242 {display_1_2, solo[0], XBM::solo_10B, {14, 50}, WHITE},
243 {display_1_2, solo[1], XBM::solo_10B, {14 + 64, 50}, WHITE},
244 {display_3_4, solo[2], XBM::solo_10B, {14, 50}, WHITE},
245 {display_3_4, solo[3], XBM::solo_10B, {14 + 64, 50}, WHITE},
246 {display_5_6, solo[4], XBM::solo_10B, {14, 50}, WHITE},
247 {display_5_6, solo[5], XBM::solo_10B, {14 + 64, 50}, WHITE},
248 {display_7_8, solo[6], XBM::solo_10B, {14, 50}, WHITE},
249 {display_7_8, solo[7], XBM::solo_10B, {14 + 64, 50}, WHITE},
250};
251
252BitmapDisplay<> rudeSoloDisp {
253 display_7_8, rudeSolo, XBM::solo_7, {36 + 64, 0}, WHITE};
254
255// Record arm / ready
256BitmapDisplay<> recrdyDisp[] {
257 {display_1_2, recrdy[0], XBM::rec_rdy_10B, {14 + 14, 50}, WHITE},
258 {display_1_2, recrdy[1], XBM::rec_rdy_10B, {14 + 14 + 64, 50}, WHITE},
259 {display_3_4, recrdy[2], XBM::rec_rdy_10B, {14 + 14, 50}, WHITE},
260 {display_3_4, recrdy[3], XBM::rec_rdy_10B, {14 + 14 + 64, 50}, WHITE},
261 {display_5_6, recrdy[4], XBM::rec_rdy_10B, {14 + 14, 50}, WHITE},
262 {display_5_6, recrdy[5], XBM::rec_rdy_10B, {14 + 14 + 64, 50}, WHITE},
263 {display_7_8, recrdy[6], XBM::rec_rdy_10B, {14 + 14, 50}, WHITE},
264 {display_7_8, recrdy[7], XBM::rec_rdy_10B, {14 + 14 + 64, 50}, WHITE},
265};
266
267// VU meters
268MCU::VUDisplay<> vuDisp[] {
269 // position (32+11, 60), width (16), bar height (3) px, bar spacing (1) px
270 {display_1_2, vu[0], {32 + 11, 60}, 16, 3, 1, WHITE},
271 {display_1_2, vu[1], {32 + 11 + 64, 60}, 16, 3, 1, WHITE},
272 {display_3_4, vu[2], {32 + 11, 60}, 16, 3, 1, WHITE},
273 {display_3_4, vu[3], {32 + 11 + 64, 60}, 16, 3, 1, WHITE},
274 {display_5_6, vu[4], {32 + 11, 60}, 16, 3, 1, WHITE},
275 {display_5_6, vu[5], {32 + 11 + 64, 60}, 16, 3, 1, WHITE},
276 {display_7_8, vu[6], {32 + 11, 60}, 16, 3, 1, WHITE},
277 {display_7_8, vu[7], {32 + 11 + 64, 60}, 16, 3, 1, WHITE},
278
279};
280
281// VPot rings
282MCU::VPotDisplay<> vpotDisp[] {
283 // position (0, 10), outer radius (14) px, inner radius (12) px
284 {display_1_2, vpot[0], {0, 10}, 14, 12, WHITE},
285 {display_1_2, vpot[1], {64, 10}, 14, 12, WHITE},
286 {display_3_4, vpot[2], {0, 10}, 14, 12, WHITE},
287 {display_3_4, vpot[3], {64, 10}, 14, 12, WHITE},
288 {display_5_6, vpot[4], {0, 10}, 14, 12, WHITE},
289 {display_5_6, vpot[5], {64, 10}, 14, 12, WHITE},
290 {display_7_8, vpot[6], {0, 10}, 14, 12, WHITE},
291 {display_7_8, vpot[7], {64, 10}, 14, 12, WHITE},
292};
293
294// Bank seting
295BankDisplay bankDisp[] {
296 // first track of the bank (1), position (0, 50), font size (2)
297 {display_1_2, bank, 1, {0, 50}, 2, WHITE},
298 {display_1_2, bank, 2, {64, 50}, 2, WHITE},
299 {display_3_4, bank, 3, {0, 50}, 2, WHITE},
300 {display_3_4, bank, 4, {64, 50}, 2, WHITE},
301 {display_5_6, bank, 5, {0, 50}, 2, WHITE},
302 {display_5_6, bank, 6, {64, 50}, 2, WHITE},
303 {display_7_8, bank, 7, {0, 50}, 2, WHITE},
304 {display_7_8, bank, 8, {64, 50}, 2, WHITE},
305};
306
307// --------------------------Rotary Encoders (x16)--------------------------- //
308// ========================================================================== //
309//Track PAN Control Change Rotary Encoders (x8)
310
311// Type for the MCP23017 encoders (translates encoder pulses to position)
312using WireType = decltype(Wire); // The type of I²C driver to use
313using EncoderPositionType = uint8_t; // The type for saving encoder positions
314using MCPEncoderType = MCP23017Encoders<WireType, EncoderPositionType>;
315
316// Type for the MIDI encoders (translates position to MIDI messages)
317struct CCMCPEncoder : GenericMIDIRotaryEncoder<MCPEncoderType::MCP23017Encoder,
318 RelativeCCSender> {
319 CCMCPEncoder(MCPEncoderType::MCP23017Encoder enc, MIDIAddress address,
320 int16_t multiplier = 4, uint8_t pulsesPerStep = 4)
321 : GenericMIDIRotaryEncoder(std::move(enc), address, multiplier,
322 pulsesPerStep, {}) {}
323};
324
325// Type for the MIDI encoders (translates position to MIDI messages)
326struct PBMCPEncoder : GenericMIDIAbsoluteEncoder<MCPEncoderType::MCP23017Encoder,
327 PitchBendSender<14>> {
328 PBMCPEncoder(MCPEncoderType::MCP23017Encoder enc, MIDIAddress address,
329 int16_t multiplier = 512, uint8_t pulsesPerStep = 4)
330 : GenericMIDIAbsoluteEncoder(std::move(enc), address, multiplier,
331 pulsesPerStep, {}) {}
332};
333
334
335// Create an object that manages the 8 encoders connected to the MCP23017.
336MCPEncoderType encPAN {Wire, 0x20, 19};
337// │ │ └─ Interrupt pin
338// │ └────── Address offset
339// └──────────── I²C interface
340
341// Create an object that manages the 8 encoders connected to the MCP23017.
342MCPEncoderType encVOL {Wire, 0x22, 5};
343// │ │ └─ Interrupt pin
344// │ └────── Address offset
345// └──────────── I²C interface
346
347// Instantiate 8 MIDI rotary encoders.
348CCMCPEncoder ccencodersPAN[] {
349 {
350 encPAN[0], // The encoder to use
351 MCU::V_POT_1, // The MIDI address
352 6, // Encoder speed multiplier
353 3, // Number of pulses per physical "click" of the encoder
354 },
355 { encPAN[1], MCU::V_POT_2, // The MIDI address
356 6, // Encoder speed multiplier
357 3, // Number of pulses per physical "click" of the encoder},
358 },
359 { encPAN[2], MCU::V_POT_3, // The MIDI address
360 6, // Encoder speed multiplier
361 3, // Number of pulses per physical "click" of the encoder},
362 },
363 { encPAN[3], MCU::V_POT_4, // The MIDI address
364 6, // Encoder speed multiplier
365 3, // Number of pulses per physical "click" of the encoder},
366 },
367 { encPAN[4], MCU::V_POT_5, // The MIDI address
368 -6, // Encoder speed multiplier ***NEGATIVE VALUES INVERT THE DIRECTION OF ENCODER READING***
369 3, // Number of pulses per physical "click" of the encoder},
370 },
371 { encPAN[5], MCU::V_POT_6, // The MIDI address
372 -6, // Encoder speed multiplier ***NEGATIVE VALUES INVERT THE DIRECTION OF ENCODER READING***
373 3, // Number of pulses per physical "click" of the encoder},
374 },
375 { encPAN[6], MCU::V_POT_7, // The MIDI address
376 -6, // Encoder speed multiplier ***NEGATIVE VALUES INVERT THE DIRECTION OF ENCODER READING***
377 3, // Number of pulses per physical "click" of the encoder},
378 },
379 { encPAN[7], MCU::V_POT_8, // The MIDI address
380 -6, // Encoder speed multiplier ***NEGATIVE VALUES INVERT THE DIRECTION OF ENCODER READING***
381 3, // Number of pulses per physical "click" of the encoder},
382 }
383};
384
385// Instantiate 8 MIDI rotary encoders.
386PBMCPEncoder pbencodersVOL[] {
387 { encVOL[0], CHANNEL_1, // The MIDI address
388 512, // Encoder speed multiplier
389 4, // Number of pulses per physical "click" of the encoder},
390 },
391 { encVOL[1], CHANNEL_2, // The MIDI address
392 512, // Encoder speed multiplier
393 4, // Number of pulses per physical "click" of the encoder},
394 },
395 { encVOL[2], CHANNEL_3, // The MIDI address
396 512, // Encoder speed multiplier
397 4, // Number of pulses per physical "click" of the encoder},
398 },
399 { encVOL[3], CHANNEL_4, // The MIDI address
400 512, // Encoder speed multiplier
401 4, // Number of pulses per physical "click" of the encoder},
402 },
403 { encVOL[4], CHANNEL_5, // The MIDI address
404 -512, // Encoder speed multiplier ***NEGATIVE VALUES INVERT THE DIRECTION OF ENCODER READING***
405 4, // Number of pulses per physical "click" of the encoder},
406 },
407 { encVOL[5], CHANNEL_6, // The MIDI address
408 -512, // Encoder speed multiplier ***NEGATIVE VALUES INVERT THE DIRECTION OF ENCODER READING***
409 4, // Number of pulses per physical "click" of the encoder},
410 },
411 { encVOL[6], CHANNEL_7, // The MIDI address
412 -512, // Encoder speed multiplier ***NEGATIVE VALUES INVERT THE DIRECTION OF ENCODER READING***
413 4, // Number of pulses per physical "click" of the encoder},
414 },
415 { encVOL[7], CHANNEL_8, // The MIDI address
416 -512, // Encoder speed multiplier ***NEGATIVE VALUES INVERT THE DIRECTION OF ENCODER READING***
417 4, // Number of pulses per physical "click" of the encoder},
418 }
419};
420
421// ------------------------ Setup Buttons and Cursor------------------------- //
422// ========================================================================== //
423
424//Butons - 16 Analog IO Multiplexers HC4067 (x4)
425CD74HC4067 mux1 {
426 A0, // Analog input pin
427 {14, 15, 16, 17},// Address pins S0, S1, S2, S3
428 22 // Enable Pin
429};
430
431CD74HC4067 mux2 {
432 A0, // Analog input pin
433 {14, 15, 16, 17},// Address pins S0, S1, S2, S3
434 23 // Enable Pin
435};
436
437CD74HC4067 mux3 {
438 A0, // Analog input pin
439 {14, 15, 16, 17},// Address pins S0, S1, S2, S3
440 24 // Enable Pin
441};
442
443NoteButton buttons1[] {
444 {mux1.pin(0), 74 , 127}, //Arrangement/Session View
445 {mux1.pin(1), 75 , 127}, //Clip/Devive View
446 {mux1.pin(2), 77, 127}, //Show/Hide Browser
447 {mux1.pin(3), 78, 127}, //Show/Hide INFO View
448 {mux1.pin(4), 89, 127}, //Timeline Begining
449 {mux1.pin(5), MCU::ZOOM, 127}, //Play Selected Clip
450 {mux1.pin(6), MCU::SCRUB, 127}, //Play All Clips (Scene)
451 {mux1.pin(7), 76, 127}, //Undo
452 {mux1.pin(8), MCU::REC_RDY_1, 127},
453 {mux1.pin(9), MCU::REC_RDY_2, 127},
454 {mux1.pin(10), MCU::REC_RDY_3, 127},
455 {mux1.pin(11), MCU::REC_RDY_4, 127},
456 {mux1.pin(12), MCU::REC_RDY_5, 127},
457 {mux1.pin(13), MCU::REC_RDY_6, 127},
458 {mux1.pin(14), MCU::REC_RDY_7, 127},
459 {mux1.pin(15), MCU::REC_RDY_8, 127},
460};
461
462NoteButton buttons2[] {
463 {mux2.pin(0), 88, 127}, //If you change the last number "127" to "0"
464 {mux2.pin(1), MCU::CYCLE, 127}, //you send a Note Off Message
465 {mux2.pin(2), 87, 127},
466 {mux2.pin(3), MCU::FAST_FWD, 127},
467 {mux2.pin(4), MCU::REWIND, 127},
468 {mux2.pin(5), MCU::RECORD, 127},
469 {mux2.pin(6), MCU::STOP, 127},
470 {mux2.pin(7), MCU::PLAY, 127},
471 {mux2.pin(8), MCU::SELECT_8, 127},
472 {mux2.pin(9), MCU::SELECT_7, 127},
473 {mux2.pin(10), MCU::SELECT_6, 127},
474 {mux2.pin(11), MCU::DOWN, 127},
475 {mux2.pin(12), MCU::UP, 127},
476 {mux2.pin(13), MCU::RIGHT, 127},
477 {mux2.pin(14), MCU::LEFT, 127},
478 {mux2.pin(15), MCU::SCRUB, 127},
479};
480
481NoteButton buttons3[] {
482 {mux3.pin(0), MCU::SOLO_8}, //Midi Note 96 = Cursor Move Up
483 {mux3.pin(1), MCU::SOLO_7}, //Midi Note 97 = Cursor Move Down
484 {mux3.pin(2), MCU::SOLO_6}, //Midi Note 98 = Cursor Move Left
485 {mux3.pin(3), MCU::SOLO_5}, //Midi Note 99 = Cursor Move Right
486 {mux3.pin(4), MCU::SOLO_4}, //Midi Note 100 = Cursor Center Function
487 {mux3.pin(5), MCU::SOLO_3}, //Midi Note 74 = Session View/Arrangement View
488 {mux3.pin(6), MCU::SOLO_2}, //Midi Note 77 = Hide/Show Browser Side Bar
489 {mux3.pin(7), MCU::SOLO_1}, //Midi Note 78 = Show/Hide Info/Detail View Window
490 {mux3.pin(8), MCU::MUTE_1}, //Midi Note 75 = Clip View Selector Clip Preview/Device Preview
491 {mux3.pin(9), MCU::MUTE_2}, //Midi Note 76 = Undo
492 {mux3.pin(10), MCU::MUTE_3}, //MCU::SCRUB = Plays all the Clips of the Session and then the Next row of Clips
493 {mux3.pin(11), MCU::MUTE_4}, //Midi Note 83 = Draw Mode
494 {mux3.pin(12), MCU::MUTE_5}, //Midi Note 82 = Αdd Locator
495 {mux3.pin(13), MCU::MUTE_6}, //Midi Note 89 = Timeline Start
496 {mux3.pin(14), MCU::MUTE_7}, //Midi Note 90 = Timeline End
497 {mux3.pin(15), MCU::MUTE_8}, //PLAY SCENE 101
498};
499
500NoteButton buttons4[] {
501 // {mux1.pin(0), 75}, //Midi Note 96 = Cursor Move Up
502 // {mux1.pin(1), 76}, //Midi Note 97 = Cursor Move Down
503 // {mux1.pin(2), MCU::SCRUB}, //Midi Note 98 = Cursor Move Left
504 // {mux1.pin(3), MCU::FAST_FWD}, //Midi Note 99 = Cursor Move Right
505 // {mux1.pin(4), MCU::REWIND}, //Midi Note 100 = Cursor Center Function
506 // {mux1.pin(5), MCU::RECORD}, //Midi Note 74 = Session View/Arrangement View
507 // {mux1.pin(6), MCU::STOP}, //Midi Note 77 = Hide/Show Browser Side Bar
508 // {mux1.pin(7), MCU::PLAY}, //Midi Note 78 = Show/Hide Info/Detail View Window
509 {mux1.pin(8), MCU::SELECT_1}, //Midi Note 75 = Clip View Selector Clip Preview/Device Preview
510 {mux1.pin(9), MCU::SELECT_2}, //Midi Note 76 = Undo
511 {mux1.pin(10), MCU::SELECT_3}, //MCU::SCRUB = Plays all the Clips of the Session and then the Next row of Clips
512 {mux1.pin(11), MCU::SELECT_4}, //Midi Note 83 = Draw Mode
513 {mux1.pin(12), MCU::SELECT_5}, //Midi Note 82 = Αdd Locator
514 {mux1.pin(13), MCU::SELECT_6}, //Midi Note 89 = Timeline Start
515 {mux1.pin(14), MCU::SELECT_7}, //Midi Note 90 = Timeline End
516 {mux1.pin(15), MCU::SELECT_8}, //PLAY SCENE 101
517};
518
519// ------------------------------ LEDs Setup -------------------------------- //
520// ========================================================================== //
521// Define the array of leds.
522
523Array<CRGB, 8> leds {};
524//The data pin with the strip connected.
525constexpr uint8_t ledpin = 18;
526
527// Create a functor that maps the velocity and the index of a note to a color.
528struct RainbowColorMapper {
529 CHSV operator()(uint8_t velocity, uint8_t index) const {
530 return CHSV(255 * index / leds.length, 255, 255u * velocity / 127u);
531 }
532};
533
534NoteRangeFastLED<leds.length, RainbowColorMapper> midiled {
535 leds,
536 MIDI_Notes::C(1),
537};
538
539// ----------------------- Master Volume Fader Setup ------------------------ //
540// ========================================================================== //
541
542PBPotentiometer potentiometer {
543 A1, // Analog pin connected to potentiometer
544 CHANNEL_9, // MIDI Channel 1
545};
546
547void setup() {
548 Control_Surface.begin();
549
550 Wire.begin(); // Must be called before enc.begin()
551 Wire.setClock(800000);
552
553 encPAN.begin(); // Initialize the MCP23017
554 encVOL.begin(); // Initialize the MCP23017
555 RelativeCCSender::setMode(relativeCCmode::MACKIE_CONTROL_RELATIVE);
556
557 ssd1306Display_1_2.clearDisplay();
558 ssd1306Display_3_4.clearDisplay();
559 ssd1306Display_5_6.clearDisplay();
560 ssd1306Display_7_8.clearDisplay();
561
562 // See FastLED examples and documentation for more information.
563 FastLED.addLeds<NEOPIXEL, ledpin>(leds.data, leds.length);
564 FastLED.setCorrection(TypicalPixelString);
565 midiled.setBrightness(128);
566
567 delay(200);
568
569}
570
571void loop() {
572 Control_Surface.loop();
573
574 ssd1306Display_1_2.clearDisplay();
575 ssd1306Display_3_4.clearDisplay();
576 ssd1306Display_5_6.clearDisplay();
577 ssd1306Display_7_8.clearDisplay();
578
579 encPAN.update();
580 encVOL.update();
581
582 if (midiled.getDirty()) { // If the colors changed
583 FastLED.show(); // Update the LEDs with the new colors
584 }
585}

Downloadable files

Case TOP

Case design is UNDER CONSTRUCTION

Case_TOP.stl

BOTTOM of case

Case_BOTTOM.stl

JOYSTICK box

Joystick case.stl

Documentation

PCB and enclosure assembly and wiring

CRIUS TRX Control PCB FRITZING IMAGE.png

PCB Design Documentation

Here you can see the TOP of the PCB with the PIN names

file.None




Note: Content and images are from: https://projecthub.arduino.cc/, with some modifications.
If you want it removed due to copyright reasons, please leave a comment. Thank you.
I want to share this article more widely so that everyone knows about Arduino and your project.

Arduino Tutorial: Mini Piano

In this video I show you how to make a mini piano with Arduino. Devices and components Arduino Uno Rev3 Jumper wires (generic) Buzzer Breadb...