Source code for metamoth.mediainfo
"""Get media information from a WAV file.
The WAV file must be a PCM WAV file. The WAV file must have a fmt chunk
and a data chunk. The WAV file must have a samplerate and channels
information in the fmt chunk.
"""
from dataclasses import dataclass
from typing import BinaryIO, Tuple
from metamoth.chunks import Chunk
__all__ = [
"MediaInfo",
"get_media_info",
]
[docs]@dataclass
class MediaInfo:
"""Media information."""
samplerate_hz: int
"""Sample rate in Hz."""
duration_s: float
"""Duration in seconds."""
samples: int
"""Number of samples."""
channels: int
"""Number of channels."""
def read_samplerate_and_channels(
wav: BinaryIO,
fmt_chunk: Chunk,
) -> Tuple[int, int]:
"""Return the media information from the fmt chunk.
Parameters
----------
wav : BinaryIO
Open file object of the WAV file.
chunk : Chunk
The fmt chunk info.
Returns
-------
samplerate : int
channels: int
"""
wav.seek(fmt_chunk.position + 8)
wav.read(2) # audio format
channels = int.from_bytes(wav.read(2), "little")
samplerate = int.from_bytes(wav.read(4), "little")
return samplerate, channels
[docs]def get_media_info(wav: BinaryIO, chunk: Chunk) -> MediaInfo:
"""Return the media information from the WAV file.
Parameters
----------
wav : BinaryIO
Open file object of the WAV file.
chunk : Chunk
The RIFF chunk info, which is the root chunk. Should include
the fmt and data chunks as subchunks.
Returns
-------
MediaInfo
"""
fmt_chunk = chunk.subchunks[0]
data_chunk = chunk.subchunks[2]
samplerate, channels = read_samplerate_and_channels(wav, fmt_chunk)
samples = data_chunk.size // (channels * 2)
duration = samples / samplerate
return MediaInfo(
samplerate_hz=samplerate,
channels=channels,
samples=samples,
duration_s=duration,
)