Skip to content

Commit

Permalink
Merge pull request #36 from TheSlowGrowth/feat/cv-calibration
Browse files Browse the repository at this point in the history
Feat/CV input calibration
  • Loading branch information
TheSlowGrowth authored Aug 16, 2024
2 parents 1ea048d + 9d3aa44 commit 69b71d2
Show file tree
Hide file tree
Showing 10 changed files with 425 additions and 55 deletions.
8 changes: 4 additions & 4 deletions dsp/src/dsp/Recorder.h
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
/**
/**
* Copyright (C) Johannes Elliesen, 2021
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
Expand Down
8 changes: 4 additions & 4 deletions dsp/tests/Recorder_gtest.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
/**
/**
* Copyright (C) Johannes Elliesen, 2021
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
Expand Down
8 changes: 4 additions & 4 deletions firmware/src/LooperController.h
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
/**
/**
* Copyright (C) Johannes Elliesen, 2021
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
Expand Down
102 changes: 74 additions & 28 deletions firmware/src/hardware/UiHardware.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,15 @@ class ButtonReader
class KnobAndCvReader
{
public:
KnobAndCvReader(daisy::QSPIHandle& qspi) :
calibrationStorage_(qspi)
{
}

void init()
{
calibrationStorage_.Init(getDefaultCalibrationData(), kCalibrationDataOffset);

const dsy_gpio_pin mux0 = { DSY_GPIOA, 1 };
const dsy_gpio_pin mux1 = { DSY_GPIOA, 0 };
const dsy_gpio_pin mux2 = { DSY_GPIOD, 11 };
Expand Down Expand Up @@ -224,7 +231,55 @@ class KnobAndCvReader
return 0.0f;
}

float getCvRaw(CvInput cv) const
{
switch (cv)
{
case CvInput::chA_speed:
return adc_.GetMuxFloat(0, 5);
case CvInput::chA_volume:
return adc_.GetMuxFloat(0, 6);
case CvInput::chB_speed:
return adc_.GetMuxFloat(1, 5);
case CvInput::chB_volume:
return adc_.GetMuxFloat(1, 6);
case CvInput::chC_speed:
return adc_.GetMuxFloat(2, 5);
case CvInput::chC_volume:
return adc_.GetMuxFloat(2, 6);
case CvInput::chD_speed:
return adc_.GetMuxFloat(3, 5);
case CvInput::chD_volume:
return adc_.GetMuxFloat(3, 6);
case CvInput::NUM_CVS:
break;
}
return 0.0f;
}

float getCvVolts(CvInput cv) const
{
const auto& coeffs = calibrationStorage_.GetSettings();
return getCvRaw(cv) * coeffs[int(cv)].scale
+ coeffs[int(cv)].offset;
}

struct CvInCoefficients
{
bool operator==(const CvInCoefficients& other) const
{
return scale == other.scale && offset == other.offset;
}
float scale;
float offset;
};
using CalibrationData = std::array<CvInCoefficients, int(CvInput::NUM_CVS)>;

CalibrationData& getCalibrationData() { return calibrationStorage_.GetSettings(); }
void saveCalibrationData() { calibrationStorage_.Save(); }

private:
static constexpr CalibrationData getDefaultCalibrationData()
{
/**
The general formula for the CV inputs is
Expand Down Expand Up @@ -262,31 +317,23 @@ class KnobAndCvReader
constexpr auto kScaleVolume = -4.852941f;
constexpr auto kOffsetVolume = 5.0f;

switch (cv)
constexpr CalibrationData defaults = []() constexpr
{
case CvInput::chA_speed:
return adc_.GetMuxFloat(0, 5) * kScaleSpeed + kOffsetSpeed;
case CvInput::chA_volume:
return adc_.GetMuxFloat(0, 6) * kScaleVolume + kOffsetVolume;
case CvInput::chB_speed:
return adc_.GetMuxFloat(1, 5) * kScaleSpeed + kOffsetSpeed;
case CvInput::chB_volume:
return adc_.GetMuxFloat(1, 6) * kScaleVolume + kOffsetVolume;
case CvInput::chC_speed:
return adc_.GetMuxFloat(2, 5) * kScaleSpeed + kOffsetSpeed;
case CvInput::chC_volume:
return adc_.GetMuxFloat(2, 6) * kScaleVolume + kOffsetVolume;
case CvInput::chD_speed:
return adc_.GetMuxFloat(3, 5) * kScaleSpeed + kOffsetSpeed;
case CvInput::chD_volume:
return adc_.GetMuxFloat(3, 6) * kScaleVolume + kOffsetVolume;
case CvInput::NUM_CVS:
break;
}
return 0.0f;
CalibrationData result = { { 0.0f, 0.0f } };
for (size_t i = 0; i < result.size(); i++)
{
const auto isSpeedCv = i % 2 == 0;
result[i] = isSpeedCv ? CvInCoefficients { kScaleSpeed, kOffsetSpeed } : CvInCoefficients { kScaleVolume, kOffsetVolume };
}
return result;
}();

return defaults;
}
static constexpr auto kCalibrationDataOffset = 0;

mutable daisy::PersistentStorage<CalibrationData> calibrationStorage_;

private:
daisy::AdcHandle adc_;
};

Expand All @@ -296,10 +343,12 @@ class UiHardware
using LedDriverType = daisy::LedDriverPca9685<3, false>;
using LedDmaBufferType = LedDriverType::DmaBuffer;

UiHardware(daisy::UiEventQueue& eventQueue,
UiHardware(daisy::QSPIHandle& qspi,
daisy::UiEventQueue& eventQueue,
LedDmaBufferType bufferA,
LedDmaBufferType bufferB,
uint16_t* shiftRegisterDmaBuffer)
uint16_t* shiftRegisterDmaBuffer) :
knobsAndCv_(qspi)
{
potMonitor_.Init(eventQueue, *this);
buttonMonitor_.Init(eventQueue,
Expand Down Expand Up @@ -340,10 +389,7 @@ class UiHardware
ledDriver_.SwapBuffersAndTransmit();
}

float getCvVolts(CvInput cv) const
{
return knobsAndCv_.getCvVolts(cv);
}
KnobAndCvReader& getKnobsAndCv() { return knobsAndCv_; }

// ===================================================================
// implements the button reader interface for the libDaisy UI system
Expand Down
21 changes: 20 additions & 1 deletion firmware/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ void flushLedDisplay(const daisy::UiCanvasDescriptor&)
void initUi()
{
// init the UI hardware
auto& hardware = *uiHardware.create(uiEventQueue,
auto& hardware = *uiHardware.create(seed.qspi,
uiEventQueue,
ledDmaBufferA,
ledDmaBufferB,
&buttonShiftRegisterDmaBuffer);
Expand Down Expand Up @@ -147,6 +148,24 @@ void audioCallback(const float* const* in, float** out, size_t size)
{
cpuLoadMeter.OnBlockStart();

// update CV values
looperParameterProvider->controlInputs_[0].pitchCvVolts =
uiHardware->getKnobsAndCv().getCvVolts(CvInput::chA_speed);
looperParameterProvider->controlInputs_[1].pitchCvVolts =
uiHardware->getKnobsAndCv().getCvVolts(CvInput::chB_speed);
looperParameterProvider->controlInputs_[2].pitchCvVolts =
uiHardware->getKnobsAndCv().getCvVolts(CvInput::chC_speed);
looperParameterProvider->controlInputs_[3].pitchCvVolts =
uiHardware->getKnobsAndCv().getCvVolts(CvInput::chD_speed);
looperParameterProvider->controlInputs_[0].volumeCvVolts =
uiHardware->getKnobsAndCv().getCvVolts(CvInput::chA_volume);
looperParameterProvider->controlInputs_[1].volumeCvVolts =
uiHardware->getKnobsAndCv().getCvVolts(CvInput::chB_volume);
looperParameterProvider->controlInputs_[2].volumeCvVolts =
uiHardware->getKnobsAndCv().getCvVolts(CvInput::chC_volume);
looperParameterProvider->controlInputs_[3].volumeCvVolts =
uiHardware->getKnobsAndCv().getCvVolts(CvInput::chD_volume);

// peak meters
peakMeters[0].readPeaks(in[0]);
peakMeters[1].readPeaks(in[1]);
Expand Down
12 changes: 6 additions & 6 deletions firmware/src/ui/LooperParameterProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ class LooperParameterProvider
/** Called by the LooperController */
float getGainParameter(size_t looperChannel) const
{
return volumeSliderToGainMultiplier(controlInputs_[looperChannel].volumeSliderPosition)
* volumeCvToGainMultiplier(controlInputs_[looperChannel].volumeCvVolts);
return std::clamp(volumeSliderToGainMultiplier(controlInputs_[looperChannel].volumeSliderPosition)
* volumeCvToGainMultiplier(controlInputs_[looperChannel].volumeCvVolts),
0.0f,
1.0f);
}
/** Called by the LooperController */
TapeProcessorParameters getProcessorParameters(size_t looperChannel) const
Expand Down Expand Up @@ -118,8 +120,7 @@ class LooperParameterProvider

