Akkorderkennung mit Chromagramm der Python Library Librosa

Dies ist @namaozi. Dieser Artikel ist eeic Adventskalender 2016 Tag 9 Artikel ** Teil 2 **.

Wenn Sie plötzlich ab ** Teil 2 ** schauen möchten, lesen Sie bitte zuerst ** Teil 1 **.

Letztes Mal habe ich ein Spektrogramm erstellt, um das Musiksignal zu visualisieren.

Diesmal mit einem Chromagramm

Diese Beispiel-Tonquelle

Fordern wir die Akkorderkennung von heraus.

Was Sie in diesem Artikel tun möchten

Beachten

Ich werde die Bibliothek benutzen.

[Teil 1] In () habe ich das Spektrogramm nur mit Numpy implementiert. Wenn ich jedoch die Akkorderkennung des Chromagramms implementiert habe, war die Genauigkeit von zu viel Müll, daher verlasse ich mich auf die Bibliothek. Ich werde entscheiden, </ font>, es ist eine erbärmliche Geschichte ... (´ ・ _ ・ `)

In diesem Artikel werde ich daher die erweiterte Python-Bibliothek zur Analyse von Sprachsignalen ** librosa ** verwenden, um das Chromagramm abzurufen und die Akkorde zu erkennen. Machen wir das. Wenn Sie es versuchen möchten, installieren Sie bitte zuerst librosa über den Link.

Ich benutze Python2.7

Es tut mir sehr leid, aber ich verwende python2.7 in diesem Beispiel ... Ich möchte 3.0 bald unterstützen.

Sprachproblem

Es gibt verschiedene musikalische Begriffe, aber ich denke, es ist in Ordnung, die Grundlagen durchzugehen, wenn Sie nicht verstehen. Wenn Sie interessiert sind, beziehen Sie sich bitte auf den Link. Im Moment ist es in Ordnung, wenn Sie wissen, dass der ** Akkord ein Akkord und der benannte Akkord ein Akkord ** ist.

Was ist Akkorderkennung?

** Eine Aufgabe, mit der der Computer den Codefortschritt kopieren kann **.

Tatsächlich ist die Aufgabe, Akkorde zu schätzen, ein sehr schwieriges Problem, und die Forschung ist noch nicht abgeschlossen. Obwohl sich die Genauigkeit von Jahr zu Jahr verbessert hat, ist sie noch nicht so flexibel wie ein ausgebildeter Mensch.

Wenn Sie mehr wissen möchten, lesen Sie bitte Artikel hier. Das Chromagramm, das zu dieser Zeit behandelt werden soll, ist ebenfalls geschrieben. Die neueste Methode finden Sie in diesem Blog.

Eigentlich ist die Implementierung mit ** Hidden Markov Model (HMM) der Mainstream, aber da es schwierig zu implementieren ist, möchte ich diesmal die Codeerkennung nur mit Chromagramm als vereinfachte Version herausfordern.

Was ist ein Chromagramm?

Chromagramm liefert Strom für alle Frequenzbänder [C, Db, D, Eb, E, F, Gb, G, Ab, A, Bb, B. ], Es ist eine Visualisierung der Klangkomponenten in einem bestimmten Zeitraum. Ich werde mit einem Bild des englischen Wikis erklären.

chromagram

(a) ist eine Partitur, in der die Klänge der weißen Tasten der C-Dur-Tonleiter, des sogenannten Klaviers, aufgereiht sind. (b) wird der theoretische Chroma-Vektor entsprechend (a), aber wenn Sie aus (c) ein Chromagramm erstellen, das die Wellenform des tatsächlich auf der C-Dur-Tonleiter (C-Dur) gespielten Klangs ist, (d) Es sieht aus wie. Ist es als Bild das Gefühl, dass alle Musiksignale in eine Oktave der Pianorolle gedrückt werden?

Da das Signal zu jedem Zeitpunkt durch die Stärke der 12 Klangkomponenten ausgedrückt werden kann, wird es auch als ** Chroma-Vektor ** bezeichnet.

Wie machst du das denn?

Woran erkennt man den Code?

** "Wie viel Musiksignal-Chromagramm ähnelt dem gewünschten Akkord-Chroma-Vektor" **

Der Code für jedes Mal wird entsprechend festgelegt. Insbesondere ist das Verfahren wie folgt.

** 1. ** Erstellen Sie einen Chroma-Vektor (Vorlagenvektor) für den Code, den Sie erkennen möchten

** 2. ** Erstelle ein Liedchromagramm

** 3. ** Berechnen Sie jeweils die Ähnlichkeit zwischen Chromagramm und Vorlagenvektor und schätzen Sie den Code mit der höchsten Ähnlichkeit wie den Code zu diesem Zeitpunkt.

1. Erstellen Sie einen Vorlagenvektor

Erstellen Sie zunächst einen idealen Chroma-Vektor für den Akkord, den Sie erkennen möchten. Im Folgenden werden wir diese idealen Chroma-Vektoren als ** Template-Vektoren ** bezeichnen.

Beispielsweise ist Diatonic Code ein Vorlagenvektor, der wie in der folgenden Abbildung aussieht. Übrigens ist ein diatonischer Akkord ein Akkord, bei dem die konstituierenden Klänge eines bestimmten Tons dreimal akkumuliert werden, dh einer überspringt einen (es gibt diatonische Akkorde in jedem Dur und Moll, aber das Bild unten ist in Dur).

diatonic_chroma2.png

Übrigens ist die Farbe des Chroma-Vektors im obigen Bild unterschiedlich, obwohl er früher schwarz war, da die Summe der Potenzen jeder Tonhöhenklasse zu einem bestimmten Zeitpunkt auf 1 ausgerichtet ist.

Die Formel am unteren Rand des obigen Bildes ist die Formel, die den Vorlagenvektor des C-Dur-Codes darstellt. 12 Arten von [Tonhöhenklasse] für jede Dimension (https://ja.wikipedia.org/wiki/%E3%83%94%E3%83%83%E3%83%81%E3%82%AF%E3% Es entspricht 83% A9% E3% 82% B9) und steigt gegenüber C um einen halben Ton.

2. Erstellen Sie ein Chromagramm

Machen Sie das zuvor eingeführte Chromagramm. Verlassen Sie sich auf Librosa aus der God Library. Als Randnotiz analysiere ich die getrennten perkussiven Komponenten. Wenn Sie neugierig sind, was Sie im Inneren tun, gehen Sie zu God Document. Siehe.

Der Code ist auf GitHub, also probieren Sie es bitte aus. https://github.com/namaozi/ChromagramSample

functions.py



def librosa_chroma(file_path="audios/harmony1.wav", sr=44100):
    #importieren(Kann nicht ohne Installation verwendet werden)
    import librosa

    #Lesen(sr:Abtastrate)
    y, sr = librosa.load(file_path, sr=sr)

    #Teilen Sie in Musikkomponente und Schlagkomponente
    y_harmonic, y_percussive = librosa.effects.hpss(y)

    #Berechnen Sie das Chromagramm
    C = librosa.feature.chroma_cens(y=y_harmonic, sr=sr)

    #Handlung
    plt.figure(figsize=(12,4))
    librosa.display.specshow(C, sr=sr, x_axis='time', y_axis='chroma', vmin=0, vmax=1)
    plt.title('Chromagram')
    plt.colorbar()
    plt.tight_layout()
    plt.show()

    return C
###

Sie können das Chromagramm in nur wenigen Zeilen berechnen. Ha Bibliotheksgott ... Das Folgende ist das erhaltene Chromagramm. harmony1_chroma.png

Diese Beispiel-Klangquelle ist BPM120

chord_types.png

Der Akkord wird um 4 Schläge verlängert, dh um 2 Sekunden. Wenn Sie sich das erhaltene Chromagramm ansehen, können Sie sehen, dass sich der Farbton zum Zeitpunkt des Akkords alle 2 Sekunden ändert und sich die Klangkomponente des Signals ändert. [^ 1]

Darüber hinaus hat zum Beispiel das dritte, das Chromagramm des G-Dur-Akkords zwischen 4 Sekunden und 6 Sekunden, eine dunklere Farbe im ** D-, G-, B ** -Part, was der konstituierende Klang des ** G-Dur-Akkords ist. Spiel **. Es scheint, dass Sie den Code nur durch Betrachten des Chromagramms verstehen können![^ 2]

[^ 1]: Eigentlich muss bestimmt werden, von wo zu welchem Abschnitt sich der Code befindet. In dieser Beispiel-Soundquelle ändert sich der Code jedoch alle 2 Sekunden. Geben Sie diese Informationen also an das Programm weiter. Ich werde am Ende.

[^ 2]: Wenn Sie interessiert sind, werden einige Beispieltonquellen in den Audios-Ordner gestellt, daher kann es interessant sein, sie anzuhören und ein Chromagramm zu erstellen. Während harmony1.wav nur Orgelakkorde und Schlagzeug war, fügte harmony2.wav Bass hinzu und harmony3.wav war eine Klangquelle mit zusätzlicher Melodie. Wenn Sie sich das Chromagramm ansehen, sollte der Teil, der der Melodie oder dem Bass entspricht, dunkler erscheinen.

3. Code-Schätzung

Sie müssen lediglich den Code entlang der Zeitachse schätzen.

chordestimation.py


#coding:utf-8
from collections import OrderedDict
import numpy as np
import matplotlib.pyplot as plt
import librosa #Bitte installiere!

import soundanalysis as sa

file_path = "audios/"
file_name = "harmony1.wav"

#
chroma = sa.librosa_chroma(file_path + file_name)

TONES = 12 #,
sampling_rate = 44100 #

# "",
# (Tonhöhenklasse Anzahl der Klangarten Abhängig von der Schallquelle Bei dieser Einstellung werden Sie aufgefordert, die Zeitachse wie folgt einzustellen. Weitere Informationen finden Sie im Dokument.)
time_unit = 512.0 / 44100 #1 Rahmen Chromagramm Länge
# stop = time_unit * (chroma.shape[1] - 1)
stop = time_unit * (chroma.shape[1])
time_ruler = np.arange(0, stop, time_unit)

###Code-Vorlagenvektor
#Betrachten Sie nur Majors und Minderjährige
#Gehirnmuskelcode,Ich hatte keine Zeit ...
#Ich benutze Ordered Dict, weil ich die Bestellung behalten möchte
one_third = 1.0/3
chord_dic = OrderedDict()
chord_dic["C"] = [one_third, 0,0,0, one_third, 0,0, one_third, 0,0,0,0]
chord_dic["Db"] = [0, one_third, 0,0,0, one_third, 0,0, one_third, 0,0,0]
chord_dic["D"] = [0,0, one_third, 0,0,0, one_third, 0,0, one_third, 0,0]
chord_dic["Eb"] = [0,0,0, one_third, 0,0,0, one_third, 0,0, one_third, 0]
chord_dic["E"] = [0,0,0,0, one_third, 0,0,0, one_third, 0,0, one_third]
chord_dic["F"] = [one_third, 0,0,0,0, one_third, 0,0,0, one_third, 0,0]
chord_dic["Gb"] = [0, one_third, 0,0,0,0, one_third, 0,0,0, one_third, 0]
chord_dic["G"] = [0,0, one_third, 0,0,0,0, one_third, 0,0,0, one_third]
chord_dic["Ab"] = [one_third, 0,0, one_third, 0,0,0,0, one_third, 0,0,0]
chord_dic["A"] = [0, one_third, 0,0, one_third, 0,0,0,0, one_third, 0,0]
chord_dic["Bb"] = [0,0, one_third, 0,0, one_third, 0,0,0,0, one_third, 0]
chord_dic["B"] = [0,0,0, one_third, 0,0, one_third, 0,0,0,0, one_third]
chord_dic["Cm"] = [one_third, 0,0, one_third, 0,0,0, one_third, 0,0,0,0]
chord_dic["Dbm"] = [0, one_third, 0,0, one_third, 0,0,0, one_third, 0,0,0]
chord_dic["Dm"] = [0,0, one_third, 0,0, one_third, 0,0,0, one_third, 0,0]
chord_dic["Ebm"] = [0,0,0, one_third, 0,0, one_third, 0,0,0, one_third, 0]
chord_dic["Em"] = [0,0,0,0, one_third, 0,0, one_third, 0,0,0, one_third]
chord_dic["Fm"] = [one_third, 0,0,0,0, one_third, 0,0, one_third, 0,0,0]
chord_dic["Gbm"] = [0, one_third, 0,0,0,0, one_third, 0,0, one_third, 0,0]
chord_dic["Gm"] = [0,0, one_third, 0,0,0,0, one_third, 0,0, one_third, 0]
chord_dic["Abm"] = [0,0,0, one_third, 0,0,0,0, one_third, 0,0, one_third]
chord_dic["Am"] = [one_third, 0,0,0, one_third, 0,0,0,0, one_third, 0,0]
chord_dic["Bbm"] = [0, one_third, 0,0,0, one_third, 0,0,0,0, one_third, 0]
chord_dic["Bm"] = [0,0, one_third, 0,0,0, one_third, 0,0,0,0, one_third]

prev_chord = 0
sum_chroma = np.zeros(TONES)
estimate_chords = []

result = np.zeros((TONES * 2, 8))

for time_index, time in enumerate(time_ruler):
    #Welche Anzahl von Code analysieren Sie gerade?
    #Es ändert sich alle 2 Sekunden, also dividieren Sie durch 2, um es zu finden.
    nth_chord = int(time) / 2

    #Beim Übergang zu den nächsten 2 Sekunden,Schätzen Sie den Code für die letzten 2 Sekunden
    if nth_chord != prev_chord:
        maximum = -100000
        this_chord = ""
        #Untersuchen Sie den Code, der die Kosinusähnlichkeit maximiert
        for chord_index, (name, vector) in enumerate(chord_dic.iteritems()):
            similarity = sa.cos_sim(sum_chroma, vector)
            result[chord_index][nth_chord - 1] = similarity
            if similarity > maximum:
                maximum = similarity
                this_chord = name
        #Speichert initialisierten und geschätzten Code
        sum_chroma = np.zeros(TONES)
        estimate_chords.append(this_chord)

    else:
        #Ich werde hinzufügen, während ich auf die Form der Chroma achte
        for i in range(TONES):
            sum_chroma[i] += chroma[i][time_index]

    #aktualisieren
    prev_chord = nth_chord
###

#Das Endergebnis
print estimate_chords


###Viel Glück Handlung
axis_x = np.arange(0, 16, 2)
bar_width = 0.07
colors = ["#ff9999", "#ffaf95","#fabb92","#ffd698","#fae991","#c1fc97","#97fac8","#96f9f5","#98e1fb","#9cb2ff","#b79bfe","#fa96f9", "#b36a6a", "#ab7361","#aa7d61","#ad9165","#b4a765","#8ab66b","#6ab48f","#68b0ad","#689fb3","#6979b0","#7462a3","#aa62a9"]
for i, (name, vector) in enumerate(chord_dic.iteritems()):
    plt.bar(axis_x - ((axis_x[1] - axis_x[0]) * 0.45) + bar_width * i, result[i], color=colors[i], width = bar_width, label = name, align = "center")

plt.legend()
plt.xticks(axis_x + bar_width / 24)
plt.show()

Das Ergebnis der Ausführung des obigen Codes! !! !! chord_result.png

Ich habe die Code-Zeichenfolge! !! Der Code für Eingegebenes Lied lautet chord_types.png

Diesmal können jedoch nur Haupt- und Nebencodes erkannt werden, sodass der zweite ** Dm7 ** (d-Moll-Siebener) überhaupt nicht die richtige Antwort ausgeben kann. Wenn man bedenkt, dass die Grundtöne von Dm7 [D, F, A, C] sind, kann es als d-Moll oder F-Dur erkannt werden, wie es ist. In der Ausgabe wird ** F-Dur ** erhalten, so dass es fast korrekt ist. Der 7. Akkord ** Am / E ** hat ebenfalls den gleichen Klang wie Am, daher ist der Ausgang Am die richtige Antwort.

Auf diese Weise konnte die Sample-Soundquelle "harmony1.wav" mit Hilfe des Chromagramms und des Vorlagenvektors fast die richtige Antwort für alle Codes ausgeben! </ font> Herzlichen Glückwunsch. [^ 3]

[^ 3]: Leider ist es unwahrscheinlich, dass ein Lied in der realen Welt so gut von einem einfachen Chromagramm kopiert werden kann. harmony1.wav hatte nur eine sehr einfache Komposition aus Akkorden + Schlagzeug, aber viele reale Songs sind komplizierte Songs mit einer unendlichen Anzahl von Tracks. Wenn die Melodie der Singstimme darin enthalten ist, wird sie stark beeinflusst, so dass es noch schwieriger ist, die Akkorde zu schätzen. Wie in Fußnote 1 erwähnt, ist es auch schwierig zu schätzen, "welches Intervall der Akkord ist", was die Akkordanalyse noch schwieriger macht.

Die folgende Abbildung zeigt die Ähnlichkeit mit allen Codes in jedem Abschnitt (Sie können sie erhalten, indem Sie das obige Programm ausführen). Dies ist keine sehr saubere Visualisierung, aber ... similarity_distribution.png

Wenn Sie sich diese Zahl ansehen (geben Sie Ihr Bestes), ist beispielsweise im ersten Abschnitt von 0 bis 2 Sekunden die Ähnlichkeit von ** C ** am höchsten, aber zusätzlich ** Cm ** desselben Hauptakkords. Sie können sehen, dass die Ähnlichkeit auch in den parallelen Hauptakkorden ** Am ** und den Hauptakkorden der Gattung (IIIm) ** Em ** hoch ist.

Sie können sehen, dass die Ähnlichkeiten der Hauptakkorde des relationalen Tons auf diese Weise ähnlich sind </ font>. Es kann interessant sein, die Musiktheorie anhand einer solchen mathematischen Interpretation zu überdenken.

Zusammenfassung

  • Python ist gut --librosa am stärksten
  • Lassen Sie uns herausfinden, ob die Bibliothek dies kann, bevor Sie es selbst implementieren
  • Die Codeerkennung ist selbst mit der stärksten Bibliothek ziemlich schwierig

Recommended Posts