diff --git a/.gitignore b/.gitignore index 5f23603..accfdd2 100644 --- a/.gitignore +++ b/.gitignore @@ -32,5 +32,26 @@ Makefile* #QtCtreator Qml *.qmlproject.user *.qmlproject.user.* +.DS_Store -.DS_Store \ No newline at end of file +*.vsp +*.obj +*.exe +*.ilk +*.pdb +Debug\* +Release\* +*.psess +*.tlog +*.log +src/debug/* +src/release/* + +*.qm +*.sln +*.vspx +*.VC.db +*.vcxproj* +*.suo +.vs/* +x64/* diff --git a/src/BPMOscControler.cpp b/src/BPMOscControler.cpp index a498643..6953f48 100644 --- a/src/BPMOscControler.cpp +++ b/src/BPMOscControler.cpp @@ -50,7 +50,6 @@ void BPMOscControler::save(QSettings& settings) { } -inline int round(float value) { return (fmod(value,1.0) < 0.5) ? value : value + 1; } // Called by the bpm detector to make the controller send the new bpm to the clients void BPMOscControler::transmitBPM(float bpm) @@ -63,18 +62,18 @@ void BPMOscControler::transmitBPM(float bpm) continue; } QString message(command); - message.replace("", QString::number(round(bpm))); - message.replace("", QString::number(round(bpm))); - message.replace("", QString::number(round(bpm*0.5))); - message.replace("", QString::number(round(bpm*0.25))); - message.replace("", QString::number(round(bpm*0.125))); - message.replace("", QString::number(round(bpm*0.0625))); - message.replace("", QString::number(round(bpm*0.03125))); - message.replace("", QString::number(round(bpm*2))); - message.replace("", QString::number(round(bpm*4))); - message.replace("", QString::number(round(bpm*8))); - message.replace("", QString::number(round(bpm*16))); - message.replace("", QString::number(round(bpm*32))); + message.replace("", QString::number(qRound(bpm))); + message.replace("", QString::number(qRound(bpm))); + message.replace("", QString::number(qRound(bpm*0.5))); + message.replace("", QString::number(qRound(bpm*0.25))); + message.replace("", QString::number(qRound(bpm*0.125))); + message.replace("", QString::number(qRound(bpm*0.0625))); + message.replace("", QString::number(qRound(bpm*0.03125))); + message.replace("", QString::number(qRound(bpm*2))); + message.replace("", QString::number(qRound(bpm*4))); + message.replace("", QString::number(qRound(bpm*8))); + message.replace("", QString::number(qRound(bpm*16))); + message.replace("", QString::number(qRound(bpm*32))); m_osc.sendMessage(message); } diff --git a/src/MainController.cpp b/src/MainController.cpp index 35fcd75..957ec34 100644 --- a/src/MainController.cpp +++ b/src/MainController.cpp @@ -34,6 +34,8 @@ #include #include #include +#include + MainController::MainController(QQmlApplicationEngine* qmlEngine, QObject *parent) @@ -56,6 +58,7 @@ MainController::MainController(QQmlApplicationEngine* qmlEngine, QObject *parent initializeGenerators(); connectGeneratorsWithGui(); + QQmlDebuggingEnabler enabler; } MainController::~MainController() @@ -163,8 +166,10 @@ void MainController::connectGeneratorsWithGui() QQuickWindow *MainController::getMainWindow() const { - QQuickWindow* window = qobject_cast(m_qmlEngine->rootObjects()[0]); - return window; + QList objects = m_qmlEngine->rootObjects(); + if(objects.isEmpty()) + return 0; + return qobject_cast(m_qmlEngine->rootObjects()[0]); } bool MainController::settingsFormatIsValid(QSettings &settings) const diff --git a/src/TriggerGenerator.cpp b/src/TriggerGenerator.cpp index 4ecff68..d7f5aec 100644 --- a/src/TriggerGenerator.cpp +++ b/src/TriggerGenerator.cpp @@ -44,13 +44,13 @@ TriggerGenerator::TriggerGenerator(QString name, OSCNetworkManager* osc, bool is bool TriggerGenerator::checkForTrigger(ScaledSpectrum &spectrum, bool forceRelease) { qreal value; + if (m_isBandpass) { value = spectrum.getMaxLevel(m_midFreq, m_width); } else { value = spectrum.getMaxLevel(); } - if (m_invert) value = 1 - value; - + if (m_invert) value = 1 - value; // check for trigger: if ((!m_isActive && value >= m_threshold) && !forceRelease) { // activate trigger: @@ -61,10 +61,35 @@ bool TriggerGenerator::checkForTrigger(ScaledSpectrum &spectrum, bool forceRelea m_isActive = false; m_filter.triggerOff(); } + qreal diff = qAbs(m_lastValue - value); + // If a range message is set, we need to do some math. + if (m_rangeCount > 0 && diff > 0.001) { + // Divide into range based on threshold + int scaledValue = value * 100; // number between 0 - 100 + int perSection = scaledValue / m_rangeCount; + int numberToDisplay = m_groupingHash.value(scaledValue); + qDebug() << "OSC Range: " << m_oscParameters.getRangeMessage()[0] + " numberToDisplay " << numberToDisplay; + + + const int startChan = m_oscParameters.getRangeMessage()[1].toInt(); + // Four Paramaters, Start channel, end channel, start value, end value + const QString cmd = m_oscParameters.getRangeMessage()[0] /*cmd*/ + + QString::number(startChan) // %1 is the + + "," + QString::number(startChan + numberToDisplay) + + ",01," + QString::number(numberToDisplay*perSection); + m_osc->sendMessage(cmd); + + const QString zeroCmd = QString("/eos/user/0/newcmd/Chan/" + + QString::number(startChan+ numberToDisplay + 1) + + "/Thru/" + + m_oscParameters.getRangeMessage()[2] /* endChan as string */ + + "/At/0#"); + m_osc->sendMessage(zeroCmd); + } // send level if levelMessage is set: // and if difference to last value is greater than 0.001: - qreal diff = qAbs(m_lastValue - value); + if (diff > 0.001 && !m_oscParameters.getLevelMessage().isEmpty() && m_threshold > 0) { qreal valueUnderThreshold = limit(0, (value / m_threshold), 1); qreal minValue = m_oscParameters.getMinLevelValue(); @@ -78,6 +103,19 @@ bool TriggerGenerator::checkForTrigger(ScaledSpectrum &spectrum, bool forceRelea return m_isActive; } +void TriggerGenerator::generateRangeHash(int grouping) +{ + const int endChan = m_oscParameters.getRangeMessage()[2].toInt(); + const int startChan = m_oscParameters.getRangeMessage()[1].toInt(); + m_rangeCount = endChan - startChan; + qDebug() << "Generating Hash for: " << startChan << " - " << endChan; + const int groupSpacing = qFloor(100 / (m_rangeCount+1)); + for(int i = 0; i <= 100; i++ ) { + const int group = qFloor(i / (groupSpacing+1)); + m_groupingHash.insert(i, group); + } +} + void TriggerGenerator::save(QSettings& settings) const { settings.setValue(m_name + "/threshold", m_threshold); diff --git a/src/TriggerGenerator.h b/src/TriggerGenerator.h index e6715f3..79f3089 100644 --- a/src/TriggerGenerator.h +++ b/src/TriggerGenerator.h @@ -96,9 +96,16 @@ class TriggerGenerator : public TriggerGeneratorInterface // resets all parameters to default values void resetParameters(); + // ----------- Generate hash table for channel range lookups + void generateRangeHash(int grouping); + protected: const QString m_name; // name of the Trigger (used for save, restore and UI) OSCNetworkManager* m_osc; // pointer to OSCNetworkManager instance (i.e. of MainController) + // This is a lookup table generated to tell us which group a given value appears in + // It should be recalculated any time the channel range changes. + QHash m_groupingHash; + int m_rangeCount; // Count of items in the range, calculated in generateRangeHash() const bool m_invert; // true if signal values should be inverted (i.e. for "silence" trigger) int m_midFreq; // middle frequency of bandpass in Hz const int m_defaultMidFreq; // default midFreq in Hz, used for reset diff --git a/src/TriggerGuiController.h b/src/TriggerGuiController.h index 6dede1e..8273cf5 100644 --- a/src/TriggerGuiController.h +++ b/src/TriggerGuiController.h @@ -100,6 +100,9 @@ public slots: QString getLevelMessage() const { return m_trigger->getOscParameters().getLevelMessage(); } void setLevelMessage(const QString& value) {m_trigger->getOscParameters().setLevelMessage(value); emit presetChanged(); } + QStringList getRangeMessage() const { return m_trigger->getOscParameters().getRangeMessage(); } + void setRangeMessage(const QStringList& value) {m_trigger->getOscParameters().setRangeMessage(value); emit presetChanged(); } + qreal getMinLevelValue() const { return m_trigger->getOscParameters().getMinLevelValue(); } void setMinLevelValue(const qreal& value) { m_trigger->getOscParameters().setMinLevelValue(value); emit presetChanged(); } @@ -110,11 +113,15 @@ public slots: void setLabelText(const QString& value) { m_trigger->getOscParameters().setLabelText(value); emit oscLabelTextChanged(); emit presetChanged(); } // --- shortcut to set all OSC parameters: - void setOscMessages(QString on, QString off, QString level, qreal minLevel, qreal maxLevel, QString labelText) - { + void setOscMessages(QString on, QString off, QString level, QStringList range, qreal minLevel, qreal maxLevel, QString labelText) + { + qDebug() << "Range: " << range; + if(range.size() > 0) + m_trigger->generateRangeHash(range.size()); m_trigger->getOscParameters().setOnMessage(on); m_trigger->getOscParameters().setOffMessage(off); m_trigger->getOscParameters().setLevelMessage(level); + m_trigger->getOscParameters().setRangeMessage(range); m_trigger->getOscParameters().setMinLevelValue(minLevel); m_trigger->getOscParameters().setMaxLevelValue(maxLevel); m_trigger->getOscParameters().setLabelText(labelText); diff --git a/src/TriggerOscParameters.cpp b/src/TriggerOscParameters.cpp index 0ed723a..6fbc28e 100644 --- a/src/TriggerOscParameters.cpp +++ b/src/TriggerOscParameters.cpp @@ -36,6 +36,7 @@ void TriggerOscParameters::save(const QString name, QSettings &settings) const settings.setValue(name + "/osc/onMessage", m_onMessage); settings.setValue(name + "/osc/offMessage", m_offMessage); settings.setValue(name + "/osc/levelMessage", m_levelMessage); + settings.setValue(name + "/osc/rangeMessage", m_rangeMessage); settings.setValue(name + "/osc/minLevelValue", m_minLevelValue); settings.setValue(name + "/osc/maxLevelValue", m_maxLevelValue); settings.setValue(name + "/osc/labelText", m_labelText); @@ -46,6 +47,7 @@ void TriggerOscParameters::restore(const QString name, QSettings &settings) setOnMessage(settings.value(name + "/osc/onMessage").toString()); setOffMessage(settings.value(name + "/osc/offMessage").toString()); setLevelMessage(settings.value(name + "/osc/levelMessage").toString()); + setRangeMessage(settings.value(name + "/osc/rangeMessage").toStringList()); setMinLevelValue(settings.value(name + "/osc/minLevelValue").toReal()); setMaxLevelValue(settings.value(name + "/osc/maxLevelValue").toReal()); setLabelText(settings.value(name + "/osc/labelText").toString()); diff --git a/src/TriggerOscParameters.h b/src/TriggerOscParameters.h index 57c8068..49a9d43 100644 --- a/src/TriggerOscParameters.h +++ b/src/TriggerOscParameters.h @@ -25,6 +25,7 @@ #include #include +#include //TODO REMOVE THIS // A class to store OSC parameters (messages and min and max values). class TriggerOscParameters @@ -47,6 +48,11 @@ class TriggerOscParameters // sets the OSC path where the level value should be sent to void setLevelMessage(const QString& value) { m_levelMessage = value; } + // returns the OSC path where the level value should be sent to + QStringList getRangeMessage() const { return m_rangeMessage; } + // sets the OSC path where the level value should be sent to + void setRangeMessage(const QStringList& value) { qDebug() << value; m_rangeMessage = value; } + // returns the value to send when the trigger level is zero qreal getMinLevelValue() const { return m_minLevelValue; } // sets the value to send when the trigger level is zero @@ -76,6 +82,7 @@ class TriggerOscParameters QString m_onMessage; // On message ("/path/value=argument") QString m_offMessage; // Off message ("/path/value=argument") QString m_levelMessage; // Level message ("/path/value=") + QStringList m_rangeMessage; qreal m_minLevelValue; // min value to be used for Level message qreal m_maxLevelValue; // max value to be used for Level message QString m_labelText; // Short description text of parameters to be displayed in UI diff --git a/src/qml/OscMessageDialog.qml b/src/qml/OscMessageDialog.qml index f89ce5c..b2451ca 100644 --- a/src/qml/OscMessageDialog.qml +++ b/src/qml/OscMessageDialog.qml @@ -134,7 +134,7 @@ Dialog { text: "OK" onClicked: { var messages = mainArea.getMessages() - triggerController.setOscMessages(messages["on"], messages["off"], messages["level"], messages["levelMin"], messages["levelMax"], messages["shortText"]) + triggerController.setOscMessages(messages["on"], messages["off"], messages["level"], messages["range"], messages["levelMin"], messages["levelMax"], messages["shortText"]) dialog.close() controller.dialogIsClosed(dialog) } diff --git a/src/qml/OscMessagesEosArea.qml b/src/qml/OscMessagesEosArea.qml index cc6efbe..ac646f9 100644 --- a/src/qml/OscMessagesEosArea.qml +++ b/src/qml/OscMessagesEosArea.qml @@ -48,7 +48,7 @@ Item { DarkComboBox { width: 100 height: 30 - model: ["Channel", "Group", "Macro", "Submaster", "Bump Sub", "Cue", "Fader", "Custom", "--- Inactive"] + model: ["Channel", "Channel Range", "Group", "Macro", "Submaster", "Bump Sub", "Cue", "Fader", "Custom", "--- Inactive"] onCurrentIndexChanged: updateSettingsArea() Component.onCompleted: { @@ -59,6 +59,7 @@ Item { var currentMessage = triggerController.getOnMessage() if (!currentMessage) currentMessage = triggerController.getOffMessage() if (!currentMessage) currentMessage = triggerController.getLevelMessage() + currentMessage = currentMessage.toLowerCase() // check which category fits the message: @@ -76,7 +77,15 @@ Item { currentIndex = model.indexOf("Cue") } else if (currentMessage.indexOf("/fader/") !== -1) { currentIndex = model.indexOf("Fader") - } + } + + // Do this after everything else to avoid having our message match an above message + if (!currentMessage) { + currentMessage = triggerController.getRangeMessage() + if(currentMessage) { + currentIndex = model.indexOf("Channel Range") + } + } // load correct Settings Component: updateSettingsArea() @@ -103,7 +112,9 @@ Item { settingsArea.sourceComponent = eosFaderSettings } else if (currentText === "Custom") { settingsArea.sourceComponent = eosCustomSettings - } else if (currentText === "--- Inactive") { + } else if (currentText === "Channel Range") { + settingsArea.sourceComponent = eosChannelRangeSettings + } else if (currentText === "--- Inactive") { settingsArea.sourceComponent = eosInactiveSettings } } @@ -241,6 +252,7 @@ Item { "on": level ? "" : "/eos/user//chan/" + channelNumber.value + "=" + channelOnValue.value, "off": level ? "" : "/eos/user//chan/" + channelNumber.value + "=" + channelOffValue.value, "level": level ? "/eos/user//chan/" + channelNumber.value + "=" : "", + "range": "", "levelMin": 0, "levelMax": 100, "shortText": "Channel " + channelNumber.value @@ -249,6 +261,94 @@ Item { } } } + // ------------------------------ Channel Range + + Component { + id: eosChannelRangeSettings + Column { + anchors.fill: parent + spacing: 5 + Row { + height: 30 + width: parent.width + CenterLabel { + height: parent.height + width: parent.width * 0.5 + text: "Start Channel:" + } + NumericInput { + id: startChannelNumber + height: parent.height + width: parent.width * 0.5 + value: 1 + minimumValue: 1 + maximumValue: 9999 + } + } + Row { + height: 30 + width: parent.width + CenterLabel { + height: parent.height + width: parent.width * 0.5 + text: "End Channel:" + } + NumericInput { + id: endChannelNumber + height: parent.height + width: parent.width * 0.5 + value: 1 + minimumValue: 1 + maximumValue: 9999 + } + } + Row { + height: 30 + width: parent.width + CenterLabel { + height: parent.height + width: parent.width * 0.5 + text: "Mode:" + } + DarkComboBox { + id: channelRangeMode + height: parent.height + width: parent.width * 0.5 + model: ["Level"] + } + } + + function restoreFromMessages() { + //restore values from current messages: + console.log(triggerController.getRangeMessage()) + if (triggerController.getRangeMessage() !== "") { + var messageArray = triggerController.getRangeMessage() + startChannelNumber.value = Utils.lastPartAsInt(messageArray[0], 1) + endChannelNumber.value = Utils.lastPartAsInt(messageArray[messageArray.length - 1], 1) + } + } + + + function getMessages() { + // Format: Command String, then start number, then end number. + var channelRangeMessages = [ + "/eos/user/0/newcmd/Chan/%1/Thru/%2/At/%3/Thru/%4#=", + startChannelNumber.value, + endChannelNumber.value + ] + var messages = { + "on": "", + "off": "", + "level": "", + "range": channelRangeMessages, + "levelMin": 0, + "levelMax": 100, + "shortText": "Channel Range " + } + return messages + } + } + } // ------------------------------ Group Component { id: eosGroupSettings @@ -345,6 +445,7 @@ Item { "on": level ? "" : "/eos/user//group/" + groupNumber.value + "=" + groupOnValue.value, "off": level ? "" : "/eos/user//group/" + groupNumber.value + "=" + groupOffValue.value, "level": level ? "/eos/user//group/" + groupNumber.value + "=" : "", + "range": "", "levelMin": 0, "levelMax": 100, "shortText": "Group " + groupNumber.value @@ -426,6 +527,7 @@ Item { "on": onMacroCheckbox.checked ? "/eos/user//macro/fire=" + onMacroNumber.value : "", "off": offMacroCheckbox.checked? "/eos/user//macro/fire=" + offMacroNumber.value : "", "level": "", + "range": "", "levelMin": 0, "levelMax": 1, "shortText": "Macro " + (onMacroCheckbox.checked ? onMacroNumber.value : offMacroNumber.value) @@ -531,6 +633,7 @@ Item { "on": level ? "" : "/eos/user//sub/" + submasterNumber.value + "=" + (submasterOnValue.value / 100), "off": level ? "" : "/eos/user//sub/" + submasterNumber.value + "=" + (submasterOffValue.value / 100), "level": level ? "/eos/user//sub/" + submasterNumber.value + "=" : "", + "range": "", "levelMin": 0, "levelMax": 1, "shortText": "Sub " + submasterNumber.value @@ -573,6 +676,7 @@ Item { "on": "/eos/user//sub/" + bumpSubNumber.value + "/fire=1.0", "off": "/eos/user//sub/" + bumpSubNumber.value + "/fire=0.0", "level": "", + "range": "", "levelMin": 0, "levelMax": 1, "shortText": "Bump " + bumpSubNumber.value @@ -706,6 +810,7 @@ Item { "on": onCueCheckbox.checked ? "/eos/user//cue/" + onCueList.value + "/" + onNumber + "/fire" : "", "off": offCueCheckbox.checked ? "/eos/user//cue/" + offCueList.value + "/" + offNumber + "/fire" : "", "level": "", + "range": "", "levelMin": 0, "levelMax": 1, "shortText": "Cue " + (onCueCheckbox.checked ? onCueNumber.text : offCueNumber.text) @@ -826,6 +931,7 @@ Item { "on": level ? "" : "/eos/user//fader/" + faderBank.value + "/" + faderNumber.value + "=" + (faderOnValue.value / 100), "off": level ? "" : "/eos/user//fader/" + faderBank.value + "/" + faderNumber.value + "=" + (faderOffValue.value / 100), "level": level ? "/eos/user//fader/" + faderBank.value + "/" + faderNumber.value + "=" : "", + "range": "", "levelMin": 0, "levelMax": 1, "shortText": "Fader " + faderBank.value + "/" + faderNumber.value @@ -935,6 +1041,7 @@ Item { "on": customOnMessage.text, "off": customOffMessage.text, "level": level, + "range": "", "levelMin": customLevelMinValue.value, "levelMax": customLevelMaxValue.value, "shortText": "Custom" @@ -967,6 +1074,7 @@ Item { "on": "", "off": "", "level": "", + "range": "", "levelMin": 0, "levelMax": 1, "shortText": ""