/* ******************************************************************** */
/*                                                                      */
/* midi-test-gen.c                         Generates a test tune in ABC */
/*                                                                      */
/* This C program writes an ABC melody to stdout, which can then be     */
/* used with 'abc2midi' to create a MIDI file in which each instrument  */
/* (numbers 0 to 131) plays its instrument-number as a binary sequence  */
/* of eight tones:  0 == middle-C, 1 == A 21 semitones higher.  Notes   */
/* are provided as "lyrics" printed at the bottom of the last page,     */
/* just in case anyone runs the file through any of the various ABC     */
/* typesetting or viewing programs.  (A little more info is provided in */
/* "history" fields, just to have a convenient place for a little more  */
/* documentation in case the binary or its output find their ways out   */
/* into the wild.)                                                      */
/*                                                                      */
/* USAGE:                                                               */
/*    cc -o midi-test-gen midi-test-gen.c                               */
/*    ./midi-test-gen > miditest.abc                                    */
/*    abc2midi miditest.abc -o miditest.mid                             */
/*                                                                      */
/* Then play the 'miditest.mid' file through whatever MIDI program or   */
/* device you want to hear the instrument list of.                      */
/*                                                                      */
/* (Yeah, I could have made it open a file to write to then exec        */
/* abc2midi on that file, but I decided to spend that energy writing    */
/* comments instead.)                                                   */
/*                                                                      */
/* REVISION HISTORY:                                                    */
/* 2005-11-17   DGA   Wrote first draft, and used it.                   */
/* 2005-11-18   DGA   Added comments, added explanation to output.      */
/*                                                                      */
/* ******************************************************************** */

#include <stdio.h>

/* Make sure this ID string appears in the executable in case someone   */
/* finds a copy of the binary and wonders where it came from.  *shrug*  */
/* Ya never know ...                                                    */
 
static char version_id[] = "$Id: midi-test-gen.c, v1.0, 2005-11-18, D. Glenn Arthur Jr., http://www.radix.net/~dglenn/code/midi-test-gen.c $";

