Skip to content

Instantly share code, notes, and snippets.

@yunga
Last active April 3, 2024 15:26
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save yunga/8df042eb4eb5970ba86ba4ba3ed535d9 to your computer and use it in GitHub Desktop.
Save yunga/8df042eb4eb5970ba86ba4ba3ed535d9 to your computer and use it in GitHub Desktop.

GRUB INIT TUNE

A GRUB_INIT_TUNE uses the following format: tempo [freq duration] [freq duration]…

  • tempo: is the base for all note durations in beats per minute, 60 gives a second base (60s/60 = 1s), 120 gives a half-second base, etc.
  • freq: is the frequency (in hertz) of the sound (set 0 to produce a rest)
  • duration: is the duration of the sound in beats

You can preview the tunes below with the standalone index.html included in this gist.

Links:


## Adams's tune (Notes: 16 / Duration: 2000ms)
GRUB_INIT_TUNE="480 220 1 277 1 330 1 440 1 185 1 220 1 277 1 370 1 294 1 370 1 440 1 587 1 330 1 415 1 494 1 659 1"

## Beep (Notes: 1 / Duration: 125ms)
GRUB_INIT_TUNE="480 440 1"

## Close Encounters of the Third Kind (Notes: 5 / Duration: 1650ms)
GRUB_INIT_TUNE="400 900 2 1000 2 800 2 400 2 600 3"

## Europe - The Final Countdown (Notes: 10 / Duration: 3375ms)
GRUB_INIT_TUNE="480 554 1 494 1 554 4 370 6 10 3 587 1 554 1 587 2 554 2 494 6"

## Fleetwood Mac: The Chain Bass Riff (Notes: 11 / Duration: 4737ms)
GRUB_INIT_TUNE="304 55 5 0 1 55 1 62 1 65 2 62 1 55 1 49 1 55 1 62 2 41 8"

## Fleetwood Mac: The Chain Bass Riff Extended Version (Notes: 72 / Duration: 25263ms)
GRUB_INIT_TUNE="9120 55 150 0 30 55 30 62 30 65 60 62 30 55 30 49 30 55 30 62 60 41 360 0 120 55 150 0 30 55 30 62 30 65 60 62 30 55 30 49 30 55 30 62 60 41 360 0 60 41 12 42 3 43 3 44 3 45 3 46 6 47 3 48 3 49 6 50 3 51 3 52 6 53 3 54 3 55 150 0 30 55 30 62 30 65 60 62 30 55 30 49 30 55 30 62 60 41 240 82 20 0 10 82 26 0 4 82 26 0 4 82 26 0 4 82 56 0 4 82 60 55 150 0 30 55 30 62 30 65 60 62 30 55 30 49 30 55 30 62 60 41 360 0 120"

## Für Elise (Notes: 35 / Duration: 5875ms)
GRUB_INIT_TUNE="480 420 1 400 1 420 1 400 1 420 1 315 1 370 1 335 1 282 3 180 1 215 1 282 1 315 3 213 1 262 1 315 1 335 3 213 1 420 1 400 1 420 1 400 1 420 1 315 1 370 1 335 1 282 3 180 1 215 1 282 1 315 3 213 1 330 1 315 1 282 3"

## Gorillaz - Fell Good Inc (Notes: 11 / Duration: 4000ms)
GRUB_INIT_TUNE="300 369 2 329 2 82 1 0 2 82 1 92 1 98 1 0 1 130 1 0 1 123 7"

## Guruku Tersayang! (Notes: 29 / Duration: 8911ms)
GRUB_INIT_TUNE="202 493 1 391 1 293 1 493 1 523 1 391 1 329 1 0 1 293 1 369 1 440 1 523 1 523 1 493 1 493 1 0 1 493 1 391 1 293 1 493 1 523 1 391 1 329 1 0 1 293 1 0 1 369 1 0 1 391 2"

## Jurassic Park (Notes: 19 / Duration: 6000ms)
GRUB_INIT_TUNE="240 1047 1 988 1 1047 2 784 1 698 1 0 1 1047 1 988 1 1047 2 784 1 698 1 0 1 1047 1 988 1 1047 2 1175 1 1175 2 1397 1 1397 2"

