flamo 0.1.6__py3-none-any.whl → 0.1.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
flamo/auxiliary/reverb.py CHANGED
@@ -67,7 +67,18 @@ class inverse_map_gamma(torch.nn.Module):
67
67
  return y
68
68
  else:
69
69
  return y**(1/self.delays)
70
-
70
+
71
+ class map_gfdn_gamma(torch.nn.Module):
72
+ def __init__(self, delays: torch.Tensor, n_groups: int, fs: int):
73
+ super().__init__()
74
+ self.delays = delays
75
+ self.n_groups = n_groups
76
+ self.fs = fs
77
+
78
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
79
+ """Map input to grouped RT values."""
80
+ gamma = torch.mul(rt2slope(x, self.fs).unsqueeze(-1), self.delays.unsqueeze(0))
81
+ return gamma
71
82
 
72
83
  class HomogeneousFDN:
73
84
  r"""
@@ -281,7 +292,7 @@ class HomogeneousFDN:
281
292
  rt60, self.config_dict.sample_rate, torch.tensor(self.delays)
282
293
  ).squeeze()
283
294
  return 10 ** (gdB / 20)
284
-
295
+
285
296
 
286
297
  class parallelFDNAccurateGEQ(dsp.parallelAccurateGEQ):
287
298
  r"""
@@ -371,6 +382,70 @@ class parallelFDNAccurateGEQ(dsp.parallelAccurateGEQ):
371
382
  self.input_channels = len(self.delays)
372
383
  self.output_channels = len(self.delays)
373
384
 
385
+ class parallelGFDNAccurateGEQ(parallelFDNAccurateGEQ):
386
+ # TODO
387
+ def __init__(
388
+ self,
389
+ octave_interval: int = 1,
390
+ n_groups: int = 2,
391
+ nfft: int = 2**11,
392
+ fs: int = 48000,
393
+ delays: torch.Tensor = None,
394
+ alias_decay_db: float = 0.0,
395
+ start_freq: float = 31.25,
396
+ end_freq: float = 16000.0,
397
+ device=None
398
+ ):
399
+ assert (delays is not None), "Delays must be provided"
400
+ self.delays = delays
401
+ map = map_gfdn_gamma(delays, n_groups, fs)
402
+ super().__init__(
403
+ size=( ),
404
+ octave_interval=octave_interval,
405
+ nfft=nfft,
406
+ delays=delays,
407
+ fs=fs,
408
+ map=map,
409
+ alias_decay_db=alias_decay_db,
410
+ start_freq=start_freq,
411
+ end_freq=end_freq,
412
+ device=device
413
+ )
414
+ self.n_gains = self.size[0]
415
+ self.size = (n_groups * self.size[0], len(delays))
416
+ self.param = param = torch.nn.Parameter(
417
+ torch.empty(self.size, device=self.device), requires_grad=self.requires_grad
418
+ )
419
+
420
+ def get_poly_coeff(self, param):
421
+ r"""
422
+ Computes the polynomial coefficients for the SOS section.
423
+ """
424
+ a = torch.zeros((3, self.size[0]+1, len(self.delays)), device=self.device)
425
+ b = torch.zeros((3, self.size[0]+1, len(self.delays)), device=self.device)
426
+ for n_i in range(len(self.delays)):
427
+ for i_group in range(self.n_gains):
428
+ (
429
+ b[:, i_group * (self.n_gains) : (i_group + 1) * self.n_gains, n_i],
430
+ a[:, i_group * (self.n_gains) : (i_group + 1) * self.n_gains, n_i],
431
+ ) = accurate_geq(
432
+ target_gain=param[
433
+ i_group * self.n_gains : (i_group + 1) * self.n_gains, n_i
434
+ ],
435
+ center_freq=self.center_freq,
436
+ shelving_crossover=self.shelving_crossover,
437
+ fs=self.fs,
438
+ device=self.device,
439
+ )
440
+
441
+ b_aa = torch.einsum('p, pon -> pon', self.alias_envelope_dcy.to(torch.double), b.to(torch.double))
442
+ a_aa = torch.einsum('p, pon -> pon', self.alias_envelope_dcy.to(torch.double), a.to(torch.double))
443
+ B = torch.fft.rfft(b_aa, self.nfft, dim=0)
444
+ A = torch.fft.rfft(a_aa, self.nfft, dim=0)
445
+ H_temp = torch.prod(B, dim=1) / (torch.prod(A, dim=1))
446
+ H = torch.where(torch.abs(torch.prod(A, dim=1)) != 0, H_temp, torch.finfo(H_temp.dtype).eps*torch.ones_like(H_temp))
447
+ H_type = torch.complex128 if param.dtype == torch.float64 else torch.complex64
448
+ return H.to(H_type), B, A
374
449
 
