Composer #1 (2025)

Nova Noise Composer //)()()()()()()()()()()()()()()()()()()()()()()( //////////////////////////////////////////////// ///////////composer version V1/2025///////////// //////////////////////////////////////////////// //Created by Mikael Madsen // MikaelMadsen.com// //////////////////////////////////////////////// //)()()()()()()()()()()()()()()()()()()()()()()( // // // // // // //)()()()()()()()()()()()()()()()()()()()()()()( let squares = []; // Array to store square objects let canvasSize = 800; // Canvas size for the sketch let numSquares = 12; // Number of basic squares to create let soundOn = true; // Flag to control if sounds should be played let isRunning = true; // Flag to control the execution of the sketch let phase = “intro”; // Initial phase of the composer let startTime; // Start time for the composer let audioCtx; // Audio context for managing sounds let totalDuration = 600000; // Total duration of the composition (10 minutes) let collisions = []; // Array to store collision effects let draggedSquare = null; // Store the currently dragged square let playedPairs = new Set(); // Set to track played pairs of squares that collided function setup() { // Set up the canvas, audio context, and initial conditions createCanvas(canvasSize, canvasSize + 30); userStartAudio(); // Ensure the audio context starts audioCtx = getAudioContext(); // Initialize the audio context startTime = millis(); // Capture the start time for timing calculations // Create basic squares for (let i = 0; i < numSquares; i++) { squares.push(new Square(i)); // Add a square to the array } // Add machine squares with different properties for (let i = 0; i < 3; i++) { squares.push(new MachineSquare(i + numSquares)); // Add machine squares } // Add 3 AudioSquares with colors and .wav links squares.push(new AudioSquare(numSquares + 3, color(0, 0, 255), "https://example.com/blue.wav")); squares.push(new AudioSquare(numSquares + 4, color(255, 255, 0), "https://example.com/yellow.wav")); squares.push(new AudioSquare(numSquares + 5, color(0, 200, 0), "https://example.com/green.wav")); } function draw() { if (!isRunning) return; // If the sketch is not running, skip the draw cycle let elapsed = millis() - startTime; // Calculate the elapsed time if (elapsed > totalDuration) noLoop(); // Stop the sketch after the total duration // Phase transition based on elapsed time if (elapsed < 120000) phase = "intro"; else if (elapsed < 300000) phase = "build"; else if (elapsed < 480000) phase = "chaos"; else if (elapsed < 590000) phase = "fadeout"; else phase = "end"; // Render the background and strokes based on the phase background(0); stroke(phase === "chaos" ? 255 : 150); strokeWeight(5); noFill(); rect(0, 0, canvasSize, canvasSize); // Update and display each square for (let sq of squares) { if (!sq.beingDragged) sq.update(); // Update square's position sq.display(); // Display the square } playedPairs.clear(); // Clear the set of played pairs for collision detection // Collision detection and sound triggering for (let i = 0; i < squares.length; i++) { for (let j = i + 1; j < squares.length; j++) { if (squares[i].collidesWith(squares[j])) { // Check for collision between squares let pairKey = `${i}-${j}`; if (!playedPairs.has(pairKey)) { // If the pair hasn't collided before if (soundOn) { squares[i].playHarshNoise(); // Play noise for both squares squares[j].playHarshNoise(); } collisions.push(new CollisionEffect( (squares[i].x + squares[j].x) / 2, (squares[i].y + squares[j].y) / 2 )); playedPairs.add(pairKey); // Add this pair to the set of played pairs } } } } // Update and display collision effects for (let i = collisions.length - 1; i >= 0; i–) { collisions[i].update(); collisions[i].display(); if (collisions[i].finished) collisions.splice(i, 1); // Remove finished collisions } drawTimeline(elapsed); // Draw the timeline of the composition } // MOUSE CONTROL BEGINS function mousePressed() { // Check if a square is clicked and start dragging it for (let sq of squares) { if (sq.contains(mouseX, mouseY)) { // If the mouse is over a square draggedSquare = sq; sq.beingDragged = true; break; } } } function mouseDragged() { // Drag the square with the mouse if (draggedSquare) { draggedSquare.x = constrain(mouseX – draggedSquare.size / 2, 0, canvasSize – draggedSquare.size); draggedSquare.y = constrain(mouseY – draggedSquare.size / 2, 0, canvasSize – draggedSquare.size); } } function mouseReleased() { // Stop dragging the square when the mouse is released if (draggedSquare) { draggedSquare.beingDragged = false; draggedSquare = null; } } // MOUSE CONTROL ENDS // Function to draw the timeline of the composition function drawTimeline(elapsed) { let progress = map(elapsed, 0, totalDuration, 0, canvasSize); // Map the elapsed time to the canvas size noStroke(); fill(0); rect(0, canvasSize, progress, 30); // Draw the timeline progress bar noFill(); stroke(100); rect(0, canvasSize, canvasSize, 30); // Draw the timeline background } // Collision effect class to visualize collisions between squares class CollisionEffect { constructor(x, y) { this.x = x; // X position of the collision this.y = y; // Y position of the collision this.life = 15; // Lifespan of the collision effect this.finished = false; // Flag to mark when the effect is finished } update() { this.life–; // Decrease the life of the collision effect if (this.life <= 0) this.finished = true; // Mark the effect as finished when life reaches zero } display() { noFill(); stroke(255, 0, 0, map(this.life, 0, 15, 0, 255)); // Red color with fading effect strokeWeight(2); ellipse(this.x, this.y, 20 + (15 - this.life) * 2); // Draw the collision effect as a growing circle } } // Class for basic squares that move around and bounce off edges class Square { constructor(id) { this.id = id; // Unique ID for the square this.size = 50; // Size of the square this.x = random(canvasSize - this.size); // Random X position this.y = random(canvasSize - this.size); // Random Y position this.vx = random(-1.5, 1.5); // Random X velocity this.vy = random(-1.5, 1.5); // Random Y velocity this.color = color(random(255), random(255), random(255)); // Random color for the square this.noiseType = random(["white", "pink", "brown"]); // Random noise type this.beingDragged = false; // Flag to indicate if the square is being dragged } // Update the square's position based on its velocity update() { this.x += this.vx; this.y += this.vy; // Bounce off edges of the canvas if (this.x <= 0 || this.x + this.size >= canvasSize) this.vx *= -1; if (this.y <= 0 || this.y + this.size >= canvasSize) this.vy *= -1; } // Display the square display() { fill(this.color); // Fill with the square’s color noStroke(); rect(this.x, this.y, this.size, this.size); // Draw the square } // Check if a point is inside the square contains(mx, my) { return mx >= this.x && mx <= this.x + this.size && my >= this.y && my <= this.y + this.size; } // Check if this square collides with another square collidesWith(other) { return !(this.x + this.size < other.x || this.x > other.x + other.size || this.y + this.size < other.y || this.y > other.y + other.size); } // Play noise when the square collides playHarshNoise() { let dur = 0.1; // Duration of the noise let gainNode = audioCtx.createGain(); // Create a gain node to control volume gainNode.gain.value = 0.25; // Set volume gainNode.connect(audioCtx.destination); // Connect to the audio context output let bufferSize = 2 * audioCtx.sampleRate * dur; // Size of the noise buffer let noiseBuffer = audioCtx.createBuffer(1, bufferSize, audioCtx.sampleRate); // Create the noise buffer let output = noiseBuffer.getChannelData(0); // Generate noise based on the noise type for (let i = 0; i < bufferSize; i++) { if (this.noiseType === "white") output[i] = Math.random() * 2 - 1; // White noise else if (this.noiseType === "pink") output[i] = (output[i - 1] || 0) * 0.9 + (Math.random() * 2 - 1) * 0.1; // Pink noise else if (this.noiseType === "brown") output[i] = (output[i - 1] || 0) + (Math.random() * 2 - 1) * 0.02; // Brown noise } // Play the noise let noise = audioCtx.createBufferSource(); noise.buffer = noiseBuffer; noise.connect(gainNode); noise.start(); } } // Class for machine squares with specific behavior class MachineSquare extends Square { constructor(id) { super(id); // Call the constructor of the parent class this.color = color(255, 0, 0); // Set the color of the machine square to red this.noiseType = "machine"; // Set noise type to "machine" } // Display the machine square with a border display() { fill(this.color); stroke(0); strokeWeight(2); rect(this.x, this.y, this.size, this.size); } // Play harsh noise using an oscillator playHarshNoise() { let osc = audioCtx.createOscillator(); // Create an oscillator osc.type = "sawtooth"; // Set oscillator type to sawtooth wave osc.frequency.setValueAtTime(random(40, 70), audioCtx.currentTime); // Set a random frequency let gainNode = audioCtx.createGain(); // Create a gain node gainNode.gain.setValueAtTime(0.65, audioCtx.currentTime); // Set the gain (volume) osc.connect(gainNode); // Connect oscillator to gain node gainNode.connect(audioCtx.destination); // Connect to the output osc.start(); // Start the oscillator osc.stop(audioCtx.currentTime + 0.2); // Stop after 0.2 seconds } } // Class for audio squares with custom sound and colors class AudioSquare extends Square { constructor(id, col, url) { super(id); // Call the constructor of the parent class this.color = col; // Set the color of the audio square this.audioURL = url; // Set the audio URL for the square this.soundBuffer = null; // Initialize the sound buffer as null this.loadSound(); // Load the sound file } // Load the sound file asynchronously loadSound() { if (this.audioURL) { fetch(this.audioURL) // Fetch the audio file .then(res => res.arrayBuffer()) // Get the audio as an array buffer .then(buf => audioCtx.decodeAudioData(buf)) // Decode the audio data .then(decoded => this.soundBuffer = decoded) // Store the decoded audio .catch(err => console.error(“Audio load error:”, err)); // Handle errors } } // Play the sound when the square is triggered playHarshNoise() { if (this.soundBuffer) { let source = audioCtx.createBufferSource(); // Create a buffer source source.buffer = this.soundBuffer; // Set the sound buffer source.connect(audioCtx.destination); // Connect to the audio context output source.start(); // Play the sound } } } //)()()()()()()()()()()()()()()()()()()()()()()( //)()()()()()()()()()()()()()()()()()()()()()()( //)()()()()()()()()()()()()()()()()()()()()()()( //)()()()()()()()()()()()()()()()()()()()()()()( //)()()()()()()()()()()()()()()()()()()()()()()( //)()()()()()()()()()()()()()()()()()()()()()()( //)()()()()()()()()()()()()()()()()()()()()()()( //)()()()()()()()()()()()()()()()()()()()()()()( //)()()()()()()()()()()()()()()()()()()()()()()( //)()()()()()()()()()()()()()()()()()()()()()()(

Leave a comment