/*		
*		GRAMophone II, a grammar based algorithmic musical composition tool
*		-------------------------------------------------------------------
*		
*		grammyVM.c
*
*		the GRAMophone II Virtual Machine
*
*		Copyright (c) 2007, Giovanni Ferranti <giovanni@giovanniferranti.it>
*
* 		GRAMophone II 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 Library 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.,
*		51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*		-------------------------------------------------------------------
*/

#include <math.h>
#include "global.h"

typedef unsigned int retrograde_buffer[DIM_RTGD_BUFFER][8];
retrograde_buffer *rtgd_buffer[MAX_RECURSION];
char melop[MAX_RECURSION][2] /*0: OFF, 1: _TRN, 2: _INV, 3: _RTRGD , 4: _RTGINV*/;
unsigned char op_counter=0, rtgd_counter=0, rtgd_note_count;

void sort_attack(unsigned int chord[MAX_CHORD][5], int l, int r)
{
	int i, j;
	unsigned int temp[5];
	
	for(i=l; i<r; i++) {
		int min=i;
		for(j=i+1; j<=r; j++)
			if(chord[j][4]<chord[min][4])
				min=j;
		temp[0]=chord[i][0];
		temp[1]=chord[i][1];
		temp[2]=chord[i][2];
		temp[3]=chord[i][3];
		temp[4]=chord[i][4];
		chord[i][0]=chord[min][0];
		chord[i][1]=chord[min][1];
		chord[i][2]=chord[min][2];
		chord[i][3]=chord[min][3];
		chord[i][4]=chord[min][4];
		chord[min][0]=temp[0];
		chord[min][1]=temp[1];
		chord[min][2]=temp[2];
		chord[min][3]=temp[3];
		chord[min][4]=temp[4];
	}
}

void sort_duration(unsigned int chord[MAX_CHORD][5], int l, int r)
{
	int i, j;
	unsigned int temp[5];
	
	for(i=l; i<r; i++) {
		int min=i;
		for(j=i+1; j<=r; j++)
			if((chord[j][2]+chord[j][4])<(chord[min][2]+chord[j][4]))
				min=j;
		temp[0]=chord[i][0];
		temp[1]=chord[i][1];
		temp[2]=chord[i][2];
		temp[3]=chord[i][3];
		temp[4]=chord[i][4];
		chord[i][0]=chord[min][0];
		chord[i][1]=chord[min][1];
		chord[i][2]=chord[min][2];
		chord[i][3]=chord[min][3];
		chord[i][4]=chord[min][4];
		chord[min][0]=temp[0];
		chord[min][1]=temp[1];
		chord[min][2]=temp[2];
		chord[min][3]=temp[3];
		chord[min][4]=temp[4];
	}
}

unsigned int casual(unsigned int numOr) {
	return rand()%numOr+1;
}

unsigned int calculate_expression(unsigned int start, unsigned int id_prod, unsigned char type) {
	unsigned char code;
	register unsigned char i=0, j=0;
	int result1, result2, result[MAX_RECURSION];
	
	players[playerCount]->productions[id_prod]->ec=start;
	while((code=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][0])!=_ENDEXP) {
		switch(code) {
			case _AND:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) {
					case 0:
						result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
						break;
					case 1:
						result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value;
						break;
					case 2:
						result1=result[j++];
				}
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) {
					case 0:
						result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4];
						break;
					case 1:
						result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value;
						break;
					case 2:
						result2=result[j++];
				}
				result[i++]=result1 && result2;
				break;
			case _OR:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) {
					case 0:
						result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
						break;
					case 1:
						result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value;
						break;
					case 2:
						result1=result[j++];
				}
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) {
					case 0:
						result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4];
						break;
					case 1:
						result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value;
						break;
					case 2:
						result2=result[j++];
				}
				result[i++]=result1 || result2;			
				break;
			case _NOT:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) {
					case 0:
						result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
						break;
					case 1:
						result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value;
						break;
					case 2:
						result1=result[j++];
				}			
				result[i++]=!result1;
				break;
			case _EQ:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) {
					case 0:
						result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
						break;
					case 1:
						result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value;
						break;
					case 2:
						result1=result[j++];
				}
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) {
					case 0:
						result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4];
						break;
					case 1:
						result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value;
						break;
					case 2:
						result2=result[j++];
				}
				result[i++]=result1==result2;			
				break;
			case _NE:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) {
					case 0:
						result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
						break;
					case 1:
						result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value;
						break;
					case 2:
						result1=result[j++];
				}
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) {
					case 0:
						result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4];
						break;
					case 1:
						result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value;
						break;
					case 2:
						result2=result[j++];
				}
				result[i++]=result1!=result2;			
				break;
			case _LT:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) {
					case 0:
						result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
						break;
					case 1:
						result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value;
						break;
					case 2:
						result1=result[j++];
				}
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) {
					case 0:
						result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4];
						break;
					case 1:
						result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value;
						break;
					case 2:
						result2=result[j++];
				}
				result[i++]=result1<result2;			
				break;
			case _LE:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) {
					case 0:
						result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
						break;
					case 1:
						result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value;
						break;
					case 2:
						result1=result[j++];
				}
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) {
					case 0:
						result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4];
						break;
					case 1:
						result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value;
						break;
					case 2:
						result2=result[j++];
				}
				result[i++]=result1<=result2;			
				break;
			case _GT:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) {
					case 0:
						result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
						break;
					case 1:
						result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value;
						break;
					case 2:
						result1=result[j++];
				}
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) {
					case 0:
						result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4];
						break;
					case 1:
						result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value;
						break;
					case 2:
						result2=result[j++];
				}
				result[i++]=result1>result2;			
				break;
			case _GE:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) {
					case 0:
						result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
						break;
					case 1:
						result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value;
						break;
					case 2:
						result1=result[j++];
				}
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) {
					case 0:
						result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4];
						break;
					case 1:
						result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value;
						break;
					case 2:
						result2=result[j++];
				}
				result[i++]=result1>=result2;			
				break;
			case _MOV:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]) {
					case 0:
						players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].name?
						(result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]):
						(result1=global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]);
						break;
					case 1:
						players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].name?
						(result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]].value):
						(result1=global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]].value);
						break;
					case 2:
						players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].name?
						(result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value=result[j++]):
						(result1=global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value=result[j++]);
				}
				result[i++]=result1;		
				break;
			case _ADD:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) {
					case 0:
						result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
						break;
					case 1:
						result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value;
						break;
					case 2:
						result1=result[j++];
				}
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) {
					case 0:
						result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4];
						break;
					case 1:
						result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value;
						break;
					case 2:
						result2=result[j++];
				}
				result[i++]=result1+result2;
				break;
			case _SUB:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) {
					case 0:
						result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
						break;
					case 1:
						result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value;
						break;
					case 2:
						result1=result[j++];
				}
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) {
					case 0:
						result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4];
						break;
					case 1:
						result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value;
						break;
					case 2:
						result2=result[j++];
				}			
				result[i++]=result1-result2;
				break;
			case _MUL:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) {
					case 0:
						result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
						break;
					case 1:
						result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value;
						break;
					case 2:
						result1=result[j++];
				}
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) {
					case 0:
						result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4];
						break;
					case 1:
						result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value;
						break;
					case 2:
						result2=result[j++];
				}			
				result[i++]=result1*result2;			
				break;
			case _DIV:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) {
					case 0:
						result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
						break;
					case 1:
						result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value;
						break;
					case 2:
						result1=result[j++];
				}
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) {
					case 0:
						result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4];
						break;
					case 1:
						result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value;
						break;
					case 2:
						result2=result[j++];
				}			
				result[i++]=result1/result2;
				break;
			case _MOD:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) {
					case 0:
						result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
						break;
					case 1:
						result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value;
						break;
					case 2:
						result1=result[j++];
				}
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) {
					case 0:
						result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4];
						break;
					case 1:
						result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value;
						break;
					case 2:
						result2=result[j++];
				}			
				result[i++]=result1%result2;
				break;				
			case _INC:
				result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value;
				result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
				result[i++]=result1+result2;
				break;
			case _DEC:
				result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value;
				result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
				result[i++]=result1-result2;						
				break;
			case _RND:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) {
					case 0:
						result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
						break;
					case 1:
						result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value;
						break;
					case 2:
						result1=result[j++];
				}
				result[i++]=rand()%result1;
				break;
			case _UMIN:
				switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) {
					case 0:
						result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2];
						break;
					case 1:
						result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value;
						break;
					case 2:
						result1=result[j++];
				}			
				result[i++]=-result1;
		}
	if(players[playerCount]->productions[id_prod]->ec+1<DIM_EXP)	
		players[playerCount]->productions[id_prod]->ec++;	
	}
	switch(type) {
		case OCT:
			if(result[i-1]<-2)
				result[i-1]=-2;
			if(result[i-1]>8)
				result[i-1]=8;
			break;
		case VEL:
		case REL:
		case BYTEDATA:
			if(result[i-1]<-127)
				result[i-1]=-127;
			if(result[i-1]>127)
				result[i-1]=127;		
			break;
		case DUR:
			if(result[i-1]<0)
				result[i-1]=0;	
	}
	return result[i-1];
}

