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