[RESOLU] Ré-écriture de fichiers MIDI, Si possible automatisée |
Bienvenue invité ( Connexion | Inscription )
[RESOLU] Ré-écriture de fichiers MIDI, Si possible automatisée |
25 Feb 2018, 13:20
Message
#1
|
|
Macbidouilleur d'argent ! Groupe : Membres Messages : 659 Inscrit : 7 May 2015 Membre no 195 224 |
Bonjour,
J'ai une série de fichiers MIDI (plus de 200) à réécrire légèrement. Le Format MIDI est écrit en hexa, pour faire simple (je passe les en-têtes), j'ai une première série d'octets indiquant un délai à attendre avant l'évènement suivant. Ensuite arrive un octet de type d'évènement (0x80 à 0xFF). Pour les évènements concernant des notes, seul le bit de poids fort indique l'action, le second bit indique le canal MIDI. Suivant l'évènement, le nombre d'octets à suivre est soit défini (entre 1 et 3), soit précisé par l'octet suivant. Bref, ce qui m'intéresse particulièrement, ce sont les notes elles-mêmes. Elles sont écrites comme ceci :
Je cherche sur l'ensemble de mes fichiers à chercher toutes les notes du canal 0, et si la hauteur est inférieure à 54, la placer sur le canal 2 ; si la hauteur est inférieure à 66, la placer sur le canal 1 ; la laisser sur le canal 0 si la hauteur est supérieure ou égale à 66. Dit comme ça, ça ne me parait pas bien compliqué. J'ai commencé par faire un script dans HarmonyAssistant qui fait le boulot. Dans l'ensemble, ça fonctionne à peu près, sauf que Harmony gère mal le format MIDI, il préfèrerait des .mus. En fait un morceau sur deux est mal importé. Donc même si le script fait bien le travail, il part d'un fichier mal importé. Donc après export, mes MIDI ne correspondent plus du tout à la musique originale. J'ai essayé MuseScore, qui abîme moins le fichier original lors de l'importation, mais qui l'abîme quand même. J'ai essayé également MidiSwing, qui semble mieux gérer l'import mais qui ne peut pas faire d'actions automatisée sur le fichier. J'ai donc cherché à réaliser un programme qui réalise le travail directement sur le fichier en le lisant en hexa. Sauf que je ne sais pas faire ça sur ordi, alors j'ai programmé un µC (en C), en utilisant la bibliothèque FatFs. Le programme ouvre le fichier (en lecture/ecriture) depuis une carte SD, enregistre avant chaque nouvel évènement le pointeur de l'endroit où il se trouve dans le fichier. S'il repère une ouverture ou fermeture de note sur le canal 0, il lit l'octet suivant pour connaître la hauteur de la note et si les conditions sont remplies, il revient en arrière au niveau de l'octet d'évènement et réécrit l'octet pour y mettre le bon canal (il écrit 0x81, 0x82, 0x91 ou 0x92 suivant le cas). Ca fonctionne... pour la première note à modifier Dès la deuxième écriture, il n'arrive pas à terminer son cycle d'écriture (il ne sort pas de la fonction f_write()) et le fichier devient inutilisable. Il doit y avoir quelque chose que je n'ai pas compris dans la fonction f_write() de la bibliothèque FatFS mais je ne vois pas du tout ce qui se passe. Voilà, si quelqu'un a une idée de la méthode que je pourrai employer pour simplement modifier mes octets d'évènements en étant sûr de ne pas toucher au reste (contrairement aux logiciels d'édition de partitions), ça m'intéresse beaucoup. Je n'ai jamais programmé en C sur ordinateur, mais je suis prêt à apprendre (ça ne doit pas trop changer par rapport aux µC). Si ça pouvait être fait par un simple script, ce serait peut-être plus simple mais j'ai bien du mal à trouver comment lire en hexa dans un fichier. Pour contrôler les modifs visuellement je n'ai trouvé que cette commande qui affiche le contenu du fichier en hexa dans le Terminal Code od -t x1 "nomDuFichier.mid" Sinon, si vous avez une idée sur la raison qui empêche mon µC d'écrire à plusieurs reprises dans un même fichier, ça pourrait être encore la solution la plus facile pour moi... Merci beaucoup pour votre aide. Extrait de mon programme sur µC : CODE #define READ_BYTES ((f_read(&File, &buff, bytesToRead, &readedBytes) == FR_OK) && (readedBytes == bytesToRead))
#define WRITE_BYTES ((f_write(&File, &newEvent, 1, &readedBytes) == FR_OK) && (readedBytes == 1)) MIDI_RESULT Read_MIDI_Event(void) { // Lecture de la musique proprement dite long buff = 0; // Buffer de sortie (initialisé pour être sûr qu'il ne reste rien dedans : sa taille est plus grande que les premières données à lire...)) unsigned int bytesToRead = 1; unsigned int readedBytes; char i, str[NB_COL+1]; unsigned char newEvent; long pointer = File.fptr; if (!READ_BYTES) return MID_TRUNCATE; // Evènement précédent terminé, recherche du nouveau nombre de lectures if (!readsToDo) { // Nouveau Statut : on enregistre et on re-lit. Sinon, même évènement que précédent if (buff & 0x80) { Event = buff; // Real-Time messages, octet seul qui ne nous intéresse pas if (Event > 0xF0 && Event < 0xFF) return MID_OK; else if (Event == 0x80 || Event == 0x90) { if (!READ_BYTES) return MID_TRUNCATE; if (buff < 66) { DataLED = 1; if (f_lseek(&File, pointer) != FR_OK) return INVALID_FILE; newEvent = Event & 0xF0; if (buff < 54) newEvent = newEvent | 0x02; else newEvent = newEvent | 0x01; //if (f_putc(buff, &File) < 0) return WRITE_ERR; if (!WRITE_BYTES) return WRITE_ERR; if (!READ_BYTES) return MID_TRUNCATE; DataLED = 0; } } else // On lit le premier octet if (!READ_BYTES) return MID_TRUNCATE; } // Meta-Event, on enregistre son type puis le nombre de lectures if (Event == 0xFF) { if (!buff) return INVALID_MIDI; metaEvent = buff; // puis lire le nombre de lectures do { if (!READ_BYTES) return MID_TRUNCATE; readsToDo = readsToDo << 7; readsToDo += (buff & 0x7F); } while ((buff & 0x80) > 0); if (readsToDo > 0) { // reads>0 pour éviter un "MID_TRUNCATE" : c'est le cas d'un évènement Fin de Piste qui a 0 bits à lire derrière // On lit le premier octet if (!READ_BYTES) return MID_TRUNCATE; } // On incrémente readsToDo s'il est nul pour pas qu'il ne se retrouve négatif en fin de lecture else readsToDo++; } // System Exclusive, donne sa longueur par un byte de fin (0xF7) else if (Event == 0xF0) readsToDo = 1; // DONNEES else { // ProgChange et CanalPressure n'ont qu'un byte à lire if ((Event & 0xF0) == 0xC0 || (Event & 0xF0) == 0xD0) readsToDo = 1; else readsToDo = 2; } } // Nombre de lectures enregistré, on traite l'octet lu et on décrémente readsToDo // META-EVENT if (Event == 0xFF && metaEvent == 0x2F) { // Fin de piste nbPistes--; if (!nbPistes) return MID_EOF; else return Read_Track_Headers(); } else if (Event == 0xF0) { while (buff != 0xF7) { if (!READ_BYTES) return MID_TRUNCATE; } readsToDo--; return MID_OK; } else { readsToDo--; while (readsToDo) { if (!READ_BYTES) return MID_TRUNCATE; readsToDo--; } return MID_OK; } } Ce message a été modifié par Anard - 1 Mar 2018, 15:38. -------------------- "iMack" : GA-H97M-D3H, Intel i5 4460, 16Go DDR3,
"Portable" : HP Pavilion DV3500, Intel core2 T6400, 4Go DDR3, NVidia GeForce 9300M, HDD 256Go / Grub2 - Gentoo-Xfce |
|
|
2 Mar 2018, 02:18
Message
#2
|
|
Macbidouilleur de vermeil ! Groupe : Membres Messages : 1 198 Inscrit : 8 Oct 2003 Membre no 10 220 |
Salut,
Il faut que tu convertisses en big endian à la sauvegarde. Un peu de lecture: Endian independent code Le plus simple c'est d'utiliser les fonctions htons ntohs si la lib est dispo pour toi. Sinon faire une petite routine: Code short swapShort(short v) { short r; // valeur de v inversée char *in=(char*)&v; char *out=(char*)&r; out[0]=in[1]; out[1]=in[0]; return r; } Tu dois faire le swap à la lecture du fichier et une nouvelle fois à l'écriture dans le fichier. Pour les ints 32 bits, Je te laisses faire la routine toi même |
|
|
Nous sommes le : 6th May 2024 - 15:03 |