网络音频 API 故障/失真问题

2024-04-02

我是网络音频 API 的新手,并制作了一个简单的合成器来了解细节。问题是,在大量声音输入后,我的音频会失真很多。因此,如果我施加大量频率,它就会失真。任何了解 API 的人都可以快速浏览一下我的代码,看看是否存在任何重大错误/遗漏?可以在 Safari、chrome 和 Firefox 中重现问题。演示版是HERE https://fedreg.github.io/Web-Audio-API-Synth/谢谢你的帮助!!

//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) - 你会得到削波,这通常听起来很糟糕。也许最好的办法(除了保持增益值低于 1)是在输出上放置一个 DynamicsCompressor(即通过 context.createDynamicsCompressor() 创建一个 DynamicsCompressorNode,将其连接到 context.destination,然后将音符连接到压缩器,而不是比 context.destination )。默认值是合理的,可以在这种情况下提供帮助(压缩器设置是一个音乐决定,但这至少有助于剪辑)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

网络音频 API 故障/失真问题 的相关文章

随机推荐

  • 如何使 XMLHttpRequest 在 Firefox 上通过 HTTPS 工作?

    当我尝试通过 XMLHttpRequest 发送 HTTP GET 请求时 它适用于非安全 HTTP 但是当通过 HTTPS 发送时 不同的浏览器给出不同的结果 在火狐 3 0 2 上 GET 请求未到达 Web 服务器 在 IE 7 上
  • 将 Plotly 与 R 结合使用的悬停模式

    当使用 R 和 ggplot2 进行绘图时 有没有办法对悬停模式进行编码 目前 我的代码是 plot lt ggplot data aes var1 var2 text var3 geom point py ggplotly plot 我希
  • Soundcloud API - Access-Control-Allow-Origin 不允许来源

    作为后续通过永久链接而不是 trackid 播放播放列表或曲目 https stackoverflow com questions 19351797 play playlist or track by permalink not track
  • 导致git merge冲突的原因和情况有哪些?

    什么是 必要和充分的条件 和 或 所有案例或一些常见案例 这可能会导致git merge报告合并冲突 如何git merge判断一行或几行是否包含 合并冲突 例如 我有时会看到类似以下的情况 其中Part 1 or Part 2是空的 lt
  • 尝试使用 socket.io 时出现错误

    我目前正在使用 socket io swift 客户端 在 Iphone SE 上运行 这是快速代码 let socket SocketIOClient socketURL URL string http example com 4000
  • 更改 CodeBlocks 中的链接器顺序

    我在 DialogBlocks 5 03 中有一个项目 可以使用 mingw32 正常编译 但使用 CodeBlocks 13 12 显示此错误 F wxWidgets 3 0 0 lib gcc lib libwxmsw30u core
  • 如何计算圆上两点之间的弧角?

    给定一个已知圆心和圆上两点 即已知半径 的圆 如何确定圆上两点之间的最小圆弧角度 将中心到两点变成一对向量 然后推过去this http en wikipedia org wiki Vector 28geometry 29 Dot prod
  • 为什么Android Studio 1.0 rc会开始下载Android SDK而不检测是否存在?

    我已经在我的 Archlinux 盒子里安装了 Android Studio 1 0 rc 和 Android SDK 但是当我尝试创建一个新的Android应用程序时 AS会尝试直接从dl ssl google com下载另一组SDK 我
  • 什么情况下不会调用 C++ 析构函数?

    我知道我的析构函数是在堆栈的正常展开和抛出异常时调用的 但不是在调用 exit 时调用 还有其他情况我的析构函数不会被调用吗 SIGINT 或 SIGSEGV 等信号怎么样 我认为对于 SIGSEGV 它们不会被调用 但对于 SIGNINT
  • ld: -bundle 和 -bitcode_bundle 不能一起使用

    我正在建造llvm clang 3 7具有位码支持 fembed bitcode 由于错误 某些模块无法链接 ld bundle 和 bitcode bundle Xcode 设置 ENABLE BITCODE YES 不能一起使用 cla
  • 实际上使用 UIDatePickerModeCountDownTimer 作为计时器

    我只是想制作一个计时器 我想用UIDatePickerModeCountDownTimer的模式UIDatePicker 这样当用户只需在选择器中选择 15 分钟时 他们就会返回到一个屏幕 该屏幕在标签中显示 15 分钟的值 然后他们可以从
  • 具有多表继承的父类上的 Django post_save 信号

    在 Django 中 如果您有使用多表继承的模型 并且您在父类上为 post save 信号定义了一个接收器 那么当保存子类的实例时 是否会调用该接收器函数 借个例子来自另一个问题 https stackoverflow com quest
  • 在 R 中将完整年龄从字符转换为数字

    我有一个数据集 其中人们的完整年龄为 R 中的字符串 例如 10 年 8 个月 23 天 我需要将其转换为有意义的数字变量 我正在考虑将其转换为有多少天人的年龄 这很困难 因为月份有不同的天数 因此 最好的解决方案可能是创建一个双变量 将年
  • 如何检测android中的屏幕覆盖?

    在某些设备中 当屏幕覆盖应用程序正在运行时 单击 VPN 权限确定按钮时不会执行任何操作 所以我想检查屏幕覆盖应用程序是否正在运行 并创建 检测到屏幕覆盖 对话框 有没有办法在android中以编程方式检测屏幕覆盖 示例代码 public
  • CATALINA_OPTS 与 JAVA_OPTS - 有什么区别?

    我试图找出 Apache Tomcat 变量之间的区别 CATALINA OPTS and JAVA OPTS in SO http stackoverflow com并惊讶地发现这里还没有发布问题 答案 所以我想在发现差异后在这里分享 带
  • 在 Haskell 中实现记忆功能

    我对 Haskell 相当陌生 我正在尝试实现一个基本的记忆功能 它使用Data Map存储计算值 我的示例是欧拉项目问题 15 其中涉及计算 20x20 网格中从一个角到另一个角的可能路径数 这是我到目前为止所拥有的 我还没有尝试编译 因
  • 如果未显式提交或回滚,则自动提交事务

    我们使用 Weblogic 服务器 并在连接到 Oracle 10g 时始终将 autoCommit 设置为 false 我想知道 Weblogic 中是否有一个设置 如果未从应用程序代码中显式调用提交或回滚 它将自动提交事务 我听说 We
  • VS2013 Intellisense 不理解 decltype

    是否有补丁 官方或非官方 可以让 IntelliSense 停止报告每次使用decltype作为语法错误 它编译得很好 所以我知道decltype是支持的 但是到处都是红色波浪线会让人分心 而且很难找到actual代码中的错误 每次编译都会
  • 重新排序表列?

    有谁知道使用 jQuery 对表列重新排序的方法吗 我的意思不是排序 我的意思是在表中向左或向右动态移动整个列 我知道优秀的可拖动插件 http www danvk org wp dragtable 但我不需要允许用户移动列的东西 我需要一
  • 网络音频 API 故障/失真问题

    我是网络音频 API 的新手 并制作了一个简单的合成器来了解细节 问题是 在大量声音输入后 我的音频会失真很多 因此 如果我施加大量频率 它就会失真 任何了解 API 的人都可以快速浏览一下我的代码 看看是否存在任何重大错误 遗漏 可以在