2016-07-23 181 views
0

我是新來的網絡音頻API,並做了一個簡單的合成器來了解情況。麻煩是我的音頻在輸入很重的聲音後會變形很多。所以如果我通過它推動一大堆頻率會扭曲。任何熟悉API的人都可以快速瀏覽一下我的代碼,看看是否有任何重大錯誤/遺漏突出顯示?可以在Safari,Chrome和Firefox中重新創建問題。演示版本是HERE感謝您的任何幫助!網絡音頻API故障/失真問題

//start new audio session. 
var context = new (window.webkitAudioContext || window.AudioContext || window.mozAudioContext) 



function playSound(note) { 
    oscillator = context.createOscillator(); 

//create volume controller 
var gainNode = context.createGain(); 

//connect signal to audio output(speakers by default) 
oscillator.connect(gainNode); 
gainNode.connect(context.destination); 

//adjusts frequency played by 50%, 100% or 200% 
var octave = document.getElementById('octave').value; 

//sets oscillator frequency 
oscillator.frequency.value = frequencies[note] * octave; 

//oscillator wave type 
oscillator.type = document.getElementById('waveSelect').value; 


//initialize gain at 0 and ramp up to full volume very quikcly (prevents audible 'pop') 
gainNode.gain.value = 0 
var quickFadeIn = gainNode.gain.setTargetAtTime(1, context.currentTime, 0.1); 

//starts oscillator. Delayed start can be achieved by adding time(in secs) after currentTime 
oscillator.start(context.currentTime + .05); 

/** 
* AUDIO EFFECTS 
*/ 

function delayNode() { 
    //create delay 
    var delay = context.createDelay(); 
    delay.delayTime.value = .5; 

    //create gain 
    gainNode; 
    //gainNode.gain.value = 0.8; 
    quickFadeIn; 

    //create feedback loop 
    oscillator.connect(gainNode); 
    gainNode.connect(delay); 
    delay.connect(gainNode); 
    delay.connect(context.destination); 

    //decrease gain 
    quickFadeOut; 
} 

function distortionNode() { 
    var distortion = context.createWaveShaper(); 

//distortion curve taken from MDN which they in turn took from Stack Overflow 
    function makeDistortionCurve(amount) { 
     var k = typeof amount === 'number' ? amount : 50, 
     n_samples = 44100, 
     curve = new Float32Array(n_samples), 
     deg = Math.PI/90, 
     i = 0, 
     x; 
     for (; i < n_samples; ++i) { 
     x = i * 2/n_samples - 1; 
     curve[i] = (3 + k) * x * 20 * deg/(Math.PI + k * Math.abs(x)); 
     } 
     return curve; 
    }; 

    distortion.curve = makeDistortionCurve(500); 
    distortion.oversample = '4x'; 

    gainNode; 

    quickFadeIn; 

    oscillator.connect(gainNode); 
    gainNode.connect(distortion); 
    distortion.connect(context.destination); 

    //decrease gain 
    quickFadeOut; 
} 

if (document.getElementById('toggleDelay').value == 'true'){delayNode();} 
if (document.getElementById('toggleDistortion').value == 'true'){distortionNode();} 

//determines note duration 
var sustain = parseFloat(document.getElementById('sustain').value); 

//stops oscillator by exponentially ramping down sound over .015 seconds to avoid audible click 
var quickFadeOut = gainNode.gain.setTargetAtTime(0, context.currentTime + sustain, 0.0015); 

//change key color on keypress 

    //append the word "note" to the object.name note to identify the correct key div 
    var divId = "note" + String(note); 
    var element = document.getElementById(divId); 

    //change background color for durarion of note length 
    var currentColor = element.style.backgroundColor; 
    element.style.backgroundColor = '#3cf7ac'; 
    setTimeout(function() { 
    if (currentColor != 'rgb(60, 247, 172)') { 
     element.style.backgroundColor = currentColor 
    } 
}, 1000 * sustain); 



//for testing 
console.log('playSound Hz:' + frequencies[note] * octave + ' octave:' + octave + ' wave:' + oscillator.type + ' duration: ' + sustain + ' time:' + context.currentTime.toFixed(2)); 
} 

