Creating a User-Friendly Metronome App: Step-by-Step Guide with HTML, CSS, and JavaScript

This tutorial will guide you through the development of a straightforward web application known as the Metronome Application. The application will be crafted using `HTML`, `CSS`, and `JavaScript`. Geared towards students and novice programmers, this tutorial serves as a practical reference for learning to create a user-friendly metronome application utilizing the mentioned programming languages. I will provide step-by-step instructions and scripts to achieve the desired result.

What is Metronome App?

The Metronome Application functions as a web-based version of a metronome device. This application generates regular, metrical ticks or beats at a consistent interval. Typically employed in music practice, a metronome aids musicians in maintaining a steady tempo or rhythm. The application offers an audible cue, often in the form of clicks, enabling musicians to stay synchronized with their desired tempo during play or practice.

How to Create a Simple Metronome Application?

Before we begin the coding process, ensure you have downloaded and installed the following if they are not yet available on your local machine:

  • XAMPP/WAMP or any similar web servers
  • Code Editor such as MS Code Editor, Notepad++, and Sublime Text
  • Single Click or Tick Audio - for the metronome audible cue

After a successful installation, be sure to run the Apache server.

Let's get started...

Step 1: Creating the Custom CSS

In this tutorial, the provided source code utilizes the Bootstrap Framework for the application interface design. However, certain elements, including the background image, control buttons, and more, have custom styling. Below is the CSS script used for the web app interface. Save the file as `style.css`.

  1. @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;600;700;800;900&display=swap');
  2. html, body{
  3. height: 100%;
  4. width: 100%;
  5. }
  6.  
  7. body{
  8. background-color:#cfd9df;
  9. background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%);
  10. display: flex;
  11. flex-flow: column wrap;
  12. justify-content: center;
  13. align-items: center;
  14. }
  15. * {
  16. font-family: 'Orbitron', sans-serif;
  17. }
  18. div#app-title {
  19. font-size: 2rem;
  20. font-weight: 600;
  21. letter-spacing: 2px;
  22. color: #5e5e5e;
  23. }
  24.  
  25. div#bpm-container {
  26. width: 300px;
  27. height: 300px;
  28. padding: 5px;
  29. background: #30c7ec;
  30. background-image: radial-gradient(circle 248px at center, #16d9e3 0%, #30c7ec 47%, #46aef7 100%);
  31. border-radius: 100%;
  32. border: 12px dashed #008096;
  33. }
  34.  
  35. div#bpm-container>span:nth-child(1) {
  36. font-size: 4rem;
  37. font-weight: 600;
  38. color: #006475;
  39. letter-spacing: 5px;
  40. }
  41.  
  42. div#bpm-container>span:nth-child(2) {
  43. font-size: 1.2rem;
  44. font-weight: 600;
  45. letter-spacing: 2px;
  46. color: #026070;
  47. }
  48.  
  49. div.beatsText {
  50. font-size: 1.3rem;
  51. font-weight: 500;
  52. }
  53.  
  54. button.beatsBTN{
  55. transition: transform .1s ease;
  56. }
  57. button.beatsBTN:active{
  58. transform: scale(.9);
  59. }
  60. #playMetronome{
  61. border: 6px dashed #006475;
  62. background: #66a6ff;
  63. background-image: linear-gradient(120deg, #89f7fe 0%, #66a6ff 100%);
  64. color: #006475;
  65. }
  66. #stopMetronome{
  67. display: none;
  68. border: 6px dashed #b14536;
  69. background: #fe9a8b;
  70. background-image: linear-gradient(to right, #f78ca0 0%, #f9748f 19%, #fd868c 60%, #fe9a8b 100%);
  71. color: #6e0d00;
  72. }
  73. button.controlBtns {
  74. height: 50px;
  75. width: 50px;
  76. display: flex;
  77. align-items: center;
  78. justify-content: center;
  79. border-radius: 100%;
  80. }

Step 2: Creating the Application Interface

