drumduino_firmware.ino 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. #include <SoftwareSerial.h>
  2. enum DrumduinoFirmwareSettings {
  3. PORT_CNT = 6,
  4. CHAN_PER_PORT_CNT = 8,
  5. PAD_CNT = PORT_CNT * CHAN_PER_PORT_CNT,
  6. FRAME_BUFFER_SIZE = 3,
  7. };
  8. enum Pins {
  9. PIN_MULTIPLEX_A = 2,
  10. PIN_MULTIPLEX_B = 3 ,
  11. PIN_MULTIPLEX_C = 4 ,
  12. PIN_SOFTSERIAL_RX = 5,
  13. PIN_SOFTSERIAL_TX = 6,
  14. };
  15. //=================================================================================
  16. // Set Bit and Clwear Bit Helpers
  17. //=================================================================================
  18. #ifndef cbi
  19. #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
  20. #endif
  21. #ifndef sbi
  22. #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
  23. #endif
  24. //=================================================================================
  25. // Prescaler
  26. //=================================================================================
  27. // Maximum sampling frequency // Resolution
  28. enum Prescaler {
  29. Prescaler_2 = B00000000, // 16 MHz / 2 = 8 MHz //
  30. Prescaler_4 = B00000010, // 16 MHz / 4 = 4 MHz // ~5.9
  31. Prescaler_8 = B00000011, // 16 MHz / 8 = 2 MHz // ~7.4
  32. Prescaler_16 = B00000100, // 16 MHz / 16 = 1 MHz // ~8.6
  33. Prescaler_32 = B00000101, // 16 MHz / 32 = 500 kHz // ~8.9
  34. Prescaler_64 = B00000110, // 16 MHz / 64 = 250 kHz // ~9.0
  35. Prescaler_128 = B00000111, // 16 MHz / 128 = 125 kHz // ~9.1
  36. };
  37. inline void setPrescaler(int prescaler) {
  38. ADCSRA &= B11111000;
  39. ADCSRA |= prescaler;
  40. }
  41. //=================================================================================
  42. // Ad Pin
  43. //=================================================================================
  44. enum AdPin {
  45. AdPin_0 = B00000000,
  46. AdPin_1 = B00000001,
  47. AdPin_2 = B00000010,
  48. AdPin_3 = B00000011,
  49. AdPin_4 = B00000100,
  50. AdPin_5 = B00000101,
  51. AdPin_6 = B00000110, // Bei Atmega8 nur in der Gehäusebauform TQFP und MLF verfügbar, nicht in PDIP
  52. AdPin_7 = B00000111, // Bei Atmega8 nur in der Gehäusebauform TQFP und MLF verfügbar, nicht in PDIP
  53. AdPin_Vbg = B00001110, // 1.23V
  54. AdPin_GND = B00001111, // 0V
  55. };
  56. inline void setAdPin(int adPin) {
  57. ADMUX &= B11110000;
  58. ADMUX |= adPin;
  59. }
  60. //=================================================================================
  61. // ADC Alignment
  62. //=================================================================================
  63. // Das Ergebnis wird in den Registern ADCH/ADCL linksbündig ausgerichtet.
  64. // Die 8 höchstwertigen Bits des Ergebnisses werden in ADCH abgelegt.
  65. // Die verbleibenden 2 niederwertigen Bits werden im Register ADCL in den Bits 6 und 7 abgelegt.
  66. enum AdcAlignment {
  67. ADAlignmentLeft = B00100000,
  68. ADAlignmentRight = B00000000,
  69. };
  70. inline void setADAlignment(int align) {
  71. ADMUX &= ~B00100000;
  72. ADMUX |= align;
  73. }
  74. //=================================================================================
  75. inline void startADCConversion() {
  76. ADCSRA |= B01000000;
  77. }
  78. //=================================================================================
  79. inline void disableAnalogComparator() {
  80. ACSR = B10000000;
  81. }
  82. inline void multiplexSelectChan(uint8_t chan) {
  83. PORTD = B00011100 & (chan << 2);
  84. }
  85. //=================================================================================
  86. // MIDI
  87. //=================================================================================
  88. namespace midi {
  89. /// http://www.midi.org/techspecs/midimessages.php
  90. #if 0
  91. struct SysexFrame {
  92. byte begin = 0xf0;
  93. byte manufacturer = 42;
  94. unsigned long time1 = 0;
  95. unsigned long time2 = 0;
  96. byte values[PAD_CNT] = { 0 };
  97. byte end = 0xF7;
  98. };
  99. #endif
  100. /**
  101. Note Off event.
  102. This message is sent when a note is released (ended).
  103. */
  104. template<typename SERIAL_IF>
  105. void noteOn(SERIAL_IF& serial, int note, int velocity) {
  106. serial.write(0x90);
  107. serial.write(note);
  108. serial.write(velocity);
  109. }
  110. /**
  111. Note On event.
  112. This message is sent when a note is depressed (start).
  113. */
  114. template<typename SERIAL_IF>
  115. void noteOff(SERIAL_IF& serial, int note, int velocity) {
  116. serial.write(0x80);
  117. serial.write(note);
  118. serial.write(velocity);
  119. }
  120. /**
  121. Polyphonic Key Pressure (Aftertouch).
  122. This message is most often sent by pressing down on the key after it "bottoms out".
  123. */
  124. template<typename SERIAL_IF>
  125. void polyphonicKeyPressure(SERIAL_IF& serial, int note, int pressure) {
  126. serial.write(0xA0);
  127. serial.write(note);
  128. serial.write(pressure);
  129. }
  130. /**
  131. Control Change.
  132. This message is sent when a controller value changes.
  133. Controllers include devices such as pedals and levers.
  134. Controller numbers 120-127 are reserved as "Channel Mode Messages" (below).
  135. */
  136. template<typename SERIAL_IF>
  137. void controlChange(SERIAL_IF& serial, int controllerNumber, int controllerValue) {
  138. serial.write(0xB0);
  139. serial.write(controllerNumber);
  140. serial.write(controllerValue);
  141. }
  142. }
  143. //=================================================================================
  144. //
  145. //=================================================================================
  146. struct Configuration {
  147. enum Type {
  148. TypeDisabled,
  149. TypePiezo,
  150. } type[PAD_CNT] = { TypeDisabled };
  151. struct CurveSettings {
  152. enum CurveType {
  153. CurveNormal,
  154. CurveExp,
  155. CurveLog,
  156. CurveSigma,
  157. CurveFlat,
  158. CurveExtra,
  159. };
  160. CurveType type = CurveNormal;
  161. uint8_t value = 127;
  162. int8_t offset = 0;
  163. uint8_t factor = 127;
  164. } curve[PAD_CNT];
  165. uint8_t note[PAD_CNT] = { 0 };
  166. uint8_t threshold[PAD_CNT] = { 25 };
  167. uint8_t scanTime[PAD_CNT] = { 25 };
  168. uint8_t maskTime[PAD_CNT] = { 35 };
  169. } g_configuration;
  170. //=================================================================================
  171. //
  172. //=================================================================================
  173. struct Runtime {
  174. SoftwareSerial softSerial{ PIN_SOFTSERIAL_RX, PIN_SOFTSERIAL_TX }; // RX, TX
  175. uint8_t value[PAD_CNT][FRAME_BUFFER_SIZE];
  176. enum State {
  177. StateAwait,
  178. StateScan,
  179. StateMask,
  180. } state[PAD_CNT] = { StateAwait };
  181. uint8_t trigger[PAD_CNT] = { 0 };
  182. uint8_t max[PAD_CNT] = { 0 };
  183. //uint64_t sum[PAD_CNT] = { 0 };
  184. uint64_t frameCounter = 0;
  185. } g_runtime;
  186. //=================================================================================
  187. //
  188. //=================================================================================
  189. inline uint8_t calcCurve(const Configuration::CurveSettings& curveSettings, uint8_t value) {
  190. uint8_t ret = 0;
  191. float x = value * 8.0;
  192. float f = ((float)curveSettings.value) / 64.0; //[1;127]->[0.;2.0]
  193. switch (curveSettings.type) {
  194. //[0-1023]x[0-127]
  195. case Configuration::CurveSettings::CurveNormal:
  196. ret = x * f / 16.0;
  197. break;
  198. case Configuration::CurveSettings::CurveExp:
  199. ret = (127.0 / (exp(2.0 * f) - 1)) * (exp(f * x / 512.0) - 1.0);
  200. break; //Exp 4*(exp(x/256)-1)
  201. case Configuration::CurveSettings::CurveLog:
  202. ret = log(1.0 + (f * x / 128.0)) * (127.0 / log((8 * f) + 1));
  203. break; //Log 64*log(1+x/128)
  204. case Configuration::CurveSettings::CurveSigma:
  205. ret = (127.0 / (1.0 + exp(f * (512.0 - x) / 64.0)));
  206. break; //Sigma
  207. case Configuration::CurveSettings::CurveFlat:
  208. ret = (64.0 - ((8.0 / f) * log((1024 / (1 + x)) - 1)));
  209. break; //Flat
  210. case Configuration::CurveSettings::CurveExtra:
  211. ret = (x + 0x20) * f / 16.0;
  212. }
  213. ret = ret * (curveSettings.factor / 127.0) + curveSettings.offset;
  214. if (ret <= 0) {
  215. return 0;
  216. }
  217. if (ret >= 127) {
  218. return 127; //127
  219. }
  220. return ret;
  221. }
  222. //=================================================================================
  223. //
  224. //=================================================================================
  225. void setup() {
  226. // generate note mapping
  227. for(uint8_t pad = 0; pad < PAD_CNT; ++pad) {
  228. uint8_t note = 0x1E + pad;
  229. g_configuration.note[pad] = note;
  230. }
  231. // Setup MultiplexSelection Pins
  232. pinMode(PIN_MULTIPLEX_A, OUTPUT);
  233. pinMode(PIN_MULTIPLEX_B, OUTPUT);
  234. pinMode(PIN_MULTIPLEX_C, OUTPUT);
  235. // Setup ADCs
  236. analogReference(DEFAULT);
  237. disableAnalogComparator();
  238. setPrescaler(Prescaler_8);
  239. //setADAlignment(ADAlignmentLeft);
  240. // Disable digital input buffers on all analog input pins
  241. DIDR0 = DIDR0 | B00111111;
  242. // Setup Serial
  243. Serial.begin(2000000);
  244. Serial.flush();
  245. g_runtime.softSerial.begin(31250);
  246. g_runtime.softSerial.flush();
  247. }
  248. //=================================================================================
  249. //
  250. //=================================================================================
  251. void loop() {
  252. uint64_t& frameCounter = g_runtime.frameCounter;
  253. size_t curFrameIdx = frameCounter % FRAME_BUFFER_SIZE;
  254. size_t lastFrameIdx = (frameCounter - 1) % FRAME_BUFFER_SIZE;
  255. //unsigned long time1 = micros();
  256. for(uint8_t chan = 0; chan < CHAN_PER_PORT_CNT; ++chan) {
  257. multiplexSelectChan(chan);
  258. for(uint8_t port = 0; port < PORT_CNT; ++port) {
  259. int pad = port * CHAN_PER_PORT_CNT + chan;
  260. // shortcuts!
  261. uint8_t& currentValue = g_runtime.value[pad][curFrameIdx];
  262. const uint8_t& lastValue = g_runtime.value[pad][lastFrameIdx];
  263. Runtime::State& state = g_runtime.state[pad];
  264. uint8_t& triggerFrame = g_runtime.trigger[pad];
  265. uint8_t& maxValue = g_runtime.max[pad];
  266. //const uint8_t& sumValue = g_runtime.sum[pad];
  267. const Configuration::Type& type = g_configuration.type[pad];
  268. const uint8_t& threshold = g_configuration.threshold[pad];
  269. const uint8_t& scanTime = g_configuration.scanTime[pad];
  270. const uint8_t& maskTime = g_configuration.maskTime[pad];
  271. // real processing
  272. currentValue = uint8_t(analogRead(port) >> 3);
  273. switch(type) {
  274. case Configuration::TypePiezo: {
  275. switch(state) {
  276. // In this state we wait for a signal to trigger
  277. default:
  278. case Runtime::StateAwait: {
  279. STATE_AGAIN:
  280. if(currentValue < lastValue + threshold) {
  281. break;
  282. }
  283. state = Runtime::StateScan;
  284. triggerFrame = frameCounter;
  285. maxValue = currentValue;
  286. //sumValue = currentValue;
  287. //### fallthrough
  288. }
  289. // In this state we measure the value for the given time period to get the max value
  290. case Runtime::StateScan: {
  291. if(frameCounter < triggerFrame + scanTime) {
  292. maxValue = max(currentValue, maxValue);
  293. //sumValue += currentValue;
  294. break;
  295. }
  296. const Configuration::CurveSettings& curve = g_configuration.curve[pad];
  297. uint8_t velocity = calcCurve(curve, maxValue);
  298. const uint8_t& note = g_configuration.note[pad];
  299. midi::noteOn(g_runtime.softSerial, note, velocity);
  300. state = Runtime::StateMask;
  301. //### fallthrough
  302. }
  303. // In this state we do nothing to prevent retriggering
  304. case Runtime::StateMask: {
  305. if(frameCounter < triggerFrame + scanTime + maskTime) {
  306. break;
  307. }
  308. state = Runtime::StateAwait;
  309. goto STATE_AGAIN;
  310. }
  311. }
  312. }
  313. }
  314. }
  315. }
  316. //unsigned long time2 = micros();
  317. ++frameCounter;
  318. }