wavemap 2.0.1__py3-none-any.whl → 2.1.0__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.
wavemap/.DS_Store ADDED
Binary file
wavemap/__init__.py CHANGED
@@ -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
- 'wavemap',
40
- 'RawMap',
41
- 'ReadMap',
42
- 'WriteMap',
43
- 'copy_to',
44
- 'new_like',
45
- 'convert',
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: '<function warn: print to stderr>'}
52
- _WRITE_PARAMETERS = 'dtype', 'shape', 'sample_rate'
53
- _READ_PARAMETERS = 'order', 'always_2d'
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 = 'r',
64
- order: Optional[str] = None,
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: Optional[np.dtype] = None,
70
- shape: Union[None, int, tuple] = None,
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: Optional[Callable] = 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('w'):
87
+ if mode.startswith("w"):
85
88
  if not dtype:
86
- raise ValueError('dtype must be set for write')
89
+ raise ValueError("dtype must be set for write")
87
90
  if not shape:
88
- raise ValueError('shape must be set for write')
91
+ raise ValueError("shape must be set for write")
89
92
  if not sample_rate:
90
- raise ValueError('sample_rate must be set for write')
93
+ raise ValueError("sample_rate must be set for write")
91
94
 
92
95
  if order:
93
- raise ValueError('order cannot be set for write')
96
+ raise ValueError("order cannot be set for write")
94
97
  if always_2d:
95
- raise ValueError('always_2d cannot be set for write')
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('shape cannot be set for write')
110
+ raise ValueError("shape cannot be set for write")
108
111
  if sample_rate:
109
- raise ValueError('sample_rate cannot be set for write')
112
+ raise ValueError("sample_rate cannot be set for write")
110
113
 
111
114
  result = ReadMap(
112
115
  filename=filename,
wavemap/convert.py CHANGED
@@ -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 = 'int' in str(old_t)
31
- new_int = 'int' in str(new_t)
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='int32')
100
- strided = as_strided(raw, strides=(12, 3,), shape=(frames, 4))
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
wavemap/docs.py CHANGED
@@ -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 = 'The numpy datatype of the samples in the file.'
18
+ DTYPE = "The numpy datatype of the samples in the file."
19
19
 
20
- FILENAME = 'The name of the file being mapped'
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 = '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)'
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'Cannot document arguments {missing}')
90
+ raise ValueError(f"Cannot document arguments {missing}")
91
91
 
92
- yield 'ARGUMENTS'
92
+ yield "ARGUMENTS"
93
93
  for name, attr in names:
94
- yield f' {name}'
94
+ yield f" {name}"
95
95
  for line in globals()[attr].strip().splitlines():
96
- yield line and f' {line}'
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() + '\n\n' + '\n'.join(params)
102
+ func.__doc__ = func.__doc__.rstrip() + "\n\n" + "\n".join(params)
103
103
  return func
104
104
 
105
105
 
wavemap/memmap.py CHANGED
@@ -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__ = ['memmap']
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('numpy')
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='r+',
207
+ mode="r+",
208
208
  offset=0,
209
209
  shape=None,
210
- order='C',
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 == 'w+' and shape is None:
227
+ if mode == "w+" and shape is None:
228
228
  raise ValueError("shape must be given")
229
229
 
230
- if hasattr(filename, 'read'):
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 ('w+', 'r+') and flen < bytes:
261
+ if mode in ("w+", "r+") and flen < bytes:
264
262
  fid.seek(bytes - 1, 0)
265
- fid.write(b'\0')
263
+ fid.write(b"\0")
266
264
  fid.flush()
267
265
 
268
- if mode == 'c':
266
+ if mode == "c":
269
267
  acc = mmap.ACCESS_COPY
270
- elif mode == 'r':
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, '_mmap') and np.may_share_memory(self, 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, 'flush'):
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(memmap, self).__array_wrap__(arr, context)
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(memmap, self).__getitem__(index)
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
wavemap/raw.py CHANGED
@@ -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 = '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: Union[tuple, int, None] = None,
23
- mode: str = 'r',
25
+ shape: tuple | int | None = None,
26
+ mode: str = "r",
24
27
  offset: int = 0,
