Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
alastair committed Apr 18, 2011
0 parents commit d516cc2
Show file tree
Hide file tree
Showing 14 changed files with 12,251 additions and 0 deletions.
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
HTML5 Synth
-----------
Alastair Porter

For Firefox 4 only

Introduction
------------
This is a synthsiser written in javascript / HTML5.
It provides 2 modes of synthesis (Additive and FM) and gives 4
oscillators/envelope combinations (called 'operators') for use in
synthesising sounds.
Any of the 4 operators can be used for additive synthesis. FM synthesis
uses the first 2 operators as the modulator and carrier, respectively.

To create a new voice, hit the Add new voice button. Click Edit voice to
change the settings. You can give it a new name and choose the synthesis
mode.
Choose a frequency multiplier for each operator, or turn it off using
the button in the top corner. Use the View envelope link to change
the ADSR envelope associated with the operator.

To save your voices to the browser you are using, click the Save synth button.
The synth will automatically restore these voices when you visit the page
again, or you can use the Load synth button to load them manually.
The Reset button will throw away all of your changes and load the default
voices.
Use the Panic button to turn off a runaway synth.

There is a display of the signal waveform and the signal spectrum. Click
Show display to toggle this.

Use the keyboard at the bottom of the screen to play the synth. Middle C is
marked.
76 changes: 76 additions & 0 deletions additive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// additive.js
// Simple additive synthesis
//
// MUMT307 project - Alastair Porter

// Adapted from the dsp.js ADSR envelope
// Only generates attack, decay and sustain
// Release happens when the mouse is unclicked
function getEnvelopeLevel(samplesProcessed, startLevel, attackLevel, attack, decay, sustainLevel) {
var amplitude = 0;

if (samplesProcessed <= attack ) {
amplitude = 0 + (attackLevel - startLevel) * ((samplesProcessed - 0) / (attack - 0));
} else if (samplesProcessed > attack && samplesProcessed <= decay ) {
amplitude = 1 + (sustainLevel - attackLevel) * ((samplesProcessed - attack) / (decay - attack));
} else if (samplesProcessed > decay) {
amplitude = sustainLevel;
}

return amplitude;
};

function makeAdditive(frequency, bufferSize) {
var sampleRate = 44100;

var ops = [];
var envs = [];
for (var i = 0; i < 4; i++) {
var oper = $('#operator'+(i+1)).operator();
var env = $('#envelope'+(i+1)).envelope();
// Only take the operator and envelope if it's active
if (oper.getSettings().active) {
ops.push(oper.getSettings().freqRatio);
envs.push(env.getSettings());
}
}

if (ops.length > 0) {
startSample = currentSoundSample;
var ret = new Float32Array(bufferSize);

// Make Envelope
e = envs[0];
startLevel = e.l1/100.0;
attackLevel = e.l2/100.0;
sustainLevel = e.l3/100.0;
attack = e.r1 * (sampleRate / 1000);
decay = e.r2 * (sampleRate / 1000);

var k = 2* Math.PI * frequency * ops[0] / sampleRate;
for (var i=0, size=ret.length; i<size; i++) {
amp = getEnvelopeLevel(currentSoundSample, startLevel, attackLevel, attack, decay, sustainLevel);
ret[i] = Math.sin(k * currentSoundSample++) * amp;
}

if (ops.length > 1) {
for (var o = 1; o < ops.length; o++) {
var sample = startSample
var k = 2* Math.PI * frequency * ops[o] / sampleRate;
e = envs[o];
startLevel = e.l1/100.0;
attackLevel = e.l2/100.0;
sustainLevel = e.l3/100.0;
attack = e.r1 * (sampleRate / 1000);
decay = e.r2 * (sampleRate / 1000);
for (var i=0, size=ret.length; i<size; i++) {
amp = getEnvelopeLevel(sample, startLevel, attackLevel, attack, decay, sustainLevel);
ret[i] += Math.sin(k * sample++) * amp;
}
}
}

return ret;
}
return [];
}
248 changes: 248 additions & 0 deletions audio.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
<!DOCTYPE html>
<html>
<head>
<title>
Synth
</title>
<script src="jquery-1.5.1.js" type="text/javascript"></script>
<script src="jquery.json-2.2.min.js" type="text/javascript"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<script type="text/javascript" src="synth.js"></script>
<script type="text/javascript" src="voice.js"></script>
<script type="text/javascript" src="operator.js"></script>
<script type="text/javascript" src="envelope.js"></script>
<script type="text/javascript" src="ui.js"></script>
<script type="text/javascript" src="dsp.js"></script>
<script type="text/javascript" src="fm.js"></script>
<script type="text/javascript" src="additive.js"></script>
<script type="text/javascript" src="defaults.js"></script>

<div id="messages"></div>

