CS 145 Lecture 26 – Sound
Agenda
- digital music
- WAV format
- binary file I/O
- generate static
- generate pitches
- generate chords
Code
WavIO.java
import java.io.DataOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; public class WavIO { /** * The sampling frequency. */ public static final int SAMPLE_RATE = 22050; /** * Write the buffer containing audio samples to the specified file in WAV * format. * * @param buffer Audio samples. * @param path Path to destination WAV file. */ public static void write(short[] buffer, String path) { try { LEDataOutputStream out = new LEDataOutputStream(path); out.writeBytes("RIFF"); // 0-3 out.writeInt(36 + buffer.length * 2); // 4-7 out.writeBytes("WAVE"); // 8-11 out.writeBytes("fmt "); // 12-15 out.writeInt(16); // chunk size, 16-19 out.writeShort((short) 1); // pcm, 20-21 out.writeShort((short) 1); // nchannels, 22-23 out.writeInt(SAMPLE_RATE); // 24-27 out.writeInt(SAMPLE_RATE * 2); // 28-31 out.writeShort((short) 2); // 32-33 out.writeShort((short) 16); // 34-35 out.writeBytes("data"); // 36-39 out.writeInt(buffer.length * 1 * 16 / 8); // 40-43 out.write(buffer); out.close(); } catch (IOException e) { throw new RuntimeException(e); } } } /** * A class for writing primitives to a file in little endian format. */ class LEDataOutputStream { /** The underlying big endian file writer. */ private DataOutputStream out; /** A collection of bytes used for an endian switcharoo. */ private byte[] bytes; /** An endian switcher. */ private ByteBuffer buffer; /** * Create a new little endian file writer for the specified file. * * @param file * Name of file to write. * * @throws FileNotFoundException */ public LEDataOutputStream(String file) throws FileNotFoundException { out = new DataOutputStream(new FileOutputStream(file)); bytes = new byte[4]; buffer = ByteBuffer.wrap(bytes); buffer.order(ByteOrder.LITTLE_ENDIAN); } /** * Write the specified String as a series of bytes. * * @param s * The String to write. * * @throws IOException */ public void writeBytes(String s) throws IOException { out.writeBytes(s); } /** * Write the specified int. * * @param value * Value to write. * * @throws IOException */ public void writeInt(int value) throws IOException { buffer.putInt(0, value); out.write(bytes, 0, 4); } /** * Writer the specified short. * * @param value * Value to write. * * @throws IOException */ public void writeShort(short value) throws IOException { buffer.putShort(0, value); out.write(bytes, 0, 2); } /** * Write the sequence of shorts. All values in the array are written in the * order in which they appear in the array. * * @param shorts * The sequence of values to write. * * @throws IOException */ public void write(short[] shorts) throws IOException { for (int i = 0; i < shorts.length; ++i) { writeShort(shorts[i]); } } /** * Close the file. * * @throws IOException */ public void close() throws IOException { out.close(); } }
Moosic.java
package prefinal; import java.util.Random; public class Moosic { public static void main(String[] args) { Random generator = new Random(); short[] a = getNote(440.0, 2); short[] c = getNote(523.25, 2); short[] song = merge(a, c); song = merge(song, song); WavIO.write(song, "/home/user/Desktop/song.wav"); } private static short[] merge(short[] a, short[] b) { short[] merged = new short[a.length + b.length]; System.arraycopy(a, 0, merged, 0, a.length); System.arraycopy(b, 0, merged, a.length, b.length); return merged; } private static short[] getNote(double frequency, double nseconds) { int nsamples = (int) (nseconds * WavIO.SAMPLE_RATE); short[] samples = new short[nsamples]; for (int i = 0; i < samples.length; ++i) { double t = i / (double) WavIO.SAMPLE_RATE; samples[i] = (short) (Short.MAX_VALUE * Math.cos(frequency * t * 2 * Math.PI)); } return samples; } }
Haiku
At first, plain beeps please.
But folks start to expect more.
You’ll have to beep songs.
But folks start to expect more.
You’ll have to beep songs.