Feature/update physical controls (#4)

* Added intepolated delay capability to AudioDelay class

* renamed testing verision of AudioEffectAnalogDelay.cpp

* Updates to the internal functions in BAPhyscontrols for better switch/pot support
pull/5/head
Blackaddr Audio 6 years ago committed by GitHub
parent 7365d5a6a2
commit 83edcf4b0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 49
      src/BAPhysicalControls.h
  2. 132
      src/peripherals/BAPhysicalControls.cpp

@ -58,9 +58,11 @@ class DigitalInput : public Bounce {
public: public:
/// Create an input where digital low is return true. Most switches ground when pressed. /// Create an input where digital low is return true. Most switches ground when pressed.
DigitalInput() : m_isPolarityInverted(true) {} DigitalInput() : m_isPolarityInverted(true) {}
/// Create an input and specify if input polarity is inverted. /// Create an input and specify if input polarity is inverted.
/// @param isPolarityInverted when false, a high voltage on the pin returns true, 0V returns false. /// @param isPolarityInverted when false, a high voltage on the pin returns true, 0V returns false.
DigitalInput(bool isPolarityInverted) : m_isPolarityInverted(isPolarityInverted) {} DigitalInput(bool isPolarityInverted) : m_isPolarityInverted(isPolarityInverted) {}
/// Read the state of the pin according to the polarity /// Read the state of the pin according to the polarity
/// @returns true when the input should be interpreted as the switch is closed, else false. /// @returns true when the input should be interpreted as the switch is closed, else false.
bool read() { return Bounce::read() != m_isPolarityInverted; } // logical XOR to conditionally invert polarity bool read() { return Bounce::read() != m_isPolarityInverted; } // logical XOR to conditionally invert polarity
@ -69,8 +71,26 @@ public:
/// @param polarity when true, a low voltage on the pin is considered true by read(), else false. /// @param polarity when true, a low voltage on the pin is considered true by read(), else false.
void setPolarityInverted(bool polarity) { m_isPolarityInverted = polarity; } void setPolarityInverted(bool polarity) { m_isPolarityInverted = polarity; }
/// Check if input has toggled from low to high to low by looking for falling edges
/// @returns true if the switch has toggled
bool hasInputToggled();
/// Check if the input is asserted
/// @returns true if the switch is held
bool isInputAssert();
/// Get the raw input value (ignores polarity inversion)
/// @returns returns true is physical pin is high, else false
bool getPinInputValue();
/// Store the current switch state and return true if it has changed.
/// @param switchState variable to store switch state in
/// @returns true when switch stage has changed since last check
bool hasInputChanged(bool &switchState);
private: private:
bool m_isPolarityInverted; bool m_isPolarityInverted;
bool m_isPushed;
}; };
/// Convenience class for handling an analog pot as a control. When calibrated, /// Convenience class for handling an analog pot as a control. When calibrated,
@ -93,8 +113,7 @@ public:
/// @param minCalibration See Potentiometer::calibrate() /// @param minCalibration See Potentiometer::calibrate()
/// @param maxCalibration See Potentiometer::calibrate() /// @param maxCalibration See Potentiometer::calibrate()
/// @param swapDirection Optional param. See Potentiometer::calibrate() /// @param swapDirection Optional param. See Potentiometer::calibrate()
Potentiometer(uint8_t analogPin, unsigned minCalibration, unsigned maxCalibration, bool swapDirection = false) Potentiometer(uint8_t analogPin, unsigned minCalibration, unsigned maxCalibration, bool swapDirection = false);
: m_pin(analogPin), m_swapDirection(swapDirection), m_minCalibration(minCalibration), m_maxCalibration(maxCalibration) {}
/// Get new value from the pot. /// Get new value from the pot.
/// @param value reference to a float, the new value will be written here. Value is between 0.0 and 1.0f. /// @param value reference to a float, the new value will be written here. Value is between 0.0 and 1.0f.
@ -117,6 +136,8 @@ public:
/// @param filterValue typical values are 0.80f to 0.95f /// @param filterValue typical values are 0.80f to 0.95f
void setFeedbackFitlerValue(float fitlerValue); void setFeedbackFitlerValue(float fitlerValue);
void setCalibrationValues(unsigned min, unsigned max, bool swapDirection);
/// Call this static function before creating the object to obtain calibration data. The sequence /// Call this static function before creating the object to obtain calibration data. The sequence
/// involves prompts over the Serial port. /// involves prompts over the Serial port.
/// @details E.g. call Potentiometer::calibrate(PIN). See BAExpansionCalibrate.ino in the library examples. /// @details E.g. call Potentiometer::calibrate(PIN). See BAExpansionCalibrate.ino in the library examples.
@ -131,6 +152,10 @@ private:
unsigned m_maxCalibration; ///< stores the max pot value unsigned m_maxCalibration; ///< stores the max pot value
unsigned m_lastValue = 0; ///< stores previous value unsigned m_lastValue = 0; ///< stores previous value
float m_feedbackFitlerValue = 0.9f; ///< feedback value for POT filter float m_feedbackFitlerValue = 0.9f; ///< feedback value for POT filter
float m_thresholdFactor = 0.05f; ///< threshold factor causes values pot to saturate faster at the limits, default is 5%
unsigned m_minCalibrationThresholded; ///< stores the min pot value after thresholding
unsigned m_maxCalibrationThresholded; ///< stores the max pot value after thresholding
unsigned m_rangeThresholded; ///< stores the range of max - min after thresholding
}; };
/// Convenience class for rotary (quadrature) encoders. Uses Arduino Encoder under the hood. /// Convenience class for rotary (quadrature) encoders. Uses Arduino Encoder under the hood.
@ -241,6 +266,18 @@ public:
/// @returns true if the pot value has changed since previous check, otherwise false /// @returns true if the pot value has changed since previous check, otherwise false
bool checkPotValue(unsigned handle, float &value); bool checkPotValue(unsigned handle, float &value);
/// Get the raw uncalibrated value from the pot
/// @returns uncalibrated pot value
int getPotRawValue(unsigned handle);
/// Override the calibration values with new values
/// @param handle handle the handle that was provided previously by calling addPot()
/// @param min the min raw value for the pot
/// @param max the max raw value for the pot
/// @param swapDirection when true, max raw value will mean min control value
/// @returns false when handle is out of range
bool setCalibrationValues(unsigned handle, unsigned min, unsigned max, bool swapDirection);
/// Check if the switch has been toggled since last call /// Check if the switch has been toggled since last call
/// @param handle the handle that was provided previously by calling addSwitch() /// @param handle the handle that was provided previously by calling addSwitch()
/// @returns true if the switch changed state, otherwise false /// @returns true if the switch changed state, otherwise false
@ -254,7 +291,13 @@ public:
/// Get the value of the switch /// Get the value of the switch
/// @param handle the handle that was provided previously by calling addSwitch() /// @param handle the handle that was provided previously by calling addSwitch()
/// @returns the value at the switch pin, either 0 or 1. /// @returns the value at the switch pin, either 0 or 1.
int getSwitchValue(unsigned handle); bool getSwitchValue(unsigned handle);
/// Determine if a switch has changed value
/// @param handle the handle that was provided previously by calling addSwitch()
/// @param switchValue a boolean to store the new switch value
/// @returns true if the switch has changed
bool hasSwitchChanged(unsigned handle, bool &switchValue);
private: private:
std::vector<Potentiometer> m_pots; ///< a vector of all added pots std::vector<Potentiometer> m_pots; ///< a vector of all added pots

