FREE THOUGHT · FREE SOFTWARE · FREE WORLD

GRUB_INIT_TUNE – Play sound through pcspkr

GRUB_INIT_TUNE

Grub Boot Menu for TunesPlay a tune directly on your pcspeaker right before the grub boot manager loads. See also: https://wiki.archlinux.org/index.php/GRUB/Tips_and_tricks#Play_a_tune

Set using env variable in grub.cfg

GRUB_INIT_TUNE

Play a specific set of frequencies for specific lengths on the machine speaker when GRUB starts. This is particularly useful for cases when you'd like to know when a reboot happens. The value is passed directly to play.

91_tunes grub config file

Grub for playing music in speaker

It's easy to play sounds on boot with GRUB. Here is a sample file you can save as /etc/grub.d/91_tunes, run grub2-mkconfig -o /boot/grub.cfg and reboot, then select "Tunes Test" to sample the various tunes.

#!/bin/sh

exec tail -n +3 $0
menuentry "Tunes Test" {
background_color "#FF9933"
echo "Close Encounters/5 Tone"
sleep 1
play 480 900 2 1000 2 800 2 400 2 600 3

background_color "#FF9900"
echo "Fur Elise (note long)"
sleep 1
play 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

background_color "#FF66FF"
echo "Totentanz"
sleep 1
play 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

background_color "#FF66CC"
echo "Oldskool Batman tune"
sleep 1
play 380 120 1 140 1 160 1 200 8 190 4

background_color "#FF6699"
echo "Legend of Zelda tune"
sleep 1
play 12000 440 100 0 1 329 150 440 50 0 1 440 25 493 25 523 25 587 25 659 200

background_color "#FF6666"
echo "Super Mario"
sleep 1
play 1000 334 1 334 1 0 1 334 1 0 1 261 1 334 1 0 1 392 2 0 4 196 2

background_color "#FF6633"
echo "Super Mario Alternate"
sleep 1
play 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

background_color "#FF6600"
echo "Mario Mushroom"
sleep 1
play 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 1175 1 1397 1 1865 1 1397 1

background_color "#FF33FF"
echo "Star Wars Imperial Death March"
sleep 1
play 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

background_color "#FF33CC"
echo "My Little Pony"
sleep 1
play 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

background_color "#FF3399"
echo "Wolfenstein 3D"
sleep 1
play 300 131 1 196 1 196 1 196 1 294 1 196 1 294 1 196 1 131 1

background_color "#FF3366"
echo "Mall (Nothing Special)"
sleep 1
play 180 440 1 554 1 659 1

background_color "#FF3333"
echo "Final Countdown"
sleep 1
play 480 554 1 494 1 554 4 370 6 10 3 587 1 554 1 587 2 554 2 494 6

background_color "#FF3300"
echo "Xie-Jelei's Tune"
sleep 1
play 2000 400 4 0 1 500 4 0 1 600 4 0 1 800 6

background_color "#FF00FF"
echo "Random tune"
sleep 1
play 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

background_color "#FF00CC"
echo "Fleetwood Mac: The Chain Bass Riff (about 5 seconds)"
sleep 1
play 304 55 5 0 1 55 1 62 1 65 2 62 1 55 1 49 1 55 1 62 2 41 8

background_color "#FF0099"
echo "Fleetwood Mac: The Chain Bass Riff Extended Version (WARNING, 25 SECONDS)"
sleep 1
play 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

background_color "#000000"
}

GRUB play

This is what plays the sounds - note much of this code was borrowed from the GNU/Hurd generic-speaker driver

Command: play file | tempo [pitch1 duration1] [pitch2 duration2] …

Plays a tune
Format is first the tempo as an unsigned 32bit little-endian number, then pairs of unsigned 16bit little-endian numbers for pitch and duration pairs.

The tempo is the base for all note durations. 60 gives a 1-second base, 120 gives a half-second base, etc. Pitches are Hz. Set pitch to 0 to produce a rest.

play.c GRUB source

More on github at play.c

/* play.c - command to play a tune  */

#include <grub/dl.h>
#include <grub/file.h>
#include <grub/disk.h>
#include <grub/term.h>
#include <grub/misc.h>
#include <grub/cpu/io.h>
#include <grub/command.h>
#include <grub/i18n.h>
#include <grub/time.h>
#include <grub/speaker.h>

