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