Projet IFT6080 Transfert de fichier WAV à MIDI
Transcription
Projet IFT6080 Transfert de fichier WAV à MIDI
Projet IFT6080 Transfert de fichier WAV à MIDI Fait par Stanislas Lauly Présenté à Douglas Eck Introduction Le projet que j’ai choisi de réaliser dans le cadre du cours IFT6080 est de monter un programme ayant la capacité d' analyser un fichier musical pour en extraire les éléments importants afin de créer ensuite un fichier Midi correspondant à la musique du fichier. Analyser le signal audio d’une musique pour en recréer la partition est un problème complexe qui n’a toujours pas été complètement résolu. Il existe pour l’instant des programmes qui donnent de bons résultats pour la musique mono instrumentale. Cependant dès qu’il y a plus de deux instruments la qualité des résultats n’est plus très bonne. De plus, même lorsqu’il s’agit d’analyser le signal audio d’une musique avec un seul instrument, cela peut représenter un défi considérable, car beaucoup d’instruments sont polyphoniques, c' est-à-dire qu’un seul instrument peut jouer plusieurs notes de musique en même temps. 1 Pour commencer mon projet, j’ai été obligé dans un premier temps de m’astreindre à faire certains choix. Par exemple j’ai choisi de spécialiser mon programme dans la musique mono instrumentale, mais l’instrument pour lequel j’ai opté est le piano, ce qui signifie que l’analyse porte principalement sur de la musique polyphonique. La technique utilisée pour créer ce programme comprend deux grandes étapes : - La première étape consiste à être capable de déterminer tous les « onset » à partir du signal audio (Wav) d' une musique. Il s' agit donc d' être en mesure d' identifier à quel moment une nouvelle entrée de son s' effectue, ce qui devrait en fait correspondre à une note jouée par le musicien. - La deuxième étape est d’analyser une portion du signal audio, qui correspond au « onset » trouvé auparavant, afin de découvrir le nombre de notes qui sont jouées à ce moment-là ainsi que la fréquence de chacune de ces notes. 2 Première étape Cette première étape consiste à identifier les entrées, c' est-à-dire à déterminer dans un fichier Wav, l’apparition d’une nouvelle note. Pour y parvenir, la technique suivante a été utilisée : - Il faut commencer par lisser le signal audio, mis en absolu, en prenant le nombre de points du signal qu’il faut pour faire des fenêtres de 25ms puis en calculant la moyenne de ces fenêtres. - Ensuite, il s’agit de mettre à zéro les points du signal qui sont plus petits que la moyenne de l’amplitude des points. Ceci facilite la tâche de l’algorithme qui doit trouver les sommets (pics) du signal. - L’étape suivante consiste à calculer la différence du signal, c’est-àdire à calculer le changement d’amplitude entre chacun des points qui se suivent. Ceci a pour effet de rendre les sommets plus individuels, plus fins et plus pointus. - Finalement pour diminuer les chances d’identifier de faux « onset », l’auto corrélation du signal est utilisée pour permettre de trouver le temps de base de la musique du signal analysé. Ensuite le temps qui sépare les « onset » est comparé avec le temps de base pour vérifier si il est compatible et si il ne s’agit pas d’une erreur due à la trop forte amplitude de bruits parasites. Le problème c’est que l’auto corrélation ne fonctionne pas bien sur de trop longs signaux audio. Par exemple, 3 dans le cas d’une musique très simple d’une durée de deux minutes, si le temps qui sépare deux « onset » est en moyenne de une seconde, mais qu’il existe également quelques rares « onset » possédant un temps qui les sépare de 0.5 seconde, l’auto corrélation donnera sûrement un temps de base de une seconde. Ceci veut dire que le programme ne va pas trouver certains « onset » qui correspondent aux notes possédant un temps qui les sépare de 0.5 seconde. o = onset 0.02 0.018 0.016 0.014 0.012 0.01 0.008 0.006 0.004 0.002 0 0 50 100 150 200 250 300 350 400 Fréquence Pour améliorer les performances, j’ai décidé de découper la totalité du signal audio en portions de huit secondes et d’appliquer toute la technique décrite précédemment sur chacune de ces portions. Chaque portion se chevauche sur un espace de deux secondes. Les « onset » trouvés pour les portions qui se chevauchent sont comparés afin de ne pas risquer de créer des doublets. 4 Deuxième étape La deuxième étape a pour but d’identifier les notes de musique jouées, de même que leur durée, pour chacun des « onset » préalablement trouvés. Pour y parvenir le vieux dicton « diviser pour mieux régner » a servi de point de départ. C’est-à-dire que la deuxième étape a été séparée en quatre sous parties pour réussir à obtenir un algorithme qui donne de bons résultats. Ces quatre subdivisions sont les suivantes : - La fonction « processPitch » a pour but d’identifier les fréquences qui correspondent aux notes de musique jouées au moment d’un « onset » ainsi que les fréquences jouées juste avant et que l’on continue encore à entendre dans le « onset » actuel. L’inconvénient de cette méthode vient du fait qu’il est parfois possible d’identifier des fréquences supplémentaires à cause des harmoniques des notes principales. Pour identifier les fréquences, il faut appliquer la transformée de Fourier, avec un grand nombre de points pour obtenir une grande précision, sur la portion du signal qui correspond au « onset ». À cette étape, les principaux sommets sont choisis et représentent les notes de musique que l’on entend. Le problème majeur qui se pose vient du fait que la fréquence principale n’est souvent pas assez précise. Il faut donc nécessairement se baser sur les harmoniques des notes pour obtenir une fréquence plus précise. 5 - La fonction « pitchFinderCord » sert justement à trouver une plus grande précision pour chaque fréquence approximative qui a été découverte au moyen de la fonction « processPitch ». La même transformée de Fourier que celle de la fonction précédente est utilisée dans le but de trouver le plus d’harmoniques possibles. Ainsi donc les sommets de fréquences présentant une moins grande amplitude sont également choisis. Ensuite il faut identifier chaque sommet de fréquence correspondant à une harmonique de la fréquence approximative fournie par la fonction « processPitch ». La moyenne des harmoniques donne une fréquence généralement assez précise pour correspondre à la note de musique jouée. 6 Une fois que les deux dernières fonctions qui viennent d’être expliquées sont appliquées sur une portion de signal représentant un « onset », on obtient comme résultat une liste de notes correspondant aux fréquences les plus importantes du signal. Cette liste peut contenir les notes qui ont été jouées au moment du « onset », les notes qui ont été jouées avant ce même « onset », ainsi que l’harmonique d’une note jouée pendant ou avant ce « onset ». - La fonction « filtreHarmo » prend une liste de notes qui est le résultat des deux fonctions décrites auparavant. Pour chaque note, le programme vérifie si la note trouvée correspond à une note jouée, ou encore à une de ses harmoniques, dans le « onset » précédent et qui avait été tenue mais non rejouée. Pour savoir si c’est la même note qui a été rejouée, on compare les amplitudes des fréquences des notes. Ensuite on identifie les harmoniques des notes principales et on les enlève. La difficulté vient du fait qu’il se peut qu’une note principale 7 soit aussi l’harmonique d’une autre note principale. Il faut alors essayer de comparer entre elles l’amplitude des fréquences des harmoniques. Il est extrêmement difficile de prédire le comportement de l’amplitude d’une harmonique, ce qui fait penser qu’un réseau neuronal pourrait être efficace pour effectuer cette tâche. - Finalement la fonction « trouverDurer » s’occupe de vérifier pour chaque note de musique de chaque « onset » si on continue à les entendre dans les « onset » qui suivent pour pouvoir calculer la durée approximative de chacune des notes jouées. Pour réussir à faire cela, il a fallu créer une liste de toutes les notes dans les « onset » considérées comme ayant été jouées à ce moment. Il a également fallu créer une autre liste qui contient toutes les fréquences considérées comme importante dans un « onset », mais qui n’était pas une note jouée à ce moment là. Il suffit de regarder pour chacune des notes dans la première liste si chacune de ces notes est retrouvée dans la deuxième liste au « onset » suivant. Résultats et conclusion Les résultats obtenus pour la première étape,celle qui consiste à trouver les « onset », sont bons lorsque les notes de musique d’un fichier WAV sont jouées avec un intervalle minimal de 250ms, mais la performance diminue grandement en dessous de 200ms. Le programme a aussi de la difficulté à 8 trouver les « onset » qui sont constitués de notes graves jouées avec peu d’intensité et qui se trouvent à proximité d’un « onset » constitué de notes plus aigues. Les résultats obtenus pour la deuxième étape, celle où il faut trouver la fréquence des notes de chaque « onset », fonctionnent bien pour la musique monophonique. Pour la musique polyphonique, les résultats sont encore bons si on ne dépasse pas quatre notes par « onset » et qu’il n’y a pas trop de notes qui sont maintenues pendant que de nouvelles jouées. Le gros problème est de géré les harmoniques, car il n’est pas toujours évident de savoir si le sommet d’une fréquence fournie par la transformée de Fourier correspond à une nouvelle note jouée ou à l’harmonique d’une autre note de musique jouée que ce soit dans le même « onset » ou dans celui qui le précède. 9 Avec un peu de recul, il me semble qu’il aurait fallu utiliser un spectrogramme pour réaliser la première partie du projet, trouver les « onset ». Il me semble en effet que c’est en analysant les changements d’amplitudes de fréquences par rapport au temps qu’il y a le plus de chance de se rendre compte qu’une nouvelle note de musique vient d’apparaître plutôt qu’en se basant uniquement sur les changements d’amplitudes du signal audio. Pour ce qui est de l’analyse des fréquences d’un signal audio correspondant à un « onset », il semble qu’un réseau neuronal pourrait être très efficace pour prédire le comportement des harmoniques d’une note jouée. Ceci pourrait permettre de mieux faire la différence entre une note jouée et l’harmonique d’une autre note. 10