GRUB_MOD_LICENSE ("GPLv3+");

#define BASE_TEMPO (60 * 1000)

#define T_REST      ((grub_uint16_t) 0)
#define T_FINE      ((grub_uint16_t) -1)

struct note
{
  grub_uint16_t pitch;
  grub_uint16_t duration;
};

/* Returns whether playing should continue.  */
static int
play (unsigned tempo, struct note *note)
{
  grub_uint64_t to;

  if (note->pitch == T_FINE || grub_getkey_noblock () != GRUB_TERM_NO_KEY)
    return 1;

  grub_dprintf ("play", "pitch = %d, duration = %d\n", note->pitch,
                note->duration);

  switch (note->pitch)
    {
      case T_REST:
        grub_speaker_beep_off ();
        break;

      default:
        grub_speaker_beep_on (note->pitch);
        break;
    }

  to = grub_get_time_ms () + BASE_TEMPO * note->duration / tempo;
  while ((grub_get_time_ms () <= to)
   && (grub_getkey_noblock () == GRUB_TERM_NO_KEY));

  return 0;
}

static grub_err_t
grub_cmd_play (grub_command_t cmd __attribute__ ((unused)),
         int argc, char **args)
{

  if (argc < 1)
    return grub_error (GRUB_ERR_BAD_ARGUMENT, 
           /* TRANSLATORS: It's musical notes, not the notes
        you take. Play command expects arguments which can
        be either a filename or tempo+notes.
        This error happens if none is specified.  */
           N_("filename or tempo and notes expected"));

  if (argc == 1)
    {
      struct note buf;
      grub_uint32_t tempo;
      grub_file_t file;

      file = grub_file_open (args[0]);

      if (! file)
        return grub_errno;

      if (grub_file_read (file, &tempo, sizeof (tempo)) != sizeof (tempo))
        {
          grub_file_close (file);
    if (!grub_errno)
      grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
      args[0]);
          return grub_errno;
        }

      if (!tempo)
        {
          grub_file_close (file);
    grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid tempo in %s"),
          args[0]);
          return grub_errno;
        }

      tempo = grub_le_to_cpu32 (tempo);
      grub_dprintf ("play","tempo = %d\n", tempo);

      while (grub_file_read (file, &buf,
                             sizeof (struct note)) == sizeof (struct note))
        {
          buf.pitch = grub_le_to_cpu16 (buf.pitch);
          buf.duration = grub_le_to_cpu16 (buf.duration);

          if (play (tempo, &buf))
            break;
        }

      grub_file_close (file);
    }
  else
    {
      char *end;
      unsigned tempo;
      struct note note;
      int i;

      tempo = grub_strtoul (args[0], &end, 0);

      if (!tempo)
        {
    grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid tempo in %s"),
          args[0]);
          return grub_errno;
        }

      if (*end)
        /* Was not a number either, assume it was supposed to be a file name.  */
        return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), args[0]);

      grub_dprintf ("play","tempo = %d\n", tempo);

      for (i = 1; i + 1 < argc; i += 2)
        {
          note.pitch = grub_strtoul (args[i], &end, 0);
    if (grub_errno)
      break;
          if (*end)
            {
              grub_error (GRUB_ERR_BAD_NUMBER, N_("unrecognized number"));
              break;
            }

          note.duration = grub_strtoul (args[i + 1], &end, 0);
    if (grub_errno)
      break;
          if (*end)
            {
              grub_error (GRUB_ERR_BAD_NUMBER, N_("unrecognized number"));
              break;
            }

          if (play (tempo, &note))
            break;
        }
    }

  grub_speaker_beep_off ();

  return 0;
}

static grub_command_t cmd;

GRUB_MOD_INIT(play)
{
  cmd = grub_register_command ("play", grub_cmd_play,
             N_("FILE | TEMPO [PITCH1 DURATION1] [PITCH2 DURATION2] ... "),
             N_("Play a tune."));
}

GRUB_MOD_FINI(play)
{
  grub_unregister_command (cmd);
}

Linux GRUB GRUB_INIT_TUNE grub.cfg speaker

Comments