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