Files
-
blinds / hardware_design / pcb / blinds_v60.brd
-
blinds / hardware_design / pcb / blinds_v60.sch
-
braids / hardware_design / pcb / braids_v50.brd
-
braids / hardware_design / pcb / braids_v50.sch
-
branches / hardware_design / pcb / branches_v40.brd
-
branches / hardware_design / pcb / branches_v40.sch
-
clouds / hardware_design / pcb / clouds_v30.brd
-
clouds / hardware_design / pcb / clouds_v30.sch
-
ears / hardware_design / panel / ears_panel_v30.brd
-
ears / hardware_design / panel / ears_panel_v30.sch
-
ears / hardware_design / pcb / ears_v40.brd
-
ears / hardware_design / pcb / ears_v40.sch
-
edges / hardware_design / pcb / edges_expander_v01.brd
-
edges / hardware_design / pcb / edges_expander_v01.sch
-
edges / hardware_design / pcb / edges_v20.brd
-
edges / hardware_design / pcb / edges_v20.sch
-
elements / hardware_design / pcb / elements_v02.brd
-
elements / hardware_design / pcb / elements_v02.sch
-
frames / hardware_design / pcb / frames_v03.brd
-
frames / hardware_design / pcb / frames_v03.sch
-
grids / hardware_design / pcb / grids_v02.brd
-
grids / hardware_design / pcb / grids_v02.sch
-
kinks / hardware_design / pcb / kinks_v41.brd
-
kinks / hardware_design / pcb / kinks_v41.sch
-
links / hardware_design / pcb / links_v40.brd
-
links / hardware_design / pcb / links_v40.sch
-
marbles / hardware_design / pcb / marbles_v70.brd
-
marbles / hardware_design / pcb / marbles_v70.sch
-
peaks / hardware_design / pcb / peaks_v30.brd
-
peaks / hardware_design / pcb / peaks_v30.sch
-
plaits / hardware_design / pcb / plaits_v50.brd
-
plaits / hardware_design / pcb / plaits_v50.sch
-
rings / hardware_design / pcb / rings_v30.brd
-
rings / hardware_design / pcb / rings_v30.sch
-
ripples / hardware_design / pcb / ripples_v40.brd
-
ripples / hardware_design / pcb / ripples_v40.sch
-
shades / hardware_design / pcb / shades_v30.brd
-
shades / hardware_design / pcb / shades_v30.sch
-
shelves / hardware_design / pcb / shelves_expander_v10.brd
-
shelves / hardware_design / pcb / shelves_expander_v10.sch
-
shelves / hardware_design / pcb / shelves_v05.brd
-
shelves / hardware_design / pcb / shelves_v05.sch
-
stages / hardware_design / pcb / stages_v70.brd
-
stages / hardware_design / pcb / stages_v70.sch
-
streams / hardware_design / pcb / streams_v02_bargraph.brd
-
streams / hardware_design / pcb / streams_v02_bargraph.sch
-
streams / hardware_design / pcb / streams_v05.brd
-
streams / hardware_design / pcb / streams_v05.sch
-
tides / hardware_design / pcb / tides_v40.brd
-
tides / hardware_design / pcb / tides_v40.sch
-
veils / hardware_design / pcb / veils_v40.brd
-
veils / hardware_design / pcb / veils_v40.sch
-
volts / hardware_design / pcb / volts_v01.brd
-
volts / hardware_design / pcb / volts_v01.sch
-
warps / hardware_design / pcb / warps_v30.brd
-
warps / hardware_design / pcb / warps_v30.sch
-
yarns / hardware_design / pcb / yarns_v03.brd
-
yarns / hardware_design / pcb / yarns_v03.sch
Last update 6 years 1 month
by
Olivier Gillet
string_synth_oscillator.h// Copyright 2015 Olivier Gillet. // // Author: Olivier Gillet (ol.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. // // ----------------------------------------------------------------------------- // // Polyblep oscillator used for string synth synthesis. #ifndef RINGS_DSP_STRING_SYNTH_OSCILLATOR_H_ #define RINGS_DSP_STRING_SYNTH_OSCILLATOR_H_ #include "stmlib/stmlib.h" #include "stmlib/dsp/dsp.h" #include "stmlib/dsp/parameter_interpolator.h" #include "stmlib/dsp/units.h" namespace rings { using namespace stmlib; enum OscillatorShape { OSCILLATOR_SHAPE_BRIGHT_SQUARE, OSCILLATOR_SHAPE_SQUARE, OSCILLATOR_SHAPE_DARK_SQUARE, OSCILLATOR_SHAPE_TRIANGLE, }; class StringSynthOscillator { public: StringSynthOscillator() { } ~StringSynthOscillator() { } inline void Init() { phase_ = 0.0f; phase_increment_ = 0.01f; filter_state_ = 0.0f; high_ = false; next_sample_ = 0.0f; next_sample_saw_ = 0.0f; gain_ = 0.0f; gain_saw_ = 0.0f; } template<OscillatorShape shape, bool interpolate_pitch> inline void Render( float target_increment, float target_gain, float target_gain_saw, float* out, size_t size) { // Cut harmonics above 12kHz, and low-pass harmonics above 8kHz to clear // highs if (target_increment >= 0.17f) { target_gain *= 1.0f - (target_increment - 0.17f) * 12.5f; if (target_increment >= 0.25f) { return; } } float phase = phase_; ParameterInterpolator phase_increment( &phase_increment_, target_increment, size); ParameterInterpolator gain(&gain_, target_gain, size); ParameterInterpolator gain_saw(&gain_saw_, target_gain_saw, size); float next_sample = next_sample_; float next_sample_saw = next_sample_saw_; float filter_state = filter_state_; bool high = high_; while (size--) { float this_sample = next_sample; float this_sample_saw = next_sample_saw; next_sample = 0.0f; next_sample_saw = 0.0f; float increment = interpolate_pitch ? phase_increment.Next() : target_increment; phase += increment; float sample = 0.0f; const float pw = 0.5f; if (!high && phase >= pw) { float t = (phase - pw) / increment; this_sample += ThisBlepSample(t); next_sample += NextBlepSample(t); high = true; } if (phase >= 1.0f) { phase -= 1.0f; float t = phase / increment; float a = ThisBlepSample(t); float b = NextBlepSample(t); this_sample -= a; next_sample -= b; this_sample_saw -= a; next_sample_saw -= b; high = false; } next_sample += phase < pw ? 0.0f : 1.0f; next_sample_saw += phase; if (shape == OSCILLATOR_SHAPE_TRIANGLE) { const float integrator_coefficient = increment * 0.125f; this_sample = 64.0f * (this_sample - 0.5f); filter_state += integrator_coefficient * (this_sample - filter_state); sample = filter_state; } else if (shape == OSCILLATOR_SHAPE_DARK_SQUARE) { const float integrator_coefficient = increment * 2.0f; this_sample = 4.0f * (this_sample - 0.5f); filter_state += integrator_coefficient * (this_sample - filter_state); sample = filter_state; } else if (shape == OSCILLATOR_SHAPE_BRIGHT_SQUARE) { const float integrator_coefficient = increment * 2.0f; this_sample = 2.0f * this_sample - 1.0f; filter_state += integrator_coefficient * (this_sample - filter_state); sample = (this_sample - filter_state) * 0.5f; } else { this_sample = 2.0f * this_sample - 1.0f; sample = this_sample; } this_sample_saw = 2.0f * this_sample_saw - 1.0f; *out++ += sample * gain.Next() + this_sample_saw * gain_saw.Next(); } high_ = high; phase_ = phase; next_sample_ = next_sample; next_sample_saw_ = next_sample_saw; filter_state_ = filter_state; } private: static inline float ThisBlepSample(float t) { return 0.5f * t * t; } static inline float NextBlepSample(float t) { t = 1.0f - t; return -0.5f * t * t; } bool high_; float phase_; float phase_increment_; float next_sample_; float next_sample_saw_; float filter_state_; float gain_; float gain_saw_; DISALLOW_COPY_AND_ASSIGN(StringSynthOscillator); }; } // namespace rings #endif // RINGS_DSP_STRING_SYNTH_OSCILLATOR_H_