void process_rest(unsigned int id_prod, unsigned char isChord) {
	if(debugOption && !rtgd_counter)
	  printf("rest parameters: ");
	switch(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][1]) {
		case 0:
			rest=players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][2];
			if(debugOption && !rtgd_counter)
			  printf("%d\n", rest);	//debug
			break;
		case 1:
			players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][2]].name?(rest=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][2]].value):(rest=global_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][2]].value);
			if(debugOption && !rtgd_counter)
			  printf("%d\n", rest); //debug
			break;
		case _EXP:
			rest=calculate_expression(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][2], id_prod, DUR);
			if(debugOption && !rtgd_counter)
			  printf("%d\n", rest);	//debug
	}	
}

void process_note(unsigned int id_prod, unsigned char isChord) {
	int octave=0, sum_trn=0, sum_inv=0;
	register int i;
	unsigned int old_note, tmp;
	
	if(op_counter && players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][1]>=0) {
		old_note=note[0]=players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][1];
		for(i=op_counter-1; i>=0; i--)
			switch(melop[i][0]) {
				case 1:
					sum_trn+=melop[i][1];
					break;
				case 2:
					tmp=players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][1]+sum_inv+sum_trn;
					sum_inv+=2*(melop[i][1]-tmp);
					break;
			}
		note[0]+=sum_trn+sum_inv;		
		while((int)note[0]<0)
		  note[0]+=12;	
		note[0]%=12;
		if(melop[op_counter-1][0]==1)
		  octave=(sum_trn+old_note)/12;
	}
	else
		note[0]=players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][1];
	if(debugOption && !rtgd_counter)		
		printf("note: %d parameters: ", note[0]);	//debug	
	switch(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][2]) {
		case 0:
			note[1]=players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][3];
			note[1]+=octave;
			if((int)note[1]<-2)
				note[1]=-2;
			if((int)note[1]>8)
				note[1]=8;
			if(debugOption && !rtgd_counter)	
				printf("%d ", note[1]);	//debug			
			break;
		case 1:
			if(players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][3]].name) {
				note[1]=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][3]].value;
				note[1]+=octave;
				if((int)note[1]<-2)
					note[1]=-2;
				if((int)note[1]>8)
					note[1];
				if(debugOption && !rtgd_counter)
					printf("%d ", note[1]); //debug				
			}
			else {
				note[1]=global_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][3]].value;
				note[1]+=octave;
				if((int)note[1]<-2)
					note[1]=-2;
				if((int)note[1]>8)
					note[1]=8;
				if(debugOption && !rtgd_counter)
					printf("%d ", note[1]);	//debug			
			}
			break;
		case _EXP:
			note[1]=calculate_expression(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][3], id_prod, OCT);
			note[1]+=octave;
			if((int)note[1]<-2)
				note[1]=-2;
			if((int)note[1]>8)
				note[1]=8;			
			if(debugOption && !rtgd_counter)
				printf("%d ", note[1]);	//debug		
	}
	switch(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][4]) {
		case 0:
			note[2]=players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][5];
			if(debugOption && !rtgd_counter)
				printf("%d ", note[2]);	//debug			
			break;
		case 1:
			players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][5]].name?(note[2]=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][5]].value):(note[2]=global_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][5]].value);
			if(debugOption && !rtgd_counter)
				printf("%d ", note[2]);	//debug
			break;
		case _EXP:
			note[2]=calculate_expression(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][5], id_prod, VEL);
			if(debugOption && !rtgd_counter)
				printf("%d ", note[2]);	//debug		
	}
	switch(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][6]) {
		case 0:
			note[3]=players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][7];
			if(debugOption && !rtgd_counter)
				printf("%d ", note[3]);	//debug			
			break;
		case 1:
			note[3]=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][7]].name?(note[3]=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][7]].value):(note[3]=global_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][7]].value);
			if(debugOption && !rtgd_counter)
				printf("%d ", note[3]);	//debug	
			break;
		case _EXP:
			note[3]=calculate_expression(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][7], id_prod, DUR);
			if(debugOption && !rtgd_counter)
				printf("%d ", note[3]);	//debug
	}
	switch(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][8]) {
		case 0:
			note[4]=players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][9];
			if(debugOption && !rtgd_counter)
				printf("%d\n", note[4]); //debug			
			break;
		case 1:
			note[4]=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][9]].name?(note[4]=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][9]].value):(note[4]=global_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][9]].value);
			if(debugOption && !rtgd_counter)
				printf("%d\n", note[4]); //debug			
			break;
		case _EXP:
			note[4]=calculate_expression(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][9], id_prod, REL);
			if(debugOption && !rtgd_counter)
				printf("%d\n", note[4]); //debug			
	}			
}

unsigned char chomsky_generator(unsigned int nt, unsigned char isChord) {
	unsigned char code, rep[MAX_RECURSION][2];
	unsigned int it, caso, casoAlt, reg, *pointer, tmp;
	register unsigned int i=0, j=0, k, w;
	register char note_chord_counter=0;
	int sum_trn=0, sum_inv=0, y;
	
	//(!players[playerCount]->productions[nt]->visited)?(players[playerCount]->productions[nt]->visited++):(players[playerCount]->productions[nt]->iterationCounter--);
	if(!players[playerCount]->productions[nt]->visited)
		players[playerCount]->productions[nt]->visited=++level;
	if(!players[playerCount]->productions[nt]->iterationCounter) {
		players[playerCount]->iterations?(players[playerCount]->productions[nt]->iterationCounter=players[playerCount]->iterations):(players[playerCount]->productions[nt]->iterationCounter=global_iterations);	
		return 0;
	}
	players[playerCount]->productions[nt]->numOr>1?(caso=casual(players[playerCount]->productions[nt]->numOr)):(caso=1);
	players[playerCount]->productions[nt]->numOrAlt>1?(casoAlt=casual(players[playerCount]->productions[nt]->numOrAlt)):(casoAlt=1);
	if(debugOption && players[playerCount]->productions[nt]->numOr>1)
		printf("this is a non-deterministic production with %d alternatives. I choose: %d\n", players[playerCount]->productions[nt]->numOr, caso);	//debug	
	players[playerCount]->productions[nt]->cc=0;
	//printf("# of %s production: %d\n", players[playerCount]->productions[nt]->name, players[playerCount]->productions[nt]->numOr);	//debug
	while(code=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]) {
		switch(code) {
			case _PRD:
				if(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]!=caso) {
					if(players[playerCount]->productions[nt]->cc+1<DIM_MIDI_CODE)
						players[playerCount]->productions[nt]->cc++;
					else
						break;
					while(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]!=_PRD) {
						if(players[playerCount]->productions[nt]->cc+1<DIM_MIDI_CODE)
							players[playerCount]->productions[nt]->cc++;
						else
							break;
					}
					players[playerCount]->productions[nt]->cc--;
				}
				break;
			case _PRD_ALT:
				if(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]!=casoAlt) {
					if(players[playerCount]->productions[nt]->cc+1<DIM_MIDI_CODE)
						players[playerCount]->productions[nt]->cc++;
					else
						break;
					while(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]!=_PRD_ALT) {
						if(players[playerCount]->productions[nt]->cc+1<DIM_MIDI_CODE)
							players[playerCount]->productions[nt]->cc++;
						else
							break;
					}
					players[playerCount]->productions[nt]->cc--;
				}			
				break;
			case _CHK:
				if(!calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1], nt, 0))
					if(!players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2])
						return 1;	
					else
						players[playerCount]->productions[nt]->cc=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]-1;
				break;
			case _ELSE:
				return 0;
			case _GOTO:
				reg=players[playerCount]->productions[nt]->cc;
				if(players[playerCount]->productions[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]]->visited && players[playerCount]->productions[nt]->visited>=players[playerCount]->productions[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]]->visited)
					players[playerCount]->productions[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]]->iterationCounter--;
				chomsky_generator(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1], isChord);
				players[playerCount]->productions[nt]->cc=reg;
				break;
			case _NOTEON:
				process_note(nt, isChord);
				if(!rtgd_counter) {
					data[0]=note[0]+(12*(note[1]+2));
					data[1]=note[2];
					if(!isChord) {
						if(!mf_write_midi_event(prev_duration, note_on, players[playerCount]->local_params[CHN], data, 2)) {
							fprintf(stderr, "Error writing midi file!\n");
							return -1;
						}
						data[1]=note[4];	
						if(!mf_write_midi_event(prev_duration=note[3], note_off, players[playerCount]->local_params[CHN], data, 2)) {
							fprintf(stderr, "Error writing midi file!\n");
							return -1;
						}
					}
					else {
						chord[note_chord_counter][0]=note[0]+(12*(note[1]+2));
						chord[note_chord_counter][1]=note[2];
						chord[note_chord_counter][2]=note[3];
						chord[note_chord_counter][3]=note[4];
						chord[note_chord_counter++][4]=prev_duration;		//rest associated with note in the chord
					}
					prev_duration=0;
				}
				else {
					if(!isChord) {
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][0]=0;
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][1]=note[0];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][2]=note[1];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][3]=note[0]+(12*(note[1]+2));
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][4]=note[2];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][5]=note[3];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][6]=note[4];
					}
					else {
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][0]=_CHORD;
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][1]=note[0];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][2]=note[1];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][3]=note[0]+(12*(note[1]+2));
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][4]=note[2];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][5]=note[3];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][6]=note[4];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][7]=prev_duration;
						prev_duration=0;
					}	
				}
				break;
			case _EMPTY:
				process_note(nt, isChord);
				break;
			case _REST:
				process_rest(nt, isChord);
				if(!rtgd_counter)
					prev_duration=rest;
				else {
					(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][0]=_REST;
					(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][1]=rest;
					if(isChord)
						prev_duration=rest;
				}				
				break;
			case _TRN:
				melop[op_counter][0]=1;
				switch(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]) {
					case 0:
						melop[op_counter++][1]=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2];
						break;
					case 1:
						melop[op_counter++][1]=players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value:global_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value;
						break;
					case _EXP:
						melop[op_counter++][1]=calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2], nt, BYTEDATA);
				}				
				break;
			case _INV:
				pointer=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc];
				if((pointer+10)[0]!=_RTRGD) {
					melop[op_counter][0]=2;
					while(pointer[0]!=_NOTEON)
						pointer++;	//step 10!!!
					melop[op_counter++][1]=pointer[1];
				}
				else
					melop[op_counter++][0]=4;		//Inversion of Retrograde	
				break;
			case _RTRGD:
				melop[op_counter++][0]=3;
				rtgd_buffer[rtgd_counter++]=(retrograde_buffer *)malloc(DIM_RTGD_BUFFER*8*sizeof(unsigned int));
				if(rtgd_counter>1) {
					(*rtgd_buffer[rtgd_counter-1])[0][0]=rtgd_note_count;
					rtgd_note_count=1;
				}
				else
					rtgd_note_count=0;		
				break;
			case _ENDMELOP:
				if(melop[op_counter-1][0]==3) {
					if(melop[op_counter-2][0]==4)
						melop[op_counter-2][1]=(!(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count-1][0])?(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count-1][1]:(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count-2][1];							
					if(rtgd_counter>1) {
						w=(*rtgd_buffer[rtgd_counter-1])[0][0];
						for(k=rtgd_note_count; k>1; k--) {
							
							/********************************************************/

							if(melop[op_counter-2][0]==4) {
								(*rtgd_buffer[rtgd_counter-1])[k-1][1]+=2*(melop[op_counter-2][1]-(*rtgd_buffer[rtgd_counter-1])[k-1][1]);
								while((int)(*rtgd_buffer[rtgd_counter-1])[k-1][1]<0)
								  (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=12;	
								(*rtgd_buffer[rtgd_counter-1])[k-1][1]%=12;
								(*rtgd_buffer[rtgd_counter-1])[k-1][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][1]+(12*((*rtgd_buffer[rtgd_counter-1])[k-1][2]+2));										
							}											
	
							/********************************************************/							
														
							(*rtgd_buffer[rtgd_counter-2])[w][0]=(*rtgd_buffer[rtgd_counter-1])[k-1][0];
							(*rtgd_buffer[rtgd_counter-2])[w][1]=(*rtgd_buffer[rtgd_counter-1])[k-1][1];
							(*rtgd_buffer[rtgd_counter-2])[w][2]=(*rtgd_buffer[rtgd_counter-1])[k-1][2];
							(*rtgd_buffer[rtgd_counter-2])[w][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][3];
							(*rtgd_buffer[rtgd_counter-2])[w][4]=(*rtgd_buffer[rtgd_counter-1])[k-1][4];
							(*rtgd_buffer[rtgd_counter-2])[w][5]=(*rtgd_buffer[rtgd_counter-1])[k-1][5];
							(*rtgd_buffer[rtgd_counter-2])[w][6]=(*rtgd_buffer[rtgd_counter-1])[k-1][6];
							(*rtgd_buffer[rtgd_counter-2])[w++][7]=(*rtgd_buffer[rtgd_counter-1])[k-1][7];
						}
						rtgd_note_count=w;
					}		
					else {						
						for(k=rtgd_note_count; k>0; k--)
							switch((*rtgd_buffer[rtgd_counter-1])[k-1][0]) {
								case _CHORD:
									if(debugOption && !isChord) {
				  						printf("Playing a chord...\n");	//debug
				  						isChord=1;
				  					}
				  					
									/********************************************************/
																	
									if(melop[op_counter-2][0]==4) {
										(*rtgd_buffer[rtgd_counter-1])[k-1][1]+=2*(melop[op_counter-2][1]-(*rtgd_buffer[rtgd_counter-1])[k-1][1]);
										while((int)(*rtgd_buffer[rtgd_counter-1])[k-1][1]<0)
										  (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=12;	
										(*rtgd_buffer[rtgd_counter-1])[k-1][1]%=12;											
										(*rtgd_buffer[rtgd_counter-1])[k-1][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][1]+(12*((*rtgd_buffer[rtgd_counter-1])[k-1][2]+2));										
									}											

									/********************************************************/				  					
				  							
									chord[note_chord_counter][0]=(*rtgd_buffer[rtgd_counter-1])[k-1][3];
									chord[note_chord_counter][1]=(*rtgd_buffer[rtgd_counter-1])[k-1][4];
									chord[note_chord_counter][2]=(*rtgd_buffer[rtgd_counter-1])[k-1][5];
									chord[note_chord_counter][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][6];
									chord[note_chord_counter++][4]=(*rtgd_buffer[rtgd_counter-1])[k-1][7];		//rest associated with note in the chord
									if(debugOption)
										printf("note: %d parameters: %d %d %d %d\n", (*rtgd_buffer[rtgd_counter-1])[k-1][1], (*rtgd_buffer[rtgd_counter-1])[k-1][2], (*rtgd_buffer[rtgd_counter-1])[k-1][4], (*rtgd_buffer[rtgd_counter-1])[k-1][5], (*rtgd_buffer[rtgd_counter-1])[k-1][6]);	//debug																	
									break;	
								case _ENDCHORD:
									if(!isChord)
										break;
									isChord=0;
									if(debugOption)
				  						printf("Chord ended\n");			//debug									
									sort_attack(chord, 0, --note_chord_counter);
									for(w=0; w<=note_chord_counter; w++) {
										data[0]=chord[w][0];
										data[1]=chord[w][1];
										if(!mf_write_midi_event(chord[w][4], note_on, players[playerCount]->local_params[CHN], data, 2)) {
											fprintf(stderr, "Error writing midi file!\n");
											return -1;
										}					
									}
									sort_duration(chord, 0, note_chord_counter);
									data[0]=chord[0][0];
									data[1]=chord[0][3];
									if(!mf_write_midi_event(chord[0][2], note_off, players[playerCount]->local_params[CHN], data, 2)) {
										fprintf(stderr, "Error writing midi file!\n");
										return -1;
									}				
									for(w=1; w<=note_chord_counter; w++) {
										data[0]=chord[w][0];
										data[1]=chord[w][3];
										if(!mf_write_midi_event((chord[w][2]+chord[w][4])-(chord[w-1][2]+chord[w-1][4]), note_off, players[playerCount]->local_params[CHN], data, 2)) {
											fprintf(stderr, "Error writing midi file!\n");
											return -1;
										}
									}
									note_chord_counter=0;
									break;
								case _REST:
									prev_duration=(*rtgd_buffer[rtgd_counter-1])[k-1][1];
									if(debugOption)
										printf("rest parameters: %d\n", (*rtgd_buffer[rtgd_counter-1])[k-1][1]);									
									break;		
								default:
									
									/********************************************************/
									
									if(melop[op_counter-2][0]==4) {
										(*rtgd_buffer[rtgd_counter-1])[k-1][1]+=2*(melop[op_counter-2][1]-(*rtgd_buffer[rtgd_counter-1])[k-1][1]);
										while((int)(*rtgd_buffer[rtgd_counter-1])[k-1][1]<0)
										  (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=12;	
										(*rtgd_buffer[rtgd_counter-1])[k-1][1]%=12;											
										(*rtgd_buffer[rtgd_counter-1])[k-1][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][1]+(12*((*rtgd_buffer[rtgd_counter-1])[k-1][2]+2));										
									}											

									/********************************************************/
									
									data[0]=(*rtgd_buffer[rtgd_counter-1])[k-1][3];
									data[1]=(*rtgd_buffer[rtgd_counter-1])[k-1][4];
									if(!mf_write_midi_event(prev_duration, note_on, players[playerCount]->local_params[CHN], data, 2)) {
										fprintf(stderr, "Error writing midi file!\n");
										return -1;
									}
									data[1]=(*rtgd_buffer[rtgd_counter-1])[k-1][6];
									if(!mf_write_midi_event(prev_duration=(*rtgd_buffer[rtgd_counter-1])[k-1][5], note_off, players[playerCount]->local_params[CHN], data, 2)) {
										fprintf(stderr, "Error writing midi file!\n");
										return -1;
									}
									if(debugOption)
										printf("note: %d parameters: %d %d %d %d\n", (*rtgd_buffer[rtgd_counter-1])[k-1][1], (*rtgd_buffer[rtgd_counter-1])[k-1][2], (*rtgd_buffer[rtgd_counter-1])[k-1][4], (*rtgd_buffer[rtgd_counter-1])[k-1][5], (*rtgd_buffer[rtgd_counter-1])[k-1][6]);	//debug
									prev_duration=0;
							}	
					}	
					free(rtgd_buffer[rtgd_counter-1]);
					rtgd_counter--;
				}
				melop[op_counter-1][0]=melop[op_counter-1][1]=0;
				op_counter--;				
				break;
			case _UPDATE:
				calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1], nt, players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]);
				break;
			case _REP:
				rep[i][0]=players[playerCount]->productions[nt]->cc+1;
				switch(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]) {
					case 0:
						rep[i++][1]=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2];
						break;
					case 1:
						rep[i++][1]=players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value:global_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value;
						break;
					case _EXP:
						rep[i++][1]=calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2], nt, BYTEDATA);
				}
				if(!rep[i-1][1]) {
					j++;
					while(j) {
						if(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]==_REP)
							j++;
						if(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]==_ENDREP)
							j--;
						if(players[playerCount]->productions[nt]->cc+1<DIM_MIDI_CODE)
							players[playerCount]->productions[nt]->cc++;
						else
							break;
					}
				}	
				break;
			case _ENDREP:
				if(rep[i-1][1]-1) {
					players[playerCount]->productions[nt]->cc=rep[i-1][0];
					rep[i-1][1]--;
					continue;
				}
				else
					i--;
				break;
			case _CHORD:
				if(debugOption && !rtgd_counter)
				  printf("Playing a chord...\n");	//debug
				else
					(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][0]=_ENDCHORD;  
				isChord=1;							
				break;
			case _ENDCHORD:
				if(debugOption && !rtgd_counter)
				  printf("Chord ended\n");			//debug
				isChord=0;
				if(!rtgd_counter) {
					sort_attack(chord, 0, --note_chord_counter);
					for(k=0; k<=note_chord_counter; k++) {
						data[0]=chord[k][0];
						data[1]=chord[k][1];
						if(!mf_write_midi_event(chord[k][4], note_on, players[playerCount]->local_params[CHN], data, 2)) {
							fprintf(stderr, "Error writing midi file!\n");
							return -1;
						}					
					}
					sort_duration(chord, 0, note_chord_counter);
					data[0]=chord[0][0];
					data[1]=chord[0][3];
					if(!mf_write_midi_event(chord[0][2], note_off, players[playerCount]->local_params[CHN], data, 2)) {
						fprintf(stderr, "Error writing midi file!\n");
						return -1;
					}				
					for(k=1; k<=note_chord_counter; k++) {
						data[0]=chord[k][0];
						data[1]=chord[k][3];
						if(!mf_write_midi_event((chord[k][2]+chord[k][4])-(chord[k-1][2]+chord[k-1][4]), note_off, players[playerCount]->local_params[CHN], data, 2)) {
							fprintf(stderr, "Error writing midi file!\n");
							return -1;
						}
					}
					note_chord_counter=0;
				}
				else
					(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][0]=_ENDCHORD;
				break;
			case _PRNT:
				switch(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]) {
					case 0:
						printf("%d", players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]);
						break;
					case 1:
						printf("%d", players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value:global_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value);
						break;
					case _EXP:
						printf("%d", calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2], nt, players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][3]));
						break;
					case _STR:
						printf("%s", strings[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]]);
				}
		}
		if(players[playerCount]->productions[nt]->cc+1<DIM_MIDI_CODE)
			players[playerCount]->productions[nt]->cc++;
		else
			break;
	}
	if(players[playerCount]->iterations) {
		if(players[playerCount]->productions[nt]->iterationCounter<players[playerCount]->iterations)
			players[playerCount]->productions[nt]->iterationCounter=players[playerCount]->iterations;
	}
	else
		if(players[playerCount]->productions[nt]->iterationCounter<global_iterations)
			players[playerCount]->productions[nt]->iterationCounter=global_iterations;
	return 0;
}

unsigned char lindenmayer_prod_generator(unsigned int nt, unsigned int *buffer) {
	unsigned char code, rep[MAX_RECURSION][2], isChord=0;
	unsigned int caso, casoAlt, *pointer, tmp;
	char string_buf[MAX_STR], str_temp_buf[MAX_STR];
	register unsigned int i=0, j=0, k, w, counter=0;
	register char note_chord_counter=0;
	int sum_trn=0, sum_inv=0, y;	
	
	memset(melop, 0, 2*MAX_RECURSION);
	players[playerCount]->productions[nt]->numOr>1?(caso=casual(players[playerCount]->productions[nt]->numOr)):(caso=1);
	players[playerCount]->productions[nt]->numOrAlt>1?(caso=casual(players[playerCount]->productions[nt]->numOrAlt)):(casoAlt=1);
	if(debugOption && players[playerCount]->productions[nt]->numOr>1)
		printf("this is a non-deterministic production with %d alternatives. I choose: %d\n", players[playerCount]->productions[nt]->numOr, caso);	//debug	
	players[playerCount]->productions[nt]->cc=0;
	while(code=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]) {
		switch(code) {
			case _PRD:
				if(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]!=caso) {
					if(players[playerCount]->productions[nt]->cc+1<DIM_MIDI_CODE)
						players[playerCount]->productions[nt]->cc++;
					else
						break;
					while(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]!=_PRD) {
						if(players[playerCount]->productions[nt]->cc+1<DIM_MIDI_CODE)
							players[playerCount]->productions[nt]->cc++;
						else
							break;
					}
					players[playerCount]->productions[nt]->cc--;
				}				
				break;
			case _PRD_ALT:
				if(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]!=casoAlt) {
					if(players[playerCount]->productions[nt]->cc+1<DIM_MIDI_CODE)
						players[playerCount]->productions[nt]->cc++;
					else
						break;
					while(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]!=_PRD_ALT) {
						if(players[playerCount]->productions[nt]->cc+1<DIM_MIDI_CODE)
							players[playerCount]->productions[nt]->cc++;
						else
							break;
					}
					players[playerCount]->productions[nt]->cc--;
				}			
				break;				
			case _CHK:
				if(!calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1], nt, 0))
					if(!players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2])
						return 0;
					else
						players[playerCount]->productions[nt]->cc=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]-1;
				break;
			case _ELSE:
				return 0;				
			case _NOTEON:
				process_note(nt, isChord);
				if(!rtgd_counter) {
					data[0]=note[0]+(12*(note[1]+2));
					data[1]=note[2];				
					if(!isChord) {
						if(!mf_write_midi_event(prev_duration, note_on, players[playerCount]->local_params[CHN], data, 2)) {
							fprintf(stderr, "Error writing midi file!\n");
							return -1;
						}
						data[1]=note[4];
						if(!mf_write_midi_event(prev_duration=note[3], note_off, players[playerCount]->local_params[CHN], data, 2)) {
							fprintf(stderr, "Error writing midi file!\n");
							return -1;
						}
						sprintf(string_buf, "%d%d%d%d%d", note[0], note[1], note[2], note[3], note[4]);
						buffer[counter++]=hash(string_buf, 0);
					}
					else {
						chord[note_chord_counter][0]=note[0]+(12*(note[1]+2));
						chord[note_chord_counter][1]=note[2];
						chord[note_chord_counter][2]=note[3];
						chord[note_chord_counter][3]=note[4];
						chord[note_chord_counter++][4]=prev_duration;		//rest associated with note in the chord
						sprintf(str_temp_buf, "%d%d%d%d%d", note[0], note[1], note[2], note[3], note[4]);
						strcat(string_buf, str_temp_buf);
					}	
					prev_duration=0;
				}
				else {
					if(!isChord) {
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][0]=0;
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][1]=note[0];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][2]=note[1];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][3]=note[0]+(12*(note[1]+2));
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][4]=note[2];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][5]=note[3];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][6]=note[4];
					}
					else {
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][0]=_CHORD;
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][1]=note[0];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][2]=note[1];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][3]=note[0]+(12*(note[1]+2));
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][4]=note[2];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][5]=note[3];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][6]=note[4];
						(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][7]=prev_duration;
						sprintf(str_temp_buf, "%d%d%d%d%d", note[0], note[1], note[2], note[3], note[4]);
						strcat(string_buf, str_temp_buf);
						prev_duration=0;
					}	
				}				
				break;
			case _EMPTY:
				process_note(nt, isChord);
				break;				
			case _REST:
				process_rest(nt, isChord);
				if(!rtgd_counter)
					prev_duration=rest;
				else {
					(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][0]=_REST;
					(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][1]=rest;
				}
				if(!isChord) {
					sprintf(string_buf, "%d", rest);
					buffer[counter++]=hash(string_buf, 0);
				}
				else {
					sprintf(str_temp_buf, "%d", rest);
					strcat(string_buf, str_temp_buf);
					if(rtgd_counter)
						prev_duration=rest;
				}									
				break;
			case _TRN:
				melop[op_counter][0]=1;
				switch(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]) {
					case 0:
						melop[op_counter++][1]=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2];
						break;
					case 1:
						melop[op_counter++][1]=players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value:global_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value;
						break;
					case _EXP:
						melop[op_counter++][1]=calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2], nt, BYTEDATA);
				}
				break;
			case _INV:
				pointer=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc];
				if((pointer+10)[0]!=_RTRGD) {			
					melop[op_counter][0]=2;
					while(pointer[0]!=_NOTEON)
						pointer++;
					melop[op_counter++][1]=pointer[1];
				}
				else
					melop[op_counter++][0]=4;		//Inversion of Retrograde				
				break;
			case _RTRGD:
				melop[op_counter++][0]=3;
				rtgd_buffer[rtgd_counter++]=(retrograde_buffer *)malloc(DIM_RTGD_BUFFER*8*sizeof(unsigned int));
				if(rtgd_counter>1) {
					(*rtgd_buffer[rtgd_counter-1])[0][0]=rtgd_note_count;
					rtgd_note_count=1;
				}
				else
					rtgd_note_count=0;			
				break;
			case _ENDMELOP:
				if(melop[op_counter-1][0]==3) {
					if(melop[op_counter-2][0]==4)
						melop[op_counter-2][1]=(!(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count-1][0])?(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count-1][1]:(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count-2][1];
					if(rtgd_counter>1) {						
						w=(*rtgd_buffer[rtgd_counter-1])[0][0];
						for(k=rtgd_note_count; k>1; k--) {
							
							/********************************************************/
		
							if(melop[op_counter-2][0]==4) {
								(*rtgd_buffer[rtgd_counter-1])[k-1][1]+=2*(melop[op_counter-2][1]-(*rtgd_buffer[rtgd_counter-1])[k-1][1]);
								while((int)(*rtgd_buffer[rtgd_counter-1])[k-1][1]<0)
								  (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=12;	
								(*rtgd_buffer[rtgd_counter-1])[k-1][1]%=12;
								(*rtgd_buffer[rtgd_counter-1])[k-1][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][1]+(12*((*rtgd_buffer[rtgd_counter-1])[k-1][2]+2));										
							}											
	
							/********************************************************/							
							
							(*rtgd_buffer[rtgd_counter-2])[w][0]=(*rtgd_buffer[rtgd_counter-1])[k-1][0];
							(*rtgd_buffer[rtgd_counter-2])[w][1]=(*rtgd_buffer[rtgd_counter-1])[k-1][1];
							(*rtgd_buffer[rtgd_counter-2])[w][2]=(*rtgd_buffer[rtgd_counter-1])[k-1][2];
							(*rtgd_buffer[rtgd_counter-2])[w][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][3];
							(*rtgd_buffer[rtgd_counter-2])[w][4]=(*rtgd_buffer[rtgd_counter-1])[k-1][4];
							(*rtgd_buffer[rtgd_counter-2])[w][5]=(*rtgd_buffer[rtgd_counter-1])[k-1][5];
							(*rtgd_buffer[rtgd_counter-2])[w][6]=(*rtgd_buffer[rtgd_counter-1])[k-1][6];
							(*rtgd_buffer[rtgd_counter-2])[w++][7]=(*rtgd_buffer[rtgd_counter-1])[k-1][7];
						}
						rtgd_note_count=w;
					}		
					else {						
						for(k=rtgd_note_count; k>0; k--)
							switch((*rtgd_buffer[rtgd_counter-1])[k-1][0]) {
								case _CHORD:
									if(debugOption && !isChord) {
				  						printf("Playing a chord...\n");	//debug
				  						isChord=1;
				  					}
				  					
				  					/********************************************************/
				  									  					
									if(melop[op_counter-2][0]==4) {
										(*rtgd_buffer[rtgd_counter-1])[k-1][1]+=2*(melop[op_counter-2][1]-(*rtgd_buffer[rtgd_counter-1])[k-1][1]);
										while((int)(*rtgd_buffer[rtgd_counter-1])[k-1][1]<0)
										  (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=12;	
										(*rtgd_buffer[rtgd_counter-1])[k-1][1]%=12;											
										(*rtgd_buffer[rtgd_counter-1])[k-1][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][1]+(12*((*rtgd_buffer[rtgd_counter-1])[k-1][2]+2));										
									}											
									
									/********************************************************/
													  							
									chord[note_chord_counter][0]=(*rtgd_buffer[rtgd_counter-1])[k-1][3];
									chord[note_chord_counter][1]=(*rtgd_buffer[rtgd_counter-1])[k-1][4];
									chord[note_chord_counter][2]=(*rtgd_buffer[rtgd_counter-1])[k-1][5];
									chord[note_chord_counter][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][6];
									chord[note_chord_counter++][4]=(*rtgd_buffer[rtgd_counter-1])[k-1][7];		//rest associated with note in the chord
									if(debugOption)
										printf("note: %d parameters: %d %d %d %d\n", (*rtgd_buffer[rtgd_counter-1])[k-1][1], (*rtgd_buffer[rtgd_counter-1])[k-1][2], (*rtgd_buffer[rtgd_counter-1])[k-1][4], (*rtgd_buffer[rtgd_counter-1])[k-1][5], (*rtgd_buffer[rtgd_counter-1])[k-1][6]);	//debug																	
									break;	
								case _ENDCHORD:
									if(!isChord)
										break;
									isChord=0;
									if(debugOption)
				  						printf("Chord ended\n");			//debug
									//buffer[counter++]=hash(string_buf, 0);
									sort_attack(chord, 0, --note_chord_counter);
									for(w=0; w<=note_chord_counter; w++) {
										data[0]=chord[w][0];
										data[1]=chord[w][1];
										if(!mf_write_midi_event(chord[w][4], note_on, players[playerCount]->local_params[CHN], data, 2)) {
											fprintf(stderr, "Error writing midi file!\n");
											return -1;
										}					
									}
									sort_duration(chord, 0, note_chord_counter);
									data[0]=chord[0][0];
									data[1]=chord[0][3];
									if(!mf_write_midi_event(chord[0][2], note_off, players[playerCount]->local_params[CHN], data, 2)) {
										fprintf(stderr, "Error writing midi file!\n");
										return -1;
									}				
									for(w=1; w<=note_chord_counter; w++) {
										data[0]=chord[w][0];
										data[1]=chord[w][3];
										if(!mf_write_midi_event((chord[w][2]+chord[w][4])-(chord[w-1][2]+chord[w-1][4]), note_off, players[playerCount]->local_params[CHN], data, 2)) {
											fprintf(stderr, "Error writing midi file!\n");
											return -1;
										}
									}
									note_chord_counter=0;	
									break;
								case _REST:
									/*if(!isChord) {
										sprintf(string_buf, "%d", (*rtgd_buffer[rtgd_counter-1])[k-1][1]);
										buffer[counter++]=hash(string_buf, 0);
									}
									else {
										sprintf(str_temp_buf, "%d", (*rtgd_buffer[rtgd_counter-1])[k-1][1]);
										strcat(string_buf, str_temp_buf);
									}*/
									prev_duration=rest;
									if(debugOption)
										printf("rest parameters: %d\n", (*rtgd_buffer[rtgd_counter-1])[k-1][1]);									
									break;		
								default:
								
									/********************************************************/
				
									if(melop[op_counter-2][0]==4) {
										(*rtgd_buffer[rtgd_counter-1])[k-1][1]+=2*(melop[op_counter-2][1]-(*rtgd_buffer[rtgd_counter-1])[k-1][1]);
										while((int)(*rtgd_buffer[rtgd_counter-1])[k-1][1]<0)
										  (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=12;	
										(*rtgd_buffer[rtgd_counter-1])[k-1][1]%=12;
										(*rtgd_buffer[rtgd_counter-1])[k-1][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][1]+(12*((*rtgd_buffer[rtgd_counter-1])[k-1][2]+2));										
									}											
			
									/********************************************************/
																	
									data[0]=(*rtgd_buffer[rtgd_counter-1])[k-1][3];
									data[1]=(*rtgd_buffer[rtgd_counter-1])[k-1][4];
									if(!mf_write_midi_event(prev_duration, note_on, players[playerCount]->local_params[CHN], data, 2)) {
										fprintf(stderr, "Error writing midi file!\n");
										return -1;
									}
									data[1]=(*rtgd_buffer[rtgd_counter-1])[k-1][6];	
									if(!mf_write_midi_event(prev_duration=(*rtgd_buffer[rtgd_counter-1])[k-1][5], note_off, players[playerCount]->local_params[CHN], data, 2)) {
										fprintf(stderr, "Error writing midi file!\n");
										return -1;
									}
									sprintf(string_buf, "%d%d%d%d%d", (*rtgd_buffer[rtgd_counter-1])[k-1][1], (*rtgd_buffer[rtgd_counter-1])[k-1][2], (*rtgd_buffer[rtgd_counter-1])[k-1][4], (*rtgd_buffer[rtgd_counter-1])[k-1][5], (*rtgd_buffer[rtgd_counter-1])[k-1][6]);
									buffer[counter++]=hash(string_buf, 0);									
									if(debugOption)
										printf("note: %d parameters: %d %d %d %d\n", (*rtgd_buffer[rtgd_counter-1])[k-1][1], (*rtgd_buffer[rtgd_counter-1])[k-1][2], (*rtgd_buffer[rtgd_counter-1])[k-1][4], (*rtgd_buffer[rtgd_counter-1])[k-1][5], (*rtgd_buffer[rtgd_counter-1])[k-1][6]);	//debug
									prev_duration=0;									
							}	
					}	
					free(rtgd_buffer[rtgd_counter-1]);
					rtgd_counter--;
				}			
				melop[op_counter-1][0]=melop[op_counter-1][1]=0;
				op_counter--;
				break;
			case _UPDATE:
				calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1], nt, players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]);
				break;
			case _REP:
				rep[i][0]=players[playerCount]->productions[nt]->cc+1;
				switch(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]) {
					case 0:
						rep[i++][1]=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2];
						break;
					case 1:
						rep[i++][1]=players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value:global_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value;
						break;
					case _EXP:
						rep[i++][1]=calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2], nt, BYTEDATA);
				}
					if(!rep[i-1][1]) {
						j++;
						while(j) {
							if(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]==_REP)
								j++;
							if(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]==_ENDREP)
								j--;
							if(players[playerCount]->productions[nt]->cc+1<DIM_MIDI_CODE)
								players[playerCount]->productions[nt]->cc++;
							else
								break;
						}
					}				
				break;
			case _ENDREP:
				if(rep[i-1][1]-1) {
					players[playerCount]->productions[nt]->cc=rep[i-1][0];
					rep[i-1][1]--;
					continue;
				}
				else
					i--;				
				break;
			case _CHORD:
				if(debugOption && !rtgd_counter)
				  printf("Playing a chord...\n");	//debug
				else
					(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][0]=_ENDCHORD;				  
				isChord=1;
				strcpy(string_buf, "");
				break;
			case _ENDCHORD:
				if(debugOption && !rtgd_counter)
				  printf("Chord ended\n");			//debug
				isChord=0;
				buffer[counter++]=hash(string_buf, 0);
				if(!rtgd_counter) {
					sort_attack(chord, 0, --note_chord_counter);
					for(k=0; k<=note_chord_counter; k++) {
						data[0]=chord[k][0];
						data[1]=chord[k][1];
						if(!mf_write_midi_event(chord[k][4], note_on, players[playerCount]->local_params[CHN], data, 2)) {
							fprintf(stderr, "Error writing midi file!\n");
							return -1;
						}					
					}
					sort_duration(chord, 0, note_chord_counter);
					data[0]=chord[0][0];
					data[1]=chord[0][3];
					if(!mf_write_midi_event(chord[0][2], note_off, players[playerCount]->local_params[CHN], data, 2)) {
						fprintf(stderr, "Error writing midi file!\n");
						return -1;
					}				
					for(k=1; k<=note_chord_counter; k++) {
						data[0]=chord[k][0];
						data[1]=chord[k][3];
						if(!mf_write_midi_event((chord[k][2]+chord[k][4])-(chord[k-1][2]+chord[k-1][4]), note_off, players[playerCount]->local_params[CHN], data, 2)) {
							fprintf(stderr, "Error writing midi file!\n");
							return -1;
						}
					}
					note_chord_counter=0;
				}
				else
					(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][0]=_ENDCHORD;
				break;
			case _PRNT:
				switch(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]) {
					case 0:
						printf("%d", players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]);
						break;
					case 1:
						printf("%d", players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value:global_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value);
						break;
					case _EXP:
						printf("%d", calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2], nt, players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][3]));
						break;
					case _STR:
						printf("%s", strings[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]]);
				}		
		}
		if(players[playerCount]->productions[nt]->cc+1<DIM_MIDI_CODE)
			players[playerCount]->productions[nt]->cc++;
		else
			break;		
	}
	return 0;
}