Moving forward, let's establish the page or web application interface. In your code editor, create a new HTML file and save it as `index.html`. This file will contain the HTML scripts incorporating essential elements for the application, including the Metronome Tempo Display and Slider, Beats per Measure, and Control Buttons (Play/Stop). Consult the following HTML script for this stage:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <meta charset="UTF-8">
  4. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  5. <title>Metronome App in JS</title>
  6. <!-- Fontawesome CSS CDN -->
  7. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css" integrity="sha512-z3gLpd7yknf1YoNbCzqRKc4qyor8gaKU1qmn+CShxbuBusANI9QpRohGBreCFkKxLhei6S9CQXFEbbKuqLg0DA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
  8. <!-- Bootstrap CSS CDN -->
  9. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
  10.  
  11. <link rel="stylesheet" href="style.css">
  12.  
  13. <!-- Fontawesome CSS CDN -->
  14. <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/js/all.min.js" integrity="sha512-uKQ39gEGiyUJl4AI6L+ekBdGKpGw4xJ55+xyJG7YFlJokPNYegn9KwQ3P8A7aFQAUtUsAQHep+d/lrGqrbPIDQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  15. <!-- jQuery CSS CDN -->
  16. <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
  17. <!-- Bootstrap CSS CDN -->
  18. <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
  19.  
  20.  
  21. </head>
  22. <div id="app-title"><strong>Simple Metronome Application</strong></div>
  23. <div class="col-lg-4 col-md-8 col-sm-12 col-12 my-3">
  24. <div class="card shadow w-100">
  25. <div class="card-body">
  26. <div class="container-fluid">
  27. <div>
  28. <label for="" class="form-label text-dark-emphasis text-center d-block">Tempo</label>
  29. </div>
  30. <!-- Beats Per Minute Elements -->
  31. <!-- BPM Text Display -->
  32. <div class="d-flex justify-content-center w-100">
  33. <div class="d-flex flex-column justify-content-center align-items-center" id="bpm-container">
  34. <span id="bpm">140</span>
  35. <span>BPM</span>
  36. </div>
  37. </div>
  38. <!-- End of BPM Text Display -->
  39.  
  40. <div class="my-3 w-100 d-flex align-items-center">
  41. <div class="col-auto flex-shrink-1">
  42. <span><i class="fas fa-minus px-2"></i></span>
  43. </div>
  44. <!-- BPM Slider -->
  45. <div class="col-auto flex-grow-1">
  46. <input type="range" class="form-range" min="35" max="250" value="140" id="bpmSlider">
  47. </div>
  48. <!-- End of BPM Slider -->
  49. <div class="col-auto flex-shrink-1 px-2">
  50. <span><i class="fas fa-plus"></i></span>
  51. </div>
  52. </div>
  53. <!-- End of Beats Per Minute Elements -->
  54.  
  55. <!-- Beats per Measure -->
  56. <div class="my-3">
  57. <label for="" class="form-label text-dark-emphasis text-center d-block">Beats per Measure</label>
  58. <div class="w-100 d-flex align-items-center justify-content-center">
  59. <div class="col-auto flex-shrink-1">
  60. <button class="btn btn-sm btn-default border shadow beatsBTN" data-type="minus"><i class="fas fa-minus"></i></button>
  61. </div>
  62. <div class="col-4">
  63. <div id="beatsText" class="text-center">4</div>
  64. </div>
  65. <div class="col-auto flex-shrink-1">
  66. <button class="btn btn-sm btn-default border shadow beatsBTN" data-type="plus"><i class="fas fa-plus"></i></button>
  67. </div>
  68. </div>
  69.  
  70. </div>
  71. <!-- End of Beats per Measure -->
  72.  
  73. <!-- Buttons -->
  74. <div class="my-3">
  75. <div class="d-flex align-items-center justify-content-center">
  76. <button type="button" class="controlBtns" id="playMetronome"><i class="fas fa-play"></i></button>
  77. <button type="button" class="controlBtns" id="stopMetronome"><i class="fas fa-stop"></i></button>
  78. </div>
  79. </div>
  80. <!-- End of Buttons -->
  81.  
  82. </div>
  83. </div>
  84. </div>
  85. </div>
  86.  
  87. <script src="script.js"></script>
  88. </body>
  89. </html>

Step 3: Creating the JS Script

