Skip to content

Instantly share code, notes, and snippets.

@ynkdir
Last active July 28, 2024 06:48
Show Gist options
  • Save ynkdir/35231576fbedbcd83ad2d6cfa94bf6b2 to your computer and use it in GitHub Desktop.
Save ynkdir/35231576fbedbcd83ad2d6cfa94bf6b2 to your computer and use it in GitHub Desktop.
pmf file
# --------------------------------------
# TOA .pmf file
# --------------------------------------
# uint8_t id[32]; // "N-8000 message\r\n"
# uint8_t name[128]; // Name encoded in Shift-JIS
# uint8_t created[32]; // Created date: yyyy-mm-dd HH:MM:SS
# uint32_t audio16k_size; // Size of 16k audio data
# uint32_t audio8k_size; // Size of 8k audio data
# uint32_t checksum; // Sum of audio16k_data and audio8k_data
# uint8_t audio16k_data[audio16k_size]; // Audio data: G722 16k sample rate 16bit mono
# uint8_t audio8k_data[audio8k_size]; // Audio data: G722 8k sample rate 16bit mono
# --------------------------------------
# Endianness is big endian
# --------------------------------------
# /// script
# dependencies = ["av"]
# ///
import io
import sys
import winsound
from dataclasses import dataclass
from typing import BinaryIO
import av
@dataclass
class Pmf:
id: str
name: str
created: str
audio16k_size: int
audio8k_size: int
checksum: int
audio16k_data: bytes
audio8k_data: bytes
class PmfReader:
def read(self, file: BinaryIO) -> Pmf:
id = file.read(32).rstrip(b"\x00\x0a\x0d").decode("ascii")
name = file.read(128).rstrip(b"\x00").decode("cp932")
created = file.read(32).rstrip(b"\x00").decode("ascii")
audio16k_size = int.from_bytes(file.read(4))
audio8k_size = int.from_bytes(file.read(4))
checksum = int.from_bytes(file.read(4))
audio16k_data = file.read(audio16k_size)
audio8k_data = file.read(audio8k_size)
assert file.read(1) == b""
assert len(audio16k_data) == audio16k_size
assert len(audio8k_data) == audio8k_size
assert checksum == sum(audio16k_data) + sum(audio8k_data)
return Pmf(id, name, created, audio16k_size, audio8k_size, checksum, audio16k_data, audio8k_data)
def convert_g722_to_wav(in_g722: BinaryIO, g722_sample_rate: int, out_wav: BinaryIO, wav_sample_rate: int) -> None:
with (
av.open(in_g722, "r", "g722") as in_container,
av.open(out_wav, "w", "wav") as out_container,
):
in_stream = in_container.streams.audio[0]
out_stream = out_container.add_stream("pcm_s16le", sample_rate=wav_sample_rate, layout="mono")
for frame in in_container.decode(in_stream):
frame.sample_rate = g722_sample_rate
for packet in out_stream.encode(frame):
out_container.mux(packet)
def main() -> None:
with open(sys.argv[1], "rb") as f:
pmf = PmfReader().read(f)
print(f"id: {pmf.id}")
print(f"name: {pmf.name}")
print(f"audio16k_size: {pmf.audio16k_size}")
print(f"audio8k_size: {pmf.audio8k_size}")
print(f"checksum: {pmf.checksum:08X}")
print("play audio16k...")
in_g722 = io.BytesIO(pmf.audio16k_data)
out_wav = io.BytesIO()
convert_g722_to_wav(in_g722, 16000, out_wav, 16000)
winsound.PlaySound(out_wav.getvalue(), winsound.SND_MEMORY)
print("play audio8k...")
in_g722 = io.BytesIO(pmf.audio8k_data)
out_wav = io.BytesIO()
convert_g722_to_wav(in_g722, 8000, out_wav, 8000)
winsound.PlaySound(out_wav.getvalue(), winsound.SND_MEMORY)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment