/* This program reads in a notefile and deforms the pitch or
rhythm. It adds a random pitch increment or time chunk to a random
note. The flag "-p" causes a pitch change, the flag "-r" causes a
rhythm change. The flag "-s" sets the "seed" of the random number
generator to a value specified by the following integer. This program
was used in error detection tests; see ch. 5 of _Music and
Probability_ for further info.  */

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

FILE *in_file;
char line[1000];
char noteword[10];

struct {
    int ontime;
    int offtime;
    int onbeat;
    int offbeat;
    int duration;
    int pitch;
} note[10000]; 

int verbosity;
int force_change=1;       /* 1: force new note to be different from original one; 0: don't */
int mode; /* 0 = pitch, 1 = rhythm */

main(argc, argv)
int argc;
char *argv[];
{

    int a, i, z=0, seed, numnotes, lowest, highest, defnote, previous, next, new;

    mode = 0;
    verbosity=0;
    seed = time(NULL) % 10000; /* Why % 10000? */
    /* Put a number below to generate a replicable output */
    //seed = 1;

    a=1;
    in_file = NULL;
    while(1) {
	if(a==argc) break;
	else if(a==argc-1) {
	    if(strcmp(argv[a], "stdin")==0) in_file = stdin;
	    else in_file = fopen(argv[a], "r");
	}
	else if(strcmp(argv[a], "-p")==0) mode=0;
	else if(strcmp(argv[a], "-r")==0) mode=1;
	else if(strcmp(argv[a], "-s")==0) (void) sscanf (argv[a+1], "%d", &seed);
	a++;
    }

    if(in_file == NULL) { printf("File not found\n"); exit(1); }

    while (fgets(line, sizeof(line), in_file) !=NULL) {            /* read in Notes and Beats */
	for (i=0; isspace(line[i]); i++);
	if(line[i] == '\0') continue;
	(void) sscanf (line, "%s", noteword);
	if (strcmp (noteword, "Note") == 0) { 
	    (void) sscanf (line, "%s %d %d %d", noteword, &note[z].ontime, &note[z].offtime, &note[z].pitch);
	    //printf("Note %d %d %d\n", note[z].ontime, note[z].offtime, note[z].pitch);
	    z++;
	}
	numnotes=z;

	highest=0;
	lowest=100;
	for(z=0; z<numnotes; z++) {
	    if(note[z].pitch > highest) highest=note[z].pitch;
	    if(note[z].pitch < lowest) lowest=note[z].pitch;
	}
    }

    srand(seed);    
    /* Choose the note to be deformed. Don't allow it to be the last note (that will screw up the 
       rhythmic deformation */
    defnote = rand() % (numnotes-1);
    if(verbosity > 0) printf("Deforming note %d (Note %d %d %d)\n", defnote, note[defnote].ontime, note[defnote].offtime, note[defnote].pitch);

    srand(seed);
    if(mode==0) {

	if(force_change == 0) note[defnote].pitch = lowest + (rand() % ((highest+1) - lowest));
	else {
	    while(1) {
		/* Careful - could be an infinite loop if the program is not able to find a different note! */
		new = lowest + (rand() % ((highest+1) - lowest));
		if(new!=note[defnote].pitch) {
		    note[defnote].pitch = new;
		    break;
		}
	    }
	}

	if(verbosity > 0) printf("Deformed note: Note %d %d %d\n", note[defnote].ontime, note[defnote].offtime, note[defnote].pitch);
    }
    if(mode==1) {
	if(defnote>0) previous = note[defnote-1].ontime;
	else previous = 0;
	next = note[defnote+1].ontime;
	if(force_change == 0) note[defnote].ontime = previous + 1 + (rand() % ((next-1)-previous));
	else {
	    while(1) {
		new = previous + 1 + (rand() % ((next-1)-previous));
		if(new!=note[defnote].ontime) {
		    note[defnote].ontime = new;
		    break;
		}
	    }
	}

	if(verbosity > 0) printf("Deformed note: Note %d %d %d\n", note[defnote].ontime, note[defnote].offtime, note[defnote].pitch);
    }

    for(z=0; z<numnotes; z++) printf("Note %d %d %d\n", note[z].ontime, note[z].offtime, note[z].pitch);
}

