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 2 months
by
Olivier Gillet
swarm_engine.h// Copyright 2016 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. // // ----------------------------------------------------------------------------- // // Swarm of sawtooths and sines. #ifndef PLAITS_DSP_ENGINE_SWARM_ENGINE_H_ #define PLAITS_DSP_ENGINE_SWARM_ENGINE_H_ #include "stmlib/dsp/polyblep.h" #include "stmlib/dsp/units.h" #include "stmlib/utils/random.h" #include "plaits/dsp/engine/engine.h" #include "plaits/dsp/oscillator/oscillator.h" #include "plaits/dsp/oscillator/string_synth_oscillator.h" #include "plaits/dsp/oscillator/sine_oscillator.h" #include "plaits/resources.h" namespace plaits { const int kNumSwarmVoices = 8; class GrainEnvelope { public: GrainEnvelope() { } ~GrainEnvelope() { } void Init() { from_ = 0.0f; interval_ = 1.0f; phase_ = 1.0f; fm_ = 0.0f; amplitude_ = 0.5f; previous_size_ratio_ = 0.0f; } inline void Step(float rate, bool burst_mode, bool start_burst) { bool randomize = false; if (start_burst) { phase_ = 0.5f; fm_ = 16.0f; randomize = true; } else { phase_ += rate * fm_; if (phase_ >= 1.0f) { phase_ -= static_cast<float>(static_cast<int>(phase_)); randomize = true; } } if (randomize) { from_ += interval_; interval_ = stmlib::Random::GetFloat() - from_; // Randomize the duration of the grain. if (burst_mode) { fm_ *= 0.8f + 0.2f * stmlib::Random::GetFloat(); } else { fm_ = 0.5f + 1.5f * stmlib::Random::GetFloat(); } } } inline float frequency(float size_ratio) const { // We approximate two overlapping grains of frequencies f1 and f2 // By a continuous tone ramping from f1 to f2. This allows a continuous // transition between the "grain cloud" and "swarm of glissandi" textures. if (size_ratio < 1.0f) { return 2.0f * (from_ + interval_ * phase_) - 1.0f; } else { return from_; } } inline float amplitude(float size_ratio) { float target_amplitude = 1.0f; if (size_ratio >= 1.0f) { float phase = (phase_ - 0.5f) * size_ratio; CONSTRAIN(phase, -1.0f, 1.0f); float e = stmlib::InterpolateWrap( lut_sine, 0.5f * phase + 1.25f, 1024.0f); target_amplitude = 0.5f * (e + 1.0f); } if ((size_ratio >= 1.0f) ^ (previous_size_ratio_ >= 1.0f)) { filter_coefficient_ = 0.5f; } filter_coefficient_ *= 0.95f; previous_size_ratio_ = size_ratio; ONE_POLE(amplitude_, target_amplitude, 0.5f - filter_coefficient_); return amplitude_; } private: float from_; float interval_; float phase_; float fm_; float amplitude_; float previous_size_ratio_; float filter_coefficient_; DISALLOW_COPY_AND_ASSIGN(GrainEnvelope); }; class AdditiveSawOscillator { public: AdditiveSawOscillator() { } ~AdditiveSawOscillator() { } inline void Init() { phase_ = 0.0f; next_sample_ = 0.0f; frequency_ = 0.01f; gain_ = 0.0f; } inline void Render( float frequency, float level, float* out, size_t size) { if (frequency >= kMaxFrequency) { frequency = kMaxFrequency; } stmlib::ParameterInterpolator fm(&frequency_, frequency, size); stmlib::ParameterInterpolator gain(&gain_, level, size); float next_sample = next_sample_; float phase = phase_; while (size--) { float this_sample = next_sample; next_sample = 0.0f; const float frequency = fm.Next(); phase += frequency; if (phase >= 1.0f) { phase -= 1.0f; float t = phase / frequency; this_sample -= stmlib::ThisBlepSample(t); next_sample -= stmlib::NextBlepSample(t); } next_sample += phase; *out++ += (2.0f * this_sample - 1.0f) * gain.Next(); } phase_ = phase; next_sample_ = next_sample; } private: // Oscillator state. float phase_; float next_sample_; // For interpolation of parameters. float frequency_; float gain_; DISALLOW_COPY_AND_ASSIGN(AdditiveSawOscillator); }; class SwarmVoice { public: SwarmVoice() { } ~SwarmVoice() { } void Init(float rank) { rank_ = rank; envelope_.Init(); saw_.Init(); sine_.Init(); } void Render( float f0, float density, bool burst_mode, bool start_burst, float spread, float size_ratio, float* saw, float* sine, size_t size) { envelope_.Step(density, burst_mode, start_burst); const float scale = 1.0f / kNumSwarmVoices; const float amplitude = envelope_.amplitude(size_ratio) * scale; const float expo_amount = envelope_.frequency(size_ratio); f0 *= stmlib::SemitonesToRatio(48.0f * expo_amount * spread * rank_); const float linear_amount = rank_ * (rank_ + 0.01f) * spread * 0.25f; f0 *= 1.0f + linear_amount; saw_.Render(f0, amplitude, saw, size); sine_.Render(f0, amplitude, sine, size); }; private: float rank_; GrainEnvelope envelope_; AdditiveSawOscillator saw_; FastSineOscillator sine_; }; class SwarmEngine : public Engine { public: SwarmEngine() { } ~SwarmEngine() { } virtual void Init(stmlib::BufferAllocator* allocator); virtual void Reset(); virtual void Render(const EngineParameters& parameters, float* out, float* aux, size_t size, bool* already_enveloped); private: SwarmVoice swarm_voice_[kNumSwarmVoices]; DISALLOW_COPY_AND_ASSIGN(SwarmEngine); }; } // namespace plaits #endif // PLAITS_DSP_ENGINE_SWARM_ENGINE_H_