Componer

Metronome

1 - 3

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)
}