| @@ -10,7 +10,6 @@ | |||
| #include "AudibleInstruments.hpp" | |||
| using namespace peaks; | |||
| enum SwitchIndex { | |||
| SWITCH_TWIN_MODE, | |||
| @@ -47,10 +46,12 @@ struct Settings { | |||
| bool snap_mode; | |||
| }; | |||
| const int32_t kLongPressDuration = 600; | |||
| const uint8_t kNumAdcChannels = 4; | |||
| const uint16_t kAdcThresholdUnlocked = 1 << (16 - 10); // 10 bits | |||
| const uint16_t kAdcThresholdLocked = 1 << (16 - 8); // 8 bits | |||
| static const int32_t kLongPressDuration = 600; | |||
| static const uint8_t kNumAdcChannels = 4; | |||
| static const uint16_t kAdcThresholdUnlocked = 1 << (16 - 10); // 10 bits | |||
| static const uint16_t kAdcThresholdLocked = 1 << (16 - 8); // 8 bits | |||
| struct Peaks : Module { | |||
| enum ParamIds { | |||
| @@ -142,7 +143,7 @@ struct Peaks : Module { | |||
| size_t potValueId; | |||
| json_t *pJ; | |||
| json_array_foreach(potValuesJ, potValueId, pJ) { | |||
| if (potValueId < sizeof(pot_value_)/sizeof(pot_value_)[0]) { | |||
| if (potValueId < sizeof(pot_value_) / sizeof(pot_value_)[0]) { | |||
| settings_.pot_value[potValueId] = json_integer_value(pJ); | |||
| } | |||
| } | |||
| @@ -167,27 +168,27 @@ struct Peaks : Module { | |||
| long long getSystemTimeMs(); | |||
| static const ProcessorFunction function_table_[FUNCTION_LAST][2]; | |||
| static const peaks::ProcessorFunction function_table_[FUNCTION_LAST][2]; | |||
| EditMode edit_mode_ = EDIT_MODE_TWIN; | |||
| Function function_[2] = {FUNCTION_ENVELOPE, FUNCTION_ENVELOPE}; | |||
| Settings settings_; | |||
| uint8_t pot_value_[8] = {0,0,0,0,0,0,0,0}; | |||
| uint8_t pot_value_[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | |||
| bool snap_mode_ = false; | |||
| bool snapped_[4] = {false,false,false,false}; | |||
| bool snapped_[4] = {false, false, false, false}; | |||
| int32_t adc_lp_[kNumAdcChannels] = {0,0,0,0}; | |||
| int32_t adc_value_[kNumAdcChannels] = {0,0,0,0}; | |||
| int32_t adc_threshold_[kNumAdcChannels] = {0,0,0,0}; | |||
| long long press_time_[2] = {0,0}; | |||
| int32_t adc_lp_[kNumAdcChannels] = {0, 0, 0, 0}; | |||
| int32_t adc_value_[kNumAdcChannels] = {0, 0, 0, 0}; | |||
| int32_t adc_threshold_[kNumAdcChannels] = {0, 0, 0, 0}; | |||
| long long press_time_[2] = {0, 0}; | |||
| SchmittTrigger switches_[2]; | |||
| std::shared_ptr<IOBuffer> ioBuffer; | |||
| std::shared_ptr<peaks::IOBuffer> ioBuffer; | |||
| GateFlags gate_flags[2] = {0,0}; | |||
| peaks::GateFlags gate_flags[2] = {0, 0}; | |||
| SampleRateConverter<2> outputSrc; | |||
| DoubleRingBuffer<Frame<2>, 256> outputBuffer; | |||
| @@ -195,30 +196,30 @@ struct Peaks : Module { | |||
| bool initNumberStation = false; | |||
| }; | |||
| const ProcessorFunction Peaks::function_table_[FUNCTION_LAST][2] = { | |||
| { PROCESSOR_FUNCTION_ENVELOPE, PROCESSOR_FUNCTION_ENVELOPE }, | |||
| { PROCESSOR_FUNCTION_LFO, PROCESSOR_FUNCTION_LFO }, | |||
| { PROCESSOR_FUNCTION_TAP_LFO, PROCESSOR_FUNCTION_TAP_LFO }, | |||
| { PROCESSOR_FUNCTION_BASS_DRUM, PROCESSOR_FUNCTION_SNARE_DRUM }, | |||
| const peaks::ProcessorFunction Peaks::function_table_[FUNCTION_LAST][2] = { | |||
| { peaks::PROCESSOR_FUNCTION_ENVELOPE, peaks::PROCESSOR_FUNCTION_ENVELOPE }, | |||
| { peaks::PROCESSOR_FUNCTION_LFO, peaks::PROCESSOR_FUNCTION_LFO }, | |||
| { peaks::PROCESSOR_FUNCTION_TAP_LFO, peaks::PROCESSOR_FUNCTION_TAP_LFO }, | |||
| { peaks::PROCESSOR_FUNCTION_BASS_DRUM, peaks::PROCESSOR_FUNCTION_SNARE_DRUM }, | |||
| { PROCESSOR_FUNCTION_MINI_SEQUENCER, PROCESSOR_FUNCTION_MINI_SEQUENCER }, | |||
| { PROCESSOR_FUNCTION_PULSE_SHAPER, PROCESSOR_FUNCTION_PULSE_SHAPER }, | |||
| { PROCESSOR_FUNCTION_PULSE_RANDOMIZER, PROCESSOR_FUNCTION_PULSE_RANDOMIZER }, | |||
| { PROCESSOR_FUNCTION_FM_DRUM, PROCESSOR_FUNCTION_FM_DRUM }, | |||
| { peaks::PROCESSOR_FUNCTION_MINI_SEQUENCER, peaks::PROCESSOR_FUNCTION_MINI_SEQUENCER }, | |||
| { peaks::PROCESSOR_FUNCTION_PULSE_SHAPER, peaks::PROCESSOR_FUNCTION_PULSE_SHAPER }, | |||
| { peaks::PROCESSOR_FUNCTION_PULSE_RANDOMIZER, peaks::PROCESSOR_FUNCTION_PULSE_RANDOMIZER }, | |||
| { peaks::PROCESSOR_FUNCTION_FM_DRUM, peaks::PROCESSOR_FUNCTION_FM_DRUM }, | |||
| }; | |||
| Peaks::Peaks() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { | |||
| ioBuffer = std::make_shared<IOBuffer>(); | |||
| ioBuffer = std::make_shared<peaks::IOBuffer>(); | |||
| settings_.edit_mode = EDIT_MODE_TWIN; | |||
| settings_.function[0] = FUNCTION_ENVELOPE; | |||
| settings_.function[0] = FUNCTION_ENVELOPE; | |||
| settings_.function[1] = FUNCTION_ENVELOPE; | |||
| settings_.snap_mode = false; | |||
| settings_.snap_mode = false; | |||
| std::fill(&settings_.pot_value[0], &settings_.pot_value[8], 0); | |||
| ioBuffer->Init(); | |||
| processors[0].Init(0); | |||
| processors[1].Init(1); | |||
| peaks::processors[0].Init(0); | |||
| peaks::processors[1].Init(1); | |||
| } | |||
| Peaks::~Peaks() { | |||
| @@ -226,18 +227,18 @@ Peaks::~Peaks() { | |||
| // Global scope, so variables can be accessed by process() function. | |||
| int16_t gOutputBuffer[kBlockSize]; | |||
| int16_t gBrightness[2] = {0,0}; | |||
| int16_t gOutputBuffer[peaks::kBlockSize]; | |||
| int16_t gBrightness[2] = {0, 0}; | |||
| void set_led_brightness(int channel, int16_t value) { | |||
| gBrightness[channel] = value; | |||
| gBrightness[channel] = value; | |||
| } | |||
| // File scope because of IOBuffer function signature. | |||
| // It cannot refer to a member function of class Peaks(). | |||
| void process(IOBuffer::Block* block, size_t size) { | |||
| for (size_t i = 0; i < kNumChannels; ++i) { | |||
| processors[i].Process(block->input[i], gOutputBuffer, size); | |||
| void process(peaks::IOBuffer::Block* block, size_t size) { | |||
| for (size_t i = 0; i < peaks::kNumChannels; ++i) { | |||
| peaks::processors[i].Process(block->input[i], gOutputBuffer, size); | |||
| set_led_brightness(i, gOutputBuffer[0]); | |||
| for (size_t j = 0; j < size; ++j) { | |||
| // From calibration_data.h, shifting signed to unsigned values. | |||
| @@ -253,9 +254,9 @@ void Peaks::init() { | |||
| std::fill(&press_time_[0], &press_time_[1], 0); | |||
| std::fill(&gBrightness[0], &gBrightness[1], 0); | |||
| std::fill(&adc_lp_[0], &adc_lp_[kNumAdcChannels], 0); | |||
| std::fill(&adc_value_[0], &adc_value_[kNumAdcChannels], 0); | |||
| std::fill(&adc_threshold_[0], &adc_threshold_[kNumAdcChannels], 0); | |||
| std::fill(&snapped_[0], &snapped_[kNumAdcChannels], false); | |||
| std::fill(&adc_value_[0], &adc_value_[kNumAdcChannels], 0); | |||
| std::fill(&adc_threshold_[0], &adc_threshold_[kNumAdcChannels], 0); | |||
| std::fill(&snapped_[0], &snapped_[kNumAdcChannels], false); | |||
| edit_mode_ = static_cast<EditMode>(settings_.edit_mode); | |||
| function_[0] = static_cast<Function>(settings_.function[0]); | |||
| @@ -265,12 +266,12 @@ void Peaks::init() { | |||
| if (edit_mode_ == EDIT_MODE_FIRST || edit_mode_ == EDIT_MODE_SECOND) { | |||
| lockPots(); | |||
| for (uint8_t i = 0; i < 4; ++i) { | |||
| processors[0].set_parameter( | |||
| i, | |||
| static_cast<uint16_t>(pot_value_[i]) << 8); | |||
| processors[1].set_parameter( | |||
| i, | |||
| static_cast<uint16_t>(pot_value_[i + 4]) << 8); | |||
| peaks::processors[0].set_parameter( | |||
| i, | |||
| static_cast<uint16_t>(pot_value_[i]) << 8); | |||
| peaks::processors[1].set_parameter( | |||
| i, | |||
| static_cast<uint16_t>(pot_value_[i + 4]) << 8); | |||
| } | |||
| } | |||
| @@ -288,8 +289,8 @@ void Peaks::step() { | |||
| // Initialize "secret" number station mode. | |||
| if (initNumberStation) { | |||
| processors[0].set_function(PROCESSOR_FUNCTION_NUMBER_STATION); | |||
| processors[1].set_function(PROCESSOR_FUNCTION_NUMBER_STATION); | |||
| peaks::processors[0].set_function(peaks::PROCESSOR_FUNCTION_NUMBER_STATION); | |||
| peaks::processors[1].set_function(peaks::PROCESSOR_FUNCTION_NUMBER_STATION); | |||
| initNumberStation = false; | |||
| } | |||
| @@ -310,19 +311,19 @@ void Peaks::step() { | |||
| // Prepare sample rate conversion. | |||
| // Peaks is sampling at 48kHZ. | |||
| outputSrc.setRates(48000, engineGetSampleRate()); | |||
| int inLen = kBlockSize; | |||
| int inLen = peaks::kBlockSize; | |||
| int outLen = outputBuffer.capacity(); | |||
| Frame<2> f[kBlockSize]; | |||
| Frame<2> f[peaks::kBlockSize]; | |||
| // Process an entire block of data from the IOBuffer. | |||
| for (size_t k = 0; k < kBlockSize; ++k) { | |||
| for (size_t k = 0; k < peaks::kBlockSize; ++k) { | |||
| IOBuffer::Slice slice = ioBuffer->NextSlice(1); | |||
| peaks::IOBuffer::Slice slice = ioBuffer->NextSlice(1); | |||
| for (size_t i = 0; i < kNumChannels; ++i) { | |||
| gate_flags[i] = ExtractGateFlags( | |||
| gate_flags[i], | |||
| gate_inputs & (1 << i)); | |||
| for (size_t i = 0; i < peaks::kNumChannels; ++i) { | |||
| gate_flags[i] = peaks::ExtractGateFlags( | |||
| gate_flags[i], | |||
| gate_inputs & (1 << i)); | |||
| f[k].samples[i] = slice.block->output[i][slice.frame_index]; | |||
| } | |||
| @@ -330,11 +331,11 @@ void Peaks::step() { | |||
| // A hack to make channel 1 aware of what's going on in channel 2. Used to | |||
| // reset the sequencer. | |||
| slice.block->input[0][slice.frame_index] = gate_flags[0] \ | |||
| | (gate_flags[1] << 4) \ | |||
| | (buttons & 8 ? GATE_FLAG_FROM_BUTTON : 0); | |||
| | (gate_flags[1] << 4) \ | |||
| | (buttons & 8 ? peaks::GATE_FLAG_FROM_BUTTON : 0); | |||
| slice.block->input[1][slice.frame_index] = gate_flags[1] \ | |||
| | (buttons & 2 ? GATE_FLAG_FROM_BUTTON : 0); | |||
| | (buttons & 2 ? peaks::GATE_FLAG_FROM_BUTTON : 0); | |||
| } | |||
| @@ -349,59 +350,64 @@ void Peaks::step() { | |||
| // Peaks manual says output spec is 0..8V for envelopes and 10Vpp for audio/CV. | |||
| // TODO Check the output values against an actual device. | |||
| outputs[OUT_1_OUTPUT].value = \ | |||
| rescale(static_cast<float>(f.samples[0]), 0.0f, 65535.f, -8.0f, 8.0f); | |||
| rescale(static_cast<float>(f.samples[0]), 0.0f, 65535.f, -8.0f, 8.0f); | |||
| outputs[OUT_2_OUTPUT].value = \ | |||
| rescale(static_cast<float>(f.samples[1]), 0.0f, 65535.f, -8.0f, 8.0f); | |||
| rescale(static_cast<float>(f.samples[1]), 0.0f, 65535.f, -8.0f, 8.0f); | |||
| } | |||
| } | |||
| void Peaks::changeControlMode() { | |||
| uint16_t parameters[4]; | |||
| for (int i = 0; i < 4; ++i) { | |||
| parameters[i] = adc_value_[i]; | |||
| } | |||
| for (int i = 0; i < 4; ++i) { | |||
| parameters[i] = adc_value_[i]; | |||
| } | |||
| if (edit_mode_ == EDIT_MODE_SPLIT) { | |||
| processors[0].CopyParameters(¶meters[0], 2); | |||
| processors[1].CopyParameters(¶meters[2], 2); | |||
| processors[0].set_control_mode(CONTROL_MODE_HALF); | |||
| processors[1].set_control_mode(CONTROL_MODE_HALF); | |||
| } else if (edit_mode_ == EDIT_MODE_TWIN) { | |||
| processors[0].CopyParameters(¶meters[0], 4); | |||
| processors[1].CopyParameters(¶meters[0], 4); | |||
| processors[0].set_control_mode(CONTROL_MODE_FULL); | |||
| processors[1].set_control_mode(CONTROL_MODE_FULL); | |||
| } else { | |||
| processors[0].set_control_mode(CONTROL_MODE_FULL); | |||
| processors[1].set_control_mode(CONTROL_MODE_FULL); | |||
| peaks::processors[0].CopyParameters(¶meters[0], 2); | |||
| peaks::processors[1].CopyParameters(¶meters[2], 2); | |||
| peaks::processors[0].set_control_mode(peaks::CONTROL_MODE_HALF); | |||
| peaks::processors[1].set_control_mode(peaks::CONTROL_MODE_HALF); | |||
| } | |||
| else if (edit_mode_ == EDIT_MODE_TWIN) { | |||
| peaks::processors[0].CopyParameters(¶meters[0], 4); | |||
| peaks::processors[1].CopyParameters(¶meters[0], 4); | |||
| peaks::processors[0].set_control_mode(peaks::CONTROL_MODE_FULL); | |||
| peaks::processors[1].set_control_mode(peaks::CONTROL_MODE_FULL); | |||
| } | |||
| else { | |||
| peaks::processors[0].set_control_mode(peaks::CONTROL_MODE_FULL); | |||
| peaks::processors[1].set_control_mode(peaks::CONTROL_MODE_FULL); | |||
| } | |||
| } | |||
| void Peaks::setFunction(uint8_t index, Function f) { | |||
| if (edit_mode_ == EDIT_MODE_SPLIT || edit_mode_ == EDIT_MODE_TWIN) { | |||
| function_[0] = function_[1] = f; | |||
| processors[0].set_function(function_table_[f][0]); | |||
| processors[1].set_function(function_table_[f][1]); | |||
| } else { | |||
| peaks::processors[0].set_function(function_table_[f][0]); | |||
| peaks::processors[1].set_function(function_table_[f][1]); | |||
| } | |||
| else { | |||
| function_[index] = f; | |||
| processors[index].set_function(function_table_[f][index]); | |||
| peaks::processors[index].set_function(function_table_[f][index]); | |||
| } | |||
| } | |||
| void Peaks::onSwitchReleased(uint16_t id, uint16_t data) { | |||
| switch (id) { | |||
| case SWITCH_TWIN_MODE: | |||
| case SWITCH_TWIN_MODE: | |||
| if (data > kLongPressDuration) { | |||
| edit_mode_ = static_cast<EditMode>( | |||
| (edit_mode_ + EDIT_MODE_FIRST) % EDIT_MODE_LAST); | |||
| (edit_mode_ + EDIT_MODE_FIRST) % EDIT_MODE_LAST); | |||
| function_[0] = function_[1]; | |||
| processors[0].set_function(function_table_[function_[0]][0]); | |||
| processors[1].set_function(function_table_[function_[0]][1]); | |||
| peaks::processors[0].set_function(function_table_[function_[0]][0]); | |||
| peaks::processors[1].set_function(function_table_[function_[0]][1]); | |||
| lockPots(); | |||
| } else { | |||
| } | |||
| else { | |||
| if (edit_mode_ <= EDIT_MODE_SPLIT) { | |||
| edit_mode_ = static_cast<EditMode>(EDIT_MODE_SPLIT - edit_mode_); | |||
| } else { | |||
| } | |||
| else { | |||
| edit_mode_ = static_cast<EditMode>(EDIT_MODE_SECOND - (edit_mode_ & 1)); | |||
| lockPots(); | |||
| } | |||
| @@ -410,49 +416,50 @@ void Peaks::onSwitchReleased(uint16_t id, uint16_t data) { | |||
| saveState(); | |||
| break; | |||
| case SWITCH_FUNCTION: | |||
| { | |||
| Function f = function(); | |||
| if (data > kLongPressDuration) { | |||
| f = static_cast<Function>((f + FUNCTION_FIRST_ALTERNATE_FUNCTION) % FUNCTION_LAST); | |||
| } else { | |||
| if (f <= FUNCTION_DRUM_GENERATOR) { | |||
| f = static_cast<Function>((f + 1) & 3); | |||
| } else { | |||
| f = static_cast<Function>(((f + 1) & 3) + FUNCTION_FIRST_ALTERNATE_FUNCTION); | |||
| } | |||
| case SWITCH_FUNCTION: { | |||
| Function f = function(); | |||
| if (data > kLongPressDuration) { | |||
| f = static_cast<Function>((f + FUNCTION_FIRST_ALTERNATE_FUNCTION) % FUNCTION_LAST); | |||
| } | |||
| else { | |||
| if (f <= FUNCTION_DRUM_GENERATOR) { | |||
| f = static_cast<Function>((f + 1) & 3); | |||
| } | |||
| else { | |||
| f = static_cast<Function>(((f + 1) & 3) + FUNCTION_FIRST_ALTERNATE_FUNCTION); | |||
| } | |||
| setFunction(edit_mode_ - EDIT_MODE_FIRST, f); | |||
| saveState(); | |||
| } | |||
| break; | |||
| setFunction(edit_mode_ - EDIT_MODE_FIRST, f); | |||
| saveState(); | |||
| } | |||
| break; | |||
| case SWITCH_GATE_TRIG_1: | |||
| case SWITCH_GATE_TRIG_1: | |||
| // no-op | |||
| break; | |||
| case SWITCH_GATE_TRIG_2: | |||
| case SWITCH_GATE_TRIG_2: | |||
| // no-op | |||
| break; | |||
| } | |||
| } | |||
| void Peaks::lockPots() { | |||
| std::fill( | |||
| &adc_threshold_[0], | |||
| &adc_threshold_[kNumAdcChannels], | |||
| kAdcThresholdLocked); | |||
| std::fill(&snapped_[0], &snapped_[kNumAdcChannels], false); | |||
| std::fill( | |||
| &adc_threshold_[0], | |||
| &adc_threshold_[kNumAdcChannels], | |||
| kAdcThresholdLocked); | |||
| std::fill(&snapped_[0], &snapped_[kNumAdcChannels], false); | |||
| } | |||
| void Peaks::pollPots() { | |||
| for (uint8_t i = 0; i < kNumAdcChannels; ++i) { | |||
| adc_lp_[i] = (int32_t(params[KNOB_1_PARAM+i].value) + adc_lp_[i] * 7) >> 3; | |||
| adc_lp_[i] = (int32_t(params[KNOB_1_PARAM + i].value) + adc_lp_[i] * 7) >> 3; | |||
| int32_t value = adc_lp_[i]; | |||
| int32_t current_value = adc_value_[i]; | |||
| if (value >= current_value + adc_threshold_[i] || | |||
| value <= current_value - adc_threshold_[i] || | |||
| !adc_threshold_[i]) { | |||
| value <= current_value - adc_threshold_[i] || | |||
| !adc_threshold_[i]) { | |||
| onPotChanged(i, value); | |||
| adc_value_[i] = value; | |||
| adc_threshold_[i] = kAdcThresholdUnlocked; | |||
| @@ -462,68 +469,68 @@ void Peaks::pollPots() { | |||
| void Peaks::onPotChanged(uint16_t id, uint16_t value) { | |||
| switch (edit_mode_) { | |||
| case EDIT_MODE_TWIN: | |||
| processors[0].set_parameter(id, value); | |||
| processors[1].set_parameter(id, value); | |||
| case EDIT_MODE_TWIN: | |||
| peaks::processors[0].set_parameter(id, value); | |||
| peaks::processors[1].set_parameter(id, value); | |||
| pot_value_[id] = value >> 8; | |||
| break; | |||
| case EDIT_MODE_SPLIT: | |||
| case EDIT_MODE_SPLIT: | |||
| if (id < 2) { | |||
| processors[0].set_parameter(id, value); | |||
| } else { | |||
| processors[1].set_parameter(id - 2, value); | |||
| peaks::processors[0].set_parameter(id, value); | |||
| } | |||
| else { | |||
| peaks::processors[1].set_parameter(id - 2, value); | |||
| } | |||
| pot_value_[id] = value >> 8; | |||
| break; | |||
| case EDIT_MODE_FIRST: | |||
| case EDIT_MODE_SECOND: | |||
| { | |||
| uint8_t index = id + (edit_mode_ - EDIT_MODE_FIRST) * 4; | |||
| Processors* p = &processors[edit_mode_ - EDIT_MODE_FIRST]; | |||
| case EDIT_MODE_FIRST: | |||
| case EDIT_MODE_SECOND: { | |||
| uint8_t index = id + (edit_mode_ - EDIT_MODE_FIRST) * 4; | |||
| peaks::Processors* p = &peaks::processors[edit_mode_ - EDIT_MODE_FIRST]; | |||
| int16_t delta = static_cast<int16_t>(pot_value_[index]) - \ | |||
| static_cast<int16_t>(value >> 8); | |||
| if (delta < 0) { | |||
| delta = -delta; | |||
| } | |||
| int16_t delta = static_cast<int16_t>(pot_value_[index]) - \ | |||
| static_cast<int16_t>(value >> 8); | |||
| if (delta < 0) { | |||
| delta = -delta; | |||
| } | |||
| if (!snap_mode_ || snapped_[id] || delta <= 2) { | |||
| p->set_parameter(id, value); | |||
| pot_value_[index] = value >> 8; | |||
| snapped_[id] = true; | |||
| } | |||
| if (!snap_mode_ || snapped_[id] || delta <= 2) { | |||
| p->set_parameter(id, value); | |||
| pot_value_[index] = value >> 8; | |||
| snapped_[id] = true; | |||
| } | |||
| break; | |||
| } | |||
| break; | |||
| case EDIT_MODE_LAST: | |||
| case EDIT_MODE_LAST: | |||
| break; | |||
| } | |||
| } | |||
| long long Peaks::getSystemTimeMs() { | |||
| return std::chrono::duration_cast<std::chrono::milliseconds>( | |||
| std::chrono::steady_clock::now().time_since_epoch() | |||
| ).count(); | |||
| std::chrono::steady_clock::now().time_since_epoch() | |||
| ).count(); | |||
| } | |||
| void Peaks::poll() { | |||
| for (uint8_t i = 0; i < 2; ++i) { | |||
| if (switches_[i].process(params[BUTTON_1_PARAM+i].value)) { | |||
| if (switches_[i].process(params[BUTTON_1_PARAM + i].value)) { | |||
| press_time_[i] = getSystemTimeMs(); | |||
| } | |||
| if (switches_[i].isHigh() && press_time_[i] != 0) { | |||
| int32_t pressed_time = getSystemTimeMs() - press_time_[i]; | |||
| if (pressed_time > kLongPressDuration) { | |||
| onSwitchReleased(SWITCH_TWIN_MODE+i, pressed_time); | |||
| onSwitchReleased(SWITCH_TWIN_MODE + i, pressed_time); | |||
| press_time_[i] = 0; // Inhibit next release event | |||
| } | |||
| } | |||
| if (!switches_[i].isHigh() && press_time_[i] != 0) { | |||
| int32_t delta = getSystemTimeMs() - press_time_[i] + 1; | |||
| onSwitchReleased(SWITCH_TWIN_MODE+i, delta); | |||
| onSwitchReleased(SWITCH_TWIN_MODE + i, delta); | |||
| press_time_[i] = 0; // Not in original code! | |||
| } | |||
| } | |||
| @@ -542,150 +549,140 @@ void Peaks::saveState() { | |||
| void Peaks::refreshLeds() { | |||
| uint8_t flash = (getSystemTimeMs() >> 7) & 7; | |||
| switch (edit_mode_) { | |||
| case EDIT_MODE_FIRST: | |||
| case EDIT_MODE_FIRST: | |||
| lights[TWIN_MODE_LIGHT].value = (flash == 1) ? 1.0f : 0.0f; | |||
| break; | |||
| case EDIT_MODE_SECOND: | |||
| case EDIT_MODE_SECOND: | |||
| lights[TWIN_MODE_LIGHT].value = (flash == 1 || flash == 3) ? 1.0f : 0.0f; | |||
| break; | |||
| default: | |||
| default: | |||
| lights[TWIN_MODE_LIGHT].value = (edit_mode_ & 1) ? 1.0f : 0.0f; | |||
| break; | |||
| } | |||
| if ((getSystemTimeMs() & 256) && function() >= FUNCTION_FIRST_ALTERNATE_FUNCTION) { | |||
| for (size_t i = 0; i < 4; ++i) { | |||
| lights[FUNC_1_LIGHT+i].value = 0.0f; | |||
| lights[FUNC_1_LIGHT + i].value = 0.0f; | |||
| } | |||
| } else { | |||
| } | |||
| else { | |||
| for (size_t i = 0; i < 4; ++i) { | |||
| lights[FUNC_1_LIGHT+i].value = ((function() & 3) == i) ? 1.0f : 0.0f; | |||
| lights[FUNC_1_LIGHT + i].value = ((function() & 3) == i) ? 1.0f : 0.0f; | |||
| } | |||
| } | |||
| uint8_t b[2]; | |||
| for (uint8_t i = 0; i < 2; ++i) { | |||
| switch (function_[i]) { | |||
| case FUNCTION_DRUM_GENERATOR: | |||
| case FUNCTION_FM_DRUM_GENERATOR: | |||
| case FUNCTION_DRUM_GENERATOR: | |||
| case FUNCTION_FM_DRUM_GENERATOR: | |||
| b[i] = std::abs(gBrightness[i]) >> 8; | |||
| b[i] = b[i] >= 255 ? 255 : b[i]; | |||
| break; | |||
| case FUNCTION_LFO: | |||
| case FUNCTION_TAP_LFO: | |||
| case FUNCTION_MINI_SEQUENCER: | |||
| { | |||
| int32_t brightness = int32_t(gBrightness[i]) * 409 >> 8; | |||
| brightness += 32768; | |||
| brightness >>= 8; | |||
| CONSTRAIN(brightness, 0, 255); | |||
| b[i] = brightness; | |||
| } | |||
| break; | |||
| default: | |||
| case FUNCTION_LFO: | |||
| case FUNCTION_TAP_LFO: | |||
| case FUNCTION_MINI_SEQUENCER: { | |||
| int32_t brightness = int32_t(gBrightness[i]) * 409 >> 8; | |||
| brightness += 32768; | |||
| brightness >>= 8; | |||
| CONSTRAIN(brightness, 0, 255); | |||
| b[i] = brightness; | |||
| } | |||
| break; | |||
| default: | |||
| b[i] = gBrightness[i] >> 7; | |||
| break; | |||
| } | |||
| } | |||
| if (processors[0].function() == PROCESSOR_FUNCTION_NUMBER_STATION) { | |||
| if (peaks::processors[0].function() == peaks::PROCESSOR_FUNCTION_NUMBER_STATION) { | |||
| uint8_t pattern = \ | |||
| processors[0].number_station().digit() ^ \ | |||
| processors[1].number_station().digit(); | |||
| peaks::processors[0].number_station().digit() ^ \ | |||
| peaks::processors[1].number_station().digit(); | |||
| for (size_t i = 0; i < 4; ++i) { | |||
| lights[FUNC_1_LIGHT+i].value = (pattern & 1) ? 1.0f : 0.0f; | |||
| lights[FUNC_1_LIGHT + i].value = (pattern & 1) ? 1.0f : 0.0f; | |||
| pattern = pattern >> 1; | |||
| } | |||
| b[0] = processors[0].number_station().gate() ? 255 : 0; | |||
| b[1] = processors[1].number_station().gate() ? 255 : 0; | |||
| b[0] = peaks::processors[0].number_station().gate() ? 255 : 0; | |||
| b[1] = peaks::processors[1].number_station().gate() ? 255 : 0; | |||
| } | |||
| lights[TRIG_1_LIGHT].value = rescale(static_cast<float>(b[0]), 0.0f, 255.0f, 0.0f, 1.0f); | |||
| lights[TRIG_2_LIGHT].value = rescale(static_cast<float>(b[1]), 0.0f, 255.0f, 0.0f, 1.0f); | |||
| } | |||
| template <typename BASE> | |||
| struct SwitchLED : BASE { | |||
| SwitchLED() { | |||
| this->box.size = mm2px(Vec(8.25, 8.25)); | |||
| } | |||
| }; | |||
| struct PeaksWidget : ModuleWidget { | |||
| PeaksWidget(Peaks *module); | |||
| Menu *createContextMenu() override; | |||
| }; | |||
| PeaksWidget(Peaks *module) : ModuleWidget(module) { | |||
| box.size = Vec(15 * 8, 380); | |||
| { | |||
| Panel *panel = new LightPanel(); | |||
| panel->backgroundImage = Image::load(assetPlugin(plugin, "res/Peaks.png")); | |||
| panel->box.size = box.size; | |||
| addChild(panel); | |||
| } | |||
| PeaksWidget::PeaksWidget(Peaks *module) : ModuleWidget(module) { | |||
| box.size = Vec(15*8, 380); | |||
| addChild(Widget::create<ScrewSilver>(Vec(15, 0))); | |||
| addChild(Widget::create<ScrewSilver>(Vec(15, 365))); | |||
| { | |||
| Panel *panel = new LightPanel(); | |||
| panel->backgroundImage = Image::load(assetPlugin(plugin, "res/Peaks.png")); | |||
| panel->box.size = box.size; | |||
| addChild(panel); | |||
| } | |||
| addParam(ParamWidget::create<TL1105>(Vec(8.5, 52), module, Peaks::BUTTON_1_PARAM, 0.0f, 1.0f, 0.0f)); | |||
| addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(11.88, 74), module, Peaks::TWIN_MODE_LIGHT)); | |||
| addParam(ParamWidget::create<TL1105>(Vec(8.5, 89), module, Peaks::BUTTON_2_PARAM, 0.0f, 1.0f, 0.0f)); | |||
| addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(11.88, 111), module, Peaks::FUNC_1_LIGHT)); | |||
| addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(11.88, 126.75), module, Peaks::FUNC_2_LIGHT)); | |||
| addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(11.88, 142.5), module, Peaks::FUNC_3_LIGHT)); | |||
| addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(11.88, 158), module, Peaks::FUNC_4_LIGHT)); | |||
| addChild(Widget::create<ScrewSilver>(Vec(15, 0))); | |||
| addChild(Widget::create<ScrewSilver>(Vec(15, 365))); | |||
| addParam(ParamWidget::create<Rogan1PSWhite>(Vec(61, 51), module, Peaks::KNOB_1_PARAM, 0.0f, 65535.0f, 16384.0f)); | |||
| addParam(ParamWidget::create<Rogan1PSWhite>(Vec(61, 115), module, Peaks::KNOB_2_PARAM, 0.0f, 65535.0f, 16384.0f)); | |||
| addParam(ParamWidget::create<Rogan1PSWhite>(Vec(61, 179), module, Peaks::KNOB_3_PARAM, 0.0f, 65535.0f, 32678.0f)); | |||
| addParam(ParamWidget::create<Rogan1PSWhite>(Vec(61, 244), module, Peaks::KNOB_4_PARAM, 0.0f, 65535.0f, 32678.0f)); | |||
| addParam(ParamWidget::create<TL1105>(Vec(8.5, 52), module, Peaks::BUTTON_1_PARAM, 0.0f, 1.0f, 0.0f)); | |||
| addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(11.88, 74), module, Peaks::TWIN_MODE_LIGHT)); | |||
| addParam(ParamWidget::create<TL1105>(Vec(8.5, 89), module, Peaks::BUTTON_2_PARAM, 0.0f, 1.0f, 0.0f)); | |||
| addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(11.88, 111), module, Peaks::FUNC_1_LIGHT)); | |||
| addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(11.88, 126.75), module, Peaks::FUNC_2_LIGHT)); | |||
| addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(11.88, 142.5), module, Peaks::FUNC_3_LIGHT)); | |||
| addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(11.88, 158), module, Peaks::FUNC_4_LIGHT)); | |||
| addParam(ParamWidget::create<LEDBezel>(Vec(11, 188), module, Peaks::TRIG_1_PARAM, 0.0f, 1.0f, 0.0f)); | |||
| addParam(ParamWidget::create<LEDBezel>(Vec(11, 273), module, Peaks::TRIG_2_PARAM, 0.0f, 1.0f, 0.0f)); | |||
| addChild(ModuleLightWidget::create<LEDBezelLight<GreenLight>>(Vec(11, 188).plus(mm2px(Vec(0.75, 0.75))), module, Peaks::TRIG_1_LIGHT)); | |||
| addChild(ModuleLightWidget::create<LEDBezelLight<GreenLight>>(Vec(11, 273).plus(mm2px(Vec(0.75, 0.75))), module, Peaks::TRIG_2_LIGHT)); | |||
| addParam(ParamWidget::create<Rogan1PSWhite>(Vec(61, 51), module, Peaks::KNOB_1_PARAM, 0.0f, 65535.0f, 16384.0f)); | |||
| addParam(ParamWidget::create<Rogan1PSWhite>(Vec(61, 115), module, Peaks::KNOB_2_PARAM, 0.0f, 65535.0f, 16384.0f)); | |||
| addParam(ParamWidget::create<Rogan1PSWhite>(Vec(61, 179), module, Peaks::KNOB_3_PARAM, 0.0f, 65535.0f, 32678.0f)); | |||
| addParam(ParamWidget::create<Rogan1PSWhite>(Vec(61, 244), module, Peaks::KNOB_4_PARAM, 0.0f, 65535.0f, 32678.0f)); | |||
| addInput(Port::create<PJ301MPort>(Vec(10, 230), Port::INPUT, module, Peaks::GATE_1_INPUT)); | |||
| addInput(Port::create<PJ301MPort>(Vec(10, 315), Port::INPUT, module, Peaks::GATE_2_INPUT)); | |||
| addParam(ParamWidget::create<LEDBezel>(Vec(10.32, 188), module, Peaks::TRIG_1_PARAM, 0.0f, 1.0f, 0.0f)); | |||
| addParam(ParamWidget::create<LEDBezel>(Vec(10.32, 273.5), module, Peaks::TRIG_2_PARAM, 0.0f, 1.0f, 0.0f)); | |||
| addChild(ModuleLightWidget::create<SwitchLED<GreenLight>>(Vec(10.32, 188), module, Peaks::TRIG_1_LIGHT)); | |||
| addChild(ModuleLightWidget::create<SwitchLED<GreenLight>>(Vec(10.32, 273.5), module, Peaks::TRIG_2_LIGHT)); | |||
| addOutput(Port::create<PJ301MPort>(Vec(53, 315), Port::OUTPUT, module, Peaks::OUT_1_OUTPUT)); | |||
| addOutput(Port::create<PJ301MPort>(Vec(86, 315), Port::OUTPUT, module, Peaks::OUT_2_OUTPUT)); | |||
| } | |||
| addInput(Port::create<PJ301MPort>(Vec(10, 230), Port::INPUT, module, Peaks::GATE_1_INPUT)); | |||
| addInput(Port::create<PJ301MPort>(Vec(10, 315), Port::INPUT, module, Peaks::GATE_2_INPUT)); | |||
| Menu *createContextMenu() override { | |||
| Menu *menu = ModuleWidget::createContextMenu(); | |||
| Peaks *peaks = dynamic_cast<Peaks*>(this->module); | |||
| addOutput(Port::create<PJ301MPort>(Vec(53, 315), Port::OUTPUT, module, Peaks::OUT_1_OUTPUT)); | |||
| addOutput(Port::create<PJ301MPort>(Vec(86, 315), Port::OUTPUT, module, Peaks::OUT_2_OUTPUT)); | |||
| } | |||
| struct SnapModeItem : MenuItem { | |||
| Peaks *peaks; | |||
| void onAction(EventAction &e) override { | |||
| peaks->snap_mode_ = !peaks->snap_mode_; | |||
| } | |||
| void step() override { | |||
| rightText = (peaks->snap_mode_) ? "✔" : ""; | |||
| MenuItem::step(); | |||
| } | |||
| }; | |||
| struct NumberStationItem : MenuItem { | |||
| Peaks *peaks; | |||
| void onAction(EventAction &e) override { | |||
| peaks->initNumberStation = true; | |||
| } | |||
| }; | |||
| struct PeaksSnapModeItem : MenuItem { | |||
| Peaks *peaks; | |||
| void onAction(EventAction &e) override { | |||
| peaks->snap_mode_ = !peaks->snap_mode_; | |||
| } | |||
| void step() override { | |||
| rightText = (peaks->snap_mode_) ? "✔" : ""; | |||
| MenuItem::step(); | |||
| } | |||
| }; | |||
| menu->addChild(construct<MenuLabel>()); | |||
| menu->addChild(construct<SnapModeItem>(&SnapModeItem::text, "Snap Mode", &SnapModeItem::peaks, peaks)); | |||
| menu->addChild(construct<MenuLabel>()); | |||
| menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Secret Modes")); | |||
| menu->addChild(construct<NumberStationItem>(&NumberStationItem::text, "Number Station", &NumberStationItem::peaks, peaks)); | |||
| struct PeaksNumberStationItem : MenuItem { | |||
| Peaks *peaks; | |||
| void onAction(EventAction &e) override { | |||
| peaks->initNumberStation = true; | |||
| return menu; | |||
| } | |||
| }; | |||
| Menu *PeaksWidget::createContextMenu() { | |||
| Menu *menu = ModuleWidget::createContextMenu(); | |||
| Peaks *peaks = dynamic_cast<Peaks*>(this->module); | |||
| menu->addChild(construct<MenuLabel>()); | |||
| menu->addChild(construct<PeaksSnapModeItem>(&PeaksSnapModeItem::text, "Snap Mode", &PeaksSnapModeItem::peaks, peaks)); | |||
| menu->addChild(construct<MenuLabel>()); | |||
| menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Secret Modes")); | |||
| menu->addChild(construct<PeaksNumberStationItem>(&PeaksNumberStationItem::text, "Number Station", &PeaksNumberStationItem::peaks, peaks)); | |||
| return menu; | |||
| } | |||
| Model *modelPeaks = Model::create<Peaks, PeaksWidget>("Audible Instruments", "Peaks", "Percussive Synthesizer", UTILITY_TAG, LFO_TAG, DRUM_TAG); | |||