//controls 2nd keyboard. Same logic as playSound() 
function playSoundb(note) { 
oscillator = context.createOscillator(); 
var gainNode = context.createGain(); 
oscillator.connect(gainNode); 
gainNode.connect(context.destination); 



var octaveb = document.getElementById('octaveb').value; 
    oscillator.frequency.value = frequencies[note] * octaveb; 


oscillator.type = document.getElementById('waveSelectb').value; 

gainNode.gain.value = 0 
var quickFadeIn = gainNode.gain.setTargetAtTime(.75, context.currentTime, .1); 
oscillator.start(context.currentTime + .05); 

/** 
* AUDIO EFFECTS 
*/ 

function delayNode() { 
    var delay = context.createDelay(); 
    delay.delayTime.value = .5; 

    gainNode; 
    quickFadeIn; 

    //create feedback loop 
    oscillator.connect(gainNode); 
    gainNode.connect(delay); 
    delay.connect(gainNode); 
    delay.connect(context.destination); 

    //decrease gain 
    quickFadeOut; 
} 

function distortionNode() { 
    var distortion = context.createWaveShaper(); 

    function makeDistortionCurve(amount) { 
     var k = typeof amount === 'number' ? amount : 50, 
     n_samples = 44100, 
     curve = new Float32Array(n_samples), 
     deg = Math.PI/90, 
     i = 0, 
     x; 
     for (; i < n_samples; ++i) { 
     x = i * 2/n_samples - 1; 
     curve[i] = (3 + k) * x * 20 * deg/(Math.PI + k * Math.abs(x)); 
     } 
     return curve; 
    }; 

    distortion.curve = makeDistortionCurve(900); 
    distortion.oversample = '4x'; 

    gainNode; 
    quickFadeIn; 

    oscillator.connect(gainNode); 
    gainNode.connect(distortion); 
    distortion.connect(context.destination); 

    quickFadeOut; 
} 

if (document.getElementById('toggleDelayb').value == 'true'){delayNode();} 
if (document.getElementById('toggleDistortionb').value == 'true'){distortionNode();}   

var sustainb = parseFloat(document.getElementById('sustainb').value); 

var quickFadeOut = gainNode.gain.setTargetAtTime(0, context.currentTime + sustainb, 0.0015); 

//change key color on keypress 
var divId = "note" + String(note) + "b"; 
var element = document.getElementById(divId); 
var currentColor = element.style.backgroundColor; 
element.style.backgroundColor = '#3ce4f7'; 
setTimeout(function() { 
    if (currentColor != 'rgb(60, 228, 247)') { 
     element.style.backgroundColor = currentColor 
    } 
}, 1000 * sustainb); 

//for testing 
console.log('playSound*B* Hz:' + frequencies[note] * octave + ' octave:' + octave + ' wave:' + oscillator.type + ' duration: ' + sustain + ' time:' + context.currentTime); 

}

//reveals 2nd keyboard 
function displayKeyboard2(lowersynth, uppersynth) { 
    var bottom = document.getElementById(lowersynth); 
    var top = document.getElementById(uppersynth); 

if (bottom.style.display == 'block') { 
    bottom.style.display = 'none'; 
    top.style.marginTop = '150px'; 
} 

else { 
    bottom.style.display = 'block'; 
    top.style.marginTop = '0'; 
} 

}

//Frequencies in Hz of notes to be played. 
var frequencies = { 
    'C_1': 130.81, 
    'C#1': 139.00, 
    'D_1': 146.83, 
    'D#1': 156.00, 
    'E_1': 164.81, 
    'F_1': 174.61, 
    'F#1': 185.00, 
    'G_1': 196.00, 
    'G#1': 208.00, 
    'A_1': 220.00, 
    'A#1': 233.00, 
    'B_1': 246.94, 
    'C_2': 261.63, 
    'C#2': 277.00, 
    'D_2': 293.66, 
    'D#2': 311.00, 
    'E_2': 329.63, 
    'F_2': 349.23, 
    'F#2': 370.00, 
    'G_2': 392.00, 
    'G#2': 415.00, 
    'A_2': 440.00, 
    'A#2': 466.00, 
    'B_2': 493.88, 
    'C_3': 523.25, 
}; 

//triggers playSound() to create note 
document.getElementById('noteC_1').addEventListener(('click' || 'touchstart'),function() { playSound('C_1');}); 
document.getElementById('noteC#1').addEventListener(('click' || 'touchstart'),function() { playSound('C#1');}); 
document.getElementById('noteD_1').addEventListener(('click' || 'touchstart'),function() { playSound('D_1');}); 
document.getElementById('noteD#1').addEventListener(('click' || 'touchstart'),function() { playSound('D#1');}); 
document.getElementById('noteE_1').addEventListener(('click' || 'touchstart'),function() { playSound('E_1');}); 
document.getElementById('noteF_1').addEventListener(('click' || 'touchstart'),function() { playSound('F_1');}); 
document.getElementById('noteF#1').addEventListener(('click' || 'touchstart'),function() { playSound('F#1');}); 
document.getElementById('noteG_1').addEventListener(('click' || 'touchstart'),function() { playSound('G_1');}); 
document.getElementById('noteG#1').addEventListener(('click' || 'touchstart'),function() { playSound('G#1');}); 
document.getElementById('noteA_1').addEventListener(('click' || 'touchstart'),function() { playSound('A_1');}); 
document.getElementById('noteA#1').addEventListener(('click' || 'touchstart'),function() { playSound('A#1');}); 
document.getElementById('noteB_1').addEventListener(('click' || 'touchstart'),function() { playSound('B_1');}); 
document.getElementById('noteC_2').addEventListener(('click' || 'touchstart'),function() { playSound('C_2');}); 
document.getElementById('noteC#2').addEventListener(('click' || 'touchstart'),function() { playSound('C#2');}); 
document.getElementById('noteD_2').addEventListener(('click' || 'touchstart'),function() { playSound('D_2');}); 
document.getElementById('noteD#2').addEventListener(('click' || 'touchstart'),function() { playSound('D#2');}); 
document.getElementById('noteE_2').addEventListener(('click' || 'touchstart'),function() { playSound('E_2');}); 
document.getElementById('noteF_2').addEventListener(('click' || 'touchstart'),function() { playSound('F_2');}); 
document.getElementById('noteF#2').addEventListener(('click' || 'touchstart'),function() { playSound('F#2');}); 
document.getElementById('noteG_2').addEventListener(('click' || 'touchstart'),function() { playSound('G_2');}); 
document.getElementById('noteG#2').addEventListener(('click' || 'touchstart'),function() { playSound('G#2');}); 
document.getElementById('noteA_2').addEventListener(('click' || 'touchstart'),function() { playSound('A_2');}); 
document.getElementById('noteA#2').addEventListener(('click' || 'touchstart'),function() { playSound('A#2');}); 
document.getElementById('noteB_2').addEventListener(('click' || 'touchstart'),function() { playSound('B_2');}); 
document.getElementById('noteC_3').addEventListener(('click' || 'touchstart'),function() { playSound('C_3');}); 


