{"id":55,"date":"2016-08-01T12:48:44","date_gmt":"2016-08-01T10:48:44","guid":{"rendered":"https:\/\/www.bollie.de\/blog\/?p=55"},"modified":"2018-05-25T00:01:04","modified_gmt":"2018-05-24T22:01:04","slug":"midi-controller-with-tap-tempo-for-tc-d-two","status":"publish","type":"post","link":"https:\/\/www.bollie.de\/blog\/2016\/08\/01\/midi-controller-with-tap-tempo-for-tc-d-two\/","title":{"rendered":"Midi Controller with Tap Tempo for the tc electronic D-Two"},"content":{"rendered":"<p><a href=\"https:\/\/www.bollie.de\/blog\/wp-content\/uploads\/2016\/08\/Photo-2016-08-01-10-56-22_FullSizeRender.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.bollie.de\/blog\/wp-content\/uploads\/2016\/08\/Photo-2016-08-01-10-56-22_FullSizeRender-284x300.jpg\" alt=\"Photo-2016-08-01-10-56-22_FullSizeRender\" width=\"284\" height=\"300\" class=\"aligncenter size-medium wp-image-68\" srcset=\"https:\/\/www.bollie.de\/blog\/wp-content\/uploads\/2016\/08\/Photo-2016-08-01-10-56-22_FullSizeRender-284x300.jpg 284w, https:\/\/www.bollie.de\/blog\/wp-content\/uploads\/2016\/08\/Photo-2016-08-01-10-56-22_FullSizeRender-768x810.jpg 768w, https:\/\/www.bollie.de\/blog\/wp-content\/uploads\/2016\/08\/Photo-2016-08-01-10-56-22_FullSizeRender-970x1024.jpg 970w, https:\/\/www.bollie.de\/blog\/wp-content\/uploads\/2016\/08\/Photo-2016-08-01-10-56-22_FullSizeRender-624x658.jpg 624w\" sizes=\"(max-width: 284px) 100vw, 284px\" \/><\/a><br \/>\nI recently discovered, that my beloved guitar amp sounds so much better without too many FX pedals in the input signal chain. Still, I don&#8217;t want to live without a nice chorus or delay. So, additionally to micing the amp&#8217;s speaker, I got myself a Palmer PSI 03 JB in order to feed my old tc d-two with a speaker simulated signal and have two additional wet channels.<\/p>\n<p>In order to switch programs on the d-two I&#8217;d need to buy myself a midi foot controller, and with that I&#8217;d not be able to tap the delay time, as tc states, that there&#8217;s no way to do that using MIDI (see <a href=\"http:\/\/support.tcelectronic.com\/entries\/20943527-D-Two-Ability-to-tap-the-delay-time-using-MIDI-or-a-footswitch\">here<\/a>). While doing a bit more research, I found the <a href=\"http:\/\/cdn-downloads.tcelectronic.com\/media\/216461\/tc_electronic_d-two_midi_sysex_specifications.pdf\" target=\"_blank\">MIDI specification<\/a> for my device. I noticed, that you&#8217;re able to change the delay time by using either MIDI CC48 or a SysEx command.<\/p>\n<p>So, I had the idea to get myself a nice pedal case, switches, etc. and some <a href=\"https:\/\/www.arduino.cc\/\" target=\"_blank\">Arduino<\/a>. I read up on how to use it to send MIDI data and founds this wonderful <a href=\"https:\/\/www.arduino.cc\/en\/Tutorial\/Midi\" target=\"_blank\">article<\/a>. So without doing much circuit design or creating a BOM, I went to my local electronics supplier and got the stuff needed, which isn&#8217;t much after all:<\/p>\n<ul>\n<li>aluminium case<\/li>\n<li>3 momentary foot switches<\/li>\n<li>3 220 Ohm resistors<\/li>\n<li>1 DIN\/MIDI plug, female<\/li>\n<li>mounting screws<\/li>\n<li>Connectors for the arduino<\/li>\n<li>Green LED<\/li>\n<li>Arduino UNO<\/li>\n<\/ul>\n<p>I had some vero board still lying around and decided to use it for the rather small circuit needed to do this. I really hate these boards! All that cutting and scraping. But well, sufficient for now. \ud83d\ude09 I first programmed the tapping using a bread board and the LED and quickly went on with putting the actual case together. It didn&#8217;t turn out as nice as I intended it to look, partly owed to my vero board aversion, partly to the fact, that I&#8217;m too stupid to create a nice cable routing. \ud83d\ude09 But anyway&#8230;<\/p>\n<p><a href=\"https:\/\/www.bollie.de\/blog\/wp-content\/uploads\/2016\/08\/Photo-2016-08-01-10-57-26_FullSizeRender.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.bollie.de\/blog\/wp-content\/uploads\/2016\/08\/Photo-2016-08-01-10-57-26_FullSizeRender-255x300.jpg\" alt=\"Photo-2016-08-01-10-57-26_FullSizeRender\" width=\"255\" height=\"300\" class=\"aligncenter size-medium wp-image-69\" srcset=\"https:\/\/www.bollie.de\/blog\/wp-content\/uploads\/2016\/08\/Photo-2016-08-01-10-57-26_FullSizeRender-255x300.jpg 255w, https:\/\/www.bollie.de\/blog\/wp-content\/uploads\/2016\/08\/Photo-2016-08-01-10-57-26_FullSizeRender-768x904.jpg 768w, https:\/\/www.bollie.de\/blog\/wp-content\/uploads\/2016\/08\/Photo-2016-08-01-10-57-26_FullSizeRender-870x1024.jpg 870w, https:\/\/www.bollie.de\/blog\/wp-content\/uploads\/2016\/08\/Photo-2016-08-01-10-57-26_FullSizeRender-624x735.jpg 624w\" sizes=\"(max-width: 255px) 100vw, 255px\" \/><\/a><\/p>\n<p>Next up: Trying to understand MIDI data. It took a while until I realized, what 7 and 14 bit packed into bytes is about. Obviously, the most significant bit usually is 1 for status bytes (I&#8217;d rather call them command bytes) and 0 for data bytes and the rest of the byte is being used for commands or data. While reading the mentioned MIDI specification for the d-two, I first thought CC48 would do what I wanted. But, how would you encode let&#8217;s say 1000ms to a data byte, that on top of that only uses 7 bits for data? The specs don&#8217;t tell. \ud83d\ude41 So I put all my hope in using the &#8220;Parameter Data&#8221; sysex command:<\/p>\n<pre class=\"lang:default decode:true \" title=\"SysEx Parameter Data\" >\r\n0xF0            SysEx\r\n0x00            TC Electronic\r\n0x20            ..\r\n0x1F            ..\r\n&lt;Device ID&gt;     Device ID\r\n0x45            D-Two\r\n0x22            SYXTYPE_PARAMDATA\r\n[0x00 | 0x01]   7-bit value specifying system- (1) or algo- (0) parameter.\r\n&lt;Param ID&gt;      7-bit Parameter identifier\r\n&lt;Data&gt;          Byte pair yielding signed 14-bit parameter values (MSB first)\r\n0xF7            EOX\r\n\r\nAlgorithm parameter name\r\nID           Min value         Max value\r\nMIDI_DELAY   0                 10000 (5000 using a stereo delay)<\/pre>\n<p>But how the hell do you encode &#8211; let&#8217;s say &#8211; a value of 5000ms to 14 bit divided into an MSB and LSB? Well, I took some paper and started to wrap my brain around bit shifting and masking. I also asked <a href=\"http:\/\/gareus.org\/\" target=\"_blank\">Robin Gareus<\/a> to verify my method and he kindly pointed out, that I had forgotten handling negative values properly (&#8220;Oh, right it&#8217;s SIGNED 14 bit!&#8221;) and that I had MSB and LSB in the wrong order. So I ended up doing this:<\/p>\n<pre class=\"lang:c decode:true \" >\r\nbyte dmsb = (d &gt;&gt; 7 ) &amp; 0x3f | (d &lt; 0 ? 0x40 : 0x00);\r\nbyte dlsb = (d &amp; 0x7f);\r\n<\/pre>\n<p><em>(d is an unsigned int containing the delay time in ms)<\/em><\/p>\n<p>Thank you so much, Robin. \ud83d\ude42<\/p>\n<p>After a few meander regarding the SysEx param IDs, I eventually succeeded:<\/p>\n<p><iframe loading=\"lazy\" title=\"Arduino MIDI-Controller \/ MIDI TAP Tempo for the tc d-two\" width=\"625\" height=\"352\" src=\"https:\/\/www.youtube.com\/embed\/9NI0gEbZUx8?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/p>\n<p>Well, and here&#8217;s the complete code of the sketch. Feel free to use and adapt it. \ud83d\ude42 It&#8217;s probably a bit quick and dirty. Feel free to send me a comment if you have suggestions.<\/p>\n<pre class=\"lang:arduino decode:true \" title=\"d2ino-midi.ino\" >\/**\r\n * d2ino-midi\r\n * \r\n * This sketch turns your arduino into a midi controller for program\r\n * up\/down and lets you tap the delay time via MIDI on the tc d-two.\r\n * \r\n * created 2016-07-27\r\n * modified 2016-08-01\r\n * by Thomas Ebeling - https:\/\/www.bollie.de\r\n * \r\n * Feel free to use and adapt it. :)\r\n *\/\r\n\r\n#define PIN_LED 13\r\n#define PIN_TAP 7\r\n#define PIN_PUP 4\r\n#define PIN_PDN 2\r\n\r\n\/\/ defaults for user bank\r\n#define P_MIN 0\r\n#define P_MAX 127\r\n\r\n\/\/ Preset\r\nunsigned int delay_t = 1000;\r\nbyte program = P_MIN;\r\n\r\n\/\/ Some states\r\nbool led_on = false;\r\nbool last_tap_state = HIGH;\r\nbool last_pup_state = HIGH;\r\nbool last_pdn_state = HIGH;\r\nunsigned int start_tap = 0;\r\nunsigned int last_led_toggle = 0;\r\n\r\n\r\n\/**\r\n * Setup serial rate and pin types\/states.\r\n *\/\r\nvoid setup() {\r\n  \/\/ put your setup code here, to run once:\r\n  pinMode(PIN_LED, OUTPUT);\r\n  pinMode(PIN_TAP, INPUT_PULLUP);\r\n  pinMode(PIN_PUP, INPUT_PULLUP);\r\n  pinMode(PIN_PDN, INPUT_PULLUP);\r\n\r\n  \/\/ Set up Serial for midi\r\n  Serial.begin(31250);\r\n}\r\n\r\n\r\n\/**\r\n * Main Loop.\r\n * It listens on the digital pins and checks wether to \r\n * send program changes or delay time.\r\n *\/\r\nvoid loop() {\r\n  unsigned int ms = millis();\r\n\r\n  \/\/ Collect button states\r\n  bool cur_tap_state = digitalRead(PIN_TAP);\r\n  bool cur_pup_state = digitalRead(PIN_PUP);\r\n  bool cur_pdn_state = digitalRead(PIN_PDN);\r\n\r\n  \/\/ Tap handling\r\n  \/\/ Memorize the tap state to avoid flutter\r\n  if (cur_tap_state == LOW &amp;&amp; last_tap_state != cur_tap_state) {\r\n    if (start_tap == 0) {\r\n      start_tap = ms;\r\n    }\r\n    else if (ms - start_tap &gt; 10000) {\r\n      start_tap = 0;\r\n    }\r\n    else if (start_tap != ms) {\r\n      \r\n      \/\/ Again, trying to avoid a bit of flutter\r\n      delay_t = ms - start_tap;\r\n\r\n      \/\/ Send the new delay time via sysex\r\n      midi_set_delay_sysex(delay_t);\r\n\r\n      \/\/ Reset start tap time\r\n      start_tap = 0;\r\n    }\r\n  }\r\n  last_tap_state = cur_tap_state;\r\n\r\n  \/\/ Tap LED toggling\r\n  if (ms - last_led_toggle &gt;= delay_t) {\r\n    if (led_on) {\r\n      digitalWrite(PIN_LED, LOW);\r\n      led_on = false;\r\n    }\r\n    else {\r\n      digitalWrite(PIN_LED, HIGH);\r\n      led_on = true;\r\n    }\r\n    last_led_toggle = ms;\r\n  }\r\n\r\n  \/\/ Program up\r\n  if (cur_pup_state == LOW &amp;&amp; last_pup_state != cur_pup_state) {\r\n    if (program + 1 &lt;= P_MAX) {\r\n      midi_set_prog(++program);\r\n    }\r\n  }\r\n\r\n  \/\/ Program down\r\n  if (cur_pdn_state == LOW &amp;&amp; last_pdn_state != cur_pdn_state) {\r\n    if (program - 1 &gt;= P_MIN) {\r\n      midi_set_prog(--program);\r\n    }\r\n  }\r\n\r\n  \/\/ Memorize the button states\r\n  last_tap_state = cur_tap_state;\r\n  last_pup_state = cur_pup_state;\r\n  last_pdn_state = cur_pdn_state;\r\n\r\n  \/\/ Wait an ms\r\n  delay(1);\r\n}\r\n\r\n\r\n\/**\r\n * Program change\r\n * \\param p Program to switch to.\r\n *\/\r\nvoid midi_set_prog(byte p) {\r\n  Serial.write(0xC0);\r\n  Serial.write(p);\r\n}\r\n\r\n\r\n\/**\r\n * Sets the delay time for the current patch using tc sysex.\r\n * \\param d delay time in ms (max. 10000)\r\n *\/\r\nvoid midi_set_delay_sysex(unsigned int d) {\r\n  \/\/ Do some bit shifting\r\n  byte dmsb = (d &gt;&gt; 7 ) &amp; 0x3f | (d &lt; 0 ? 0x40 : 0x00);\r\n  byte dlsb = (d &amp; 127) &amp; 0x7f;\r\n  Serial.write(0xf0);\r\n  Serial.write(0x00);\r\n  Serial.write(0x20);\r\n  Serial.write(0x1f);\r\n  Serial.write(0x00); \/\/ Device ID\r\n  Serial.write(0x45);\r\n  Serial.write(0x22);\r\n  Serial.write(0x00);\r\n  Serial.write(0x00); \/\/ Param\r\n  Serial.write(dmsb); \/\/ MSB\r\n  Serial.write(dlsb); \/\/ LSB\r\n  Serial.write(0xf7); \/\/ end\r\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I recently discovered, that my beloved guitar amp sounds so much better without too many FX pedals in the input signal chain. Still, I don&#8217;t want to live without a nice chorus or delay. So, additionally to micing the amp&#8217;s speaker, I got myself a Palmer PSI 03 JB in order to feed my old [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[23,31,29,32,25,30,28,27],"_links":{"self":[{"href":"https:\/\/www.bollie.de\/blog\/wp-json\/wp\/v2\/posts\/55"}],"collection":[{"href":"https:\/\/www.bollie.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bollie.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bollie.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bollie.de\/blog\/wp-json\/wp\/v2\/comments?post=55"}],"version-history":[{"count":11,"href":"https:\/\/www.bollie.de\/blog\/wp-json\/wp\/v2\/posts\/55\/revisions"}],"predecessor-version":[{"id":73,"href":"https:\/\/www.bollie.de\/blog\/wp-json\/wp\/v2\/posts\/55\/revisions\/73"}],"wp:attachment":[{"href":"https:\/\/www.bollie.de\/blog\/wp-json\/wp\/v2\/media?parent=55"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bollie.de\/blog\/wp-json\/wp\/v2\/categories?post=55"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.bollie.de\/blog\/wp-json\/wp\/v2\/tags?post=55"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}