float pitchCvToSemitones(float cvVolts) const
{
(void) (cvVolts);
return 0.0f; // TODO
return cvVolts * 12.0f;
}

float volumeSliderToGainMultiplier(float sliderValue) const
Expand All @@ -130,8 +131,7 @@ class LooperParameterProvider

float volumeCvToGainMultiplier(float cvVolts) const
{
(void) (cvVolts);
return 1.0f; // TODO
return cvVolts / 5.0f;
}

float getUnclampedSpeedParameter(size_t looperChannel) const
Expand Down
7 changes: 6 additions & 1 deletion firmware/src/ui/TapeLooperUi.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include "LooperParameterProvider.h"
#include "UiBasePage.h"
#include "UiCalibrationPage.h"
#include "UiSettingsPage.h"
#include "UiSavePage.h"
#include "UiLoadPage.h"
Expand All @@ -45,8 +46,10 @@ class TapeLooperUi
ParameterProviderType& looperParameterProvider) :
uiHardware_(uiHardware),
eventQueue_(eventQueue),
calibrationPage_(uiHardware),
settingsPage_(looperController,
looperParameterProvider),
looperParameterProvider,
calibrationPage_),
savePage_(looperController),
loadPage_(looperController),
recordingPage_(looperController),
Expand Down Expand Up @@ -83,6 +86,8 @@ class TapeLooperUi
UiHardwareType& uiHardware_;
daisy::UiEventQueue& eventQueue_;
daisy::UI ui_;
UiCalibrationPage<UiHardwareType>
calibrationPage_;
UiSettingsPage<LooperControllerType,
UiHardwareType,
ParameterProviderType>
Expand Down
Loading

0 comments on commit 69b71d2

Please sign in to comment.