25
28
  roffset: int = 0,
26
- order: Optional[str] = None,
29
+ order: str | None = None,
27
30
  always_2d: bool = False,
28
- warn: Optional[Callable] = 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('offset and roffset must be non-negative')
42
+ raise ValueError("offset and roffset must be non-negative")
40
43
 
41
- if order not in ('C', 'F', None):
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('Wave files must have 1 or 2 dimensions')
51
+ raise ValueError("Wave files must have 1 or 2 dimensions")
49
52
 
50
- if 'w' in mode:
53
+ if "w" in mode:
51
54
  if not shape:
52
- raise ValueError('Must set a shape in write mode')
53
- order = order or 'FC'[max(shape) == shape[0]]
54
- return new(mode='w+', order=order)
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('Cannot memory map 24-bit audio')
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, 'rb') as fp:
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 = 's' if len(extra) != 1 else ''
82
- warn(f'24-bit conversion lost last {extra} byte{s}, sorry')
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'Requested {frames_requested} frames, got {frames}')
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 = '' if extra == 1 else 's'
96
- warn(f'{extra} byte{s} after end-of-frame discarded')
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 == 'C':
104
+ if not order or order == "C":
102
105
  return frames, channels
103
106
 
104
107
  return channels, frames
wavemap/read.py CHANGED
@@ -1,15 +1,18 @@
1
+ import struct
2
+ from typing import Optional, Type
3
+ from collections.abc import Callable
4
+
5
+ import numpy as np
6
+
1
7
  from . import docs, raw
2
8
  from .structure import wave
3
- from typing import Callable, Optional, Type
4
- import numpy as np
5
- import struct
6
9
 
7
10
  FLOAT_BITS_PER_SAMPLE = {32, 64}
8
11
  PCM_BITS_PER_SAMPLE = {8, 16, 24, 32, 64}
9
12
 
10
13
  BITS_PER_SAMPLE = PCM_BITS_PER_SAMPLE, FLOAT_BITS_PER_SAMPLE
11
14
  FMT_BLOCK_LENGTHS = {16, 18, 20, 40}
12
- MODES = 'r', 'r+', 'c'
15
+ MODES = "r", "r+", "c"
13
16
 
14
17
  # Deal with a quirk in certain .WAV test files
15
18
  BAD_TAG_ADJUSTMENT = True
@@ -18,24 +21,24 @@ BAD_TAG_ADJUSTMENT = True
18
21
  class ReadMap(raw.RawMap):
19
22
  """Memory-map an existing WAVE file into a numpy vector or matrix"""
20
23
 
21
- @docs.update(mode='READ_ONLY_MODE')
24
+ @docs.update(mode="READ_ONLY_MODE")
22
25
  def __new__(
23
- cls: Type,
26
+ cls: type,
24
27
  filename: str,
25
- mode: str = 'r',
26
- order: Optional[str] = None,
28
+ mode: str = "r",
29
+ order: str | None = None,
27
30
  always_2d: bool = False,
28
- warn: Optional[Callable] = raw.warn,
31
+ warn: Callable | None = raw.warn,
29
32
  ):
30
33
  # Documentation for parameters is in docs.py
31
34
  """Memory-map an existing WAVE file into a numpy matrix."""
32
35
 
33
36
  if mode not in MODES:
34
- raise ValueError(f'Mode {mode} not in {MODES}')
37
+ raise ValueError(f"Mode {mode} not in {MODES}")
35
38
 
36
39
  file_size = raw.file_byte_size(filename)
37
40
 
38
- with open(filename, 'rb') as fp:
41
+ with open(filename, "rb") as fp:
39
42
  begin, end, fmt = _metadata(fp, warn, file_size)
40
43
  offset = begin + wave.CHUNK.size
41
44
  roffset = file_size - end
@@ -47,23 +50,21 @@ class ReadMap(raw.RawMap):
47
50
  f.wFormatTag = g.wFormatTag
48
51
 
49
52
  if f.wFormatTag not in wave.WAVE_FORMATS:
