Skip to content

Commit

Permalink
Replace "BPM Detection" checkbox with "Auto BPM" and make Waveform
Browse files Browse the repository at this point in the history
checkbox independent from Auto BPM
  • Loading branch information
luminosuslight committed Jul 24, 2018
1 parent 8f82101 commit 6f87c1f
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 49 deletions.
9 changes: 5 additions & 4 deletions src/BPMDetector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,10 @@ BPMDetector::BPMDetector(const MonoAudioBuffer &buffer, BPMOscControler *osc) :
, m_lastSpectrum(NUM_BPM_FFT_SAMPLES)
, m_beatStrings()
, m_lastIntervals(INTERVALS_TO_STORE)
, m_transmitBpm(false)
, m_oscController(osc)
{
m_fft = (BasicFFTInterface*) new FFTRealWrapper<NUM_BPM_FFT_SAMPLES_EXPONENT>();
m_fft = static_cast<BasicFFTInterface*>(new FFTRealWrapper<NUM_BPM_FFT_SAMPLES_EXPONENT>());
calculateWindow();
}

Expand Down Expand Up @@ -755,7 +756,7 @@ void BPMDetector::evaluateStrings()
QLinkedList<IntervalCluster> finalIntervalClusters;
for (float& interval : m_lastIntervals) {
// Identify the cluster that most closely matches the interval (up to CLUSTER_WIDTH deviation is allowd)
IntervalCluster* closestCluster = 0;
IntervalCluster* closestCluster = nullptr;
int closestDistance = INT_MAX;
for (IntervalCluster& cluster : finalIntervalClusters) {
int distance = qAbs(cluster.getAverageInterval() - interval);
Expand All @@ -774,7 +775,7 @@ void BPMDetector::evaluateStrings()
}

// Identify the winning cluster of tempos
IntervalCluster* maxFinalCluster = 0;
IntervalCluster* maxFinalCluster = nullptr;
for (IntervalCluster& cluster : finalIntervalClusters) {
if (!maxFinalCluster || cluster.getScore() > maxFinalCluster->getScore()) {
maxFinalCluster = &cluster;
Expand All @@ -786,7 +787,7 @@ void BPMDetector::evaluateStrings()
m_lastWinningInterval = maxFinalCluster->getAverageInterval();
float newBPM = bpmInRange(msToBPM(maxFinalCluster->getAverageInterval()), m_minBPM);
m_bpm = newBPM;
m_oscController->transmitBPM(m_bpm);
if (m_transmitBpm) m_oscController->transmitBPM(m_bpm);
m_framesSinceLastBPMDetection = 0;
return;
}
Expand Down
3 changes: 3 additions & 0 deletions src/BPMDetector.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ class BPMDetector

int getMinBPM() { return m_minBPM; } // Returns the minium bpm of the range

void setTransmitBpm(bool value) { m_transmitBpm = value; }

// Helper functions to display a nice GUI
const QVector<bool>& getOnsets() { return m_onsetBuffer; }
const Qt3DCore::QCircularBuffer<float>& getWaveDisplay() { return m_spectralFluxBuffer; }
Expand Down Expand Up @@ -102,6 +104,7 @@ class BPMDetector
QLinkedList<BeatString> m_beatStrings; // the IOI Clusters identified from the intervalls
Qt3DCore::QCircularBuffer<float> m_lastIntervals; // the last bpm values stored as their interval, to achieve smoothing
float m_lastWinningInterval; // the last outputed bpm as an interval before doubling/halfing
bool m_transmitBpm; // true if the BPM should be transmitted via OSC

BPMOscControler* m_oscController; // the object respoinsible for handling osc output
};
Expand Down
10 changes: 5 additions & 5 deletions src/BPMOscControler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,11 @@ void BPMOscControler::transmitBPM(float bpm)
//Sending "03" is correctly interpreted as "3"
message.replace("<BPM>", "0" + QString::number(qRound(bpm)));
message.replace("<BPM1>", "0" + QString::number(qRound(bpm)));
message.replace("<BPM1-2>", "0" + QString::number(qRound(bpm*0.5)));
message.replace("<BPM1-4>", "0" + QString::number(qRound(bpm*0.25)));
message.replace("<BPM1-8>", "0" + QString::number(qRound(bpm*0.125)));
message.replace("<BPM1-16>", "0" + QString::number(qRound(bpm*0.0625)));
message.replace("<BPM1-32>", "0" + QString::number(qRound(bpm*0.03125)));
message.replace("<BPM1-2>", "0" + QString::number(qRound(bpm*0.5f)));
message.replace("<BPM1-4>", "0" + QString::number(qRound(bpm*0.25f)));
message.replace("<BPM1-8>", "0" + QString::number(qRound(bpm*0.125f)));
message.replace("<BPM1-16>", "0" + QString::number(qRound(bpm*0.0625f)));
message.replace("<BPM1-32>", "0" + QString::number(qRound(bpm*0.03125f)));
message.replace("<BPM2>", "0" + QString::number(qRound(bpm*2)));
message.replace("<BPM4>", "0" + QString::number(qRound(bpm*4)));
message.replace("<BPM8>", "0" + QString::number(qRound(bpm*8)));
Expand Down
2 changes: 1 addition & 1 deletion src/FFTRealWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
// LENGTH_EXPONENT is the number of samples used expressed as an exponent of two

template<int LENGTH_EXPONENT>
class FFTRealWrapper : BasicFFTInterface
class FFTRealWrapper : public BasicFFTInterface
{

public:
Expand Down
39 changes: 31 additions & 8 deletions src/MainController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ MainController::MainController(QQmlApplicationEngine* qmlEngine, QObject *parent
, m_bpmTap(&m_bpmOSC)
, m_bpmActive(false)
, m_waveformVisible(true)
, m_autoBpm(false)
{
m_audioInput = new QAudioInputWrapper(&m_buffer);

Expand Down Expand Up @@ -223,17 +224,13 @@ void MainController::initAudioInput()

void MainController::triggerBeat()
{
if (m_bpmActive) {
setBPMActive(false);
}
setAutoBpm(false);
m_bpmTap.triggerBeat();
}

void MainController::setBPM(float value)
{
if (m_bpmActive) {
setBPMActive(false);
}
setAutoBpm(false);
m_bpmTap.setBpm(value);
}

Expand Down Expand Up @@ -310,6 +307,7 @@ void MainController::setOscEnabled(bool value) {

// enable or disables bpm detection
void MainController::setBPMActive(bool value) {
if (value == m_bpmActive) return;
m_bpmActive = value;
if (m_bpmActive) {
activateBPM();
Expand All @@ -321,6 +319,19 @@ void MainController::setBPMActive(bool value) {
m_osc.sendMessage("/s2l/out/bpm/enabled", (value ? "1" : "0"), true);
}

void MainController::setAutoBpm(bool value) {
if (value == m_autoBpm) return;
m_autoBpm = value;
qDebug() << m_autoBpm;
m_bpm.setTransmitBpm(m_autoBpm);
if (m_autoBpm && !m_bpmActive) {
setBPMActive(true);
} else if (!m_autoBpm && !m_waveformVisible && m_bpmActive) {
setBPMActive(false);
}
emit autoBpmChanged();
}

// sets the minium bpm of the range
void MainController::setMinBPM(int value) {
m_bpm.setMinBPM(value);
Expand All @@ -329,10 +340,20 @@ void MainController::setMinBPM(int value) {
m_osc.sendMessage("/s2l/out/bpm/range", QString::number(value), true);
}

void MainController::setWaveformVisible(bool value) {
m_waveformVisible = value;
if (m_waveformVisible && !m_bpmActive) {
setBPMActive(true);
} else if (!m_autoBpm && !m_waveformVisible && m_bpmActive) {
setBPMActive(false);
}
emit waveformVisibleChanged();
}

void MainController::onExit()
{
savePresetIndependentSettings();
autosave();
savePresetIndependentSettings();
autosave();
}

void MainController::onVisibilityChanged()
Expand Down Expand Up @@ -464,6 +485,7 @@ void MainController::loadPreset(const QString &constFileName, bool createIfNotEx
setConsoleType(settings.value("consoleType").toString());
setLowSoloMode(settings.value("lowSoloMode").toBool());
setBPMActive(settings.value("bpm/Active", false).toBool());
setAutoBpm(settings.value("autoBpm", false).toBool());
setWaveformVisible(settings.value("waveformVisible", true).toBool());

// restore the settings in all TriggerGenerators:
Expand Down Expand Up @@ -550,6 +572,7 @@ void MainController::savePresetAs(const QString &constFileName, bool isAutosave)
settings.setValue("consoleType", getConsoleType());
settings.setValue("lowSoloMode", getLowSoloMode());
settings.setValue("bpm/Active", getBPMActive());
settings.setValue("autoBpm", getAutoBpm());
settings.setValue("waveformVisible", m_waveformVisible); // store property because getter is for GUI, and only returns true if bpm is active

// save the settings in all TriggerGenerators:
Expand Down
17 changes: 13 additions & 4 deletions src/MainController.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ class MainController : public QObject
// this property is used for the lowSoloMode checkbox:
Q_PROPERTY(bool lowSoloMode READ getLowSoloMode WRITE setLowSoloMode NOTIFY lowSoloModeChanged)

Q_PROPERTY(bool autoBpm READ getAutoBpm WRITE setAutoBpm NOTIFY autoBpmChanged)
Q_PROPERTY(bool waveformVisible READ getWaveformVisible WRITE setWaveformVisible NOTIFY waveformVisibleChanged)

public:
explicit MainController(QQmlApplicationEngine* m_qmlEngine, QObject* parent = nullptr);
~MainController();
Expand Down Expand Up @@ -124,6 +127,8 @@ class MainController : public QObject
// emitted if the bpm activation changed
void bpmActiveChanged();

void autoBpmChanged();

// emitted if the bpm range changed
void bpmRangeChanged();

Expand Down Expand Up @@ -235,13 +240,16 @@ public slots:

// returns if the bpm detection is currently active
bool getBPMActive() { return m_bpmActive; }
bool getBPMManual() { return m_bpmTap.hasBpm() && !m_bpmActive; }
bool getBPMManual() { return m_bpmTap.hasBpm() && !m_autoBpm; }
// enable or disables bpm detection
void setBPMActive(bool value);

bool getAutoBpm() const { return m_autoBpm; }
void setAutoBpm(bool value);

// forward calls to BPMDetector
// returns the current bpm
float getBPM() { return getBPMManual() || m_bpm.getBPM() == 0.0 ? m_bpmTap.getBpm() : m_bpm.getBPM(); }
float getBPM() { return getBPMManual() || m_bpm.getBPM() == 0.0f ? m_bpmTap.getBpm() : m_bpm.getBPM(); }
// returns if the detected bpm is old and should be marked as such in the gui
bool bpmIsOld() { return m_bpm.bpmIsOld(); }
// sets the minium bpm of the range
Expand All @@ -254,8 +262,8 @@ public slots:
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();}
bool getWaveformVisible() { return m_waveformVisible; }
void setWaveformVisible(bool value);

// returns the last seconds of waveform as a list of qreal values in the range 0...1
// as well as the marks where a peak was detected as a boolean value and colors that represent the spectrum
Expand Down Expand Up @@ -389,6 +397,7 @@ private slots:
bool m_bpmActive; // true if the bpm detection is active
QTimer m_bpmUpdatetimer; // Timer to trigger bpm update
bool m_waveformVisible; // true if the waveform is visible
bool m_autoBpm; // true if BPM should be set automatically

TriggerGenerator* m_bass; // pointer to Bass TriggerGenerator instance
TriggerGenerator* m_loMid; // pointer to LoMid TriggerGenerator instance
Expand Down
29 changes: 13 additions & 16 deletions src/qml/BPMSettings.qml
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,18 @@ Item {
DarkCheckBox {
id: bpmActiveCheckbox
height: parent.height
checked: controller.getBPMActive()
onClicked: controller.setBPMActive(checked)
text: "BPM Detection"
onCheckedChanged: {
if (controller.autoBpm !== checked) {
controller.autoBpm = checked
}
}
text: "Auto BPM"

Component.onCompleted: checked = controller.autoBpm

Connections {
target: controller
onBpmActiveChanged: {
bpmActiveCheckbox.checked = controller.getBPMActive()
}
onAutoBpmChanged: bpmActiveCheckbox.checked = controller.autoBpm
}
}

Expand Down Expand Up @@ -172,16 +176,9 @@ Item {
width: parent.width - 2*x
height: 30
x: 10
enabled: bpmActiveCheckbox.checked
checked: controller.getWaveformVisible()
onClicked: controller.setWaveformVisible(checked)
checked: controller.waveformVisible
onClicked: controller.waveformVisible = checked
text: "Waveform"
Connections {
target: controller
onWaveformVisibleChanged: {
waveformVisibleCheckbox.checked = controller.getWaveformVisible()
}
}
}

// ------------------------------ Range Picker ---------------------------
Expand Down Expand Up @@ -218,7 +215,7 @@ Item {

function updateFromController() {
var minBpm = controller.getMinBPM();
if (minBpm == 0) {
if (minBpm === 0) {
rangeComboBox.currentIndex = 0
} else if (minBpm < 75) {
rangeComboBox.currentIndex = 1
Expand Down
11 changes: 1 addition & 10 deletions src/qml/SpectrumWithControls.qml
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,7 @@ Row {
Column {
id: wavePlot
width: parent.width
height: {
return controller.getWaveformVisible() ? 80 : 0
}
height: controller.waveformVisible ? 80 : 0


// -------------------------------- Wave Plot --------------------------------
Expand All @@ -65,13 +63,6 @@ Row {
height: 5
color: "#333333"
}

Connections {
target: controller
onWaveformVisibleChanged: {
wavePlot.height = controller.getWaveformVisible() ? 80 : 0
}
}
}


Expand Down
2 changes: 1 addition & 1 deletion src/qml/main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ ApplicationWindow {
text: "Enable BPM Detection"
shortcut: "Escape"
onTriggered: {
controller.setBPMActive(true)
controller.setBPMActive(!controller.getBPMActive())
}
}

Expand Down

0 comments on commit 6f87c1f

Please sign in to comment.