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
generator.cc// Copyright 2013 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. // // ----------------------------------------------------------------------------- // // Tidal generator. #include "tides/generator.h" #include <algorithm> #include <cmath> #include "stmlib/utils/dsp.h" #include "tides/resources.h" namespace tides { using namespace std; using namespace stmlib; const int16_t kOctave = 12 * 128; const uint16_t kSlopeBits = 12; const uint32_t kSyncCounterMaxTime = 8 * 48000; const int32_t kDownsampleCoefficient[4] = { 17162, 19069, 17162, 12140 }; /* static */ const FrequencyRatio Generator::frequency_ratios_[] = { { 1, 1 }, { 5, 4 }, { 4, 3 }, { 3, 2 }, { 5, 3 }, { 2, 1 }, { 3, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 12, 1 }, { 16, 1 }, }; /* static */ const int16_t Generator::num_frequency_ratios_ = \ sizeof(Generator::frequency_ratios_) / sizeof(FrequencyRatio); void Generator::Init() { mode_ = GENERATOR_MODE_LOOPING; range_ = GENERATOR_RANGE_HIGH; clock_divider_ = 1; phase_ = 0; set_pitch(60 << 7); pattern_predictor_.Init(); GeneratorSample s; s.flags = 0; s.unipolar = 0; s.bipolar = 0; for (size_t i = 0; i < kNumBlocks; ++i) { fill(&output_samples_[i][0], &output_samples_[i][kBlockSize], s); fill(&input_samples_[i][0], &input_samples_[i][kBlockSize], 0); } playback_block_ = kNumBlocks / 2; render_block_ = 0; current_sample_ = 0; shape_ = 0; slope_ = 0; smoothed_slope_ = 0; smoothness_ = 0; previous_sample_.unipolar = previous_sample_.bipolar = 0; running_ = false; ClearFilterState(); sync_counter_ = kSyncCounterMaxTime; frequency_ratio_.p = 1; frequency_ratio_.q = 1; sync_ = false; phase_increment_ = 9448928; local_osc_phase_increment_ = phase_increment_; target_phase_increment_ = phase_increment_; } void Generator::ComputeFrequencyRatio(int16_t pitch) { int16_t delta = previous_pitch_ - pitch; // Hysteresis for preventing glitchy transitions. if (delta < 96 && delta > -96) { return; } previous_pitch_ = pitch; // Corresponds to a 0V CV after calibration pitch -= (36 << 7); // The range of the control panel knob is 4 octaves. pitch = pitch * 12 / (48 << 7); bool swap = false; if (pitch < 0) { pitch = -pitch; swap = true; } if (pitch >= num_frequency_ratios_) { pitch = num_frequency_ratios_ - 1; } frequency_ratio_ = frequency_ratios_[pitch]; if (swap) { frequency_ratio_.q = frequency_ratio_.p; frequency_ratio_.p = frequency_ratios_[pitch].q; } } uint32_t Generator::ComputePhaseIncrement(int16_t pitch) { int16_t num_shifts = 0; while (pitch < 0) { pitch += kOctave; --num_shifts; } while (pitch >= kOctave) { pitch -= kOctave; ++num_shifts; } // Lookup phase increment uint32_t a = lut_increments[pitch >> 4]; uint32_t b = lut_increments[(pitch >> 4) + 1]; uint32_t phase_increment = a + ((b - a) * (pitch & 0xf) >> 4); // Compensate for downsampling phase_increment *= clock_divider_; return num_shifts >= 0 ? phase_increment << num_shifts : phase_increment >> -num_shifts; } int16_t Generator::ComputePitch(uint32_t phase_increment) { uint32_t first = lut_increments[0]; uint32_t last = lut_increments[LUT_INCREMENTS_SIZE - 2]; int16_t pitch = 0; if (phase_increment == 0) { phase_increment = 1; } phase_increment /= clock_divider_; while (phase_increment > last) { phase_increment >>= 1; pitch += kOctave; } while (phase_increment < first) { phase_increment <<= 1; pitch -= kOctave; } pitch += (std::lower_bound( lut_increments, lut_increments + LUT_INCREMENTS_SIZE, phase_increment) - lut_increments) << 4; return pitch; } int32_t Generator::ComputeCutoffFrequency(int16_t pitch, int16_t smoothness) { size_t shifts = clock_divider_; while (shifts > 1) { shifts >>= 1; pitch += kOctave; } int32_t frequency; if (smoothness > 0) { frequency = 256 << 7; } else if (smoothness > -16384) { int32_t start = pitch + (36 << 7); int32_t end = 256 << 7; frequency = start + ((end - start) * (smoothness + 16384) >> 14); } else { int32_t start = pitch - (36 << 7); int32_t end = pitch + (36 << 7); frequency = start + ((end - start) * (smoothness + 32768) >> 14); } frequency += 32768; if (frequency < 0) { frequency = 0; } return frequency; } int32_t Generator::ComputeAntialiasAttenuation( int16_t pitch, int16_t slope, int16_t shape, int16_t smoothness) const { pitch += 12 * 128; if (pitch < 0) pitch = 0; if (slope < 0) slope = ~slope; if (shape < 0) shape = ~shape; if (smoothness < 0) smoothness = 0; int32_t p = 252059; p += -76 * smoothness >> 5; p += -30 * shape >> 5; p += -102 * slope >> 5; p += -664 * pitch >> 5; p += 31 * (smoothness * shape >> 16) >> 5; p += 12 * (smoothness * slope >> 16) >> 5; p += 14 * (shape * slope >> 16) >> 5; p += 219 * (pitch * smoothness >> 16) >> 5; p += 50 * (pitch * shape >> 16) >> 5; p += 425 * (pitch * slope >> 16) >> 5; p += 13 * (smoothness * smoothness >> 16) >> 5; p += 1 * (shape * shape >> 16) >> 5; p += -11 * (slope * slope >> 16) >> 5; p += 776 * (pitch * pitch >> 16) >> 5; if (p < 0) p = 0; if (p > 32767) p = 32767; return p; } void Generator::ProcessFilterWavefolder( GeneratorSample* in_out, size_t size) { int32_t frequency = ComputeCutoffFrequency(pitch_, smoothness_); int32_t f_a = lut_cutoff[frequency >> 7] >> 16; int32_t f_b = lut_cutoff[(frequency >> 7) + 1] >> 16; int32_t f = f_a + ((f_b - f_a) * (frequency & 0x7f) >> 7); int32_t wf_gain = 2048; int32_t wf_balance = 0; if (smoothness_ > 0) { int16_t attenuated_smoothness = smoothness_ * attenuation_ >> 15; wf_gain += attenuated_smoothness * (32767 - 1024) >> 14; wf_balance = attenuated_smoothness; } int32_t uni_lp_state_0 = uni_lp_state_[0]; int32_t uni_lp_state_1 = uni_lp_state_[1]; int32_t bi_lp_state_0 = bi_lp_state_[0]; int32_t bi_lp_state_1 = bi_lp_state_[1]; while (size--) { int32_t original, folded; // Run through LPF. bi_lp_state_0 += f * (in_out->bipolar - bi_lp_state_0) >> 15; bi_lp_state_1 += f * (bi_lp_state_0 - bi_lp_state_1) >> 15; // Fold. original = bi_lp_state_1; folded = Interpolate1022(wav_bipolar_fold, original * wf_gain + (1UL << 31)); in_out->bipolar = original + ((folded - original) * wf_balance >> 15); // Run through LPF. uni_lp_state_0 += f * (in_out->unipolar - uni_lp_state_0) >> 15; uni_lp_state_1 += f * (uni_lp_state_0 - uni_lp_state_1) >> 15; // Fold. original = uni_lp_state_1 << 1; folded = Interpolate1022(wav_unipolar_fold, original * wf_gain) << 1; in_out->unipolar = original + ((folded - original) * wf_balance >> 15); uni_lp_state_[0] = uni_lp_state_0; uni_lp_state_[1] = uni_lp_state_1; bi_lp_state_[0] = bi_lp_state_0; bi_lp_state_[1] = bi_lp_state_1; in_out++; } uni_lp_state_[0] = uni_lp_state_0; uni_lp_state_[1] = uni_lp_state_1; bi_lp_state_[0] = bi_lp_state_0; bi_lp_state_[1] = bi_lp_state_1; } void Generator::ProcessAudioRate( const uint8_t* in, GeneratorSample* out, size_t size) { GeneratorSample sample = previous_sample_; if (sync_) { pitch_ = ComputePitch(phase_increment_); CONSTRAIN(pitch_, 0, 120 << 7); } else { CONSTRAIN(pitch_, 0, 120 << 7); phase_increment_ = ComputePhaseIncrement(pitch_); local_osc_phase_increment_ = phase_increment_; target_phase_increment_ = phase_increment_; } attenuation_ = ComputeAntialiasAttenuation( pitch_, slope_, shape_, smoothness_); uint16_t shape = static_cast<uint16_t>((shape_ * attenuation_ >> 15) + 32768); uint16_t wave_index = WAV_INVERSE_TAN_AUDIO + (shape >> 14); const int16_t* shape_1 = waveform_table[wave_index]; const int16_t* shape_2 = waveform_table[wave_index + 1]; uint16_t shape_xfade = shape << 2; uint32_t end_of_attack = (static_cast<uint32_t>(slope_ + 32768) << 16); // Load state into registers - saves some memory load/store inside the // rendering loop. uint32_t phase = phase_; uint32_t phase_increment = phase_increment_; bool wrap = wrap_; // Enforce that the EOA pulse is at least 1 sample wide. if (end_of_attack >= phase_increment) { end_of_attack -= phase_increment; } if (end_of_attack < phase_increment) { end_of_attack = phase_increment; } uint32_t mid_point = mid_point_; int32_t next_sample = next_sample_; while (size--) { ++sync_counter_; uint8_t control = *in++; // When freeze is high, discard any start/reset command. if (!(control & CONTROL_FREEZE)) { if (control & CONTROL_GATE_RISING) { phase = 0; running_ = true; } else if (mode_ != GENERATOR_MODE_LOOPING && wrap) { phase = 0; running_ = false; } } if (sync_) { if (control & CONTROL_CLOCK_RISING) { ++sync_edges_counter_; if (sync_edges_counter_ >= frequency_ratio_.q) { sync_edges_counter_ = 0; if (sync_counter_ < kSyncCounterMaxTime && sync_counter_) { uint64_t increment = frequency_ratio_.p * static_cast<uint64_t>( 0xffffffff / sync_counter_); if (increment > 0x20000000) { increment = 0x20000000; } target_phase_increment_ = static_cast<uint32_t>(increment); local_osc_phase_ = 0; } sync_counter_ = 0; } } // Fast tracking of the local oscillator to the external oscillator. local_osc_phase_increment_ += static_cast<int32_t>( target_phase_increment_ - local_osc_phase_increment_) >> 8; local_osc_phase_ += local_osc_phase_increment_; // Slow phase realignment between the master oscillator and the local // oscillator. int32_t phase_error = local_osc_phase_ - phase; phase_increment = local_osc_phase_increment_ + (phase_error >> 13); } if (control & CONTROL_FREEZE) { *out++ = sample; continue; } bool sustained = mode_ == GENERATOR_MODE_AR && phase >= (1UL << 31) && control & CONTROL_GATE; if (sustained) { phase = 1L << 31; } mid_point = (mid_point >> 5) * 31; mid_point += (end_of_attack >> 5); uint32_t min_mid_point = 2 * phase_increment; uint32_t max_mid_point = 0xffffffff - min_mid_point; CONSTRAIN(mid_point, min_mid_point, max_mid_point); CONSTRAIN(mid_point, 0x10000, 0xffff0000); int32_t slope_up = static_cast<int32_t>(0xffffffff / (mid_point >> 16)); int32_t slope_down = static_cast<int32_t>(0xffffffff / (~mid_point >> 16)); int32_t this_sample = next_sample; next_sample = 0; // Process reset discontinuity. if (phase < phase_increment) { slope_up_ = true; uint32_t t = phase / (phase_increment >> 16); int32_t discontinuity = slope_up + slope_down; discontinuity = (discontinuity * (phase_increment >> 18)) >> 14; this_sample += ThisIntegratedBlepSample(t) * discontinuity >> 16; next_sample += NextIntegratedBlepSample(t) * discontinuity >> 16; } else { // Process transition discontinuity. if (slope_up_ ^ (phase < mid_point)) { slope_up_ = phase < mid_point; uint32_t t = (phase - mid_point) / (phase_increment >> 16); int32_t discontinuity = slope_up + slope_down; discontinuity = (discontinuity * (phase_increment >> 18)) >> 14; this_sample -= ThisIntegratedBlepSample(t) * discontinuity >> 16; next_sample -= NextIntegratedBlepSample(t) * discontinuity >> 16; } } next_sample += slope_up_ ? ((phase >> 16) * slope_up) >> 16 : 65535 - (((phase - mid_point) >> 16) * slope_down >> 16); CONSTRAIN(this_sample, 0, 65535); sample.bipolar = Crossfade115(shape_1, shape_2, this_sample, shape_xfade); sample.unipolar = Crossfade115(shape_1, shape_2, (this_sample >> 1) + 32768, shape_xfade); sample.flags = 0; bool looped = mode_ == GENERATOR_MODE_LOOPING && wrap; if (phase >= end_of_attack || !running_) { sample.flags |= FLAG_END_OF_ATTACK; } if (!running_ || looped) { eor_counter_ = phase_increment < 44739242 ? 48 : 1; } if (eor_counter_) { sample.flags |= FLAG_END_OF_RELEASE; --eor_counter_; } *out++ = sample; if (running_ && !sustained) { phase += phase_increment; wrap = phase < phase_increment; } if (!running_ && !sustained) { sample.bipolar = 0; sample.unipolar = 0; } } previous_sample_ = sample; phase_ = phase; phase_increment_ = phase_increment; wrap_ = wrap; next_sample_ = next_sample; mid_point_ = mid_point; } void Generator::ProcessControlRate( const uint8_t* in, GeneratorSample* out, size_t size) { if (sync_) { pitch_ = ComputePitch(phase_increment_); } else { phase_increment_ = ComputePhaseIncrement(pitch_); local_osc_phase_increment_ = phase_increment_; target_phase_increment_ = phase_increment_; } attenuation_ = 32767; GeneratorSample sample = previous_sample_; uint16_t shape = static_cast<uint16_t>(shape_ + 32768); shape = (shape >> 2) * 3; uint16_t wave_index = WAV_REVERSED_CONTROL + (shape >> 13); const int16_t* shape_1 = waveform_table[wave_index]; const int16_t* shape_2 = waveform_table[wave_index + 1]; uint16_t shape_xfade = shape << 3; // Load state into registers - saves some memory load/store inside the // rendering loop. uint32_t phase = phase_; uint32_t phase_increment = phase_increment_; bool wrap = wrap_; int32_t smoothed_slope = smoothed_slope_; int32_t previous_smoothed_slope = 0x7fffffff; uint32_t end_of_attack = 1UL << 31; uint32_t attack_factor = 1 << kSlopeBits; uint32_t decay_factor = 1 << kSlopeBits; while (size--) { sync_counter_++; // Low-pass filter the slope parameter. smoothed_slope += (slope_ - smoothed_slope) >> 4; uint8_t control = *in++; // When freeze is high, discard any start/reset command. if (!(control & CONTROL_FREEZE)) { if (control & CONTROL_GATE_RISING) { phase = 0; running_ = true; } else if (mode_ != GENERATOR_MODE_LOOPING && wrap) { running_ = false; phase = 0; } } if ((control & CONTROL_CLOCK_RISING) && sync_ && sync_counter_) { if (sync_counter_ >= kSyncCounterMaxTime) { phase = 0; } else { uint32_t predicted_period = sync_counter_ < 480 ? sync_counter_ : pattern_predictor_.Predict(sync_counter_); uint64_t increment = frequency_ratio_.p * static_cast<uint64_t>( 0xffffffff / (predicted_period * frequency_ratio_.q)); if (increment > 0x20000000) { increment = 0x20000000; } phase_increment = static_cast<uint32_t>(increment); } sync_counter_ = 0; } if (control & CONTROL_FREEZE) { *out++ = sample; continue; } // Recompute the waveshaping parameters only when the slope has changed. if (smoothed_slope != previous_smoothed_slope) { uint32_t slope_offset = Interpolate88( lut_slope_compression, smoothed_slope + 32768); if (slope_offset <= 1) { decay_factor = 32768 << kSlopeBits; attack_factor = 1 << (kSlopeBits - 1); } else { decay_factor = (32768 << kSlopeBits) / slope_offset; attack_factor = (32768 << kSlopeBits) / (65536 - slope_offset); } previous_smoothed_slope = smoothed_slope; end_of_attack = slope_offset << 16; } uint32_t skewed_phase = phase; if (phase <= end_of_attack) { skewed_phase = (phase >> kSlopeBits) * decay_factor; } else { skewed_phase = ((phase - end_of_attack) >> kSlopeBits) * attack_factor; skewed_phase += 1L << 31; } bool sustained = mode_ == GENERATOR_MODE_AR && phase >= end_of_attack && control & CONTROL_GATE; if (sustained) { skewed_phase = 1L << 31; phase = end_of_attack + 1; } sample.unipolar = Crossfade115( shape_1, shape_2, skewed_phase >> 16, shape_xfade); sample.bipolar = Crossfade115( shape_1, shape_2, skewed_phase >> 15, shape_xfade); if (skewed_phase >= (1UL << 31)) { sample.bipolar = -sample.bipolar; } uint32_t adjusted_end_of_attack = end_of_attack; if (adjusted_end_of_attack >= phase_increment) { adjusted_end_of_attack -= phase_increment; } if (adjusted_end_of_attack < phase_increment) { adjusted_end_of_attack = phase_increment; } sample.flags = 0; bool looped = mode_ == GENERATOR_MODE_LOOPING && wrap; if (phase >= adjusted_end_of_attack || !running_ || sustained) { sample.flags |= FLAG_END_OF_ATTACK; } if (!running_ || looped) { eor_counter_ = phase_increment < 44739242 ? 48 : 1; } if (eor_counter_) { sample.flags |= FLAG_END_OF_RELEASE; --eor_counter_; } // Two special cases for the "pure decay" scenario: // END_OF_ATTACK is always true except at the initial trigger. if (end_of_attack == 0) { sample.flags |= FLAG_END_OF_ATTACK; } bool triggered = control & CONTROL_GATE_RISING; if ((sustained || end_of_attack == 0) && (triggered || looped)) { sample.flags &= ~FLAG_END_OF_ATTACK; } *out++ = sample; if (running_ && !sustained) { phase += phase_increment; wrap = phase < phase_increment; } else { wrap = false; } } previous_sample_ = sample; phase_ = phase; phase_increment_ = phase_increment; wrap_ = wrap; smoothed_slope_ = smoothed_slope; } void Generator::ProcessWavetable( const uint8_t* in, GeneratorSample* out, size_t size) { GeneratorSample sample = previous_sample_; if (sync_) { pitch_ = ComputePitch(phase_increment_); } else { phase_increment_ = ComputePhaseIncrement(pitch_); } uint32_t phase = phase_; uint32_t phase_increment = phase_increment_; // The grid is only 8x8 rather than 9x9 so we need to scale by 7/8.0 uint16_t target_x = static_cast<uint16_t>(slope_ + 32768); target_x = target_x * 57344 >> 16; uint16_t x = x_; uint16_t x_increment = (target_x - x) / size; uint16_t target_y = static_cast<uint16_t>(shape_ + 32768); target_y = target_y * 57344 >> 16; uint16_t y = y_; uint16_t y_increment = (target_y - y) / size; int32_t wf_gain = smoothness_ > 0 ? smoothness_ : 0; wf_gain = wf_gain * wf_gain >> 15; int32_t frequency = ComputeCutoffFrequency(pitch_, smoothness_); int32_t f_a = lut_cutoff[frequency >> 7] >> 16; int32_t f_b = lut_cutoff[(frequency >> 7) + 1] >> 16; int32_t f = f_a + ((f_b - f_a) * (frequency & 0x7f) >> 7); int32_t lp_state_0 = bi_lp_state_[0]; int32_t lp_state_1 = bi_lp_state_[1]; const int16_t* bank = wt_waves + mode_ * 64 * 257 - (mode_ & 2) * 4 * 257; while (size--) { ++sync_counter_; uint8_t control = *in++; // When freeze is high, discard any start/reset command. if (!(control & CONTROL_FREEZE)) { if (control & CONTROL_GATE_RISING) { phase = 0; } } if (control & CONTROL_CLOCK_RISING) { if (sync_) { if (range_ == GENERATOR_RANGE_HIGH) { ++sync_edges_counter_; if (sync_edges_counter_ >= frequency_ratio_.q) { sync_edges_counter_ = 0; if (sync_counter_ < kSyncCounterMaxTime && sync_counter_) { uint64_t increment = frequency_ratio_.p * static_cast<uint64_t>( 0xffffffff / sync_counter_); if (increment > 0x20000000) { increment = 0x20000000; } target_phase_increment_ = static_cast<uint32_t>(increment); local_osc_phase_ = 0; } sync_counter_ = 0; } } else { if (sync_counter_ >= kSyncCounterMaxTime) { phase = 0; } else if (sync_counter_) { uint32_t predicted_period = sync_counter_ < 480 ? sync_counter_ : pattern_predictor_.Predict(sync_counter_); uint64_t increment = frequency_ratio_.p * static_cast<uint64_t>( 0xffffffff / (predicted_period * frequency_ratio_.q)); if (increment > 0x20000000) { increment = 0x20000000; } phase_increment = static_cast<uint32_t>(increment); } sync_counter_ = 0; } } else { // Normal behaviour: switch banks. uint8_t bank_index = mode_ + 1; if (bank_index > 2) { bank_index = 0; } mode_ = static_cast<GeneratorMode>(bank_index); bank = wt_waves + mode_ * 64 * 257 - (mode_ & 2) * 4 * 257; } } // PLL stuff if (sync_ && range_ == GENERATOR_RANGE_HIGH) { // Fast tracking of the local oscillator to the external oscillator. local_osc_phase_increment_ += static_cast<int32_t>( target_phase_increment_ - local_osc_phase_increment_) >> 8; local_osc_phase_ += local_osc_phase_increment_; // Slow phase realignment between the master oscillator and the local // oscillator. int32_t phase_error = local_osc_phase_ - phase; phase_increment = local_osc_phase_increment_ + (phase_error >> 13); } x += x_increment; y += y_increment; if (control & CONTROL_FREEZE) { *out++ = sample; continue; } uint16_t x_integral = x >> 13; uint16_t y_integral = y >> 13; const int16_t* wave_1 = &bank[(x_integral + y_integral * 8) * 257]; const int16_t* wave_2 = wave_1 + 257 * 8; uint16_t x_fractional = x << 3; int32_t y_fractional = (y << 2) & 0x7fff; int32_t s = 0; for (int32_t subsample = 0; subsample < 4; ++subsample) { int32_t y_1 = Crossfade(wave_1, wave_1 + 257, phase << 1, x_fractional); int32_t y_2 = Crossfade(wave_2, wave_2 + 257, phase << 1, x_fractional); int32_t y_mix = y_1 + ((y_2 - y_1) * y_fractional >> 15); int32_t folded = Interpolate1022( ws_smooth_bipolar_fold, (y_mix + 32768) << 16); y_mix = y_mix + ((folded - y_mix) * wf_gain >> 15); s += y_mix * kDownsampleCoefficient[subsample]; phase += (phase_increment >> 3); } lp_state_0 += f * ((s >> 16) - lp_state_0) >> 15; lp_state_1 += f * (lp_state_0 - lp_state_1) >> 15; uint8_t flags = 0; sample.bipolar = lp_state_1; sample.unipolar = sample.bipolar + 32768; if (sample.unipolar & 0x8000) { flags |= FLAG_END_OF_ATTACK; } if (phase & 0x80000000) { flags |= FLAG_END_OF_RELEASE; } sample.flags = flags; *out++ = sample; } previous_sample_ = sample; phase_ = phase; phase_increment_ = phase_increment; x_ = x; y_ = y; bi_lp_state_[0] = lp_state_0; bi_lp_state_[1] = lp_state_1; } } // namespace tides