我想做这样一个功能:网页播放有规律的节拍声音,用户按照这个节拍敲击键盘;我需要比较“节拍声音播放的时刻”和“用户敲击键盘的时刻”
以下是例子:
<html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/keymaster/1.6.1/keymaster.min.js"></script>
<script src="https://tonejs.github.io/CDN/latest/Tone.min.js"></script>
<script>
var contextCreatedTime = Date.now();
var context = Tone.context;
// 从第 3 秒开始,每隔 0.5 秒发出声音,共 8 次
for (var i = 0; i < 8; i++) {
var oscillator = context.createOscillator();
oscillator.connect(context.destination);
oscillator.frequency.value = 220;
var soundStartTime = 3 + i * 0.5;
oscillator.start(soundStartTime);
oscillator.stop(soundStartTime + 0.05);
// 将后 4 次发出声音的时刻输出到 console
if (i > 3) {
console.log("sound time: " + (contextCreatedTime + Math.floor(soundStartTime * 1000)));
}
}
// 记录键盘“ k ”键的敲击时刻,输出到 console
key('k', function () {
console.log("keyboard time: " + Date.now());
});
</script>
</body>
</html>
具体操作是这样:
这个网页从载入完成之后的第 3 秒开始,会播放 8 个短促音,它们之间的间隔是 0.5 秒。其中,前 4 个音的作用是提示用户节奏,用户需要踩着后 4 个音的节拍敲击“ k ”键
这后 4 个音的输出时间,以及用户踩着后 4 个音的节拍敲击“ k ”键的时间,都会被输出到 console
但是,通过比较它们之间的时间差,我发现这个时间并不够准确, 比如说,有时候, 4 个节拍音比 4 个按键音的时间要大 40 (毫秒),有时候要大 7 80 ,有时候误差在 10 以内,有时候又会差 100 多……
用这个可解:
oscillator.onended = function () {
console.log("actual note time: ", Date.now());
};
1
starvedcat OP 它们之间的差值可能是这样的:[35, 46, 42, 50],也可能是[107, 95, 88, 102],也可能是[7, 4, -2, 11]这样。我每次都是以相同的节奏感去敲击键盘的,也试了相当多次了,可以排除人为因素。
这里牵扯到三个东西的时刻,理论上他们应该属于同一时刻: 1. 人为设置的发声时间,即“ contextCreatedTime + Math.floor(soundStartTime * 1000)”。这个就是算式,必定准确,关键看另外两者是不是符合它 2. 实际发出声音的时间,即, web audio api 是否按照 1 中设置的时间准时发声了?姑且认为这个 API 也是准确的 3. 用户敲击键盘的时间。 但是令我非常不理解的是,为什么输出按键的时刻,反而是要小于节拍音的时刻呢?照道理说,如果按键在监听事件的过程中耗费的时间从而导致误差的话,那应该是会大于节拍音才对啊? |
2
starvedcat OP 上面 2 也应该是必定准确的。
我的想法就是:这个键盘敲击的时间,仿佛和这个节拍音的时间有一个固定的差值。而每次刷新网页,这个差值都在变化…… |
3
starvedcat OP 对了键盘是机械键盘巡检速率 1000Hz ……
|
4
starvedcat OP 而且我发现,加载的 js 越多,这个误差就越大。上面这个最小化的例子,误差就几十,说实话还可以接受,真正项目中,误差都快上 200 了……比如这样:
sound time: 1479096471944 sound time: 1479096472444 sound time: 1479096472944 sound time: 1479096473444 keyboard time: 1479096471779 keyboard time: 1479096472260 keyboard time: 1479096472750 keyboard time: 1479096473264 差值都在 180 左右 |
5
ctsed 2016-11-14 14:09:38 +08:00 1
requestAnimationFrame
|
6
zzNucker 2016-11-14 14:13:52 +08:00
有网址吗
|
7
starvedcat OP @ctsed 没用到 canvas
|
8
starvedcat OP @zzNucker 上面的网页复制下来就行了。。。。。。。。。
|
9
otakustay 2016-11-14 14:27:44 +08:00 1
@starvedcat raf 和 canvas 没关系,用的话基本能控制在 16ms 左右的精度,算是比较可以的了
|
10
murmur 2016-11-14 14:32:36 +08:00
击拍定速还是音游? 校正输入延迟么?
|
11
xxxyyy 2016-11-14 15:26:41 +08:00 1
你的 sound time 应该使用实际播放时的时间,比如:
oscillator.onended = function () { console.log("sound start time:", Date.now() - 500); }; |
12
cst4you 2016-11-14 19:51:08 +08:00
setInterval 1 毫秒
|
13
starvedcat OP 感谢 ls 诸位!
|
14
andy12530 2016-11-15 04:59:30 +08:00 via iPhone 1
performance api 能精确一些。还有一个可以取到 ns
|