|
@@ -16,6 +16,11 @@ size_t mapChannels(size_t channel)
|
|
|
return port * CHAN_CNT + pinMapping[chan];
|
|
return port * CHAN_CNT + pinMapping[chan];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+unsigned long g_lastTime = 0;
|
|
|
|
|
+
|
|
|
|
|
+uint64_t g_timeSum = 0;
|
|
|
|
|
+uint64_t g_frameTime = 0;
|
|
|
|
|
+
|
|
|
bool readNextFrame(std::shared_ptr<Serial>& serial, DrumduinoProc& proc)
|
|
bool readNextFrame(std::shared_ptr<Serial>& serial, DrumduinoProc& proc)
|
|
|
{
|
|
{
|
|
|
AGAIN:
|
|
AGAIN:
|
|
@@ -26,17 +31,28 @@ AGAIN:
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
byte sentinel;
|
|
byte sentinel;
|
|
|
- serial->readBytes(&sentinel, 1);
|
|
|
|
|
|
|
+ serial->readBytes(&sentinel, sizeof(sentinel));
|
|
|
|
|
|
|
|
if(sentinel != 0xf0) {
|
|
if(sentinel != 0xf0) {
|
|
|
goto AGAIN;
|
|
goto AGAIN;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
byte manufacturer;
|
|
byte manufacturer;
|
|
|
- serial->readBytes(&manufacturer, 1);
|
|
|
|
|
|
|
+ serial->readBytes(&manufacturer, sizeof(manufacturer));
|
|
|
|
|
+
|
|
|
|
|
+ unsigned long time1;
|
|
|
|
|
+ serial->readBytes((byte*)&time1, sizeof(time1));
|
|
|
|
|
+
|
|
|
|
|
+ unsigned long time2;
|
|
|
|
|
+ serial->readBytes((byte*)&time2, sizeof(time2));
|
|
|
|
|
+
|
|
|
|
|
|
|
|
- unsigned long time;
|
|
|
|
|
- serial->readBytes((byte*)&time, sizeof(unsigned long));
|
|
|
|
|
|
|
+ auto timeDiff1 = time1 - g_lastTime;
|
|
|
|
|
+ auto timeDiff2 = time2 - time1;
|
|
|
|
|
+
|
|
|
|
|
+ g_lastTime = time2;
|
|
|
|
|
+ g_frameTime = timeDiff1 + timeDiff2;
|
|
|
|
|
+ g_timeSum += g_frameTime;
|
|
|
|
|
|
|
|
auto& frame = proc.frameBuffer[proc.frameCounter % BufferSize];
|
|
auto& frame = proc.frameBuffer[proc.frameCounter % BufferSize];
|
|
|
serial->readBytes(frame.data(), frame.size());
|
|
serial->readBytes(frame.data(), frame.size());
|
|
@@ -58,7 +74,7 @@ void midiNoteOn(std::shared_ptr<MidiOut>& midiOut, byte channel, byte note, byte
|
|
|
midiOut->send(message);
|
|
midiOut->send(message);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void processFrame(std::shared_ptr<MidiOut>& midiOut, DrumduinoProc& proc, const Settings& settings)
|
|
|
|
|
|
|
+void processFrame(DrumduinoProc& proc, const Settings& settings, std::function<void(size_t channel, byte maxValue, byte sumValue)> fnOnNote)
|
|
|
{
|
|
{
|
|
|
const auto& lastFrame = proc.frameBuffer[(proc.frameCounter - 1) % BufferSize];
|
|
const auto& lastFrame = proc.frameBuffer[(proc.frameCounter - 1) % BufferSize];
|
|
|
const auto& currentFrame = proc.frameBuffer[proc.frameCounter % BufferSize];
|
|
const auto& currentFrame = proc.frameBuffer[proc.frameCounter % BufferSize];
|
|
@@ -70,6 +86,7 @@ void processFrame(std::shared_ptr<MidiOut>& midiOut, DrumduinoProc& proc, const
|
|
|
auto& state = proc.states[channel];
|
|
auto& state = proc.states[channel];
|
|
|
auto& triggerFrame = proc.triggers[channel];
|
|
auto& triggerFrame = proc.triggers[channel];
|
|
|
auto& maxValue = proc.maxs[channel];
|
|
auto& maxValue = proc.maxs[channel];
|
|
|
|
|
+ auto& sumValue = proc.sums[channel];
|
|
|
|
|
|
|
|
const auto& channelSettings = settings.channelSettings[channel];
|
|
const auto& channelSettings = settings.channelSettings[channel];
|
|
|
|
|
|
|
@@ -87,6 +104,7 @@ STATE_AGAIN:
|
|
|
state = StateScan;
|
|
state = StateScan;
|
|
|
triggerFrame = proc.frameCounter;
|
|
triggerFrame = proc.frameCounter;
|
|
|
maxValue = currentValue;
|
|
maxValue = currentValue;
|
|
|
|
|
+ sumValue = currentValue;
|
|
|
//fallthrough
|
|
//fallthrough
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -94,10 +112,11 @@ STATE_AGAIN:
|
|
|
case StateScan: {
|
|
case StateScan: {
|
|
|
if(proc.frameCounter < triggerFrame + channelSettings.scanTime) {
|
|
if(proc.frameCounter < triggerFrame + channelSettings.scanTime) {
|
|
|
maxValue = std::max(currentValue, maxValue);
|
|
maxValue = std::max(currentValue, maxValue);
|
|
|
|
|
+ sumValue += currentValue;
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- midiNoteOn(midiOut, settings.midiChannel, channelSettings.note, calcCurve(channelSettings.curve, maxValue));
|
|
|
|
|
|
|
+ fnOnNote(channel, maxValue, sumValue / channelSettings.scanTime);
|
|
|
state = StateMask;
|
|
state = StateMask;
|
|
|
//fallthrough
|
|
//fallthrough
|
|
|
|
|
|
|
@@ -175,96 +194,148 @@ Drumduino::Drumduino(QWidget* parent)
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+ connect(this, &Drumduino::updateChannelProgess, this, &Drumduino::slotUpdateChannelProgress, Qt::QueuedConnection);
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ //_serial = std::make_shared<Serial>(L"COM3", 115200);
|
|
|
|
|
+ _serial = std::make_shared<Serial>(L"COM3", 2000000);
|
|
|
|
|
+ _midiOut = std::make_shared<MidiOut>(1);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ _drumduinoThread = new DrumduinoThread(this, [this]() {
|
|
|
|
|
+ if(readNextFrame(_serial, _proc)) {
|
|
|
|
|
+ processFrame(_proc, _settings, [this](size_t channel, byte maxValue, byte sumValue) {
|
|
|
|
|
+ const auto& channelSettings = _settings.channelSettings[channel];
|
|
|
|
|
|
|
|
- _serial = std::make_shared<Serial>(L"COM3", 115200);
|
|
|
|
|
- _midiOut = std::make_shared<MidiOut>(1);
|
|
|
|
|
|
|
+ auto calcValue = 0;
|
|
|
|
|
|
|
|
|
|
+ if(channelSettings.sum) {
|
|
|
|
|
+ calcValue = calcCurve(channelSettings.curve, sumValue * 2);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ else {
|
|
|
|
|
+ calcValue = calcCurve(channelSettings.curve, maxValue);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- _drumduinoThread = new DrumduinoThread(this, [this]() {
|
|
|
|
|
- if(readNextFrame(_serial, _proc)) {
|
|
|
|
|
- processFrame(_midiOut, _proc, _settings);
|
|
|
|
|
|
|
+ midiNoteOn(_midiOut, _settings.midiChannel, channelSettings.note, calcValue);
|
|
|
|
|
+ emit updateChannelProgess(channel, maxValue, sumValue, calcValue);
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
#if 1
|
|
#if 1
|
|
|
- _proc.stateBuffer[_proc.frameCounter % BufferSize] = _proc.states;
|
|
|
|
|
|
|
+ _proc.stateBuffer[_proc.frameCounter % BufferSize] = _proc.states;
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
- ++_proc.frameCounter;
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- _drumduinoThread->start();
|
|
|
|
|
|
|
+ ++_proc.frameCounter;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ _drumduinoThread->start();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 1
|
|
#if 1
|
|
|
- {
|
|
|
|
|
- std::array<QCustomPlot*, PORT_CNT* CHAN_CNT> plots;
|
|
|
|
|
-
|
|
|
|
|
- for(auto port = 0; port < PORT_CNT; ++port) {
|
|
|
|
|
- auto wgtPort = ui.tabWidget->widget(ui.tabWidget->addTab(new PortTab(), "Graph_Port " + QString::number(port)));
|
|
|
|
|
-
|
|
|
|
|
- auto table = new QTableWidget(CHAN_CNT, 1, wgtPort);
|
|
|
|
|
- table->horizontalHeader()->setStretchLastSection(true);
|
|
|
|
|
- table->verticalHeader()->setMinimumHeight(100);
|
|
|
|
|
- table->horizontalHeader()->setVisible(false);
|
|
|
|
|
- wgtPort->layout()->addWidget(table);
|
|
|
|
|
-
|
|
|
|
|
- for(auto pin = 0; pin < CHAN_CNT; ++pin) {
|
|
|
|
|
- auto channel = port * CHAN_CNT + pin;
|
|
|
|
|
- auto wgtPlot = new QCustomPlot(table);
|
|
|
|
|
- wgtPlot->addGraph();
|
|
|
|
|
- table->setRowHeight(pin, 127);
|
|
|
|
|
- table->setCellWidget(pin, 0, wgtPlot);
|
|
|
|
|
-
|
|
|
|
|
- wgtPlot->xAxis->setRange(0, BufferSize);
|
|
|
|
|
- wgtPlot->yAxis->setRange(0, 127);
|
|
|
|
|
- wgtPlot->yAxis2->setRange(0, 2);
|
|
|
|
|
- wgtPlot->yAxis2->setVisible(true);
|
|
|
|
|
-
|
|
|
|
|
- auto stateGraph = wgtPlot->addGraph(wgtPlot->xAxis, wgtPlot->yAxis2);
|
|
|
|
|
- stateGraph->setPen(QPen(Qt::red));
|
|
|
|
|
- stateGraph->setLineStyle(QCPGraph::LineStyle::lsStepLeft);
|
|
|
|
|
-
|
|
|
|
|
- plots[port * CHAN_CNT + pin] = wgtPlot;
|
|
|
|
|
|
|
+ {
|
|
|
|
|
+ std::array<QCustomPlot*, PORT_CNT* CHAN_CNT> plots;
|
|
|
|
|
+
|
|
|
|
|
+ for(auto port = 0; port < PORT_CNT; ++port) {
|
|
|
|
|
+ auto wgtPort = ui.tabWidget->widget(ui.tabWidget->addTab(new PortTab(), "Graph_Port " + QString::number(port)));
|
|
|
|
|
+
|
|
|
|
|
+ auto table = new QTableWidget(CHAN_CNT, 1, wgtPort);
|
|
|
|
|
+ table->horizontalHeader()->setStretchLastSection(true);
|
|
|
|
|
+ table->verticalHeader()->setMinimumHeight(100);
|
|
|
|
|
+ table->horizontalHeader()->setVisible(false);
|
|
|
|
|
+ wgtPort->layout()->addWidget(table);
|
|
|
|
|
+
|
|
|
|
|
+ for(auto pin = 0; pin < CHAN_CNT; ++pin) {
|
|
|
|
|
+ auto channel = port * CHAN_CNT + pin;
|
|
|
|
|
+ auto wgtPlot = new QCustomPlot(table);
|
|
|
|
|
+
|
|
|
|
|
+ wgtPlot->setBackground(qApp->palette().button());
|
|
|
|
|
+ QPen pen(qApp->palette().midlight().color());
|
|
|
|
|
+ pen.setStyle(Qt::PenStyle::DotLine);
|
|
|
|
|
+ wgtPlot->xAxis->grid()->setPen(pen);
|
|
|
|
|
+ wgtPlot->yAxis->grid()->setPen(pen);
|
|
|
|
|
+ wgtPlot->xAxis2->grid()->setPen(pen);
|
|
|
|
|
+ wgtPlot->yAxis2->grid()->setPen(pen);
|
|
|
|
|
+
|
|
|
|
|
+ wgtPlot->xAxis->setBasePen(qApp->palette().windowText().color());
|
|
|
|
|
+ wgtPlot->yAxis->setBasePen(qApp->palette().windowText().color());
|
|
|
|
|
+ wgtPlot->xAxis2->setBasePen(qApp->palette().windowText().color());
|
|
|
|
|
+ wgtPlot->yAxis2->setBasePen(qApp->palette().windowText().color());
|
|
|
|
|
+
|
|
|
|
|
+ wgtPlot->xAxis->setTickPen(qApp->palette().windowText().color());
|
|
|
|
|
+ wgtPlot->yAxis->setTickPen(qApp->palette().windowText().color());
|
|
|
|
|
+ wgtPlot->xAxis2->setTickPen(qApp->palette().windowText().color());
|
|
|
|
|
+ wgtPlot->yAxis2->setTickPen(qApp->palette().windowText().color());
|
|
|
|
|
+
|
|
|
|
|
+ auto curve = wgtPlot->addGraph();
|
|
|
|
|
+ curve->setPen(QPen(qApp->palette().buttonText().color()));
|
|
|
|
|
+ table->setRowHeight(pin, 127);
|
|
|
|
|
+ table->setCellWidget(pin, 0, wgtPlot);
|
|
|
|
|
+
|
|
|
|
|
+ wgtPlot->xAxis->setRange(0, BufferSize);
|
|
|
|
|
+ wgtPlot->yAxis->setRange(0, 127);
|
|
|
|
|
+ wgtPlot->yAxis2->setRange(0, 2);
|
|
|
|
|
+ wgtPlot->yAxis2->setVisible(true);
|
|
|
|
|
+
|
|
|
|
|
+ auto stateGraph = wgtPlot->addGraph(wgtPlot->xAxis, wgtPlot->yAxis2);
|
|
|
|
|
+ stateGraph->setPen(QPen(qApp->palette().highlight().color()));
|
|
|
|
|
+ stateGraph->setLineStyle(QCPGraph::LineStyle::lsStepLeft);
|
|
|
|
|
+
|
|
|
|
|
+ plots[port * CHAN_CNT + pin] = wgtPlot;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- QTimer* timer = new QTimer(this);
|
|
|
|
|
- connect(timer, &QTimer::timeout, [this, plots]() {
|
|
|
|
|
- auto currentIndex = _proc.frameCounter % BufferSize;
|
|
|
|
|
- QVector<qreal> x(BufferSize);
|
|
|
|
|
- QVector<qreal> y(BufferSize);
|
|
|
|
|
- QVector<qreal> s(BufferSize);
|
|
|
|
|
|
|
+ QTimer* timer = new QTimer(this);
|
|
|
|
|
+ connect(timer, &QTimer::timeout, [this, plots]() {
|
|
|
|
|
+ auto currentIndex = _proc.frameCounter % BufferSize;
|
|
|
|
|
+ QVector<qreal> x(BufferSize);
|
|
|
|
|
+ QVector<qreal> y(BufferSize);
|
|
|
|
|
+ QVector<qreal> s(BufferSize);
|
|
|
|
|
|
|
|
- for(auto i = 0; i < BufferSize; ++i) {
|
|
|
|
|
- x[i] = i;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ for(auto i = 0; i < BufferSize; ++i) {
|
|
|
|
|
+ x[i] = i;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- for(auto i = 0; i < PORT_CNT * CHAN_CNT; ++i) {
|
|
|
|
|
- if(plots[i]->isVisible()) {
|
|
|
|
|
- auto channel = mapChannels(i);
|
|
|
|
|
|
|
+ for(auto i = 0; i < PORT_CNT * CHAN_CNT; ++i) {
|
|
|
|
|
+ if(plots[i]->isVisible()) {
|
|
|
|
|
+ auto channel = mapChannels(i);
|
|
|
|
|
|
|
|
- plots[i]->yAxis->setLabel(QString(_settings.channelSettings[i].name));
|
|
|
|
|
- plots[i]->xAxis->setRange(x.front(), x.back());
|
|
|
|
|
|
|
+ plots[i]->yAxis->setLabel(QString(_settings.channelSettings[i].name));
|
|
|
|
|
+ plots[i]->xAxis->setRange(x.front(), x.back());
|
|
|
|
|
|
|
|
- for(auto k = 0; k < BufferSize; ++k) {
|
|
|
|
|
- y[k] = _proc.frameBuffer[k][channel];
|
|
|
|
|
- s[k] = _proc.stateBuffer[k][i];
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ for(auto k = 0; k < BufferSize; ++k) {
|
|
|
|
|
+ y[k] = _proc.frameBuffer[k][channel];
|
|
|
|
|
+ s[k] = _proc.stateBuffer[k][i];
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- plots[i]->graph(0)->setData(x, y);
|
|
|
|
|
- plots[i]->graph(1)->setData(x, s);
|
|
|
|
|
|
|
+ plots[i]->graph(0)->setData(x, y);
|
|
|
|
|
+ plots[i]->graph(1)->setData(x, s);
|
|
|
|
|
|
|
|
- plots[i]->replot();
|
|
|
|
|
|
|
+ plots[i]->replot();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- timer->start(1000 / 12);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+
|
|
|
|
|
+ setWindowTitle("drumduino - sampling each channel at " + QString::number(double(g_frameTime)) + "Hz");
|
|
|
|
|
+ });
|
|
|
|
|
+ timer->start(1000 / 12);
|
|
|
|
|
+ }
|
|
|
#endif
|
|
#endif
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ catch(...)
|
|
|
|
|
+ {}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Drumduino::~Drumduino()
|
|
Drumduino::~Drumduino()
|
|
|
{
|
|
{
|
|
|
- _drumduinoThread->stop();
|
|
|
|
|
- _drumduinoThread->wait();
|
|
|
|
|
|
|
+ if(_drumduinoThread) {
|
|
|
|
|
+ _drumduinoThread->stop();
|
|
|
|
|
+ _drumduinoThread->wait();
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void Drumduino::slotUpdateChannelProgress(size_t channel, byte maxValue, byte sumValue, byte calcValue)
|
|
|
|
|
+{
|
|
|
|
|
+ _channels[channel]->triggered(maxValue, sumValue, calcValue);
|
|
|
}
|
|
}
|