diff --git a/README.md b/README.md index b9269f9..90c99f2 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ it is not supported, please submit an issue! and Dolby Atmos `dbmd` metadata for re-renders and mixdowns. * Wave embedded [cue markers][cues], cue marker labels, notes and timed ranges as used 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 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 [cues]:https://wavinfo.readthedocs.io/en/latest/scopes/cue.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 [adm]:https://wavinfo.readthedocs.io/en/latest/scopes/adm.html [ebu3285s6]:https://wavinfo.readthedocs.io/en/latest/scopes/dolby.html diff --git a/docs/source/scopes/smpl.rst b/docs/source/scopes/smpl.rst new file mode 100644 index 0000000..bd533c7 --- /dev/null +++ b/docs/source/scopes/smpl.rst @@ -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: diff --git a/pyproject.toml b/pyproject.toml index 19e7eda..511e7ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "wavinfo" -version = "3.0.1" +version = "3.1.0" description = "Probe WAVE files for all metadata" authors = ["Jamie Hardt "] license = "MIT" diff --git a/tests/test_files/smpl/alarm_citizen_loop1_udata.wav b/tests/test_files/smpl/alarm_citizen_loop1_udata.wav new file mode 100644 index 0000000..08b0210 Binary files /dev/null and b/tests/test_files/smpl/alarm_citizen_loop1_udata.wav differ diff --git a/wavinfo/__main__.py b/wavinfo/__main__.py index 5d444b7..6f9b560 100644 --- a/wavinfo/__main__.py +++ b/wavinfo/__main__.py @@ -15,7 +15,7 @@ def default(self, o): if isinstance(o, Enum): return o._name_ elif isinstance(o, bytes): - return b64encode(o).decode('ascii') + return 'base64:' + b64encode(o).decode('ascii') else: return super().default(o) diff --git a/wavinfo/wave_smpl_reader.py b/wavinfo/wave_smpl_reader.py index 746689d..2dcecf6 100644 --- a/wavinfo/wave_smpl_reader.py +++ b/wavinfo/wave_smpl_reader.py @@ -8,7 +8,7 @@ class WaveSmplLoop(NamedTuple): loop_type: int start: int end: int - fraction: int + detune_cents: int repetition_count: int def loop_type_desc(self): @@ -30,7 +30,7 @@ def to_dict(self): 'loop_type_description': self.loop_type_desc(), 'start_samples': self.start, 'end_samples': self.end, - 'fraction': self.fraction, + 'detune_cents': self.detune_cents, 'repetition_count': self.repetition_count, } @@ -42,8 +42,8 @@ def __init__(self, smpl_data: bytes): Read sampler metadata from smpl chunk. """ - header_field_fmt = " 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): return { @@ -103,7 +106,7 @@ def to_dict(self): 'product': self.product, 'sample_period_ns': self.sample_period_ns, '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_offset': "%02i:%02i:%02i:%02i" % self.smpte_offset, 'loops': [x.to_dict() for x in self.sample_loops],