Skip to content

Commit

Permalink
Automatic convertion of wav to adpcm for samples
Browse files Browse the repository at this point in the history
Update vromtool.py and soundtool.py to generate automatically
convert input .wav samples into ADPCM-A or ADPCM-B, based on
the playback speed

This removes to need to convert sound asserts with adpcmtool
prior to use them in vromtool or soundtool.
  • Loading branch information
dciabrin committed Sep 28, 2024
1 parent d687bea commit 3b4a4eb
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 4 deletions.
18 changes: 17 additions & 1 deletion tools/soundtool.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import yaml
import glob
import os
import wave

VERBOSE = False

Expand Down Expand Up @@ -55,6 +56,17 @@ def merge_descs(a,b):
bdata = b[btype]
return {atype: {**adata, **bdata}}

def detect_adpcm_type(f):
try:
w = wave.open(f, 'rb')
assert w.getnchannels() == 1, "Only mono WAV file is supported"
assert w.getsampwidth() == 2, "Only 16bits per sample is supported"
assert w.getcomptype() == 'NONE', "Only uncompressed WAV file is supported"
wavrate = w.getframerate()
return "adpcm_a" if wavrate == 18500 else "adpcm_b"
except Exception as e:
return ""

existing_data = {}
for i in desc:
itemtype = list(i.keys())[0]
Expand All @@ -68,7 +80,7 @@ def merge_descs(a,b):
for f in glob.iglob(e, recursive=True):
if not os.path.isfile(f):
continue
if os.path.splitext(f)[1] not in ('.fur', '.adpcma', '.adpcmb'):
if os.path.splitext(f)[1] not in ('.fur', '.adpcma', '.adpcmb', '.wav'):
continue
if f.endswith('fur'):
# Furnace module
Expand All @@ -83,6 +95,10 @@ def merge_descs(a,b):
sfxtype = 'adpcm_a'
elif '.adpcmb' in f.lower():
sfxtype = 'adpcm_b'
elif '.wav' in f.lower():
sfxtype = detect_adpcm_type(f)
if not sfxtype:
error("could not autodetect a suitable ADPCM format for '%s'"%f)
uri='file://'+f
name=mkid(os.path.splitext(os.path.basename(f))[0])
sfx = {'name': name, 'uri': uri}
Expand Down
27 changes: 24 additions & 3 deletions tools/vromtool.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
import sys
from dataclasses import dataclass
from furtool import samples_from_module
from struct import pack, unpack, unpack_from
import wave
from adpcmtool import ym2610_adpcma, ym2610_adpcmb

import yaml

Expand Down Expand Up @@ -126,6 +129,22 @@ def generate_asm_defines(smp, f):
print(" .equ %s_STOP_MSB, 0x%02x" % (s.name.upper(), s.stop_msb), file=f)
print("", file=f)

def convert_to_adpcm(sample, path):
codec = {"adpcm_a": ym2610_adpcma,
"adpcm_b": ym2610_adpcmb}[sample.__class__.__name__]()
try:
w = wave.open(path, 'rb')
assert w.getnchannels() == 1, "Only mono WAV file is supported"
assert w.getsampwidth() == 2, "Only 16bits per sample is supported"
assert w.getcomptype() == 'NONE', "Only uncompressed WAV file is supported"
nframes = w.getnframes()
data = w.readframes(nframes)
except Exception as e:
error("Could not convert sample '%s' to ADPCM: %s"%(path, e))
pcm16s = unpack('<%dh' % (len(data)>>1), data)
adpcms=codec.encode(pcm16s)
adpcms_packed = [(adpcms[i] << 4 | adpcms[i+1]) for i in range(0, len(adpcms), 2)]
return bytes(adpcms_packed)

def load_sample_map_file(filenames):
# Allow multiple documents in the yaml file
Expand Down Expand Up @@ -163,9 +182,11 @@ def load_sample_map_file(filenames):
# load sample's data
if sample.uri.startswith("file://"):
samplepath = sample.uri[7:]
with open(samplepath, "rb") as f:
dbg(" %s: loaded from '%s'" % (sample.name, samplepath))
sample.data = f.read()
if samplepath.endswith(".wav"):
sample.data = convert_to_adpcm(sample, samplepath)
else:
with open(samplepath, "rb") as f:
sample.data = data
elif sample.uri.startswith("data:;base64,"):
dbg(" %s: encoded in '%s'" % (sample.name, mapfile))
sample.data = base64.b64decode(sample.uri[13:])
Expand Down

0 comments on commit 3b4a4eb

Please sign in to comment.