50
- raise ValueError(f'Do not understand f.wFormatTag={f.wFormatTag}')
53
+ raise ValueError(f"Do not understand f.wFormatTag={f.wFormatTag}")
51
54
 
52
55
  is_float = f.wFormatTag == wave.WAVE_FORMAT_IEEE_FLOAT
53
56
 
54
57
  if f.wBitsPerSample == 24:
55
- raise ValueError('Reading 24-bit WAVEs is not quite supported')
58
+ raise ValueError("Reading 24-bit WAVEs is not quite supported")
56
59
 
57
60
  if f.wBitsPerSample not in BITS_PER_SAMPLE[is_float]:
58
- raise ValueError(
59
- f'Cannot mmap f.wBitsPerSample={f.wBitsPerSample}'
60
- )
61
+ raise ValueError(f"Cannot mmap f.wBitsPerSample={f.wBitsPerSample}")
61
62
 
62
63
  if f.wBitsPerSample == 8:
63
- dtype = 'uint8'
64
+ dtype = "uint8"
64
65
  else:
65
- type_name = ('int', 'float')[is_float]
66
- dtype = f'{type_name}{f.wBitsPerSample}'
66
+ type_name = ("int", "float")[is_float]
67
+ dtype = f"{type_name}{f.wBitsPerSample}"
67
68
 
68
69
  assert np.dtype(dtype).itemsize == f.wBitsPerSample // 8
