A simple tone generator.
Wave is a simple text-based tone generator written in Rust. Note that this is mostly a toy project and an exercise, rather than a productive application.
First, build Wave by running cargo build --release
. Then, use target/release/wave
(or target/release/wave.exe
on Windows) for all further steps, wherever the command wave
is used.
To get started, it’s easiest to use one of the pre-made input files. To generate an output file ./the_licc.wav
from an input file ./input_files/the_licc.wss
, run
wave input_files/the_licc.wss the_licc.wav
Note that the second argument is optional. If it’s not supplied, the output file will be ./output.wav
by default.
To write custom input files, it’s easiest to copy one of the pre-made input files as a starting point. Note that the #header
and #data
section both need to be present and their order must not be switched. Also note that lines starting with //
are considered comments and will be ignored by the parser. Partial-line comments are not supported.
The header section consists of a list of key=value
fields. The following fields must be present in the header section:
sample_rate
: Number of samples per second, u16
.freq_a4
: Frequency of the reference pitch A4, f64
.subdivision
: Number of note subdivisions per bar (e.g. subdivision=8
-> 8 8th notes per bar), u8
.bpm
: Tempo of the track, in beats per minute, u16
.volume
: Volume of the resulting track, in [0, 1], f64
.The data section consists of an unlimited number of lines, where each line represents a “fragment”. A fragment is either a single note, chord (group of notes), or rest, to be played for a given number of subdivisions (note value). Each line has the following format:
<value> <note> [note] ... [note]
So, each line needs to start with a note value (e.g. 2, for a quarter note, if subdivision=8
in the header), followed by an arbitrary number of notes. Notes have the following format:
<note_name><octave>[detune]
Acceptable note names consist of a single upper-case letter, followed by a #
for sharps, or a b
for flats. Notes such as Cb
(=B) or E#
(=F) are allowed as well. The octave
value is a number referring to the octave in which to play a given note. E.g. A4
represents a note A
in the 4th octave. Finally, a detune
value can be used to detune a note by a given number of cents, upward or downward. For instance A4+20
is a note A4
, detuned by +20 cents, and C5-12
is a note C5
, detuned by -12 cents. Note that there is no white-space between note names, octaves and detune specifiers. Additional white-space between notes, or between the value and the first note is ignored.
To specify a rest, instead of a note or chord, use -
in place of the first note specifier. For instance, a line which represents a rest with a duration of 4 subdivisions would be denoted as
4 -
For examples of how to use rests, check input_files/the_licc_with_rests.wss
. For an example with detuned notes, check input_files/the_licc_detuned.wss
.