Repository: pyfar/pyfar
Pull request #624 (2024-06-11 06:13:35)

Enhance user warning for writing clipped audio files
### Which issue(s) are closed by this pull request?

Closes #623 




Patch:
diff --git a/HISTORY.rst b/HISTORY.rst
index 391d98b4..9471d559 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -2,6 +2,10 @@
 History
 =======
 
+0.6.7 (2024-06-17)
+------------------
+* Make compatibile for numpy 2.0 (PR #629)
+
 0.6.6 (2024-06-07)
 ------------------
 * Improve documentation (PR #569, #574, #590, #591, #597, #605)
diff --git a/docs/index.rst b/docs/index.rst
index cc508ad0..5921a19b 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,1 +1,4 @@
+pyfar
+=====
+
 .. include:: header.rst
diff --git a/pyfar/__init__.py b/pyfar/__init__.py
index ebad9a2c..fe6d28e4 100644
--- a/pyfar/__init__.py
+++ b/pyfar/__init__.py
@@ -4,7 +4,7 @@
 
 __author__ = """The pyfar developers"""
 __email__ = ''
-__version__ = '0.6.6'
+__version__ = '0.6.7'
 
 
 from .classes.audio import Signal, TimeData, FrequencyData
diff --git a/pyfar/classes/orientations.py b/pyfar/classes/orientations.py
index c73271bc..ca74a874 100644
--- a/pyfar/classes/orientations.py
+++ b/pyfar/classes/orientations.py
@@ -3,11 +3,15 @@ import numpy as np
 import warnings
 
 import pyfar as pf
+if np.__version__ < '2.0.0':
+    from numpy import VisibleDeprecationWarning
+else:
+    from numpy.exceptions import VisibleDeprecationWarning
 
 # this warning needs to be caught and appears if numpy array are generated
 # from nested lists containing lists of unequal lengths, e.g.,
 #  [[1, 0, 0], [1, 0]]
-warnings.filterwarnings("error", category=np.VisibleDeprecationWarning)
+warnings.filterwarnings("error", category=VisibleDeprecationWarning)
 
 
 class Orientations(Rotation):
@@ -54,10 +58,10 @@ class Orientations(Rotation):
 
     """
 
-    def __init__(self, quat=None, normalize=True, copy=True):
+    def __init__(self, quat=None, normalize=True, copy=True, **kwargs):
         if quat is None:
             quat = np.array([0., 0., 0., 1.])
-        super().__init__(quat, copy=copy)
+        super().__init__(quat, copy=copy, **kwargs)
 
     @classmethod
     def from_view_up(cls, views, ups):
@@ -92,7 +96,7 @@ class Orientations(Rotation):
         try:
             views = np.atleast_2d(views).astype(np.float64)
             ups = np.atleast_2d(ups).astype(np.float64)
-        except np.VisibleDeprecationWarning:
+        except VisibleDeprecationWarning:
             raise ValueError("Expected `views` and `ups` to have shape (N, 3)")
 
         # check views and ups
diff --git a/pyfar/dsp/dsp.py b/pyfar/dsp/dsp.py
index 887f1cd1..ee1f4cbf 100644
--- a/pyfar/dsp/dsp.py
+++ b/pyfar/dsp/dsp.py
@@ -524,8 +524,11 @@ def time_window(signal, interval, window='hann', shape='symmetric',
                 window_zeropadded, signal_win.sampling_rate)
 
     if return_window:
+        interval_str = str(tuple(interval))
+        if 'np' in interval_str:
+            interval_str = f"({', '.join([str(i) for i in interval])})"
         window_fin.comment = (
-            f"Time window with parameters interval={tuple(interval)},"
+            f"Time window with parameters interval={interval_str}, "
             f"window='{window}', shape='{shape}', unit='{unit}', "
             f"crop='{crop}'")
         return signal_win, window_fin
@@ -925,7 +928,7 @@ def minimum_phase(signal, n_fft=None, truncate=True):
         >>> from scipy.signal import remez
         >>> import matplotlib.pyplot as plt
         >>> freq = [0, 0.2, 0.3, 1.0]
-        >>> h_linear = pf.Signal(remez(151, freq, [1, 0], Hz=2.), 44100)
+        >>> h_linear = pf.Signal(remez(151, freq, [1, 0], fs=2.), 44100)
         >>> # create minimum phase impulse responses
         >>> h_min = pf.dsp.minimum_phase(h_linear, truncate=False)
         >>> # plot the result
diff --git a/pyfar/io/io.py b/pyfar/io/io.py
index 9051cf69..1cfa49d5 100644
--- a/pyfar/io/io.py
+++ b/pyfar/io/io.py
@@ -463,7 +463,11 @@ def write_audio(signal, filename, subtype=None, overwrite=True, **kwargs):
         if (np.any(data > 1.) and
                 subtype.upper() not in ['FLOAT', 'DOUBLE', 'VORBIS']):
             warnings.warn(
-                f'{format}-files of subtype {subtype} are clipped to +/- 1.')
+                (f'{format}-files of subtype {subtype} are clipped to +/- 1. '
+                 'Normalize your audio with pyfar.dsp.normalize to 1-LSB, with'
+                 ' LSB being the least significant bit (e.g. 2**-15 for '
+                 "16 bit) or use non-clipping subtypes 'FLOAT', 'DOUBLE', or "
+                 "'VORBIS' (see pyfar.io.audio_subtypes)"))
         soundfile.write(
             file=filename, data=data.T, samplerate=sampling_rate,
             subtype=subtype, **kwargs)
diff --git a/setup.cfg b/setup.cfg
index 8966e32a..7e7a310a 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 0.6.6
+current_version = 0.6.7
 commit = True
 tag = True
 
diff --git a/setup.py b/setup.py
index b074d1e4..9b1954bb 100644
--- a/setup.py
+++ b/setup.py
@@ -67,7 +67,7 @@ setup(
         "Documentation": "https://pyfar.readthedocs.io/",
         "Source Code": "https://github.com/pyfar/pyfar",
     },
-    version='0.6.6',
+    version='0.6.7',
     zip_safe=False,
     python_requires='>=3.8'
 )


Test patch:
diff --git a/tests/test_dsp.py b/tests/test_dsp.py
index cbc7e27f..0788f5f0 100644
--- a/tests/test_dsp.py
+++ b/tests/test_dsp.py
@@ -529,10 +529,12 @@ def test_time_window_return_window(crop):
     assert isinstance(win, pyfar.Signal)
     assert sig_win.sampling_rate == win.sampling_rate
     npt.assert_allclose(sig_win.time, win.time)
-    desired_comment = (
-        f"Time window with parameters interval=(4, 8),"
-        f"window='hann', shape='symmetric', unit='samples', crop='{crop}'")
-    assert win.comment == desired_comment
+    assert 'interval=(4, 8)' in win.comment
+    assert "window='hann'," in win.comment
+    assert "shape='symmetric'," in win.comment
+    assert "unit='samples'," in win.comment
+    assert f"crop='{crop}'" in win.comment
+    assert 'Time window with parameters' in win.comment
 
 
 def test_time_window_return_window_error():