document.getElementById('noteC_1b').addEventListener(('click' || 'touchstart'),function() { playSoundb('C_1');}); 
document.getElementById('noteC#1b').addEventListener(('click' || 'touchstart'),function() { playSoundb('C#1');}); 
document.getElementById('noteD_1b').addEventListener(('click' || 'touchstart'),function() { playSoundb('D_1');}); 
document.getElementById('noteD#1b').addEventListener(('click' || 'touchstart'),function() { playSoundb('D#1');}); 
document.getElementById('noteE_1b').addEventListener(('click' || 'touchstart'),function() { playSoundb('E_1');}); 
document.getElementById('noteF_1b').addEventListener(('click' || 'touchstart'),function() { playSoundb('F_1');}); 
document.getElementById('noteF#1b').addEventListener(('click' || 'touchstart'),function() { playSoundb('F#1');}); 
document.getElementById('noteG_1b').addEventListener(('click' || 'touchstart'),function() { playSoundb('G_1');}); 
document.getElementById('noteG#1b').addEventListener(('click' || 'touchstart'),function() { playSoundb('G#1');}); 
document.getElementById('noteA_1b').addEventListener(('click' || 'touchstart'),function() { playSoundb('A_1');}); 
document.getElementById('noteA#1b').addEventListener(('click' || 'touchstart'),function() { playSoundb('A#1');}); 
document.getElementById('noteB_1b').addEventListener(('click' || 'touchstart'),function() { playSoundb('B_1');}); 
document.getElementById('noteC_2b').addEventListener(('click' || 'touchstart'),function() { playSoundb('C_2');}); 
document.getElementById('noteC#2b').addEventListener(('click' || 'touchstart'),function() { playSoundb('C#2');}); 
document.getElementById('noteD_2b').addEventListener(('click' || 'touchstart'),function() { playSoundb('D_2');}); 
document.getElementById('noteD#2b').addEventListener(('click' || 'touchstart'),function() { playSoundb('D#2');}); 
document.getElementById('noteE_2b').addEventListener(('click' || 'touchstart'),function() { playSoundb('E_2');}); 
document.getElementById('noteF_2b').addEventListener(('click' || 'touchstart'),function() { playSoundb('F_2');}); 
document.getElementById('noteF#2b').addEventListener(('click' || 'touchstart'),function() { playSoundb('F#2');}); 
document.getElementById('noteG_2b').addEventListener(('click' || 'touchstart'),function() { playSoundb('G_2');}); 
document.getElementById('noteG#2b').addEventListener(('click' || 'touchstart'),function() { playSoundb('G#2');}); 
document.getElementById('noteA_2b').addEventListener(('click' || 'touchstart'),function() { playSoundb('A_2');}); 
document.getElementById('noteA#2b').addEventListener(('click' || 'touchstart'),function() { playSoundb('A#2');}); 
document.getElementById('noteB_2b').addEventListener(('click' || 'touchstart'),function() { playSoundb('B_2');}); 
document.getElementById('noteC_3b').addEventListener(('click' || 'touchstart'),function() { playSoundb('C_3');}); 

回答

2

無重大遺漏的 - 這是在數字音頻剛剛發生的事情,當你重載輸出(即音頻的瞬時值< -1或> +1) - 你會得到裁剪,這通常聽起來很討厭。可能最好的做法(除了保持增益值低於1)是將DynamicsCompressor放在輸出上(即通過context.createDynamicsCompressor()創建一個DynamicsCompressorNode,將它連接到context.destination,然後將註釋連接到壓縮器比context.destination)。在這種情況下,默認值是合理的(壓縮器設置是一個音樂決定,但這至少有助於剪輯)。

+0

謝謝Chris!我會玩弄增益和壓縮機的建議。很高興知道我沒有犯任何重大錯誤。我真的很感謝你看看我的代碼! – Fedreg