analyzeAudio 0.0.12__py3-none-any.whl → 0.0.14__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.
@@ -40,7 +40,7 @@ def getSI_SDRmean(pathFilenameAlpha: str | PathLike[Any], pathFilenameBeta: str
40
40
  return SI_SDRmean
41
41
 
42
42
  @cachetools.cached(cache=cacheAudioAnalyzers)
43
- def ffprobeShotgunAndCache(pathFilename: str | PathLike[Any]) -> dict[str, float]:
43
+ def ffprobeShotgunAndCache(pathFilename: str | PathLike[Any]) -> dict[str, float | numpy.ndarray]:
44
44
  # for lavfi amovie/movie, the colons after driveLetter letters need to be escaped twice.
45
45
  pFn = pathlib.PureWindowsPath(pathFilename)
46
46
  lavfiPathFilename = pFn.drive.replace(":", "\\\\:")+pathlib.PureWindowsPath(pFn.root,pFn.relative_to(pFn.anchor)).as_posix()
@@ -63,16 +63,20 @@ def ffprobeShotgunAndCache(pathFilename: str | PathLike[Any]) -> dict[str, float
63
63
  stdoutFFprobe, _DISCARDstderr = systemProcessFFprobe.communicate()
64
64
  FFprobeStructured = pythonizeFFprobe(stdoutFFprobe.decode('utf-8'))[-1]
65
65
 
66
- dictionaryAspectsAnalyzed: dict[str, float] = {}
66
+ dictionaryAspectsAnalyzed: dict[str, float | numpy.ndarray] = {}
67
67
  if 'aspectralstats' in FFprobeStructured:
68
68
  for keyName in FFprobeStructured['aspectralstats']:
69
- dictionaryAspectsAnalyzed[keyName] = numpy.mean(FFprobeStructured['aspectralstats'][keyName]).astype(float)
69
+ # No matter how many channels, each keyName is `numpy.ndarray[tuple[int, int], numpy.dtype[numpy.float64]]`
70
+ # where `tuple[int, int]` is (channel, frame)
71
+ # NOTE (as of this writing) `registrar` can only understand the generic class `numpy.ndarray` and not more specific typing
72
+ dictionaryAspectsAnalyzed[keyName] = FFprobeStructured['aspectralstats'][keyName]
73
+ # dictionaryAspectsAnalyzed[keyName] = numpy.mean(FFprobeStructured['aspectralstats'][keyName]).astype(float)
70
74
  if 'r128' in FFprobeStructured:
71
75
  for keyName in FFprobeStructured['r128']:
72
76
  dictionaryAspectsAnalyzed[keyName] = FFprobeStructured['r128'][keyName][-1]
73
77
  if 'astats' in FFprobeStructured:
74
78
  for keyName, arrayFeatureValues in cast(dict[str, numpy.ndarray[Any, Any]], FFprobeStructured['astats']).items():
75
- dictionaryAspectsAnalyzed[keyName.split('.')[-1]] = numpy.mean(arrayFeatureValues[..., -1:]).astype(float)
79
+ dictionaryAspectsAnalyzed[keyName.split('.')[-1]] = numpy.mean(arrayFeatureValues[..., -1:None]).astype(float)
76
80
 
77
81
  return dictionaryAspectsAnalyzed
78
82
 
@@ -128,56 +132,56 @@ def analyzeLUFSlow(pathFilename: str | PathLike[Any]) -> float | None:
128
132
  def analyzeLUFShigh(pathFilename: str | PathLike[Any]) -> float | None:
129
133
  return ffprobeShotgunAndCache(pathFilename).get('LRA.high')
130
134
 
131
- @registrationAudioAspect('Spectral mean')
132
- def analyzeMean(pathFilename: str | PathLike[Any]) -> float | None:
135
+ @registrationAudioAspect('Power spectral density')
136
+ def analyzeMean(pathFilename: str | PathLike[Any]) -> numpy.ndarray:
133
137
  return ffprobeShotgunAndCache(pathFilename).get('mean')
134
138
 
135
139
  @registrationAudioAspect('Spectral variance')
136
- def analyzeVariance(pathFilename: str | PathLike[Any]) -> float | None:
140
+ def analyzeVariance(pathFilename: str | PathLike[Any]) -> numpy.ndarray:
137
141
  return ffprobeShotgunAndCache(pathFilename).get('variance')
138
142
 
139
143
  @registrationAudioAspect('Spectral centroid')
140
- def analyzeCentroid(pathFilename: str | PathLike[Any]) -> float | None:
144
+ def analyzeCentroid(pathFilename: str | PathLike[Any]) -> numpy.ndarray:
141
145
  return ffprobeShotgunAndCache(pathFilename).get('centroid')
142
146
 
143
147
  @registrationAudioAspect('Spectral spread')
144
- def analyzeSpread(pathFilename: str | PathLike[Any]) -> float | None:
148
+ def analyzeSpread(pathFilename: str | PathLike[Any]) -> numpy.ndarray:
145
149
  return ffprobeShotgunAndCache(pathFilename).get('spread')
146
150
 
147
151
  @registrationAudioAspect('Spectral skewness')
148
- def analyzeSkewness(pathFilename: str | PathLike[Any]) -> float | None:
152
+ def analyzeSkewness(pathFilename: str | PathLike[Any]) -> numpy.ndarray:
149
153
  return ffprobeShotgunAndCache(pathFilename).get('skewness')
150
154
 
151
155
  @registrationAudioAspect('Spectral kurtosis')
152
- def analyzeKurtosis(pathFilename: str | PathLike[Any]) -> float | None:
156
+ def analyzeKurtosis(pathFilename: str | PathLike[Any]) -> numpy.ndarray:
153
157
  return ffprobeShotgunAndCache(pathFilename).get('kurtosis')
154
158
 
155
159
  @registrationAudioAspect('Spectral entropy')
156
- def analyzeSpectralEntropy(pathFilename: str | PathLike[Any]) -> float | None:
160
+ def analyzeSpectralEntropy(pathFilename: str | PathLike[Any]) -> numpy.ndarray:
157
161
  return ffprobeShotgunAndCache(pathFilename).get('entropy')
158
162
 
159
163
  @registrationAudioAspect('Spectral flatness')
160
- def analyzeFlatness(pathFilename: str | PathLike[Any]) -> float | None:
164
+ def analyzeFlatness(pathFilename: str | PathLike[Any]) -> numpy.ndarray:
161
165
  return ffprobeShotgunAndCache(pathFilename).get('flatness')
162
166
 
163
167
  @registrationAudioAspect('Spectral crest')
164
- def analyzeCrest(pathFilename: str | PathLike[Any]) -> float | None:
168
+ def analyzeCrest(pathFilename: str | PathLike[Any]) -> numpy.ndarray:
165
169
  return ffprobeShotgunAndCache(pathFilename).get('crest')
166
170
 
167
171
  @registrationAudioAspect('Spectral flux')
168
- def analyzeFlux(pathFilename: str | PathLike[Any]) -> float | None:
172
+ def analyzeFlux(pathFilename: str | PathLike[Any]) -> numpy.ndarray:
169
173
  return ffprobeShotgunAndCache(pathFilename).get('flux')
170
174
 
171
175
  @registrationAudioAspect('Spectral slope')
172
- def analyzeSlope(pathFilename: str | PathLike[Any]) -> float | None:
176
+ def analyzeSlope(pathFilename: str | PathLike[Any]) -> numpy.ndarray:
173
177
  return ffprobeShotgunAndCache(pathFilename).get('slope')
174
178
 
175
179
  @registrationAudioAspect('Spectral decrease')
176
- def analyzeDecrease(pathFilename: str | PathLike[Any]) -> float | None:
180
+ def analyzeDecrease(pathFilename: str | PathLike[Any]) -> numpy.ndarray:
177
181
  return ffprobeShotgunAndCache(pathFilename).get('decrease')
178
182
 
179
183
  @registrationAudioAspect('Spectral rolloff')
180
- def analyzeRolloff(pathFilename: str | PathLike[Any]) -> float | None:
184
+ def analyzeRolloff(pathFilename: str | PathLike[Any]) -> numpy.ndarray:
181
185
  return ffprobeShotgunAndCache(pathFilename).get('rolloff')
182
186
 
183
187
  @registrationAudioAspect('Abs_Peak_count')
@@ -1,8 +1,20 @@
1
1
  from collections import defaultdict
2
- from typing import Any
2
+ from typing import Any, cast, NamedTuple
3
3
  import json
4
4
  import numpy
5
5
 
6
+ # NOTE hey! hey! hey!
7
+ # Is blackdetect broken?
8
+ # 1. You don't have pytest tests for anything in the entire fricken package
9
+ # 2. You tried to improve the blackdetect code, but you didn't test it with anything
10
+ # 3. Search for "uncommentToFixBlackdetect"
11
+ # NOTE You changed the code because a static type checker was mad at you. Ask yourself,
12
+ # "Are you the tool or is the type checker the tool?"
13
+
14
+ class Blackdetect(NamedTuple):
15
+ black_start: float | None = None
16
+ black_end: float | None = None
17
+
6
18
  def pythonizeFFprobe(FFprobeJSON_utf8: str):
7
19
  FFroot: dict[str, Any] = json.loads(FFprobeJSON_utf8)
8
20
  Z0Z_dictionaries: dict[str, numpy.ndarray[Any, Any] | dict[str, numpy.ndarray[Any, Any]]] = {}
@@ -25,14 +37,24 @@ def pythonizeFFprobe(FFprobeJSON_utf8: str):
25
37
  leftCrumbs = False
26
38
  if 'frames' in FFroot:
27
39
  leftCrumbs = False
28
- listTuplesBlackdetect: list[float | tuple[float]] = []
40
+ # listTuplesBlackdetect = [] # uncommentToFixBlackdetect
41
+ listTuplesBlackdetect: list[Blackdetect] = []
29
42
  for indexFrame, FFframe in enumerate(FFroot['frames']):
30
43
  if 'tags' in FFframe:
31
44
  if 'lavfi.black_start' in FFframe['tags']:
32
- listTuplesBlackdetect.append(float(FFframe['tags']['lavfi.black_start']))
45
+ # listTuplesBlackdetect.append(float(FFframe['tags']['lavfi.black_start'])) # uncommentToFixBlackdetect
46
+ listTuplesBlackdetect.append(Blackdetect(black_start=float(FFframe['tags']['lavfi.black_start'])))
33
47
  del FFframe['tags']['lavfi.black_start']
34
48
  if 'lavfi.black_end' in FFframe['tags']:
35
- listTuplesBlackdetect[-1] = (listTuplesBlackdetect[-1], float(FFframe['tags']['lavfi.black_end']))
49
+ # listTuplesBlackdetect[-1] = (listTuplesBlackdetect[-1], float(FFframe['tags']['lavfi.black_end'])) # uncommentToFixBlackdetect
50
+ tupleBlackdetectLast = listTuplesBlackdetect.pop() if listTuplesBlackdetect else Blackdetect()
51
+ match tupleBlackdetectLast.black_end:
52
+ case None:
53
+ listTuplesBlackdetect.append(Blackdetect(tupleBlackdetectLast.black_start, float(FFframe['tags']['lavfi.black_end'])))
54
+ case _:
55
+ if tupleBlackdetectLast.black_start is not None:
56
+ listTuplesBlackdetect.append(tupleBlackdetectLast)
57
+ listTuplesBlackdetect.append(Blackdetect(black_end=(float(FFframe['tags']['lavfi.black_end']))))
36
58
  del FFframe['tags']['lavfi.black_end']
37
59
 
38
60
  # This is not the way to do it
@@ -66,12 +88,15 @@ def pythonizeFFprobe(FFprobeJSON_utf8: str):
66
88
  if registrant not in Z0Z_dictionaries:
67
89
  Z0Z_dictionaries[registrant] = {}
68
90
  elif statistic not in Z0Z_dictionaries[registrant]:
69
- Z0Z_dictionaries[registrant][statistic] = numpy.zeros((channel, len(FFroot['frames'])))
91
+ # NOTE (as of this writing) `registrar` can only understand the generic class `numpy.ndarray` and not more specific typing
92
+ valueSherpa = cast(numpy.ndarray, numpy.zeros((channel, len(FFroot['frames']))))
93
+ Z0Z_dictionaries[registrant][statistic] = valueSherpa
70
94
  else:
71
95
  raise # Re-raise the exception
72
96
  except IndexError:
73
97
  if channel > Z0Z_dictionaries[registrant][statistic].shape[0]:
74
- Z0Z_dictionaries[registrant][statistic].resize((channel, len(FFroot['frames'])))
98
+ Z0Z_dictionaries[registrant][statistic] = numpy.resize(Z0Z_dictionaries[registrant][statistic], (channel, len(FFroot['frames'])))
99
+ # Z0Z_dictionaries[registrant][statistic].resize((channel, len(FFroot['frames'])))
75
100
  else:
76
101
  raise # Re-raise the exception
77
102
 
@@ -80,7 +105,17 @@ def pythonizeFFprobe(FFprobeJSON_utf8: str):
80
105
  if FFframe:
81
106
  leftCrumbs = True
82
107
  if listTuplesBlackdetect:
83
- Z0Z_dictionaries['blackdetect'] = numpy.array(listTuplesBlackdetect, dtype=[('black_start', numpy.float32), ('black_end', numpy.float32)], copy=False)
108
+ # 2025-03-06: I am _shocked_ that I was able to create a numpy structured array whenever it was that I originally wrote this code.
109
+ arrayBlackdetect = numpy.array(
110
+ [(
111
+ -1.0 if detect.black_start is None else detect.black_start,
112
+ -1.0 if detect.black_end is None else detect.black_end
113
+ ) for detect in listTuplesBlackdetect],
114
+ dtype=[('black_start', numpy.float64), ('black_end', numpy.float64)],
115
+ copy=False
116
+ )
117
+ Z0Z_dictionaries['blackdetect'] = arrayBlackdetect
118
+ # Z0Z_dictionaries['blackdetect'] = numpy.array(listTuplesBlackdetect, dtype=[('black_start', numpy.float32), ('black_end', numpy.float32)], copy=False) # uncommentToFixBlackdetect
84
119
  if not leftCrumbs:
85
120
  del FFroot['frames']
86
121
  return FFroot, Z0Z_dictionaries
@@ -0,0 +1,194 @@
1
+ Metadata-Version: 2.2
2
+ Name: analyzeAudio
3
+ Version: 0.0.14
4
+ Summary: Measure one or more aspects of one or more audio files.
5
+ Author-email: Hunter Hogan <HunterHogan@pm.me>
6
+ License: CC-BY-NC-4.0
7
+ Project-URL: Donate, https://www.patreon.com/integrated
8
+ Project-URL: Homepage, https://github.com/hunterhogan/analyzeAudio
9
+ Project-URL: Repository, https://github.com/hunterhogan/analyzeAudio.git
10
+ Keywords: audio,analysis,measurement,metrics,torch,spectrum,spectral,waveform,loudness,LUFS,RMS,FFmpeg,FFprobe,SRMR,audio-analysis,signal-processing
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Intended Audience :: Information Technology
17
+ Classifier: Intended Audience :: Other Audience
18
+ Classifier: License :: Free for non-commercial use
19
+ Classifier: Natural Language :: English
20
+ Classifier: Operating System :: OS Independent
21
+ Classifier: Programming Language :: Python
22
+ Classifier: Programming Language :: Python :: 3
23
+ Classifier: Programming Language :: Python :: 3.10
24
+ Classifier: Programming Language :: Python :: 3.11
25
+ Classifier: Programming Language :: Python :: 3.12
26
+ Classifier: Programming Language :: Python :: 3.13
27
+ Classifier: Topic :: Multimedia :: Sound/Audio
28
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis
29
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Conversion
30
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
31
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
32
+ Classifier: Typing :: Typed
33
+ Requires-Python: >=3.10
34
+ Description-Content-Type: text/markdown
35
+ License-File: LICENSE
36
+ Requires-Dist: cachetools
37
+ Requires-Dist: librosa
38
+ Requires-Dist: numpy
39
+ Requires-Dist: optype[numpy]
40
+ Requires-Dist: standard-aifc; python_version >= "3.13"
41
+ Requires-Dist: standard-sunau; python_version >= "3.13"
42
+ Requires-Dist: torch
43
+ Requires-Dist: torchmetrics[audio]
44
+ Requires-Dist: tqdm
45
+ Requires-Dist: Z0Z_tools
46
+ Provides-Extra: testing
47
+ Requires-Dist: pytest-cov; extra == "testing"
48
+ Requires-Dist: pytest-xdist; extra == "testing"
49
+ Requires-Dist: pytest; extra == "testing"
50
+ Requires-Dist: pyupgrade; extra == "testing"
51
+
52
+ # analyzeAudio
53
+
54
+ Measure one or more aspects of one or more audio files.
55
+
56
+ ## Note well: FFmpeg & FFprobe binaries must be in PATH
57
+
58
+ Some options to [download FFmpeg and FFprobe](https://www.ffmpeg.org/download.html) at ffmpeg.org.
59
+
60
+ ## Some ways to use this package
61
+
62
+ ### Use `analyzeAudioFile` to measure one or more aspects of a single audio file
63
+
64
+ ```python
65
+ from analyzeAudio import analyzeAudioFile
66
+ listAspectNames = ['LUFS integrated',
67
+ 'RMS peak',
68
+ 'SRMR mean',
69
+ 'Spectral Flatness mean']
70
+ listMeasurements = analyzeAudioFile(pathFilename, listAspectNames)
71
+ ```
72
+
73
+ ### Use `getListAvailableAudioAspects` to get a crude list of aspects this package can measure
74
+
75
+ The aspect names are accurate, but the lack of additional documentation can make things challenging. 'Zero-crossing rate', 'Zero-crossing rate mean', and 'Zero-crossings rate', for example, are different from each other. ("... lack of additional documentation ...")
76
+
77
+ ```python
78
+ import analyzeAudio
79
+ analyzeAudio.getListAvailableAudioAspects()
80
+ ```
81
+
82
+ ### Use `analyzeAudioListPathFilenames` to measure one or more aspects of individual file in a list of audio files
83
+
84
+ ### Use `audioAspects` to call an analyzer function by using the name of the aspect you wish to measure
85
+
86
+ ```python
87
+ from analyzeAudio import audioAspects
88
+ SI_SDR_channelsMean = audioAspects['SI-SDR mean']['analyzer'](pathFilenameAudioFile, pathFilenameDifferentAudioFile)
89
+ ```
90
+
91
+ Retrieve the names of the parameters for an analyzer function with the `['analyzerParameters']` key-name.
92
+
93
+ ```python
94
+ from analyzeAudio import audioAspects
95
+ print(audioAspects['Chromagram']['analyzerParameters'])
96
+ ```
97
+
98
+ ### Use `whatMeasurements` command line tool to list available measurements
99
+
100
+ ```sh
101
+ (.venv) C:\apps\analyzeAudio>whatMeasurements
102
+ ['Abs_Peak_count', 'Bit_depth', 'Chromagram', 'Chromagram mean', 'Crest factor', 'DC offset', 'Duration-samples', 'Dynamic range', 'Flat_factor', 'LUFS high', 'LUFS integrated', 'LUFS loudness range', 'LUFS low', 'Max_difference', 'Max_level', 'Mean_difference', 'Min_difference', 'Min_level', 'Noise_floor', 'Noise_floor_count', 'Peak dB', 'Peak_count', 'Power spectral density', 'Power spectral density mean', 'RMS from waveform', 'RMS from waveform mean', 'RMS peak', 'RMS total', 'RMS_difference', 'RMS_trough', 'SI-SDR mean', 'SRMR', 'SRMR mean', 'Signal entropy', 'Spectral Bandwidth', 'Spectral Bandwidth mean', 'Spectral Centroid', 'Spectral Centroid mean', 'Spectral Contrast', 'Spectral Contrast mean', 'Spectral Flatness', 'Spectral Flatness mean', 'Spectral centroid', 'Spectral centroid mean', 'Spectral crest', 'Spectral crest mean', 'Spectral decrease', 'Spectral decrease mean', 'Spectral entropy', 'Spectral entropy mean', 'Spectral flatness', 'Spectral flatness mean', 'Spectral flux', 'Spectral flux mean', 'Spectral kurtosis', 'Spectral kurtosis mean', 'Spectral rolloff', 'Spectral rolloff mean', 'Spectral skewness', 'Spectral skewness mean', 'Spectral slope', 'Spectral slope mean', 'Spectral spread', 'Spectral spread mean', 'Spectral variance', 'Spectral variance mean', 'Tempo', 'Tempo mean', 'Tempogram', 'Tempogram mean', 'Zero-crossing rate', 'Zero-crossing rate mean', 'Zero-crossings rate']
103
+ ```
104
+
105
+ ## Some clues about the aspects
106
+
107
+ ```python
108
+ 'Abs_Peak_count': float
109
+ 'Bit_depth': float
110
+ 'Chromagram': NDArray[float64] # shape(..., 12, frames)
111
+ 'Chromagram mean': float
112
+ 'Crest factor': float
113
+ 'DC offset': float
114
+ 'Duration-samples': float
115
+ 'Dynamic range': float
116
+ 'Flat_factor': float
117
+ 'LUFS high': float
118
+ 'LUFS integrated': float
119
+ 'LUFS loudness range': float
120
+ 'LUFS low': float
121
+ 'Max_difference': float
122
+ 'Max_level': float
123
+ 'Mean_difference': float
124
+ 'Min_difference': float
125
+ 'Min_level': float
126
+ 'Noise_floor_count': float
127
+ 'Noise_floor': float
128
+ 'Peak dB': float
129
+ 'Peak_count': float
130
+ 'Power spectral density': NDArray[float64] # shape(channels, frames)
131
+ 'Power spectral density mean': float
132
+ 'RMS from waveform': NDArray[float64] # shape(..., 1, frames)
133
+ 'RMS from waveform mean': float
134
+ 'RMS peak': float
135
+ 'RMS total': float
136
+ 'RMS_difference': float
137
+ 'RMS_trough': float
138
+ 'SI-SDR mean': float
139
+ 'Signal entropy': float
140
+ 'Spectral Bandwidth': NDArray[float64] # shape(..., 1, frames)
141
+ 'Spectral Bandwidth mean': float
142
+ 'Spectral centroid': NDArray[float64] # shape(channels, frames)
143
+ 'Spectral centroid mean': float
144
+ 'Spectral Centroid': NDArray[float64] # shape(..., 1, frames)
145
+ 'Spectral Centroid mean': float
146
+ 'Spectral Contrast': NDArray[float64] # shape(..., 7, frames)
147
+ 'Spectral Contrast mean': float
148
+ 'Spectral crest': NDArray[float64] # shape(channels, frames)
149
+ 'Spectral crest mean': float
150
+ 'Spectral decrease': NDArray[float64] # shape(channels, frames)
151
+ 'Spectral decrease mean': float
152
+ 'Spectral entropy': NDArray[float64] # shape(channels, frames)
153
+ 'Spectral entropy mean': float
154
+ 'Spectral flatness': NDArray[float64] # shape(channels, frames)
155
+ 'Spectral flatness mean': float
156
+ 'Spectral Flatness': NDArray[float64] # shape(..., 1, frames)
157
+ 'Spectral Flatness mean': float
158
+ 'Spectral flux': NDArray[float64] # shape(channels, frames)
159
+ 'Spectral flux mean': float
160
+ 'Spectral kurtosis': NDArray[float64] # shape(channels, frames)
161
+ 'Spectral kurtosis mean': float
162
+ 'Spectral rolloff': NDArray[float64] # shape(channels, frames)
163
+ 'Spectral rolloff mean': float
164
+ 'Spectral skewness': NDArray[float64] # shape(channels, frames)
165
+ 'Spectral skewness mean': float
166
+ 'Spectral slope': NDArray[float64] # shape(channels, frames)
167
+ 'Spectral slope mean': float
168
+ 'Spectral spread': NDArray[float64] # shape(channels, frames)
169
+ 'Spectral spread mean': float
170
+ 'Spectral variance': NDArray[float64] # shape(channels, frames)
171
+ 'Spectral variance mean': float
172
+ 'SRMR': NDArray[float64] # shape(...)
173
+ 'SRMR mean': float
174
+ 'Tempo': NDArray[float64] # shape(...)
175
+ 'Tempo mean': float
176
+ 'Tempogram': NDArray[float64] # shape(..., 384, samples)
177
+ 'Tempogram mean': float
178
+ 'Zero-crossing rate': NDArray[float64] # shape(..., 1, frames)
179
+ 'Zero-crossing rate mean': float
180
+ 'Zero-crossings rate': float
181
+ ```
182
+
183
+ ## Installation
184
+
185
+ ```sh
186
+ pip install analyzeAudio
187
+ ```
188
+
189
+ ## My recovery
190
+
191
+ [![Static Badge](https://img.shields.io/badge/2011_August-Homeless_since-blue?style=flat)](https://HunterThinks.com/support)
192
+ [![YouTube Channel Subscribers](https://img.shields.io/youtube/channel/subscribers/UC3Gx7kz61009NbhpRtPP7tw)](https://www.youtube.com/@HunterHogan)
193
+
194
+ [![CC-BY-NC-4.0](https://github.com/hunterhogan/analyzeAudio/blob/main/CC-BY-NC-4.0.png)](https://creativecommons.org/licenses/by-nc/4.0/)
@@ -1,16 +1,16 @@
1
1
  analyzeAudio/__init__.py,sha256=2D5JMeZfLGnwyQvt4Q2-HCsShHulcNXBM_Wu9vZPCiI,437
2
- analyzeAudio/analyzersUseFilename.py,sha256=EToFicrCkFg_YTMJsGbXX3CtDGO9TFch-GUr4fh65Tc,10541
2
+ analyzeAudio/analyzersUseFilename.py,sha256=iXF3Ut_Ldd6hKtNC54vpwRLGaQQA0UdE83aCMcFfVGI,10972
3
3
  analyzeAudio/analyzersUseSpectrogram.py,sha256=j-e69ICVHOC_W3ev8HOTem4KGGpE9QyKnYZEvFseMkE,1835
4
4
  analyzeAudio/analyzersUseTensor.py,sha256=-wD_QAd41lB65ceT5UedEoxWL078tZ0E-kC9ssDSghc,553
5
5
  analyzeAudio/analyzersUseWaveform.py,sha256=AwDyagz9bLLAq8ji4by51x7d2YWRdUQaY3iaw1k0yD4,1472
6
6
  analyzeAudio/audioAspectsRegistry.py,sha256=EvFKNncWKDv4KDyI0UcfBplkgVK_fGOFOdjolDy8hE0,8517
7
- analyzeAudio/pythonator.py,sha256=cH4BJhXb_awvxWbB1cRtZTfCDUUgi9WiVrleVT4hyyI,3499
7
+ analyzeAudio/pythonator.py,sha256=St6KmIxvHwoW6IuHcEJjjvUUrEkG0sPv2S3Th9rjJtE,5603
8
8
  tests/conftest.py,sha256=BhZswOjkl_u-qiS4Zy38d2fETdWAtZiigeuXYBK8l0k,397
9
9
  tests/test_audioAspectsRegistry.py,sha256=-TWTLMdAn6IFv7ZdFWrBm1KxpLBa3Mz1sCygAwxV6gE,27
10
10
  tests/test_other.py,sha256=sd20ms4StQ13_3-gmwZwtAuoIAwfxWC5IXM_Cp5GQXM,428
11
- analyzeaudio-0.0.12.dist-info/LICENSE,sha256=NxH5Y8BdC-gNU-WSMwim3uMbID2iNDXJz7fHtuTdXhk,19346
12
- analyzeaudio-0.0.12.dist-info/METADATA,sha256=DWLUaMD_RnKL0i2W0sD0WgEnN5dj4VW95oIeK3mk5mY,4783
13
- analyzeaudio-0.0.12.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
14
- analyzeaudio-0.0.12.dist-info/entry_points.txt,sha256=FHgSx7fndtZ6SnQ-nWVXf0NB59exaHQ2DtatTK9KrLg,100
15
- analyzeaudio-0.0.12.dist-info/top_level.txt,sha256=QV8LQ0r_1LIQuewxDcEzODpykv5qRYG3I70piOUSVRg,19
16
- analyzeaudio-0.0.12.dist-info/RECORD,,
11
+ analyzeaudio-0.0.14.dist-info/LICENSE,sha256=NxH5Y8BdC-gNU-WSMwim3uMbID2iNDXJz7fHtuTdXhk,19346
12
+ analyzeaudio-0.0.14.dist-info/METADATA,sha256=Q_oiZl_dpECEzAv33Zla9SuVugUKr0sw9IZuUxPGaZs,8659
13
+ analyzeaudio-0.0.14.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
14
+ analyzeaudio-0.0.14.dist-info/entry_points.txt,sha256=FHgSx7fndtZ6SnQ-nWVXf0NB59exaHQ2DtatTK9KrLg,100
15
+ analyzeaudio-0.0.14.dist-info/top_level.txt,sha256=QV8LQ0r_1LIQuewxDcEzODpykv5qRYG3I70piOUSVRg,19
16
+ analyzeaudio-0.0.14.dist-info/RECORD,,
@@ -1,103 +0,0 @@
1
- Metadata-Version: 2.2
2
- Name: analyzeAudio
3
- Version: 0.0.12
4
- Summary: Measure one or more aspects of one or more audio files.
5
- Author-email: Hunter Hogan <HunterHogan@pm.me>
6
- License: CC-BY-NC-4.0
7
- Project-URL: Donate, https://www.patreon.com/integrated
8
- Project-URL: Homepage, https://github.com/hunterhogan/analyzeAudio
9
- Project-URL: Repository, https://github.com/hunterhogan/analyzeAudio.git
10
- Keywords: audio,analysis,measurement,metrics,torch
11
- Classifier: Development Status :: 3 - Alpha
12
- Classifier: Environment :: Console
13
- Classifier: Intended Audience :: Developers
14
- Classifier: Intended Audience :: End Users/Desktop
15
- Classifier: Intended Audience :: Other Audience
16
- Classifier: Natural Language :: English
17
- Classifier: Operating System :: OS Independent
18
- Classifier: Programming Language :: Python
19
- Classifier: Programming Language :: Python :: 3
20
- Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis
21
- Classifier: Typing :: Typed
22
- Requires-Python: >=3.10
23
- Description-Content-Type: text/markdown
24
- License-File: LICENSE
25
- Requires-Dist: cachetools
26
- Requires-Dist: librosa
27
- Requires-Dist: numpy
28
- Requires-Dist: optype[numpy]
29
- Requires-Dist: torch
30
- Requires-Dist: torchmetrics[audio]
31
- Requires-Dist: tqdm
32
- Requires-Dist: Z0Z_tools
33
- Provides-Extra: testing
34
- Requires-Dist: pytest-cov; extra == "testing"
35
- Requires-Dist: pytest-xdist; extra == "testing"
36
- Requires-Dist: pytest; extra == "testing"
37
- Requires-Dist: pyupgrade; extra == "testing"
38
-
39
- # analyzeAudio
40
-
41
- Measure one or more aspects of one or more audio files.
42
-
43
- ## Note well: FFmpeg & FFprobe binaries must be in PATH
44
-
45
- Some options to [download FFmpeg and FFprobe](https://www.ffmpeg.org/download.html) at ffmpeg.org.
46
-
47
- ## Some ways to use this package
48
-
49
- ### Use `analyzeAudioFile` to measure one or more aspects of a single audio file
50
-
51
- ```python
52
- from analyzeAudio import analyzeAudioFile
53
- listAspectNames = ['LUFS integrated',
54
- 'RMS peak',
55
- 'SRMR mean',
56
- 'Spectral Flatness mean']
57
- listMeasurements = analyzeAudioFile(pathFilename, listAspectNames)
58
- ```
59
-
60
- ### Use `getListAvailableAudioAspects` to get a crude list of aspects this package can measure
61
-
62
- The aspect names are accurate, but the lack of additional documentation can make things challenging. 'Zero-crossing rate', 'Zero-crossing rate mean', and 'Zero-crossings rate', for example, are different from each other. ("... lack of additional documentation ...")
63
-
64
- ```python
65
- import analyzeAudio
66
- analyzeAudio.getListAvailableAudioAspects()
67
- ```
68
-
69
- ### Use `analyzeAudioListPathFilenames` to measure one or more aspects of individual file in a list of audio files
70
-
71
- ### Use `audioAspects` to call an analyzer function by using the name of the aspect you wish to measure
72
-
73
- ```python
74
- from analyzeAudio import audioAspects
75
- SI_SDR_channelsMean = audioAspects['SI-SDR mean']['analyzer'](pathFilenameAudioFile, pathFilenameDifferentAudioFile)
76
- ```
77
-
78
- Retrieve the names of the parameters for an analyzer function with the `['analyzerParameters']` key-name.
79
-
80
- ```python
81
- from analyzeAudio import audioAspects
82
- print(audioAspects['Chromagram']['analyzerParameters'])
83
- ```
84
-
85
- ### Use `whatMeasurements` command line tool to list available measurements
86
-
87
- ```sh
88
- (.venv) C:\apps\analyzeAudio> whatMeasurements
89
- ['Abs_Peak_count', 'Bit_depth', 'Chromagram', 'Chromagram mean', 'Crest factor', 'DC offset', 'Duration-samples', 'Dynamic range', 'Flat_factor', 'LUFS high', 'LUFS integrated', 'LUFS loudness range', 'LUFS low', 'Max_difference', 'Max_level', 'Mean_difference', 'Min_difference', 'Min_level', 'Noise_floor', 'Noise_floor_count', 'Peak dB', 'Peak_count', 'RMS from waveform', 'RMS from waveform mean', 'RMS peak', 'RMS total', 'RMS_difference', 'RMS_trough', 'SI-SDR mean', 'SRMR', 'SRMR mean', 'Signal entropy', 'Spectral Bandwidth', 'Spectral Bandwidth mean', 'Spectral Centroid', 'Spectral Centroid mean', 'Spectral Contrast', 'Spectral Contrast mean', 'Spectral Flatness', 'Spectral Flatness mean', 'Spectral centroid', 'Spectral crest', 'Spectral decrease', 'Spectral entropy', 'Spectral flatness', 'Spectral flux', 'Spectral kurtosis', 'Spectral mean', 'Spectral rolloff', 'Spectral skewness', 'Spectral slope', 'Spectral spread', 'Spectral variance', 'Tempo', 'Tempo mean', 'Tempogram', 'Tempogram mean', 'Zero-crossing rate', 'Zero-crossing rate mean', 'Zero-crossings rate']
90
- ```
91
-
92
- ## Installation
93
-
94
- ```sh
95
- pip install analyzeAudio
96
- ```
97
-
98
- ## My recovery
99
-
100
- [![Static Badge](https://img.shields.io/badge/2011_August-Homeless_since-blue?style=flat)](https://HunterThinks.com/support)
101
- [![YouTube Channel Subscribers](https://img.shields.io/youtube/channel/subscribers/UC3Gx7kz61009NbhpRtPP7tw)](https://www.youtube.com/@HunterHogan)
102
-
103
- [![CC-BY-NC-4.0](https://github.com/hunterhogan/analyzeAudio/blob/main/CC-BY-NC-4.0.png)](https://creativecommons.org/licenses/by-nc/4.0/)