<div id="synth" style="border: thin solid black;">
Voices: <button id="addvoice">Add new voice</button>
<table id="voicetable">
<tbody></tbody>
</table>
<button id="savelocal">Save synth to PC</button><button id="loadlocal">Load synth from PC</button>
<!-- <button id="savefile">Save synth to file</button><button id="loadfile">Load synth from file</button> -->
<button id="resetsynth">Reset to defaults</button><button id="panic">Panic</button>
</div>

<div id="voice" style="display:none;">
<table>
<tr>
<td colspan="2">Voice name: <input type="text" id="voicename">
<button id="doneeditingvoice">Done editing</button></td>
<td rowspan="3" valign="top"><!--Algorithm choice:<br>-->
<input type="hidden" id="voicealgorithm">
Synth type<br>
<label for="synthmodefm">FM</label><input type="radio" name="synthmode" value="fm" id="synthmodefm">
<label for="synthmodeadd">Additive</label><input type="radio" name="synthmode" value="add" id="synthmodeadd"><br>
In FM, operator 1 acts as the modulator and operator 2 as the carrier.
</td>
</tr><tr>
<td>
<div id="operator1" class="operator">
<div class="title">
<span style="display:table-cell; float:none; text-align: left;">Operator 1</span>
<span style="display:table-cell; text-align: right;"><button id="o1power">Turn off</button></span>
</div>
<div class="swap"><a id="swapo1" href="">View Envelope</a></div>
Freq ratio <input type="text" id="freqratio1">
</div>
<div id="envelope1" class="envelope">
<div class="title">Envelope 1</div>
<div class="swap"><a id="swape1" href="">View Operator</a></div>

<canvas id="envelope1canvas" width="210" height="100"></canvas>

<table>
<tr>
<th>L1:</th><td><input type="text" size="2" id="e1l1" class="e1val"></td>
<th>L2:</th><td><input type="text" size="2" id="e1l2" class="e1val"></td>
<th>L3:</th><td><input type="text" size="2" id="e1l3" class="e1val"></td>
<th>L4:</th><td><input type="text" size="2" id="e1l4" class="e1val"></td>
</tr><tr>
<th>R1:</th><td><input type="text" size="2" id="e1r1" class="e1val"></td>
<th>R2:</th><td><input type="text" size="2" id="e1r2" class="e1val"></td>
<th></th><td><input type="hidden" size="2" id="e1r3" class="e1val"></td>
<th>R4:</th><td><input type="text" size="2" id="e1r4" class="e1val"></td>
</tr>
</table>
</div>
</td>
<td>
<div id="operator2" class="operator">
<div class="title">
<span style="display:table-cell; float:none; text-align: left;">Operator 2</span>
<span style="display:table-cell; text-align: right;"><button id="o2power">Turn off</button></span>
</div>
<div class="swap"><a id="swapo2" href="">View Envelope</a></div>
Freq ratio <input type="text" id="freqratio2">
</div>
<div id="envelope2" class="envelope">
<div class="title">Envelope 2</div>
<div class="swap"><a id="swape2" href="">View Operator</a></div>

<canvas id="envelope2canvas" width="210" height="100"></canvas>

<table>
<tr>
<th>L1:</th><td><input type="text" size="2" id="e2l1" class="e2val"></td>
<th>L2:</th><td><input type="text" size="2" id="e2l2" class="e2val"></td>
<th>L3:</th><td><input type="text" size="2" id="e2l3" class="e2val"></td>
<th>L4:</th><td><input type="text" size="2" id="e2l4" class="e2val"></td>
</tr><tr>
<th>R1:</th><td><input type="text" size="2" id="e2r1" class="e2val"></td>
<th>R2:</th><td><input type="text" size="2" id="e2r2" class="e2val"></td>
<th></th><td><input type="hidden" size="2" id="e2r3" class="e2val"></td>
<th>R4:</th><td><input type="text" size="2" id="e2r4" class="e2val"></td>
</tr>
</table>

</div>
</td></tr>
<tr><td>
<div id="operator3" class="operator">
<div class="title">
<span style="display:table-cell; float:none; text-align: left;">Operator 3</span>
<span style="display:table-cell; text-align: right;"><button id="o3power">Turn off</button></span>
</div>
<div class="swap"><a id="swapo3" href="">View Envelope</a></div>
Freq ratio <input type="text" id="freqratio3">
</div>
<div id="envelope3" class="envelope">
<div class="title">Envelope 3</div>
<div class="swap"><a id="swape3" href="">View Operator</a></div>

<canvas id="envelope3canvas" width="210" height="100"></canvas>

