Sound generators and happy little accidents
Writing generators of all kinds is fun. Even if the generator is not randomized, you still have many parameters to tweak — and many unexpected outcomes.
Once I needed to generate WAV files with dummy content and certain bitrate and duration.
The StackOverflow example by Joshua Beckford turned out to be the closest to what I needed.
I played around with the frequencies and accidentally created a bunch of something resembling obscure electronic music. Here are six hand-picked “tracks”, named with the help of colleagues. Listen at your own risk.
For the actual usage we went with “Malfunctioning Zipper”.
It doesn’t differ much from the original version, mostly deals with one frequency instead of two, but anyway — here’s its source, as a single executable class. If you have IntelliJ IDEA open, but don’t want to mess with new project, simply paste it into a Java scratch file (Ctrl-Alt-Shift-Insert)
and run.
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
// sound generation magic taken from https://stackoverflow.com/a/28934588/2807168
class WavGenerator {
public static void main(String[] args) throws IOException {
byte[] bytes = generate();
// places generated file in your project root
Files.write(Paths.get("./generated.wav"), bytes);
}
public static byte[] generate() throws IOException {
double seconds = 5;
// try tweaking these three values
double sampleRate = 44100.0;
double frequency = 3;
double scaleFactor = 32767.0;
double piF = Math.PI * frequency;
float[] buffer = new float[(int) (seconds * sampleRate)];
for (int sample = 0; sample < buffer.length; sample++) {
double time = sample / sampleRate;
buffer[sample] = (float) (Math.cos(piF * time));
}
final byte[] byteBuffer = new byte[buffer.length * 2];
int bufferIndex = 0;
for (int i = 0; i < byteBuffer.length; i++) {
final int x = (int) (buffer[bufferIndex++] * scaleFactor);
byteBuffer[i] = (byte) x;
i++;
byteBuffer[i] = (byte) (x >>> 8);
}
AudioFormat format = getAudioFormat((float) sampleRate);
ByteArrayInputStream bais = new ByteArrayInputStream(byteBuffer);
AudioInputStream ais = new AudioInputStream(bais, format, buffer.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, baos);
ais.close();
return baos.toByteArray();
}
private static AudioFormat getAudioFormat(float sampleRate) {
int bits = 8;
int channels = 1;
boolean signed = true;
boolean bigEndian = false;
return new AudioFormat(sampleRate, bits, channels, signed, bigEndian);
}
}