Skip to main content

rill_core_dsp/generators/
noise.rs

1//! Генераторы шума (White, Pink, Brown, Blue, Violet)
2
3use super::Generator;
4use crate::algorithm::{Algorithm, AlgorithmCategory, AlgorithmMetadata};
5use crate::filters::{FilterParams, FilterType, OnePole};
6use crate::vector::prelude::*;
7use rill_core::traits::{ActionContext, ProcessResult};
8use rill_core::Transcendental;
9
10/// Тип шума
11#[derive(Debug, Clone, Copy, PartialEq)]
12pub enum NoiseType {
13    White,  // Равномерный спектр
14    Pink,   // 3dB/октава (1/f)
15    Brown,  // 6dB/октава (1/f²)
16    Blue,   // +3dB/октава
17    Violet, // +6dB/октава
18}
19
20impl NoiseType {
21    pub fn name(&self) -> &'static str {
22        match self {
23            NoiseType::White => "White Noise",
24            NoiseType::Pink => "Pink Noise",
25            NoiseType::Brown => "Brown Noise",
26            NoiseType::Blue => "Blue Noise",
27            NoiseType::Violet => "Violet Noise",
28        }
29    }
30
31    pub fn description(&self) -> &'static str {
32        match self {
33            NoiseType::White => "Equal energy per Hz",
34            NoiseType::Pink => "Equal energy per octave (1/f)",
35            NoiseType::Brown => "Brownian motion (1/f²)",
36            NoiseType::Blue => "Increasing with frequency (+3dB/oct)",
37            NoiseType::Violet => "Strongly increasing (+6dB/oct)",
38        }
39    }
40}
41
42/// Генератор шума (Xorshift RNG)
43pub struct NoiseGenerator<T: Transcendental> {
44    /// Тип шума
45    noise_type: NoiseType,
46    /// Амплитуда
47    amplitude: ScalarVector1<T>,
48    /// Состояние RNG (Xorshift) - храним как u32 для битовых операций
49    state: u32,
50    /// Фильтры для окраски
51    pink_filters: [OnePole<T>; 6],
52    brown_state: ScalarVector1<T>,
53    /// Частота дискретизации
54    sample_rate: f32,
55    /// Для синего шума
56    last_white: ScalarVector1<T>,
57    /// Для фиолетового шума
58    last_white1: ScalarVector1<T>,
59    last_white2: ScalarVector1<T>,
60}
61
62impl<T: Transcendental> NoiseGenerator<T> {
63    /// Создать новый генератор шума
64    pub fn new(noise_type: NoiseType, amplitude: T) -> Self {
65        // Создаем OnePole фильтры через new с правильными параметрами
66        let filter_params = FilterParams {
67            filter_type: FilterType::LowPass,
68            cutoff: 1.0,
69            q: 0.707,
70            gain_db: 0.0,
71        };
72
73        Self {
74            noise_type,
75            amplitude: ScalarVector1::splat(amplitude),
76            state: 123456789,
77            pink_filters: [
78                OnePole::new(filter_params.clone()),
79                OnePole::new(filter_params.clone()),
80                OnePole::new(filter_params.clone()),
81                OnePole::new(filter_params.clone()),
82                OnePole::new(filter_params.clone()),
83                OnePole::new(filter_params),
84            ],
85            brown_state: ScalarVector1::splat(T::ZERO),
86            sample_rate: 44100.0,
87            last_white: ScalarVector1::splat(T::ZERO),
88            last_white1: ScalarVector1::splat(T::ZERO),
89            last_white2: ScalarVector1::splat(T::ZERO),
90        }
91    }
92
93    /// Xorshift RNG (работает с u32, возвращает f32 через Transcendental)
94    #[inline(always)]
95    fn xorshift(&mut self) -> T {
96        let mut x = self.state;
97
98        x ^= x << 13;
99        x ^= x >> 17;
100        x ^= x << 5;
101
102        self.state = x;
103
104        // Конвертируем u32 в f32 в диапазоне [-1, 1]
105        // Берем старшие 24 бита для равномерного распределения
106        let float_val = (x as f32 / 2147483648.0) - 1.0; // 2^31
107        T::from_f32(float_val)
108    }
109
110    /// Генерация белого шума
111    #[inline(always)]
112    fn generate_white(&mut self) -> ScalarVector1<T> {
113        ScalarVector1::splat(self.xorshift()) * self.amplitude
114    }
115
116    /// Генерация розового шума (1/f)
117    /// Метод Paul Kellett'a
118    fn generate_pink(&mut self) -> ScalarVector1<T> {
119        let white = self.xorshift();
120
121        // 6-полосный фильтр для аппроксимации 1/f
122        let mut output = T::ZERO;
123        for filter in &mut self.pink_filters {
124            output = output.add(filter.process_sample(white));
125        }
126
127        ScalarVector1::splat(output) * self.amplitude / ScalarVector1::splat(T::from_f32(3.0))
128        // нормализация
129    }
130
131    /// Генерация броуновского шума (1/f²)
132    fn generate_brown(&mut self) -> ScalarVector1<T> {
133        let white = self.xorshift();
134
135        // Интегратор с ограничением
136        self.brown_state =
137            self.brown_state + ScalarVector1::splat(white) * ScalarVector1::splat(T::from_f32(0.1));
138        // Клиппинг
139        let one_vec = ScalarVector1::splat(T::from_f32(1.0));
140        let neg_one_vec = ScalarVector1::splat(T::from_f32(-1.0));
141        self.brown_state = self.brown_state.clamp(&neg_one_vec, &one_vec);
142
143        self.brown_state * self.amplitude
144    }
145
146    /// Генерация синего шума (+3dB/октава)
147    fn generate_blue(&mut self) -> ScalarVector1<T> {
148        let white = self.xorshift();
149        let white_vec = ScalarVector1::splat(white);
150
151        // Дифференциатор (high-pass)
152        let diff = white_vec - self.last_white;
153        self.last_white = white_vec;
154
155        diff * self.amplitude
156    }
157
158    /// Генерация фиолетового шума (+6dB/октава)
159    fn generate_violet(&mut self) -> ScalarVector1<T> {
160        let white = self.xorshift();
161        let white_vec = ScalarVector1::splat(white);
162
163        // Двойной дифференциатор
164        let diff1 = white_vec - self.last_white1;
165        let diff2 = diff1 - self.last_white2;
166        self.last_white2 = diff1;
167        self.last_white1 = white_vec;
168
169        diff2 * self.amplitude
170    }
171}
172
173impl<T: Transcendental> Algorithm<T> for NoiseGenerator<T> {
174    fn init(&mut self, sample_rate: f32) {
175        self.sample_rate = sample_rate;
176
177        // Настройка фильтров для розового шума
178        let freqs = [5.0, 15.0, 45.0, 135.0, 405.0, 1215.0];
179        for (i, &freq) in freqs.iter().enumerate() {
180            // Обновляем параметры фильтра через set_cutoff
181            // Для этого нужно импортировать трейт Filter
182            use crate::filters::Filter;
183            self.pink_filters[i].set_cutoff(freq);
184        }
185
186        self.reset();
187    }
188
189    fn reset(&mut self) {
190        self.state = 123456789;
191        self.brown_state = ScalarVector1::splat(T::ZERO);
192        self.last_white = ScalarVector1::splat(T::ZERO);
193        self.last_white1 = ScalarVector1::splat(T::ZERO);
194        self.last_white2 = ScalarVector1::splat(T::ZERO);
195        for filter in &mut self.pink_filters {
196            filter.reset();
197        }
198    }
199
200    fn process(
201        &mut self,
202        input: Option<&[T]>,
203        output: &mut [T],
204        _ctx: &ActionContext,
205    ) -> ProcessResult<()> {
206        let input = input.unwrap_or(&[]);
207        for out in output.iter_mut() {
208            *out = match self.noise_type {
209                NoiseType::White => self.generate_white().extract(0),
210                NoiseType::Pink => self.generate_pink().extract(0),
211                NoiseType::Brown => self.generate_brown().extract(0),
212                NoiseType::Blue => self.generate_blue().extract(0),
213                NoiseType::Violet => self.generate_violet().extract(0),
214            };
215        }
216        Ok(())
217    }
218
219    fn metadata(&self) -> AlgorithmMetadata {
220        AlgorithmMetadata {
221            name: self.noise_type.name(),
222            category: AlgorithmCategory::Generator,
223            description: self.noise_type.description(),
224            author: "Rill",
225            version: env!("CARGO_PKG_VERSION"),
226        }
227    }
228}
229
230impl<T: Transcendental> Generator<T> for NoiseGenerator<T> {
231    fn phase(&self) -> T {
232        T::ZERO
233    } // Шум не имеет фазы
234
235    fn set_phase(&mut self, _phase: T) {}
236
237    fn frequency(&self) -> f32 {
238        0.0
239    }
240
241    fn set_frequency(&mut self, _freq: f32) {}
242
243    fn amplitude(&self) -> T {
244        self.amplitude.extract(0)
245    }
246
247    fn set_amplitude(&mut self, amp: T) {
248        let one = T::from_f32(1.0);
249        let clamped = if amp > one {
250            one
251        } else if amp < T::ZERO {
252            T::ZERO
253        } else {
254            amp
255        };
256        self.amplitude = ScalarVector1::splat(clamped);
257    }
258}