## Jurassic Park Long (Notes: 39 / Duration: 12500ms)
GRUB_INIT_TUNE="240 1047 1 988 1 1047 2 784 1 698 1 0 1 1047 1 988 1 1047 2 784 1 698 1 0 1 1047 1 988 1 1047 2 1175 1 1175 2 1397 1 1397 2 1319 2 1319 1 1047 1 1175 2 988 1 784 1 0 1 1319 1 1047 1 1175 2 988 1 784 1 0 1 1568 1 1047 1 1397 2 1319 1 1319 2 1175 1 1175 2"

## Macintosh Startup (Notes: 4 / Duration: 1020ms)
GRUB_INIT_TUNE="1000 271 3 331 3 394 3 443 8"

## Mall (Notes: 3 / Duration: 1000ms)
GRUB_INIT_TUNE="180 440 1 554 1 659 1"

## My Little Pony (Notes: 16 / Duration: 4500ms)
GRUB_INIT_TUNE="2400 587 18 554 4 587 8 659 12 587 16 0 10 587 4 659 4 740 8 587 4 784 12 740 8 659 8 587 4 740 20 587 40"

## Oldskool Batman tune (Notes: 5 / Duration: 2368ms)
GRUB_INIT_TUNE="380 120 1 140 1 160 1 200 8 190 4"

## On Wisconsin! (Notes: 4 / Duration: 1600ms)
GRUB_INIT_TUNE="600 294 5 277 2 330 4 294 5"

## Raining Blood (Notes: 15 / Duration: 4875ms)
GRUB_INIT_TUNE="640 165 4 165 4 165 4 554 2 587 2 554 4 370 2 554 2 523 4 349 2 523 2 494 8 165 4 165 4 165 4"

## Shave and a Haircut (Notes: 8 / Duration: 2100ms)
GRUB_INIT_TUNE="400 523 2 392 1 392 1 440 2 392 2 1 2 494 2 523 2"

## Star Wars - Imperial Death March (Notes: 18 / Duration: 8000ms)
GRUB_INIT_TUNE="480 440 4 440 4 440 4 349 3 523 1 440 4 349 3 523 1 440 8 659 4 659 4 659 4 698 3 523 1 415 4 349 3 523 1 440 8"

## Super Mario (Notes: 11 / Duration: 960ms)
GRUB_INIT_TUNE="512 334 1 334 1 0 1 334 1 0 1 261 1 334 1 0 1 392 2 0 2 196 2"

## Super Mario Alternate (Notes: 15 / Duration: 3250ms)
GRUB_INIT_TUNE="480 165 2 165 2 165 3 554 1 587 1 554 2 370 1 554 1 523 2 349 1 523 1 494 3 165 2 165 2 165 2"

## Super Mario Mushroom Powerup (Notes: 25 / Duration: 857ms)
GRUB_INIT_TUNE="1750 523 1 392 1 523 1 659 1 784 1 1047 1 784 1 415 1 523 1 622 1 831 1 622 1 831 1 1046 1 1244 1 1661 1 1244 1 466 1 587 1 698 1 932 1 1185 1 1397 1 1865 1 1397 1"

## Super Mario Coin (Notes: 2 / Duration: 700ms)
GRUB_INIT_TUNE="600 988 1 1319 8"

## The Legend of Zelda Overworld (Notes: 10 / Duration: 3010ms)
GRUB_INIT_TUNE="12000 440 100 0 1 329 150 440 50 0 1 440 25 493 25 523 25 587 25 659 200"

## Totentanz (Notes: 20 / Duration: 11923ms)
GRUB_INIT_TUNE="312 262 3 247 3 262 3 220 3 247 3 196 3 220 3 220 3 262 3 262 3 294 3 262 3 247 3 220 3 196 3 247 3 262 3 247 5 220 1 220 5"

