diff --git a/index.html b/index.html index 6873402..b5e312e 100644 --- a/index.html +++ b/index.html @@ -307,41 +307,46 @@

Advanced Organ Composition with Markov Chains

// Function to create a rich organ sound with careful layering function createOrganOscillator(frequency, startTime, duration, isChord = false) { - const osc1 = audioContext.createOscillator(); - const gainNode = audioContext.createGain(); - - // Create filters - const lowPassFilter = audioContext.createBiquadFilter(); - lowPassFilter.type = 'lowpass'; - lowPassFilter.frequency.setValueAtTime(2000, startTime); // Set cutoff frequency for low pass - - const highPassFilter = audioContext.createBiquadFilter(); - highPassFilter.type = 'highpass'; - highPassFilter.frequency.setValueAtTime(200, startTime); // Set cutoff frequency for high pass - - // Use a sine wave (for the smoothest organ-like sound) - osc1.type = 'sine'; - osc1.frequency.setValueAtTime(frequency, startTime); - - const targetGain = isChord ? 0.25 : 0.7; // Lowered gain for chords - gainNode.gain.setValueAtTime(0, startTime); - gainNode.gain.linearRampToValueAtTime(targetGain, startTime + 0.05); // Smooth attack - gainNode.gain.setValueAtTime(targetGain, startTime + duration - 0.05); // Sustain - gainNode.gain.linearRampToValueAtTime(0, startTime + duration); // Release - - // Connect nodes: Oscillator -> High-Pass -> Low-Pass -> Gain -> Destination - osc1.connect(highPassFilter); - highPassFilter.connect(lowPassFilter); - lowPassFilter.connect(gainNode); - gainNode.connect(audioContext.destination); - - osc1.start(startTime); - osc1.stop(startTime + duration); - - oscillators.push({ osc1, gainNode }); - logToConsole(`Organ ${isChord ? "Chord" : "Melody"} played: ${frequency.toFixed(2)}Hz`, 'info'); -} - + const osc1 = audioContext.createOscillator(); + const osc2 = audioContext.createOscillator(); + const gainNode = audioContext.createGain(); + + // Create filters + const lowPassFilter = audioContext.createBiquadFilter(); + lowPassFilter.type = 'lowpass'; + lowPassFilter.frequency.setValueAtTime(4000, startTime); // Increased cutoff frequency for a brighter sound + + const highPassFilter = audioContext.createBiquadFilter(); + highPassFilter.type = 'highpass'; + highPassFilter.frequency.setValueAtTime(200, startTime); // Keep high pass frequency + + // Use a sine wave and triangle wave for richness + osc1.type = 'sine'; + osc2.type = 'triangle'; // Slightly detuned for a richer sound + osc1.frequency.setValueAtTime(frequency, startTime); + osc2.frequency.setValueAtTime(frequency * 1.005, startTime); // Small detuning + + const targetGain = isChord ? 0.2 : 0.5; // Softer for chords + gainNode.gain.setValueAtTime(0, startTime); + gainNode.gain.linearRampToValueAtTime(targetGain, startTime + 0.1); // Smoother attack + gainNode.gain.setValueAtTime(targetGain, startTime + duration - 0.1); // Sustain + gainNode.gain.linearRampToValueAtTime(0, startTime + duration); // Smoother release + + // Connect nodes: Oscillators -> High-Pass -> Low-Pass -> Gain -> Destination + osc1.connect(highPassFilter); + osc2.connect(highPassFilter); + highPassFilter.connect(lowPassFilter); + lowPassFilter.connect(gainNode); + gainNode.connect(audioContext.destination); + + osc1.start(startTime); + osc2.start(startTime); + osc1.stop(startTime + duration); + osc2.stop(startTime + duration); + + oscillators.push({ osc1, osc2, gainNode }); + logToConsole(`Organ ${isChord ? "Chord" : "Melody"} played: ${frequency.toFixed(2)}Hz`, 'info'); + } function playChord(chord, currentTime) { logBox(`=== Chord Strategy: ${currentChordStrategy.toUpperCase()} ===`); @@ -401,8 +406,9 @@

Advanced Organ Composition with Markov Chains

clearTimeout(schedulerId); logToConsole('Music playback stopped.', 'warn'); - oscillators.forEach(({ osc1, gainNode }) => { + oscillators.forEach(({ osc1, osc2, gainNode }) => { osc1.stop(); + osc2.stop(); gainNode.disconnect(); }); oscillators = [];