10 Commits

Author SHA1 Message Date
Jamie Hardt
299f79aeb3 README update and stubbed out docs. 2024-11-25 11:05:32 -08:00
Jamie Hardt
a46590df29 Merge branch 'master' of https://github.com/iluvcapra/wavinfo into feature-smpl 2024-11-25 10:52:46 -08:00
Jamie Hardt
c6f66b2d6e Changes to fix docs 2024-11-25 10:48:58 -08:00
Jamie Hardt
b8617a35e2 Fixing doc dependencies I think 2024-11-25 10:41:05 -08:00
Jamie Hardt
8a755b4466 Merge pull request #35 from iluvcapra/maint-poetry
Change build system to Poetry
2024-11-25 10:37:05 -08:00
Jamie Hardt
f0353abd4e Added a test case for sampler udata
And a little marker for base64
2024-11-24 15:10:31 -08:00
Jamie Hardt
6304666d11 Autopep8 2024-11-24 15:05:19 -08:00
Jamie Hardt
d2b0c68dd2 Made sampler udata field nullable 2024-11-24 15:04:00 -08:00
Jamie Hardt
a0a9c38cb4 Assuming detune is signed 2024-11-24 14:37:18 -08:00
Jamie Hardt
f68eea4cd9 Rectified some terminology 2024-11-24 14:35:56 -08:00
8 changed files with 37 additions and 17 deletions

View File

@@ -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

View File

@@ -12,24 +12,25 @@
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import importlib
import os
import sys
sys.path.insert(0, os.path.abspath('../..'))
sys.path.insert(0, os.path.abspath("../../.."))
print(sys.path)
import wavinfo
import importlib
# -- Project information -----------------------------------------------------
project = u'wavinfo'
copyright = u'2018-2023, Jamie Hardt'
copyright = u'2018-2024, Jamie Hardt'
author = u'Jamie Hardt'
# The short X.Y version
version = wavinfo.__short_version__
version = "3.1"
# The full version, including alpha/beta/rc tags
release = wavinfo.__version__
release = importlib.metadata.version("wavinfo")
# -- General configuration ---------------------------------------------------

View File

@@ -39,7 +39,7 @@ iXML
Sampler Metadata
----------------
* `RecordingBlogs.com — Sample chunk (of a Wave file)<https://www.recordingblogs.com/wiki/sample-chunk-of-a-wave-file>`_
* `RecordingBlogs.com — Sample chunk (of a Wave file) <https://www.recordingblogs.com/wiki/sample-chunk-of-a-wave-file>`_
RIFF Metadata
-------------

View 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:

View File

@@ -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 <jamiehardt@me.com>"]
license = "MIT"

Binary file not shown.

View File

@@ -15,7 +15,7 @@ class MyJSONEncoder(json.JSONEncoder):
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)

View File

@@ -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 @@ class WaveSmplLoop(NamedTuple):
'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 @@ class WavSmplReader:
Read sampler metadata from smpl chunk.
"""
header_field_fmt = "<IIIIIIbbbbII"
loop_field_fmt = "<IIIIII"
header_field_fmt = "<IIIIiIbbbbII"
loop_field_fmt = "<IIIIiI"
header_size = struct.calcsize(header_field_fmt)
loop_size = struct.calcsize(loop_field_fmt)
@@ -65,7 +65,7 @@ class WavSmplReader:
self.midi_note: int = unpacked_data[3]
#: 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)
self.smpte_format: int = unpacked_data[5]
@@ -89,13 +89,16 @@ class WavSmplReader:
loop_type=unpacked_loop[1],
start=unpacked_loop[2],
end=unpacked_loop[3],
fraction=unpacked_loop[4],
detune_cents=unpacked_loop[4],
repetition_count=unpacked_loop[5]))
#: Sampler-specific user data.
self.sampler_udata: bytes = smpl_data[
header_size + loop_size * loop_count:
header_size + loop_size * loop_count + sampler_udata_length]
self.sampler_udata: bytes | None = None
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):
return {
@@ -103,7 +106,7 @@ class WavSmplReader:
'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],