MicroDexed is a compatible 6-operator-FM-synth based on the Teensy(-3.6/-4.0) Microcontroller. https://www.parasitstudio.de
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1101 lines
33KB

  1. /*
  2. MicroDexed
  3. MicroDexed is a port of the Dexed sound engine
  4. (https://github.com/asb2m10/dexed) for the Teensy-3.5/3.6 with audio shield.
  5. Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android
  6. (c)2018,2019 H. Wirtz <wirtz@parasitstudio.de>
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 3 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software Foundation,
  17. Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. */
  19. #include "config.h"
  20. #include <Audio.h>
  21. #include <Wire.h>
  22. #include <SPI.h>
  23. #include <SD.h>
  24. #include <MIDI.h>
  25. #include <EEPROM.h>
  26. #include "EEPROMAnything.h"
  27. #include "midi_devices.hpp"
  28. #include <limits.h>
  29. #include "dexed.h"
  30. #include "dexed_sysex.h"
  31. #include "PluginFx.h"
  32. #ifdef I2C_DISPLAY // selecting sounds by encoder, button and display
  33. #include "UI.h"
  34. #define BOUNCE_WITH_PROMPT_DETECTION
  35. #include <Bounce.h>
  36. #define ENCODER_DO_NOT_USE_INTERRUPTS
  37. #include "Encoder4.h"
  38. #include "LiquidCrystalPlus_I2C.h"
  39. LiquidCrystalPlus_I2C lcd(LCD_I2C_ADDRESS, LCD_CHARS, LCD_LINES);
  40. Encoder4 enc[2] = {Encoder4(ENC_L_PIN_A, ENC_L_PIN_B), Encoder4(ENC_R_PIN_A, ENC_R_PIN_B)};
  41. int32_t enc_val[2] = {INITIAL_ENC_L_VALUE, INITIAL_ENC_R_VALUE};
  42. Bounce but[2] = {Bounce(BUT_L_PIN, BUT_DEBOUNCE_MS), Bounce(BUT_R_PIN, BUT_DEBOUNCE_MS)};
  43. elapsedMillis master_timer;
  44. uint8_t ui_state = UI_MAIN;
  45. uint8_t ui_main_state = UI_MAIN_VOICE;
  46. #else
  47. float mapfloat(float val, float in_min, float in_max, float out_min, float out_max);
  48. #endif
  49. AudioPlayQueue queue1;
  50. AudioAnalyzePeak peak1;
  51. AudioEffectDelay delay1;
  52. AudioMixer4 mixer1;
  53. AudioMixer4 mixer2;
  54. AudioAmplifier volume_r;
  55. AudioAmplifier volume_l;
  56. AudioOutputUSB usb1;
  57. AudioConnection patchCord0(queue1, peak1);
  58. AudioConnection patchCord1(queue1, 0, mixer1, 0);
  59. AudioConnection patchCord2(queue1, 0, mixer2, 0);
  60. AudioConnection patchCord3(delay1, 0, mixer1, 1);
  61. AudioConnection patchCord4(delay1, 0, mixer2, 2);
  62. AudioConnection patchCord5(mixer1, delay1);
  63. AudioConnection patchCord6(mixer1, 0, mixer2, 1);
  64. AudioConnection patchCord7(mixer2, volume_r);
  65. AudioConnection patchCord8(mixer2, volume_l);
  66. AudioConnection patchCord9(mixer2, 0, usb1, 0);
  67. AudioConnection patchCord10(mixer2, 0, usb1, 1);
  68. #if defined(TEENSY_AUDIO_BOARD)
  69. AudioOutputI2S i2s1;
  70. AudioConnection patchCord11(volume_r, 0, i2s1, 0);
  71. AudioConnection patchCord12(volume_l, 0, i2s1, 1);
  72. AudioControlSGTL5000 sgtl5000_1;
  73. #elif defined(TGA_AUDIO_BOARD)
  74. AudioOutputI2S i2s1;
  75. AudioConnection patchCord11(volume_r, 0, i2s1, 0);
  76. AudioConnection patchCord12(volume_l, 0, i2s1, 1);
  77. AudioControlWM8731master wm8731_1;
  78. #elif defined(TEENSY_DAC)
  79. AudioOutputAnalogStereo dacOut;
  80. AudioConnection patchCord11(volume_r, 0, dacOut, 0);
  81. AudioConnection patchCord12(volume_l, 0, dacOut, 1);
  82. #elif defined(TEENSY_DAC_SYMMETRIC)
  83. AudioOutputAnalogStereo dacOut;
  84. AudioMixer4 invMixer;
  85. AudioConnection patchCord11(volume_l, 0, dacOut , 0);
  86. AudioConnection patchCord12(volume_l, 0, invMixer, 0);
  87. AudioConnection patchCord13(invMixer, 0, dacOut , 1);
  88. #else
  89. AudioOutputPT8211 pt8211_1;
  90. AudioConnection patchCord11(volume_r, 0, pt8211_1, 0);
  91. AudioConnection patchCord12(volume_l, 0, pt8211_1, 1);
  92. #endif
  93. Dexed* dexed = new Dexed(SAMPLE_RATE);
  94. bool sd_card_available = false;
  95. uint32_t xrun = 0;
  96. uint32_t overload = 0;
  97. uint32_t peak = 0;
  98. uint16_t render_time_max = 0;
  99. uint8_t max_loaded_banks = 0;
  100. char bank_name[BANK_NAME_LEN];
  101. char voice_name[VOICE_NAME_LEN];
  102. char bank_names[MAX_BANKS][BANK_NAME_LEN];
  103. char voice_names[MAX_VOICES][VOICE_NAME_LEN];
  104. elapsedMillis autostore;
  105. uint8_t midi_timing_counter = 0; // 24 per qarter
  106. elapsedMillis midi_timing_timestep;
  107. uint16_t midi_timing_quarter = 0;
  108. elapsedMillis long_button_pressed;
  109. uint8_t effect_filter_cutoff = 0;
  110. uint8_t effect_filter_resonance = 0;
  111. uint8_t effect_delay_time = 0;
  112. uint8_t effect_delay_feedback = 0;
  113. uint8_t effect_delay_volume = 0;
  114. bool effect_delay_sync = 0;
  115. elapsedMicros fill_audio_buffer;
  116. elapsedMillis control_rate;
  117. uint8_t active_voices = 0;
  118. #ifdef SHOW_CPU_LOAD_MSEC
  119. elapsedMillis cpu_mem_millis;
  120. #endif
  121. config_t configuration = {0xffff, 0, 0, VOLUME, 0.5f, DEFAULT_MIDI_CHANNEL};
  122. bool eeprom_update_flag = false;
  123. value_change_t soften_volume = {0.0, 0};
  124. value_change_t soften_filter_res = {0.0, 0};
  125. value_change_t soften_filter_cut = {0.0, 0};
  126. void setup()
  127. {
  128. //while (!Serial) ; // wait for Arduino Serial Monitor
  129. Serial.begin(SERIAL_SPEED);
  130. #ifdef I2C_DISPLAY
  131. lcd.init();
  132. lcd.blink_off();
  133. lcd.cursor_off();
  134. lcd.backlight();
  135. lcd.noAutoscroll();
  136. lcd.clear();
  137. lcd.display();
  138. lcd.show(0, 0, 16, "MicroDexed");
  139. lcd.show(0, 11, 16, VERSION);
  140. lcd.show(1, 0, 16, "(c)parasiTstudio");
  141. pinMode(BUT_L_PIN, INPUT_PULLUP);
  142. pinMode(BUT_R_PIN, INPUT_PULLUP);
  143. #endif
  144. delay(220);
  145. Serial.println(F("MicroDexed based on https://github.com/asb2m10/dexed"));
  146. Serial.println(F("(c)2018,2019 H. Wirtz <wirtz@parasitstudio.de>"));
  147. Serial.println(F("https://codeberg.org/dcoredump/MicroDexed"));
  148. Serial.print(F("Version: "));
  149. Serial.println(VERSION);
  150. Serial.println(F("<setup start>"));
  151. initial_values_from_eeprom();
  152. setup_midi_devices();
  153. // start audio card
  154. AudioNoInterrupts();
  155. AudioMemory(AUDIO_MEM);
  156. #ifdef TEENSY_AUDIO_BOARD
  157. sgtl5000_1.enable();
  158. sgtl5000_1.dacVolumeRamp();
  159. //sgtl5000_1.dacVolumeRampLinear();
  160. //sgtl5000_1.dacVolumeRampDisable();
  161. sgtl5000_1.unmuteHeadphone();
  162. sgtl5000_1.unmuteLineout();
  163. sgtl5000_1.autoVolumeDisable(); // turn off AGC
  164. sgtl5000_1.volume(0.5, 0.5); // Headphone volume
  165. sgtl5000_1.lineOutLevel(SGTL5000_LINEOUT_LEVEL);
  166. sgtl5000_1.audioPostProcessorEnable();
  167. sgtl5000_1.autoVolumeControl(1, 1, 1, 0.9, 0.01, 0.05);
  168. sgtl5000_1.autoVolumeEnable();
  169. sgtl5000_1.surroundSoundEnable();
  170. sgtl5000_1.surroundSound(7, 2); // Configures virtual surround width from 0 (mono) to 7 (widest). select may be set to 1 (disable), 2 (mono input) or 3 (stereo input).
  171. sgtl5000_1.enhanceBassEnable();
  172. sgtl5000_1.enhanceBass(1.0, 0.2, 1, 2); // Configures the bass enhancement by setting the levels of the original stereo signal and the bass-enhanced mono level which will be mixed together. The high-pass filter may be enabled (0) or bypassed (1).
  173. /* The cutoff frequency is specified as follows:
  174. value frequency
  175. 0 80Hz
  176. 1 100Hz
  177. 2 125Hz
  178. 3 150Hz
  179. 4 175Hz
  180. 5 200Hz
  181. 6 225Hz
  182. */
  183. //sgtl5000_1.eqBands(bass, mid_bass, midrange, mid_treble, treble);
  184. Serial.println(F("Teensy-Audio-Board enabled."));
  185. #elif defined(TGA_AUDIO_BOARD)
  186. wm8731_1.enable();
  187. wm8731_1.volume(1.0);
  188. Serial.println(F("TGA board enabled."));
  189. #elif defined(TEENSY_DAC)
  190. Serial.println(F("Internal DAC enabled."));
  191. #elif defined(TEENSY_DAC_SYMMETRIC)
  192. invMixer.gain(0,-1.f);
  193. Serial.println(F("Internal DAC using symmetric outputs enabled."));
  194. #else
  195. Serial.println(F("PT8211 enabled."));
  196. #endif
  197. // start SD card
  198. SPI.setMOSI(SDCARD_MOSI_PIN);
  199. SPI.setSCK(SDCARD_SCK_PIN);
  200. if (!SD.begin(SDCARD_CS_PIN))
  201. {
  202. Serial.println(F("SD card not accessable."));
  203. strcpy(bank_name, "Default");
  204. strcpy(voice_name, "Default");
  205. }
  206. else
  207. {
  208. Serial.println(F("SD card found."));
  209. sd_card_available = true;
  210. // read all bank names
  211. max_loaded_banks = get_bank_names();
  212. strip_extension(bank_names[configuration.bank], bank_name);
  213. // read all voice name for actual bank
  214. get_voice_names_from_bank(configuration.bank);
  215. #ifdef DEBUG
  216. Serial.print(F("Bank ["));
  217. Serial.print(bank_names[configuration.bank]);
  218. Serial.print(F("/"));
  219. Serial.print(bank_name);
  220. Serial.println(F("]"));
  221. for (uint8_t n = 0; n < MAX_VOICES; n++)
  222. {
  223. if (n < 10)
  224. Serial.print(F(" "));
  225. Serial.print(F(" "));
  226. Serial.print(n, DEC);
  227. Serial.print(F("["));
  228. Serial.print(voice_names[n]);
  229. Serial.println(F("]"));
  230. }
  231. #endif
  232. // load default SYSEX data
  233. load_sysex(configuration.bank, configuration.voice);
  234. }
  235. // Init effects
  236. delay1.delay(0, mapfloat(effect_delay_feedback, 0, ENC_DELAY_TIME_STEPS, 0.0, DELAY_MAX_TIME));
  237. // mixer1 is the feedback-adding mixer, mixer2 the whole delay (with/without feedback) mixer
  238. mixer1.gain(0, 1.0); // original signal
  239. mixer1.gain(1, mapfloat(effect_delay_feedback, 0, ENC_DELAY_FB_STEPS, 0.0, 1.0)); // amount of feedback
  240. mixer2.gain(0, 1.0 - mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // original signal
  241. mixer2.gain(1, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // delayed signal (including feedback)
  242. mixer2.gain(2, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // only delayed signal (without feedback)
  243. dexed->fx.Gain = 1.0;
  244. dexed->fx.Reso = 1.0 - float(effect_filter_resonance) / ENC_FILTER_RES_STEPS;
  245. dexed->fx.Cutoff = 1.0 - float(effect_filter_cutoff) / ENC_FILTER_CUT_STEPS;
  246. // set initial volume and pan (read from EEPROM)
  247. set_volume(configuration.vol, configuration.pan);
  248. #ifdef I2C_DISPLAY
  249. enc[0].write(map(configuration.vol * 100, 0, 100, 0, ENC_VOL_STEPS));
  250. enc_val[0] = enc[0].read();
  251. enc[1].write(configuration.voice);
  252. enc_val[1] = enc[1].read();
  253. but[0].update();
  254. but[1].update();
  255. #endif
  256. #if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC)
  257. // Initialize processor and memory measurements
  258. AudioProcessorUsageMaxReset();
  259. AudioMemoryUsageMaxReset();
  260. #endif
  261. #ifdef DEBUG
  262. Serial.print(F("Bank/Voice from EEPROM ["));
  263. Serial.print(configuration.bank, DEC);
  264. Serial.print(F("/"));
  265. Serial.print(configuration.voice, DEC);
  266. Serial.println(F("]"));
  267. show_patch();
  268. #endif
  269. Serial.print(F("AUDIO_BLOCK_SAMPLES="));
  270. Serial.print(AUDIO_BLOCK_SAMPLES);
  271. Serial.print(F(" (Time per block="));
  272. Serial.print(1000000 / (SAMPLE_RATE / AUDIO_BLOCK_SAMPLES));
  273. Serial.println(F("ms)"));
  274. #if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC)
  275. show_cpu_and_mem_usage();
  276. #endif
  277. #ifdef I2C_DISPLAY
  278. lcd.clear();
  279. ui_show_main();
  280. #endif
  281. AudioInterrupts();
  282. Serial.println(F("<setup end>"));
  283. }
  284. void loop()
  285. {
  286. int16_t* audio_buffer; // pointer to AUDIO_BLOCK_SAMPLES * int16_t
  287. const uint16_t audio_block_time_us = 1000000 / (SAMPLE_RATE / AUDIO_BLOCK_SAMPLES);
  288. // Main sound calculation
  289. if (queue1.available() && fill_audio_buffer > audio_block_time_us - 10)
  290. {
  291. fill_audio_buffer = 0;
  292. audio_buffer = queue1.getBuffer();
  293. elapsedMicros t1;
  294. dexed->getSamples(AUDIO_BLOCK_SAMPLES, audio_buffer);
  295. if (t1 > audio_block_time_us) // everything greater 2.9ms is a buffer underrun!
  296. xrun++;
  297. if (t1 > render_time_max)
  298. render_time_max = t1;
  299. if (peak1.available())
  300. {
  301. if (peak1.read() > 0.99)
  302. peak++;
  303. }
  304. #ifndef TEENSY_AUDIO_BOARD
  305. for (uint8_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
  306. audio_buffer[i] *= configuration.vol;
  307. #endif
  308. queue1.playBuffer();
  309. }
  310. // EEPROM update handling
  311. if (autostore >= AUTOSTORE_MS && active_voices == 0 && eeprom_update_flag == true)
  312. {
  313. // only store configuration data to EEPROM when AUTOSTORE_MS is reached and no voices are activated anymore
  314. eeprom_update();
  315. }
  316. // MIDI input handling
  317. check_midi_devices();
  318. // CONTROL-RATE-EVENT-HANDLING
  319. if (control_rate > CONTROL_RATE_MS)
  320. {
  321. control_rate = 0;
  322. // Shutdown unused voices
  323. active_voices = dexed->getNumNotesPlaying();
  324. // check for value changes
  325. if (soften_volume.steps > 0)
  326. {
  327. // soften volume value
  328. soften_volume.steps--;
  329. set_volume(configuration.vol + soften_volume.diff, configuration.pan);
  330. #ifdef DEBUG
  331. Serial.print(F("Volume: "));
  332. Serial.print(configuration.vol, 5);
  333. Serial.print(F(" Volume step: "));
  334. Serial.print(soften_volume.steps);
  335. Serial.print(F(" Volume diff: "));
  336. Serial.println(soften_volume.diff, 5);
  337. #endif
  338. }
  339. if (soften_filter_res.steps > 0)
  340. {
  341. // soften filter resonance value
  342. soften_filter_res.steps--;
  343. dexed->fx.Reso = dexed->fx.Reso + soften_filter_res.diff;
  344. #ifdef DEBUG
  345. Serial.print(F("Filter-Resonance: "));
  346. Serial.print(dexed->fx.Reso, 5);
  347. Serial.print(F(" Filter-Resonance step: "));
  348. Serial.print(soften_filter_res.steps);
  349. Serial.print(F(" Filter-Resonance diff: "));
  350. Serial.println(soften_filter_res.diff, 5);
  351. #endif
  352. }
  353. if (soften_filter_cut.steps > 0)
  354. {
  355. // soften filter cutoff value
  356. soften_filter_cut.steps--;
  357. dexed->fx.Cutoff = dexed->fx.Cutoff + soften_filter_cut.diff;
  358. #ifdef DEBUG
  359. Serial.print(F("Filter-Cutoff: "));
  360. Serial.print(dexed->fx.Cutoff, 5);
  361. Serial.print(F(" Filter-Cutoff step: "));
  362. Serial.print(soften_filter_cut.steps);
  363. Serial.print(F(" Filter-Cutoff diff: "));
  364. Serial.println(soften_filter_cut.diff, 5);
  365. #endif
  366. }
  367. }
  368. #ifdef I2C_DISPLAY
  369. // UI-HANDLING
  370. if (master_timer >= TIMER_UI_HANDLING_MS)
  371. {
  372. master_timer -= TIMER_UI_HANDLING_MS;
  373. #ifdef I2C_DISPLAY
  374. handle_ui();
  375. #endif
  376. }
  377. #endif
  378. #if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC)
  379. if (cpu_mem_millis >= SHOW_CPU_LOAD_MSEC)
  380. {
  381. cpu_mem_millis -= SHOW_CPU_LOAD_MSEC;
  382. show_cpu_and_mem_usage();
  383. }
  384. #endif
  385. }
  386. /******************************************************************************
  387. MIDI MESSAGE HANDLER
  388. ******************************************************************************/
  389. void handleNoteOn(byte inChannel, byte inNumber, byte inVelocity)
  390. {
  391. if (checkMidiChannel(inChannel))
  392. {
  393. dexed->keydown(inNumber, inVelocity);
  394. }
  395. }
  396. void handleNoteOff(byte inChannel, byte inNumber, byte inVelocity)
  397. {
  398. if (checkMidiChannel(inChannel))
  399. {
  400. dexed->keyup(inNumber);
  401. }
  402. }
  403. void handleControlChange(byte inChannel, byte inCtrl, byte inValue)
  404. {
  405. if (checkMidiChannel(inChannel))
  406. {
  407. #ifdef DEBUG
  408. Serial.print(F("CC#"));
  409. Serial.print(inCtrl, DEC);
  410. Serial.print(F(":"));
  411. Serial.println(inValue, DEC);
  412. #endif
  413. switch (inCtrl) {
  414. case 0:
  415. if (inValue < MAX_BANKS)
  416. {
  417. configuration.bank = inValue;
  418. #ifdef I2C_DISPLAY
  419. handle_ui();
  420. #endif
  421. }
  422. break;
  423. case 1:
  424. dexed->controllers.modwheel_cc = inValue;
  425. dexed->controllers.refresh();
  426. break;
  427. case 2:
  428. dexed->controllers.breath_cc = inValue;
  429. dexed->controllers.refresh();
  430. break;
  431. case 4:
  432. dexed->controllers.foot_cc = inValue;
  433. dexed->controllers.refresh();
  434. break;
  435. case 7: // Volume
  436. configuration.vol = float(inValue) / 0x7f;
  437. set_volume(configuration.vol, configuration.pan);
  438. break;
  439. case 10: // Pan
  440. configuration.pan = float(inValue) / 128;
  441. set_volume(configuration.vol, configuration.pan);
  442. break;
  443. case 32: // BankSelect LSB
  444. configuration.bank = inValue;
  445. break;
  446. case 64:
  447. dexed->setSustain(inValue > 63);
  448. if (!dexed->getSustain()) {
  449. for (uint8_t note = 0; note < dexed->getMaxNotes(); note++) {
  450. if (dexed->voices[note].sustained && !dexed->voices[note].keydown) {
  451. dexed->voices[note].dx7_note->keyup();
  452. dexed->voices[note].sustained = false;
  453. }
  454. }
  455. }
  456. break;
  457. case 103: // CC 103: filter resonance
  458. effect_filter_resonance = map(inValue, 0, 127, 0, ENC_FILTER_RES_STEPS);
  459. dexed->fx.Reso = 1.0 - float(effect_filter_resonance) / ENC_FILTER_RES_STEPS;
  460. #ifdef I2C_DISPLAY
  461. handle_ui();
  462. #endif
  463. break;
  464. case 104: // CC 104: filter cutoff
  465. effect_filter_cutoff = map(inValue, 0, 127, 0, ENC_FILTER_CUT_STEPS);
  466. dexed->fx.Cutoff = 1.0 - float(effect_filter_cutoff) / ENC_FILTER_CUT_STEPS;
  467. #ifdef I2C_DISPLAY
  468. handle_ui();
  469. #endif
  470. break;
  471. case 105: // CC 105: delay time
  472. effect_delay_time = map(inValue, 0, 127, 0, ENC_DELAY_TIME_STEPS);
  473. delay1.delay(0, mapfloat(effect_delay_time, 0, ENC_DELAY_TIME_STEPS, 0.0, DELAY_MAX_TIME));
  474. #ifdef I2C_DISPLAY
  475. handle_ui();
  476. #endif
  477. break;
  478. case 106: // CC 106: delay feedback
  479. effect_delay_feedback = map(inValue, 0, 127, 0, ENC_DELAY_FB_STEPS);
  480. mixer1.gain(1, mapfloat(float(effect_delay_feedback), 0, ENC_DELAY_FB_STEPS, 0.0, 1.0));
  481. #ifdef I2C_DISPLAY
  482. handle_ui();
  483. #endif
  484. break;
  485. case 107: // CC 107: delay volume
  486. effect_delay_volume = map(inValue, 0, 127, 0, ENC_DELAY_VOLUME_STEPS);
  487. mixer2.gain(1, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // delay tap1 signal (with added feedback)
  488. #ifdef I2C_DISPLAY
  489. handle_ui();
  490. #endif
  491. break;
  492. case 120:
  493. dexed->panic();
  494. break;
  495. case 121:
  496. dexed->resetControllers();
  497. break;
  498. case 123:
  499. dexed->notesOff();
  500. break;
  501. case 126:
  502. dexed->setMonoMode(true);
  503. break;
  504. case 127:
  505. dexed->setMonoMode(false);
  506. break;
  507. }
  508. }
  509. }
  510. void handleAfterTouch(byte inChannel, byte inPressure)
  511. {
  512. dexed->controllers.aftertouch_cc = inPressure;
  513. dexed->controllers.refresh();
  514. }
  515. void handlePitchBend(byte inChannel, int inPitch)
  516. {
  517. dexed->controllers.values_[kControllerPitch] = inPitch + 0x2000; // -8192 to +8191 --> 0 to 16383
  518. }
  519. void handleProgramChange(byte inChannel, byte inProgram)
  520. {
  521. if (inProgram < MAX_VOICES)
  522. {
  523. load_sysex(configuration.bank, inProgram);
  524. #ifdef I2C_DISPLAY
  525. handle_ui();
  526. #endif
  527. }
  528. }
  529. void handleSystemExclusive(byte * sysex, uint len)
  530. {
  531. /*
  532. SYSEX MESSAGE: Parameter Change
  533. -------------------------------
  534. bits hex description
  535. 11110000 F0 Status byte - start sysex
  536. 0iiiiiii 43 ID # (i=67; Yamaha)
  537. 0sssnnnn 10 Sub-status (s=1) & channel number (n=0; ch 1)
  538. 0gggggpp ** parameter group # (g=0; voice, g=2; function)
  539. 0ppppppp ** parameter # (these are listed in next section)
  540. Note that voice parameter #'s can go over 128 so
  541. the pp bits in the group byte are either 00 for
  542. par# 0-127 or 01 for par# 128-155. In the latter case
  543. you add 128 to the 0ppppppp byte to compute par#.
  544. 0ddddddd ** data byte
  545. 11110111 F7 Status - end sysex
  546. */
  547. #ifdef DEBUG
  548. Serial.print(F("SYSEX-Data["));
  549. Serial.print(len, DEC);
  550. Serial.print(F("]"));
  551. for (uint8_t i = 0; i < len; i++)
  552. {
  553. Serial.print(F(" "));
  554. Serial.print(sysex[i], DEC);
  555. }
  556. Serial.println();
  557. #endif
  558. if (!checkMidiChannel((sysex[2] & 0x0f) + 1 ))
  559. {
  560. #ifdef DEBUG
  561. Serial.println(F("SYSEX-MIDI-Channel mismatch"));
  562. #endif
  563. return;
  564. }
  565. if (sysex[1] != 0x43) // check for Yamaha sysex
  566. {
  567. #ifdef DEBUG
  568. Serial.println(F("E: SysEx vendor not Yamaha."));
  569. #endif
  570. return;
  571. }
  572. #ifdef DEBUG
  573. Serial.print(F("Substatus: ["));
  574. Serial.print((sysex[2] & 0x70) >> 4);
  575. Serial.println(F("]"));
  576. #endif
  577. // parse parameter change
  578. if (len == 7)
  579. {
  580. if (((sysex[3] & 0x7c) >> 2) != 0 && ((sysex[3] & 0x7c) >> 2) != 2)
  581. {
  582. #ifdef DEBUG
  583. Serial.println(F("E: Not a SysEx parameter or function parameter change."));
  584. #endif
  585. return;
  586. }
  587. if (sysex[6] != 0xf7)
  588. {
  589. #ifdef DEBUG
  590. Serial.println(F("E: SysEx end status byte not detected."));
  591. #endif
  592. return;
  593. }
  594. sysex[4] &= 0x7f;
  595. sysex[5] &= 0x7f;
  596. uint8_t data_index;
  597. if (((sysex[3] & 0x7c) >> 2) == 0)
  598. {
  599. dexed->notesOff();
  600. dexed->data[sysex[4] + ((sysex[3] & 0x03) * 128)] = sysex[5]; // set parameter
  601. dexed->doRefreshVoice();
  602. data_index = sysex[4] + ((sysex[3] & 0x03) * 128);
  603. }
  604. else
  605. {
  606. dexed->data[DEXED_GLOBAL_PARAMETER_OFFSET - 63 + sysex[4]] = sysex[5]; // set function parameter
  607. dexed->controllers.values_[kControllerPitchRange] = dexed->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_PITCHBEND_RANGE];
  608. dexed->controllers.values_[kControllerPitchStep] = dexed->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_PITCHBEND_STEP];
  609. dexed->controllers.wheel.setRange(dexed->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_MODWHEEL_RANGE]);
  610. dexed->controllers.wheel.setTarget(dexed->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_MODWHEEL_ASSIGN]);
  611. dexed->controllers.foot.setRange(dexed->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_FOOTCTRL_RANGE]);
  612. dexed->controllers.foot.setTarget(dexed->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_FOOTCTRL_ASSIGN]);
  613. dexed->controllers.breath.setRange(dexed->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_BREATHCTRL_RANGE]);
  614. dexed->controllers.breath.setTarget(dexed->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_BREATHCTRL_ASSIGN]);
  615. dexed->controllers.at.setRange(dexed->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_AT_RANGE]);
  616. dexed->controllers.at.setTarget(dexed->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_AT_ASSIGN]);
  617. dexed->controllers.masterTune = (dexed->data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_MASTER_TUNE] * 0x4000 << 11) * (1.0 / 12);
  618. dexed->controllers.refresh();
  619. data_index = DEXED_GLOBAL_PARAMETER_OFFSET - 63 + sysex[4];
  620. }
  621. #ifdef DEBUG
  622. Serial.print(F("SysEx"));
  623. if (((sysex[3] & 0x7c) >> 2) == 0)
  624. Serial.print(F(" function"));
  625. Serial.print(F(" parameter "));
  626. Serial.print(sysex[4], DEC);
  627. Serial.print(F(" = "));
  628. Serial.print(sysex[5], DEC);
  629. Serial.print(F(", data_index = "));
  630. Serial.println(data_index, DEC);
  631. #endif
  632. }
  633. else if (len == 163)
  634. {
  635. int32_t bulk_checksum_calc = 0;
  636. int8_t bulk_checksum = sysex[161];
  637. // 1 Voice bulk upload
  638. #ifdef DEBUG
  639. Serial.println(F("1 Voice bulk upload"));
  640. #endif
  641. if (sysex[162] != 0xf7)
  642. {
  643. #ifdef DEBUG
  644. Serial.println(F("E: Found no SysEx end marker."));
  645. #endif
  646. return;
  647. }
  648. if ((sysex[3] & 0x7f) != 0)
  649. {
  650. #ifdef DEBUG
  651. Serial.println(F("E: Not a SysEx voice bulk upload."));
  652. #endif
  653. return;
  654. }
  655. if (((sysex[4] << 7) | sysex[5]) != 0x9b)
  656. {
  657. #ifdef DEBUG
  658. Serial.println(F("E: Wrong length for SysEx voice bulk upload (not 155)."));
  659. #endif
  660. return;
  661. }
  662. // checksum calculation
  663. for (uint8_t i = 0; i < 155 ; i++)
  664. {
  665. bulk_checksum_calc -= sysex[i + 6];
  666. }
  667. bulk_checksum_calc &= 0x7f;
  668. if (bulk_checksum_calc != bulk_checksum)
  669. {
  670. #ifdef DEBUG
  671. Serial.print(F("E: Checksum error for one voice [0x"));
  672. Serial.print(bulk_checksum, HEX);
  673. Serial.print(F("/0x"));
  674. Serial.print(bulk_checksum_calc, HEX);
  675. Serial.println(F("]"));
  676. #endif
  677. return;
  678. }
  679. // load sysex-data into voice memory
  680. uint8_t tmp_data[155];
  681. memset(tmp_data, 0, 155 * sizeof(uint8_t));
  682. for (uint8_t i = 0; i < 155 ; i++)
  683. {
  684. tmp_data[i] = sysex[i + 6];
  685. }
  686. strncpy(voice_name, (char *)&tmp_data[145], sizeof(voice_name) - 1);
  687. Serial.print(F("Voice ["));
  688. Serial.print(voice_name);
  689. Serial.print(F("] loaded."));
  690. dexed->loadSysexVoice(tmp_data);
  691. }
  692. #ifdef DEBUG
  693. else
  694. Serial.println(F("E: SysEx parameter length wrong."));
  695. #endif
  696. }
  697. void handleTimeCodeQuarterFrame(byte data)
  698. {
  699. ;
  700. }
  701. void handleAfterTouchPoly(byte inChannel, byte inNumber, byte inVelocity)
  702. {
  703. ;
  704. }
  705. void handleSongSelect(byte inSong)
  706. {
  707. ;
  708. }
  709. void handleTuneRequest(void)
  710. {
  711. ;
  712. }
  713. void handleClock(void)
  714. {
  715. midi_timing_counter++;
  716. if (midi_timing_counter % 24 == 0)
  717. {
  718. midi_timing_quarter = midi_timing_timestep;
  719. midi_timing_counter = 0;
  720. midi_timing_timestep = 0;
  721. // Adjust delay control here
  722. #ifdef DEBUG
  723. Serial.print(F("MIDI Clock: "));
  724. Serial.print(60000 / midi_timing_quarter, DEC);
  725. Serial.print(F("bpm ("));
  726. Serial.print(midi_timing_quarter, DEC);
  727. Serial.println(F("ms per quarter)"));
  728. #endif
  729. }
  730. }
  731. void handleStart(void)
  732. {
  733. ;
  734. }
  735. void handleContinue(void)
  736. {
  737. ;
  738. }
  739. void handleStop(void)
  740. {
  741. ;
  742. }
  743. void handleActiveSensing(void)
  744. {
  745. ;
  746. }
  747. void handleSystemReset(void)
  748. {
  749. #ifdef DEBUG
  750. Serial.println(F("MIDI SYSEX RESET"));
  751. #endif
  752. dexed->notesOff();
  753. dexed->panic();
  754. dexed->resetControllers();
  755. }
  756. /******************************************************************************
  757. MIDI HELPER
  758. ******************************************************************************/
  759. bool checkMidiChannel(byte inChannel)
  760. {
  761. // check for MIDI channel
  762. if (configuration.midi_channel == MIDI_CHANNEL_OMNI)
  763. {
  764. return (true);
  765. }
  766. else if (inChannel != configuration.midi_channel)
  767. {
  768. #ifdef DEBUG
  769. Serial.print(F("Ignoring MIDI data on channel "));
  770. Serial.print(inChannel);
  771. Serial.print(F("(listening on "));
  772. Serial.print(configuration.midi_channel);
  773. Serial.println(F(")"));
  774. #endif
  775. return (false);
  776. }
  777. return (true);
  778. }
  779. /******************************************************************************
  780. VOLUME HELPER
  781. ******************************************************************************/
  782. void set_volume(float v, float p)
  783. {
  784. configuration.vol = v;
  785. configuration.pan = p;
  786. #ifdef DEBUG
  787. Serial.print(F("Setting volume: VOL="));
  788. Serial.print(v, DEC);
  789. Serial.print(F("["));
  790. Serial.print(configuration.vol, DEC);
  791. Serial.print(F("] PAN="));
  792. Serial.print(F("["));
  793. Serial.print(configuration.pan, DEC);
  794. Serial.print(F("] "));
  795. Serial.print(pow(configuration.vol * sinf(configuration.pan * PI / 2), VOLUME_CURVE), 3);
  796. Serial.print(F("/"));
  797. Serial.println(pow(configuration.vol * cosf( configuration.pan * PI / 2), VOLUME_CURVE), 3);
  798. #endif
  799. dexed->fx.Gain = v;
  800. // http://files.csound-tutorial.net/floss_manual/Release03/Cs_FM_03_ScrapBook/b-panning-and-spatialization.html
  801. volume_r.gain(sinf(p * PI / 2));
  802. volume_l.gain(cosf(p * PI / 2));
  803. }
  804. // https://www.dr-lex.be/info-stuff/volumecontrols.html#table1
  805. inline float logvol(float x)
  806. {
  807. return (0.001 * expf(6.908 * x));
  808. }
  809. /******************************************************************************
  810. EEPROM HELPER
  811. ******************************************************************************/
  812. void initial_values_from_eeprom(void)
  813. {
  814. uint32_t checksum;
  815. config_t tmp_conf;
  816. EEPROM_readAnything(EEPROM_START_ADDRESS, tmp_conf);
  817. checksum = crc32((byte*)&tmp_conf + 4, sizeof(tmp_conf) - 4);
  818. #ifdef DEBUG
  819. Serial.print(F("EEPROM checksum: 0x"));
  820. Serial.print(tmp_conf.checksum, HEX);
  821. Serial.print(F(" / 0x"));
  822. Serial.print(checksum, HEX);
  823. #endif
  824. if (checksum != tmp_conf.checksum)
  825. {
  826. #ifdef DEBUG
  827. Serial.print(F(" - mismatch -> initializing EEPROM!"));
  828. #endif
  829. eeprom_update();
  830. }
  831. else
  832. {
  833. EEPROM_readAnything(EEPROM_START_ADDRESS, configuration);
  834. Serial.print(F(" - OK, loading!"));
  835. }
  836. #ifdef DEBUG
  837. Serial.println();
  838. #endif
  839. }
  840. void eeprom_write(void)
  841. {
  842. autostore = 0;
  843. eeprom_update_flag = true;
  844. }
  845. void eeprom_update(void)
  846. {
  847. eeprom_update_flag = false;
  848. configuration.checksum = crc32((byte*)&configuration + 4, sizeof(configuration) - 4);
  849. EEPROM_writeAnything(EEPROM_START_ADDRESS, configuration);
  850. Serial.println(F("Updating EEPROM with configuration data"));
  851. }
  852. uint32_t crc32(byte * calc_start, uint16_t calc_bytes) // base code from https://www.arduino.cc/en/Tutorial/EEPROMCrc
  853. {
  854. const uint32_t crc_table[16] =
  855. {
  856. 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
  857. 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
  858. 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
  859. 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
  860. };
  861. uint32_t crc = ~0L;
  862. for (byte* index = calc_start ; index < (calc_start + calc_bytes) ; ++index)
  863. {
  864. crc = crc_table[(crc ^ *index) & 0x0f] ^ (crc >> 4);
  865. crc = crc_table[(crc ^ (*index >> 4)) & 0x0f] ^ (crc >> 4);
  866. crc = ~crc;
  867. }
  868. return (crc);
  869. }
  870. /******************************************************************************
  871. DEBUG HELPER
  872. ******************************************************************************/
  873. #if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC)
  874. void show_cpu_and_mem_usage(void)
  875. {
  876. Serial.print(F("CPU: "));
  877. Serial.print(AudioProcessorUsage(), 2);
  878. Serial.print(F("% CPU MAX: "));
  879. Serial.print(AudioProcessorUsageMax(), 2);
  880. Serial.print(F("% MEM: "));
  881. Serial.print(AudioMemoryUsage(), DEC);
  882. Serial.print(F(" MEM MAX: "));
  883. Serial.print(AudioMemoryUsageMax(), DEC);
  884. Serial.print(F(" RENDER_TIME_MAX: "));
  885. Serial.print(render_time_max, DEC);
  886. Serial.print(F(" XRUN: "));
  887. Serial.print(xrun, DEC);
  888. Serial.print(F(" OVERLOAD: "));
  889. Serial.print(overload, DEC);
  890. Serial.print(F(" PEAK: "));
  891. Serial.print(peak, DEC);
  892. Serial.print(F(" BLOCKSIZE: "));
  893. Serial.print(AUDIO_BLOCK_SAMPLES, DEC);
  894. Serial.print(F(" ACTIVE_VOICES: "));
  895. Serial.print(active_voices, DEC);
  896. Serial.println();
  897. AudioProcessorUsageMaxReset();
  898. AudioMemoryUsageMaxReset();
  899. render_time_max = 0;
  900. }
  901. #endif
  902. #ifdef DEBUG
  903. void show_patch(void)
  904. {
  905. uint8_t i;
  906. char voicename[VOICE_NAME_LEN];
  907. memset(voicename, 0, sizeof(voicename));
  908. for (i = 0; i < 6; i++)
  909. {
  910. Serial.print(F("OP"));
  911. Serial.print(6 - i, DEC);
  912. Serial.println(F(": "));
  913. Serial.println(F("R1 | R2 | R3 | R4 | L1 | L2 | L3 | L4 LEV_SCL_BRK_PT | SCL_LEFT_DEPTH | SCL_RGHT_DEPTH"));
  914. Serial.print(dexed->data[(i * 21) + DEXED_OP_EG_R1], DEC);
  915. Serial.print(F(" "));
  916. Serial.print(dexed->data[(i * 21) + DEXED_OP_EG_R2], DEC);
  917. Serial.print(F(" "));
  918. Serial.print(dexed->data[(i * 21) + DEXED_OP_EG_R3], DEC);
  919. Serial.print(F(" "));
  920. Serial.print(dexed->data[(i * 21) + DEXED_OP_EG_R4], DEC);
  921. Serial.print(F(" "));
  922. Serial.print(dexed->data[(i * 21) + DEXED_OP_EG_L1], DEC);
  923. Serial.print(F(" "));
  924. Serial.print(dexed->data[(i * 21) + DEXED_OP_EG_L2], DEC);
  925. Serial.print(F(" "));
  926. Serial.print(dexed->data[(i * 21) + DEXED_OP_EG_L3], DEC);
  927. Serial.print(F(" "));
  928. Serial.print(dexed->data[(i * 21) + DEXED_OP_EG_L4], DEC);
  929. Serial.print(F(" "));
  930. Serial.print(dexed->data[(i * 21) + DEXED_OP_LEV_SCL_BRK_PT], DEC);
  931. Serial.print(F(" "));
  932. Serial.print(dexed->data[(i * 21) + DEXED_OP_SCL_LEFT_DEPTH], DEC);
  933. Serial.print(F(" "));
  934. Serial.println(dexed->data[(i * 21) + DEXED_OP_SCL_RGHT_DEPTH], DEC);
  935. Serial.println(F("SCL_L_CURVE | SCL_R_CURVE | RT_SCALE | AMS | KVS | OUT_LEV | OP_MOD | FRQ_C | FRQ_F | DETUNE"));
  936. Serial.print(F(" "));
  937. Serial.print(dexed->data[(i * 21) + DEXED_OP_SCL_LEFT_CURVE], DEC);
  938. Serial.print(F(" "));
  939. Serial.print(dexed->data[(i * 21) + DEXED_OP_SCL_RGHT_CURVE], DEC);
  940. Serial.print(F(" "));
  941. Serial.print(dexed->data[(i * 21) + DEXED_OP_OSC_RATE_SCALE], DEC);
  942. Serial.print(F(" "));
  943. Serial.print(dexed->data[(i * 21) + DEXED_OP_AMP_MOD_SENS], DEC);
  944. Serial.print(F(" "));
  945. Serial.print(dexed->data[(i * 21) + DEXED_OP_KEY_VEL_SENS], DEC);
  946. Serial.print(F(" "));
  947. Serial.print(dexed->data[(i * 21) + DEXED_OP_OUTPUT_LEV], DEC);
  948. Serial.print(F(" "));
  949. Serial.print(dexed->data[(i * 21) + DEXED_OP_OSC_MODE], DEC);
  950. Serial.print(F(" "));
  951. Serial.print(dexed->data[(i * 21) + DEXED_OP_FREQ_COARSE], DEC);
  952. Serial.print(F(" "));
  953. Serial.print(dexed->data[(i * 21) + DEXED_OP_FREQ_FINE], DEC);
  954. Serial.print(F(" "));
  955. Serial.println(dexed->data[(i * 21) + DEXED_OP_OSC_DETUNE], DEC);
  956. }
  957. Serial.println(F("PR1 | PR2 | PR3 | PR4 | PL1 | PL2 | PL3 | PL4"));
  958. Serial.print(F(" "));
  959. for (i = 0; i < 8; i++)
  960. {
  961. Serial.print(dexed->data[DEXED_VOICE_OFFSET + i], DEC);
  962. Serial.print(F(" "));
  963. }
  964. Serial.println();
  965. Serial.print(F("ALG: "));
  966. Serial.println(dexed->data[DEXED_VOICE_OFFSET + DEXED_ALGORITHM], DEC);
  967. Serial.print(F("FB: "));
  968. Serial.println(dexed->data[DEXED_VOICE_OFFSET + DEXED_FEEDBACK], DEC);
  969. Serial.print(F("OKS: "));
  970. Serial.println(dexed->data[DEXED_VOICE_OFFSET + DEXED_OSC_KEY_SYNC], DEC);
  971. Serial.print(F("LFO SPD: "));
  972. Serial.println(dexed->data[DEXED_VOICE_OFFSET + DEXED_LFO_SPEED], DEC);
  973. Serial.print(F("LFO_DLY: "));
  974. Serial.println(dexed->data[DEXED_VOICE_OFFSET + DEXED_LFO_DELAY], DEC);
  975. Serial.print(F("LFO PMD: "));
  976. Serial.println(dexed->data[DEXED_VOICE_OFFSET + DEXED_LFO_PITCH_MOD_DEP], DEC);
  977. Serial.print(F("LFO_AMD: "));
  978. Serial.println(dexed->data[DEXED_VOICE_OFFSET + DEXED_LFO_AMP_MOD_DEP], DEC);
  979. Serial.print(F("LFO_SYNC: "));
  980. Serial.println(dexed->data[DEXED_VOICE_OFFSET + DEXED_LFO_SYNC], DEC);
  981. Serial.print(F("LFO_WAVEFRM: "));
  982. Serial.println(dexed->data[DEXED_VOICE_OFFSET + DEXED_LFO_WAVE], DEC);
  983. Serial.print(F("LFO_PMS: "));
  984. Serial.println(dexed->data[DEXED_VOICE_OFFSET + DEXED_LFO_PITCH_MOD_SENS], DEC);
  985. Serial.print(F("TRNSPSE: "));
  986. Serial.println(dexed->data[DEXED_VOICE_OFFSET + DEXED_TRANSPOSE], DEC);
  987. Serial.print(F("NAME: "));
  988. strncpy(voicename, (char *)&dexed->data[DEXED_VOICE_OFFSET + DEXED_NAME], sizeof(voicename) - 1);
  989. Serial.print(F("["));
  990. Serial.print(voicename);
  991. Serial.println(F("]"));
  992. for (i = DEXED_GLOBAL_PARAMETER_OFFSET; i <= DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_MAX_NOTES; i++)
  993. {
  994. Serial.print(i, DEC);
  995. Serial.print(F(": "));
  996. Serial.println(dexed->data[i]);
  997. }
  998. Serial.println();
  999. }
  1000. #endif