69
70
  self = raw.RawMap.__new__(
@@ -85,35 +86,35 @@ class ReadMap(raw.RawMap):
85
86
 
86
87
  def _metadata(fp, warn, file_size):
87
88
  (tag, b, e), *chunks = _chunks(fp, warn, file_size)
88
- if tag != b'WAVE':
89
- raise ValueError(f'Not a WAVE file: {tag}')
89
+ if tag != b"WAVE":
90
+ raise ValueError(f"Not a WAVE file: {tag}")
90
91
 
91
92
  assert b == 0
92
93
  if e != file_size - 8:
93
- warn(f'WAVE cksize is wrong: {e} != {file_size - 8}')
94
+ warn(f"WAVE cksize is wrong: {e} != {file_size - 8}")
94
95
 
95
96
  begin = end = fmt = None
96
97
  for tag, b, e in chunks:
97
- if tag == b'fmt ':
98
+ if tag == b"fmt ":
98
99
  if not fmt:
99
100
  fp.seek(b)
100
101
  fmt = fp.read(e - b)
101
102
  else:
102
- warn('fmt chunk after first ignored')
103
- elif tag == b'data':
103
+ warn("fmt chunk after first ignored")
104
+ elif tag == b"data":
104
105
  if not (begin or end):
105
106
  begin, end = b, e
106
107
  else:
107
- warn('data chunk after first ignored')
108
+ warn("data chunk after first ignored")
108
109
 
109
110
  if begin is None:
110
- raise ValueError('No data chunk found')
111
+ raise ValueError("No data chunk found")
111
112
 
112
113
  if fmt is None:
113
- raise ValueError('No fmt chunk found')
114
+ raise ValueError("No fmt chunk found")
114
115
 
115
116
  if (len(fmt) - wave.CHUNK.size) not in FMT_BLOCK_LENGTHS:
116
- warn(f'Weird fmt block length {len(fmt)}')
117
+ warn(f"Weird fmt block length {len(fmt)}")
117
118
 
118
119
  return begin, end, fmt
119
120
 
@@ -128,26 +129,26 @@ def _chunks(fp, warn, file_size):
128
129
  if len(s) < size:
129
130
  raise IncompleteChunk()
130
131
 
131
- return struct.unpack('<' + format, s)[0]
132
+ return struct.unpack("<" + format, s)[0]
132
133
 
133
134
  def read_tag():
134
- tag = read_one('4s')
135
+ tag = read_one("4s")
135
136
  if tag and not tag.rstrip().isalnum():
136
137
  if BAD_TAG_ADJUSTMENT and tag[0] == 0:
137
138
  tag = tag[1:] + fp.read(1)
138
139
  if tag.rstrip().isalnum():
139
140
  return tag
140
141
 
141
- warn(f'Dubious tag {tag}')
142
+ warn(f"Dubious tag {tag}")
142
143
 
143
144
  return tag
144
145
 
145
146
  def read_int():
146
- return read_one('I')
147
+ return read_one("I")
147
148
 
148
149
  tag = read_tag()
149
- if tag != b'RIFF':
150
- raise ValueError('Not a RIFF file')
150
+ if tag != b"RIFF":
151
+ raise ValueError("Not a RIFF file")
151
152
 
152
153
  size = read_int()
153
154
  yield read_tag(), 0, size
@@ -158,19 +159,19 @@ def _chunks(fp, warn, file_size):
158
159
  try:
159
160
  tag = read_tag()
160
161
  except IncompleteChunk:
161
- warn('Incomplete chunk: no tag')
162
+ warn("Incomplete chunk: no tag")
162
163
  break
163
164
 
164
165
  try:
165
166
  chunk_size = read_int()
166
167
  except IncompleteChunk:
167
- warn('Incomplete chunk: no size')
168
+ warn("Incomplete chunk: no size")
168
169
  break
169
170
 
170
171
  fp.seek(chunk_size, 1)
171
172
  end = fp.tell()
172
173
  if end > file_size:
173
174
  if end > file_size + 1:
174
- warn(f'Incomplete chunk: {end} > {file_size + 1}')
175
+ warn(f"Incomplete chunk: {end} > {file_size + 1}")
175
176
  end = file_size
176
177
  yield tag, begin, end
@@ -1,9 +1,10 @@
1
1
  """Better struct"""
2
- from argparse import Namespace
2
+
3
3
  import struct
4
+ from argparse import Namespace
4
5
 
5
- INT16 = 'H'
6
- INT32 = 'I'
6
+ INT16 = "H"
7
+ INT32 = "I"
7
8
 
8
9
  INT = INT16, INT32
9
10
 
@@ -11,7 +12,7 @@ INT = INT16, INT32
11
12
  class Structure:
12
13
  def __init__(self, **formats):
13
14
  self.formats = formats
14
- self.struct = struct.Struct('<' + ''.join(formats.values()))
15
+ self.struct = struct.Struct("<" + "".join(formats.values()))
15
16
  self.size = self.struct.size
16
17
 
17
18
  def pack(self, **kwargs):
@@ -33,28 +34,26 @@ class Structure:
33
34
  try:
34
35
  v = kw[name]
35
36
  except KeyError:
36
- errors.append(f'Unknown param {name}')
37
+ errors.append(f"Unknown param {name}")
37
38
  else:
38
39
  if fmt in INT and not isinstance(v, int):
39
- errors.append(f'Integer {name} had value {v!r}')
40
- elif fmt.endswith('s') and not isinstance(v, bytes):
41
- errors.append(f'Bytes {name} had value {v!r}')
40
+ errors.append(f"Integer {name} had value {v!r}")
41
+ elif fmt.endswith("s") and not isinstance(v, bytes):
42
+ errors.append(f"Bytes {name} had value {v!r}")
42
43
  else:
43
44
  args.append(v)
44
45
 
45
46
  # We accept the unknown
46
47
  unknown = False and set(kw).difference(self.names)
47
48
  if unknown:
48
- s = '' if len(unknown) == 1 else 's'
49
- unknown = ', '.join(sorted(unknown))
50
- errors.append(f'Unknown argument{s}: {unknown}')
49
+ s = "" if len(unknown) == 1 else "s"
50
+ unknown = ", ".join(sorted(unknown))
51
+ errors.append(f"Unknown argument{s}: {unknown}")
51
52
  raise ValueError(errors[-1])
52
53
 
53
- msg = '. '.join(errors)
54
+ msg = ". ".join(errors)
54
55
  if msg:
55
56
  raise ValueError(msg)
56
57
 
57
- assert len(args) == len(
58
- self.formats
59
- ), f'{len(args)} == {len(self.formats)}'
58
+ assert len(args) == len(self.formats), f"{len(args)} == {len(self.formats)}"
60
59
  return args
wavemap/structure/wave.py CHANGED
@@ -1,4 +1,4 @@
1
- from .structure import Structure, INT16, INT32
1
+ from .structure import INT16, INT32, Structure
2
2
 
3
3
  WAVE_FORMAT_PCM = 0x0001
4
4
  WAVE_FORMAT_IEEE_FLOAT = 0x0003
@@ -14,8 +14,8 @@ WAVE_FORMATS = (
14
14
  WAVE_FORMAT_EXTENSIBLE,
15
15
  )
16
16
 
17
- TAG = '4s'
18
- SUBFORMAT = '14s'
17
+ TAG = "4s"
18
+ SUBFORMAT = "14s"
19
19
 
20
20
  CHUNK = Structure(ckID=TAG, cksize=INT32)
21
21
  RIFF = Structure(ckIDRiff=TAG, cksizeRiff=INT32, WAVEID=TAG)
@@ -58,8 +58,8 @@ NON_PCM = RIFF + FMT_NON_PCM + FACT + DATA
58
58
  assert PCM.size == 44
59
59
  assert NON_PCM.size == 58
60
60
 
61
- if __name__ == '__main__':
61
+ if __name__ == "__main__":
62
62
  d = list(locals().items())
63
63
  for k, v in d:
64
64
  if isinstance(v, Structure):
65
- print(f'assert {k}.size == {v.size}')
65
+ print(f"assert {k}.size == {v.size}")
wavemap/write.py CHANGED
@@ -1,26 +1,28 @@
1
- from . import docs
2
- from . import raw
3
- from .structure import wave
4
- from .structure.wave import PCM, NON_PCM, FMT_PCM, FMT_NON_PCM
5
- from typing import Callable, Optional, Type, Union
1
+ from typing import Optional, Type, Union
2
+ from collections.abc import Callable
3
+
6
4
  import numpy as np
7
5
 
6
+ from . import docs, raw
7
+ from .structure import wave
8
+ from .structure.wave import FMT_NON_PCM, FMT_PCM, NON_PCM, PCM
9
+
8
10
  CHUNK_HEADER = 8
9
11
  DEFAULT_SAMPLE_RATE = 44100
10
12
 
11
13
 
12
14
  class WriteMap(raw.RawMap):
13
- """"Memory-map a new wave file into a new numpy vector or matrix"""
15
+ """ "Memory-map a new wave file into a new numpy vector or matrix"""
14
16
 
15
17
  @docs.update
16
18
  def __new__(
17
- cls: Type,
19
+ cls: type,
18
20
  filename: str,
19
21
  dtype: np.dtype,
20
- shape: Union[None, int, tuple],
22
+ shape: None | int | tuple,
21
23
  sample_rate: int,
22
24
  roffset: int = 0,
23
- warn: Optional[Callable] = raw.warn,
25
+ warn: Callable | None = raw.warn,
24
26
  ):
25
27
  """
26
28
  Open a memory-mapped WAVE file in write mode and overwrite any existing
@@ -50,7 +52,7 @@ class WriteMap(raw.RawMap):
50
52
  cls,
51
53
  filename=filename,
52
54
  dtype=dtype,
53
- mode='w+',
55
+ mode="w+",
54
56
  shape=shape,
55
57
  offset=structure.size,
56
58
  roffset=roffset + pad,
@@ -62,10 +64,10 @@ class WriteMap(raw.RawMap):
62
64
 
63
65
  structure.pack_into(
64
66
  self._mmap,
65
- ckIDRiff=b'RIFF',
67
+ ckIDRiff=b"RIFF",
66
68
  cksizeRiff=self.file_size - CHUNK_HEADER,
67
- WAVEID=b'WAVE',
68
- ckIDFmt=b'fmt ',
69
+ WAVEID=b"WAVE",
70
+ ckIDFmt=b"fmt ",
69
71
  cksizeFmt=fmt_structure.size - CHUNK_HEADER,
70
72
  wFormatTag=wFormatTag,
71
73
  nChannels=channel_count,
@@ -74,10 +76,10 @@ class WriteMap(raw.RawMap):
74
76
  nBlockAlign=frame_bytes,
75
77
  wBitsPerSample=sample_bytes * 8,
76
78
  cbSize=0, # Non PCM
77
- ckIDFact=b'fact',
79
+ ckIDFact=b"fact",
78
80
  cksizeFact=4,
79
81
  dwSampleLength=channel_count * frame_count,
80
- ckIDData=b'data',
82
+ ckIDData=b"data",
81
83
  cksizeData=total_frame_bytes,
82
84
  )
83
85
 
@@ -85,30 +87,30 @@ class WriteMap(raw.RawMap):
85
87
 
86
88
  @classmethod
87
89
  def new_like(
88
- cls: Type,
90
+ cls: type,
89
91
  arr: np.ndarray,
90
92
  filename: str,
91
- sample_rate: Optional[int] = None,
92
- roffset: Optional[int] = None,
93
- warn: Optional[Callable] = raw.warn,
93
+ sample_rate: int | None = None,
94
+ roffset: int | None = None,
95
+ warn: Callable | None = raw.warn,
94
96
  ):
95
97
  if sample_rate is None:
96
- sample_rate = getattr(arr, 'sample_rate', DEFAULT_SAMPLE_RATE)
98
+ sample_rate = getattr(arr, "sample_rate", DEFAULT_SAMPLE_RATE)
97
99
 
98
100
  if roffset is None:
99
- roffset = getattr(arr, 'roffset', 0)
101
+ roffset = getattr(arr, "roffset", 0)
100
102
 
101
103
  return cls(filename, arr.dtype, arr.shape, sample_rate, roffset, warn)
102
104
 
103
105
  @classmethod
104
106
  def copy_to(
105
- cls: Type,
107
+ cls: type,
106
108
  arr: np.ndarray,
107
109
  filename: str,
108
- sample_rate: Optional[int] = None,
109
- roffset: Optional[int] = None,
110
- warn: Optional[Callable] = raw.warn,
110
+ sample_rate: int | None = None,
111
+ roffset: int | None = None,
112
+ warn: Callable | None = raw.warn,
111
113
  ):
112
114
  wm = cls.new_like(arr, filename, sample_rate, roffset, warn)
113
- np.copyto(src=arr, dst=wm, casting='no')
115
+ np.copyto(src=arr, dst=wm, casting="no")
114
116
  return wm
@@ -1,25 +1,20 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: wavemap
3
- Version: 2.0.1
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
- Keywords: testing,modules
10
- Platform: UNKNOWN
11
- Classifier: Development Status :: 4 - Beta
12
- Classifier: Programming Language :: Python :: 3.6
13
- Classifier: Programming Language :: Python :: 3.7
14
- Classifier: Programming Language :: Python :: 3.8
15
- Classifier: Programming Language :: Python :: 3.9
16
- Classifier: Intended Audience :: Developers
17
- Classifier: License :: OSI Approved :: MIT License
18
- Classifier: Topic :: Software Development :: Libraries
19
- Classifier: Topic :: Utilities
20
- License-File: LICENSE
21
- Requires-Dist: numpy
22
- Requires-Dist: xmod
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
23
18
 
24
19
  🌊 Memory map WAVE files into numpy arrays 🌊
25
20
  ----------------------------------------------
@@ -381,5 +376,3 @@ ARGUMENTS
381
376
  If true, ``arr`` is copied even if it is already the requested type
382
377
 
383
378
  (automatically generated by `doks <https://github.com/rec/doks/>`_ on 2021-02-23T14:37:02.652534)
384
-
385
-
@@ -0,0 +1,14 @@
1
+ wavemap/.DS_Store,sha256=uGGhkWaTZaKSqiGr6XGHeFWLCFzn9KHjY8US4dk2k2E,6148
2
+ wavemap/__init__.py,sha256=UpU6uAIKQVOJebgxCgr5FP5krAmTwhQeBNWQbxCnBMs,3171
3
+ wavemap/convert.py,sha256=uqa3xz51Gd-6lfxj4l0ZJ4ITqTbNRk9-PUKlwaMdfUY,2853
4
+ wavemap/docs.py,sha256=3-ulKnCbYzfHw12pS8u3JoHJArSTzx6tjx5g5ft4JTY,3532
5
+ wavemap/memmap.py,sha256=8CT6Wwnn7lhDeUMBJ7e2dRdxAt4EH6Maa2e5Yu4wab0,11839
6
+ wavemap/raw.py,sha256=QCOdPCf6PmTsZgmTltjwIjqGvSeWxCuLLWQb7deYZJc,3069
7
+ wavemap/read.py,sha256=YvKACeT3EW7lwPeK2giXXILogGKhyKk-VNc7hx4cKp0,4883
8
+ wavemap/structure/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ wavemap/structure/structure.py,sha256=V6WHT341WM9ghr9LWkuN5VBJcOa6N_00--y3malnHBQ,1844
10
+ wavemap/structure/wave.py,sha256=-IvgbYdUjzDmP-j-X9aRQ9__-94IrTWJmr-Qp8xZ_OY,1462
11
+ wavemap/write.py,sha256=wzQShFzAp6ON_DTyC1qn8YI8tplDzH9d-s4q6j3p9qQ,3347
12
+ wavemap-2.1.0.dist-info/WHEEL,sha256=fAguSjoiATBe7TNBkJwOjyL1Tt4wwiaQGtNtjRPNMQA,80
13
+ wavemap-2.1.0.dist-info/METADATA,sha256=WJUW-Kj_Ry-ot9RriGD8WF-S6rS7mlnS9UBkxQWFJI0,11949
14
+ wavemap-2.1.0.dist-info/RECORD,,
@@ -1,5 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.37.1)
2
+ Generator: uv 0.9.28
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
-
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2020 Tom Ritchford
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1,15 +0,0 @@
1
- wavemap/__init__.py,sha256=B6Z-VKW6E9qdm6RPYhDrv28_AmYdqgZHqht1pOnRGoU,3177
2
- wavemap/convert.py,sha256=_UMqZHoZxye2currVAJI9dnZ_pBgYMxnpgqSj_F8Av0,2796
3
- wavemap/docs.py,sha256=nS3xRn8CXaxFf-cBromvzYlqWDzO0dSbnPfZ5q2IkY4,3532
4
- wavemap/memmap.py,sha256=IYPZOZIkXBuxKbOQiHWzBt4u05Le7tvdeUHjjHHpL40,11893
5
- wavemap/raw.py,sha256=TbIOLA0sJ1pEiKECK9lvQo8yZCQ1tuMqb24sCehrL4U,3050
6
- wavemap/read.py,sha256=I5aVUHUF2cdWTNlD3eRK4OxPRMq5x-E4BOd06pFbH-A,4890
7
- wavemap/write.py,sha256=-6IJsf6feiux0QlZl97Jat61JN5hB5Y-ghpwzVTbKLE,3356
8
- wavemap/structure/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- wavemap/structure/structure.py,sha256=gzQN-rCV_tsjV-LxOOdbGFlhuun6tixTgTbpcUL1weU,1865
10
- wavemap/structure/wave.py,sha256=uawYz0olhIzn4HSQu3l7gAAh_gxgPKqKS2zu2nKyq1s,1462
11
- wavemap-2.0.1.dist-info/LICENSE,sha256=2H3TTsBJEVDu73RHBbYDXTPRFsypRLOplkjh_AwfOi8,1070
12
- wavemap-2.0.1.dist-info/METADATA,sha256=-LpuSwdamJCvTEjuhQer1SBe3T9QZT9mcQLD73QTehk,12061
13
- wavemap-2.0.1.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
14
- wavemap-2.0.1.dist-info/top_level.txt,sha256=c-q4GFil8vegM_d7zFxRbPqt-wCNCz-6RuVchjFPFL0,8
15
- wavemap-2.0.1.dist-info/RECORD,,
@@ -1 +0,0 @@
1
- wavemap