wavemap 2.0.1__tar.gz → 2.1.0__tar.gz
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.
- {wavemap-2.0.1/wavemap.egg-info → wavemap-2.1.0}/PKG-INFO +15 -20
- wavemap-2.1.0/pyproject.toml +47 -0
- wavemap-2.1.0/wavemap/.DS_Store +0 -0
- {wavemap-2.0.1 → wavemap-2.1.0}/wavemap/__init__.py +30 -27
- {wavemap-2.0.1 → wavemap-2.1.0}/wavemap/convert.py +14 -8
- {wavemap-2.0.1 → wavemap-2.1.0}/wavemap/docs.py +11 -11
- {wavemap-2.0.1 → wavemap-2.1.0}/wavemap/memmap.py +18 -20
- {wavemap-2.0.1 → wavemap-2.1.0}/wavemap/raw.py +27 -24
- {wavemap-2.0.1 → wavemap-2.1.0}/wavemap/read.py +39 -38
- {wavemap-2.0.1 → wavemap-2.1.0}/wavemap/structure/structure.py +14 -15
- {wavemap-2.0.1 → wavemap-2.1.0}/wavemap/structure/wave.py +5 -5
- {wavemap-2.0.1 → wavemap-2.1.0}/wavemap/write.py +28 -26
- wavemap-2.0.1/LICENSE +0 -21
- wavemap-2.0.1/PKG-INFO +0 -383
- wavemap-2.0.1/pyproject.toml +0 -8
- wavemap-2.0.1/setup.cfg +0 -7
- wavemap-2.0.1/setup.py +0 -40
- wavemap-2.0.1/test/test_convert.py +0 -37
- wavemap-2.0.1/test/test_docs.py +0 -68
- wavemap-2.0.1/test/test_expected.py +0 -21
- wavemap-2.0.1/test/test_read.py +0 -89
- wavemap-2.0.1/test/test_vs_ffmpeg.py +0 -77
- wavemap-2.0.1/test/test_write.py +0 -106
- wavemap-2.0.1/wavemap.egg-info/SOURCES.txt +0 -26
- wavemap-2.0.1/wavemap.egg-info/dependency_links.txt +0 -1
- wavemap-2.0.1/wavemap.egg-info/requires.txt +0 -2
- wavemap-2.0.1/wavemap.egg-info/top_level.txt +0 -1
- {wavemap-2.0.1 → wavemap-2.1.0}/README.rst +0 -0
- {wavemap-2.0.1 → wavemap-2.1.0}/wavemap/structure/__init__.py +0 -0
|
@@ -1,23 +1,20 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: wavemap
|
|
3
|
-
Version: 2.0
|
|
4
|
-
Summary: Memory map WAVE or raw audio files
|
|
5
|
-
Home-page: https://github.com/rec/wavemap
|
|
3
|
+
Version: 2.1.0
|
|
4
|
+
Summary: 🌊 Memory map WAVE or raw audio files 🌊
|
|
6
5
|
Author: Tom Ritchford
|
|
7
|
-
Author-email: tom@swirly.com
|
|
8
|
-
License: MIT
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Classifier:
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Classifier: Topic :: Utilities
|
|
20
|
-
License-File: LICENSE
|
|
6
|
+
Author-email: Tom Ritchford <tom@swirly.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Requires-Dist: numpy>=1.24.1,<2
|
|
15
|
+
Requires-Dist: xmod>=1.3.2,<2
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/x-rst
|
|
21
18
|
|
|
22
19
|
🌊 Memory map WAVE files into numpy arrays 🌊
|
|
23
20
|
----------------------------------------------
|
|
@@ -379,5 +376,3 @@ ARGUMENTS
|
|
|
379
376
|
If true, ``arr`` is copied even if it is already the requested type
|
|
380
377
|
|
|
381
378
|
(automatically generated by `doks <https://github.com/rec/doks/>`_ on 2021-02-23T14:37:02.652534)
|
|
382
|
-
|
|
383
|
-
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "wavemap"
|
|
3
|
+
version = "2.1.0"
|
|
4
|
+
description = "🌊 Memory map WAVE or raw audio files 🌊"
|
|
5
|
+
authors = [{ name = "Tom Ritchford", email = "tom@swirly.com" }]
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
readme = "README.rst"
|
|
8
|
+
license = "MIT"
|
|
9
|
+
classifiers = ["Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14"]
|
|
10
|
+
dependencies = [
|
|
11
|
+
"numpy>=1.24.1,<2",
|
|
12
|
+
"xmod>=1.3.2,<2",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[tool.doks]
|
|
16
|
+
auto = true
|
|
17
|
+
source = 'wavemap/__init__.py'
|
|
18
|
+
|
|
19
|
+
[tool.ruff]
|
|
20
|
+
[dependency-groups]
|
|
21
|
+
dev = [
|
|
22
|
+
"coverage>=7.1.0,<8",
|
|
23
|
+
"pytest>=7.2.1,<8",
|
|
24
|
+
"pyupgrade>=3.21.2",
|
|
25
|
+
"ruff>=0.14.14",
|
|
26
|
+
"stroll>=1.1.0,<2",
|
|
27
|
+
"tdir>=1.4.1,<2",
|
|
28
|
+
"ty>=0.0.14",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[tool.uv]
|
|
32
|
+
|
|
33
|
+
[tool.uv.build-backend]
|
|
34
|
+
module-root = ""
|
|
35
|
+
|
|
36
|
+
[build-system]
|
|
37
|
+
requires = ["uv_build>=0.9.0,<0.10.0"]
|
|
38
|
+
build-backend = "uv_build"
|
|
39
|
+
[tool.coverage.run]
|
|
40
|
+
branch = true
|
|
41
|
+
source = "wavemap"
|
|
42
|
+
|
|
43
|
+
[tool.coverage.report]
|
|
44
|
+
fail_under = "68"
|
|
45
|
+
skip_covered = true
|
|
46
|
+
exclude_lines = ["pragma: no cover", "if False:", "if __name__ == .__main__.:", "raise NotImplementedError"]
|
|
47
|
+
|
|
Binary file
|
|
@@ -26,31 +26,34 @@ Typical usage:
|
|
|
26
26
|
wm /= 2
|
|
27
27
|
# Each sample in the file is scaled by half.
|
|
28
28
|
"""
|
|
29
|
+
|
|
30
|
+
from typing import Optional, Union
|
|
31
|
+
from collections.abc import Callable
|
|
32
|
+
|
|
33
|
+
import numpy as np
|
|
34
|
+
import xmod
|
|
35
|
+
|
|
29
36
|
from . import docs
|
|
30
37
|
from .convert import convert
|
|
31
38
|
from .raw import RawMap, warn
|
|
32
39
|
from .read import ReadMap as ReadMap
|
|
33
40
|
from .write import WriteMap as WriteMap
|
|
34
|
-
from typing import Callable, Optional, Union
|
|
35
|
-
import numpy as np
|
|
36
|
-
import xmod
|
|
37
41
|
|
|
38
42
|
__all__ = (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
"wavemap",
|
|
44
|
+
"RawMap",
|
|
45
|
+
"ReadMap",
|
|
46
|
+
"WriteMap",
|
|
47
|
+
"copy_to",
|
|
48
|
+
"new_like",
|
|
49
|
+
"convert",
|
|
46
50
|
)
|
|
47
|
-
__version__ = '2.0.1'
|
|
48
51
|
|
|
49
52
|
copy_to = WriteMap.copy_to
|
|
50
53
|
new_like = WriteMap.new_like
|
|
51
|
-
_DOKS = {warn:
|
|
52
|
-
_WRITE_PARAMETERS =
|
|
53
|
-
_READ_PARAMETERS =
|
|
54
|
+
_DOKS = {warn: "<function warn: print to stderr>"}
|
|
55
|
+
_WRITE_PARAMETERS = "dtype", "shape", "sample_rate"
|
|
56
|
+
_READ_PARAMETERS = "order", "always_2d"
|
|
54
57
|
|
|
55
58
|
|
|
56
59
|
@xmod(mutable=True)
|
|
@@ -60,20 +63,20 @@ def wavemap(
|
|
|
60
63
|
#
|
|
61
64
|
# Read parameters
|
|
62
65
|
#
|
|
63
|
-
mode: str =
|
|
64
|
-
order:
|
|
66
|
+
mode: str = "r",
|
|
67
|
+
order: str | None = None,
|
|
65
68
|
always_2d: bool = False,
|
|
66
69
|
#
|
|
67
70
|
# Write parameters
|
|
68
71
|
#
|
|
69
|
-
dtype:
|
|
70
|
-
shape:
|
|
72
|
+
dtype: np.dtype | None = None,
|
|
73
|
+
shape: None | int | tuple = None,
|
|
71
74
|
sample_rate: int = 0,
|
|
72
75
|
roffset: int = 0,
|
|
73
76
|
#
|
|
74
77
|
# Read and write parameters
|
|
75
78
|
#
|
|
76
|
-
warn:
|
|
79
|
+
warn: Callable | None = warn,
|
|
77
80
|
):
|
|
78
81
|
"""
|
|
79
82
|
Memory map a WAVE file to a `numpy` array
|
|
@@ -81,18 +84,18 @@ def wavemap(
|
|
|
81
84
|
Return an instance of `ReadMap` or `WriteMap`, depending on
|
|
82
85
|
`mode`.
|
|
83
86
|
"""
|
|
84
|
-
if mode.startswith(
|
|
87
|
+
if mode.startswith("w"):
|
|
85
88
|
if not dtype:
|
|
86
|
-
raise ValueError(
|
|
89
|
+
raise ValueError("dtype must be set for write")
|
|
87
90
|
if not shape:
|
|
88
|
-
raise ValueError(
|
|
91
|
+
raise ValueError("shape must be set for write")
|
|
89
92
|
if not sample_rate:
|
|
90
|
-
raise ValueError(
|
|
93
|
+
raise ValueError("sample_rate must be set for write")
|
|
91
94
|
|
|
92
95
|
if order:
|
|
93
|
-
raise ValueError(
|
|
96
|
+
raise ValueError("order cannot be set for write")
|
|
94
97
|
if always_2d:
|
|
95
|
-
raise ValueError(
|
|
98
|
+
raise ValueError("always_2d cannot be set for write")
|
|
96
99
|
|
|
97
100
|
return WriteMap(
|
|
98
101
|
filename=filename,
|
|
@@ -104,9 +107,9 @@ def wavemap(
|
|
|
104
107
|
)
|
|
105
108
|
else:
|
|
106
109
|
if shape:
|
|
107
|
-
raise ValueError(
|
|
110
|
+
raise ValueError("shape cannot be set for write")
|
|
108
111
|
if sample_rate:
|
|
109
|
-
raise ValueError(
|
|
112
|
+
raise ValueError("sample_rate cannot be set for write")
|
|
110
113
|
|
|
111
114
|
result = ReadMap(
|
|
112
115
|
filename=filename,
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
from numpy.lib.stride_tricks import as_strided
|
|
2
1
|
from typing import Optional
|
|
2
|
+
|
|
3
3
|
import numpy as np
|
|
4
|
+
from numpy.lib.stride_tricks import as_strided
|
|
4
5
|
|
|
5
6
|
|
|
6
|
-
def convert(
|
|
7
|
-
arr: np.ndarray, dtype: Optional[np.dtype], must_copy: bool = False
|
|
8
|
-
):
|
|
7
|
+
def convert(arr: np.ndarray, dtype: np.dtype | None, must_copy: bool = False):
|
|
9
8
|
"""
|
|
10
9
|
Returns a copy of a numpy array or matrix that represents audio data in
|
|
11
10
|
another type, scaling and shifting as necessary.
|
|
@@ -27,8 +26,8 @@ def convert(
|
|
|
27
26
|
arr = np.copy(arr)
|
|
28
27
|
return arr
|
|
29
28
|
|
|
30
|
-
old_int =
|
|
31
|
-
new_int =
|
|
29
|
+
old_int = "int" in str(old_t)
|
|
30
|
+
new_int = "int" in str(new_t)
|
|
32
31
|
|
|
33
32
|
if not (new_int or old_int):
|
|
34
33
|
# Convert between floats
|
|
@@ -96,8 +95,15 @@ def _twenty_four_bit(shape, new, raw, itemsize):
|
|
|
96
95
|
assert not (frames % 4)
|
|
97
96
|
|
|
98
97
|
# https://stackoverflow.com/a/34128171/4383
|
|
99
|
-
raw = new(shape=(itemsize * frames // 4,), dtype=
|
|
100
|
-
strided = as_strided(
|
|
98
|
+
raw = new(shape=(itemsize * frames // 4,), dtype="int32")
|
|
99
|
+
strided = as_strided(
|
|
100
|
+
raw,
|
|
101
|
+
strides=(
|
|
102
|
+
12,
|
|
103
|
+
3,
|
|
104
|
+
),
|
|
105
|
+
shape=(frames, 4),
|
|
106
|
+
)
|
|
101
107
|
reshaped = np.reshape(strided, shape=shape)
|
|
102
108
|
|
|
103
109
|
result = reshaped & 0x00FFFFFF
|
|
@@ -15,9 +15,9 @@ Think of this as `self`. (This is because you need to implement `__new__`
|
|
|
15
15
|
and not `__init__` when deriving from `np.darray`.)
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
DTYPE =
|
|
18
|
+
DTYPE = "The numpy datatype of the samples in the file."
|
|
19
19
|
|
|
20
|
-
FILENAME =
|
|
20
|
+
FILENAME = "The name of the file being mapped"
|
|
21
21
|
|
|
22
22
|
ORDER = """
|
|
23
23
|
Samples usually get laid out in into a `numpy.darray` with`
|
|
@@ -63,9 +63,9 @@ In mode `'w+'`, "write", the file is opened for write, and overwrites
|
|
|
63
63
|
whatever else is there.
|
|
64
64
|
"""
|
|
65
65
|
|
|
66
|
-
OFFSET =
|
|
67
|
-
ROFFSET =
|
|
68
|
-
SAMPLE_RATE =
|
|
66
|
+
OFFSET = "How many bytes in the file before the WAV data"
|
|
67
|
+
ROFFSET = "How many bytes in the file after the WAV data"
|
|
68
|
+
SAMPLE_RATE = "The sample rate in Hz (cycles per second)"
|
|
69
69
|
|
|
70
70
|
SHAPE = """
|
|
71
71
|
The shape of the resulting numpy.darray. Can be a tuple, or a positive
|
|
@@ -87,19 +87,19 @@ def arguments(*names, subs=None):
|
|
|
87
87
|
names = [(i, subs.get(i, i).upper()) for i in names]
|
|
88
88
|
missing = [n for (n, a) in names if a not in globals()]
|
|
89
89
|
if missing:
|
|
90
|
-
raise ValueError(f
|
|
90
|
+
raise ValueError(f"Cannot document arguments {missing}")
|
|
91
91
|
|
|
92
|
-
yield
|
|
92
|
+
yield "ARGUMENTS"
|
|
93
93
|
for name, attr in names:
|
|
94
|
-
yield f
|
|
94
|
+
yield f" {name}"
|
|
95
95
|
for line in globals()[attr].strip().splitlines():
|
|
96
|
-
yield line and f
|
|
97
|
-
yield
|
|
96
|
+
yield line and f" {line}"
|
|
97
|
+
yield ""
|
|
98
98
|
|
|
99
99
|
|
|
100
100
|
def add_arguments(func, names, subs=None):
|
|
101
101
|
params = arguments(*names, subs=subs)
|
|
102
|
-
func.__doc__ = func.__doc__.rstrip() +
|
|
102
|
+
func.__doc__ = func.__doc__.rstrip() + "\n\n" + "\n".join(params)
|
|
103
103
|
return func
|
|
104
104
|
|
|
105
105
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
from numpy.compat import os_fspath, contextlib_nullcontext, is_pathlib_path
|
|
2
|
-
from numpy.core.numeric import uint8, ndarray, dtype
|
|
3
|
-
from numpy.core.overrides import set_module
|
|
4
1
|
import numpy as np
|
|
2
|
+
from numpy.compat import contextlib_nullcontext, is_pathlib_path, os_fspath
|
|
3
|
+
from numpy.core.numeric import dtype, ndarray, uint8
|
|
4
|
+
from numpy.core.overrides import set_module
|
|
5
5
|
|
|
6
|
-
__all__ = [
|
|
6
|
+
__all__ = ["memmap"]
|
|
7
7
|
|
|
8
8
|
dtypedescr = dtype
|
|
9
9
|
valid_filemodes = ["r", "c", "r+", "w+"]
|
|
@@ -17,7 +17,7 @@ mode_equivalents = {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
@set_module(
|
|
20
|
+
@set_module("numpy")
|
|
21
21
|
class memmap(ndarray):
|
|
22
22
|
"""Create a memory-map to an array stored in a *binary* file on disk.
|
|
23
23
|
|
|
@@ -204,10 +204,10 @@ class memmap(ndarray):
|
|
|
204
204
|
subtype,
|
|
205
205
|
filename,
|
|
206
206
|
dtype=uint8,
|
|
207
|
-
mode=
|
|
207
|
+
mode="r+",
|
|
208
208
|
offset=0,
|
|
209
209
|
shape=None,
|
|
210
|
-
order=
|
|
210
|
+
order="C",
|
|
211
211
|
roffset=0,
|
|
212
212
|
):
|
|
213
213
|
# Import here to minimize 'import numpy' overhead
|
|
@@ -224,15 +224,13 @@ class memmap(ndarray):
|
|
|
224
224
|
)
|
|
225
225
|
) from None
|
|
226
226
|
|
|
227
|
-
if mode ==
|
|
227
|
+
if mode == "w+" and shape is None:
|
|
228
228
|
raise ValueError("shape must be given")
|
|
229
229
|
|
|
230
|
-
if hasattr(filename,
|
|
230
|
+
if hasattr(filename, "read"):
|
|
231
231
|
f_ctx = contextlib_nullcontext(filename)
|
|
232
232
|
else:
|
|
233
|
-
f_ctx = open(
|
|
234
|
-
os_fspath(filename), ('r' if mode == 'c' else mode) + 'b'
|
|
235
|
-
)
|
|
233
|
+
f_ctx = open(os_fspath(filename), ("r" if mode == "c" else mode) + "b")
|
|
236
234
|
|
|
237
235
|
with f_ctx as fid:
|
|
238
236
|
fid.seek(0, 2)
|
|
@@ -260,14 +258,14 @@ class memmap(ndarray):
|
|
|
260
258
|
|
|
261
259
|
bytes = int(offset + size * _dbytes + roffset)
|
|
262
260
|
|
|
263
|
-
if mode in (
|
|
261
|
+
if mode in ("w+", "r+") and flen < bytes:
|
|
264
262
|
fid.seek(bytes - 1, 0)
|
|
265
|
-
fid.write(b
|
|
263
|
+
fid.write(b"\0")
|
|
266
264
|
fid.flush()
|
|
267
265
|
|
|
268
|
-
if mode ==
|
|
266
|
+
if mode == "c":
|
|
269
267
|
acc = mmap.ACCESS_COPY
|
|
270
|
-
elif mode ==
|
|
268
|
+
elif mode == "r":
|
|
271
269
|
acc = mmap.ACCESS_READ
|
|
272
270
|
else:
|
|
273
271
|
acc = mmap.ACCESS_WRITE
|
|
@@ -304,7 +302,7 @@ class memmap(ndarray):
|
|
|
304
302
|
return self
|
|
305
303
|
|
|
306
304
|
def __array_finalize__(self, obj):
|
|
307
|
-
if hasattr(obj,
|
|
305
|
+
if hasattr(obj, "_mmap") and np.may_share_memory(self, obj):
|
|
308
306
|
self._mmap = obj._mmap
|
|
309
307
|
self.filename = obj.filename
|
|
310
308
|
self.offset = obj.offset
|
|
@@ -330,11 +328,11 @@ class memmap(ndarray):
|
|
|
330
328
|
memmap
|
|
331
329
|
|
|
332
330
|
"""
|
|
333
|
-
if self.base is not None and hasattr(self.base,
|
|
331
|
+
if self.base is not None and hasattr(self.base, "flush"):
|
|
334
332
|
self.base.flush()
|
|
335
333
|
|
|
336
334
|
def __array_wrap__(self, arr, context=None):
|
|
337
|
-
arr = super(
|
|
335
|
+
arr = super().__array_wrap__(arr, context)
|
|
338
336
|
|
|
339
337
|
# Return a memmap if a memmap was given as the output of the
|
|
340
338
|
# ufunc. Leave the arr class unchanged if self is not a memmap
|
|
@@ -349,7 +347,7 @@ class memmap(ndarray):
|
|
|
349
347
|
return arr.view(np.ndarray)
|
|
350
348
|
|
|
351
349
|
def __getitem__(self, index):
|
|
352
|
-
res = super(
|
|
350
|
+
res = super().__getitem__(index)
|
|
353
351
|
if type(res) is memmap and res._mmap is None:
|
|
354
352
|
return res.view(type=ndarray)
|
|
355
353
|
return res
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from typing import Optional, Union
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
1
7
|
from . import docs
|
|
2
8
|
from .memmap import memmap
|
|
3
|
-
from typing import Callable, Optional, Union
|
|
4
|
-
import numpy as np
|
|
5
|
-
import sys
|
|
6
9
|
|
|
7
|
-
int24 =
|
|
10
|
+
int24 = "int24"
|
|
8
11
|
|
|
9
12
|
|
|
10
13
|
def warn(msg):
|
|
@@ -12,20 +15,20 @@ def warn(msg):
|
|
|
12
15
|
|
|
13
16
|
|
|
14
17
|
class RawMap(memmap):
|
|
15
|
-
""""Memory map raw audio data from a disk file into a numpy matrix"""
|
|
18
|
+
""" "Memory map raw audio data from a disk file into a numpy matrix"""
|
|
16
19
|
|
|
17
20
|
@docs.update
|
|
18
21
|
def __new__(
|
|
19
22
|
cls,
|
|
20
23
|
filename: str,
|
|
21
24
|
dtype: np.dtype,
|
|
22
|
-
shape:
|
|
23
|
-
mode: str =
|
|
25
|
+
shape: tuple | int | None = None,
|
|
26
|
+
mode: str = "r",
|
|
24
27
|
offset: int = 0,
|
|
25
28
|
roffset: int = 0,
|
|
26
|
-
order:
|
|
29
|
+
order: str | None = None,
|
|
27
30
|
always_2d: bool = False,
|
|
28
|
-
warn:
|
|
31
|
+
warn: Callable | None = warn,
|
|
29
32
|
):
|
|
30
33
|
"""Memory map raw audio data from a disk file into a numpy matrix"""
|
|
31
34
|
# Documentation for parameters is in docs.py
|
|
@@ -36,22 +39,22 @@ class RawMap(memmap):
|
|
|
36
39
|
)
|
|
37
40
|
|
|
38
41
|
if offset < 0 or roffset < 0:
|
|
39
|
-
raise ValueError(
|
|
42
|
+
raise ValueError("offset and roffset must be non-negative")
|
|
40
43
|
|
|
41
|
-
if order not in (
|
|
44
|
+
if order not in ("C", "F", None):
|
|
42
45
|
raise ValueError(f'Bad order "{order}"')
|
|
43
46
|
|
|
44
47
|
if isinstance(shape, int):
|
|
45
48
|
shape = (shape,)
|
|
46
49
|
|
|
47
50
|
if not (shape is None or 1 <= len(shape) <= 2):
|
|
48
|
-
raise ValueError(
|
|
51
|
+
raise ValueError("Wave files must have 1 or 2 dimensions")
|
|
49
52
|
|
|
50
|
-
if
|
|
53
|
+
if "w" in mode:
|
|
51
54
|
if not shape:
|
|
52
|
-
raise ValueError(
|
|
53
|
-
order = order or
|
|
54
|
-
return new(mode=
|
|
55
|
+
raise ValueError("Must set a shape in write mode")
|
|
56
|
+
order = order or "FC"[max(shape) == shape[0]]
|
|
57
|
+
return new(mode="w+", order=order)
|
|
55
58
|
|
|
56
59
|
if str(dtype) == int24:
|
|
57
60
|
itemsize = 3
|
|
@@ -62,12 +65,12 @@ class RawMap(memmap):
|
|
|
62
65
|
audio_size = file_size - offset - roffset
|
|
63
66
|
shape = _get_shape(shape, audio_size, itemsize, order, always_2d, warn)
|
|
64
67
|
if itemsize == 3:
|
|
65
|
-
raise ValueError(
|
|
68
|
+
raise ValueError("Cannot memory map 24-bit audio")
|
|
66
69
|
return new(shape=shape)
|
|
67
70
|
|
|
68
71
|
|
|
69
72
|
def file_byte_size(filename: str):
|
|
70
|
-
with open(filename,
|
|
73
|
+
with open(filename, "rb") as fp:
|
|
71
74
|
return fp.seek(0, 2)
|
|
72
75
|
|
|
73
76
|
|
|
@@ -78,27 +81,27 @@ def _get_shape(shape, audio_size, itemsize, order, always_2d, warn):
|
|
|
78
81
|
if itemsize == 3:
|
|
79
82
|
extra = audio_size % 12
|
|
80
83
|
if extra and warn:
|
|
81
|
-
s =
|
|
82
|
-
warn(f
|
|
84
|
+
s = "s" if len(extra) != 1 else ""
|
|
85
|
+
warn(f"24-bit conversion lost last {extra} byte{s}, sorry")
|
|
83
86
|
audio_size -= extra
|
|
84
87
|
|
|
85
88
|
frame_size = itemsize * channels
|
|
86
89
|
frames = audio_size // frame_size
|
|
87
90
|
|
|
88
91
|
if frames_requested and frames_requested < frames:
|
|
89
|
-
warn(f
|
|
92
|
+
warn(f"Requested {frames_requested} frames, got {frames}")
|
|
90
93
|
frames = frames_requested
|
|
91
94
|
|
|
92
95
|
if warn:
|
|
93
96
|
extra = audio_size % frame_size
|
|
94
97
|
if extra:
|
|
95
|
-
s =
|
|
96
|
-
warn(f
|
|
98
|
+
s = "" if extra == 1 else "s"
|
|
99
|
+
warn(f"{extra} byte{s} after end-of-frame discarded")
|
|
97
100
|
|
|
98
101
|
if channels == 1 and not always_2d:
|
|
99
102
|
return (frames,)
|
|
100
103
|
|
|
101
|
-
if not order or order ==
|
|
104
|
+
if not order or order == "C":
|
|
102
105
|
return frames, channels
|
|
103
106
|
|
|
104
107
|
return channels, frames
|