375
450
  class parallelFDNGEQ(dsp.parallelGEQ):
376
451
  r"""
@@ -721,7 +796,6 @@ class parallelFDNPEQ(Filter):
721
796
  self.output_channels = len(self.delays)
722
797
 
723
798
 
724
-
725
799
  class parallelFirstOrderShelving(dsp.parallelFilter):
726
800
 
727
801
  def __init__(
flamo/functional.py CHANGED
@@ -1,3 +1,4 @@
1
+ import math
1
2
  import torch
2
3
  import torch.nn as nn
3
4
  import numpy as np
@@ -175,11 +176,12 @@ def signal_gallery(
175
176
  - ``sweep``: A linear sweep from 20 Hz to 20 kHz.
176
177
  - ``wgn``: White Gaussian noise.
177
178
  - ``exp``: An exponential decay signal.
179
+ - ``velvet``: A velvet noise signal with density :attr:`rate` impulses per second.
178
180
  - ``reference``: A reference signal provided as argument :attr:`reference`.
179
181
 
180
182
  **Arguments**:
181
183
  - **batch_size** (int): The number of batches to generate.
182
- - **n_samples** (int): THe signal length in samples.
184
+ - **n_samples** (int): The signal length in samples.
183
185
  - **n_channel** (int): The number of channels in each signal.
184
186
  - **signal_type** (str, optional): The type of signal to generate. Defaults to 'impulse'.
185
187
  - **fs** (int, optional): The sampling frequency of the signals. Defaults to 48000.
@@ -198,6 +200,7 @@ def signal_gallery(
198
200
  "exp",
199
201
  "reference",
200
202
  "noise",
203
+ "velvet",
201
204
  }
202
205
 
203
206
  if signal_type not in signal_types:
@@ -243,6 +246,12 @@ def signal_gallery(
243
246
  .expand(batch_size, n_samples, n)
244
247
  .to(device)
245
248
  )
249
+ case "velvet":
250
+ x = torch.empty((batch_size, n_samples, n), device=device)
251
+ for i_batch in range(batch_size):
252
+ for i_ch in range(n):
253
+ x[i_batch, :, i_ch] = gen_velvet_noise(n_samples, fs, rate, device)
254
+ return x
246
255
  case "reference":
247
256
  if isinstance(reference, torch.Tensor):
248
257
  return reference.expand(batch_size, n_samples, n).to(device)
@@ -254,6 +263,38 @@ def signal_gallery(
254
263
  return torch.randn((batch_size, n_samples, n), device=device)
255
264
 
256
265
 
266
+ def gen_velvet_noise(n_samples: int, fs: int, density: float, device: str | torch.device = None) -> torch.Tensor:
267
+ r"""
268
+ Generate a velvet noise sequence.
269
+ **Arguments**:
270
+ - **n_samples** (int): The length of the signal in samples.
271
+ - **fs** (int): The sampling frequency of the signal in Hz.
272
+ - **density** (float): The density of impulses in impulses per second.
273
+ - **device** (str | torch.device): The device of constructed tensors.
274
+ **Returns**:
275
+ - torch.Tensor: A tensor of shape (n_samples,) containing the velvet noise sequence.
276
+ """
277
+ Td = fs / density # average distance between impulses
278
+ num_impulses = n_samples / Td # expected number of impulses
279
+ floor_impulses = math.floor(num_impulses)
280
+ grid = torch.arange(floor_impulses) * Td
281
+
282
+ jitter_factors = torch.rand(floor_impulses)
283
+ impulse_indices = torch.ceil(grid + jitter_factors * (Td - 1)).long()
284
+
285
+ # first impulse is at position 0 and all indices are within bounds
286
+ impulse_indices[0] = 0
287
+ impulse_indices = torch.clamp(impulse_indices, max=n_samples - 1)
288
+
289
+ # Generate random signs (+1 or -1)
290
+ signs = 2 * torch.randint(0, 2, (floor_impulses,)) - 1
291
+
292
+ # Construct sparse signal
293
+ sequence = torch.zeros(n_samples, device=device)
294
+ sequence[impulse_indices] = signs.float()
295
+
296
+ return sequence
297
+
257
298
  def hertz2rad(hertz: torch.Tensor, fs: int):
258
299
  r"""
