Skip to content

Commit

Permalink
Added source of v0.0.2.1.0.9
Browse files Browse the repository at this point in the history
  • Loading branch information
HendrikNoeller committed Mar 1, 2017
1 parent d7a2240 commit f8b60f8
Show file tree
Hide file tree
Showing 25 changed files with 253 additions and 33 deletions.
Binary file modified doc/Sound2Light_Tool_Anleitung.pdf
Binary file not shown.
Binary file modified doc/Sound2Light_Tool_Manual_en.pdf
Binary file not shown.
4 changes: 4 additions & 0 deletions doc/s2l_changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@

# Sound2Light Change Log

### Version 0.0.2.1.0.9 - 1 Mar 2017

- Supports Muting the OSC output of individual channels

### Version 0.0.2.1.0.8 - 1 Mar 2017

- Fixed BPM OSC Messages with a one digit value being interpreted falsely on EOS
Expand Down
Binary file modified doc/screenshot_main_window.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 18 additions & 1 deletion src/BPMOscControler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,25 @@
#include "BPMOscControler.h"

BPMOscControler::BPMOscControler(OSCNetworkManager &osc) :
m_osc(osc)
m_bpmMute(false)
, m_osc(osc)
, m_oscCommands()
{
}

void BPMOscControler::setBPMMute(bool mute)
{
m_bpmMute = mute;

m_osc.sendMessage("/s2l/out/bpm/mute", (m_bpmMute ? "1" : "0"), true);
}

void BPMOscControler::toggleBPMMute()
{
m_bpmMute = !m_bpmMute;
m_osc.sendMessage("/s2l/out/bpm/mute", (m_bpmMute ? "1" : "0"), true);
}

