mirror of
https://github.com/jhbruhn/eurorack.git
synced 2025-03-15 02:55:49 +00:00
Add fake tides
This commit is contained in:
parent
a7b31cb9e7
commit
d7294bbc12
7 changed files with 581 additions and 4 deletions
81
pure_adsr/hysteresis_quantizer.h
Normal file
81
pure_adsr/hysteresis_quantizer.h
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
// Copyright 2015 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.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Quantize a float in [0, 1] to an integer in [0, num_steps[. Apply hysteresis
|
||||||
|
// to prevent jumps near the decision boundary.
|
||||||
|
|
||||||
|
#ifndef STMLIB_DSP_HYSTERESIS_QUANTIZER_H_
|
||||||
|
#define STMLIB_DSP_HYSTERESIS_QUANTIZER_H_
|
||||||
|
|
||||||
|
#include <avrlib/avrlib.h>
|
||||||
|
|
||||||
|
namespace pure_adsr {
|
||||||
|
|
||||||
|
class HysteresisQuantizer {
|
||||||
|
public:
|
||||||
|
HysteresisQuantizer() { }
|
||||||
|
~HysteresisQuantizer() { }
|
||||||
|
|
||||||
|
void Init() {
|
||||||
|
quantized_value_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int Process(float value, int num_steps) {
|
||||||
|
return Process(value, num_steps, 0.25f);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int Process(float value, int num_steps, float hysteresis) {
|
||||||
|
return Process(0, value, num_steps, hysteresis);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int Process(int base, float value, int num_steps, float hysteresis) {
|
||||||
|
value *= static_cast<float>(num_steps - 1);
|
||||||
|
value += static_cast<float>(base);
|
||||||
|
float hysteresis_feedback = value > static_cast<float>(quantized_value_)
|
||||||
|
? -hysteresis
|
||||||
|
: hysteresis;
|
||||||
|
int q = static_cast<int>(value + hysteresis_feedback + 0.5f);
|
||||||
|
if(q < 0) q = 0;
|
||||||
|
if(q > num_steps - 1) q = num_steps - 1;
|
||||||
|
quantized_value_ = q;
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const T& Lookup(const T* array, float value, int num_steps) {
|
||||||
|
return array[Process(value, num_steps)];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int quantized_value_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(HysteresisQuantizer);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace stmlib
|
||||||
|
|
||||||
|
#endif // STMLIB_DSP_HYSTERESIS_QUANTIZER_H_
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "pure_adsr/io_buffer.h"
|
#include "pure_adsr/io_buffer.h"
|
||||||
#include "pure_adsr/mini_sequencer.h"
|
#include "pure_adsr/mini_sequencer.h"
|
||||||
#include "pure_adsr/multistage_envelope.h"
|
#include "pure_adsr/multistage_envelope.h"
|
||||||
|
#include "pure_adsr/tides.h"
|
||||||
|
|
||||||
using namespace avrlib;
|
using namespace avrlib;
|
||||||
using namespace pure_adsr;
|
using namespace pure_adsr;
|
||||||
|
@ -20,7 +21,7 @@ using namespace pure_adsr;
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MODE_ADSR,
|
MODE_ADSR,
|
||||||
MODE_SEQ,
|
MODE_SEQ,
|
||||||
MODE_LFO
|
MODE_TIDES
|
||||||
} Mode;
|
} Mode;
|
||||||
|
|
||||||
typedef SpiMaster<Gpio<PortB, 2>, MSB_FIRST, 2> dac1Spi;
|
typedef SpiMaster<Gpio<PortB, 2>, MSB_FIRST, 2> dac1Spi;
|
||||||
|
@ -38,6 +39,7 @@ typedef AdcInputScanner AnalogInputs;
|
||||||
|
|
||||||
MultistageEnvelope envelope;
|
MultistageEnvelope envelope;
|
||||||
MiniSequencer sequencer;
|
MiniSequencer sequencer;
|
||||||
|
Tides tides;
|
||||||
|
|
||||||
IOBuffer io_buffer;
|
IOBuffer io_buffer;
|
||||||
int16_t output_buffer[kBlockSize];
|
int16_t output_buffer[kBlockSize];
|
||||||
|
@ -55,6 +57,7 @@ void Process(IOBuffer::Block* block, size_t size)
|
||||||
pot_values[i] = read_value;
|
pot_values[i] = read_value;
|
||||||
envelope.Configure(pot_values, CONTROL_MODE_FULL);
|
envelope.Configure(pot_values, CONTROL_MODE_FULL);
|
||||||
sequencer.Configure(pot_values, CONTROL_MODE_FULL);
|
sequencer.Configure(pot_values, CONTROL_MODE_FULL);
|
||||||
|
tides.Configure(pot_values, CONTROL_MODE_FULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +69,9 @@ void Process(IOBuffer::Block* block, size_t size)
|
||||||
break;
|
break;
|
||||||
case MODE_SEQ:
|
case MODE_SEQ:
|
||||||
sequencer.Process(block->input[i], output_buffer, size);
|
sequencer.Process(block->input[i], output_buffer, size);
|
||||||
default:
|
break;
|
||||||
|
case MODE_TIDES:
|
||||||
|
tides.Process(block->input[i], output_buffer, size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +106,7 @@ void Init()
|
||||||
pots[4 - (i + 1)] = AnalogInputs::Read8(i) << 8;
|
pots[4 - (i + 1)] = AnalogInputs::Read8(i) << 8;
|
||||||
envelope.Configure(pots, CONTROL_MODE_FULL);
|
envelope.Configure(pots, CONTROL_MODE_FULL);
|
||||||
sequencer.Configure(pots, CONTROL_MODE_FULL);
|
sequencer.Configure(pots, CONTROL_MODE_FULL);
|
||||||
|
tides.Configure(pots, CONTROL_MODE_FULL);
|
||||||
|
|
||||||
Timer<2>::Start();
|
Timer<2>::Start();
|
||||||
}
|
}
|
||||||
|
@ -128,7 +134,7 @@ TIMER_0_TICK
|
||||||
mode = MODE_SEQ;
|
mode = MODE_SEQ;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
mode = MODE_LFO;
|
mode = MODE_TIDES;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
mode = MODE_ADSR;
|
mode = MODE_ADSR;
|
||||||
|
|
|
@ -215,10 +215,46 @@ const prog_uint32_t lut_res_env_increments[] PROGMEM = {
|
||||||
253893, 249198, 244605, 240110, 235713, 231409, 227198, 223077,
|
253893, 249198, 244605, 240110, 235713, 231409, 227198, 223077,
|
||||||
219043,
|
219043,
|
||||||
};
|
};
|
||||||
|
const prog_uint32_t lut_res_env_increments_slow[] PROGMEM = {
|
||||||
|
35046933, 33184343, 31436989, 29796754, 28256163, 26808323, 25446875, 24165949,
|
||||||
|
22960121, 21824376, 20754076, 19744924, 18792940, 17894435, 17045985, 16244414,
|
||||||
|
15486770, 14770309, 14092480, 13450909, 12843386, 12267850, 11722382, 11205191,
|
||||||
|
10714605, 10249065, 9807112, 9387383, 8988604, 8609583, 8249203, 7906418,
|
||||||
|
7580249, 7269776, 6974139, 6692528, 6424184, 6168395, 5924489, 5691837,
|
||||||
|
5469847, 5257961, 5055654, 4862432, 4677829, 4501406, 4332750, 4171471,
|
||||||
|
4017200, 3869589, 3728311, 3593055, 3463528, 3339453, 3220568, 3106625,
|
||||||
|
2997389, 2892639, 2792164, 2695765, 2603253, 2514449, 2429184, 2347295,
|
||||||
|
2268632, 2193047, 2120405, 2050573, 1983428, 1918852, 1856732, 1796962,
|
||||||
|
1739439, 1684069, 1630758, 1579418, 1529968, 1482327, 1436419, 1392173,
|
||||||
|
1349520, 1308394, 1268733, 1230477, 1193569, 1157955, 1123584, 1090404,
|
||||||
|
1058371, 1027437, 997560, 968699, 940814, 913868, 887824, 862647,
|
||||||
|
838306, 814767, 792001, 769979, 748673, 728057, 708104, 688790,
|
||||||
|
670093, 651989, 634458, 617477, 601028, 585092, 569649, 554684,
|
||||||
|
540178, 526116, 512482, 499262, 486440, 474003, 461939, 450233,
|
||||||
|
438875, 427852, 417153, 406766, 396683, 386891, 377383, 368148,
|
||||||
|
359177, 350462, 341994, 333766, 325770, 317997, 310442, 303096,
|
||||||
|
295954, 289009, 282255, 275685, 269295, 263077, 257028, 251142,
|
||||||
|
245413, 239837, 234409, 229126, 223981, 218972, 214094, 209343,
|
||||||
|
204715, 200207, 195816, 191537, 187368, 183304, 179344, 175484,
|
||||||
|
171722, 168054, 164477, 160990, 157589, 154272, 151037, 147882,
|
||||||
|
144803, 141800, 138869, 136010, 133219, 130496, 127837, 125242,
|
||||||
|
122709, 120236, 117821, 115462, 113160, 110911, 108714, 106568,
|
||||||
|
104472, 102424, 100423, 98468, 96557, 94690, 92865, 91081,
|
||||||
|
89338, 87633, 85967, 84338, 82744, 81187, 79663, 78173,
|
||||||
|
76716, 75290, 73895, 72531, 71196, 69890, 68612, 67362,
|
||||||
|
66138, 64940, 63767, 62620, 61496, 60396, 59320, 58265,
|
||||||
|
57233, 56222, 55232, 54262, 53313, 52382, 51471, 50579,
|
||||||
|
49704, 48847, 48008, 47185, 46379, 45589, 44815, 44056,
|
||||||
|
43313, 42584, 41869, 41168, 40481, 39808, 39148, 38500,
|
||||||
|
37865, 37243, 36632, 36033, 35446, 34869, 34304, 33750,
|
||||||
|
33206, 32672, 32148, 31634, 31130, 30635, 30150, 29673,
|
||||||
|
29205,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const prog_uint32_t* const lookup_table_32_table[] = {
|
const prog_uint32_t* const lookup_table_32_table[] = {
|
||||||
lut_res_env_increments,
|
lut_res_env_increments,
|
||||||
|
lut_res_env_increments_slow,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ extern const prog_uint16_t lut_res_env_expo[] PROGMEM;
|
||||||
extern const prog_uint16_t lut_res_env_quartic[] PROGMEM;
|
extern const prog_uint16_t lut_res_env_quartic[] PROGMEM;
|
||||||
extern const prog_uint16_t lut_res_raised_cosine[] PROGMEM;
|
extern const prog_uint16_t lut_res_raised_cosine[] PROGMEM;
|
||||||
extern const prog_uint32_t lut_res_env_increments[] PROGMEM;
|
extern const prog_uint32_t lut_res_env_increments[] PROGMEM;
|
||||||
|
extern const prog_uint32_t lut_res_env_increments_slow[] PROGMEM;
|
||||||
#define STR_RES_DUMMY 0 // dummy
|
#define STR_RES_DUMMY 0 // dummy
|
||||||
#define LUT_RES_ENV_LINEAR 0
|
#define LUT_RES_ENV_LINEAR 0
|
||||||
#define LUT_RES_ENV_LINEAR_SIZE 257
|
#define LUT_RES_ENV_LINEAR_SIZE 257
|
||||||
|
@ -55,6 +56,8 @@ extern const prog_uint32_t lut_res_env_increments[] PROGMEM;
|
||||||
#define LUT_RES_RAISED_COSINE_SIZE 257
|
#define LUT_RES_RAISED_COSINE_SIZE 257
|
||||||
#define LUT_RES_ENV_INCREMENTS 0
|
#define LUT_RES_ENV_INCREMENTS 0
|
||||||
#define LUT_RES_ENV_INCREMENTS_SIZE 257
|
#define LUT_RES_ENV_INCREMENTS_SIZE 257
|
||||||
|
#define LUT_RES_ENV_INCREMENTS_SLOW 1
|
||||||
|
#define LUT_RES_ENV_INCREMENTS_SLOW_SIZE 257
|
||||||
|
|
||||||
} // namespace pure_adsr
|
} // namespace pure_adsr
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,20 @@ lookup_tables_32.append(
|
||||||
('env_increments', values)
|
('env_increments', values)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
max_time = 60.0 # seconds
|
||||||
|
min_time = 0.05
|
||||||
|
gamma = 0.175
|
||||||
|
min_increment = excursion / (max_time * sample_rate)
|
||||||
|
max_increment = excursion / (min_time * sample_rate)
|
||||||
|
|
||||||
|
rates = numpy.linspace(numpy.power(max_increment, -gamma),
|
||||||
|
numpy.power(min_increment, -gamma), num_values)
|
||||||
|
|
||||||
|
values = numpy.power(rates, -1/gamma).astype(int)
|
||||||
|
lookup_tables_32.append(
|
||||||
|
('env_increments_slow', values)
|
||||||
|
)
|
||||||
"""----------------------------------------------------------------------------
|
"""----------------------------------------------------------------------------
|
||||||
Envelope curves
|
Envelope curves
|
||||||
-----------------------------------------------------------------------------"""
|
-----------------------------------------------------------------------------"""
|
||||||
|
@ -69,7 +83,6 @@ env_linear = numpy.arange(0, 257.0) / 256.0
|
||||||
env_linear[-1] = env_linear[-2]
|
env_linear[-1] = env_linear[-2]
|
||||||
env_quartic = env_linear ** 3.32
|
env_quartic = env_linear ** 3.32
|
||||||
env_expo = 1.0 - numpy.exp(-4 * env_linear)
|
env_expo = 1.0 - numpy.exp(-4 * env_linear)
|
||||||
|
|
||||||
lookup_tables.append(('env_linear', env_linear / env_linear.max() * 65535.0))
|
lookup_tables.append(('env_linear', env_linear / env_linear.max() * 65535.0))
|
||||||
lookup_tables.append(('env_expo', env_expo / env_expo.max() * 65535.0))
|
lookup_tables.append(('env_expo', env_expo / env_expo.max() * 65535.0))
|
||||||
lookup_tables.append(
|
lookup_tables.append(
|
||||||
|
|
89
pure_adsr/tides.cc
Normal file
89
pure_adsr/tides.cc
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Multistage envelope.
|
||||||
|
|
||||||
|
#include "pure_adsr/tides.h"
|
||||||
|
|
||||||
|
#include "pure_adsr/resources.h"
|
||||||
|
|
||||||
|
namespace pure_adsr {
|
||||||
|
|
||||||
|
void Tides::Init()
|
||||||
|
{
|
||||||
|
set_adsr(0, 8192, 16384, 32767);
|
||||||
|
segment_ = num_segments_;
|
||||||
|
phase_ = 0;
|
||||||
|
phase_increment_ = 0;
|
||||||
|
start_value_ = 0;
|
||||||
|
value_ = 0;
|
||||||
|
hard_reset_ = false;
|
||||||
|
quant.Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tides::Process(
|
||||||
|
const GateFlags* gate_flags, int16_t* out, size_t size)
|
||||||
|
{
|
||||||
|
while (size--) {
|
||||||
|
GateFlags gate_flag = *gate_flags++;
|
||||||
|
if (gate_flag & GATE_FLAG_RISING) {
|
||||||
|
start_value_ = (segment_ == num_segments_ || hard_reset_)
|
||||||
|
? level_[0]
|
||||||
|
: value_;
|
||||||
|
segment_ = 0;
|
||||||
|
phase_ = 0;
|
||||||
|
} else if (gate_flag & GATE_FLAG_FALLING && sustain_point_) {
|
||||||
|
start_value_ = value_;
|
||||||
|
segment_ = sustain_point_;
|
||||||
|
phase_ = 0;
|
||||||
|
} else if (phase_ < phase_increment_) {
|
||||||
|
start_value_ = level_[segment_ + 1];
|
||||||
|
++segment_;
|
||||||
|
phase_ = 0;
|
||||||
|
if (segment_ == loop_end_) {
|
||||||
|
segment_ = loop_start_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool done = segment_ == num_segments_;
|
||||||
|
bool sustained = sustain_point_ && segment_ == sustain_point_ && gate_flag & GATE_FLAG_HIGH;
|
||||||
|
|
||||||
|
phase_increment_ = sustained || done ? 0 : pgm_read_dword(lut_res_env_increments_slow + (time_[segment_] >> 8));
|
||||||
|
|
||||||
|
int32_t a = start_value_;
|
||||||
|
int32_t b = level_[segment_ + 1];
|
||||||
|
|
||||||
|
uint32_t x = pgm_read_word(lookup_table_table[LUT_RES_ENV_LINEAR + shape_[segment_]] + (phase_ >> 24));
|
||||||
|
uint32_t y = pgm_read_word(lookup_table_table[LUT_RES_ENV_LINEAR + shape_[segment_]] + (phase_ >> 24) + 1);
|
||||||
|
uint16_t t = x + ((y - x) * static_cast<uint32_t>((phase_ >> 8) & 0xffff) >> 16);
|
||||||
|
|
||||||
|
value_ = a + ((b - a) * (t >> 1) >> 15);
|
||||||
|
phase_ += phase_increment_;
|
||||||
|
*out++ = value_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace peaks
|
349
pure_adsr/tides.h
Normal file
349
pure_adsr/tides.h
Normal file
|
@ -0,0 +1,349 @@
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Multistage envelope.
|
||||||
|
|
||||||
|
#ifndef PEAKS_MODULATIONS_TIDES_H_
|
||||||
|
#define PEAKS_MODULATIONS_TIDES_H_
|
||||||
|
|
||||||
|
#include "pure_adsr/gate_processor.h"
|
||||||
|
#include "pure_adsr/hysteresis_quantizer.h"
|
||||||
|
#include "pure_adsr/multistage_envelope.h"
|
||||||
|
#include <avrlib/avrlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
namespace pure_adsr {
|
||||||
|
|
||||||
|
class Tides {
|
||||||
|
public:
|
||||||
|
Tides() {}
|
||||||
|
~Tides() {}
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
void Process(const GateFlags* gate_flags, int16_t* out, size_t size);
|
||||||
|
|
||||||
|
void Configure(uint16_t* parameter, ControlMode control_mode)
|
||||||
|
{
|
||||||
|
set_ar_loop(parameter[0], parameter[1]);
|
||||||
|
|
||||||
|
uint8_t waveform_mode = quant.Process(parameter[2] / 65536.0f, 5);
|
||||||
|
|
||||||
|
switch (waveform_mode) {
|
||||||
|
case 0:
|
||||||
|
shape_[0] = ENV_SHAPE_QUARTIC;
|
||||||
|
shape_[1] = ENV_SHAPE_EXPONENTIAL;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
shape_[0] = ENV_SHAPE_QUARTIC;
|
||||||
|
shape_[1] = ENV_SHAPE_QUARTIC;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
shape_[0] = ENV_SHAPE_LINEAR;
|
||||||
|
shape_[1] = ENV_SHAPE_LINEAR;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
shape_[0] = ENV_SHAPE_EXPONENTIAL;
|
||||||
|
shape_[1] = ENV_SHAPE_EXPONENTIAL;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
shape_[0] = ENV_SHAPE_EXPONENTIAL;
|
||||||
|
shape_[1] = ENV_SHAPE_QUARTIC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (segment_ > num_segments_) {
|
||||||
|
segment_ = 0;
|
||||||
|
phase_ = 0;
|
||||||
|
value_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_time(uint16_t segment, uint16_t time)
|
||||||
|
{
|
||||||
|
time_[segment] = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_level(uint16_t segment, int16_t level)
|
||||||
|
{
|
||||||
|
level_[segment] = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_num_segments(uint16_t num_segments)
|
||||||
|
{
|
||||||
|
num_segments_ = num_segments;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_sustain_point(uint16_t sustain_point)
|
||||||
|
{
|
||||||
|
sustain_point_ = sustain_point;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_adsr(
|
||||||
|
uint16_t attack,
|
||||||
|
uint16_t decay,
|
||||||
|
uint16_t sustain,
|
||||||
|
uint16_t release)
|
||||||
|
{
|
||||||
|
num_segments_ = 3;
|
||||||
|
sustain_point_ = 2;
|
||||||
|
|
||||||
|
level_[0] = 0;
|
||||||
|
level_[1] = 32767;
|
||||||
|
level_[2] = sustain;
|
||||||
|
level_[3] = 0;
|
||||||
|
|
||||||
|
time_[0] = attack;
|
||||||
|
time_[1] = decay;
|
||||||
|
time_[2] = release;
|
||||||
|
|
||||||
|
shape_[0] = ENV_SHAPE_QUARTIC;
|
||||||
|
shape_[1] = ENV_SHAPE_EXPONENTIAL;
|
||||||
|
shape_[2] = ENV_SHAPE_EXPONENTIAL;
|
||||||
|
|
||||||
|
loop_start_ = loop_end_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_ad(uint16_t attack, uint16_t decay)
|
||||||
|
{
|
||||||
|
num_segments_ = 2;
|
||||||
|
sustain_point_ = 0;
|
||||||
|
|
||||||
|
level_[0] = 0;
|
||||||
|
level_[1] = 32767;
|
||||||
|
level_[2] = 0;
|
||||||
|
|
||||||
|
time_[0] = attack;
|
||||||
|
time_[1] = decay;
|
||||||
|
|
||||||
|
shape_[0] = ENV_SHAPE_EXPONENTIAL;
|
||||||
|
shape_[1] = ENV_SHAPE_EXPONENTIAL;
|
||||||
|
|
||||||
|
loop_start_ = loop_end_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_adr(
|
||||||
|
uint16_t attack,
|
||||||
|
uint16_t decay,
|
||||||
|
uint16_t sustain,
|
||||||
|
uint16_t release)
|
||||||
|
{
|
||||||
|
num_segments_ = 3;
|
||||||
|
sustain_point_ = 0;
|
||||||
|
|
||||||
|
level_[0] = 0;
|
||||||
|
level_[1] = 32767;
|
||||||
|
level_[2] = sustain;
|
||||||
|
level_[3] = 0;
|
||||||
|
|
||||||
|
time_[0] = attack;
|
||||||
|
time_[1] = decay;
|
||||||
|
time_[2] = release;
|
||||||
|
|
||||||
|
shape_[0] = ENV_SHAPE_LINEAR;
|
||||||
|
shape_[1] = ENV_SHAPE_LINEAR;
|
||||||
|
shape_[2] = ENV_SHAPE_LINEAR;
|
||||||
|
|
||||||
|
loop_start_ = loop_end_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_ar(uint16_t attack, uint16_t decay)
|
||||||
|
{
|
||||||
|
num_segments_ = 2;
|
||||||
|
sustain_point_ = 1;
|
||||||
|
|
||||||
|
level_[0] = 0;
|
||||||
|
level_[1] = 32767;
|
||||||
|
level_[2] = 0;
|
||||||
|
|
||||||
|
time_[0] = attack;
|
||||||
|
time_[1] = decay;
|
||||||
|
|
||||||
|
shape_[0] = ENV_SHAPE_LINEAR;
|
||||||
|
shape_[1] = ENV_SHAPE_LINEAR;
|
||||||
|
|
||||||
|
loop_start_ = loop_end_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_adsar(
|
||||||
|
uint16_t attack,
|
||||||
|
uint16_t decay,
|
||||||
|
uint16_t sustain,
|
||||||
|
uint16_t release)
|
||||||
|
{
|
||||||
|
num_segments_ = 4;
|
||||||
|
sustain_point_ = 2;
|
||||||
|
|
||||||
|
level_[0] = 0;
|
||||||
|
level_[1] = 32767;
|
||||||
|
level_[2] = sustain;
|
||||||
|
level_[3] = 32767;
|
||||||
|
level_[4] = 0;
|
||||||
|
|
||||||
|
time_[0] = attack;
|
||||||
|
time_[1] = decay;
|
||||||
|
time_[2] = attack;
|
||||||
|
time_[3] = release;
|
||||||
|
|
||||||
|
shape_[0] = ENV_SHAPE_LINEAR;
|
||||||
|
shape_[1] = ENV_SHAPE_LINEAR;
|
||||||
|
shape_[2] = ENV_SHAPE_LINEAR;
|
||||||
|
shape_[3] = ENV_SHAPE_LINEAR;
|
||||||
|
|
||||||
|
loop_start_ = loop_end_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_adar(
|
||||||
|
uint16_t attack,
|
||||||
|
uint16_t decay,
|
||||||
|
uint16_t sustain,
|
||||||
|
uint16_t release)
|
||||||
|
{
|
||||||
|
num_segments_ = 4;
|
||||||
|
sustain_point_ = 0;
|
||||||
|
|
||||||
|
level_[0] = 0;
|
||||||
|
level_[1] = 32767;
|
||||||
|
level_[2] = sustain;
|
||||||
|
level_[3] = 32767;
|
||||||
|
level_[4] = 0;
|
||||||
|
|
||||||
|
time_[0] = attack;
|
||||||
|
time_[1] = decay;
|
||||||
|
time_[2] = attack;
|
||||||
|
time_[3] = release;
|
||||||
|
|
||||||
|
shape_[0] = ENV_SHAPE_LINEAR;
|
||||||
|
shape_[1] = ENV_SHAPE_LINEAR;
|
||||||
|
shape_[2] = ENV_SHAPE_LINEAR;
|
||||||
|
shape_[3] = ENV_SHAPE_LINEAR;
|
||||||
|
|
||||||
|
loop_start_ = loop_end_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_ad_loop(uint16_t attack, uint16_t decay)
|
||||||
|
{
|
||||||
|
num_segments_ = 2;
|
||||||
|
sustain_point_ = 0;
|
||||||
|
|
||||||
|
level_[0] = 0;
|
||||||
|
level_[1] = 32767;
|
||||||
|
level_[2] = 0;
|
||||||
|
|
||||||
|
time_[0] = attack;
|
||||||
|
time_[1] = decay;
|
||||||
|
|
||||||
|
shape_[0] = ENV_SHAPE_LINEAR;
|
||||||
|
shape_[1] = ENV_SHAPE_LINEAR;
|
||||||
|
|
||||||
|
loop_start_ = 0;
|
||||||
|
loop_end_ = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_adr_loop(
|
||||||
|
uint16_t attack,
|
||||||
|
uint16_t decay,
|
||||||
|
uint16_t sustain,
|
||||||
|
uint16_t release)
|
||||||
|
{
|
||||||
|
num_segments_ = 3;
|
||||||
|
sustain_point_ = 0;
|
||||||
|
|
||||||
|
level_[0] = 0;
|
||||||
|
level_[1] = 32767;
|
||||||
|
level_[2] = sustain;
|
||||||
|
level_[3] = 0;
|
||||||
|
|
||||||
|
time_[0] = attack;
|
||||||
|
time_[1] = decay;
|
||||||
|
time_[2] = release;
|
||||||
|
|
||||||
|
shape_[0] = ENV_SHAPE_LINEAR;
|
||||||
|
shape_[1] = ENV_SHAPE_LINEAR;
|
||||||
|
shape_[2] = ENV_SHAPE_LINEAR;
|
||||||
|
|
||||||
|
loop_start_ = 0;
|
||||||
|
loop_end_ = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_adar_loop(
|
||||||
|
uint16_t attack,
|
||||||
|
uint16_t decay,
|
||||||
|
uint16_t sustain,
|
||||||
|
uint16_t release)
|
||||||
|
{
|
||||||
|
num_segments_ = 4;
|
||||||
|
sustain_point_ = 0;
|
||||||
|
|
||||||
|
level_[0] = 0;
|
||||||
|
level_[1] = 32767;
|
||||||
|
level_[2] = sustain;
|
||||||
|
level_[3] = 32767;
|
||||||
|
level_[4] = 0;
|
||||||
|
|
||||||
|
time_[0] = attack;
|
||||||
|
time_[1] = decay;
|
||||||
|
time_[2] = attack;
|
||||||
|
time_[3] = release;
|
||||||
|
|
||||||
|
shape_[0] = ENV_SHAPE_LINEAR;
|
||||||
|
shape_[1] = ENV_SHAPE_LINEAR;
|
||||||
|
shape_[2] = ENV_SHAPE_LINEAR;
|
||||||
|
shape_[3] = ENV_SHAPE_LINEAR;
|
||||||
|
|
||||||
|
loop_start_ = 0;
|
||||||
|
loop_end_ = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_hard_reset(bool hard_reset)
|
||||||
|
{
|
||||||
|
hard_reset_ = hard_reset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int16_t level_[kMaxNumSegments];
|
||||||
|
uint16_t time_[kMaxNumSegments];
|
||||||
|
EnvelopeShape shape_[kMaxNumSegments];
|
||||||
|
|
||||||
|
int16_t segment_;
|
||||||
|
int16_t start_value_;
|
||||||
|
int16_t value_;
|
||||||
|
|
||||||
|
uint32_t phase_;
|
||||||
|
uint32_t phase_increment_;
|
||||||
|
|
||||||
|
uint16_t num_segments_;
|
||||||
|
uint16_t sustain_point_;
|
||||||
|
uint16_t loop_start_;
|
||||||
|
uint16_t loop_end_;
|
||||||
|
|
||||||
|
bool hard_reset_;
|
||||||
|
HysteresisQuantizer quant;
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(Tides);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace peaks
|
||||||
|
|
||||||
|
#endif // PEAKS_MODULATIONS_MULTISTAGE_ENVELOPE_H_
|
Loading…
Reference in a new issue