// Version 1.1: 5 de junio de 2013 // corregido un bug debido a considerar la pista de control como una pista normal // El error se puso de manifiesto al tratar de leer un midi de voces con musescore // Gracias a Angel Criado por avisarme de este error. #define SI 1 #define NO 0 #define ISOLISTA 71 #define IACOMP 4 #define MAXTRACKS 24 #include #include #include struct track { char myl[8]; /*marca y longitud*/ int longitud; /*longitud de la pista sin contar los 8 bytes iniciales*/ unsigned char *datos; /*la pista propiamente dicha*/ char *nombrepista; int posinstrumento; /*posicion en datos donde va el instrumento*/ int posvolumen; /*posicion en datos donde va el volumen*/ int pospanning; /*posicion en datos donde va el panning*/ unsigned char instrumento; /*instrumento original de la pista*/ unsigned char volumen; /*volumen original*/ int enabled; /*flag que indica si se creara un fichero con esta pista destacada*/ }; struct opciones { int cambiaracomp; /*flag que indica si hay que cambiar los instrumentos de las pistas de acompaniamiento*/ unsigned char acomp; /*el instrumento de acompaniamiento*/ unsigned char instrumento[MAXTRACKS]; /*instrumentos de cada pista destacada*/ }; /******************************************************************/ /*la organizacion de los 4 bytes de un int en memoria * va en orden contrario a como se guarda en el fichero, por eso * es necesario dar la vuelta byte a byte a la informacion leida*/ int vuelveint (char *s) { int resultado, i; unsigned char n; resultado=0; for (i=0; i<4; i++) { n=s[i]; resultado=resultado*256+(int)n; } return resultado; } /*************************************************************/ /*leer abre el fichero MIDI y lo guarda en memoria * la estructura track contiene dos campos principales * myl, donde va la marca y longitud y * datos donde va todo lo demas*/ leer (struct track *midi, char *nombrefichero) { FILE *p; int l,i; int ntracks; if ((p=fopen(nombrefichero,"r"))==NULL) { printf ("Error al abrir el fichero %s\n",nombrefichero); exit (1); } /*en primer lugar hay que leer la cabecera * entre otros datos, aqui esta la informacion sobre cuantas pistas * hay en el fichero*/ fread (midi[0].myl, 8, 1, p); if (midi[0].myl[0]!='M' || midi[0].myl[1]!='T' || midi[0].myl[2]!='h' || midi[0].myl[3]!='d') { printf ("El fichero %s no es MIDI\n", nombrefichero); exit (2); } l=vuelveint(midi[0].myl+4); midi[0].longitud=l; midi[0].datos=malloc(l); fread(midi[0].datos, 1, l, p); if (midi[0].datos[0]!=0 || midi[0].datos[1]!=1) { printf("El fichero MIDI %s no es de formato 1\n", nombrefichero); exit(3); } if (midi[0].datos[2]!=0 || midi[0].datos[3]>=MAXTRACKS) { printf("El fichero MIDI %s tiene demasiadas pistas\n", nombrefichero); exit(7); } ntracks=(int)midi[0].datos[3]; /*ya sabemos cuantas pistas hay, ahora las guardamos una a una*/ for (i=1; i<=ntracks; i++) { fread (midi[i].myl, 8,1, p); if (midi[i].myl[0]!='M' || midi[i].myl[1]!='T' || midi[i].myl[2]!='r' || midi[i].myl[3]!='k') { printf ("Pista %d invalida\n", i); exit (4); } l=vuelveint(midi[i].myl+4); midi[i].longitud=l; midi[i].datos=malloc(l); fread(midi[i].datos, 1, l, p); } fclose (p); } /*************************************************************************/ /*copianombre coloca en un campo de la estructura track el nombre de la pista*/ char * copianombre(char *data,int l){ int i; char * name; name=malloc(l+1); for (i=0;i'9')) return -1; a=(int)(s[i]-(int)'0'); resultado=resultado*10+a; } return resultado; } /****************************************************************/ /*leeropciones analiza la linea de comandos y rellena la estructura * opciones con los datos que obtiene. * Las opciones posibles son -a que indica que hay que cambiar el instrumento * de las pistas de acompaniamiento por un instrumento por defecto, o por el * instrumento especificado a continuacion de -a. * Cualquier otro numero en la linea de comandos se interpreta como un * instrumento para dar a las pistas destacadas, por orden. Si se suministran * menos instrumentos que pistas, se usara el ultimo instrumento suministrado*/ leeropciones(struct opciones *options, int argc, char *argv[]) { int i,k; int n; int a; /*primero damos valores por defecto*/ options->cambiaracomp=NO; options->acomp=IACOMP; for (i=0; iinstrumento[i]=ISOLISTA; } /*y ahora analizamos la linea de comando*/ if (argc>MAXTRACKS+2) { printf("Excesivo numero de instrumentos\n"); exit (11); } if (argc>2) { k=0; a=NO; for (i=2; i127) { printf("Instrumento fuera de rango\n"); exit (12); } if (n!=-1) if (a==SI) { options->acomp=(unsigned char)n; a=NO; } else options->instrumento[k++]=(unsigned char)n; else if (strcmp(argv[i], "-a")==0) { options->cambiaracomp=SI; a=SI; } else { printf("Error de sintaxis\n"); exit(10); } } /*rellenamos las otras pistas con el ultimo instrumento*/ if (k>0) { for (i=k; iinstrumento[i]=options->instrumento[k-1]; } } } /***************************************************************/ /*breves instrucciones de uso*/ usage() { printf("\nsplitmidi 1.0\n"); printf("instrucciones: splitmidi fichero.mid [n1 n2 n3 ...] [-a [n]]\n\n"); printf("Los parametros n1, n2, ... son los diferentes instrumentos\n"); printf("que toman las pistas destacadas. El parametro n es el instrumento\n"); printf("que toman las demas voces por defecto. Si no se utiliza la opcion -a,\n"); printf("los instrumentos asignados a las demas voces no se alteran.\n"); printf("Los parametros entre corchetes son opcionales.\n\n"); printf("El programa splitmidi programa toma un fichero MIDI con n pistas\n"); printf("y genera n ficheros MIDI cada uno de los cuales tiene \n"); printf("una pista destacada sobre las demas.\n"); printf("Para destacar las voces, cada fichero creado sufre los siguientes cambios:\n"); printf("1. el instrumento: se le da un instrumento a cada pista destacada mediante\n"); printf(" la linea de comandos, o bien, se le da un valor por defecto.\n"); printf("2. el panning: se pone a 127 y el resto de las voces a 0, es decir\n"); printf(" la voz principal va por un altavoz y el resto por el otro.\n"); printf("3. el volumen: se pone a 127, el valor maximo, las otras voces no se alteran.\n\n"); printf("Debido a la limitada funcionalidad del programa se requiere que:\n"); printf("1. el fichero de entrada sea de formato MIDI 1\n"); printf("2. el fichero de entrada tenga la extension .mid, .MID, o .Mid\n"); printf("3. los primeros eventos de cada pista sean metaeventos\n"); printf(" de texto, controladores, o cambios de instrumento\n"); printf("4. las voces que se deseen extraer han de tener asignada:\n"); printf(" nombre de la pista, volumen, panning, e instrumento.\n"); printf(" En caso contrario, no se creara el respectivo fichero.\n"); printf("\nCopyright http://tomasluisdevictoria.org\n"); } /****************************************************************/ int main (int argc, char *argv[]) { struct track midi[MAXTRACKS]; struct opciones options; if (argc<2) { usage(); exit (9); } leeropciones(&options, argc, argv); leer(midi, argv[1]); analizar(midi, options); escribir(midi, argv[1], options); return 0; }