制作一个JavaScript节拍器

huangapple go评论63阅读模式
英文:

making a Javascript metronome

问题

Newbie here, I'm trying to make a Javascript metronome, but I'm stuck on making the sound play according to the current bpm of the project

Here's where I think the problem lies, when I press play, it sounds, but in a fixed bpm, that is not the one being inputted in the bpm variable:

//VARIABLES
let bpm = 150;
let soundInterval = (60/bpm)*1000;

//FUNCTIONS

//START METRONOME
let startStopMetronome = startButton.addEventListener('click', () => {
    startMetronome(soundInterval);
})

function startMetronome(si) {
    setTimeout(() => {
        primaryBeat.play();
        startMetronome(si);
    }, si);
}

UPDATE:
I've tried making the soundInterval update with a function, but it still does the same, and plays the same fixed interval no matter the bpm changes

//VARIABLES
let bpm = 150;
let soundInterval;

//FUNCTIONS

//START METRONOME
let startStopMetronome = startButton.addEventListener('click', () => {
    soundInterval = calculateSoundInterval();
    startMetronome(soundInterval);
})

function startMetronome(si) {
    setTimeout(() => {
        primaryBeat.play();
        startMetronome(si);
    }, si);
}

let calculateSoundInterval = () => {
    return (60/bpm)*1000;
}

let updateBpmInDisplay = display.addEventListener('change', () => {
    soundInterval = calculateSoundInterval();
})
英文:

Newbie here, I'm trying to make a Javascript metronome, but I'm stuck on making the sound play according to the current bpm of the project

Here's where I think the problem lies, when I press play, it sounds, but in a fixed bpm, that is not the one being inputted in the bpm variable:

//VARIABLES
let bpm = 150;
let soundInterval = (60/bpm)*1000;


//FUNCTIONS

//START METRONOME
let startStopMetronome = startButton.addEventListener('click', () => {
    startMetronome(soundInterval);
})


function startMetronome(si) {
    setTimeout(() => {
        primaryBeat.play();
        startMetronome(si); 
    },si);
}

UPDATE:
I´ve tried making the soundInterval update with a function, but it still does the same, and plays the same fixed interval no matter the bpm changes

//VARIABLES
let bpm = 150;
let soundInterval;




//FUNCTIONS

//START METRONOME
let startStopMetronome = startButton.addEventListener('click', () => {
    soundInterval = calculateSoundInterval();
    startMetronome(soundInterval);
})


function startMetronome(si) {
    setTimeout(() => {
        primaryBeat.play();
        startMetronome(si); 
    },si);
}

let calculateSoundInterval = () => {
    return (60/bpm)*1000;
}

let updateBpmInDisplay = display.addEventListener('change', ()=> {
    soundInterval = calculateSoundInterval();
})

答案1

得分: 1

以下是翻译好的部分:

"我认为查看我如何完成这个任务可能会很有趣。我使用了AudioContext和振荡器来制作声音,而不是直接使用setTimeout,我使用了一个辅助函数来模拟异步操作。如果我想要改进这个,我可能会在更高的作用域中保留我的timeout,这样当停止按钮按下时,我可以清除timeout,并防止在快速按下停止和开始按钮以同时运行两个循环时出现任何错误。希望我的想法对你有一些价值,很有趣。"

请注意,代码部分没有被翻译。

英文:

I thought it might be fun to look over how I would accomplish this. I used an AudioContext and oscillator to make the sound, and instead of using setTimeout directly I used a helper function to model async practice. If I wanted to improve upon this, I might hold onto my timeout in a higher scope, so when stop is pressed I could clear the timeout and prevent any bugs when pressing stop and start quickly to have two loops running at the same time. I hope my take on things has some value 👍 was fun to look at.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const get = str =&gt; document.querySelector(str);
const wait = seconds =&gt; new Promise(r =&gt; setTimeout(r, seconds * 1e3));

const context = new AudioContext();   
let cntr = 0;
const makeSound = () =&gt; {
  const sound = context.createOscillator();
  const fourthBeat = cntr++ % 4 === 0;
  sound.frequency.value = fourthBeat ? 400 : 440;
  sound.connect(context.destination);
  sound.start(context.currentTime);
  sound.stop(context.currentTime + .1);
};

let bpm = 60;
get(&quot;input&quot;).addEventListener(&quot;input&quot;, e =&gt; {
  bpm = e.target.value;
  get(&quot;.display&quot;).innerText = bpm;
});

let running = true;
get(&quot;.start&quot;).addEventListener(&quot;click&quot;, async () =&gt; {
  running = true;
  get(&quot;.start&quot;).disabled = true;
  while (running) {
    makeSound();    
    await wait(60 / bpm);
  }
});

get(&quot;.stop&quot;).addEventListener(&quot;click&quot;, () =&gt; {
  running = false
  get(&quot;.start&quot;).disabled = false;
  cntr = 0;
});

<!-- language: lang-html -->

&lt;div class=&quot;display&quot;&gt;60&lt;/div&gt;
&lt;input min=&quot;30&quot; max=&quot;200&quot; value=&quot;60&quot; type=&quot;range&quot; /&gt;
&lt;button class=&quot;start&quot;&gt;start&lt;/button&gt;
&lt;button class=&quot;stop&quot;&gt;stop&lt;/button&gt;

<!-- end snippet -->

答案2

得分: 0

感谢大家的帮助。最后,问题是我没有配置输入来在点击或输入时重置声音,所以声音一直播放直到自然停止。我添加了 currentTime = 0,问题解决了,现在它按预期工作:

function startMetronome(si) {
    timerId = setInterval(() => {
        primaryBeat.play();
        primaryBeat.currentTime = 0;
    }, si);
}
英文:

Thanks everyone for the help. At the end, the issue was that I had not configured the inputs to reset the sound on click or input, so the sound just played until it stopped naturally. I added currentTime = 0, and problem solved, now it works as intended:

function startMetronome(si) {
    timerId = setInterval(() =&gt; {
        primaryBeat.play();
        primaryBeat.currentTime = 0;
    },si);
}

huangapple
  • 本文由 发表于 2023年3月4日 06:30:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/75632384.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定