User:Thijshijsijsjss/Pen Plotting Panache/Volume Plotting

From XPUB & Lens-Based wiki
Example of volume plot

A modification of the code written at Zinecamp 2023 that captures audio and makes HPGL code for a volume plot. This version is more user friendly, with buttons for starting, restarting and copying, and with input length and title. Like this:

Screenshot of volume plotting web interface

Volume plotting is part of the SI23 webquilt! Find it here, or get your own with the code below:

<!DOCTYPE html>
<html>
<head>
<title>Noiseplotting!</title>
</head>
<body>

<h1></h1>
<p>This is a small script to capture a snippet of sound and convert it to a volume HPGL code for your penplotting pleasure. </p>
<p>Usage:
<ol>
  <li>Press the button saying 'Start recording'.</li>
  <li>Wait until recording is done, indicated by HPGL code appearing below.</li>
  <li>Copy the HPGL output if you want to use it.</li>
  <li>Press the button saying 'Rerecord' to repeat the process!!</li>
</ol>
</p>
<p>(Don't forget to allow the use of the microphone!)</p>

<p>Optionally, change the length of the recording: <input type="text" value="1000" id="nr_points_input"> points</p>
<p>Optionally, change the title of the recording: <input type="text" value="ZINECAMP RECORDING" id="title_input"></p>
<button onclick="start_recording()">Start recording</button>
<button onclick="copy_HPGL()">Copy HPGL output</button>
<button onclick="clear_HPGL()">Rerecord</button>

<p id="output-p">(HPGL code will appear here)</p>

</body>

<script>

var noise_values = [];
var nr_points = 1000;
console.log(nr_points);

var start = 0.0;
var end = 0.0;

function start_recording() {
  nr_points = document.getElementById("nr_points_input").value;
  if (start == 0.0) start = Date.now();

  // capturing template taken from https://stackoverflow.com/questions/52097840/how-to-overwrite-text-in-p-tag-using-javascript
  navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true
  })
    .then(function(stream) {
      const audioContext = new AudioContext();
      const analyser = audioContext.createAnalyser();
      const microphone = audioContext.createMediaStreamSource(stream);
      const scriptProcessor = audioContext.createScriptProcessor(2048, 1, 1);

      analyser.smoothingTimeConstant = 0.8;
      analyser.fftSize = 1024;

      microphone.connect(analyser);
      analyser.connect(scriptProcessor);
      scriptProcessor.connect(audioContext.destination);
      scriptProcessor.onaudioprocess = function() {
        const array = new Uint8Array(analyser.frequencyBinCount);
        analyser.getByteFrequencyData(array);
        const arraySum = array.reduce((a, value) => a + value, 0);
        const average = arraySum / array.length;
        noise_values.push(Math.round(average));
        if(noise_values.length >= nr_points) {create_output(); return;}
        console.log(Math.round(average));
        // colorPids(average);
      };
    })
    .catch(function(err) {
    console.error(err);
  });

}

function create_output() {

    console.log(noise_values[0]);

    var output = "IN;SC0,100,0,100;PU;DT$;SI0.2,1;";
  
    if (end == 0.0) end = Date.now();
    output += "PA2,90;LB" + document.getElementById("title_input").value + ":$;";
    output += "PA2,80;LBstart recording at: " + start + "$;";
    output += "PA2,70;LBend recording at:   " + end   + "$;";
    output += "PA2,60;LB(seconds after Unix Epoch)$;";

    for (var x = 0; x < nr_points; x += 1) {
      output += "PA"+ (x/10) + "," + noise_values[x] + ";PD;\n";
    }
    output += "PU;";
  //  console.log(output);

   document.getElementById("output-p").innerText = output;
   
  }

// inspired by https://www.w3schools.com/howto/howto_js_copy_clipboard.asp
function copy_HPGL () {
    // Get the text field
    var copyText = document.getElementById("output-p");
    // Copy the text inside the text field
    navigator.clipboard.writeText(copyText.innerText);
    // Alert the copied text
    alert("Copied the text: " + copyText.innerText);
  } 

function clear_HPGL() {
    noise_values = [];
    start = 0.0;
    end = 0.0;
    nr_points = document.getElementById("nr_points_input").value;
    document.getElementById("output-p").innerText = "";
  }

  </script>

</html>