Last active
July 28, 2024 06:48
-
-
Save ynkdir/35231576fbedbcd83ad2d6cfa94bf6b2 to your computer and use it in GitHub Desktop.
pmf file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -------------------------------------- | |
# 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