1
1

drumduino.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #include "stdafx.h"
  2. #include "drumduino.h"
  3. #include "porttab.h"
  4. size_t mapChannels(size_t channel)
  5. {
  6. return channel;
  7. //size_t port = channel / 8;
  8. //size_t chan = channel % 8;
  9. //const size_t pinMapping[8] = {2, 4, 1, 6, 0, 7, 3, 5};
  10. //return port * CHAN_CNT + pinMapping[chan] - 1;
  11. }
  12. drumduino::drumduino(QWidget* parent)
  13. : QMainWindow(parent)
  14. , _lasttime(QDateTime::currentMSecsSinceEpoch())
  15. {
  16. ui.setupUi(this);
  17. for(auto i = 0; i < PORT_CNT; ++i) {
  18. ui.tabWidget->addTab(new PortTab(), "Port_" + QString::number(i));
  19. }
  20. for(auto i = 0; i < PORT_CNT * CHAN_CNT; ++i) {
  21. _plots.push_back(new QCustomPlot(ui.tabWidget->widget(i / 8)));
  22. _plots.back()->addGraph();
  23. _plots.back()->xAxis->setRange(0, 1024);
  24. _plots.back()->yAxis->setRange(0, 127);
  25. _plots.back()->resize(1100, 100);
  26. _plots.back()->move(0, i % 8 * 100);
  27. }
  28. _serial = std::make_shared<Serial>(L"COM3", 115200);
  29. _midiOut = std::make_shared<MidiOut>(1);
  30. {
  31. QTimer* timer = new QTimer(this);
  32. _lasttime = QDateTime::currentMSecsSinceEpoch();
  33. connect(timer, &QTimer::timeout, this, &drumduino::serialRead);
  34. timer->start(0);
  35. }
  36. //{
  37. // QTimer* timer = new QTimer(this);
  38. // connect(timer, &QTimer::timeout, this, &drumduino::updateGraph);
  39. // timer->start(1000);
  40. //}
  41. }
  42. drumduino::~drumduino()
  43. {
  44. }
  45. void drumduino::serialRead()
  46. {
  47. AGAIN:
  48. auto available = _serial->available();
  49. if(available < 1 + PORT_CNT * CHAN_CNT) {
  50. return;
  51. }
  52. byte sentinel;
  53. _serial->readBytes(&sentinel, 1);
  54. if(sentinel != 0xff) {
  55. goto AGAIN;
  56. }
  57. //now we have a full frame
  58. std::array<byte, PORT_CNT* CHAN_CNT> frame;
  59. _serial->readBytes(frame.data(), frame.size());
  60. auto currentIndex = _currentFrame % 1024;
  61. handleFrame(frame, currentIndex);
  62. //for(size_t i = 0; i < PORT_CNT * CHAN_CNT; ++i) {
  63. // _frameBuffer[mapChannels(i)][currentIndex] = frame[i];
  64. //}
  65. ++_currentFrame;
  66. //auto now = QDateTime::currentMSecsSinceEpoch();
  67. //float deltaT = now - _lasttime;
  68. //float fps = _currentFrame / deltaT * 1000;
  69. //setWindowTitle(QString::number(fps));
  70. }
  71. void drumduino::updateGraph()
  72. {
  73. QVector<qreal> x(1024);
  74. QVector<qreal> y(1024);
  75. for(auto i = 0; i < 1024; ++i) {
  76. x[i] = i;
  77. }
  78. for(auto i = 0; i < PORT_CNT * CHAN_CNT; ++i) {
  79. if(_plots[i]->isVisible()) {
  80. for(auto k = 0; k < 1024; ++k) {
  81. y[k] = _frameBuffer[i][k];
  82. }
  83. _plots[i]->graph(0)->setData(x, y);
  84. _plots[i]->replot();
  85. }
  86. }
  87. }
  88. void drumduino::handleFrame(const std::array<byte, PORT_CNT* CHAN_CNT>& frame, const uint64_t currentIndex)
  89. {
  90. auto fnMidiNoteOn = [this](size_t channel, byte newValue) {
  91. auto note = 50 + channel;
  92. auto velocity = newValue;
  93. byte data[] = {0x90 | channel, 0x7f & note , 0x7f & velocity };
  94. std::vector<byte> message(sizeof(data));
  95. memcpy(message.data(), data, message.size());
  96. _midiOut->send(message);
  97. };
  98. for(auto channel = 0; channel < PORT_CNT * CHAN_CNT; ++channel) {
  99. auto curTime = QDateTime::currentMSecsSinceEpoch();
  100. auto newValue = frame[channel];
  101. auto lastValue = _frameBuffer[mapChannels(channel)][currentIndex];
  102. auto& state = _states[channel];
  103. auto& trigger = _triggers[channel];
  104. auto& max = _max[channel];
  105. //switch(channelSettings.type) {
  106. // case TypePiezo: {
  107. switch(state) {
  108. // In this state we wait for a signal to trigger
  109. case StateAwait: {
  110. if(newValue > lastValue + 35) {
  111. state = StateScan;
  112. trigger = curTime;
  113. }
  114. lastValue = newValue;
  115. max = newValue;
  116. break;
  117. }
  118. // In this state we measure the value for the given time period to get the max value
  119. case StateScan: {
  120. if(curTime < trigger + 25) {
  121. max = newValue > max ? newValue : max;
  122. }
  123. else {
  124. fnMidiNoteOn(channel, max);
  125. state = StateMask;
  126. }
  127. break;
  128. }
  129. // In this state we do nothing to prevent retriggering
  130. case StateMask: {
  131. if(curTime >= trigger + 25 + 30) {
  132. state = StateAwait;
  133. lastValue = newValue;
  134. }
  135. break;
  136. }
  137. }
  138. // }
  139. //}
  140. }
  141. }