@ -117,15 +117,24 @@ bool BAPhysicalControls::checkPotValue(unsigned handle, float &value) {
return m_pots[handle].getValue(value); return m_pots[handle].getValue(value);
} }
int BAPhysicalControls::getPotRawValue(unsigned handle)
{
if (handle >= m_pots.size()) { return false;} // handle is greater than number of pots
return m_pots[handle].getRawValue();
}
bool BAPhysicalControls::setCalibrationValues(unsigned handle, unsigned min, unsigned max, bool swapDirection)
{
if (handle >= m_pots.size()) { return false;} // handle is greater than number of pots
m_pots[handle].setCalibrationValues(min, max, swapDirection);
return true;
}
bool BAPhysicalControls::isSwitchToggled(unsigned handle) { bool BAPhysicalControls::isSwitchToggled(unsigned handle) {
if (handle >= m_switches.size()) { return 0; } // handle is greater than number of switches if (handle >= m_switches.size()) { return 0; } // handle is greater than number of switches
DigitalInput &sw = m_switches[handle]; DigitalInput &sw = m_switches[handle];
if (sw.update() && sw.fallingEdge()) { return sw.hasInputToggled();
return true;
} else {
return false;
}
} }
bool BAPhysicalControls::isSwitchHeld(unsigned handle) bool BAPhysicalControls::isSwitchHeld(unsigned handle)
@ -133,15 +142,10 @@ bool BAPhysicalControls::isSwitchHeld(unsigned handle)
if (handle >= m_switches.size()) { return 0; } // handle is greater than number of switches if (handle >= m_switches.size()) { return 0; } // handle is greater than number of switches
DigitalInput &sw = m_switches[handle]; DigitalInput &sw = m_switches[handle];
sw.update(); return sw.isInputAssert();
if (sw.read()) {
return true;
} else {
return false;
}
} }
int BAPhysicalControls::getSwitchValue(unsigned handle) bool BAPhysicalControls::getSwitchValue(unsigned handle)
{ {
if (handle >= m_switches.size()) { return 0; } // handle is greater than number of switches if (handle >= m_switches.size()) { return 0; } // handle is greater than number of switches
DigitalInput &sw = m_switches[handle]; DigitalInput &sw = m_switches[handle];
@ -149,8 +153,66 @@ int BAPhysicalControls::getSwitchValue(unsigned handle)
return sw.read(); return sw.read();
} }
bool BAPhysicalControls::hasSwitchChanged(unsigned handle, bool &switchValue)
{
if (handle >= m_switches.size()) { return 0; } // handle is greater than number of switches
DigitalInput &sw = m_switches[handle];
return sw.hasInputChanged(switchValue);
}
///////////////////////////
// DigitalInput
/////////////////////////// ///////////////////////////
bool DigitalInput::hasInputToggled() {
update();
if (fell() && (m_isPolarityInverted == false)) {
// switch fell and polarity is not inverted
return true;
} else if (rose() && (m_isPolarityInverted == true)) {
// switch rose and polarity is inveretd
return true;
} else {
return false;
}
}
bool DigitalInput::isInputAssert()
{
update();
// if polarity is inverted, return the opposite state
bool retValue = Bounce::read() ^ m_isPolarityInverted;
return retValue;
}
bool DigitalInput::getPinInputValue()
{
update();
return Bounce::read();
}
bool DigitalInput::hasInputChanged(bool &switchState)
{
update();
if (rose()) {
// return true if not inverted
switchState = m_isPolarityInverted ? false : true;
return true;
} else if (fell()) {
// return false if not inverted
switchState = m_isPolarityInverted ? true : false;
return true;
} else {
// return current value
switchState = Bounce::read() != m_isPolarityInverted;
return false;
}
}
///////////////////////////
// DigitalOutput
///////////////////////////
void DigitalOutput::set(int val) { void DigitalOutput::set(int val) {
m_val = val; m_val = val;
digitalWriteFast(m_pin, m_val); digitalWriteFast(m_pin, m_val);
@ -161,6 +223,16 @@ void DigitalOutput::toggle(void) {
digitalWriteFast(m_pin, m_val); digitalWriteFast(m_pin, m_val);
} }
///////////////////////////
// Potentiometer
///////////////////////////
Potentiometer::Potentiometer(uint8_t analogPin, unsigned minCalibration, unsigned maxCalibration, bool swapDirection)
: m_pin(analogPin), m_swapDirection(swapDirection), m_minCalibration(minCalibration), m_maxCalibration(maxCalibration)
{
adjustCalibrationThreshold(m_thresholdFactor); // Calculate the thresholded values
}
void Potentiometer::setFeedbackFitlerValue(float fitlerValue) void Potentiometer::setFeedbackFitlerValue(float fitlerValue)
{ {
m_feedbackFitlerValue = fitlerValue; m_feedbackFitlerValue = fitlerValue;
@ -171,17 +243,25 @@ bool Potentiometer::getValue(float &value) {
bool newValue = true; bool newValue = true;
unsigned val = analogRead(m_pin); // read the raw value unsigned val = analogRead(m_pin); // read the raw value
// Use an IIR filter to smooth out the noise in the pot readings
unsigned valFilter = ( (1.0f - m_feedbackFitlerValue)*val + m_feedbackFitlerValue*m_lastValue);
// constrain it within the calibration values, them map it to the desired range. // constrain it within the calibration values, them map it to the desired range.
valFilter = constrain(valFilter, m_minCalibration, m_maxCalibration); val = constrain(val, m_minCalibration, m_maxCalibration);
// Use an IIR filter to smooth out the noise in the pot readings
unsigned valFilter = static_cast<unsigned>( (1.0f - m_feedbackFitlerValue)*val + (m_feedbackFitlerValue*m_lastValue));
if (valFilter == m_lastValue) { if (valFilter == m_lastValue) {
newValue = false; newValue = false;
} }
m_lastValue = valFilter; m_lastValue = valFilter;
value = static_cast<float>(valFilter - m_minCalibration) / static_cast<float>(m_maxCalibration); //
if (valFilter < m_minCalibrationThresholded) { value = 0.0f; }
else if (valFilter > m_maxCalibrationThresholded) { value = 1.0f; }
else {
value = static_cast<float>(valFilter - m_minCalibrationThresholded) / static_cast<float>(m_rangeThresholded);
}
if (m_swapDirection) { if (m_swapDirection) {
value = 1.0f - value; value = 1.0f - value;
} }
@ -192,11 +272,25 @@ int Potentiometer::getRawValue() {
return analogRead(m_pin); return analogRead(m_pin);
} }
// Recalculate thresholded limits based on thresholdFactor
void Potentiometer::adjustCalibrationThreshold(float thresholdFactor) void Potentiometer::adjustCalibrationThreshold(float thresholdFactor)
{ {
float threshold = m_maxCalibration * thresholdFactor; m_thresholdFactor = thresholdFactor;
m_maxCalibration -= static_cast<unsigned>(threshold); // the threshold is specificed as a fraction of the min/max range.
m_minCalibration += static_cast<unsigned>(threshold); unsigned threshold = static_cast<unsigned>((m_maxCalibration - m_minCalibration) * thresholdFactor);
// Update the thresholded values
m_minCalibrationThresholded = m_minCalibration + threshold;
m_maxCalibrationThresholded = m_maxCalibration - threshold;
m_rangeThresholded = m_maxCalibrationThresholded - m_minCalibrationThresholded;
}
void Potentiometer::setCalibrationValues(unsigned min, unsigned max, bool swapDirection)
{
m_minCalibration = min;
m_maxCalibration = max;
m_swapDirection = swapDirection;
adjustCalibrationThreshold(m_thresholdFactor);
} }
Potentiometer::Calib Potentiometer::calibrate(uint8_t pin) { Potentiometer::Calib Potentiometer::calibrate(uint8_t pin) {

Loading…
Cancel
Save