Finally, let's generate the JavaScript file for the application. This file encompasses multiple functions and event listeners crucial for the functionality of our Metronome application. The script includes playing the metronome, updating the tempo, adjusting the beats per measure, and other relevant functions. Create a JS file and save it as `script.js`.

  1. /**
  2. * Setting elements to constants and Decalring Variables
  3. */
  4. const playButton = document.getElementById('playMetronome');
  5. const stopButton = document.getElementById('stopMetronome');
  6. const bpmSlider = document.getElementById('bpmSlider');
  7. const bpmEl = document.getElementById('bpm');
  8. const beatTxt = document.getElementById('beatsText');
  9. const beatBTN = document.querySelectorAll('button.beatsBTN');
  10. const audio = new AudioContext()
  11. let audioBuffer;
  12. let i =1;
  13. let beat_count = 4
  14. let metronome;
  15. let bpm = 140;
  16. let isplaying = false;
  17.  
  18. // Loading Metronome Audi
  19. function load_audio(){
  20. return fetch('./metronome.mp3')
  21. .then(response => response.arrayBuffer())
  22. .then(buffer => audio.decodeAudioData(buffer) );
  23. }
  24. load_audio().then(buffer => audioBuffer = buffer )
  25.  
  26. /**
  27. * Function for Playing the Metronome Click Sound
  28. * @param int rate = to change playbackrate or the pitch
  29. */
  30. function playClick(rate=1) {
  31. // creating the audio buffer source
  32. const source = audio.createBufferSource();
  33. // Serring audio buffer to source
  34. source.buffer = audioBuffer;
  35. // changing the pitch
  36. source.playbackRate.value = rate;
  37. // Connect source to audio destination
  38. source.connect(audio.destination);
  39. // play the audio from the start
  40. source.start(0);
  41. }
  42.  
  43.  
  44. /**
  45. * Function that Loops the Metronome depending to provided tempo and beats
  46. */
  47. function metronome_play(){
  48. // identifying that metronome is playing
  49. isplaying = true
  50. // looping the beat
  51. metronome = setInterval(function(){
  52. // setting up the pitch, high pitch the 1 beat per measure
  53. var PBrate = 1
  54. if(i == 1)
  55. PBrate = 2;
  56. playClick(PBrate)
  57. i = i + 1;
  58. if(i > beat_count){
  59. i = 1;
  60. }
  61. }, (60000 / bpm))
  62. }
  63.  
  64. // Function that stops the metronome
  65. function metronome_stop(){
  66. clearInterval(metronome)
  67. i = 1;
  68. isplaying = false
  69. }
  70.  
  71. // function that updates the beats per measure
  72. function change_beat(type = "plus"){
  73. if(type == 'plus'){
  74. beat_count = beat_count + 1;
  75. }else{
  76. beat_count = beat_count - 1;
  77. }
  78.  
  79. if(beat_count < 2)
  80. beat_count = 2;
  81. beatTxt.innerText = beat_count
  82. if(isplaying){
  83. metronome_stop()
  84. metronome_play()
  85. }
  86.  
  87. }
  88.  
  89. /**
  90. * Event Listener that triggers the metronome to play
  91. */
  92. playButton.addEventListener('click', function(e){
  93. e.preventDefault()
  94. if(!isplaying){
  95. metronome_play()
  96. }
  97. // Hide Play Button
  98. playButton.style.display = 'none'
  99. // Show Stop Button
  100. stopButton.style.display = 'flex'
  101. })
  102.  
  103. /**
  104. * Event Listener that triggers the metronome to stop
  105. */
  106. stopButton.addEventListener('click', function(e){
  107. e.preventDefault()
  108. metronome_stop()
  109. // Hide Stop Button
  110. stopButton.style.display = 'none'
  111. // Show Play Button
  112. playButton.style.display = 'flex'
  113. })
  114.  
  115. /**
  116. * Event Listener that triggers the metronome speed up or down
  117. */
  118. bpmSlider.addEventListener('input', function(e){
  119. e.preventDefault()
  120. bpmEl.innerText = `${bpmSlider.value}`
  121. bpm = bpmSlider.value
  122. if(isplaying){
  123. metronome_stop()
  124. metronome_play()
  125. }
  126.  
  127. })
  128.  
  129. /**
  130. * Event Listener that triggers the metronome to change the number of beats per measure
  131. */
  132. beatBTN.forEach(el=>{
  133. el.addEventListener('click', function(e){
  134. e.preventDefault()
  135. change_beat(el.dataset.type)
  136. })
  137. })
  138.  

Prior to testing the application, ensure to modify the path of the metronome click or tick audio file you've downloaded in the `load_audio()` function of the JavaScript file.

Snapshots

Here are some snapshots of the result script I have provided above:

Page Interface

Simple Metronome Application using HTML, CSS, and JavaScript

Metronome when not playing

Simple Metronome Application using HTML, CSS, and JavaScript

Metronome when playing

Simple Metronome Application using HTML, CSS, and JavaScript

I have also provided the compressed complete source code zip file of the Simple Metronome Application that I created on this website. To download it, simply click the Download button below this article tutorial.

That' it! I hope this Metronome Application Tutorial using HTML, CSS, and JavaScript will help you with what you are looking for and you'll find something useful from the script for your future web application projects. Explore more on this website for more Free Source Codes, Tutorials, and Article covering various programming languages.

Happy Coding =)

Add new comment