Question

Je développe un système pour aider les musiciens à effectuer des transcriptions.L'objectif est d'effectuer une transcription automatique de la musique (elle ne doit pas nécessairement être parfaite, car l'utilisateur corrigera les problèmes/erreurs plus tard) sur un enregistrement monophonique d'un seul instrument.Quelqu'un ici a-t-il de l'expérience dans la transcription automatique de musique ?Ou le traitement du signal numérique en général ?L’aide de quiconque est grandement appréciée, quel que soit votre parcours.

Jusqu'à présent, j'ai étudié l'utilisation de la transformation de Fourier rapide pour la détection de hauteur, et un certain nombre de tests dans MATLAB et dans mes propres programmes de test Java ont montré qu'elle était suffisamment rapide et précise pour mes besoins.Un autre élément de la tâche qui devra être abordé est l'affichage des données MIDI produites sous forme de partitions, mais c'est quelque chose qui ne m'intéresse pas pour le moment.

En bref, ce que je recherche, c'est une bonne méthode de détection de l'apparition des notes, c'est-à-direla position dans le signal où commence une nouvelle note.Comme les apparitions lentes peuvent être assez difficiles à détecter correctement, j'utiliserai dans un premier temps le système avec des enregistrements de piano.Cela est également dû en partie au fait que je joue du piano et que je devrais être dans une meilleure position pour obtenir des enregistrements appropriés pour les tests.Comme indiqué ci-dessus, les premières versions de ce système seront utilisées pour des enregistrements monophoniques simples, pouvant évoluer ultérieurement vers des entrées plus complexes en fonction des progrès réalisés dans les semaines à venir.

Était-ce utile?

La solution

Voici un graphique qui illustre l’approche seuil pour détecter l’apparition des notes :

alt text

Cette image montre un fichier WAV typique avec trois notes discrètes jouées successivement.La ligne rouge représente un seuil de signal choisi et les lignes bleues représentent les positions de début de note renvoyées par un algorithme simple qui marque un début lorsque le niveau du signal dépasse le seuil.

Comme le montre l’image, il est difficile de sélectionner un seuil absolu approprié.Dans ce cas, la première note est bien captée, la deuxième note est complètement manquée et la troisième note (à peine) est démarrée très tard.En général, un seuil bas vous amène à capter des notes fantômes, tandis que son augmentation vous fait manquer des notes.Une solution à ce problème consiste à utiliser un seuil relatif qui déclenche un démarrage si le signal augmente d'un certain pourcentage sur une certaine durée, mais cela pose ses propres problèmes.

Une solution plus simple consiste à utiliser la compression nommée de manière quelque peu contre-intuitive (pas de compression MP3 - c'est tout autre chose) sur votre fichier wave en premier.La compression aplatit essentiellement les pics de vos données audio, puis amplifie le tout afin qu'une plus grande partie de l'audio soit proche des valeurs maximales.L'effet sur l'échantillon ci-dessus ressemblerait à ceci (ce qui montre pourquoi le nom « compression » semble n'avoir aucun sens - sur les équipements audio, il est généralement appelé « volume ») :

alt text

Après compression, l'approche du seuil absolu fonctionnera beaucoup mieux (bien qu'il soit facile de surcompresser et de commencer à capter des débuts de notes fictives, le même effet que l'abaissement du seuil).Il existe de nombreux éditeurs Wave qui font un bon travail de compression, et il est préférable de les laisser gérer cette tâche - vous devrez probablement faire pas mal de travail pour "nettoyer" vos fichiers Wave avant de détecter des notes dans eux de toute façon.

En termes de codage, un fichier WAV chargé en mémoire n'est essentiellement qu'un tableau d'entiers de deux octets, où 0 ne représente aucun signal et 32 767 et -32 768 représentent les pics.Dans sa forme la plus simple, un algorithme de détection de seuil démarrerait simplement au premier échantillon et parcourrait le tableau jusqu'à ce qu'il trouve une valeur supérieure au seuil.

short threshold = 10000;
for (int i = 0; i < samples.Length; i++)
{
    if ((short)Math.Abs(samples[i]) > threshold) 
    {
        // here is one note onset point
    }
}

En pratique, cela fonctionne horriblement, car l'audio normal présente toutes sortes de pics transitoires au-dessus d'un seuil donné.Une solution consiste à utiliser une force de signal moyenne mobile (c.-à-d.ne marquez pas de départ tant que la moyenne des n derniers échantillons n'est pas supérieure au seuil).

short threshold = 10000;
int window_length = 100;
int running_total = 0;
// tally up the first window_length samples
for (int i = 0; i < window_length; i++)
{
    running_total += samples[i];
}
// calculate moving average
for (int i = window_length; i < samples.Length; i++)
{
    // remove oldest sample and add current
    running_total -= samples[i - window_length];
    running_total += samples[i];
    short moving_average = running_total / window_length;
    if (moving_average > threshold)
    {
        // here is one note onset point 
        int onset_point = i - (window_length / 2);
    }
}

Tout cela nécessite beaucoup de réglages et de manipulations pour lui permettre de trouver avec précision les positions de départ d'un fichier WAV, et généralement ce qui fonctionne pour un fichier ne fonctionnera pas très bien sur un autre.Il s'agit d'un domaine problématique très difficile et pas parfaitement résolu que vous avez choisi, mais je pense que c'est cool que vous vous y attaquiez.

Mise à jour:ce graphique montre un détail de détection de note que j'ai omis, à savoir la détection de la fin de la note :

alt text

La ligne jaune représente le hors-seuil.Une fois que l'algorithme a détecté le début d'une note, il suppose que la note continue jusqu'à ce que la force moyenne du signal descende en dessous de cette valeur (indiquée ici par les lignes violettes).C'est bien entendu une autre source de difficultés, comme c'est le cas lorsque deux ou plusieurs notes se chevauchent (polyphonie).

Une fois que vous avez détecté les points de début et de fin de chaque note, vous pouvez maintenant analyser chaque tranche de données du fichier WAV pour déterminer les hauteurs.

Mise à jour 2 :Je viens de lire votre question mise à jour.La détection de hauteur via l'autocorrélation est beaucoup plus facile à mettre en œuvre que FFT si vous écrivez la vôtre à partir de zéro, mais si vous avez déjà extrait et utilisé une bibliothèque FFT prédéfinie, vous feriez mieux de l'utiliser, c'est sûr. .Une fois que vous avez identifié les positions de début et de fin de chaque note (et inclus un peu de remplissage au début et à la fin pour les parties d'attaque et de relâchement manquées), vous pouvez maintenant extraire chaque tranche de données audio et la transmettre à une fonction FFT pour déterminer le terrain.

Un point important ici n’est pas d’utiliser une tranche des données audio compressées, mais plutôt une tranche des données originales non modifiées.Le processus de compression déforme l'audio et peut produire une lecture de hauteur inexacte.

Un dernier point concernant les temps d'attaque des notes est que cela peut être moins problématique que vous ne le pensez.Souvent, en musique, un instrument avec une attaque lente (comme un synthétiseur logiciel) commencera une note plus tôt qu'un instrument à attaque forte (comme un piano) et les deux notes sonneront comme si elles commençaient en même temps.Si vous jouez des instruments de cette manière, l'algorithme prend la même heure de début pour les deux types d'instruments, ce qui est bon du point de vue WAV vers MIDI.

Dernière mise à jour (j'espère) :Oubliez ce que j'ai dit à propos de l'inclusion de certains échantillons de remplissage de la première partie d'attaque de chaque note - j'ai oublié que c'était en fait une mauvaise idée pour la détection de la hauteur.Les parties d'attaque de nombreux instruments (en particulier le piano et autres instruments de type percussif) contiennent des transitoires qui ne sont pas des multiples de la hauteur fondamentale et auront tendance à gâcher la détection de la hauteur.C'est pour cette raison que vous souhaitez en fait commencer chaque tranche un peu après l'attaque.

Oh, et c'est assez important : le terme « compression » ici ne fait pas référence à la compression de type MP3.

Mettre à jour à nouveau :voici une fonction simple qui effectue une compression non dynamique :

public void StaticCompress(short[] samples, float param)
{
    for (int i = 0; i < samples.Length; i++)
    {
        int sign = (samples[i] < 0) ? -1 : 1;
        float norm = ABS(samples[i] / 32768); // NOT short.MaxValue
        norm = 1.0 - POW(1.0 - norm, param);
        samples[i] = 32768 * norm * sign;
    }
}

Lorsque param = 1.0, cette fonction n'aura aucun effet sur l'audio.Des valeurs de paramètre plus grandes (2,0 est une bonne chose, ce qui correspondra à la différence normalisée entre chaque échantillon et la valeur de crête maximale) produiront plus de compression et un son global plus fort (mais merdique).Les valeurs inférieures à 1,0 produiront un effet d’expansion.

Un autre point probablement évident :vous devez enregistrer la musique dans une petite pièce sans écho, car les échos sont souvent captés par cet algorithme sous forme de notes fantômes.

Mise à jour:voici une version de StaticCompress qui compilera en C# et transtypera tout explicitement.Cela renvoie le résultat attendu :

public void StaticCompress(short[] samples, double param)
{
    for (int i = 0; i < samples.Length; i++)
    {
        Compress(ref samples[i], param);
    }
}

public void Compress(ref short orig, double param)
{
    double sign = 1;
    if (orig < 0)
    {
        sign = -1;
    }
    // 32768 is max abs value of a short. best practice is to pre-
    // normalize data or use peak value in place of 32768
    double norm = Math.Abs((double)orig / 32768.0);
    norm = 1.0 - Math.Pow(1.0 - norm, param);
    orig = (short)(32768.0 * norm * sign); // should round before cast,
        // but won't affect note onset detection
}

Désolé, mon score de connaissances sur Matlab est de 0.Si vous avez posté une autre question expliquant pourquoi votre fonction Matlab ne fonctionne pas comme prévu, vous y répondriez (mais pas par moi).

Autres conseils

Ce que vous voulez faire s'appelle souvent WAV-to-MIDI (google & "; wav-to-midi &";). Ce processus a fait l’objet de nombreuses tentatives, avec des résultats variables (l’apparition de la note est l’une des difficultés; la polyphonie est beaucoup plus difficile à gérer). Je vous recommande de commencer par une recherche approfondie des solutions disponibles dans le commerce et de ne commencer à travailler que par vous-même s'il n'y a rien d'acceptable dans le marché.

L’autre partie du processus dont vous avez besoin est de rendre la sortie MIDI sous forme de partition musicale traditionnelle, mais il existe un grand nombre de produits qui le font.

Une autre réponse est: oui, j’ai fait beaucoup de traitement du signal numérique (voir le logiciel sur mon site Web - c’est un synthétiseur logiciel à la voix infinie écrit en VB et C), et j’aimerais vous aider avec ce problème. La partie WAV-to-MIDI n’est pas si difficile conceptuellement, elle consiste simplement à la rendre fiable et pratique. Le début de la note ne fait que définir un seuil - les erreurs peuvent être facilement ajustées en avant ou en arrière pour compenser les différences d'attaque de note. La détection de la hauteur est beaucoup plus facile à réaliser sur un enregistrement qu'en temps réel et consiste simplement à mettre en œuvre une routine d'auto-corrélation.

Vous devriez consulter MIRToolbox . - il est écrit pour Matlab et a un détecteur de début intégré - il fonctionne plutôt bien. Le code source est GPL, vous pouvez donc implémenter l'algorithme dans la langue qui vous convient. Quelle langue votre code de production va-t-il utiliser?

cette bibliothèque est centrée sur l'étiquetage audio:

aubio

  

aubio est une bibliothèque d’étiquetage audio. Ses fonctions incluent la segmentation d'un fichier son avant chacune de ses attaques, la détection de la hauteur, le rythme et la production de flux MIDI à partir de l'audio en direct. Le nom aubio vient de 'audio' avec une faute de frappe: plusieurs erreurs de transcription risquent également de se trouver dans les résultats.

et j’ai eu de la chance avec elle pour la détection des débuts et la détection de la hauteur. C'est en c, mais il y a des wrappers swig / python.

De plus, l'auteur de la bibliothèque a publié un pdf de sa thèse sur la page, qui contient d'excellentes informations et de bonnes connaissances en matière d'étiquetage.

Les détecteurs de surintensité sont facilement détectés dans le domaine temporel en utilisant une mesure d'énergie moyenne.

SUM de 0 à N (X ^ 2)

Faites ceci avec des morceaux du signal entier. Vous devriez voir des pointes lorsque des apparitions se produisent (la taille de la fenêtre dépend de vous, ma suggestion est de 50 ms ou plus).

Documents détaillés sur la détection de départ:

Pour les ingénieurs hardcore:

http://www.nyu.edu/classes/bello/MIR_files /2005_BelloEtAl_IEEE_TSALP.pdf

Plus facile à comprendre pour une personne moyenne:

http://bingweb.binghamton.edu/~ahess2/Onset_Detection_Nov302011.pdf

Vous pouvez essayer de transformer le signal wav en un graphique de l’amplitude en fonction du temps. Ensuite, un moyen de déterminer un début cohérent consiste à calculer l'intersection d'une tangente au point d'inflexion du flanc montant d'un signal avec l'axe des x.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top