From a7b31cb9e7a0ca4199a49187a612d72407c0b8d5 Mon Sep 17 00:00:00 2001 From: Jan-Henrik Bruhn Date: Sun, 15 Mar 2020 00:13:26 +0100 Subject: [PATCH] Implement mini sequencer --- pure_adsr/mini_sequencer.h | 110 +++++++++++++++++++++++++++++++++++++ pure_adsr/pure_adsr.cc | 15 ++++- 2 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 pure_adsr/mini_sequencer.h diff --git a/pure_adsr/mini_sequencer.h b/pure_adsr/mini_sequencer.h new file mode 100644 index 0000000..c08b626 --- /dev/null +++ b/pure_adsr/mini_sequencer.h @@ -0,0 +1,110 @@ +// Copyright 2013 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// 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. +// +// ----------------------------------------------------------------------------- +// +// Mini sequencer. + +#ifndef PEAKS_MODULATIONS_MINI_SEQUENCER_H_ +#define PEAKS_MODULATIONS_MINI_SEQUENCER_H_ + +#include "pure_adsr/gate_processor.h" +#include + +#define abs(X) ((X) < 0 ? -(X) : (X)) + +namespace pure_adsr { + +const uint8_t kMaxNumSteps = 4; + +class MiniSequencer { + public: + MiniSequencer() {} + ~MiniSequencer() {} + + void Init() + { + for (size_t i = 0; i < kMaxNumSteps; i++) + steps_[i] = 0; + num_steps_ = 4; + step_ = 0; + reset_at_next_clock_ = false; + } + + inline void set_step(uint8_t index, int16_t value) + { + int32_t difference = abs(int32_t(steps_[index]) - value); + if (difference > 0) { + steps_[index] = value; + } + } + + inline void set_num_steps(uint8_t num_steps) + { + num_steps_ = num_steps; + } + + void Configure(uint16_t* parameter, ControlMode control_mode) + { + set_step(0, parameter[0] >> 1); + set_step(1, parameter[1] >> 1); + set_step(2, parameter[2] >> 1); + set_step(3, parameter[3] >> 1); + set_num_steps(4); + } + + void Process(const GateFlags* gate_flags, int16_t* out, size_t size) + { + while (size--) { + GateFlags gate_flag = *gate_flags++; + if (gate_flag & GATE_FLAG_RISING) { + ++step_; + if (reset_at_next_clock_) { + reset_at_next_clock_ = false; + step_ = 0; + } + } + if (num_steps_ > 2 && gate_flag & GATE_FLAG_AUXILIARY_RISING) { + reset_at_next_clock_ = true; + } + if (step_ >= num_steps_) { + step_ = 0; + } + *out++ = static_cast(steps_[step_]) * 40960 >> 16; + } + } + + private: + uint8_t num_steps_; + uint8_t step_; + int16_t steps_[kMaxNumSteps]; + + bool reset_at_next_clock_; + + DISALLOW_COPY_AND_ASSIGN(MiniSequencer); +}; + +} // namespace peaks + +#endif // PEAKS_MODULATIONS_MINI_SEQUENCER_H_ diff --git a/pure_adsr/pure_adsr.cc b/pure_adsr/pure_adsr.cc index 5b1373b..ca34e48 100644 --- a/pure_adsr/pure_adsr.cc +++ b/pure_adsr/pure_adsr.cc @@ -11,6 +11,7 @@ #include "pure_adsr/drivers/switches.h" #include "pure_adsr/gate_processor.h" #include "pure_adsr/io_buffer.h" +#include "pure_adsr/mini_sequencer.h" #include "pure_adsr/multistage_envelope.h" using namespace avrlib; @@ -36,6 +37,7 @@ Switch>> button_input; typedef AdcInputScanner AnalogInputs; MultistageEnvelope envelope; +MiniSequencer sequencer; IOBuffer io_buffer; int16_t output_buffer[kBlockSize]; @@ -52,6 +54,7 @@ void Process(IOBuffer::Block* block, size_t size) if (read_value != pot_values[i]) { // TODO: apply filtering pot_values[i] = read_value; envelope.Configure(pot_values, CONTROL_MODE_FULL); + sequencer.Configure(pot_values, CONTROL_MODE_FULL); } } @@ -61,6 +64,8 @@ void Process(IOBuffer::Block* block, size_t size) case MODE_ADSR: envelope.Process(block->input[i], output_buffer, size); break; + case MODE_SEQ: + sequencer.Process(block->input[i], output_buffer, size); default: break; } @@ -89,11 +94,14 @@ void Init() io_buffer.Init(); envelope.Init(); + sequencer.Init(); uint16_t pots[4]; for (size_t i = 0; i < 4; i++) pots[4 - (i + 1)] = AnalogInputs::Read8(i) << 8; envelope.Configure(pots, CONTROL_MODE_FULL); + sequencer.Configure(pots, CONTROL_MODE_FULL); + Timer<2>::Start(); } @@ -120,7 +128,7 @@ TIMER_0_TICK mode = MODE_SEQ; break; case 1: - mode = MODE_THREE; + mode = MODE_LFO; break; case 2: mode = MODE_ADSR; @@ -135,7 +143,10 @@ TIMER_2_TICK --clock_divider_midi; if (!clock_divider_midi) { uint32_t gate_inputs = gate_input.Read(); - gate_inputs |= button_input.pressed(); + + if (mode == MODE_ADSR || mode == MODE_SEQ) + gate_inputs |= button_input.pressed(); + IOBuffer::Slice slice = io_buffer.NextSlice(1); for (size_t i = 0; i < kNumChannels; ++i) { gate_flags = ExtractGateFlags(