hunterHearsPy 1.0.3__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.
@@ -0,0 +1,36 @@
1
+ # ruff: noqa: D104
2
+ from __future__ import annotations
3
+
4
+ from hunterHearsPy.theTypes import (
5
+ ArraySpectrograms as ArraySpectrograms, ArrayType as ArrayType, ArrayWaveforms as ArrayWaveforms,
6
+ callableReturnsNDArray as callableReturnsNDArray, NormalizationReverter as NormalizationReverter,
7
+ ParametersShortTimeFFT as ParametersShortTimeFFT, ParametersSTFT as ParametersSTFT, ParametersUniversal as ParametersUniversal,
8
+ Spectrogram as Spectrogram, SpectrogramDtype as SpectrogramDtype, Waveform as Waveform, WaveformDtype as WaveformDtype,
9
+ WaveformMetadata as WaveformMetadata, WindowingFunction as WindowingFunction, WindowingFunctionDtype as WindowingFunctionDtype)
10
+
11
+ # isort: split
12
+ from hunterHearsPy.amplitude import normalizeArrayWaveforms as normalizeArrayWaveforms, normalizeWaveform as normalizeWaveform
13
+ from hunterHearsPy.clippingArrays import applyHardLimit as applyHardLimit, applyHardLimitComplexValued as applyHardLimitComplexValued
14
+ from hunterHearsPy.windowingFunctions import cosineWings as cosineWings, equalPower as equalPower, halfsine as halfsine, tukey as tukey
15
+
16
+ # isort: split
17
+ from hunterHearsPy.autoRevert import moveToAxisOfOperation as moveToAxisOfOperation
18
+
19
+ # isort: split
20
+ from hunterHearsPy.ioAudio import (
21
+ getWaveformMetadata as getWaveformMetadata, lengthWindowingFunctionDEFAULT as lengthWindowingFunctionDEFAULT,
22
+ loadSpectrograms as loadSpectrograms, loadWaveforms as loadWaveforms, parametersDEFAULT as parametersDEFAULT,
23
+ parametersShortTimeFFTUniversal as parametersShortTimeFFTUniversal, parametersSTFTUniversal as parametersSTFTUniversal,
24
+ readAudioFile as readAudioFile, resampleWaveform as resampleWaveform, setParametersUniversal as setParametersUniversal,
25
+ spectrogramToWAV as spectrogramToWAV, stft as stft, universalDtypeSpectrogram as universalDtypeSpectrogram,
26
+ universalDtypeWaveform as universalDtypeWaveform, waveformSpectrogramWaveform as waveformSpectrogramWaveform,
27
+ windowingFunctionCallableDEFAULT as windowingFunctionCallableDEFAULT,
28
+ windowingFunctionCallableUniversal as windowingFunctionCallableUniversal, writeWAV as writeWAV)
29
+
30
+ # isort: split
31
+ from contextlib import suppress
32
+
33
+ with suppress(ModuleNotFoundError): # noqa: RUF067
34
+ from hunterHearsPy.windowingFunctionsTensor import (
35
+ cosineWingsTensor as cosineWingsTensor, equalPowerTensor as equalPowerTensor, halfsineTensor as halfsineTensor,
36
+ tukeyTensor as tukeyTensor)
@@ -0,0 +1,170 @@
1
+ """Normalize audio waveform amplitudes.
2
+
3
+ (AI generated docstring)
4
+
5
+ You can use this module to scale audio waveforms to a target peak amplitude. Each normalization
6
+ function returns both the scaled waveform and a reversion callable that restores the original
7
+ amplitude scale when applied to any waveform derived from the normalized result.
8
+
9
+ Contents
10
+ --------
11
+ Functions
12
+ normalizeArrayWaveforms
13
+ Normalize multiple waveforms in an array to a specified peak amplitude.
14
+ normalizeWaveform
15
+ Normalize a waveform to a specified peak amplitude.
16
+
17
+ """
18
+ from __future__ import annotations
19
+
20
+ from numpy import divide, finfo as numpy_finfo, max as numpy_max, multiply
21
+ from typing import cast, overload, TYPE_CHECKING
22
+
23
+ if TYPE_CHECKING:
24
+ from hunterHearsPy import ArrayWaveforms, NormalizationReverter, Waveform
25
+
26
+ def normalizeWaveform(waveform: Waveform, amplitudeNorm: float = 1.0) -> tuple[Waveform, NormalizationReverter]:
27
+ """Normalize a waveform to a specified peak amplitude.
28
+
29
+ (AI generated docstring)
30
+
31
+ You can use this function to scale a `Waveform` [1] so that its absolute peak value equals
32
+ `amplitudeNorm`. This function also returns `revertNormalization`, a `NormalizationReverter` [2]
33
+ callable that reverses the scaling when applied to any waveform derived from `waveformNormalized`.
34
+
35
+ Parameters
36
+ ----------
37
+ waveform : Waveform
38
+ The input audio waveform to normalize.
39
+ amplitudeNorm : float = 1.0
40
+ Target peak amplitude. The absolute maximum value of `waveformNormalized` equals `amplitudeNorm`.
41
+
42
+ Returns
43
+ -------
44
+ waveformNormalized : Waveform
45
+ The scaled waveform with absolute peak value equal to `amplitudeNorm`.
46
+ revertNormalization : NormalizationReverter
47
+ A callable that reverses the normalization scaling. Apply `revertNormalization` to any
48
+ waveform derived from `waveformNormalized` to restore the original amplitude scale.
49
+
50
+ Warns
51
+ -----
52
+ UserWarning
53
+ If `amplitudeNorm` is 0, `normalizeWaveform` replaces it with the smallest positive finite
54
+ value representable in the dtype of `waveform` using `numpy.finfo` [3] and continues.
55
+ UserWarning
56
+ If `waveform` contains only zeros, `waveformNormalized` will also be all zeros.
57
+ `revertNormalization` will divide by `amplitudeNorm` rather than by the waveform peak.
58
+
59
+ See Also
60
+ --------
61
+ `normalizeArrayWaveforms`
62
+ Normalize multiple waveforms in an array to a specified peak amplitude.
63
+
64
+ Amplitude Scaling
65
+ -----------------
66
+ `normalizeWaveform` computes the absolute peak of `waveform` as the maximum of `waveform.max()`
67
+ and `-waveform.min()`, then multiplies every sample by `amplitudeNorm / peakAbsolute`.
68
+ `revertNormalization` reverses this by dividing every sample by the same factor.
69
+
70
+ Examples
71
+ --------
72
+ Normalize a waveform and revert the normalization:
73
+
74
+ ```python
75
+ from hunterHearsPy import normalizeWaveform
76
+
77
+ waveformNormalized, revertNormalization = normalizeWaveform(waveform.copy())
78
+ waveformReverted = revertNormalization(waveformNormalized)
79
+ ```
80
+
81
+ References
82
+ ----------
83
+ [1] `hunterHearsPy.theTypes.Waveform`
84
+
85
+ [2] `hunterHearsPy.theTypes.NormalizationReverter`
86
+
87
+ [3] numpy.finfo - NumPy reference
88
+ https://numpy.org/doc/stable/reference/generated/numpy.finfo.html
89
+
90
+ """
91
+ amplitudeNorm = amplitudeNorm or float(numpy_finfo(waveform.dtype).tiny.astype(waveform.dtype))
92
+
93
+ peakAbsolute: float = abs(float(numpy_max([waveform.max(), -waveform.min()]))) or 1.0
94
+ amplitudeAdjustment: float = amplitudeNorm / peakAbsolute
95
+
96
+ multiply(waveform, amplitudeAdjustment, out=waveform)
97
+
98
+ @overload
99
+ def revertNormalization(waveformDescendant: Waveform) -> Waveform: ...
100
+ @overload
101
+ def revertNormalization(waveformDescendant: ArrayWaveforms) -> ArrayWaveforms: ...
102
+ def revertNormalization(waveformDescendant: ArrayWaveforms | Waveform) -> ArrayWaveforms | Waveform:
103
+ return divide(waveformDescendant, amplitudeAdjustment, out=waveformDescendant)
104
+ return waveform, revertNormalization
105
+
106
+ def normalizeArrayWaveforms(arrayWaveforms: ArrayWaveforms, amplitudeNorm: float = 1.0) -> tuple[ArrayWaveforms, list[NormalizationReverter]]:
107
+ """Normalize multiple waveforms in an array to a specified peak amplitude.
108
+
109
+ (AI generated docstring)
110
+
111
+ You can use this function to scale each `Waveform` [1] in an `ArrayWaveforms` [2] so that
112
+ each waveform's absolute peak value equals `amplitudeNorm`. This function also returns
113
+ `listRevertNormalization`, a list of `NormalizationReverter` [3] callables, one per waveform,
114
+ that each reverse the scaling for the corresponding waveform at the matching last-axis index.
115
+
116
+ `normalizeArrayWaveforms` delegates each individual waveform normalization to
117
+ `normalizeWaveform` [4] and modifies `arrayWaveforms` in place before returning it.
118
+
119
+ Parameters
120
+ ----------
121
+ arrayWaveforms : ArrayWaveforms
122
+ Array containing multiple waveforms indexed on the last axis. Shape is
123
+ (channels, samples, waveforms).
124
+ amplitudeNorm : float = 1.0
125
+ Target peak amplitude. The absolute maximum value of each normalized waveform equals
126
+ `amplitudeNorm`.
127
+
128
+ Returns
129
+ -------
130
+ arrayWaveformsNormalized : ArrayWaveforms
131
+ The array of normalized waveforms, identical to `arrayWaveforms` modified in place.
132
+ Each waveform is scaled to peak amplitude `amplitudeNorm`.
133
+ listRevertNormalization : list[NormalizationReverter]
134
+ A list of callables indexed in the same order as the last axis of `arrayWaveforms`.
135
+ Each callable reverses the normalization scaling for the corresponding waveform.
136
+
137
+ See Also
138
+ --------
139
+ `normalizeWaveform`
140
+ Normalize a single waveform to a specified peak amplitude.
141
+
142
+ Examples
143
+ --------
144
+ Normalize all waveforms in an array and revert each one:
145
+
146
+ ```python
147
+ from hunterHearsPy import normalizeArrayWaveforms
148
+
149
+ arrayNormalized, listRevertNormalization = normalizeArrayWaveforms(arrayWaveforms.copy())
150
+ for indexWaveform in range(arrayNormalized.shape[-1]):
151
+ arrayReverted[..., indexWaveform] = listRevertNormalization[indexWaveform](
152
+ arrayReverted[..., indexWaveform]
153
+ )
154
+ ```
155
+
156
+ References
157
+ ----------
158
+ [1] `hunterHearsPy.theTypes.Waveform`
159
+
160
+ [2] `hunterHearsPy.theTypes.ArrayWaveforms`
161
+
162
+ [3] `hunterHearsPy.theTypes.NormalizationReverter`
163
+
164
+ [4] `normalizeWaveform`
165
+
166
+ """
167
+ listRevertNormalization: list[NormalizationReverter] = [lambda makeTypeCheckerHappy: makeTypeCheckerHappy] * arrayWaveforms.shape[-1]
168
+ for index in range(arrayWaveforms.shape[-1]):
169
+ arrayWaveforms[..., index], listRevertNormalization[index] = normalizeWaveform(cast("Waveform", arrayWaveforms[..., index]), amplitudeNorm)
170
+ return arrayWaveforms, listRevertNormalization
@@ -0,0 +1,75 @@
1
+ """Temporarily reposition array axes and restore the original axis order on context exit.
2
+
3
+ Contents
4
+ --------
5
+ Functions
6
+ moveToAxisOfOperation
7
+ Move an array axis to an operation position, then automatically restore the original axis order on exit.
8
+
9
+ """
10
+ from __future__ import annotations
11
+
12
+ from contextlib import contextmanager
13
+ from hunterHearsPy import normalizeWaveform
14
+ from numpy import moveaxis
15
+ from typing import TYPE_CHECKING
16
+
17
+ if TYPE_CHECKING:
18
+ from collections.abc import Generator
19
+ from hunterHearsPy import ArrayType, Waveform
20
+
21
+ @contextmanager
22
+ def moveToAxisOfOperation(arrayTarget: ArrayType, axisSource: int, axisOfOperation: int = -1) -> Generator[ArrayType]:
23
+ """Move an array axis to an operation position, then automatically restore the original axis order on exit.
24
+
25
+ You can use `moveToAxisOfOperation` as a context manager to temporarily rearrange the axes of
26
+ `arrayTarget`. The context yields `arrayStandardized`, a `numpy.moveaxis` [1] view of `arrayTarget`
27
+ with `axisSource` moved to `axisOfOperation`. Because `arrayStandardized` shares memory with
28
+ `arrayTarget`, modifications to `arrayStandardized` inside the context are reflected in `arrayTarget`.
29
+ When the context exits, `arrayTarget` retains its original axis order.
30
+
31
+ Parameters
32
+ ----------
33
+ arrayTarget : ArrayType
34
+ The array whose axis to move.
35
+ axisSource : int
36
+ The source axis position to move. Negative values count from the last axis.
37
+ axisOfOperation : int = -1
38
+ The destination axis position for `axisSource`. Negative values count from the last axis.
39
+
40
+ Yields
41
+ ------
42
+ arrayStandardized : ArrayType
43
+ A view of `arrayTarget` with `axisSource` at position `axisOfOperation`.
44
+
45
+ Examples
46
+ --------
47
+ Move axis 0 to the last position and modify values inside the context:
48
+
49
+ ```python
50
+ import numpy
51
+ from hunterHearsPy import moveToAxisOfOperation
52
+
53
+ arrayAxisOperation = numpy.arange(24).reshape(2, 3, 4)
54
+ with moveToAxisOfOperation(arrayAxisOperation, axisSource=0, axisOfOperation=-1) as arrayStandardized:
55
+ arrayStandardized += 10
56
+ ```
57
+
58
+ References
59
+ ----------
60
+ [1] numpy.moveaxis
61
+ https://numpy.org/doc/stable/reference/generated/numpy.moveaxis.html
62
+
63
+ """
64
+ arrayStandardized: ArrayType = moveaxis(arrayTarget, axisSource, axisOfOperation)
65
+ try:
66
+ yield arrayStandardized
67
+ finally:
68
+ moveaxis(arrayStandardized, axisOfOperation, axisSource)
69
+
70
+ """
71
+ @contextmanager
72
+ def normalizeUnnormalize(waveform: Waveform, amplitudeNorm: float = 1.0):
73
+ pass
74
+ """
75
+ # C:\apps\loudnessWeightedSpectrogram\loudnessWeightedSpectrogram\spectrogram.py
@@ -0,0 +1,143 @@
1
+ """Clip and limit array values using magnitude-based hard limits.
2
+
3
+ (AI generated docstring)
4
+
5
+ You can use this module to apply hard clipping [1] to NumPy [2] arrays, constraining element
6
+ magnitudes within bounds defined by a comparand array. The module is not yet fully implemented
7
+ and may not correctly handle all cases.
8
+
9
+ Contents
10
+ --------
11
+ Functions
12
+ applyHardLimit
13
+ Clip the elements of a real-valued array to stay within the magnitude of a comparand.
14
+ applyHardLimitComplexValued
15
+ Clip the elements of a complex-valued array using magnitude-based scaling.
16
+
17
+ References
18
+ ----------
19
+ [1] Clipping (signal processing) - Wikipedia
20
+ https://en.wikipedia.org/wiki/Clipping_(signal_processing)
21
+
22
+ [2] NumPy
23
+ https://numpy.org/doc/stable/
24
+ """
25
+ from __future__ import annotations
26
+
27
+ from numpy import absolute, complexfloating, float64, floating, multiply, ones_like
28
+ from typing import Any, TYPE_CHECKING
29
+
30
+ if TYPE_CHECKING:
31
+ from hunterHearsPy import ArrayType
32
+ from numpy.typing import ArrayLike, NDArray
33
+
34
+ def applyHardLimit(arrayTarget: ArrayType, comparand: ArrayLike = 1.0) -> ArrayType:
35
+ """Clip the elements of `arrayTarget` to the magnitude bounds defined by `comparand`.
36
+
37
+ This function applies a hard amplitude limit element-wise to `arrayTarget`. Elements whose
38
+ magnitude exceeds the corresponding magnitude of `comparand` are reduced toward zero until
39
+ the element magnitude equals the comparand magnitude. The operation modifies `arrayTarget`
40
+ in place and returns a reference to it.
41
+
42
+ Parameters
43
+ ----------
44
+ arrayTarget : ArrayType
45
+ The array to clip. Modified in place.
46
+ comparand : ArrayLike = 1.0
47
+ The magnitude threshold. Elements of `arrayTarget` whose magnitude strictly exceeds the
48
+ corresponding magnitude in `comparand` are clipped to that comparand magnitude.
49
+
50
+ Returns
51
+ -------
52
+ arrayClipped : ArrayType
53
+ A reference to the modified `arrayTarget`.
54
+
55
+ See Also
56
+ --------
57
+ `applyHardLimitComplexValued`
58
+ Clip complex-valued array elements using magnitude-based scaling.
59
+
60
+ References
61
+ ----------
62
+ [1] Clipping (signal processing) - Wikipedia
63
+ https://en.wikipedia.org/wiki/Clipping_(signal_processing)
64
+
65
+ [2] numpy.typing.NDArray
66
+ https://numpy.org/doc/stable/reference/typing.html#numpy.typing.NDArray
67
+
68
+ [3] numpy.typing.ArrayLike
69
+ https://numpy.org/doc/stable/reference/typing.html#numpy.typing.ArrayLike
70
+
71
+ """
72
+ maskTrueAboveThreshold = absolute(comparand) - absolute(arrayTarget) < 0.0
73
+ reduction = arrayTarget - (absolute(arrayTarget) - absolute(comparand))
74
+ arrayTarget[maskTrueAboveThreshold] = reduction[maskTrueAboveThreshold]
75
+ return arrayTarget
76
+
77
+ def applyHardLimitComplexValued(
78
+ arrayTarget: ArrayType,
79
+ comparand: NDArray[floating[Any] | complexfloating[Any, Any]],
80
+ penalty: float = 1.0
81
+ ) -> ArrayType:
82
+ """Clip the elements of complex-valued `arrayTarget` by scaling magnitudes to stay within `comparand`.
83
+
84
+ This function applies a magnitude-based hard limit to each element of `arrayTarget`. When the
85
+ magnitude of an element strictly exceeds the corresponding value in `comparand`, the element is
86
+ scaled down by a power of the ratio of comparand magnitude to target magnitude. Elements whose
87
+ magnitudes are within the limit are left unchanged. This function returns a new array and does
88
+ not modify `arrayTarget` in place.
89
+
90
+ Parameters
91
+ ----------
92
+ arrayTarget : NDArray[complexfloating[Any, Any]]
93
+ The complex-valued array to clip.
94
+ comparand : NDArray[floating[Any] | complexfloating[Any, Any]]
95
+ The magnitude threshold array. Only the magnitudes of `comparand` values are used.
96
+ penalty : float = 1.0
97
+ Exponent applied to the scaling factor when limiting is needed. Values greater than 1.0
98
+ produce more aggressive clipping; values between 0.0 and 1.0 produce less aggressive clipping.
99
+
100
+ Returns
101
+ -------
102
+ arrayResult : NDArray[complexfloating[Any, Any]]
103
+ A new array with the same shape and dtype as `arrayTarget`, with element magnitudes
104
+ clipped according to `comparand`.
105
+
106
+ See Also
107
+ --------
108
+ `applyHardLimit`
109
+ Clip real-valued array elements to stay within the magnitude of a comparand.
110
+
111
+ Mathematics
112
+ -----------
113
+ magnitude scaling : equation
114
+ ```
115
+ Let a ≜ `arrayTarget`, c ≜ `comparand`, p ≜ `penalty`,
116
+ s ≜ (|cᵢ| / |aᵢ|)
117
+
118
+ For each element i where |aᵢ| > |cᵢ|:
119
+ resultᵢ = aᵢ × sᵖ
120
+
121
+ For each element i where |aᵢ| ≤ |cᵢ|:
122
+ resultᵢ = aᵢ
123
+ ```
124
+
125
+ References
126
+ ----------
127
+ [1] Clipping (signal processing) - Wikipedia
128
+ https://en.wikipedia.org/wiki/Clipping_(signal_processing)
129
+
130
+ [2] numpy.typing.NDArray
131
+ https://numpy.org/doc/stable/reference/typing.html#numpy.typing.NDArray
132
+
133
+ """
134
+ magnitudeArrayTarget: NDArray[float64] = absolute(arrayTarget, dtype=float64)
135
+ magnitudeComparand: NDArray[float64] = absolute(comparand, dtype=float64)
136
+
137
+ maskTrueAboveThreshold = magnitudeComparand - magnitudeArrayTarget < 0.0
138
+
139
+ arrayCoefficients_Float64: NDArray[float64] = magnitudeComparand[maskTrueAboveThreshold] / magnitudeArrayTarget[maskTrueAboveThreshold]
140
+ arrayCoefficients_ComplexValued: ArrayType = ones_like(arrayTarget, dtype=arrayTarget.dtype)
141
+ arrayCoefficients_ComplexValued[maskTrueAboveThreshold] = arrayCoefficients_Float64**penalty
142
+
143
+ return multiply(arrayTarget, arrayCoefficients_ComplexValued)