Repository: audeering/auglib

Issue:
PinkNoise() can fail with wrong signal length of noise
```python
import auglib
import numpy as np

signal = np.ones((1, 30045))
transform = auglib.transform.PinkNoise()
transform(signal)
```

returns

```
ValueError: operands could not be broadcast together with shapes (1,30045) (1,30044)
```

Discussion:
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/audeering/auglib/pull/24?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=audeering) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Comparison is base [(`ef48643`)](https://app.codecov.io/gh/audeering/auglib/commit/ef48643f15408b680e09f211054fb487e8d8ece7?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=audeering) 100.0% compared to head [(`cc799ce`)](https://app.codecov.io/gh/audeering/auglib/pull/24?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=audeering) 100.0%.

<details><summary>Additional details and impacted files</summary>


| [Files](https://app.codecov.io/gh/audeering/auglib/pull/24?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=audeering) | Coverage Δ | |
|---|---|---|
| [auglib/core/transform.py](https://app.codecov.io/gh/audeering/auglib/pull/24?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=audeering#diff-YXVnbGliL2NvcmUvdHJhbnNmb3JtLnB5) | `100.0% <100.0%> (ø)` | |

</details>

Patch:
diff --git a/auglib/core/transform.py b/auglib/core/transform.py
index 808ca87..7387129 100644
--- a/auglib/core/transform.py
+++ b/auglib/core/transform.py
@@ -3261,16 +3261,20 @@ class PinkNoise(Base):
         def psd(f):
             return 1 / np.where(f == 0, float("inf"), np.sqrt(f))
 
-        white_noise = np.fft.rfft(np.random.randn(samples))
+        # Add extra sample
+        # to ensure correct length for odd samples
+        length = samples + 1
+
+        white_noise = np.fft.rfft(np.random.randn(length))
 
         # Normalized pink noise shape
-        pink_shape = psd(np.fft.rfftfreq(samples))
+        pink_shape = psd(np.fft.rfftfreq(length))
         pink_shape = pink_shape / np.sqrt(np.mean(pink_shape**2))
 
         white_noise_shaped = white_noise * pink_shape
         pink_noise = np.fft.irfft(white_noise_shaped)
 
-        return np.atleast_2d(pink_noise)
+        return np.atleast_2d(pink_noise[:samples])
 
 
 class Prepend(Base):


Test patch:
diff --git a/tests/test_transform_pink_noise.py b/tests/test_transform_pink_noise.py
index 4a34ee3..ef80f4c 100644
--- a/tests/test_transform_pink_noise.py
+++ b/tests/test_transform_pink_noise.py
@@ -74,3 +74,19 @@ def test_pink_noise(duration, sampling_rate, gain_db, snr_db):
     assert noise.shape == expected_noise.shape
     assert noise.dtype == expected_noise.dtype
     np.testing.assert_almost_equal(noise, expected_noise)
+
+
+@pytest.mark.parametrize(
+    "signal",
+    [
+        # Odd,
+        # compare https://github.com/audeering/auglib/issues/23
+        np.ones((1, 30045)),
+        # Even
+        np.ones((1, 200)),
+    ],
+)
+def test_pink_noise_odd_and_even_samples(signal):
+    transform = auglib.transform.PinkNoise()
+    augmented_signal = transform(signal)
+    assert signal.shape == augmented_signal.shape