Files

copied
Last update 6 years 1 month by Olivier Gillet
Filesringsdsp
..
fx
dsp.h
fm_voice.cc
fm_voice.h
follower.h
limiter.h
note_filter.h
onset_detector.h
part.cc
part.h
patch.h
performance_state.h
plucker.h
resonator.cc
resonator.h
string.cc
string.h
string_synth_envelope.h
string_synth_oscillator.h
string_synth_part.cc
string_synth_part.h
string_synth_voice.h
strummer.h
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_
Report a bug