mirror of
https://github.com/iluvcapra/wavinfo.git
synced 2025-12-31 08:50:41 +00:00
Merge pull request #36 from iluvcapra/feature-smpl
Feature: smpl Metadata
This commit is contained in:
@@ -31,6 +31,7 @@ it is not supported, please submit an issue!
|
|||||||
and Dolby Atmos `dbmd` metadata for re-renders and mixdowns.
|
and Dolby Atmos `dbmd` metadata for re-renders and mixdowns.
|
||||||
* Wave embedded [cue markers][cues], cue marker labels, notes and timed ranges as used
|
* Wave embedded [cue markers][cues], cue marker labels, notes and timed ranges as used
|
||||||
by Zoom, iZotope RX, etc.
|
by Zoom, iZotope RX, etc.
|
||||||
|
* Wave embedded [sampler][smpl] and sample loop metadata.
|
||||||
* The [wav format][format] is also parsed, so you can access the basic sample rate
|
* The [wav format][format] is also parsed, so you can access the basic sample rate
|
||||||
and channel count information.
|
and channel count information.
|
||||||
|
|
||||||
@@ -38,6 +39,7 @@ it is not supported, please submit an issue!
|
|||||||
[format]:https://wavinfo.readthedocs.io/en/latest/classes.html#wavinfo.wave_reader.WavAudioFormat
|
[format]:https://wavinfo.readthedocs.io/en/latest/classes.html#wavinfo.wave_reader.WavAudioFormat
|
||||||
[cues]:https://wavinfo.readthedocs.io/en/latest/scopes/cue.html
|
[cues]:https://wavinfo.readthedocs.io/en/latest/scopes/cue.html
|
||||||
[bext]:https://wavinfo.readthedocs.io/en/latest/scopes/bext.html
|
[bext]:https://wavinfo.readthedocs.io/en/latest/scopes/bext.html
|
||||||
|
[smpl]:https://wavinfo.readthedocs.io/en/latest/scopes/smpl.html
|
||||||
[smpte_330m2011]:https://wavinfo.readthedocs.io/en/latest/scopes/bext.html#wavinfo.wave_bext_reader.WavBextReader.umid
|
[smpte_330m2011]:https://wavinfo.readthedocs.io/en/latest/scopes/bext.html#wavinfo.wave_bext_reader.WavBextReader.umid
|
||||||
[adm]:https://wavinfo.readthedocs.io/en/latest/scopes/adm.html
|
[adm]:https://wavinfo.readthedocs.io/en/latest/scopes/adm.html
|
||||||
[ebu3285s6]:https://wavinfo.readthedocs.io/en/latest/scopes/dolby.html
|
[ebu3285s6]:https://wavinfo.readthedocs.io/en/latest/scopes/dolby.html
|
||||||
|
|||||||
14
docs/source/scopes/smpl.rst
Normal file
14
docs/source/scopes/smpl.rst
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
Sampler Metadata
|
||||||
|
=================
|
||||||
|
|
||||||
|
Class Reference
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: wavinfo.wave_smpl_reader
|
||||||
|
|
||||||
|
.. autoclass:: wavinfo.wave_smpl_reader.WavSmplReader
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. autoclass:: wavinfo.wave_smpl_reader.WaveSmplLoop
|
||||||
|
:members:
|
||||||
@@ -6,7 +6,7 @@ build-backend = "poetry.core.masonry.api"
|
|||||||
|
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "wavinfo"
|
name = "wavinfo"
|
||||||
version = "3.0.1"
|
version = "3.1.0"
|
||||||
description = "Probe WAVE files for all metadata"
|
description = "Probe WAVE files for all metadata"
|
||||||
authors = ["Jamie Hardt <jamiehardt@me.com>"]
|
authors = ["Jamie Hardt <jamiehardt@me.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
BIN
tests/test_files/smpl/alarm_citizen_loop1_udata.wav
Normal file
BIN
tests/test_files/smpl/alarm_citizen_loop1_udata.wav
Normal file
Binary file not shown.
@@ -15,7 +15,7 @@ class MyJSONEncoder(json.JSONEncoder):
|
|||||||
if isinstance(o, Enum):
|
if isinstance(o, Enum):
|
||||||
return o._name_
|
return o._name_
|
||||||
elif isinstance(o, bytes):
|
elif isinstance(o, bytes):
|
||||||
return b64encode(o).decode('ascii')
|
return 'base64:' + b64encode(o).decode('ascii')
|
||||||
else:
|
else:
|
||||||
return super().default(o)
|
return super().default(o)
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class WaveSmplLoop(NamedTuple):
|
|||||||
loop_type: int
|
loop_type: int
|
||||||
start: int
|
start: int
|
||||||
end: int
|
end: int
|
||||||
fraction: int
|
detune_cents: int
|
||||||
repetition_count: int
|
repetition_count: int
|
||||||
|
|
||||||
def loop_type_desc(self):
|
def loop_type_desc(self):
|
||||||
@@ -30,7 +30,7 @@ class WaveSmplLoop(NamedTuple):
|
|||||||
'loop_type_description': self.loop_type_desc(),
|
'loop_type_description': self.loop_type_desc(),
|
||||||
'start_samples': self.start,
|
'start_samples': self.start,
|
||||||
'end_samples': self.end,
|
'end_samples': self.end,
|
||||||
'fraction': self.fraction,
|
'detune_cents': self.detune_cents,
|
||||||
'repetition_count': self.repetition_count,
|
'repetition_count': self.repetition_count,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,8 +42,8 @@ class WavSmplReader:
|
|||||||
Read sampler metadata from smpl chunk.
|
Read sampler metadata from smpl chunk.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
header_field_fmt = "<IIIIIIbbbbII"
|
header_field_fmt = "<IIIIiIbbbbII"
|
||||||
loop_field_fmt = "<IIIIII"
|
loop_field_fmt = "<IIIIiI"
|
||||||
header_size = struct.calcsize(header_field_fmt)
|
header_size = struct.calcsize(header_field_fmt)
|
||||||
loop_size = struct.calcsize(loop_field_fmt)
|
loop_size = struct.calcsize(loop_field_fmt)
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ class WavSmplReader:
|
|||||||
self.midi_note: int = unpacked_data[3]
|
self.midi_note: int = unpacked_data[3]
|
||||||
|
|
||||||
#: The number of semitones above the MIDI note the loops tune for.
|
#: The number of semitones above the MIDI note the loops tune for.
|
||||||
self.midi_pitch_fraction_semis: int = unpacked_data[4]
|
self.midi_pitch_detune_cents: int = unpacked_data[4]
|
||||||
|
|
||||||
#: SMPTE timecode format, one of (0, 24, 25, 29, 30)
|
#: SMPTE timecode format, one of (0, 24, 25, 29, 30)
|
||||||
self.smpte_format: int = unpacked_data[5]
|
self.smpte_format: int = unpacked_data[5]
|
||||||
@@ -89,13 +89,16 @@ class WavSmplReader:
|
|||||||
loop_type=unpacked_loop[1],
|
loop_type=unpacked_loop[1],
|
||||||
start=unpacked_loop[2],
|
start=unpacked_loop[2],
|
||||||
end=unpacked_loop[3],
|
end=unpacked_loop[3],
|
||||||
fraction=unpacked_loop[4],
|
detune_cents=unpacked_loop[4],
|
||||||
repetition_count=unpacked_loop[5]))
|
repetition_count=unpacked_loop[5]))
|
||||||
|
|
||||||
#: Sampler-specific user data.
|
#: Sampler-specific user data.
|
||||||
self.sampler_udata: bytes = smpl_data[
|
self.sampler_udata: bytes | None = None
|
||||||
header_size + loop_size * loop_count:
|
|
||||||
header_size + loop_size * loop_count + sampler_udata_length]
|
if sampler_udata_length > 0:
|
||||||
|
self.sampler_udata = smpl_data[
|
||||||
|
header_size + loop_size * loop_count:
|
||||||
|
header_size + loop_size * loop_count + sampler_udata_length]
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return {
|
return {
|
||||||
@@ -103,7 +106,7 @@ class WavSmplReader:
|
|||||||
'product': self.product,
|
'product': self.product,
|
||||||
'sample_period_ns': self.sample_period_ns,
|
'sample_period_ns': self.sample_period_ns,
|
||||||
'midi_note': self.midi_note,
|
'midi_note': self.midi_note,
|
||||||
'midi_pitch_fraction_semis': self.midi_pitch_fraction_semis,
|
'midi_pitch_detune_cents': self.midi_pitch_detune_cents,
|
||||||
'smpte_format': self.smpte_format,
|
'smpte_format': self.smpte_format,
|
||||||
'smpte_offset': "%02i:%02i:%02i:%02i" % self.smpte_offset,
|
'smpte_offset': "%02i:%02i:%02i:%02i" % self.smpte_offset,
|
||||||
'loops': [x.to_dict() for x in self.sample_loops],
|
'loops': [x.to_dict() for x in self.sample_loops],
|
||||||
|
|||||||
Reference in New Issue
Block a user