1 // Copyright 2014 Olivier Gillet. 2 // 3 // Author: Olivier Gillet (ol.gillet@gmail.com) 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 // THE SOFTWARE. 22 // 23 // See http://creativecommons.org/licenses/MIT/ for more information. 24 // 25 // ----------------------------------------------------------------------------- 26 // 27 // Pitch shifter. 28 29 #ifndef CLOUDS_DSP_FX_PITCH_SHIFTER_H_ 30 #define CLOUDS_DSP_FX_PITCH_SHIFTER_H_ 31 32 #include "stmlib/stmlib.h" 33 #include "stmlib/dsp/dsp.h" 34 35 #include "clouds/resources.h" 36 #include "clouds/dsp/frame.h" 37 #include "clouds/dsp/fx/fx_engine.h" 38 39 namespace clouds { 40 41 class PitchShifter { 42 public: PitchShifter()43 PitchShifter() { } ~PitchShifter()44 ~PitchShifter() { } 45 Init(uint16_t * buffer)46 void Init(uint16_t* buffer) { 47 engine_.Init(buffer); 48 phase_ = 0; 49 size_ = 2047.0f; 50 dry_wet_ = 0.0f; 51 } 52 Clear()53 void Clear() { 54 engine_.Clear(); 55 } 56 Process(FloatFrame * input_output,size_t size)57 inline void Process(FloatFrame* input_output, size_t size) { 58 while (size--) { 59 Process(input_output); 60 ++input_output; 61 } 62 } 63 Process(FloatFrame * input_output)64 void Process(FloatFrame* input_output) { 65 typedef E::Reserve<2047, E::Reserve<2047> > Memory; 66 E::DelayLine<Memory, 0> left; 67 E::DelayLine<Memory, 1> right; 68 E::Context c; 69 engine_.Start(&c); 70 71 phase_ += (1.0f - ratio_) / size_; 72 if (phase_ >= 1.0f) { 73 phase_ -= 1.0f; 74 } 75 if (phase_ <= 0.0f) { 76 phase_ += 1.0f; 77 } 78 float tri = 2.0f * (phase_ >= 0.5f ? 1.0f - phase_ : phase_); 79 tri = stmlib::Interpolate(lut_window, tri, LUT_WINDOW_SIZE-1); 80 float phase = phase_ * size_; 81 float half = phase + size_ * 0.5f; 82 if (half >= size_) { 83 half -= size_; 84 } 85 86 float wet = 0.0f; 87 88 c.Read(input_output->l, 1.0f); 89 c.Write(left, 0.0f); 90 c.InterpolateHermite(left, phase, tri); 91 c.InterpolateHermite(left, half, 1.0f - tri); 92 c.Write(wet, 0.0f); 93 94 input_output->l += (wet - input_output->l) * dry_wet_; 95 96 c.Read(input_output->r, 1.0f); 97 c.Write(right, 0.0f); 98 c.InterpolateHermite(right, phase, tri); 99 c.InterpolateHermite(right, half, 1.0f - tri); 100 c.Write(wet, 0.0f); 101 102 input_output->r += (wet - input_output->r) * dry_wet_; 103 104 } 105 set_ratio(float ratio)106 inline void set_ratio(float ratio) { 107 ratio_ = ratio; 108 } 109 set_dry_wet(float dry_wet)110 inline void set_dry_wet(float dry_wet) { 111 dry_wet_ = dry_wet; 112 } 113 set_size(float size)114 inline void set_size(float size) { 115 float target_size = 128.0f + (2047.0f - 128.0f) * size * size * size; 116 ONE_POLE(size_, target_size, 0.05f) 117 } 118 119 private: 120 typedef FxEngine<4096, FORMAT_16_BIT> E; 121 E engine_; 122 float phase_; 123 float ratio_; 124 float size_; 125 float dry_wet_; 126 127 DISALLOW_COPY_AND_ASSIGN(PitchShifter); 128 }; 129 130 } // namespace clouds 131 132 #endif // CLOUDS_DSP_FX_MINI_CHORUS_H_ 133