259
300
  Convert frequency from Hz to rad.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flamo
3
- Version: 0.1.6
3
+ Version: 0.1.8
4
4
  Summary: An Open-Source Library for Frequency-Domain Differentiable Audio Processing
5
5
  Project-URL: Homepage, https://github.com/gdalsanto/flamo
6
6
  Project-URL: Issues, https://github.com/gdalsanto/flamo/issues
@@ -1,11 +1,11 @@
1
1
  flamo/__init__.py,sha256=ujezWOJfD7DUoj4q1meeMUnB97rOEtNR7mYw_PE9LMg,49
2
- flamo/functional.py,sha256=9wl6fHkc8KMB5IMvbd_K7-z8Z2Miw0qOsNxWPItliPU,35138
2
+ flamo/functional.py,sha256=8cKYzR5GDzH4ph4ja7x1znNFL-8ufWoxa666QHaZR1A,36917
3
3
  flamo/utils.py,sha256=ypGKSABZMphgIrjCKgCH-zgR7BaupRbyzuUhsZFqAAM,3350
4
4
  flamo/auxiliary/__init__.py,sha256=7lVNh8OxHloZ4KPmp-iTUJnUbi8XbuRzGaQ3Z-NKXio,42
5
5
  flamo/auxiliary/eq.py,sha256=eIWMIq0ggizXLhTdeWWbgBXWUFXCJyoEbkBH7Gzasao,6779
6
6
  flamo/auxiliary/filterbank.py,sha256=02w8dI8HoNDtKpdVhSJkIkd-h-KNXvZtivf3l4_ozzU,9866
7
7
  flamo/auxiliary/minimize.py,sha256=fMTAAAk9yD7Y4luKS4XA1-HTq44xo2opq_dRPRrhlIY,2474
8
- flamo/auxiliary/reverb.py,sha256=9iKSuyuqRiHGGvaj0eizqVpu2V7plsX13OWiB6o1whU,31636
8
+ flamo/auxiliary/reverb.py,sha256=9c9aLRJCBnudNF3kefcf76HobFicrsxI3GcXyiOcYxo,34737
9
9
  flamo/auxiliary/scattering.py,sha256=qlK8cynrpde56yLlbPuScC0Y1VmsPb0SFXl6Xisv6hA,9420
10
10
  flamo/auxiliary/velvet.py,sha256=B4pYEnhaQPkh02pxqiGdAhLRX2g-eWtHezphi0_h4Qs,4201
11
11
  flamo/auxiliary/config/config.py,sha256=CxXj-8sLq0_m9KyLg1a6NwLoK1UvTz3i0jZOLraq14I,2893
@@ -18,7 +18,7 @@ flamo/optimize/utils.py,sha256=R5-KoZagRho3eykY88pC3UB2mc5SsE4Yv9X-ogskXdA,1610
18
18
  flamo/processor/__init__.py,sha256=paGdxGVZgA2VAs0tBwRd0bobzGxeyK79DS7ZGO8drkI,41
19
19
  flamo/processor/dsp.py,sha256=n92YJPrES-ydwHgXmZ9RkFevIC3n-Wh4X8I1QNZqcV0,126378
20
20
  flamo/processor/system.py,sha256=9XwLtaGEVs9glVOFvyiPnQpsnR_Wjrv6k1i1qCs8D1Q,42516
21
- flamo-0.1.6.dist-info/METADATA,sha256=n7uiBeQ1bqIP4Xwpmyx7Ah3FxCl2Xowucprz00lk2BM,7825
22
- flamo-0.1.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
23
- flamo-0.1.6.dist-info/licenses/LICENSE,sha256=smMocRH7xdPT5RvFNqSLtbSNzohXJM5G_rX1Qaej6vg,1120
24
- flamo-0.1.6.dist-info/RECORD,,
21
+ flamo-0.1.8.dist-info/METADATA,sha256=a0hX9Mfk2wSUX7nPKwesQ6WYnmpgSUNpf_iBitMz2iA,7825
22
+ flamo-0.1.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
23
+ flamo-0.1.8.dist-info/licenses/LICENSE,sha256=smMocRH7xdPT5RvFNqSLtbSNzohXJM5G_rX1Qaej6vg,1120
24
+ flamo-0.1.8.dist-info/RECORD,,
File without changes