int main( int argc , char **argv )
	{
	int counter;        /* Just what it sounds like.                     */
	char melody[9];     /* String of eight note values, plus terminator. */

	/* Really simple version & usage garbage.  If there are any command  */
	/* line arguments, the user probably doesn't know what this is.  So  */
	/* let's be helpful (and point them to my web site for good measure  */
	/* while we're at it).                                               */

	if ( argc > 1 )
		if ( (strcmp(argv[1], "-v") == 0) || (strcmp(argv[1], "-V") == 0))
			{
			printf("%s\n", version_id);
			exit(1);
			}
		else
			{
			printf("\nUsage:\n");
			printf("  %s > [filename].abc\n", argv[0]);
			printf("  abc2midi [filename].abc -o [filename].mid\n");
			printf("(then play the MIDI file).\n\n");
			printf("For version info:\n");
			printf("  %s -v\n", argv[0]);
			printf("For an explanation of what this is for:\n");
			printf("  %s | grep '[WHN]:' | sed -e 's/^.://' | more\n\n", 
							argv[0]);
			exit(1);
			}

	/* Okay, all done with the cutesy; on to the main event.             */
	

	/* Print the ABC tune header.                                        */

	printf("%% This file isn't actually meant to be typset.  ");
	printf("See notes in W fields for info.\n");
 	printf("X:999\n");
	printf("T:Midi Instrument Test\n");
	printf("C:D. Glenn Arthur Jr.\n");
	printf("Z:Automatically generated by midi-test-gen.c\n");
	printf("H:This is the output of the midi-test-gen program \n");
	printf("H:(at http://www.radix.net/~dglenn/code/midi-test-gen.c if you\n");
	printf("H:want a peek at the code).  It's in ABC notation -- if that\n");
	printf("H:is unfamiliar, see http://abc.sourceforge.net/resources.html\n");
	printf("H:for links to explanations, relevant software, and if you're\n");
	printf("H:in the market for sheet music, a starting point for finding\n");
	printf("H:the thousands of tunes available in this notation online.\n");
	printf("H:\n");
	printf("W:Each measure plays in the MIDI instrument corresponding\n");
	printf("W:to the (zero-based) measure number, which is also encoded\n");
	printf("W:in the note pattern for the measure.  When listening to\n");
	printf("W:the MIDI file generated from this, one can thus hear the\n");
	printf("W:mapping of instrument sounds to instrument numbers, as long.\n");
	printf("W:as one is halfway decent at counting in binary.\n");
	printf("N:(If anyone feels like sending me a routine to output Morse\n");
	printf("N:code instead, I'll make that a command-line option.)\n");
	printf("W:At 70 beats per minute, it plays for about eleven minutes.\n");
	printf("W:\n");
	printf("W:This is one tune that should not need measure numbers\n");
	printf("W:above the staff (it's not even really meant to be printed\n");
	printf("W:out), but if you want 'em, I suggest typesetting this file\n");
	printf("W:using the '-b0' option to abcm2ps so that the printed\n");
	printf("W:measure numbers are zero-based as well.\n");
	printf("W:\n");
	printf("W:dglenn@radix.net\n");
	printf("M:6/8\n");
	printf("L:1/16\n");
	printf("Q:1/8=70\n");
	printf("K:C\n");
	
	/* Initialize the melody string to CCCCCCCC (eight 16th-notes of     */
	/* middle-C) to represent 00000000(two).  Add the null-terminator.   */

	for (counter=0 ; counter<8 ; counter++)
		melody[counter]='C';
	melody[8]='\0';

	/* Start counting from zero in binary ... Print the first value, the */
	/* zero, outside the loop so that the loop is nothing more than "add */
	/* one and carry", without my having to be awake enough to start at  */
	/* -1 and have the loop increment that to 0 on the first pass.       */

	counter=0;

	printf ("%%%%MIDI program %d\n  %s z4 | \\\n", counter, melody);
	
	/* (If that pritnf() doesn't make sense, go read the ABC notation    */
	/* standard.)                                                        */

	/* Now do the promised "add one and carry" loop from 1 to 131.  Why  */
	/* 131?  Because that way if someone does print out the sheet music, */
	/* at either 4 or 6 measures per line, it will come out even on the  */
	/* page, and I wanted to go to at least 128 because the list I've    */
	/* got numbers 'em from 1 to 128 instead of 0 to 127, and that's     */
	/* part of what I was checking.  (Silly of me perhaps, but having a  */
	/* lone measure sticking out at the end of the last page bothered me */
	/* even if the output of this program isn't really inteded to ever   */
	/* be printed.)  If your device has more than 128 instruments, just  */
	/* change it in the for() statement here.                            */
	
	/* Do the loop the brute-force way because I was half asleep when I  */
	/* wrote it.  (If the last byte of the melody is a 'C' -- "zero" --  */
	/* set it to 'a' -- "one".  If it was already an 'a', set it to 'C'  */
	/* and repeat the logic on the byte to the left.  This should really */
	/* just do eight shift-and-tests on the counter variable to fill the */
	/* string, but as I mentioned, I was half asleep.                    */

	for (counter=1 ; counter<132 ; counter++)
		{
		if (melody[7]=='C')
			melody[7]='a';
		else
			{
			melody[7]='C';
			if (melody[6]=='C')
				melody[6]='a';
			else
				{
				melody[6]='C';
				if (melody[5]=='C')
					melody[5]='a';
				else
					{
					melody[5]='C';
					if (melody[4]=='C')
						melody[4]='a';
					else
						{
						melody[4]='C';
						if (melody[3]=='C')
							melody[3]='a';
						else
							{
							melody[3]='C';
							if (melody[2]=='C')
								melody[2]='a';
							else
								{
								melody[2]='C';
								if (melody[1]=='C')
									melody[1]='a';
								else
									{
									melody[1]='C';
									melody[0]='a';
									}
								}
							}
						}
					}
				}
			}
		
		/* Print the resulting string, preceeded by a MIDI instrument    */
		/* change command and followed by a rest and a bar line.         */

		printf ("%%%%MIDI program %d\n  %s z4 | \\\n", counter, melody);
		}
	
	/* C'est tout. At this point I've spent about three times as long on */
	/* the internal documentation as I did writing the code itself.      */

	}
