Skip to content

Commit 46fcad7

Browse files
committed
Rework documentation, copy bits from char2mozzi
1 parent 04c828d commit 46fcad7

1 file changed

Lines changed: 52 additions & 24 deletions

File tree

extras/python/wav2mozzi.py

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,62 @@
11
#!/usr/bin/env python3
22

3-
##@file wav2mozzi.py
4-
# @ingroup util
5-
# A script for converting .WAV sound files to wavetables for Mozzi.
6-
#
7-
# Usage:
8-
# >>>wav2mozzi.py infile [-t tablename] [-o outfile] [--output-bits {8,16}] [--no-symmetric-output]
9-
#
3+
"""
4+
A script for converting .WAV files to wavetables for Mozzi.
5+
6+
Reads bitness, sample format, and sample rate from the WAV header automatically.
7+
Supports 8-bit unsigned, 16-bit signed, 24-bit signed, and 32-bit signed PCM WAV files,
8+
as well as 32-bit IEEE float WAV files (samples in -1.0..1.0 range).
9+
10+
All sample data is converted to signed 8-bit or 16-bit values.
11+
Output values are centered around 0 and can be negated without overflow.
12+
If audio file is stereo, only the first channel is used.
13+
14+
Requires Python 3.9+, no dependencies.
15+
16+
NOTE: Using Audacity to prepare sound files:
17+
18+
For generated waveforms like sine or sawtooth, set the project
19+
rate to the size of the wavetable you wish to create, which must
20+
be a power of two (eg. 8192), and set the selection format
21+
(beneath the editing window) to samples. Then you can generate
22+
and save 1 second of a waveform and it will fit your table
23+
length.
24+
25+
For a recorded audio sample, set the project rate to the
26+
MOZZI_AUDIO_RATE (16384 in the current version).
27+
Samples can be any length, as long as they fit in your Arduino.
28+
29+
Save the file by "Export" -> "Export as WAV".
30+
To keep all the details, choose "32-bit float" encoding.
31+
Other supported encodings are 8,16,24,32-bit PCM.
32+
33+
Now use the file you just exported, as the "infile" to convert.
34+
35+
36+
Author: Paul Melnikov, 2026-04
37+
"""
38+
39+
# Usage:
40+
# >>>wav2mozzi.py infile [-t tablename] [-o outfile] [-b {8,16}] [--no-symmetric-output]
1041
# Arguments:
11-
# * infile The .WAV file to convert.
42+
# * infile The .WAV file to convert.
1243
# * -t tablename (Optional) The name to give the table. Default: uppercase input filename.
13-
# * -o outfile (Optional) The output .h file. Default: derived from input filename.
14-
# * -b, --output-bits
44+
# * -o outfile (Optional) The output .h file. Default: derived from input filename.
45+
# * -b, --output-bits
1546
# (Optional) Output sample size in bits. Allowed: 8 or 16. Default: 8.
16-
# * --symmetric-output, --no-symmetric-output
47+
# * --symmetric-output, --no-symmetric-output
1748
# (Optional) Generate symmetric signed output range. Default: enabled.
18-
#
19-
# Reads bitness, sample format, and sample rate from the WAV header automatically.
20-
# Supports 8-bit unsigned, 16-bit signed, 24-bit signed, and 32-bit signed PCM WAV files,
21-
# as well as 32-bit IEEE float WAV files (samples in -1.0..1.0 range).
22-
#
23-
# All sample data is converted to signed 8-bit (-128..127).
24-
# If audio is stereo, only the first channel is used.
25-
#
26-
# Requires Python 3.9+, no dependencies.
27-
#
49+
2850

2951
import sys, os, textwrap, struct, random, argparse, re
3052

3153
def read_wav(infile):
3254
"""Read a WAV file, supporting both PCM and IEEE float formats.
33-
Returns (nchannels, sample_size, samplerate, nframes, raw_bytes, is_float)."""
55+
Returns (nchannels, sample_size, samplerate, nframes, raw_bytes, is_float).
56+
57+
Technically, python has built-in "wave" library for this,
58+
but it doesn't support IEEE floats, so decode headers manually.
59+
"""
3460
with open(infile, 'rb') as f:
3561
# Parse RIFF header
3662
riff = f.read(4)
@@ -201,14 +227,16 @@ def wav2mozzi(infile, outfile, tablename, output_bytes=1, symmetric_output=True)
201227

202228

203229
if __name__ == "__main__":
204-
parser = argparse.ArgumentParser(description='Convert a .WAV file to a Mozzi wavetable header.')
230+
parser = argparse.ArgumentParser(
231+
description=__doc__,
232+
formatter_class=argparse.RawDescriptionHelpFormatter)
205233
parser.add_argument('infile', help='Input .WAV file')
206234
parser.add_argument('-t', '--tablename', help='Table name for the generated header (default: uppercase input filename)')
207235
parser.add_argument('-o', '--outfile', help='Output .h file (default: derived from input filename)')
208236
parser.add_argument('-b', '--output-bits', type=int, choices=(8, 16), default=8,
209237
help='Output sample size in bits (default: 8)')
210238
parser.add_argument('-s', '--symmetric-output', action=argparse.BooleanOptionalAction, default=True,
211-
help='Generate a symmetric signed output range (default: enabled)')
239+
help='Generate symmetric signed output range (default: enabled)')
212240
args = parser.parse_args()
213241

214242
infile = os.path.expanduser(args.infile)

0 commit comments

Comments
 (0)