mirror of
https://github.com/jhbruhn/eurorack.git
synced 2025-03-15 02:55:49 +00:00
Implement hidden attenuverters for volume
This commit is contained in:
parent
1f57683c0c
commit
af0de40517
8 changed files with 359 additions and 70 deletions
|
@ -2,10 +2,6 @@
|
||||||
#include "peripherals.h"
|
#include "peripherals.h"
|
||||||
#include <stm32f0xx_hal.h>
|
#include <stm32f0xx_hal.h>
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
void DMA_TransferComplete(DMA_HandleTypeDef* dma); // declared in stereo_mix.cc
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace stereo_mix {
|
namespace stereo_mix {
|
||||||
|
|
||||||
Adc::Adc()
|
Adc::Adc()
|
||||||
|
|
|
@ -35,7 +35,21 @@ class Adc {
|
||||||
|
|
||||||
void OnDMATransferComplete();
|
void OnDMATransferComplete();
|
||||||
inline const uint16_t* values() { return &values_[0]; }
|
inline const uint16_t* values() { return &values_[0]; }
|
||||||
inline int32_t value(int32_t channel) const
|
|
||||||
|
inline int16_t cv_value(AdcChannel channel)
|
||||||
|
{
|
||||||
|
#ifdef NEW_HARDWARE
|
||||||
|
return this->values_[ADC_GROUP_CV + channel] - 32768;
|
||||||
|
#else
|
||||||
|
if (channel >= ADC_CHANNEL_PAN_1) {
|
||||||
|
return this->values_[ADC_GROUP_CV + channel] - 32768;
|
||||||
|
} else {
|
||||||
|
return this->values_[ADC_GROUP_CV + channel] >> 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint16_t value(int32_t channel) const
|
||||||
{
|
{
|
||||||
return static_cast<int32_t>(values_[channel]);
|
return static_cast<int32_t>(values_[channel]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,12 @@ class Dac { // MCP4xx2 dac implementation
|
||||||
: ssGpioPort(ssGpioPort_)
|
: ssGpioPort(ssGpioPort_)
|
||||||
, ssGpioPin(ssGpioPin_)
|
, ssGpioPin(ssGpioPin_)
|
||||||
{
|
{
|
||||||
|
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||||
|
__HAL_RCC_SPI1_CLK_ENABLE();
|
||||||
|
|
||||||
ssGpioPort = ssGpioPort_;
|
ssGpioPort = ssGpioPort_;
|
||||||
ssGpioPin = ssGpioPin_;
|
ssGpioPin = ssGpioPin_;
|
||||||
// init SS/CS/RST GPIO
|
// init SS/CS/RST GPIO
|
||||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
|
||||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
|
||||||
|
|
||||||
GPIO_InitTypeDef gpio_init;
|
GPIO_InitTypeDef gpio_init;
|
||||||
gpio_init.Mode = GPIO_MODE_OUTPUT_PP;
|
gpio_init.Mode = GPIO_MODE_OUTPUT_PP;
|
||||||
|
@ -38,10 +39,6 @@ class Dac { // MCP4xx2 dac implementation
|
||||||
HAL_GPIO_Init(GPIOB, &gpio_init);
|
HAL_GPIO_Init(GPIOB, &gpio_init);
|
||||||
|
|
||||||
// init SPI
|
// init SPI
|
||||||
__HAL_RCC_SPI1_CLK_ENABLE();
|
|
||||||
// HAL_SPI_DeInit(&spi);
|
|
||||||
|
|
||||||
// Initialize SPI TODO: check which config we need
|
|
||||||
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
|
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
|
||||||
hspi1.Init.Mode = SPI_MODE_MASTER;
|
hspi1.Init.Mode = SPI_MODE_MASTER;
|
||||||
hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
|
hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
|
||||||
|
|
|
@ -22,18 +22,23 @@ class Leds {
|
||||||
gpioInit.Pull = GPIO_NOPULL;
|
gpioInit.Pull = GPIO_NOPULL;
|
||||||
gpioInit.Speed = GPIO_SPEED_FREQ_MEDIUM;
|
gpioInit.Speed = GPIO_SPEED_FREQ_MEDIUM;
|
||||||
HAL_GPIO_Init(kGpioPorts[i], &gpioInit);
|
HAL_GPIO_Init(kGpioPorts[i], &gpioInit);
|
||||||
|
|
||||||
|
intensities[i] = 0;
|
||||||
|
blinking[i] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Write()
|
void Write()
|
||||||
{
|
{
|
||||||
pwm_counter++;
|
pwm_counter++;
|
||||||
pwm_counter &= 0x1ff; // equals to if(pwm_counter > 512) pwm_counter = 0;
|
pwm_counter &= 0x1ff; // equals to if(pwm_counter > 512) pwm_counter = 0;
|
||||||
|
blink_counter++;
|
||||||
|
blink_counter &= 0x7FFF;
|
||||||
for (size_t i = 0; i < kNumChannels; i++) {
|
for (size_t i = 0; i < kNumChannels; i++) {
|
||||||
if (intensities[0] && lut_led_gamma[intensities[i]] >= pwm_counter) {
|
bool in_blink_phase = blink_counter < 16383 || !blinking[i];
|
||||||
HAL_GPIO_WritePin(kGpioPorts[i], kGpioPins[i], GPIO_PIN_SET);
|
if (intensities[0] && lut_led_gamma[intensities[i]] >= pwm_counter && in_blink_phase) {
|
||||||
|
kGpioPorts[i]->BSRR |= kGpioPins[i];
|
||||||
} else {
|
} else {
|
||||||
HAL_GPIO_WritePin(kGpioPorts[i], kGpioPins[i], GPIO_PIN_RESET);
|
kGpioPorts[i]->BRR |= kGpioPins[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,8 +48,16 @@ class Leds {
|
||||||
return;
|
return;
|
||||||
intensities[channel] = intensity;
|
intensities[channel] = intensity;
|
||||||
}
|
}
|
||||||
|
void set_blinking(uint8_t channel, bool blink)
|
||||||
|
{
|
||||||
|
if (channel >= kNumChannels)
|
||||||
|
return;
|
||||||
|
blinking[channel] = blink;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t pwm_counter;
|
uint16_t pwm_counter;
|
||||||
|
uint16_t blink_counter;
|
||||||
uint8_t intensities[kNumChannels];
|
uint8_t intensities[kNumChannels];
|
||||||
|
bool blinking[kNumChannels];
|
||||||
};
|
};
|
||||||
|
|
170
stereo_mix/pot_controller.h
Normal file
170
stereo_mix/pot_controller.h
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
// Copyright 2015 Emilie Gillet.
|
||||||
|
//
|
||||||
|
// Author: Emilie Gillet (emilie.o.gillet@gmail.com)
|
||||||
|
// modified for ints by Jan-Henrik Bruhn (hi@jhbruhn.de)
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// See http://creativecommons.org/licenses/MIT/ for more information.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Handles the "hold button to tweak a hidden parameter" behaviour of pots.
|
||||||
|
// A pot can be in 4 states:
|
||||||
|
// - POT_STATE_TRACKING: the main parameter tracks the position of the pot.
|
||||||
|
// - POT_STATE_LOCKING: the main parameter no longer tracks the position of
|
||||||
|
// the pot. We wait for the pot to move further from its original position
|
||||||
|
// to start modifying the hidden parameter.
|
||||||
|
// - POT_STATE_HIDDEN_PARAMETER: the hidden parameter tracks the position of
|
||||||
|
// the pot.
|
||||||
|
// - POT_STATE_CATCHING_UP: the pot adjusts the main parameter in a relative
|
||||||
|
// way, until the position of the pot and the value of the parameter match
|
||||||
|
// again.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "stmlib/stmlib.h"
|
||||||
|
#include "stmlib/dsp/dsp.h"
|
||||||
|
|
||||||
|
|
||||||
|
enum PotState {
|
||||||
|
POT_STATE_TRACKING,
|
||||||
|
POT_STATE_LOCKING,
|
||||||
|
POT_STATE_HIDDEN_PARAMETER,
|
||||||
|
POT_STATE_CATCHING_UP
|
||||||
|
};
|
||||||
|
|
||||||
|
class PotController {
|
||||||
|
public:
|
||||||
|
PotController() { }
|
||||||
|
~PotController() { }
|
||||||
|
|
||||||
|
inline void Init(
|
||||||
|
uint16_t* main_parameter,
|
||||||
|
uint16_t* hidden_parameter // this pot controller always works on values between 0 and 65535
|
||||||
|
) {
|
||||||
|
state_ = POT_STATE_TRACKING;
|
||||||
|
was_catching_up_ = false;
|
||||||
|
|
||||||
|
main_parameter_ = main_parameter;
|
||||||
|
hidden_parameter_ = hidden_parameter;
|
||||||
|
|
||||||
|
value_ = 0;
|
||||||
|
stored_value_ = 0;
|
||||||
|
previous_value_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Lock() {
|
||||||
|
if (state_ == POT_STATE_LOCKING || state_ == POT_STATE_HIDDEN_PARAMETER) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (hidden_parameter_) {
|
||||||
|
was_catching_up_ = state_ == POT_STATE_CATCHING_UP;
|
||||||
|
state_ = POT_STATE_LOCKING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool editing_hidden_parameter() const {
|
||||||
|
return state_ == POT_STATE_HIDDEN_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Unlock() {
|
||||||
|
if (state_ == POT_STATE_HIDDEN_PARAMETER || was_catching_up_) {
|
||||||
|
state_ = POT_STATE_CATCHING_UP;
|
||||||
|
} else {
|
||||||
|
state_ = POT_STATE_TRACKING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Realign() {
|
||||||
|
state_ = POT_STATE_TRACKING;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ProcessControlRate(uint16_t adc_value) {
|
||||||
|
value_ += (adc_value - value_) >> 6;
|
||||||
|
CONSTRAIN(value_, 0, 65535);
|
||||||
|
// approximately this:
|
||||||
|
// ONE_POLE(value_, adc_value, 0.01f);
|
||||||
|
|
||||||
|
if (state_ == POT_STATE_TRACKING) {
|
||||||
|
*main_parameter_ = value_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ProcessUIRate() {
|
||||||
|
switch (state_) {
|
||||||
|
case POT_STATE_TRACKING:
|
||||||
|
previous_value_ = value_;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case POT_STATE_LOCKING:
|
||||||
|
if (abs(value_ - previous_value_) > 1966) {
|
||||||
|
stored_value_ = previous_value_;
|
||||||
|
CONSTRAIN(value_, 0, 65535);
|
||||||
|
*hidden_parameter_ = value_;
|
||||||
|
state_ = POT_STATE_HIDDEN_PARAMETER;
|
||||||
|
previous_value_ = value_;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case POT_STATE_HIDDEN_PARAMETER:
|
||||||
|
CONSTRAIN(value_, 0, 65535);
|
||||||
|
*hidden_parameter_ = value_;
|
||||||
|
previous_value_ = value_;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case POT_STATE_CATCHING_UP:
|
||||||
|
{
|
||||||
|
if (abs(value_ - previous_value_) > 327) {
|
||||||
|
int32_t delta = value_ - previous_value_;
|
||||||
|
|
||||||
|
int32_t skew_ratio = delta > 0
|
||||||
|
? (65600 - stored_value_) / (65535 - previous_value_)
|
||||||
|
: (66 + stored_value_) / (66 + previous_value_);
|
||||||
|
CONSTRAIN(skew_ratio, 6553, 655350);
|
||||||
|
|
||||||
|
stored_value_ += (skew_ratio * delta) >> 11;
|
||||||
|
CONSTRAIN(stored_value_, 0, 65535);
|
||||||
|
|
||||||
|
if (abs(stored_value_ - value_) < 327) {
|
||||||
|
state_ = POT_STATE_TRACKING;
|
||||||
|
}
|
||||||
|
previous_value_ = value_;
|
||||||
|
*main_parameter_ = stored_value_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PotState state_;
|
||||||
|
bool was_catching_up_;
|
||||||
|
|
||||||
|
uint16_t* main_parameter_;
|
||||||
|
uint16_t* hidden_parameter_;
|
||||||
|
int32_t value_;
|
||||||
|
int32_t stored_value_;
|
||||||
|
int32_t previous_value_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(PotController);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "drivers/switches.h"
|
#include "drivers/switches.h"
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
#include "stmlib/ui/event_queue.h"
|
#include "stmlib/ui/event_queue.h"
|
||||||
|
#include "ui.h"
|
||||||
#include <stm32f0xx_hal.h>
|
#include <stm32f0xx_hal.h>
|
||||||
|
|
||||||
using namespace stereo_mix;
|
using namespace stereo_mix;
|
||||||
|
@ -14,14 +15,11 @@ Dac dacs[8] = {
|
||||||
{ GPIOB, GPIO_PIN_8 }, { GPIOB, GPIO_PIN_9 }, { GPIOB, GPIO_PIN_10 }, { GPIOB, GPIO_PIN_11 },
|
{ GPIOB, GPIO_PIN_8 }, { GPIOB, GPIO_PIN_9 }, { GPIOB, GPIO_PIN_10 }, { GPIOB, GPIO_PIN_11 },
|
||||||
{ GPIOA, GPIO_PIN_8 }, { GPIOA, GPIO_PIN_9 }, { GPIOA, GPIO_PIN_10 }, { GPIOA, GPIO_PIN_11 }
|
{ GPIOA, GPIO_PIN_8 }, { GPIOA, GPIO_PIN_9 }, { GPIOA, GPIO_PIN_10 }, { GPIOA, GPIO_PIN_11 }
|
||||||
};
|
};
|
||||||
|
|
||||||
Adc adc;
|
Adc adc;
|
||||||
Leds leds;
|
Leds leds;
|
||||||
Switches switches;
|
Switches switches;
|
||||||
|
UI ui(&adc, &switches, &leds);
|
||||||
const int32_t kLongPressDuration = 2000;
|
|
||||||
EventQueue<> queue;
|
|
||||||
uint32_t press_time[SWITCH_COUNT];
|
|
||||||
bool ignore_release[SWITCH_COUNT];
|
|
||||||
|
|
||||||
bool mute[4];
|
bool mute[4];
|
||||||
|
|
||||||
|
@ -65,28 +63,7 @@ void SysTick_Handler()
|
||||||
system_clock.Tick();
|
system_clock.Tick();
|
||||||
|
|
||||||
switches.Debounce();
|
switches.Debounce();
|
||||||
|
ui.Poll();
|
||||||
for (size_t i = 0; i < SWITCH_COUNT; i++) {
|
|
||||||
if (switches.just_pressed(Switch(i))) {
|
|
||||||
queue.AddEvent(CONTROL_SWITCH, i, 0);
|
|
||||||
press_time[i] = HAL_GetTick();
|
|
||||||
ignore_release[i] = false;
|
|
||||||
}
|
|
||||||
if (switches.pressed(Switch(i)) && !ignore_release[i]) {
|
|
||||||
int32_t pressed_time = HAL_GetTick() - press_time[i];
|
|
||||||
if (pressed_time > kLongPressDuration) {
|
|
||||||
queue.AddEvent(CONTROL_SWITCH, i, pressed_time);
|
|
||||||
ignore_release[i] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (switches.released(Switch(i)) && !ignore_release[i]) {
|
|
||||||
queue.AddEvent(
|
|
||||||
CONTROL_SWITCH,
|
|
||||||
i,
|
|
||||||
system_clock.milliseconds() - press_time[i] + 1);
|
|
||||||
ignore_release[i] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemClock_Config(void)
|
void SystemClock_Config(void)
|
||||||
|
@ -124,7 +101,8 @@ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
|
||||||
{
|
{
|
||||||
adc.OnDMATransferComplete();
|
adc.OnDMATransferComplete();
|
||||||
}
|
}
|
||||||
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) // called with 1kHz (OPTIMIZE!) the display should get its own spi bus
|
|
||||||
|
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
|
||||||
{
|
{
|
||||||
if (htim != &htim3) {
|
if (htim != &htim3) {
|
||||||
return;
|
return;
|
||||||
|
@ -135,18 +113,25 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) // called with 1kHz
|
||||||
|
|
||||||
void Init(void)
|
void Init(void)
|
||||||
{
|
{
|
||||||
|
__HAL_RCC_SYSCFG_CLK_ENABLE();
|
||||||
|
__HAL_RCC_PWR_CLK_ENABLE();
|
||||||
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||||
|
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||||
|
__HAL_RCC_GPIOF_CLK_ENABLE();
|
||||||
|
__HAL_RCC_TIM3_CLK_ENABLE();
|
||||||
|
__HAL_RCC_SPI1_CLK_ENABLE();
|
||||||
|
|
||||||
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
|
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
|
||||||
HAL_NVIC_EnableIRQ(TIM3_IRQn);
|
HAL_NVIC_EnableIRQ(TIM3_IRQn);
|
||||||
__HAL_RCC_TIM3_CLK_ENABLE();
|
htim3.Init.Prescaler = 10;
|
||||||
htim3.Init.Prescaler = 14;
|
|
||||||
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
|
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||||
htim3.Init.Period = 128;
|
htim3.Init.Period = 128;
|
||||||
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||||
htim3.Init.RepetitionCounter = 0;
|
htim3.Init.RepetitionCounter = 0;
|
||||||
HAL_TIM_Base_Init(&htim3);
|
HAL_TIM_Base_Init(&htim3);
|
||||||
HAL_TIM_Base_Start_IT(&htim3);
|
HAL_TIM_Base_Start_IT(&htim3);
|
||||||
|
|
||||||
system_clock.Init();
|
system_clock.Init();
|
||||||
queue.Init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteOutputs(void)
|
void WriteOutputs(void)
|
||||||
|
@ -157,8 +142,8 @@ void WriteOutputs(void)
|
||||||
|
|
||||||
uint16_t pan_pot = adc.value(ADC_GROUP_POT + ADC_CHANNEL_PAN_1 + i) >> (16 - 12); // adc is only 12 bit anyways
|
uint16_t pan_pot = adc.value(ADC_GROUP_POT + ADC_CHANNEL_PAN_1 + i) >> (16 - 12); // adc is only 12 bit anyways
|
||||||
uint16_t vol_pot = adc.value(ADC_GROUP_POT + ADC_CHANNEL_VOL_1 + i) >> (16 - 12);
|
uint16_t vol_pot = adc.value(ADC_GROUP_POT + ADC_CHANNEL_VOL_1 + i) >> (16 - 12);
|
||||||
int16_t pan_cv = (adc.value(ADC_GROUP_CV + ADC_CHANNEL_PAN_1 + i) - 32768) >> (16 - 12);
|
int16_t pan_cv = adc.cv_value(AdcChannel(ADC_CHANNEL_PAN_1 + i)) >> (16 - 12);
|
||||||
uint16_t vol_cv = adc.value(ADC_GROUP_CV + ADC_CHANNEL_VOL_1 + i) >> (16 - 12);
|
int16_t vol_cv = adc.cv_value(AdcChannel(ADC_CHANNEL_VOL_1 + i)) >> (16 - 12);
|
||||||
int32_t pan = pan_pot + pan_cv;
|
int32_t pan = pan_pot + pan_cv;
|
||||||
int32_t vol = vol_pot + vol_cv;
|
int32_t vol = vol_pot + vol_cv;
|
||||||
|
|
||||||
|
@ -167,7 +152,7 @@ void WriteOutputs(void)
|
||||||
|
|
||||||
CONSTRAIN(pan, 0, (1 << 12) - 1);
|
CONSTRAIN(pan, 0, (1 << 12) - 1);
|
||||||
CONSTRAIN(vol, 0, (1 << 12) - 1);
|
CONSTRAIN(vol, 0, (1 << 12) - 1);
|
||||||
leds.set_intensity(i, vol >> 4);
|
// leds.set_intensity(i, vol >> 4);
|
||||||
value_l = (lut_left_sin_pan[pan] * lut_linear_to_exp[vol]) >> 16;
|
value_l = (lut_left_sin_pan[pan] * lut_linear_to_exp[vol]) >> 16;
|
||||||
value_r = (lut_right_cos_pan[pan] * lut_linear_to_exp[vol]) >> 16;
|
value_r = (lut_right_cos_pan[pan] * lut_linear_to_exp[vol]) >> 16;
|
||||||
|
|
||||||
|
@ -178,36 +163,16 @@ void WriteOutputs(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleEvent(void)
|
|
||||||
{
|
|
||||||
while (queue.available()) {
|
|
||||||
Event ev = queue.PullEvent();
|
|
||||||
switch (ev.control_type) {
|
|
||||||
case CONTROL_SWITCH:
|
|
||||||
if (ev.data != 0) { // switch released
|
|
||||||
mute[ev.control_id] = !mute[ev.control_id];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
HAL_Init();
|
HAL_Init();
|
||||||
SystemClock_Config();
|
SystemClock_Config();
|
||||||
__HAL_RCC_SYSCFG_CLK_ENABLE();
|
|
||||||
__HAL_RCC_PWR_CLK_ENABLE();
|
|
||||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
|
||||||
__HAL_RCC_GPIOF_CLK_ENABLE();
|
|
||||||
|
|
||||||
Init();
|
Init();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
HandleEvent();
|
ui.DoEvents();
|
||||||
|
|
||||||
WriteOutputs();
|
WriteOutputs();
|
||||||
}
|
}
|
||||||
|
|
84
stereo_mix/ui.cc
Normal file
84
stereo_mix/ui.cc
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
#include "ui.h"
|
||||||
|
#include "pot_controller.h"
|
||||||
|
#include <stm32f0xx_hal.h>
|
||||||
|
|
||||||
|
const int kLongPressDuration = 2000;
|
||||||
|
|
||||||
|
void UI::Poll()
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < SWITCH_COUNT; i++) {
|
||||||
|
if (switches->just_pressed(Switch(i))) {
|
||||||
|
queue.AddEvent(CONTROL_SWITCH, i, 0);
|
||||||
|
press_time[i] = HAL_GetTick();
|
||||||
|
ignore_release[i] = false;
|
||||||
|
potControllers[0].Lock();
|
||||||
|
}
|
||||||
|
if (switches->pressed(Switch(i)) && !ignore_release[i]) {
|
||||||
|
bool suppress_release_hidden_parameters = false;
|
||||||
|
for (size_t j = 0; j < kNumChannels * 2; j++) {
|
||||||
|
suppress_release_hidden_parameters |= potControllers[j].editing_hidden_parameter();
|
||||||
|
}
|
||||||
|
int32_t pressed_time = HAL_GetTick() - press_time[i];
|
||||||
|
if (!suppress_release_hidden_parameters && pressed_time > kLongPressDuration) {
|
||||||
|
queue.AddEvent(CONTROL_SWITCH, i, pressed_time);
|
||||||
|
ignore_release[i] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (switches->released(Switch(i))) {
|
||||||
|
bool suppress_release_hidden_parameters = false;
|
||||||
|
for (size_t j = 0; j < kNumChannels * 2; j++) {
|
||||||
|
suppress_release_hidden_parameters |= potControllers[j].editing_hidden_parameter();
|
||||||
|
}
|
||||||
|
if (!suppress_release_hidden_parameters && !ignore_release[i]) {
|
||||||
|
queue.AddEvent(
|
||||||
|
CONTROL_SWITCH,
|
||||||
|
i,
|
||||||
|
system_clock.milliseconds() - press_time[i] + 1);
|
||||||
|
ignore_release[i] = true;
|
||||||
|
}
|
||||||
|
potControllers[0].Unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < kNumChannels * 2; i++) {
|
||||||
|
potControllers[i].ProcessControlRate(adc->value(ADC_GROUP_POT + i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI::OnSwitchPressed(const Event& e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI::OnSwitchReleased(const Event& e)
|
||||||
|
{
|
||||||
|
mute[e.control_id] = !mute[e.control_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
void UI::DoEvents()
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < kNumChannels * 2; i++) {
|
||||||
|
potControllers[i].ProcessUIRate();
|
||||||
|
|
||||||
|
if (potControllers[i].editing_hidden_parameter()) {
|
||||||
|
leds->set_intensity(i, abs(volume_att_pots[i] - 32767) >> 7);
|
||||||
|
leds->set_blinking(i, volume_att_pots[i] - 32767 < 0);
|
||||||
|
} else {
|
||||||
|
leds->set_intensity(i, mute[i] ? 0 : volume_pots[i] >> 8);
|
||||||
|
leds->set_blinking(i, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (queue.available()) {
|
||||||
|
Event ev = queue.PullEvent();
|
||||||
|
switch (ev.control_type) {
|
||||||
|
case CONTROL_SWITCH:
|
||||||
|
if (ev.data != 0) {
|
||||||
|
OnSwitchReleased(ev);
|
||||||
|
} else {
|
||||||
|
OnSwitchPressed(ev);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
stereo_mix/ui.h
Normal file
50
stereo_mix/ui.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "drivers/adc.h"
|
||||||
|
#include "drivers/leds.h"
|
||||||
|
#include "drivers/switches.h"
|
||||||
|
#include "pot_controller.h"
|
||||||
|
#include "stmlib/ui/event_queue.h"
|
||||||
|
|
||||||
|
using namespace stmlib;
|
||||||
|
|
||||||
|
extern const uint8_t kNumChannels; // TODO
|
||||||
|
|
||||||
|
class UI {
|
||||||
|
public:
|
||||||
|
UI(Adc* adc_, Switches* switches_, Leds* leds_)
|
||||||
|
: adc(adc_)
|
||||||
|
, switches(switches_)
|
||||||
|
, leds(leds_)
|
||||||
|
{
|
||||||
|
queue.Init();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < kNumChannels; i++) {
|
||||||
|
potControllers[i].Init(&volume_pots[i], &volume_att_pots[i]);
|
||||||
|
potControllers[i + kNumChannels].Init(&pan_pots[i], &pan_att_pots[i]);
|
||||||
|
|
||||||
|
volume_att_pots[i] = pan_att_pots[i] = 65535;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
void Poll();
|
||||||
|
void DoEvents();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void OnSwitchPressed(const Event&);
|
||||||
|
void OnSwitchReleased(const Event&);
|
||||||
|
|
||||||
|
EventQueue<> queue;
|
||||||
|
uint32_t press_time[SWITCH_COUNT];
|
||||||
|
bool ignore_release[SWITCH_COUNT];
|
||||||
|
Adc* adc;
|
||||||
|
Switches* switches;
|
||||||
|
Leds* leds;
|
||||||
|
|
||||||
|
uint16_t volume_pots[kNumChannels];
|
||||||
|
uint16_t pan_pots[kNumChannels];
|
||||||
|
uint16_t volume_att_pots[kNumChannels];
|
||||||
|
uint16_t pan_att_pots[kNumChannels];
|
||||||
|
bool mute[kNumChannels];
|
||||||
|
|
||||||
|
PotController potControllers[kNumChannels * 2]; // todo: count
|
||||||
|
};
|
Loading…
Reference in a new issue