It is now possible to node melodies on E2!

tempo=240
72 0 0 67 69 67

(I just infringed copyright; see Yes! We have no bananas! for details)

When you see a sequence of numbers like this in a lyrics write-up, it's probably a melody. To play back melodies on DOS and Windows machines, paste the melody into a new text file and run this program on the text file. For a PC speaker version, compile the source listed below with DJGPP; it should also work on Borland Turbo C but I haven't tried it. It can also talk to the cross-platform Allegro library.

Yes, I know it sucks and Lilypond is better, but it was a start...

The melody metanode

Changelog

  • April 20, 2001: add interface to Allegro. Now it should work on Win32, UNIX, and BeOS.

To do

  • Support human-readable note names
  • Interface with Lilypond as an exit strategy

Source of the E2 melody playback program

Don't want to compile it? Get a DOS binary at http://www.cs.rose-hulman.edu/~yerricde/e2midi.zip


/**************************************\
* e2midi.c                             *
* Everything MIDI note playback tool   *
* For Borland Turbo C++ and DJGPP      *
*                                      ********************************\
* Copyright 2000 Damian Yerrick                                        *
*                                                                      *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or    *
* (at your option) any later version.                                  *
*                                                                      *
* This program is distributed in the hope that it will be useful,      *
* but WITHOUT ANY WARRANTY; without even the implied warranty of       *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
* GNU General Public License for more details.                         *
*                                                                      *
* You should have received a copy of the GNU General Public License    *
* along with this program; if not, write to the Free Software          *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
* Or view the License online at http://www.gnu.org/copyleft/gpl.html   *
*                                                                      *
* Damian Yerrick's World Wide Web pages are located at                 *
*   http://www.PinEight.com                                            *
*                                                                      *
\**********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#define USE_CONSOLE

/* Uncomment one of these: */

#include <allegro.h>
/* #include <dos.h> */

#ifdef ALLEGRO_VERSION

int last_note = 0;

void sound_note(int midiNote)
{
  if(last_note)
  {
    char midi_event[3] = {0x90, last_note, 0}; /* note off */

    midi_out(midi_event, sizeof(midi_event));
  }
  last_note = midiNote;
  if(midiNote)
  {
    char midi_event[3] = {0x90, midiNote, 100}; /* note on */

    midi_out(midi_event, sizeof(midi_event));
  }
}

#else

void sound_note(int midiNote)
{
  static const unsigned int SoundNote_freq[12] =
  {523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988};
  int freq;

  if(midiNote == 0)
  {
    nosound();
    return;
  }
  // Find pitch within this octave.
  freq = SoundNote_freq[midiNote % 12];

  // If we have a low note, move it down an octave at a time.
  while(midiNote < 72)
  {
    freq >>= 1;
    midiNote += 12;
  }

  // If we have a high note, move it up an octave at a time.
  while(midiNote >= 84)
  {
    freq <<= 1;
    midiNote -= 12;
  }

  sound(freq);
}

#endif

int getno(const char *tok)
{
  if(!isdigit(tok[0]))
    return -1;
  return strtol(tok, NULL, 10);
}

int main(const int argc, const char **argv)
{
  unsigned int filesPlayed = 0;
  int arg = 0;
  FILE *fp;
  const char *tok;
  char linebuf[512];
  int n;

  int duration = 125; /* milliseconds for default tempo=480 */

#ifdef ALLEGRO_VERSION
  allegro_init();
  install_timer();
  install_keyboard();
  install_sound(DIGI_NONE, MIDI_AUTODETECT, NULL);
#endif

  while(++arg < argc)
  {
    fp = fopen(argv[arg], "rt"); /* try to open the file */
    if(fp != 0)
    {
      printf("#%d: %s", filesPlayed++, argv[arg]);

      /* read lines from the file */
      while(fgets(linebuf, sizeof(linebuf), fp) != 0)
      {
        for(tok = strtok(linebuf, " ,\r\n"); tok != 0; tok = strtok(0, " ,\r\n"))
        {
          /* look for numbers */
          if(memcmp("tempo=", tok, 6) == 0)
          {
            n = getno(tok + 6);
            if(n > 5)
              duration = (int)(60000L / n);
          }
          else
          {
            n = getno(tok);
            if(n >= 0)
            {
              sound_note(n);
#ifdef ALLEGRO_VERSION
              rest(duration);
#else
              delay(duration);
#endif
            }
          }
        }
      }

      fclose(fp);
      sound_note(0);
    }
  }

  if(filesPlayed == 0)
  {
    fputs("e2midi: play back a melody noded on E2\n"
          "syntax: e2midi foo.txt", stderr);
  }

  return 0;
}
#ifdef ALLEGRO_VERSION
END_OF_MAIN();
#endif

(back to) Everything University