Web Audio API故障/失真问题

时间:2016-07-23 23:34:47

标签: javascript web-audio

我是网络音频API的新手,并制作了一个简单的合成器来学习细节。在输入沉重的声音后,麻烦是我的音频扭曲了很多。因此,如果我通过它推动大量频率将会扭曲。任何了解API的人都可以快速查看我的代码,看看是否有任何重大错误/遗漏?可以在Safari,Chrome和Firefox中重新创建问题。演示版是HERE感谢您的帮助!!

//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');});

1 个答案:

答案 0 :(得分:2)

没有重大遗漏 - 这就是当您重载输出时数字音频中发生的事情(即音频的瞬时值<-1或+1) - 你得到剪辑,这通常听起来很讨厌。可能最好的事情(除了保持增益值低于1)是在输出上放置一个DynamicsCompressor(即通过context.createDynamicsCompressor()创建一个DynamicsCompressorNode,将它连接到context.destination,然后将注释连接到压缩器而不是比context.destination)。在这种情况下,默认值是合理的(压缩器设置是一个音乐决定,但这至少会有助于裁剪)。