IPB

Bienvenue invité ( Connexion | Inscription )

> [RESOLU] Ré-écriture de fichiers MIDI, Si possible automatisée
Options
Anard
posté 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 :
  • Octet d'évènement :
    • 0x8c = fermer la note sur le canal c
    • 0x9c = ouvrir la note sur le canal c
  • Octet de hauteur de note : une valeur entre 0 et 127 (0x00 à 0xFF)
  • Octet de vélocité, correspondant à une force de frappe entre 0 et 100. Celui-ci ne m'intéresse pas.


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 mad.gif 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, Asus GTX670 Intel HD4600, 2x SSD 256Go, HDD 500Go+Zraid 3x2To / Clover - macOS Mojave / Gentoo-Xfce
"Portable" : HP Pavilion DV3500, Intel core2 T6400, 4Go DDR3, NVidia GeForce 9300M, HDD 256Go / Grub2 - Gentoo-Xfce
Go to the top of the page
 
+Quote Post
 
Start new topic
Réponse(s)
mpergand
posté 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 wink.gif
Go to the top of the page
 
+Quote Post

Les messages de ce sujet


Reply to this topicStart new topic
1 utilisateur(s) sur ce sujet (1 invité(s) et 0 utilisateur(s) anonyme(s))
0 membre(s) :

 



Nous sommes le : 6th May 2024 - 15:03