首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >滚筒机<audio> lag

滚筒机<audio> lag
EN

Stack Overflow用户
提问于 2020-08-09 13:12:45
回答 1查看 50关注 0票数 0

我正在组装一个鼓机/音序器,虽然音序器的主要功能运行良好,但当音序器第一次播放时,我嵌入到每个鼓单元中的音频确实有明显的滞后。它似乎在第一个节拍后自我纠正,一切正常播放,直到其他声音添加到模式中。

我有三行表格单元格,每一行代表不同的鼓声。当用户使用所有可用的声音构建一个鼓模式时,循环最终似乎失去了同步,一些声音比其他声音晚了几分之一秒,但后来又进行了自我纠正。我主要担心的是样本的回放不一致。

我已经将标记嵌入到元素中,并将preload属性设置为auto。

代码语言:javascript
运行
复制
<table class="pad">
        <tbody>
        <tr>
            <td class="kick sounds">
                <audio preload="auto"  src="https://raw.githubusercontent.com/wesbos/JavaScript30/master/01%20-%20JavaScript%20Drum%20Kit/sounds/kick.wav"></audio>
            </td>
        </tr>
      </tbody>
</table>

因此,每行有8个表单元格,每个单元格都具有与上面相同的格式(嵌入了元素)。诚然,我可以想象我的结构方式是相当低效的,使用web音频API会更好,但我还没有学习API。在JS中有什么我可以做的,可以让这些音频样本的播放速度更快?

编辑:这是序列器代码。它循环遍历每个元素,并检查是否有选定的单元格。如果是,则播放该元素的音频文件。如果不是,则跳到下一列。

代码语言:javascript
运行
复制
class Sequencer {
    playButton = btn;
    clearButton = clear;
    sounds = Array.from(sounds);
    kicks = Array.from(kicks);
    hihats = Array.from(hihats);
    snares = Array.from(snares);
    currentBeatIndexKick = 0;
    currentBeatIndexHiHat = 0;
    currentBeatIndexSnare = 0;
    isPlaying = false;

    constructor(msPerBeat) {
        this.msPerBeat = msPerBeat;
        this.playButton.addEventListener('click', () => this.toggleStartStop())
        this.clearButton.addEventListener('click', () => this.clear())
        this.sounds.forEach(sound => {
            sound.addEventListener('click', e => {
                if (((e.target.classList.contains('kick')) || (e.target.classList.contains('hihat')) || (e.target.classList.contains('snare'))) && !e.target.classList.contains('selected')) {
                    e.target.classList.add('selected');
                } else {
                    e.target.classList.remove('selected');
                }
            })
        })
    }
    
    toggleStartStop() {
        if (this.isPlaying) {
            this.stop();
        } else {
            this.start();
        }
    }

    clear() {
        this.kicks.forEach(kick => {
            if (kick.classList.contains('selected')) {
                kick.classList.remove('selected');
            }
        });
        hihats.forEach(hihat => {
            if (hihat.classList.contains('selected')) {
                hihat.classList.remove('selected');
            }
        });
        snares.forEach(snare => {
            if (snare.classList.contains('selected')) {
                snare.classList.remove('selected');
            }
        });
        this.stop();
        console.clear();
    }

    stop() {
        this.isPlaying = false;
        this.currentBeatIndexKick = 0;
        this.currentBeatIndexHiHat = 0;
        this.currentBeatIndexSnare = 0;
        this.playButton.innerText = 'Play'; 
    }

    start() {
        this.isPlaying = true;
        this.playCurrentNoteAndSetTimeoutKick() // kicks
        this.playCurrentNoteAndSetTimeoutHiHats() // hihats
        this.playCurrentNoteAndSetTimeoutSnares() // snares
        this.playButton.innerText = 'Stop';
    }

    playCurrentNoteAndSetTimeoutKick() {
        if (this.isPlaying && this.kicks[this.currentBeatIndexKick].classList.contains('selected')) {
            this.kicks[this.currentBeatIndexKick].childNodes[1].play();
            setTimeout(() => {
                this.toNextBeatKicks();
                this.playCurrentNoteAndSetTimeoutKick(); 
            }, this.msPerBeat)
        }
        if (this.isPlaying && !this.kicks[this.currentBeatIndexKick].classList.contains('selected'))
            setTimeout(() => {
                this.toNextBeatKicks();
                this.playCurrentNoteAndSetTimeoutKick();
            }, this.msPerBeat)
    }

    playCurrentNoteAndSetTimeoutHiHats() {
        if (this.isPlaying && this.hihats[this.currentBeatIndexHiHat].classList.contains('selected')) {
            this.hihats[this.currentBeatIndexHiHat].childNodes[1].play();
            setTimeout(() => {
                this.toNextBeatHiHats();
                this.playCurrentNoteAndSetTimeoutHiHats();
            }, this.msPerBeat)
        }
        if (this.isPlaying && !this.hihats[this.currentBeatIndexHiHat].classList.contains('selected'))
            setTimeout(() => {
                this.toNextBeatHiHats();
                this.playCurrentNoteAndSetTimeoutHiHats();
            }, this.msPerBeat)
    }

    playCurrentNoteAndSetTimeoutSnares() {
        if (this.isPlaying && this.snares[this.currentBeatIndexSnare].classList.contains('selected')) {
            this.snares[this.currentBeatIndexSnare].childNodes[1].play();
            setTimeout(() => {
                this.toNextBeatSnares();
                this.playCurrentNoteAndSetTimeoutSnares(); 
            }, this.msPerBeat)
        }
        if (this.isPlaying && !this.snares[this.currentBeatIndexSnare].classList.contains('selected'))
            setTimeout(() => {
                this.toNextBeatSnares();
                this.playCurrentNoteAndSetTimeoutSnares(); 
            }, this.msPerBeat)
    }

    toNextBeatKicks() {
        this.currentBeatIndexKick = ++this.currentBeatIndexKick % this.kicks.length; 
    }

    toNextBeatHiHats() {
        this.currentBeatIndexHiHat = ++this.currentBeatIndexHiHat % this.hihats.length; 
    }

    toNextBeatSnares() {
        this.currentBeatIndexSnare = ++this.currentBeatIndexSnare % this.snares.length; 
    }
    
}

const sequencer = new Sequencer(213)
EN

回答 1

Stack Overflow用户

发布于 2020-08-09 13:36:14

我认为你可能需要做的是以编程的方式播放音频文件。如果不让我们更多地访问你的代码,就很难理解你的sequencer是如何工作的,我的方法是一旦用户选择了序列,就通过编程播放音频文件。我会分配一个变量来播放,一旦在你的音序器上选择了这些步骤。

代码语言:javascript
运行
复制
var audio = new Audio('audio_file.mp3');
audio.play();

将在序列上调用audio.play。我不确定这是否有帮助,但我认为这是您所指的api的一部分。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63322702

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档