<table>
<tr>
<th>L1:</th><td><input type="text" size="2" id="e3l1" class="e3val"></td>
<th>L2:</th><td><input type="text" size="2" id="e3l2" class="e3val"></td>
<th>L3:</th><td><input type="text" size="2" id="e3l3" class="e3val"></td>
<th>L4:</th><td><input type="text" size="2" id="e3l4" class="e3val"></td>
</tr><tr>
<th>R1:</th><td><input type="text" size="2" id="e3r1" class="e3val"></td>
<th>R2:</th><td><input type="text" size="2" id="e3r2" class="e3val"></td>
<th></th><td><input type="hidden" size="2" id="e3r3" class="e3val"></td>
<th>R4:</th><td><input type="text" size="2" id="e3r4" class="e3val"></td>
</tr>
</table>
</div>

</td>
<td>

<div id="operator4" class="operator">
<div class="title">
<span style="display:table-cell; float:none; text-align: left;">Operator 4</span>
<span style="display:table-cell; text-align: right;"><button id="o4power">Turn off</button></span>
</div>
<div class="swap"><a id="swapo4" href="">View Envelope</a></div>
Freq ratio <input type="text" id="freqratio4">
</div>
<div id="envelope4" class="envelope">
<div class="title">Envelope 4</div>
<div class="swap"><a id="swape4" href="">View Operator</a></div>

<canvas id="envelope4canvas" width="210" height="100"></canvas>

<table>
<tr>
<th>L1:</th><td><input type="text" size="2" id="e4l1" class="e4val"></td>
<th>L2:</th><td><input type="text" size="2" id="e4l2" class="e4val"></td>
<th>L3:</th><td><input type="text" size="2" id="e4l3" class="e4val"></td>
<th>L4:</th><td><input type="text" size="2" id="e4l4" class="e4val"></td>
</tr><tr>
<th>R1:</th><td><input type="text" size="2" id="e4r1" class="e4val"></td>
<th>R2:</th><td><input type="text" size="2" id="e4r2" class="e4val"></td>
<th></th><td><input type="hidden" size="2" id="e4r3" class="e4val"></td>
<th>R4:</th><td><input type="text" size="2" id="e4r4" class="e4val"></td>
</tr>
</table>

</div>
</td>
</tr>
</table>
</div>
<p>
<button id="displaytoggle">Show display</button>
<div id="visualdisplay" style="display:none">
Waveform
<div><canvas id="signal" width="500px" height="200px"></canvas></div>
<p></p>
FFT
<div><canvas id="fft" width="500px" height="200px"></canvas></div>
</div>

<p>

<div id="keyboard" style="">
<div style="border-right: 1px solid black; height:202px; float:left;"></div>
<div class="whitekey key" id="m48"></div>
<div class="whitekey key" id="m50"></div>
<div class="whitekey key" id="m52"></div>
<div class="whitekey key" id="m53"></div>
<div class="whitekey key" id="m55"></div>
<div class="whitekey key" id="m57"></div>
<div class="whitekey key" id="m59"></div>
<div class="whitekey key" style="display:table !important;">
<span style="display:table-cell; vertical-align:bottom;" id="m60">&#10057;</span>
</div>
<div class="whitekey key" id="m62"></div>
<div class="whitekey key" id="m64"></div>
<div class="whitekey key" id="m65"></div>
<div class="whitekey key" id="m67"></div>
<div class="whitekey key" id="m69"></div>
<div class="whitekey key" id="m71"></div>
<div class="whitekey key" id="m72"></div>
<div class="whitekey key" id="m74"></div>
<div class="whitekey key" id="m76"></div>
<div class="whitekey key" id="m77"></div>
<div class="whitekey key" id="m79"></div>
<div class="whitekey key" id="m81"></div>
<div class="whitekey key" id="m83"></div>
<div class="whitekey key" id="m84"></div>

<!-- Note that the margins are stopping white notes
from being pressed next to black notes. -->
<div class="black">
<div class="blackcont">
<div class="blackkey key" id="m49"></div>
<div class="blackkey key" id="m51"></div>
</div>
<div class="blackcont">
<div class="blackkey key" id="m54"></div>
<div class="blackkey key" id="m56"></div>
<div class="blackkey key" id="m58"></div>
</div>
<div class="blackcont">
<div class="blackkey key" id="m61"></div>
<div class="blackkey key" id="m63"></div>
</div>
<div class="blackcont">
<div class="blackkey key" id="m66"></div>
<div class="blackkey key" id="m68"></div>
<div class="blackkey key" id="m70"></div>
</div>
<div class="blackcont">
<div class="blackkey key" id="m73"></div>
<div class="blackkey key" id="m75"></div>
</div>
<div class="blackcont">
<div class="blackkey key" id="m78"></div>
<div class="blackkey key" id="m80"></div>
<div class="blackkey key" id="m82"></div>
</div>
</div>
</div>


</body>
</html>
Loading

0 comments on commit d516cc2

Please sign in to comment.