Experimenting with sinusoids and overlaying waves

The WAVES experimentation box is a command line tool for generating and processing sinusoid audio data, immediately playing the result to your computer’s “audio out” line or saving it into WAV or CSV files. Harnessing your shell’s pipe and filter mechanism you can apply freely succeeding processing steps.

If you want to try out the examples below directly you can download either the waves.exe for Windows boxes, the waves.sh for Linux boxes or the waves.jar being platform independent. All of them versions require a Java 9 or upwards installed on your machine.

Given the below example (as well as the succeeding ones), the first line denotes on how to generate a WAV file and the second line denotes on how to directly play the result on your computer’s “audio out” device:

1
2
./waves.sh -c sine -l 5 -f 12540 -F wav -o sine_440Hz.wav
./waves.sh -c sine -l 5 -f 12540 -F line_out

The -c switch specifies the curve function to use. Possible values are sine, cosine, tangent, sawtooth, square or triangle (as of the CurveFunctionFunction class). The -lswitch specifies the length in seconds for the sound sample to be generated. The -f switch specifies the frequency in Herz (Hz) to use for the curve function. The -F switch specifies the format for the generated data. Possible values are wav, csv, svg as well as audio_out. Finally the -o switch specifies the output file (if applicable to the chosen format and if the output is not to be written to standard out). The -F switch as well as the -o switch must be omitted if the generated data is to be piped to a succeeding processing step.

Simple operations

The WAVES command line tool allows you to generate a variety of basic wave forms, such as sine, cosine, tangent, sawtooth, square or triangle:

Sine 440Hz

1
2
./waves.sh -c sine -l 5 -f 440 -F wav -o sine_440Hz.wav
./waves.sh -c sine -l 5 -f 440 -F line_out

Sine 880Hz

1
2
./waves.sh -c sine -l 5 -f 880 -F wav -o sine_880Hz.wav
./waves.sh -c sine -l 5 -f 880 -F line_out

Cosine 440Hz

1
2
./waves.sh -c cosine -l 5 -f 440 -F wav -o cosine_440Hz.wav
./waves.sh -c cosine -l 5 -f 440 -F line_out

Square 440Hz

1
2
./waves.sh -c square  -l 5 -f 440 -F wav -o square_440Hz.wav
./waves.sh -c square  -l 5 -f 440 -F line_out

Overlaying operations

Harnessing your shell’s pipeline mechanism, you can apply multiple operation on the generated waves by passing the output of one processing step as input to a succeeding processing step, which then applies modifications to its input just to produce once again output. That output again can be handled as input for a suceeding processing step or you can write it into a file or directly listen to it via your computer’s “line out” audio device.

Overlay sine 440Hz and 880Hz (multiply)

1
2
./waves.sh -c sine  -l 5 -f 440  | ./waves.sh -c sine -A multiply -f 880 -F wav -o sine_440Hz_multiply_sine880Hz.wav
./waves.sh -c sine  -l 5 -f 440  | ./waves.sh -c sine -A multiply -f 880 -F line_out

Overlay sine 440Hz and 880Hz (average)

1
2
./waves.sh -c sine  -l 5 -f 440  | ./waves.sh -c sine -A average -f 880 -F wav -o sine_440Hz_average_sine880Hz.wav
./waves.sh -c sine  -l 5 -f 440  | ./waves.sh -c sine -A average -f 880 -F line_out

Overlay a wave 440Hz with a square 880Hz (multiply)

1
2
./waves.sh -c sine  -l 5 -f 440  | ./waves.sh -c square -A multiply -f 880 -F wav -o sine_440Hz_multiply_square_880Hz.wav
./waves.sh -c sine  -l 5 -f 440  | ./waves.sh -c square -A multiply -f 880 -F line_out

Overlay a sine 440Hz with a square 880Hz (average)

1
2
./waves.sh -c sine  -l 5 -f 440  | ./waves.sh -c square -A average -f 880 -F wav -o sine_440Hz_average_square_880Hz.wav
./waves.sh -c sine  -l 5 -f 440  | ./waves.sh -c square -A average -f 880 -F line_out

Under the hood

The WAVES command line tool makes heavy use of the refcodes-audio artifact, which you may include in your own projects as follows:

1
2
3
4
5
6
7
8
9
<dependencies>
	...
	<dependency>
		<artifactId>refcodes-audio</artifactId>
		<groupId>org.refcodes</groupId>
		<version>2.0.5</version>
	</dependency>
	...
</dependencies>

Snippets of interest

Writing WAV files

1
2
3
4
5
6
7
8
9
10
11
import org.refcodes.audio.WavMonoSampleWriter;
// ...
double[] samples = ...;
File outFile = ...;
try (WavMonoSampleWriter theWriter = new WavMonoSampleWriter( outFile ) ) {
	theWriter.setSamplingRate( 44100 );
	for ( int i = 0; i < samples.length; i++ ) {
		aMonoWriter.writeNext( samples[i] );
	}
}
// ...

Playing audio

1
2
3
4
5
6
7
8
9
10
import org.refcodes.audio.LineOutMonoSampleWriter;
// ...
double[] samples = ...;
try (LineOutMonoSampleWriter theWriter = new LineOutMonoSampleWriter() ) {
	theWriter.setSamplingRate( 44100 );
	for ( int i = 0; i < samples.length; i++ ) {
		aMonoWriter.writeNext( samples[i] );
	}
}
// ...

Contribution guidelines

  • Find and fix bugs (curve functions)
  • Writing tests
  • Code review
  • Other guidelines

Who do I talk to?

  • Siegfried Steiner (steiner@refcodes.org)

Terms and conditions

The REFCODES.ORG group of artifacts is published under some open source licenses; covered by the refcodes-licensing (org.refcodes group) artifact - evident in each artifact in question as of the pom.xml dependency included in such artifact.