Files

copied
Last update 6 years 3 months by Olivier Gillet
Filesyarns
..
bootloader
drivers
hardware_design
resources
scale_editor
song
__init__.py
internal_clock.h
just_intonation_processor.cc
just_intonation_processor.h
layout_configurator.cc
layout_configurator.h
makefile
midi_handler.cc
midi_handler.h
multi.cc
multi.h
part.cc
part.h
resources.cc
resources.h
settings.cc
settings.h
storage_manager.cc
storage_manager.h
ui.cc
ui.h
voice.cc
voice.h
yarns.cc
voice.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. // // ----------------------------------------------------------------------------- // // Voice. #include "yarns/voice.h" #include <algorithm> #include <cstdio> #include <cstdlib> #include "stmlib/midi/midi.h" #include "stmlib/utils/dsp.h" #include "stmlib/utils/random.h" #include "yarns/resources.h" namespace yarns { using namespace stmlib; using namespace stmlib_midi; const int32_t kOctave = 12 << 7; const int32_t kMaxNote = 120 << 7; void Voice::Init() { note_ = -1; note_source_ = note_target_ = note_portamento_ = 60 << 7; gate_ = false; mod_velocity_ = 0; ResetAllControllers(); modulation_rate_ = 0; pitch_bend_range_ = 2; vibrato_range_ = 0; lfo_phase_ = portamento_phase_ = 0; portamento_phase_increment_ = 1U << 31; portamento_exponential_shape_ = false; trigger_duration_ = 2; for (uint8_t i = 0; i < kNumOctaves; ++i) { calibrated_dac_code_[i] = 54586 - 5133 * i; } dirty_ = false; oscillator_.Init( calibrated_dac_code_[3] - calibrated_dac_code_[8], calibrated_dac_code_[3]); } void Voice::Calibrate(uint16_t* calibrated_dac_code) { std::copy( &calibrated_dac_code[0], &calibrated_dac_code[kNumOctaves], &calibrated_dac_code_[0]); } inline uint16_t Voice::NoteToDacCode(int32_t note) const { if (note <= 0) { note = 0; } if (note >= kMaxNote) { note = kMaxNote - 1; } uint8_t octave = 0; while (note >= kOctave) { note -= kOctave; ++octave; } // Note is now between 0 and kOctave // Octave indicates the octave. Look up in the DAC code table. int32_t a = calibrated_dac_code_[octave]; int32_t b = calibrated_dac_code_[octave + 1]; return a + ((b - a) * note / kOctave); } void Voice::ResetAllControllers() { mod_pitch_bend_ = 8192; mod_wheel_ = 0; std::fill(&mod_aux_[0], &mod_aux_[7], 0); } void Voice::Refresh() { // Compute base pitch with portamento. portamento_phase_ += portamento_phase_increment_; if (portamento_phase_ < portamento_phase_increment_) { portamento_phase_ = 0; portamento_phase_increment_ = 0; note_source_ = note_target_; } uint16_t portamento_level = portamento_exponential_shape_ ? Interpolate824(lut_env_expo, portamento_phase_) : portamento_phase_ >> 16; int32_t note = note_source_ + \ ((note_target_ - note_source_) * portamento_level >> 16); note_portamento_ = note; // Add pitch-bend. note += static_cast<int32_t>(mod_pitch_bend_ - 8192) * pitch_bend_range_ >> 6; // Add transposition/fine tuning. note += tuning_; // Add vibrato. if (modulation_rate_ < 100) { lfo_phase_ += lut_lfo_increments[modulation_rate_]; } else { lfo_phase_ += lfo_pll_phase_increment_; } int32_t lfo = lfo_phase_ < 1UL << 31 ? -32768 + (lfo_phase_ >> 15) : 0x17fff - (lfo_phase_ >> 15); note += lfo * mod_wheel_ * vibrato_range_ >> 15; mod_aux_[0] = mod_velocity_ << 9; mod_aux_[1] = mod_wheel_ << 9; mod_aux_[5] = static_cast<uint16_t>(mod_pitch_bend_) << 2; mod_aux_[6] = (lfo * mod_wheel_ >> 7) + 32768; mod_aux_[7] = lfo + 32768; if (retrigger_delay_) { --retrigger_delay_; } if (trigger_pulse_) { --trigger_pulse_; } if (trigger_phase_increment_) { trigger_phase_ += trigger_phase_increment_; if (trigger_phase_ < trigger_phase_increment_) { trigger_phase_ = 0; trigger_phase_increment_ = 0; } } if (note != note_ || dirty_) { note_dac_code_ = NoteToDacCode(note); note_ = note; dirty_ = false; } } void Voice::NoteOn( int16_t note, uint8_t velocity, uint8_t portamento, bool trigger) { note_source_ = note_portamento_; note_target_ = note; if (!portamento) { note_source_ = note_target_; } portamento_phase_ = 0; if (portamento <= 50) { portamento_phase_increment_ = lut_portamento_increments[portamento << 1]; portamento_exponential_shape_ = true; } else { uint32_t base_increment = lut_portamento_increments[(portamento - 51) << 1]; uint32_t delta = abs(note_target_ - note_source_) + 1; portamento_phase_increment_ = (1536 * (base_increment >> 11) / delta) << 11; CONSTRAIN(portamento_phase_increment_, 1, 2147483647); portamento_exponential_shape_ = false; } mod_velocity_ = velocity; if (gate_ && trigger) { retrigger_delay_ = 2; } if (trigger) { trigger_pulse_ = trigger_duration_ * 8; trigger_phase_ = 0; trigger_phase_increment_ = lut_portamento_increments[trigger_duration_]; } gate_ = true; } void Voice::NoteOff() { gate_ = false; } void Voice::ControlChange(uint8_t controller, uint8_t value) { switch (controller) { case kCCModulationWheelMsb: mod_wheel_ = value; break; case kCCBreathController: mod_aux_[3] = value << 9; break; case kCCFootPedalMsb: mod_aux_[4] = value << 9; break; } } uint16_t Voice::trigger_dac_code() const { if (trigger_phase_ <= trigger_phase_increment_) { return calibrated_dac_code_[3]; // 0V. } else { int32_t velocity_coefficient = trigger_scale_ ? mod_velocity_ << 8 : 32768; int32_t value = 0; switch(trigger_shape_) { case TRIGGER_SHAPE_SQUARE: value = 32767; break; case TRIGGER_SHAPE_LINEAR: value = 32767 - (trigger_phase_ >> 17); break; default: { const int16_t* table = waveform_table[ trigger_shape_ - TRIGGER_SHAPE_EXPONENTIAL]; value = Interpolate824(table, trigger_phase_); } break; } value = value * velocity_coefficient >> 15; int32_t max = calibrated_dac_code_[8]; int32_t min = calibrated_dac_code_[3]; return min + ((max - min) * value >> 15); } } static const uint16_t kHighestNote = 128 * 128; static const uint16_t kPitchTableStart = 116 * 128; void Oscillator::Init(int32_t scale, int32_t offset) { audio_buffer_.Init(); phase_ = 0; next_sample_ = 0; high_ = false; scale_ = scale; offset_ = offset; integrator_state_ = 0; } uint32_t Oscillator::ComputePhaseIncrement(int16_t midi_pitch) { if (midi_pitch >= kHighestNote) { midi_pitch = kHighestNote - 1; } int32_t ref_pitch = midi_pitch; ref_pitch -= kPitchTableStart; size_t num_shifts = 0; while (ref_pitch < 0) { ref_pitch += kOctave; ++num_shifts; } uint32_t a = lut_oscillator_increments[ref_pitch >> 4]; uint32_t b = lut_oscillator_increments[(ref_pitch >> 4) + 1]; uint32_t phase_increment = a + \ (static_cast<int32_t>(b - a) * (ref_pitch & 0xf) >> 4); phase_increment >>= num_shifts; return phase_increment; } void Oscillator::RenderSilence() { size_t size = kAudioBlockSize; while (size--) { audio_buffer_.Overwrite(offset_); } } void Oscillator::RenderSine(uint32_t phase_increment) { size_t size = kAudioBlockSize; while (size--) { phase_ += phase_increment; int32_t sample = Interpolate1022(wav_sine, phase_); audio_buffer_.Overwrite(offset_ - (scale_ * sample >> 16)); } } void Oscillator::RenderNoise() { size_t size = kAudioBlockSize; while (size--) { int16_t sample = Random::GetSample(); audio_buffer_.Overwrite(offset_ - (scale_ * sample >> 16)); } } void Oscillator::RenderSaw(uint32_t phase_increment) { uint32_t phase = phase_; int32_t next_sample = next_sample_; size_t size = kAudioBlockSize; while (size--) { int32_t this_sample = next_sample; next_sample = 0; phase += phase_increment; if (phase < phase_increment) { uint32_t t = phase / (phase_increment >> 16); this_sample -= ThisBlepSample(t); next_sample -= NextBlepSample(t); } next_sample += phase >> 17; this_sample = (this_sample - 16384) << 1; audio_buffer_.Overwrite(offset_ - (scale_ * this_sample >> 16)); } next_sample_ = next_sample; phase_ = phase; } void Oscillator::RenderSquare( uint32_t phase_increment, uint32_t pw, bool integrate) { uint32_t phase = phase_; int32_t next_sample = next_sample_; int32_t integrator_state = integrator_state_; int16_t integrator_coefficient = phase_increment >> 18; size_t size = kAudioBlockSize; while (size--) { int32_t this_sample = next_sample; next_sample = 0; phase += phase_increment; if (!high_) { if (phase >= pw) { uint32_t t = (phase - pw) / (phase_increment >> 16); this_sample += ThisBlepSample(t); next_sample += NextBlepSample(t); high_ = true; } } if (high_ && (phase < phase_increment)) { uint32_t t = phase / (phase_increment >> 16); this_sample -= ThisBlepSample(t); next_sample -= NextBlepSample(t); high_ = false; } next_sample += phase < pw ? 0 : 32767; this_sample = (this_sample - 16384) << 1; if (integrate) { integrator_state += integrator_coefficient * (this_sample - integrator_state) >> 15; this_sample = integrator_state << 3; } audio_buffer_.Overwrite(offset_ - (scale_ * this_sample >> 16)); } integrator_state_ = integrator_state; next_sample_ = next_sample; phase_ = phase; } void Oscillator::Render(uint8_t mode, int16_t note, bool gate) { if (mode == 0 || audio_buffer_.writable() < kAudioBlockSize) { return; } if ((mode & 0x80) && !gate) { RenderSilence(); return; } uint32_t phase_increment = ComputePhaseIncrement(note); switch ((mode & 0x0f) - 1) { case 0: RenderSaw(phase_increment); break; case 1: RenderSquare(phase_increment, 0x40000000, false); break; case 2: RenderSquare(phase_increment, 0x80000000, false); break; case 3: RenderSquare(phase_increment, 0x80000000, true); break; case 4: RenderSine(phase_increment); break; default: RenderNoise(); break; } } } // namespace yarns
Report a bug