| @@ -47,36 +47,15 @@ struct Settings { | |||
| }; | |||
| static const size_t kNumBlocks = 2; | |||
| static const size_t kNumChannels = 2; | |||
| static const size_t kBlockSize = 4; | |||
| 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 | |||
| // File scope, so resources can be accessed by process() function. | |||
| static int16_t gOutputBuffer[peaks::kBlockSize]; | |||
| static int16_t gBrightness[peaks::kNumChannels] = {0, 0}; | |||
| static peaks::Processors processors[2]; | |||
| // File scope because of IOBuffer function signature. | |||
| // It cannot refer to a member function of class Peaks(). | |||
| static void set_led_brightness(int channel, int16_t value) { | |||
| gBrightness[channel] = value; | |||
| } | |||
| static void process(peaks::IOBuffer::Block* block, size_t size) { | |||
| for (size_t i = 0; i < peaks::kNumChannels; ++i) { | |||
| 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. | |||
| int32_t shifted_value = 32767 + static_cast<int32_t>(gOutputBuffer[j]); | |||
| CONSTRAIN(shifted_value, 0, 65535); | |||
| block->output[i][j] = static_cast<uint16_t>(shifted_value); | |||
| } | |||
| } | |||
| } | |||
| struct Peaks : Module { | |||
| enum ParamIds { | |||
| KNOB_1_PARAM, | |||
| @@ -126,6 +105,11 @@ struct Peaks : Module { | |||
| int32_t adc_threshold_[kNumAdcChannels] = {0, 0, 0, 0}; | |||
| long long press_time_[2] = {0, 0}; | |||
| peaks::Processors processors[2]; | |||
| int16_t output[peaks::kBlockSize]; | |||
| int16_t brightness[peaks::kNumChannels] = {0, 0}; | |||
| SchmittTrigger switches_[2]; | |||
| peaks::IOBuffer ioBuffer; | |||
| @@ -137,6 +121,22 @@ struct Peaks : Module { | |||
| bool initNumberStation = false; | |||
| struct Block { | |||
| peaks::GateFlags input[kNumChannels][kBlockSize]; | |||
| uint16_t output[kNumChannels][kBlockSize]; | |||
| }; | |||
| struct Slice { | |||
| Block* block; | |||
| size_t frame_index; | |||
| }; | |||
| Block block_[kNumBlocks]; | |||
| size_t io_frame_ = 0; | |||
| size_t io_block_ = 0; | |||
| size_t render_block_ = kNumBlocks / 2; | |||
| Peaks() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { | |||
| settings_.edit_mode = EDIT_MODE_TWIN; | |||
| settings_.function[0] = FUNCTION_ENVELOPE; | |||
| @@ -159,7 +159,7 @@ struct Peaks : Module { | |||
| void init() { | |||
| std::fill(&pot_value_[0], &pot_value_[8], 0); | |||
| std::fill(&press_time_[0], &press_time_[1], 0); | |||
| std::fill(&gBrightness[0], &gBrightness[1], 0); | |||
| std::fill(&brightness[0], &brightness[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); | |||
| @@ -257,7 +257,11 @@ struct Peaks : Module { | |||
| } | |||
| if (outputBuffer.empty()) { | |||
| ioBuffer.Process(process); | |||
| while (render_block_ != io_block_) { | |||
| process(&block_[render_block_], kBlockSize); | |||
| render_block_ = (render_block_ + 1) % kNumBlocks; | |||
| } | |||
| uint32_t external_gate_inputs = 0; | |||
| external_gate_inputs |= (inputs[GATE_1_INPUT].value ? 1 : 0); | |||
| @@ -279,7 +283,7 @@ struct Peaks : Module { | |||
| // Process an entire block of data from the IOBuffer. | |||
| for (size_t k = 0; k < peaks::kBlockSize; ++k) { | |||
| peaks::IOBuffer::Slice slice = ioBuffer.NextSlice(1); | |||
| Slice slice = NextSlice(1); | |||
| for (size_t i = 0; i < peaks::kNumChannels; ++i) { | |||
| gate_flags[i] = peaks::ExtractGateFlags( | |||
| @@ -311,10 +315,39 @@ struct Peaks : Module { | |||
| } | |||
| } | |||
| inline Slice NextSlice(size_t size) { | |||
| Slice s; | |||
| s.block = &block_[io_block_]; | |||
| s.frame_index = io_frame_; | |||
| io_frame_ += size; | |||
| if (io_frame_ >= kBlockSize) { | |||
| io_frame_ -= kBlockSize; | |||
| io_block_ = (io_block_ + 1) % kNumBlocks; | |||
| } | |||
| return s; | |||
| } | |||
| inline Function function() const { | |||
| return edit_mode_ == EDIT_MODE_SECOND ? function_[1] : function_[0]; | |||
| } | |||
| inline void set_led_brightness(int channel, int16_t value) { | |||
| brightness[channel] = value; | |||
| } | |||
| inline void process(Block* block, size_t size) { | |||
| for (size_t i = 0; i < peaks::kNumChannels; ++i) { | |||
| processors[i].Process(block->input[i], output, size); | |||
| set_led_brightness(i, output[0]); | |||
| for (size_t j = 0; j < size; ++j) { | |||
| // From calibration_data.h, shifting signed to unsigned values. | |||
| int32_t shifted_value = 32767 + static_cast<int32_t>(output[j]); | |||
| CONSTRAIN(shifted_value, 0, 65535); | |||
| block->output[i][j] = static_cast<uint16_t>(shifted_value); | |||
| } | |||
| } | |||
| } | |||
| void changeControlMode(); | |||
| void setFunction(uint8_t index, Function f); | |||
| void onPotChanged(uint16_t id, uint16_t value); | |||
| @@ -560,21 +593,21 @@ void Peaks::refreshLeds() { | |||
| switch (function_[i]) { | |||
| case FUNCTION_DRUM_GENERATOR: | |||
| case FUNCTION_FM_DRUM_GENERATOR: | |||
| b[i] = (int16_t) abs(gBrightness[i]) >> 8; | |||
| b[i] = (int16_t) abs(brightness[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; | |||
| int32_t brightnessVal = int32_t(brightness[i]) * 409 >> 8; | |||
| brightnessVal += 32768; | |||
| brightnessVal >>= 8; | |||
| CONSTRAIN(brightnessVal, 0, 255); | |||
| b[i] = brightnessVal; | |||
| } | |||
| break; | |||
| default: | |||
| b[i] = gBrightness[i] >> 7; | |||
| b[i] = brightness[i] >> 7; | |||
| break; | |||
| } | |||
| } | |||
| @@ -648,7 +681,7 @@ struct PeaksWidget : ModuleWidget { | |||
| peaks->initNumberStation = true; | |||
| } | |||
| void step() override { | |||
| rightText = (processors[0].function() == peaks::PROCESSOR_FUNCTION_NUMBER_STATION) ? "✔" : ""; | |||
| rightText = (peaks->processors[0].function() == peaks::PROCESSOR_FUNCTION_NUMBER_STATION) ? "✔" : ""; | |||
| MenuItem::step(); | |||
| } | |||
| }; | |||