如何解决音频上下文演示 Chrome/Android 上的音量减半,Firefox 上爆裂
我使用 AudioContext
对象做了一个纯 CSS/JS 钢琴键盘,但我有两个与 playTone
函数相关的问题:
-
在 Chrome/android (
v.89.0.4389.105/Android 10
) 上,似乎每次按下键时音量都会减半:弹奏几个音符后,音量就听不见了。 -
在 Firefox (
v.88/MacOS 10.15.7
) 上,我每次按下按键时都会听到噼啪声。
在最新的 Chrome/MacOS 上,相比之下,听起来不错。
const noteFrequencies = {
'C1' : 261.63,'C1#': 277.18,'D1' : 293.66,'D1#': 311.13,'E1' : 329.63,'F1' : 349.23,'F1#': 369.99,'G1' : 392.00,'G1#': 415.30,'A1' : 440.00,'A1#': 466.16,'B1' : 493.88
}
function playTone(note,duration = 1) {
let ac = new AudioContext();
let oscl = ac.createOscillator();
let gain = ac.createGain();
gain.connect(ac.destination);
oscl.connect(gain);
oscl.frequency.value = noteFrequencies[note];
oscl.type = "sine"
gain.gain.linearRampTovalueAtTime(.0001,ac.currentTime + duration);
oscl.start();
oscl.stop(ac.currentTime + duration);
}
let notelist = document.querySelector('.piano');
notelist.addEventListener('click',(ev) => {
let tgt = ev.target;
let tone;
if (tgt.matches('[data-tone]')) {
tone = tgt.getAttribute('data-tone');
playTone(tone);
}
});
* {
Box-sizing: border-Box;
font-family: "Lobster Two";
color: #555666;
}
h1 {
text-align: center;
font-size: 5rem;
margin-bottom: 4rem;
}
.piano {
position : relative;
display : flex;
width : max-content;
list-style : none;
margin : 0 auto;
padding : 0;
align-items: flex-start;
}
.piano li {
--ar : .2;
display: inherit;
cursor : pointer;
color : transparent;
user-select : none;
aspect-ratio: var(--ar);
}
@supports (not (aspect-ratio: 1)) {
.piano li::before {
content: "";
padding-top: calc(100% / var(--ar));
}
}
li:not(.diesis) {
width : max(50px,4vw);
border-left : 1px solid #c4c4c8;
border-bottom : 1px solid #c4c4c8;
border-radius : 0 0 4px 4px;
background : linear-gradient(to bottom,#f2f2f5,#fff);
Box-shadow : 0 0 5px #ccc inset;
}
li:not(.diesis):active {
border-top : 1px solid #bbb;
border-left : 1px solid #ccc;
border-bottom : 1px solid #ccc;
background : linear-gradient(to bottom,#fff,#f2f2f5);
Box-shadow :
2px 0 3px rgba(0,0.1) inset,-4px 2px 10px rgba(0,.02) inset;
}
li.diesis {
position : relative;
z-index : 1;
--w : max(30px,2.5vw);
width : var(--w);
margin : 0 calc(var(--w) / -2);
border : 1px solid #131313;
border-radius : 0 0 4px 4px;
background : linear-gradient(40deg,#222,#555);
Box-shadow :
0 -1px 1px 2px rgba(0,.5) inset,0 1px 2px rgba(0,.5);
}
li.diesis:active {
background: linear-gradient(100deg,#505050,#131313);
Box-shadow:
-1px -1px 2px rgba(255,255,0.2) inset,0 -2px 2px 3px rgba(0,0.6) inset,0.5);
}
<ul class="piano">
<li data-tone="C1">C1</li>
<li data-tone="C1#" class="diesis">C1#</li>
<li data-tone="D1">D1</li>
<li data-tone="D1#" class="diesis">D1#</li>
<li data-tone="E1">E1</li>
<li data-tone="F1">F1</li>
<li data-tone="F1#" class="diesis">F1#</li>
<li data-tone="G1">G1</li>
<li data-tone="G1#" class="diesis">G1#</li>
<li data-tone="A1">A1</li>
<li data-tone="A1#" class="diesis">A1#</li>
<li data-tone="B1">B1</li>
</ul>
如果可以帮助调试,也可以使用 codepen 上的 full demo。
谢谢
解决方法
Chrome 中的音量问题可以通过只使用一个全局 AudioContext
来解决,然后需要在点击处理程序中恢复。
可以通过向自动化时间线添加显式值来消除 Firefox 中的噼啪声。
const currentTime = ac.currentTime;
gain.gain.setValueAtTime(1,currentTime);
gain.gain.linearRampToValueAtTime(.0001,currentTime + duration);
您的 CodePen 更新后的 JavaScript 代码将如下所示:
const ac = new AudioContext();
const noteFrequencies = {
'C1' : 261.63,'C1#': 277.18,'D1' : 293.66,'D1#': 311.13,'E1' : 329.63,'F1' : 349.23,'F1#': 369.99,'G1' : 392.00,'G1#': 415.30,'A1' : 440.00,'A1#': 466.16,'B1' : 493.88,'C2' : 523.25,'C2#': 554.37,'D2' : 587.33,'D2#': 622.25,'E2' : 659.25
}
function playTone(note,duration = 1) {
const currentTime = ac.currentTime;
let oscl = ac.createOscillator();
let gain = ac.createGain();
gain.connect(ac.destination);
oscl.connect(gain);
oscl.frequency.value = noteFrequencies[note];
oscl.type = "sine"
gain.gain.setValueAtTime(1,currentTime);
gain.gain.linearRampToValueAtTime(.0001,currentTime + duration);
oscl.start();
oscl.stop(currentTime + duration);
}
let notelist = document.querySelector('.piano');
notelist.addEventListener('click',(ev) => {
ac.resume();
let tgt = ev.target;
let tone;
if (tgt.matches('[data-tone]')) {
tone = tgt.getAttribute('data-tone');
playTone(tone);
}
});
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。