## Twinkle, Twinkle (Notes: 7 / Duration: 1600ms)
GRUB_INIT_TUNE="300 294 1 294 1 440 1 440 1 494 1 494 1 440 2"

## Wolfenstein 3D (Notes: 9 / Duration: 1800ms)
GRUB_INIT_TUNE="300 131 1 196 1 196 1 196 1 294 1 196 1 294 1 196 1 131 1"

## Xiè-jìléi's tune (Notes: 7 / Duration: 630ms)
GRUB_INIT_TUNE="2000 400 4 0 1 500 4 0 1 600 4 0 1 800 6"

##########

## Unknown tune 1 (Notes: 16 / Duration: 2000ms)
GRUB_INIT_TUNE="480 220 1 277 1 330 1 440 1 185 1 220 1 277 1 370 1 294 1 370 1 440 1 587 1 330 1 415 1 494 1 659 1"

## Unknown Tune 2 (Notes: 9 / Duration: 1800ms)
GRUB_INIT_TUNE="300 131 1 196 1 196 1 196 1 294 1 196 1 294 1 196 1 131 1"

## Unknown Tune 3 (Notes: 9 / Duration: 2250ms)
GRUB_INIT_TUNE="480 494 1 523 1 587 2 494 2 523 2 440 2 494 2 392 2 440 4"

## Unknown Tune 4 (Notes: 10 / Duration: 1000ms)
GRUB_INIT_TUNE="1200 270 1 300 1 330 1 360 1 390 1 420 1 450 1 480 1 510 1 540 1 510 1 480 1 450 1 420 1 390 1 360 1 330 1 300 1 270 1"

## Unknown Tune 4 Reversed (Notes: 10 / Duration: 1000ms)
GRUB_INIT_TUNE="1200 540 1 510 1 480 1 450 1 420 1 390 1 360 1 330 1 300 1 270 1 300 1 330 1 360 1 390 1 420 1 450 1 480 1 510 1 540 1"

# Unknown Tune 5
GRUB_INIT_TUNE="512 220 1 277 1 440 1 544 1 493 1 554 1 440 1 311 1 220 1"

##########

## Sounds 1 (Notes: 13 / Duration: 1300ms)
GRUB_INIT_TUNE="600 5400 1 4773 1 4156 1 3559 1 2991 1 2461 1 1977 1 1547 1 1178 1 875 1 644 1 488 1 409 1"

## Sounds 2 (Notes: 50 / Duration: 857ms)
GRUB_INIT_TUNE="3500 5400 1 0 1 4773 1 676 1 4156 1 1342 1 3559 1 1987 1 2991 1 2601 1 2461 1 3174 1 1977 1 3696 1 1547 1 4160 1 1178 1 4559 1 875 1 4886 1 644 1 5135 1 488 1 5304 1 409 1 5389 1 409 1 5389 1 488 1 5304 1 644 1 5135 1 875 1 4886 1 1178 1 4559 1 1547 1 4160 1 1977 1 3696 1 2461 1 3174 1 2991 1 2601 1 3559 1 1987 1 4156 1 1342 1 4773 1 676 1"

## Sounds 3 (Notes: 19 / Duration: 570ms)
GRUB_INIT_TUNE="2000 631 1 1282 1 1972 1 2713 1 3504 1 4297 1 4909 1 4768 1 2332 1 3993 1 4441 1 4493 1 3867 1 179 1 911 1 4999 1 3740 1 1979 1 666 1"

## Sounds 4 (Notes: 33 / Duration: 1483ms)
GRUB_INIT_TUNE="7000 735 7 1823 2 4484 3 1608 2 644 5 2295 2 2117 8 4540 6 3705 5 413 9 2087 5 2000 5 3113 10 4641 2 1787 4 133 2 954 9 2759 8 1053 8 2313 10 3056 8 637 4 512 1 2102 8 4344 1 4542 1 742 10 1789 7 140 10 913 2 3394 1 3792 3 3938 5"

