async function playFreddie() { let freddie = [[500, 1], [1000, 40], [1500, 5], [2000, 10], [2500, 10], [3000, 15], [3500, 10], [4000, 5]] // Play frequencies with their respective volumes, with vibrato depth of 2% and speed of 7 Hz await playFrequencies(500, 3, freddie, 2, 7, 0.2); } async function playFrequencies(baseFrequency, duration, frequencyVolumeArray, vibratoDepthPercent = 2, vibratoSpeed = 7, maxRandomness = 0.2) { // Create AudioContext let audioCtx = new (window.AudioContext || window.webkitAudioContext)(); let pitchRatio = baseFrequency / frequencyVolumeArray[0][0]; console.log('pitchRatio', pitchRatio) // Create a list of promises let promises = frequencyVolumeArray.map((freqVol) => { // Extract the frequency and volume let frequency = freqVol[0]; let volume = freqVol[1] / 100; // Convert percentage to decimal // Create oscillator for the frequency let oscillator = audioCtx.createOscillator(); oscillator.frequency.value = pitchRatio * frequency; // Set base frequency // Create a GainNode to control the volume let gainNode = audioCtx.createGain(); gainNode.gain.value = volume; // Create vibrato oscillator and gain let vibrato = audioCtx.createOscillator(); let vGain = audioCtx.createGain(); // Connect the vibrato to the main oscillator frequency vibrato.connect(vGain); vGain.connect(oscillator.frequency); // Connect the oscillator to the gain node oscillator.connect(gainNode); // Connect the gain node to the output destination gainNode.connect(audioCtx.destination); // Function to update vibrato parameters const updateVibrato = () => { let randomDepthVariation = (Math.random() * 2 - 1) * maxRandomness; // -5% to +5% let randomSpeedVariation = (Math.random() * 2 - 1) * maxRandomness; // -5% to +5% let adjustedVibratoDepth = vibratoDepthPercent * (1 + randomDepthVariation); let adjustedVibratoSpeed = vibratoSpeed * (1 + randomSpeedVariation); vibrato.frequency.value = adjustedVibratoSpeed; // Vibrato frequency vGain.gain.value = frequency * (adjustedVibratoDepth / 100); // Vibrato depth }; // Start the oscillator and vibrato oscillator.start(); vibrato.start(); // Update vibrato parameters every 0.5 seconds let vibratoInterval = setInterval(updateVibrato, 500); // Return a promise that resolves after the sound finishes return new Promise((resolve) => { setTimeout(function () { clearInterval(vibratoInterval); resolve(); }, duration * 1000); }); }); // Wait for all sounds to finish await Promise.all(promises); // Close the AudioContext audioCtx.close(); }