void lindenmayer_generator(unsigned int nt, unsigned int iteration) {
	unsigned int buffer[DIM_BUFFER], supporto[DIM_BUFFER], *pointerToBuffer;
	
	register unsigned int i, j;
	
	memset(supporto, 0, DIM_BUFFER);
	lindenmayer_prod_generator(nt, supporto);
	for(i=1; i<iteration; i++) {
		pointerToBuffer=buffer;
		for(j=0; nt=supporto[j]; j++)
			if(players[playerCount]->productions[nt]) {
				lindenmayer_prod_generator(nt, pointerToBuffer);
				while(*pointerToBuffer)
					pointerToBuffer++;
			}
		memset(supporto, 0, DIM_BUFFER);		
		memcpy(supporto, buffer, DIM_BUFFER);
		memset(buffer, 0, DIM_BUFFER);
	}	
}

int myputc(c) {
	return putc(c, midi);	
}

int write_player_track(track) {
	register unsigned int iteration;
	
	playerCount = track;
	memset(melop, 0, MAX_RECURSION*2);
	if(!globalWritten) {
		if(!mf_write_meta_event(0, copyright_notice, copyright, strlen(copyright))) {
			fprintf(stderr, "Error writing midi file!\n");
			return -1;
		}
		mf_write_tempo((long)60000000/tempo);
		globalWritten++;
	}
	prev_duration=0;
	if(!debugOption)
		printf("Player %s is generating...\n", players[playerCount]->identifier);
	players[playerCount]->num?(data[0]=players[playerCount]->num):(data[0]=glob_num);
	players[playerCount]->den?(data[1]=log10(players[playerCount]->den)/log10(2)):(data[1]=log10(glob_den)/log10(2));
	data[2]=24;
	data[3]=8;
	if(!mf_write_meta_event(0, time_signature, data, 4)) {
		fprintf(stderr, "Error writing midi file!\n");
		return -1;
	}
	players[playerCount]->local_params[DEFINSTR]?(data[0]=players[playerCount]->local_params[DEFINSTR]):(data[0]=global_params[DEFINSTR]);	
	if(!mf_write_midi_event(0, program_chng, players[playerCount]->local_params[CHN], data, 1)) {
		fprintf(stderr, "Error writing midi file!\n");
		return -1;
	}	
	players[playerCount]->iterations?(iteration=players[playerCount]->iterations):(iteration=global_iterations);
	switch(players[playerCount]->grammar) {
		case 1:
			if(debugOption)
				print_local_params(playerCount);		//debug
			chomsky_generator(hash("@composition", 0), 0);
			break;
		case 2:
			if(debugOption)
				print_local_params(playerCount);		//debug
			lindenmayer_generator(hash("axiom", 0), iteration);
			break;
		default:
			if(debugOption)
				print_local_params(playerCount);		//debug
			switch(grammarOption) {
				case 1:
					chomsky_generator(hash("@composition", 0), 0);
					break;
				case 2:
					lindenmayer_generator(hash("axiom", 0), iteration);
			}
	}
	if(!debugOption)
		printf("\n...ok\n");
	return 1;
}

int grammyvm() {
	unsigned int ntracks;

	if(!strcmp(namefile, ""))
		strcpy(namefile, DEFAULT_FILENAME);
	if(!(midi=fopen(namefile, "w"))) {
		fprintf(stderr, "Error writing midi file!\n");
		exit(1);
	}
	if(debugOption) {
	  print_composition_info();		//debug
	  print_global_params();		//debug
	}
	Mf_putc=myputc;
	Mf_writetrack=write_player_track;
	mfwrite(0, playerCount, global_resolution, midi);
	if(!debugOption)
		printf("midi file succesfully generated!\n");
}
