Hello Sunshine
Theresa's Sound World is powerful way of manipulating audio in the browser in a quick and friendly manner. Built on top of the Web Audio API, it uses a modular routing system allowing you to make sophisticated audio applications and instruments.
Download
Development Version (0.1.15, 64kb) Uncompressed with comments. Like Barry White.
Production Version (0.1.15, 16kb) Minified, tiny and fast. Like Prince.
Alternatively, if you are a Bower user, just type bower install tsw
at the command line.
Getting Started
Create your Sound World
To get started, download and include tsw.js in your HTML. From this point on all you need to do is use the variable "tsw" to make audio magic.
If you see "0.1.5" in your browser's JS console, then super. You're using the latest version and are ready to go.
Make some noise
Let's create a triangle wave oscillating at 300Hz.
var osc = tsw.osc(300, 'triangle'), volume = tsw.gain(0.5); // Half volume. tsw.connect(osc, volume, tsw.speakers); osc.start();
Press play to hear how it sounds.
Lovely. What if we want to control the pitch of the oscillator? Let's add a slider. Theresa's Sound World doesn't need jQuery to work, but let's use it here to make things nicer.
// HTML // JavaScript $('#slider').change(function () { osc.frequency($(this).val()); });
Press the play button above again, and use this slider to change the pitch.
Your very own html <theremin> element!
Reference
Ok, here's the definitive list of things you can do with Theresa's Sound World and how to do them.
Core
tsw.buffer()
Creates an audio buffer. If you want to play a sound from a file you have to load it into memory first. An audio buffer is how you store audio in memory. Create a buffer and assign your audio data to it.
var my_awful_singing = tsw.buffer(files.singing); // see tsw.load() for how to load files.singing.
tsw.bufferBox()
Creates a Buffer Box. A Buffer Box is a a little box that holds audio buffers in order to control them like like a little buffer record player.
var bufferBox = tsw.bufferBox(myBuffer); tsw.connect(bufferBox, tsw.speakers); bufferBox.play(); // start the buffer in the Buffer Box playing immediately.
tsw.compressor(settings)
Creates a compressor node. Takes an object with the following parameters. threshold, knee, ratio, attack, release.
var compressor = tsw.compressor({ threshold: -24, // dbs (min: -100, max: 0) knee: 30, // dbs (min: 0, max: 40) ratio: 12, // ratio (min: 1, max: 20) attack: 0.003, // seconds (min: 0, max: 1) release: 0.25 // seconds (min: 0, max: 1) });
tsw.connect(node1, node2, arrayOfNodes)
Connects two or more audio nodes together.
var osc = tsw.osc(), volume = tsw.gain(0.8); tsw.connect(osc, volume, tsw.speakers);
Numerous nodes can connect to and from other nodes by using an array.
// Connect 3 nodes to the speakers. tsw.connect([node1, node2, node3], tsw.speakers); // Connect oscillator to 3 nodes, then connect 3 nodes to speakers. tsw.connect(osc, [node1, node2, node3], tsw.speakers);
If you no longer need a connection, it's best to free up memory by using the disconnect method.
tsw.context()
An AudioContext is essentially your canvas for audio. All nodes you create exist within this context. Theresa's Sound World creates this automatically for you. You can access the context directly if you want to use native Web Audio API functions, or you can even replace the default context with your own for easy intergration to an existing project.
console.log(tsw.context()); // Outputs current AudioContext. var my_context = new AudioContext(); // Create new AudioContext. tsw.context(my_context); // Assign context to tsw. tsw.context().createGain(); // Use native Web Audio API function.
After assigning your own context, Theresa's Sound World will perform all of its operations using said context.
tsw.disconnect(node1, node2, ...node99)
Disconnects any number of nodes from all nodes attached to it.
tsw.connect(osc, gainNode, tsw.speakers); // Connect nodes. tsw.disconnect(gainNode); // Disconnect gainNode. // osc is no longer connected to speakers.
tsw.envelope(settings)
Creates an envelope which can control any audio node parameter.
Show example
tsw.filter(settings)
Creates a filter node, which removes certain frequencies from any audio passed through it.
Possible filter types: lowpass, highpass, bandpass, lowshelf, highshelf, peaking, notch, allpass.
var filter = tsw.filter({ type: 'lowpass', frequency: 200, Q: 1 });
Individual parameters can also be changed individually and at a scheduled time.
// Change the filter to a highpass filter immediately. filter.type('highpass'); // Change the filter frequency to 500Hz, 4 seconds from now. filter.frequency(500, tsw.now() + 4);
tsw.gain(number, time_to_change)
Creates an gain node. The value passed in multiplies the volume of the passed input signal.
Defaults to 1, which doesn't affect the signal.
var sine_wave = tsw.osc(), gain_node = tsw.gain(0.75); tsw.connect(sine_wave, gain_node, tsw.speakers); console.log(gain_node.gain()); // Outputs 0.75. gain_node.gain(0.5); // Changes gain to 0.5.
You can also specify when the level of gain will change.
gain_node.gain(0.2, tsw.now() + 5); // Change gain to 0.2, 5 seconds from now. gain_node.gain(0.8, tsw.now() + 7); // Change gain to 0.8, 2 seconds after that.
tsw.getUserAudio(stream)
Gets and audio stream from the user's microphone or line-in. Connect it like you would any other node.
tsw.getUserAudio(function (stream) { tsw.connect(stream, tsw.speakers); });
tsw.isBrowserSupported
Property to determine whether the Web Audio API is available.
if (tsw.isBrowserSupported) { console.log('All good! Pump up the volume, pump up the volume, pump pump pump.'); } else { console.log('Sorry, your browser doesn\'t support the Web Audio API.'); }
tsw.lfo(frequency)
Creates an LFO node to modulate an audio parameter of another node.
var osc = tsw.oscillator(), lfo = tsw.lfo(), vol = tsw.gain(); tsw.connect(osc, vol, tsw.speakers); osc.start(); lfo.modulate(vol.params.gain); // modulate the gain parameter of the vol node.
tsw.load(object, function)
Loads one or more audio files into memory and executes a callback function once complete.
tsw.load( { files: { talking: 'talking-sample.mp3', singing: 'my-lovely-singing.mp3' } }, function (files) { // Files have loaded successfully var bufferBox = tsw.buffer(files.talking); tsw.connect(bufferBox, tsw.speakers); bufferBox.play(); } );
tsw.noise()
Creates a source node of white noise.
var noise = tsw.noise(); tsw.connect(noise, tsw.speakers); noise.start(); console.log(noise.color()); // Outputs colour of noise. Only white supported at the moment.
tsw.now()
Returns the time in seconds since the audio context was activated.
Show example
tsw.oscillator(frequency, wave_type)
Creates an oscillator. Takes one of four values (sine, square, triangle, sawtooth).
var osc1 = tsw.oscillator(), // Creates a 440Hz sine wave. osc2 = tsw.oscillator(600, 'sawtooth'); // Creates a 600Hz sawtooth wave. tsw.connect([osc1, osc2], tsw.speakers); // Connect oscillators to speakers. osc1.start(); // Start sine wave. osc2.start(); // Start sawtooth wave. console.log(osc2.type()); // Outputs 'sawtooth'. osc2.type('triangle'); // Oscillator now produces a triangle wave.
Available methods
- frequency(number)
-
The frequency of the oscillator in Hertz.
var osc = tsw.oscillator(); osc.frequency(300); // Set the frequency to 300Hz. console.log(osc.frequency()); // Logs "300" out to the console.
- start(optional number)
- When to start the oscillator.
- stop(optional number)
- When to stop the oscillator.
Show example
tsw.panner(number)
Spreads an incoming audio signal over the left and right channels depending on the value specified.
var oscillator = tsw.osc(), panner = tsw.panner(-1); // Pan completely to the left. panner = tsw.panner(1); // Pan completely to the right. panner = tsw.panner(0.2); // Pan slightly to the right. panner = tsw.panner(0); // Pan to the center. tsw.connect(oscillator, panner, tsw.speakers); );
tsw.play(number)
Plays an audio buffer after a specified number of seconds. If nothing is passed, audio will play immediately.
tsw.load( { files: { talking: 'talking.mp3', singing: 'singing.mp3' } }, function (files) { tsw.play(files.talking, tsw.now() + 5); // Start playing after 5 seconds. tsw.play(files, tsw.now()); Play all files at the same time. } );
tsw.reverse(buffer)
Reverses an audio buffer in order for it to be played backwards.
var backward_buffer = tsw.reverse(buffer); tsw.play(backward_buffer);
tsw.speakers
The final output node. You'll need to connect to this to hear something.
tsw.connect(osc, gainNode, tsw.speakers); osc.start();
tsw.stop(number)
Stops an audio buffer or oscillator from playing after a specified number of seconds. If nothing is passed, audio will stop immediately.
sine.stop(); // Stop oscillator immediately. saw.stop(tsw.now() + 5); // Stop oscillator after 5 seconds.
tsw.wait()
Creates a node that will delay the incoming signal.
var osc = tsw.osc(), wait = tsw.wait(5); tsw.connect(osc, wait, tsw.speakers); // Start oscillator immediately, but won't be heard for 5 seconds. osc.start(tsw.now());
Effects
tsw.delay(settings)
Creates delay effect. Be just like the Edge! Or not. It takes an object with various settings:
- Delay Time
- Number of seconds to delay signal
- Feedback
- Volume of signal fed back into delay node.
- Effect Level
- Volume of effect mixed back into signal
// Create delay effect node. var delay = delay({ delayTime: 0.5, feedback: 0.2, level: 0.5 }); // Connect nodes. tsw.connect(madGuitarRiff, delay, tsw.speakers); tsw.play(madGuitarRiff)
tsw.distortion()
Creates distortion effect.
tsw.phaser()
Creates phaser node. Takes an object of settings:
- Rate
- The speed at which the filter changes.
- Depth
- The depth of the filter change.
- Resonance
- Strength of the filter effect.
var dr_phaser_crane = tsw.phaser({ rate: 8, depth: 0.5, feedback: 0.8 });
tsw.tremolo(settings)
Creates tremolo effect. Takes a settings object with the possible values:
var tremolo = tsw.tremolo({ rate: 5, depth: 0.4 });
Music
tsw.chord(string)
Returns an array of notes in any given chord.
Show example
tsw.flat(string)
Returns the note a semitone below that of the one passed.
tsw.flat('A4'); // returns 'G4' tsw.flat('D2'); // Returns 'C#2'
tsw.frequency(string)
Returns the frequency in Hz of a musical note passed by name.
Show example
tsw.note(number)
Returns individual note from frequency.
tsw.note(440); // returns 'A4'
tsw.scale(string, string)
Gets the musical scale of given note. Returns an array of notes as strings.
tsw.scale('A', 'minor'); // returns ["A", "B", "C", "D", "E", "F", "G", "A"]
tsw.sharp(string)
Returns the note a semitone above that of the one passed.
tsw.sharp('A4'); // returns 'B4' tsw.flat('D2'); // returns 'D#2'
MIDI
tsw.getUserMidi(success, failure)
Requests access from user to handle MIDI input/output. Takes a success and a failure callback.
tsw.getUserMidi(function () {
console.log('We have midi!');
}, function () {
console.log('Nope, no midi for you.')
});
tsw.isMidiSupported()
Returns a boolean dependant on whether the current browser supports the Web MIDI API.
tsw.isMidiSupported(); // returns true or false
tsw.midiNote(number || string)
Returns the note name or number from a either a MIDI message note number or note name string.
tsw.midiNote(24); // returns 'C2'
tsw.midiNote('A3'); // returns 45
tsw.getUserMidi(success, failure)
Requests access from user to handle MIDI input/output. Takes a success and a failure callback.
tsw.getUserMidi(function () { console.log('We have midi!'); }, function () { console.log('Nope, no midi for you.') });
tsw.isMidiSupported()
Returns a boolean dependant on whether the current browser supports the Web MIDI API.
tsw.isMidiSupported(); // returns true or false
tsw.midiNote(number || string)
Returns the note name or number from a either a MIDI message note number or note name string.
tsw.midiNote(24); // returns 'C2' tsw.midiNote('A3'); // returns 45
Examples
Here are a selection of things that have been made using Theresa's Sound World.
Sympathetic Synthesizer System Mk 1
A synth with feelings.
Beat Petite
A sample-free drum machine in the browser.
THX Deep Note
A recreation of the famous THX sound.
Copyright 2014 Stuart Memo