alisaing-square.html (Source)

<!DOCTYPE html>

<html>

<head>
  <link rel="stylesheet" href="/media/anwaldt/ANWALDT_2TB/WORK/TEACHING/Sound_Synthesis_Introduction/webaudio/webaudio_style.css">
</head>

<body>

  <p><p>Pitch (Hz): <span id="oscillatorA_text"></span></p>
  <input type="range" min="1" max="1000" value="440" class="slider"   step="0.01"  oninput="set_osc_freq(this.value)">
</p>


<p><p>Output Gain: <span id="gain_text"></span></p>
<input type="range" min="0" max="1" value="0" class="slider"   step="0.01"  oninput="set_gain(this.value)">
</p>

<div class="scope-box">

  Time Domain:
  <p>
    <canvas id='scope' width=400 height=200></canvas>
  </p>

  Frequency Domain:
  <p>
    <canvas id='spectrum' width=400 height=200></canvas>
  </p>

</div>

</body>



<script type="text/javascript">

var context     = new AudioContext();

var analyser    = context.createAnalyser();
var outgain     = context.createGain();

const oscillators = [];
const gains       = [];

for(let i = 0; i < 20; i++)
{

  const osc           = context.createOscillator();
  osc.frequency.value = 110 * 2 ** i;
  osc.type            = 'sine';
  osc.start();

  const gain      = context.createGain();
  gain.gain.value = 1;

  osc.connect(gain);
  gain.connect(outgain);

  oscillators.push(osc);
  gains.push(gain);


}

set_osc_freq(440);
set_max_harmonics(20);

outgain.connect(analyser);

analyser.connect(context.destination);



analyser.fftSize = 2048;

analyser.minDecibels = -120;
analyser.maxDecibels = 0;

var scopeCtx = document.getElementById('scope').getContext('2d');
var spectCtx = document.getElementById('spectrum').getContext('2d');

draw();

function draw()
{
  drawSpectrum(analyser, spectCtx);
  drawScope(analyser, scopeCtx);
  requestAnimationFrame(draw);
}

function drawSpectrum(analyser, ctx)
{
  var width    = ctx.canvas.width;
  var height   = ctx.canvas.height;
  var freqData = new Uint8Array(analyser.frequencyBinCount);
  var scaling  = height / 256;

  analyser.getByteFrequencyData(freqData);

  ctx.fillStyle = 'rgba(256, 256, 256, 0.1)';
  ctx.fillRect(0, 0, width, height);

  ctx.lineWidth   = 2;
  ctx.strokeStyle = 'rgb(0, 0, 0)';
  ctx.beginPath();

  for (var x = 0; x < width; x++)
  ctx.lineTo(x, height - freqData[x] * scaling);

  ctx.stroke();
}

function drawScope(analyser, ctx) {
  var width    = ctx.canvas.width;
  var height     = ctx.canvas.height;
  var timeData   = new Uint8Array(analyser.frequencyBinCount);
  var scaling    = height / 256;
  var risingEdge = 0;
  var edgeThreshold = 0.1;

  analyser.getByteTimeDomainData(timeData);

  ctx.fillStyle = 'rgba(256, 256, 256, 0.1)';
  ctx.fillRect(0, 0, width, height);

  ctx.lineWidth = 2;
  ctx.strokeStyle = 'rgb(0, 0, 0)';
  ctx.beginPath();

  // No buffer overrun protection
  while (timeData[risingEdge++] - 128 > 0 && risingEdge <= width);
  if (risingEdge >= width) risingEdge = 0;

  while (timeData[risingEdge++] - 128 < edgeThreshold && risingEdge <= width);
  if (risingEdge >= width) risingEdge = 0;

  for (var x = risingEdge; x < timeData.length && x - risingEdge < width; x++)
  ctx.lineTo(x - risingEdge, height - timeData[x] * scaling);

  ctx.stroke();
}


function set_osc_freq(y)
{
  for(let i = 0; i < 20; i++)
  {
    let f = y*(i+1);
    oscillators[i].frequency.setValueAtTime(f, context.currentTime);
    var output = document.getElementById('oscillatorA_text');
      output.innerHTML = y;
  }
}


function set_max_harmonics(y)
{


  for(let i = 0; i < 20; i++)
  {

    let g = (2.0 / 3.1415) * ((-1.0)**(i+1.0)) * (1.0/(i+1.0));

    if(i<y)
    {
      // gains[i].gain.value = 0.5 / g;
      gains[i].gain.setTargetAtTime(g, context.currentTime + 0.1, 0.1);
    }
    else
    gains[i].gain.setTargetAtTime(0, context.currentTime + 0.1, 0.1);
    {
    }

  }

  var output = document.getElementById('max_text');
  output.innerHTML = y;

}

function set_gain(y)
{
  outgain.gain.value = y
}


</script>

</html>


Contents © Henrik von Coler 2021 - Contact