|
- // 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.
- //
- // -----------------------------------------------------------------------------
- //
- // Exciter.
-
- #include "elements/dsp/exciter.h"
-
- #include <algorithm>
-
- #include "stmlib/dsp/dsp.h"
- #include "stmlib/dsp/units.h"
-
- #include "elements/dsp/dsp.h"
- #include "elements/resources.h"
-
- namespace elements {
-
- using namespace std;
- using namespace stmlib;
-
- void Exciter::Init() {
- set_model(EXCITER_MODEL_MALLET);
- set_parameter(0.0f);
- set_timbre(0.99f);
-
- lp_.Init();
- damp_state_ = 0.0f;
- delay_ = 0;
- plectrum_delay_ = 0;
- particle_state_ = 0.5f;
- damping_ = 0.0f;
- signature_ = 0.0f;
- }
-
- float Exciter::GetPulseAmplitude(float cutoff) {
- uint32_t cutoff_index = static_cast<uint32_t>(cutoff * 256.0f);
- return lut_approx_svf_gain[cutoff_index];
- }
-
- void Exciter::Process(const uint8_t flags, float* out, size_t size) {
- damping_ = 0.0f;
- (this->*fn_table_[model_])(flags, out, size);
- // Apply filters.
- if (model_ != EXCITER_MODEL_GRANULAR_SAMPLE_PLAYER &&
- model_ != EXCITER_MODEL_SAMPLE_PLAYER) {
- uint32_t cutoff_index = static_cast<uint32_t>(timbre_ * 256.0f);
- if (model_ == EXCITER_MODEL_NOISE) {
- uint32_t resonance_index = static_cast<uint32_t>(parameter_ * 256.0f);
- lp_.set_g_r(
- lut_approx_svf_g[cutoff_index],
- lut_approx_svf_r[resonance_index]);
- } else {
- lp_.set_g_r_h(
- lut_approx_svf_g[cutoff_index],
- 2.0f,
- lut_approx_svf_h[cutoff_index]);
- }
- lp_.Process<FILTER_MODE_LOW_PASS>(out, out, size);
- }
- }
-
- void Exciter::ProcessGranularSamplePlayer(
- const uint8_t flags, float* out, size_t size) {
- const uint32_t restart_prob = uint32_t(0.01f * 4294967296.0f);
- const uint32_t restart_point = uint32_t(parameter_ * 32767.0f) << 17;
- const uint32_t phase_increment = static_cast<uint32_t>(
- 131072.0f * SemitonesToRatio(72.0f * timbre_ - 60.0f));
- const int16_t* base = &smp_noise_sample[static_cast<size_t>(
- signature_ * 8192.0f)];
-
- uint32_t phase = phase_;
- while (size--) {
- uint32_t phase_integral = phase >> 17;
- float phase_fractional = static_cast<float>(phase & 0x1ffff) / 131072.0f;
- float a = static_cast<float>(base[phase_integral]);
- float b = static_cast<float>(base[phase_integral + 1]);
- *out++ = (a + (b - a) * phase_fractional) / 32768.0f;
- phase += phase_increment;
- if (Random::GetWord() < restart_prob) {
- phase = restart_point;
- }
- }
- phase_ = phase;
- damping_ = 0.0f;
- }
-
- void Exciter::ProcessSamplePlayer(
- const uint8_t flags, float* out, size_t size) {
- float index = (1.0f - parameter_) * 8.0f;
- MAKE_INTEGRAL_FRACTIONAL(index);
- if (index_integral == 8) {
- index_integral = 7;
- index_fractional = 1.0f;
- }
-
- const uint32_t offset_1 = smp_boundaries[index_integral];
- const uint32_t offset_2 = smp_boundaries[index_integral + 1];
- const uint32_t length_1 = offset_2 - offset_1 - 1;
- const uint32_t length_2 = smp_boundaries[index_integral + 2] - offset_2 - 1;
- const uint32_t phase_increment = static_cast<uint32_t>(
- 65536.0f * SemitonesToRatio(72.0f * timbre_ - 36.0f + 7.0f));
-
- float damp = damp_state_;
- uint32_t phase = phase_;
-
- if (flags & EXCITER_FLAG_RISING_EDGE) {
- damp = 0.0f;
- phase = 0;
- }
- if (!(flags & EXCITER_FLAG_GATE)) {
- damp = 1.0f - 0.95f * (1.0f - damp);
- }
-
- while (size--) {
- uint32_t phase_integral = phase >> 16;
- float phase_fractional = static_cast<float>(phase & 0xffff) / 65536.0f;
- float sample_1 = 0.0f;
- float sample_2 = 0.0f;
- bool step = false;
- if (phase_integral < length_1) {
- const int16_t* base = &smp_sample_data[offset_1 + phase_integral];
- float a = static_cast<float>(base[0]);
- float b = static_cast<float>(base[1]);
- sample_1 = a + (b - a) * phase_fractional;
- step = true;
- }
- if (phase_integral < length_2) {
- const int16_t* base = &smp_sample_data[offset_2 + phase_integral];
- float a = static_cast<float>(base[0]);
- float b = static_cast<float>(base[1]);
- sample_2 = a + (b - a) * phase_fractional;
- step = true;
- }
- if (step) {
- phase += phase_increment;
- }
-
- *out++ = (sample_1 + (sample_2 - sample_1) * index_fractional) / 65536.0f;
- }
- phase_ = phase;
- damping_ = damp * (parameter_ >= 0.8f ? parameter_ * 5.0f - 4.0f : 0.0f);
- damp_state_ = damp;
- }
-
- void Exciter::ProcessMallet(const uint8_t flags, float* out, size_t size) {
- fill(&out[0], &out[size], 0.0f);
- if (flags & EXCITER_FLAG_RISING_EDGE) {
- damp_state_ = 0.0f;
- out[0] = GetPulseAmplitude(timbre_);
- }
- if (!(flags & EXCITER_FLAG_GATE)) {
- damp_state_ = 1.0f - 0.95f * (1.0f - damp_state_);
- }
- damping_ = damp_state_ * (1.0f - parameter_);
- }
-
- void Exciter::ProcessPlectrum(
- const uint8_t flags,
- float* out,
- size_t size) {
- float amplitude = GetPulseAmplitude(timbre_);
- float damp = damp_state_;
- float impulse = 0.0f;
- if (flags & EXCITER_FLAG_RISING_EDGE) {
- impulse = -amplitude * (0.05f + signature_ * 0.2f);
- plectrum_delay_ = static_cast<uint32_t>(
- 4096.0f * parameter_ * parameter_) + 64;
- }
- while (size--) {
- if (plectrum_delay_) {
- --plectrum_delay_;
- if (plectrum_delay_ == 0) {
- impulse = amplitude;
- }
- damp = 1.0f - 0.997f * (1.0f - damp);
- } else {
- damp = 0.9f * damp;
- }
- *out++ = impulse;
- impulse = 0.0f;
- }
- damping_ = damp * 0.5f;
- damp_state_ = damp;
- }
-
- void Exciter::ProcessParticles(
- const uint8_t flags,
- float* out,
- size_t size) {
- if (flags & EXCITER_FLAG_RISING_EDGE) {
- particle_state_ = RandomSample();
- particle_state_ = 1.0f - 0.6f * particle_state_ * particle_state_;
- delay_ = 0;
- particle_range_ = 1.0f;
- }
- fill(&out[0], &out[size], 0.0f);
- if (flags & EXCITER_FLAG_GATE) {
- const uint32_t up_probability = uint32_t(0.7f * 4294967296.0f);
- const uint32_t down_probability = uint32_t(0.3f * 4294967296.0f);
- const float amplitude = GetPulseAmplitude(timbre_);
- while (size--) {
- if (delay_ == 0) {
- float amount = RandomSample();
- amount = 1.05f + 0.5f * amount * amount;
- if (Random::GetWord() > up_probability) {
- particle_state_ *= amount;
- if (particle_state_ >= (particle_range_ + 0.25f)) {
- particle_state_ = particle_range_ + 0.25f;
- }
- } else if (Random::GetWord() < down_probability) {
- particle_state_ /= amount;
- if (particle_state_ <= 0.02f) {
- particle_state_ = 0.02f;
- }
- }
- delay_ = static_cast<uint32_t>(particle_state_ * 0.15f * kSampleRate);
- float gain = 1.0f - particle_range_;
- gain *= gain;
- *out = particle_state_ * amplitude * (1.0f - gain);
-
- float decay_factor = 1.0f - parameter_;
- particle_range_ *= 1.0f - decay_factor * decay_factor * 0.5f;
- } else {
- --delay_;
- }
- ++out;
- }
- }
- }
-
- void Exciter::ProcessFlow(
- const uint8_t flags,
- float* out,
- size_t size) {
- float scale = parameter_ * parameter_ * parameter_ * parameter_;
- float threshold = 0.0001f + scale * 0.125f;
- if (flags & EXCITER_FLAG_RISING_EDGE) {
- particle_state_ = 0.5f;
- }
- while (size--) {
- float sample = RandomSample();
- if (sample < threshold) {
- particle_state_ = -particle_state_;
- }
- *out++ = particle_state_ + (sample - 0.5f - particle_state_) * scale;
- }
- }
-
- void Exciter::ProcessNoise(const uint8_t flags, float* out, size_t size) {
- while (size--) {
- *out++ = RandomSample() - 0.5f;
- }
- }
-
- /* static */
- Exciter::ProcessFn Exciter::fn_table_[] = {
- &Exciter::ProcessGranularSamplePlayer,
- &Exciter::ProcessSamplePlayer,
- &Exciter::ProcessMallet,
- &Exciter::ProcessPlectrum,
- &Exciter::ProcessParticles,
- &Exciter::ProcessFlow,
- &Exciter::ProcessNoise
- };
-
- } // namespace elements
|