"use strict"; // // Voicegardens front-end Javascript // var archiveUrl = window.location + "add-to-archive"; var canvas; var microphone; var frameRate = 60; var mouseInitialDrag = false; var newSoundJustRecorded = false; var playButton; var recordButton; var recorder; var recording; var recordingTimeout = 30000; // 30 seconds (in milliseconds) var screenX; var screenY; var shapes = []; var stopButton; var color; var centerX; var centerY; var numberOfEdges; var radius; var angle; function record() { /** * Starting recording. **/ if (microphone.enabled) { setTimeout(recorder.record(recording), recordingTimeout); } } function stop() { /** * Stop recording a new recording. **/ if (recorder.recording) { recorder.stop(); newSoundJustRecorded = true; } } function play() { /** * Play the recording. **/ if (recording.isLoaded()) { recording.play(); } } function archive() { /** * Send the recording to the back-end. **/ var soundBlob = recording.getBlob(); var formData = new FormData(); var date = new Date(); var filename = date.getTime().toString() + ".wav"; formData.append("file", soundBlob, filename); var config = new Headers({ "Content-Type": "multipart/form-data" }); axios.post(archiveUrl, formData, config).catch(function(error) { console.log( "Upload failed!", "Received the following message:", error.response.data ); }); } function showArchive() { window.location.href = "/archive"; } function setupRecording() { /** * Setup logic for recording. **/ microphone = new p5.AudioIn(); microphone.start(); recorder = new p5.SoundRecorder(); recorder.setInput(microphone); recording = new p5.SoundFile(); recordButton = createButton("record"); recordButton.position(10, 5); recordButton.mousePressed(record); stopButton = createButton("stop"); stopButton.position(10, 40); stopButton.mousePressed(stop); playButton = createButton("play"); playButton.position(10, 75); playButton.mousePressed(play); playButton = createButton("archive"); playButton.position(10, 110); playButton.mousePressed(archive); playButton = createButton("view archive"); playButton.position(10, 145); playButton.mousePressed(showArchive); } function getSoundInfo() { /** * Retrieve sound information like pitch, amplitude, duration, etc. **/ amplitude = recording.getPeaks(); duration = recording.duration(); // pitch (frequency?) I think we can use fft.analyze() and then find the // highest value (0 -> 1024) that has a non-zero value this gives us the // highest frequency from the recording // https://p5js.org/reference/#/p5.FFT // https://p5js.org/reference/#/p5.FFT/analyze // nuance? // "I meant the amount of variation in the voice - i.e is it one single // monotone note or does it go up and down octaves or start soft and high and // become deep and guttural etc." // // How do to do this? Unsure ... } class GeneratedShape { constructor() { /** * Initialise the new shape. **/ this.xSpeed = 1.4; this.ySpeed = 1.6; this.xDirection = 1; this.yDirection = 1; this.synth = new p5.MonoSynth(); this.points = []; this.calculatePoints(); this.opacity = 0; this.colour = this.chooseColour(); } collide(shapes) { /** * Detect if the shape collides with another shape. **/ if (shapes.length === 1) { return false; } for (var shape of shapes) { if (this === shape) { continue; } var collision = collideCircleCircle( this.x, this.y, this.w, shape.x, shape.y, shape.w ); if (collision === true) { return true; } } return false; } sound() { /** * Play a sound after a collision is detected. **/ var notes = ["G2", "C3", "G3"]; var duration = 0.8; var time = 0; var velocity = 0.5; var index = floor(random(0, notes.length)); this.synth.play(notes[index], velocity, time, duration); } move() { /** * Move the shape around the canvas. **/ return; } fadein() { /** * Fade intro the shape. **/ if (this.opacity < 256) { let currentAlpha = this.colour._getAlpha(); this.colour.setAlpha(currentAlpha + random(0, 3)); } else { this.opacity = 256; } } chooseColour() { /** * Choose a colour for the shape. **/ let colourChoices = [ color("red"), color("blue"), color("green"), color("black"), color("white") ]; let index = floor(random(0, colourChoices.length)); let chosenColour = colourChoices[index]; chosenColour.setAlpha(this.opacity); return chosenColour; } display() { /** * Show the shape on the canvas. **/ // TODO: use getSoundInfo function to influence how shape is drawn if (this.opacity != 256) { this.fadein(); } fill(this.colour); this.createShape(); } calculatePoints() { /* Calculate the points of the shape */ for (var i = 0; i < numberOfEdges; i++) { var pointX = cos(angle * i) * radius + random(-77, 77); var pointY = sin(angle * i) * radius + random(-77, 77); var vector = createVector(pointX, pointY); this.points.push(vector); } } /*function for drawing the shape on the screen*/ createShape() { beginShape(); var lastItem = this.points.length - 1; curveVertex(this.points[lastItem].x, this.points[lastItem].y); for (var i = 0; i < this.points.length; i++) { curveVertex(this.points[i].x, this.points[i].y); } var firstItem = 0; curveVertex(this.points[firstItem].x, this.points[firstItem].y); endShape(CLOSE); } } function setup() { /** * The p5.js initial setup function. **/ createCanvas(windowWidth, windowHeight); frameRate(frameRate); setupRecording(); centerX = windowWidth / 2; centerY = windowHeight / 2; numberOfEdges = 5; angle = radians(180 / numberOfEdges); radius = random(30, 50); } function draw() { /** * The p5.js draw loop. **/ background("#69D2E7"); translate(centerX, centerX); blendMode(BLEND); smooth(); noStroke(); if (newSoundJustRecorded === true) { shapes.push(new GeneratedShape()); newSoundJustRecorded = false; } for (var shape of shapes) { shape.move(); shape.display(); if (shape.collide(shapes) === true) { shape.sound(); } } }