
Metronome
Short Description
A component acting as a metronome with the ability for various inputs.
Long Description
Context
Musicians use a thing called a metronome to keep their tempo. In this component you're going to start with a blinking box and end with a metronome playing a sound for each beat.
Feel free to add subcomponents as you like.
Stages
1. Display a blinking indicator
Create a component which takes the BPM (beats per minute) as an input number and blinks an indicator (e.g. a circle) like below:
Limit the possible values to between 40 and 240 bpm. (I know that music outside that range exists, but I want you to enforce those limits)
2. Range Input
Add a range input to your component with the same limits as above and make sure that the range and number input are always in sync.
<input type="range" min="40" max="240" value="120" />
3. Tap Input
As a last input method I'd like you to add a button which allows the user to tap a speed by clicking it.
At 40 bpm the duration between each tap is 1.5 seconds, so let's say if the user stops tapping for 5 seconds, you start a new measurement. Average all taps inside one measurement to get the BPM (update the UI live with each tap).
4. Help Counting
Music is written with bars which each contains a number of note lengths of a certain duration. Most of the time this is 4/4 (four quarter notes), but also 3/4 (three quarter notes) is common and you find things like 7/8 (seven eights notes) and more.
Please add two inputs to your components which allow the user to select the number of subdevisions of a bar and the note length of each subdivision (so {number}/{length}).
Depending on the number of subdivisions you add new indicators to your component and light up the corresponding indicator for each beat.
So for a 4/4 it would look like this:
5. Final Changes
Now let's give the first blinking indicator a different color so it's easier to keep track of the 1s and let's add a short beep to each indicator so the musician doesn't have to keep his eyes on the screen (please also add a mute button). Again the 1s should sound different to the others.
You can either use your own clicks or use this JS to generate a sound:
function play_sound(frequency = 440){
const context = new AudioContext()
const gain = context.createGain()
const oscillator = context.createOscillator()
gain.connect(context.destination)
oscillator.connect(gain)
oscillator.frequency.value = frequency;
oscillator.start(0);
gain.gain.exponentialRampToValueAtTime(
0.000001, context.currentTime + .5
)
setTimeout(() => context.close(), 1000)
}