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