Files

copied
Last update 6 years 1 month by Olivier Gillet
Fileselementsdsp
..
fx
dsp.h
exciter.cc
exciter.h
multistage_envelope.cc
multistage_envelope.h
ominous_voice.cc
ominous_voice.h
part.cc
part.h
patch.h
resonator.cc
resonator.h
string.cc
string.h
tube.cc
tube.h
voice.cc
voice.h
resonator.cc
// Copyright 2014 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. // // ----------------------------------------------------------------------------- // // Resonator. #include "elements/dsp/resonator.h" #include "stmlib/dsp/dsp.h" #include "stmlib/dsp/cosine_oscillator.h" #include "elements/drivers/debug_pin.h" #include "elements/dsp/dsp.h" #include "elements/resources.h" namespace elements { using namespace std; using namespace stmlib; void Resonator::Init() { for (size_t i = 0; i < kMaxModes; ++i) { f_[i].Init(); } for (size_t i = 0; i < kMaxBowedModes; ++i) { f_bow_[i].Init(); d_bow_[i].Init(); } set_frequency(220.0f / kSampleRate); set_geometry(0.25f); set_brightness(0.5f); set_damping(0.3f); set_position(0.999f); set_resolution(kMaxModes); bow_signal_ = 0.0f; } size_t Resonator::ComputeFilters() { ++clock_divider_; float stiffness = Interpolate(lut_stiffness, geometry_, 256.0f); float harmonic = frequency_; float stretch_factor = 1.0f; float q = 500.0f * Interpolate( lut_4_decades, damping_ * 0.8f, 256.0f); float brightness_attenuation = 1.0f - geometry_; // Reduces the range of brightness when geometry is very low, to prevent // clipping. brightness_attenuation *= brightness_attenuation; brightness_attenuation *= brightness_attenuation; brightness_attenuation *= brightness_attenuation; float brightness = brightness_ * (1.0f - 0.2f * brightness_attenuation); float q_loss = brightness * (2.0f - brightness) * 0.85f + 0.15f; float q_loss_damping_rate = geometry_ * (2.0f - geometry_) * 0.1f; size_t num_modes = 0; for (size_t i = 0; i < min(kMaxModes, resolution_); ++i) { // Update the first 24 modes every time (2kHz). The higher modes are // refreshed as a slowest rate. bool update = i <= 24 || ((i & 1) == (clock_divider_ & 1)); float partial_frequency = harmonic * stretch_factor; if (partial_frequency >= 0.49f) { partial_frequency = 0.49f; } else { num_modes = i + 1; } if (update) { f_[i].set_f_q<FREQUENCY_FAST>( partial_frequency, 1.0f + partial_frequency * q); if (i < kMaxBowedModes) { size_t period = 1.0f / partial_frequency; while (period >= kMaxDelayLineSize) period >>= 1; d_bow_[i].set_delay(period); f_bow_[i].set_g_q(f_[i].g(), 1.0f + partial_frequency * 1500.0f); } } stretch_factor += stiffness; if (stiffness < 0.0f) { // Make sure that the partials do not fold back into negative frequencies. stiffness *= 0.93f; } else { // This helps adding a few extra partials in the highest frequencies. stiffness *= 0.98f; } // This prevents the highest partials from decaying too fast. q_loss += q_loss_damping_rate * (1.0f - q_loss); harmonic += frequency_; q *= q_loss; } return num_modes; } void Resonator::Process( const float* bow_strength, const float* in, float* center, float* sides, size_t size) { size_t num_modes = ComputeFilters(); size_t num_banded_wg = min(kMaxBowedModes, num_modes); // Linearly interpolate position. This parameter is extremely sensitive to // zipper noise. float position_increment = (position_ - previous_position_) / size; while (size--) { float s; // 0.5 Hz LFO used to modulate the position of the stereo side channel. lfo_phase_ += modulation_frequency_; if (lfo_phase_ >= 1.0f) { lfo_phase_ -= 1.0f; } previous_position_ += position_increment; float lfo = lfo_phase_ > 0.5f ? 1.0f - lfo_phase_ : lfo_phase_; CosineOscillator amplitudes; CosineOscillator aux_amplitudes; amplitudes.Init<COSINE_OSCILLATOR_APPROXIMATE>(previous_position_); aux_amplitudes.Init<COSINE_OSCILLATOR_APPROXIMATE>( modulation_offset_ + lfo); // Render normal modes. float input = *in++ * 0.125f; float sum_center = 0.0f; float sum_side = 0.0f; // Note: For a steady sound, the correct way of simulating the effect of // a pickup is to use a comb filter. But it sounds very flange-y when // modulated, even mildly, and incur a slight delay/smearing of the // attacks. // Thus, we directly apply the comb filter in the frequency domain by // adjusting the amplitude of each mode in the sum. Because the // partials may not be in an integer ratios, what we are doing here is // approximative when the stretch factor is non null. // It sounds interesting nevertheless. amplitudes.Start(); aux_amplitudes.Start(); for (size_t i = 0; i < num_modes; i++) { s = f_[i].Process<FILTER_MODE_BAND_PASS>(input); sum_center += s * amplitudes.Next(); sum_side += s * aux_amplitudes.Next(); } *sides++ = sum_side - sum_center; // Render bowed modes. float bow_signal = 0.0f; input += bow_signal_; amplitudes.Start(); for (size_t i = 0; i < num_banded_wg; ++i) { s = 0.99f * d_bow_[i].Read(); bow_signal += s; s = f_bow_[i].Process<FILTER_MODE_BAND_PASS_NORMALIZED>(input + s); d_bow_[i].Write(s); sum_center += s * amplitudes.Next() * 8.0f; } bow_signal_ = BowTable(bow_signal, *bow_strength++); *center++ = sum_center; } } } // namespace elements
Report a bug