>From saf  Tue Jun 16 10:27:35 1987 remote from moss
Date: 16 Jun 87 10:27:35 EDT (Tue)
From: saf@moss.ATT.COM (Steve Falco)
==========================================================================
The following program generates the next generation of a 0L grammer.  To
get the initial (level 0) string, say:

	fib < /dev/null > f0

Subsequent generations are gotten by:

	fib < f0 > f1 ; fib < f1 > f2 ; etc.

You can change the ARULE and BRULE lines as per the examples in P.S.Langstons
paper and recompile to make other strings.  (I tried "smith" last night - it
sounds neat!)

==========================================fib.c=============================
#include <stdio.h>

#define AXIOM "a"	/* the starting state */
#define ARULE "b"	/* production for "a" */
#define BRULE "(a)[b]"	/* production for "b" */

int anyprint = 0;

main()
{
	int c;
	
	while((c = getchar()) != EOF) {
		switch(c) {
			case '\n': /* ignored */
				continue;
			case 'a':
				printf(ARULE);
				anyprint++;
				break;
			case 'b':
				printf(BRULE);
				anyprint++;
				break;
			default:
				printf("%c", c);
				anyprint++;
				break;
		}
		if(!(anyprint % 10)) { /* hack to keep the lines short */
			printf("\n");
		}
	}
	if(!anyprint) { /* didn't print anything so this is generation 0 */
		printf(AXIOM);
	}

	printf("\n");
	exit(0);
}
=========================================end==============================
Next, you need to interpret the grammer.  The following program does that
in a manner similar to PSL's approach.  I have tried a few extensions:
Have the bracket symbols "<" and ">" manipulate a new variable (branch2)
and let it select voices. (You have to modify the grammers to include <> also.)
Wow!  Run it as:

	interp < f10 > f10.phr

====================================interp.c==============================
#include <stdio.h>

char *notes[][4] = { /* some random phrases (key of C sort-of) */
	{"co3", "eo3", "go3", "co4"},
	{"e-o3", "b-o3", "co3", "a-o3"},
	{"ao3", "co3", "fo3", "go3"},
	{"co4", "fo3", "go3", "bo3"},
	{"ao3", "eo3", "go3", "ao3"},
	{"fo3", "co3", "e-o3", "fo3"},
	{"go3", "go3", "do3", "fo3"},
	{"bo3", "a-o3", "g-o3", "eo3"},
	{"co3", "ao3", "co3", "ao3"},
	{"co3", "eo4", "go4", "co4"},
	{"e-o4", "b-o4", "co4", "a-o4"},
	{"ao4", "co3", "fo3", "go3"},
	{"co4", "fo3", "go3", "bo3"},
	{"ao4", "eo3", "go4", "ao3"},
	{"fo3", "co3", "e-o3", "fo3"},
	{"go4", "go4", "do3", "fo3"},
	{"bo4", "a-o4", "g-o3", "eo3"},
	{"co3", "ao3", "co4", "ao4"},
	{"co3", "c+o3", "do3", "d+o3"}
};

int notesize = sizeof(notes) / (4 * sizeof(char *));

/* 24 = whole beat		*/
/* 12 = half beat		*/
/* 8  = third beat (triplets)	*/
/* 6  = quarter beat		*/
/* 4  = sixth beat (triplets)	*/
/* 3  = eighth beat		*/

int times[][4] = { /* some random rhythmic patterns */
	{8, 8, 8, 0},
	{0, 8, 8, 8},
	{6, 6, 6, 6},
	{24, 0, 0, 0},
	{0, 12, 12, 0},
	{6, 6, 12, 0},
	{3, 3, 6, 12},
	{12, 6, 3, 3},
	{18, 0, 0, 3},
	{4, 4, 4, 12}
};

int rhysize = sizeof(times) / (4 * sizeof(int));

int now = 0;    /* cumulative time in clicks */
int branch = 0; /* really nesting depth of brackets */

main()
{
	int c;
	
	while((c = getchar()) != EOF) {
		switch(c) {
			case '\n':	/* ignored */
				break;
			case '[':
			case '(':
			case '{':
			case '<':
				branch++; /* deeper */
				break;
			case ']':
			case ')':
			case '}':
			case '>':
				branch--; /* shallower */
				break;
			default:
				gennote(c, branch); /* hit a non-terminal */
				break;
		}
	}
	
	exit(0);
}

gennote(c, b)
	int c, b;
{
	int i, j, k;
	
	/* select a phrase and duration - rather ad-hoc */
	i = ((c - 'a' + 1) * b) % notesize;
	j = b % rhysize;
	
	for(k = 0; k < 4; k++) {
		if(times[j][k] == 0) { /* skip zero duration notes */
			continue;
		}

		/* print it in keynote format */
		printf("%sd%dt%d\n", notes[i][k], times[j][k], now);

		now += times[j][k]; /* remember cumulative time */
	}
	
	return;
}
==================================end=====================================
Have fun!

	Steve Falco

