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 "audio/effects/effect.h"
9 : #include <atomic>
10 :
11 : namespace Amplitron {
12 :
13 : class TunerPedal : public Effect {
14 : public:
15 : TunerPedal();
16 : void process(float* buffer, int num_samples) override;
17 : void set_sample_rate(int sample_rate) override;
18 : void reset() override;
19 29 : const char* name() const override { return "Tuner"; }
20 3 : const char* type_id() const override { return "Tuner"; }
21 103 : std::vector<EffectParam>& params() override { return params_; }
22 :
23 : // Tuner detection results (audio thread writes, UI thread reads)
24 : std::atomic<float> detected_freq{0.0f};
25 : std::atomic<float> detected_cents{0.0f};
26 : std::atomic<int> detected_note{-1}; // 0=C, 1=C#, 2=D, ... 11=B
27 : std::atomic<int> detected_octave{-1};
28 : std::atomic<bool> signal_detected{false};
29 :
30 : static const char* note_name(int note_index);
31 :
32 : private:
33 : std::vector<EffectParam> params_;
34 :
35 : // YIN pitch detection buffer
36 : // 4096 samples at 48kHz gives ~85ms window, ample headroom for E2 (82.41Hz, period ~582 samples)
37 : static constexpr int YIN_BUFFER_SIZE = 4096;
38 : std::vector<float> yin_buffer_;
39 : int yin_write_pos_ = 0;
40 : bool yin_buffer_full_ = false;
41 :
42 : // YIN internals
43 : float yin_detect_pitch(float a4_ref);
44 : void freq_to_note(float freq, float a4_ref);
45 :
46 : // Preallocated work buffers for yin_detect_pitch() (avoids RT heap allocs)
47 : std::vector<float> yin_buf_; // linearized circular buffer (YIN_BUFFER_SIZE)
48 : std::vector<float> yin_d_; // cumulative mean normalized difference (YIN_BUFFER_SIZE/2)
49 :
50 : // Update rate control (~15 updates/sec)
51 : int samples_since_update_ = 0;
52 : int update_interval_ = 0;
53 : void recalc_update_interval();
54 : };
55 :
56 : } // namespace Amplitron
|