Line data Source code
1 : #pragma once
2 :
3 : // Chromatic tuner based on pitch detection from the input signal.
4 : // Uses the YIN difference d(tau)=sum_j(x[j]-x[j+tau])^2 and cumulative mean
5 : // normalized difference to estimate period tau; frequency is Fs/tau and cents
6 : // error is 1200*log2(freq / nearest_note_freq).
7 :
8 : #include <atomic>
9 : #include <vector>
10 :
11 : #include "audio/effects/core/effect.h"
12 :
13 : namespace Amplitron {
14 :
15 : class TunerPedal : public Effect {
16 : public:
17 : TunerPedal();
18 : void process(float* buffer, int num_samples) override;
19 : void set_sample_rate(int sample_rate) override;
20 : void reset() override;
21 29 : const char* name() const override { return "Tuner"; }
22 3 : const char* type_id() const override { return "Tuner"; }
23 94 : std::vector<EffectParam>& params() override { return params_; }
24 0 : const std::vector<EffectParam>& params() const override { return params_; }
25 :
26 : // Tuner detection results (audio thread writes, UI thread reads)
27 : std::atomic<float> detected_freq{0.0f};
28 : std::atomic<float> detected_cents{0.0f};
29 : std::atomic<int> detected_note{-1}; // 0=C, 1=C#, 2=D, ... 11=B
30 : std::atomic<int> detected_octave{-1};
31 : std::atomic<bool> signal_detected{false};
32 :
33 : static const char* note_name(int note_index);
34 :
35 : private:
36 : std::vector<EffectParam> params_;
37 :
38 : // YIN pitch detection buffer
39 : // 4096 samples at 48kHz gives ~85ms window, ample headroom for E2 (82.41Hz, period ~582
40 : // samples)
41 : static constexpr int YIN_BUFFER_SIZE = 4096;
42 : std::vector<float> yin_buffer_;
43 : int yin_write_pos_ = 0;
44 : bool yin_buffer_full_ = false;
45 :
46 : // YIN internals
47 : float yin_detect_pitch(float a4_ref);
48 : void freq_to_note(float freq, float a4_ref);
49 :
50 : // Preallocated work buffers for yin_detect_pitch() (avoids RT heap allocs)
51 : std::vector<float> yin_buf_; // linearized circular buffer (YIN_BUFFER_SIZE)
52 : std::vector<float> yin_d_; // cumulative mean normalized difference (YIN_BUFFER_SIZE/2)
53 :
54 : // Update rate control (~15 updates/sec)
55 : int samples_since_update_ = 0;
56 : int update_interval_ = 0;
57 : void recalc_update_interval();
58 : };
59 :
60 : } // namespace Amplitron
|