Line data Source code
1 : #pragma once
2 :
3 : // Pitch shifting effect for semitone-based transposition.
4 : // The shift ratio is r = 2^(semitones/12); the processor reads from a delay
5 : // line/resampling window at rate r and crossfades windows to reduce clicks,
6 : // producing y[n] from time-scaled input samples.
7 :
8 : #include "audio/effects/effect.h"
9 : #include <vector>
10 : #include <array>
11 :
12 : namespace Amplitron {
13 :
14 : /**
15 : * Pitch Shifter — shifts pitch by +/- 12 semitones using a dual-tap
16 : * granular overlap-add algorithm.
17 : *
18 : * Two read pointers scan through a circular buffer at a rate determined by
19 : * the pitch ratio. A raised-cosine (Hann) crossfade between the two taps
20 : * hides the grain boundary discontinuities.
21 : *
22 : * Controls: Shift (semitones), Fine (cents), Mix.
23 : */
24 : class PitchShifter : public Effect {
25 : public:
26 : PitchShifter();
27 : void process(float* buffer, int num_samples) override;
28 : void set_sample_rate(int sample_rate) override;
29 : void reset() override;
30 3 : const char* name() const override { return "Pitch Shifter"; }
31 6 : const char* type_id() const override { return "Pitch Shifter"; }
32 124 : std::vector<EffectParam>& params() override { return params_; }
33 :
34 : private:
35 : std::vector<EffectParam> params_;
36 :
37 : // Grain buffer
38 : std::vector<float> grain_buf_;
39 : int buf_size_ = 0;
40 : int write_pos_ = 0;
41 :
42 : // Two crossfading read taps (phase in [0, buf_size_))
43 : float read_phase_a_ = 0.0f;
44 : float read_phase_b_ = 0.0f;
45 :
46 : // Parameter smoothing
47 : float shift_smooth_ = 0.0f;
48 : float fine_smooth_ = 0.0f;
49 : float mix_smooth_ = 0.0f;
50 :
51 : // --- NEW OPTIMIZATION VARIABLES ---
52 : // Adds the function to pre-calculate the cosine math
53 : void build_hann_lut();
54 :
55 : // 8192 is a power of 2 (allows fast bitwise wrapping) and fits easily in L1 cache
56 : std::array<float, 8192> hann_lut_;
57 :
58 : // Cached pitch ratio to avoid per-sample pow()
59 : float ratio_ = 1.0f;
60 :
61 : float read_linear(float phase) const;
62 : };
63 :
64 : } // namespace Amplitron
|