// Restore the commands from e.g. a preset or whatever else
void BPMOscControler::restore(QSettings& settings)
{
Expand Down Expand Up @@ -55,6 +69,9 @@ inline int round(float value) { return (fmod(value,1.0) < 0.5) ? value : value +
// Called by the bpm detector to make the controller send the new bpm to the clients
void BPMOscControler::transmitBPM(float bpm)
{
// Don't transmit if mute is engaged
if (m_bpmMute) return;

// Send user specified commands

for (QString& command : m_oscCommands) {
Expand Down
6 changes: 6 additions & 0 deletions src/BPMOscControler.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ class BPMOscControler
public:
BPMOscControler(OSCNetworkManager& osc);

// Getter/Setter for mute
bool getBPMMute() { return m_bpmMute; }
void setBPMMute(bool mute);
void toggleBPMMute();

// Called by the bpm detector to make the controller send the new bpm to the clients
void transmitBPM(float bpm);

Expand All @@ -49,6 +54,7 @@ class BPMOscControler


protected:
bool m_bpmMute; // If the bpm osc is muted
OSCNetworkManager& m_osc; // The network manager to send network signals thorugh
QStringList m_oscCommands; // The osc messages to be sent on a tempo changed. Delivered as finished strings with the <BPM> (<BPM1-2>, <BPM4> etc. for fractions from 1/4 to 4) qualifier to be changed. The message is generated in the qml because thats the way tim did it with the other osc messages
};
Expand Down
19 changes: 19 additions & 0 deletions src/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) 2016 Electronic Theatre Controls, Inc., http://www.etcconnect.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
15 changes: 14 additions & 1 deletion src/MainController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,8 @@ void MainController::loadPreset(const QString &constFileName, bool createIfNotEx
// Restore the manual BPM
m_bpmTap.setBpm(settings.value("bpm/tapvalue", 60).toInt());

m_bpmOSC.setBPMMute(settings.value("bpm/mute", false).toBool());


// this is now the loaded preset, update the preset name:
m_currentPresetFilename = fileName; emit presetNameChanged();
Expand All @@ -491,6 +493,7 @@ void MainController::loadPreset(const QString &constFileName, bool createIfNotEx
emit bpmActiveChanged();
emit bpmRangeChanged();
emit waveformVisibleChanged();
emit bpmMuteChanged();

emit m_bassController->parameterChanged();
emit m_loMidController->parameterChanged();
Expand All @@ -505,6 +508,13 @@ void MainController::loadPreset(const QString &constFileName, bool createIfNotEx
emit m_highController->oscLabelTextChanged();
emit m_envelopeController->oscLabelTextChanged();
emit m_silenceController->oscLabelTextChanged();

emit m_bassController->muteChanged();
emit m_loMidController->muteChanged();
emit m_hiMidController->muteChanged();
emit m_highController->muteChanged();
emit m_envelopeController->muteChanged();
emit m_silenceController->muteChanged();
}

void MainController::savePresetAs(const QString &constFileName, bool isAutosave)
Expand Down Expand Up @@ -547,9 +557,12 @@ void MainController::savePresetAs(const QString &constFileName, bool isAutosave)
// save the settings in the BPMOscController
m_bpmOSC.save(settings);

// Restore the manual BPM
// save the manual BPM
settings.setValue("bpm/tapvalue", m_bpmTap.getBpm());

// save bpm mute
settings.setValue("bpm/mute", m_bpmOSC.getBPMMute());

if (!isAutosave) {
// this is now the loaded preset, update the preset name:
m_currentPresetFilename = fileName; emit presetNameChanged();
Expand Down
7 changes: 7 additions & 0 deletions src/MainController.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ class MainController : public QObject
// emitted if the waveform visiblity changed
void waveformVisibleChanged();

// emitted if the bpm mute changed
void bpmMuteChanged();

// forwarded from OSCNetworkManager:
void messageReceived(OSCMessage msg);
void packetSent();
Expand Down Expand Up @@ -246,6 +249,10 @@ public slots:
// gets the minium bpm of the range
int getMinBPM() { return m_bpm.getMinBPM(); }

// set/get bpm mute
bool getBPMMute() { return m_bpmOSC.getBPMMute(); }
void toggleBPMMute() { m_bpmOSC.toggleBPMMute(); emit bpmMuteChanged(); }

// set/get the waveform visibility
bool getWaveformVisible() { return m_waveformVisible & m_bpmActive; }
void setWaveformVisible(bool value) { m_waveformVisible = value; emit waveformVisibleChanged();}
Expand Down
14 changes: 14 additions & 0 deletions src/OSCMapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,20 @@ void OSCMapping::handleMessage(OSCMessage msg)
if (msg.arguments().size() == 0 || msg.arguments().at(0).toBool()) {
m_controller->triggerBeat();
}
} else if (msg.pathStartsWith("/s2l/bpm/mute")) {
m_controller->toggleBPMMute();
} else if (msg.pathStartsWith("/s2l/bass/mute")) {
m_controller->m_bassController->toggleMute();
} else if (msg.pathStartsWith("/s2l/lo_mid/mute")) {
m_controller->m_loMidController->toggleMute();
} else if (msg.pathStartsWith("/s2l/hi_mid/mute")) {
m_controller->m_hiMidController->toggleMute();
} else if (msg.pathStartsWith("/s2l/high/mute")) {
m_controller->m_highController->toggleMute();
} else if (msg.pathStartsWith("/s2l/level/mute")) {
m_controller->m_envelopeController->toggleMute();
} else if (msg.pathStartsWith("/s2l/silence/mute")) {
m_controller->m_silenceController->toggleMute();
}
}

Expand Down
19 changes: 19 additions & 0 deletions src/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Sound2Light Tool

The Sound2Light tool converts live audio signals to trigger events that can be sent as OSC messages. It can reproduce the sound-to-light function of the NT/NTX consoles with systems of the Eos-, Cobalt- and ColorSource-family. It can also be remotely controlled by OSC.

## About this ETCLabs Project
The Sound2Light Tool is open-source software designed to interact with Electronic Theatre Controls products. This is not official ETC software.
ETC Support is not familiar with this software and will not be able to assist if issues arise.

We also welcome pull requests for bug fixes and feature additions.

# Download

The current release for Windows and Mac is available here: [Download](https://github.com/ElectronicTheatreControlsLabs/Sound2Light/releases)

The manual can be found here: [Manual](https://github.com/ElectronicTheatreControlsLabs/Sound2Light/blob/master/doc/Sound2Light_Tool_Manual_en.pdf)

# Screenshot

![screenshot](https://github.com/ElectronicTheatreControlsLabs/Sound2Light/blob/master/doc/screenshot_main_window.png)
7 changes: 4 additions & 3 deletions src/TriggerFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
#include <QDebug>
#include <QTimer>

TriggerFilter::TriggerFilter(OSCNetworkManager* osc, TriggerOscParameters& oscParameters)
TriggerFilter::TriggerFilter(OSCNetworkManager* osc, TriggerOscParameters& oscParameters, bool mute)
: QObject(0)
, m_mute(mute)
, m_onDelay(0.0)
, m_offDelay(0.0)
, m_maxHold(0.0)
Expand Down Expand Up @@ -75,14 +76,14 @@ void TriggerFilter::triggerOff()
void TriggerFilter::sendOnSignal()
{
QString message = m_oscParameters.getOnMessage();
if (!message.isEmpty()) m_osc->sendMessage(message);
if (!message.isEmpty() && !m_mute) m_osc->sendMessage(message);
emit onSignalSent();
}

void TriggerFilter::sendOffSignal()
{
QString message = m_oscParameters.getOffMessage();
if (!message.isEmpty()) m_osc->sendMessage(message);
if (!message.isEmpty() && !m_mute) m_osc->sendMessage(message);
emit offSignalSent();
}

Expand Down
5 changes: 4 additions & 1 deletion src/TriggerFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ class TriggerFilter : public QObject
Q_OBJECT

public:
explicit TriggerFilter(OSCNetworkManager* osc, TriggerOscParameters& oscParameters);
explicit TriggerFilter(OSCNetworkManager* osc, TriggerOscParameters& oscParameters, bool mute);

void setMute(bool mute) { m_mute = mute; }

// returns the on delay time in seconds
qreal getOnDelay() const { return m_onDelay; }
Expand Down Expand Up @@ -105,6 +107,7 @@ public slots:
void onMaxHoldEnd();

protected:
bool m_mute; // Wether the associated band is muted
qreal m_onDelay; // On delay in seconds
qreal m_offDelay; // Off delay in seconds
qreal m_maxHold; // max hold time (decay) in seconds
Expand Down
52 changes: 36 additions & 16 deletions src/TriggerGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,34 @@ TriggerGenerator::TriggerGenerator(QString name, OSCNetworkManager* osc, bool is
, m_name(name)
, m_osc(osc)
, m_invert(invert)
, m_mute(false)
, m_midFreq(midFreq)
, m_defaultMidFreq(midFreq)
, m_width(0.1)
, m_threshold(0.5)
, m_isActive(false)
, m_oscParameters()
, m_filter(osc, m_oscParameters)
, m_filter(osc, m_oscParameters, m_mute)
{
resetParameters();
}

// toggles mute on and off
void TriggerGenerator::toggleMute()
{
m_mute = !m_mute;
m_filter.setMute(m_mute);
m_osc->sendMessage("/s2l/out/" + m_name + "/mute", (m_mute ? "1" : "0"), true);
}

// toggles mute on and off
void TriggerGenerator::setMute(bool mute)
{
m_mute = mute;
m_filter.setMute(m_mute);
m_osc->sendMessage("/s2l/out/" + m_name + "/mute", (m_mute ? "1" : "0"), true);
}

bool TriggerGenerator::checkForTrigger(ScaledSpectrum &spectrum, bool forceRelease)
{
qreal value;
Expand All @@ -51,7 +68,7 @@ bool TriggerGenerator::checkForTrigger(ScaledSpectrum &spectrum, bool forceRelea
}
if (m_invert) value = 1 - value;

// check for trigger:
// check for trigger:
if ((!m_isActive && value >= m_threshold) && !forceRelease) {
// activate trigger:
m_isActive = true;
Expand All @@ -60,27 +77,28 @@ bool TriggerGenerator::checkForTrigger(ScaledSpectrum &spectrum, bool forceRelea
// release trigger:
m_isActive = false;
m_filter.triggerOff();
}
}

// send level if levelMessage is set:
// send level if levelMessage is set and band is not muted:
// 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();
qreal maxValue = m_oscParameters.getMaxLevelValue();
qreal scaledValue = minValue + valueUnderThreshold * (maxValue - minValue);
QString oscMessage = m_oscParameters.getLevelMessage() + QString::number(scaledValue, 'f', 3);
m_osc->sendMessage(oscMessage);
}
qreal diff = qAbs(m_lastValue - value);
if (diff > 0.001 && !m_oscParameters.getLevelMessage().isEmpty() && m_threshold > 0 && !m_mute) {
qreal valueUnderThreshold = limit(0, (value / m_threshold), 1);
qreal minValue = m_oscParameters.getMinLevelValue();
qreal maxValue = m_oscParameters.getMaxLevelValue();
qreal scaledValue = minValue + valueUnderThreshold * (maxValue - minValue);
QString oscMessage = m_oscParameters.getLevelMessage() + QString::number(scaledValue, 'f', 3);
m_osc->sendMessage(oscMessage);
}

m_lastValue = value;
return m_isActive;
}

void TriggerGenerator::save(QSettings& settings) const
{
settings.setValue(m_name + "/threshold", m_threshold);
settings.setValue(m_name + "/mute", m_mute);
settings.setValue(m_name + "/threshold", m_threshold);
settings.setValue(m_name + "/midFreq", m_midFreq);
settings.setValue(m_name + "/width", m_width);
m_filter.save(m_name, settings);
Expand All @@ -89,17 +107,19 @@ void TriggerGenerator::save(QSettings& settings) const

void TriggerGenerator::restore(QSettings& settings)
{
m_mute = settings.value(m_name + "/mute", false).toBool();
setThreshold(settings.value(m_name + "/threshold").toReal());
setMidFreq(settings.value(m_name + "/midFreq").toReal());
setWidth(settings.value(m_name + "/width").toReal());
m_filter.restore(m_name, settings);
m_oscParameters.restore(m_name, settings);
m_oscParameters.restore(m_name, settings);
}

void TriggerGenerator::resetParameters()
{
setMidFreq(m_defaultMidFreq);
setMidFreq(m_defaultMidFreq);
setWidth(0.1);
m_mute = false;
if (m_isBandpass) {
setThreshold(0.5);
// default Bandpass settings:
Expand Down
13 changes: 12 additions & 1 deletion src/TriggerGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ class TriggerGenerator : public TriggerGeneratorInterface

// ---------------- Parameters -------------

// returns wether the frequency band is muted
bool getMute() const { return m_mute; }

// toggles mute on and off
void toggleMute();

// toggles mute on and off
void setMute(bool mute);


// returns the middle frequency of the frequency band [20...22050]
int getMidFreq() const { return m_midFreq; }

Expand Down Expand Up @@ -97,9 +107,10 @@ class TriggerGenerator : public TriggerGeneratorInterface
void resetParameters();

protected:
const QString m_name; // name of the Trigger (used for save, restore and UI)
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)
const bool m_invert; // true if signal values should be inverted (i.e. for "silence" trigger)
bool m_mute; // true if the band is muted, which will supress OSC Output
int m_midFreq; // middle frequency of bandpass in Hz
const int m_defaultMidFreq; // default midFreq in Hz, used for reset
qreal m_width; // width of bandpass [0...1]
Expand Down
6 changes: 6 additions & 0 deletions src/TriggerGuiController.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,18 @@ class TriggerGuiController : public QObject
void oscLabelTextChanged();
// emitted when a value of the preset changed
void presetChanged();
// emmited when mute changes
void muteChanged();

public slots:

// forward calls to TriggerGenerator
// see TriggerGenerator.h for documentation

bool getMute() const { return m_trigger->getMute(); }
void toggleMute() { m_trigger->toggleMute(); emit muteChanged(); }
void setMute(bool mute) { m_trigger->setMute(mute); emit muteChanged(); }

int getMidFreq() const { return m_trigger->getMidFreq(); }
void setMidFreq(const int& value) { m_trigger->setMidFreq(value); emit parameterChanged(); emit presetChanged(); }

Expand Down
Loading

0 comments on commit f8b60f8

Please sign in to comment.