## Sounds 5 (Notes: 52 / Duration: 1523ms)
GRUB_INIT_TUNE="2048 100 1 5400 1 316 1 5184 1 532 1 4968 1 748 1 4752 1 964 1 4536 1 1180 1 4320 1 1396 1 4104 1 1612 1 3888 1 1828 1 3672 1 2044 1 3456 1 2260 1 3240 1 2476 1 3024 1 2692 1 2808 1 2908 1 2592 1 3124 1 2376 1 3340 1 2160 1 3556 1 1944 1 3772 1 1728 1 3988 1 1512 1 4204 1 1296 1 4420 1 1080 1 4636 1 864 1 4852 1 648 1 5068 1 432 1 5284 1 216 1 5500 1 0 1"

## Sounds 6 (Notes: 36 / Duration: 703ms)
GRUB_INIT_TUNE="3072 1100 1 1000 1 1155 1 945 1 1211 1 889 1 1267 1 833 1 1323 1 777 1 1379 1 721 1 1435 1 665 1 1491 1 609 1 1547 1 553 1 1602 1 498 1 1658 1 442 1 1714 1 386 1 1770 1 330 1 1826 1 274 1 1882 1 218 1 1938 1 162 1 1994 1 106 1 2049 1 51 1"
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<title>GRUB Tune Tester</title>
<meta name="description" content="Quick and dirty GRUB tune tester…">
<meta name="author" content="Yunga Palatino (@gmail)">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
*, *::before, *::after {
box-sizing: border-box;
margin: auto;
padding: 0.5em;
font-family: inherit;
font-size: inherit;
}
html {
display: grid;
place-items: center;
width: 100vw;
height: 100vh;
font-family: sans-serif;
line-height: 1.2em;
overflow: hidden;
}
body > *:not(:last-child) {
display: block;
width: 75vw;
}
input:invalid {
font-style: italic;
}
</style>
<label for="juke">Jukebox</label>
<select id="juke">
<option disabled selected value> ~♬~ select a tune ~♬~ </option>
<optgroup label="Tunes">
<option value="480 220 1 277 1 330 1 440 1 185 1 220 1 277 1 370 1 294 1 370 1 440 1 587 1 330 1 415 1 494 1 659 1"> Adams's tune</option>
<option value="480 440 1">Beep</option>
<option value="400 900 2 1000 2 800 2 400 2 600 3">Close Encounters of the Third Kind</option>
<option value="480 554 1 494 1 554 4 370 6 10 3 587 1 554 1 587 2 554 2 494 6">Europe - The Final Countdown </option>
<option value="304 55 5 0 1 55 1 62 1 65 2 62 1 55 1 49 1 55 1 62 2 41 8">Fleetwood Mac: The Chain Bass Riff </option>
<option value="9120 55 150 0 30 55 30 62 30 65 60 62 30 55 30 49 30 55 30 62 60 41 360 0 120 55 150 0 30 55 30 62 30 65 60 62 30 55 30 49 30 55 30 62 60 41 360 0 60 41 12 42 3 43 3 44 3 45 3 46 6 47 3 48 3 49 6 50 3 51 3 52 6 53 3 54 3 55 150 0 30 55 30 62 30 65 60 62 30 55 30 49 30 55 30 62 60 41 240 82 20 0 10 82 26 0 4 82 26 0 4 82 26 0 4 82 56 0 4 82 60 55 150 0 30 55 30 62 30 65 60 62 30 55 30 49 30 55 30 62 60 41 360 0 120"> Fleetwood Mac: The Chain Bass Riff Extended Version</option>
<option value="480 420 1 400 1 420 1 400 1 420 1 315 1 370 1 335 1 282 3 180 1 215 1 282 1 315 3 213 1 262 1 315 1 335 3 213 1 420 1 400 1 420 1 400 1 420 1 315 1 370 1 335 1 282 3 180 1 215 1 282 1 315 3 213 1 330 1 315 1 282 3"> Für Elise</option>
<option value="300 369 2 329 2 82 1 0 2 82 1 92 1 98 1 0 1 130 1 0 1 123 7">Gorillaz - Fell Good Inc</option>
<option value="202 493 1 391 1 293 1 493 1 523 1 391 1 329 1 0 1 293 1 369 1 440 1 523 1 523 1 493 1 493 1 0 1 493 1 391 1 293 1 493 1 523 1 391 1 329 1 0 1 293 1 0 1 369 1 0 1 391 2"> Guruku Tersayang!</option>
<option value="240 1047 1 988 1 1047 2 784 1 698 1 0 1 1047 1 988 1 1047 2 784 1 698 1 0 1 1047 1 988 1 1047 2 1175 1 1175 2 1397 1 1397 2"> Jurassic Park</option>
<option value="240 1047 1 988 1 1047 2 784 1 698 1 0 1 1047 1 988 1 1047 2 784 1 698 1 0 1 1047 1 988 1 1047 2 1175 1 1175 2 1397 1 1397 2 1319 2 1319 1 1047 1 1175 2 988 1 784 1 0 1 1319 1 1047 1 1175 2 988 1 784 1 0 1 1568 1 1047 1 1397 2 1319 1 1319 2 1175 1 1175 2"> Jurassic Park Long</option>
<option value="1000 271 3 331 3 394 3 443 8">Macintosh Startup</option>
<option value="180 440 1 554 1 659 1">Mall</option>
<option value="2400 587 18 554 4 587 8 659 12 587 16 0 10 587 4 659 4 740 8 587 4 784 12 740 8 659 8 587 4 740 20 587 40"> My Little Pony</option>
<option value="380 120 1 140 1 160 1 200 8 190 4">Oldskool Batman tune</option>
<option value="600 294 5 277 2 330 4 294 5">On Wisconsin!</option>
<option value="640 165 4 165 4 165 4 554 2 587 2 554 4 370 2 554 2 523 4 349 2 523 2 494 8 165 4 165 4 165 4"> Raining Blood</option>
<option value="400 523 2 392 1 392 1 440 2 392 2 1 2 494 2 523 2">Shave and a Haircut - Shampoo</option>
<option value="480 440 4 440 4 440 4 349 3 523 1 440 4 349 3 523 1 440 8 659 4 659 4 659 4 698 3 523 1 415 4 349 3 523 1 440 8"> Star Wars - Imperial Death March</option>
<option value="512 334 1 334 1 0 1 334 1 0 1 261 1 334 1 0 1 392 2 0 2 196 2">Super Mario</option>
<option value="480 165 2 165 2 165 3 554 1 587 1 554 2 370 1 554 1 523 2 349 1 523 1 494 3 165 2 165 2 165 2"> Super Mario Alternate</option>
<option value="1750 523 1 392 1 523 1 659 1 784 1 1047 1 784 1 415 1 523 1 622 1 831 1 622 1 831 1 1046 1 1244 1 1661 1 1244 1 466 1 587 1 698 1 932 1 1185 1 1397 1 1865 1 1397 1"> Super Mario Mushroom Powerup</option>
<option value="600 988 1 1319 8">Super Mario Coin</option>
<option value="312 262 3 247 3 262 3 220 3 247 3 196 3 220 3 220 3 262 3 262 3 294 3 262 3 247 3 220 3 196 3 247 3 262 3 247 5 220 1 220 5"> Berlioz's extract from Sabbath Night of Symphonie Fantastique</option>
<option value="300 294 1 294 1 440 1 440 1 494 1 494 1 440 2">Twinkle, Twinkle</option>
<option value="300 131 1 196 1 196 1 196 1 294 1 196 1 294 1 196 1 131 1">Wolfenstein 3D</option>
<option value="2000 400 4 0 1 500 4 0 1 600 4 0 1 800 6">Xiè-jìléi's tune</option>
<option value="12000 440 100 0 1 329 150 440 50 0 1 440 25 493 25 523 25 587 25 659 200">Zelda - Overworld</option>
</optgroup>
<optgroup label="Unkown Tunes">
<option value="480 220 1 277 1 330 1 440 1 185 1 220 1 277 1 370 1 294 1 370 1 440 1 587 1 330 1 415 1 494 1 659 1"> Unknown tune 1</option>
<option value="300 131 1 196 1 196 1 196 1 294 1 196 1 294 1 196 1 131 1">Unknown Tune 2</option>
<option value="480 494 1 523 1 587 2 494 2 523 2 440 2 494 2 392 2 440 4">Unknown Tune 3</option>
<option value="1200 270 1 300 1 330 1 360 1 390 1 420 1 450 1 480 1 510 1 540 1 510 1 480 1 450 1 420 1 390 1 360 1 330 1 300 1 270 1"> Unknown Tune 4</option>
<option value="1200 540 1 510 1 480 1 450 1 420 1 390 1 360 1 330 1 300 1 270 1 300 1 330 1 360 1 390 1 420 1 450 1 480 1 510 1 540 1"> Unknown Tune 4 Reversed</option>
<option value="512 220 1 277 1 440 1 544 1 493 1 554 1 440 1 311 1 220 1">Unknown Tune 5</option>
</optgroup>
<optgroup label="Random Sounds">
<option value="600 5400 1 4773 1 4156 1 3559 1 2991 1 2461 1 1977 1 1547 1 1178 1 875 1 644 1 488 1 409 1"> Sounds 1 </option>
<option value="3500 5400 1 0 1 4773 1 676 1 4156 1 1342 1 3559 1 1987 1 2991 1 2601 1 2461 1 3174 1 1977 1 3696 1 1547 1 4160 1 1178 1 4559 1 875 1 4886 1 644 1 5135 1 488 1 5304 1 409 1 5389 1 409 1 5389 1 488 1 5304 1 644 1 5135 1 875 1 4886 1 1178 1 4559 1 1547 1 4160 1 1977 1 3696 1 2461 1 3174 1 2991 1 2601 1 3559 1 1987 1 4156 1 1342 1 4773 1 676 1"> Sounds 2</option>
<option value="2000 631 1 1282 1 1972 1 2713 1 3504 1 4297 1 4909 1 4768 1 2332 1 3993 1 4441 1 4493 1 3867 1 179 1 911 1 4999 1 3740 1 1979 1 666 1"> Sounds 3</option>
<option value="7000 735 7 1823 2 4484 3 1608 2 644 5 2295 2 2117 8 4540 6 3705 5 413 9 2087 5 2000 5 3113 10 4641 2 1787 4 133 2 954 9 2759 8 1053 8 2313 10 3056 8 637 4 512 1 2102 8 4344 1 4542 1 742 10 1789 7 140 10 913 2 3394 1 3792 3 3938 5"> Sounds 4</option>
<option value="2048 100 1 5400 1 316 1 5184 1 532 1 4968 1 748 1 4752 1 964 1 4536 1 1180 1 4320 1 1396 1 4104 1 1612 1 3888 1 1828 1 3672 1 2044 1 3456 1 2260 1 3240 1 2476 1 3024 1 2692 1 2808 1 2908 1 2592 1 3124 1 2376 1 3340 1 2160 1 3556 1 1944 1 3772 1 1728 1 3988 1 1512 1 4204 1 1296 1 4420 1 1080 1 4636 1 864 1 4852 1 648 1 5068 1 432 1 5284 1 216 1 5500 1 0 1"> Sounds 5</option>
<option value="3072 1100 1 1000 1 1155 1 945 1 1211 1 889 1 1267 1 833 1 1323 1 777 1 1379 1 721 1 1435 1 665 1 1491 1 609 1 1547 1 553 1 1602 1 498 1 1658 1 442 1 1714 1 386 1 1770 1 330 1 1826 1 274 1 1882 1 218 1 1938 1 162 1 1994 1 106 1 2049 1 51 1"> Sounds 6</option>
</optgroup>
</select>
<label for="knob">Volume</label>
<input id="knob" type="range" min="0" max="10000" value="2500">
<label for="tune">GRUB_INIT_TUNE=</label>
<input id="tune" autofocus placeholder="BPM NOTE_in_Hz DURATION_in_Beats [NOTE DURATION]…" inputmode="numeric" pattern="\s*[0-9]+(\s+[0-9]+\s+[0-9]+){1,}\s*">
<label id="info">Notes: <br> Duration:</label>
<button id="play">Play</button>
<button id="copy">Copy</button>
<div>
<script>
// Inputs
const juke = document.getElementById(`juke`);
const tune = document.getElementById(`tune`);
const knob = document.getElementById(`knob`);
const info = document.getElementById(`info`);
const play = document.getElementById(`play`);
const copy = document.getElementById(`copy`);
// Don't display the copy button if the clipboard isn't available
if (!navigator.clipboard) copy.style.display = `none`;
// Add events
juke.addEventListener(`change`, jukeChange);
tune.addEventListener(`keyup`, event => processTune(/^(?:Enter|NumpadEnter)$/.test(event.code)));
play.addEventListener(`click`, processTune);
copy.addEventListener(`click`, () => navigator.clipboard?.writeText(`GRUB_INIT_TUNE="${tune.value.replace(/\s+$/, '').split(/\s+/).filter(t => t !== ``).join(' ')}"`));
function jukeChange() {
// A new tune as been selected in the combobox...
tune.value = juke.value;
processTune(true);
}
function processTune(shouldPlay) {
// Quick and dirty validity check:
// Only space and numbers allowed, an odd number of tokens, and at least 3 of them
let isTuneValid = false;
let token = tune.value.replace(/[^ 0-9]+/g, ``).split(/\s+/).filter(t => t !== ``);
if (token.length % 2 === 1 && token.length >= 3) isTuneValid = true;
// Give some validity feedback, eventually update and play the tune
if (isTuneValid) {
let TUNE = parse(token);
tune.style.color = `blue`;
info.innerHTML = `Notes: ${TUNE.partition.length} <br> Duration: ${Math.round((TUNE.duration + Number.EPSILON) * 1000) / 1000}s`;
play.disabled = false;
if (shouldPlay) {
tune.value = token.join(` `);
playTune(TUNE);
}
} else {
tune.style.color = `red`;
info.innerHTML = `Notes: <br> Duration:`;
play.disabled = true;
}
}
function parse(GRUB_INIT_TUNE) {
// Tune format: TEMPO_IN_BPM NOTE_FREQUENCY_IN_HZ DURATION_IN_BEATS [NOTE DURATION]…
let TUNE = {
tempo: GRUB_INIT_TUNE[0], // Original tempo in bpm
beat: 60 / GRUB_INIT_TUNE[0], // Duration of a beat in seconds
duration: 0, // Duration of the tune in seconds
partition: []
};
for (let i = 1; i < GRUB_INIT_TUNE.length; i += 2) {
TUNE.partition.push({
frequency: GRUB_INIT_TUNE[i + 0], // Note Frequency
beats: GRUB_INIT_TUNE[i + 1], // Number of beats
duration: GRUB_INIT_TUNE[i + 1] * TUNE.beat // Duration in seconds
});
TUNE.duration += GRUB_INIT_TUNE[i + 1] * TUNE.beat;
}
return TUNE;
}
function playTune(TUNE) {
disableInput(true);
// audio <- volume <== oscillators
let audio = new AudioContext();
let volume = audio.createGain();
volume.gain.value = knob.value / 10000;
volume.connect(audio.destination);
// Schedule each note with oscillators
let lastNote = TUNE.partition.length - 1;
let time = audio.currentTime;
for (let i = 0; i <= lastNote; i++) {
let oscillator = audio.createOscillator();
oscillator.type = `square`; // sine sawtooth triangle
oscillator.frequency.value = TUNE.partition[i].frequency;
oscillator.start(time);
oscillator.stop(time += TUNE.partition[i].duration);
oscillator.connect(volume);
// Reenable inputs when the last oscillator is done
if (i === lastNote) oscillator.onended = () => disableInput(false);
}
}
function disableInput(status) {
juke.disabled = tune.disabled = knob.disabled = info.disabled = play.disabled = copy.disabled = status;
}
</script>
</div>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment