Skip to content

Commit 7450c7c

Browse files
committed
Added Technische Umsetzung.
Implemented FeatureExtraction from Studienarbeit.
1 parent b519307 commit 7450c7c

File tree

12 files changed

+122
-52
lines changed

12 files changed

+122
-52
lines changed

chapter/TechnischeUmsetzung.tex

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ \section{Technische Umsetzung}\label{sec:TechnischeUmsetzung}
55
Folglich findet auch die Implementierung der Signalvorverarbeitung, sowie der \ac{LPC} Berechnung mit Hilfe der Sprache Python statt.
66

77
Um Programmierfehler zu vermeiden, sowie die Effizienz des Codes zu erhöhen, werden Funktionen aus verschiedenen Bibliotheken verwendet.
8-
Als Basis wird die Bibliothek \textKlasse{numpy} verwendet, welche Funktionen für die Bearbeitung von Arrays und Matrizen bereitstellt.
8+
Als Basis wird die Bibliothek \textKlasse{numpy} verwendet, welche Funktionen für die Bearbeitung von Arrays und Matrizen bereitstellt, sowie die Bibliothek \textKlasse{librosa} für Audio spezifische Funktionen wie das Laden von WAV Dateien.
99

1010
\subsection{Klasse AudioPreprocessor}
1111
Die Klasse \textKlasse{AudioPreprocessor} (vgl. Quellcode~\ref{code:AudioPreprocessor}) beinhaltet die Funktionen für die Schritte der Signalvorverarbeitung (vgl. Kapitel~\ref{sec:Signalvorverarbeitung}).
@@ -15,3 +15,11 @@ \subsection{Klasse AudioPreprocessor}
1515
Die passende Fensterfunktion wird dabei ebenfalls durch die \textKlasse{numpy} Bibliothek bereitgestellt (vgl. Zeile~\ref{line:windowFunction}).
1616

1717
\subsection{Klasse FeatureExtractor}
18+
Mit Blick auf die an diese Arbeit folgende Studienarbeit wird für die Implementierung der Koeffizientenberechnung ein Ansatz gewählt, der eine einfache Erweiterung des Programms um verschiedene andere Verfahren wie etwa \ac{MFCC} ermöglicht.
19+
Dazu wird das Design Pattern Strategie in abgewandelter Form verwendet, wobei zunächst ein Interface für die Berechnungsverfahren erstellt werden muss (vgl. Quellcode~\ref{code:ExtractorInterface}).
20+
Dieses definiert die Funktion \textFunktion{calculateFeatures}, welche in den abgeleiteten Klassen implementiert wird.
21+
Die Klasse \textKlasse{LPCExtractor} (vgl. Quellcode~\ref{code:LPCExtractor}) nutzt hierfür die von der Bibliothek \textKlasse{librosa} bereitgestellt Funktion \textFunktion{lpc} um für die übergebenen Frames die zugehörigen \ac{LPC} Koeffizienten zu berechnen und anschließend zurückzugeben.
22+
Der \ac{LPC} Koeffizienten nullter Ordnung wird dabei von der Funktion standardmäßig mit der Zahl eins befüllt und ist kein Teil der berechneten \ac{LPC}-Ordnung, weshalb dieser manuell entfernt werden muss (vgl. Z.~\ref{line:removeLPC0}).
23+
24+
Die Klasse \textKlasse{FeatureExtractor} (vgl. Quellcode~\ref{code:FeatureExtractor}) implementiert die Funktion \textFunktion{ex\-tract\-\_features}, welcher über den Parameter \textVariable{feature\_list} eine genaue Anweisung über die zu berechnenden Koeffizienten übergeben werden kann (vgl. Z.~\ref{line:extract_features}).
25+
Dabei kann im Speziellen eine Angabe zu der Art der Koeffizienten, der Anzahl an zu berechnenden Koeffizienten, sowie der zusätzlich zu berechnenden Ableitungs-Ordnungen übergeben werden (vgl. Z.~\ref{line:feature_list_info}).

chapter/Validierung.tex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
\section{Validierung}\label{sec:Validierung}
1+
\section{Validierung}\label{sec:Validierung}

code/preprocessing/AudioPreprocessor.py renamed to code/AudioPreprocessor/AudioPreprocessor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from utils.utils import Utils
1+
import librosa
22
import numpy as np
33
import noisereduce as nr
44

@@ -118,7 +118,7 @@ def load_preprocessed_frames(filepath=None, y=None, sr=None):
118118
raise ValueError("Either filepath or y and sr must be given.")
119119

120120
if y is None or sr is None:
121-
y, sr = Utils.load_file(filepath)
121+
y, sr = librosa.load(filepath)
122122

123123
y = AudioPreprocessor.remove_noise(y=y, sr=sr)
124124
y = AudioPreprocessor.remove_silence(y=y)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class ExtractorInterface:
2+
def calculateFeatures(self, frames, sr, order):
3+
pass
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from FeatureExtractor.LPCExtractor import LPCExtractor
2+
3+
import librosa
4+
import numpy as np
5+
from enum import Enum
6+
7+
class Feature(Enum):
8+
LPC = 0
9+
10+
class FeatureExtractor:
11+
def __init__(self, frames, sr):
12+
self.frames = frames
13+
self.sr = sr
14+
self.extractors = [
15+
LPCExtractor()
16+
]
17+
self.last_feature_count = 0
18+
19+
def extract_features(self, feature_list): #(*@\label{line:extract_features}@*)
20+
"""_summary_
21+
22+
Args:
23+
feature_list ((Feature, int, int[])[]): 2D List of Features (enum) + order (int) + deltas (int[]) lists to extract #(*@\label{line:feature_list_info}@*)
24+
25+
Returns:
26+
NDArray[]: Array of requested features for each frame
27+
"""
28+
feature_set = None
29+
30+
for feature_info in feature_list:
31+
features = self.extractors[feature_info[0].value].calculateFeatures(self.frames, self.sr, feature_info[1])
32+
if feature_set is None:
33+
feature_set = np.array(features)
34+
else:
35+
np.concatenate((feature_set, np.array(features)), axis=1)
36+
37+
for delta in feature_info[2]:
38+
delta_features = librosa.feature.delta(np.array(features), order=delta, mode='nearest')
39+
np.concatenate((feature_set, delta_features), axis=1)
40+
41+
feature_set = feature_set.tolist()
42+
self.last_feature_count = len(feature_set[0])
43+
44+
return feature_set
45+
46+
def get_last_feature_count(self):
47+
return self.last_feature_count

code/FeatureExtractor/LPCExtractor.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from FeatureExtractor.ExtractorInterface import ExtractorInterface
2+
3+
import librosa
4+
5+
class LPCExtractor(ExtractorInterface):
6+
def calculateFeatures(self, frames, sr, order):
7+
lpc_coefficients = []
8+
9+
for frame in frames:
10+
lpc_coefficients.append(librosa.lpc(y=frame, order=order)[1:]) #(*@\label{line:removeLPC0}@*)
11+
12+
return lpc_coefficients

code/feature_extraction/LPCExtractor.py

Lines changed: 0 additions & 36 deletions
This file was deleted.
Binary file not shown.

code/main.py

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,34 @@
1-
from preprocessing.AudioPreprocessor import AudioPreprocessor
2-
from feature_extraction.LPCExtractor import LPCExtractor
1+
from AudioPreprocessor.AudioPreprocessor import AudioPreprocessor
2+
from FeatureExtractor.FeatureExtractor import FeatureExtractor, Feature
3+
4+
import librosa
5+
import numpy as np
6+
7+
def unison_shuffled_copies(a, b):
8+
assert len(a) == len(b)
9+
p = np.random.permutation(len(a))
10+
return a[p], b[p]
311

412
def main():
5-
frames = AudioPreprocessor.load_preprocessed_frames("C:\\Users\\SCU8BH\\Documents\\T3000\\Studienarbeit\\Data\\50_speakers_audio_data\\Speaker_0003\\Speaker_0003_00000.wav")
6-
lpccs = LPCExtractor.get_lpcc_from_frames(frames=frames, order=12)
7-
print(len(lpccs))
13+
filePath = "C:\\Users\\SCU8BH\\Documents\\T3000\\Studienarbeit\\Data\\50_speakers_audio_data\\Speaker_0003\\Speaker_0003_00000.wav"
14+
15+
# Load audio file
16+
y, sr = librosa.load(filePath)
17+
18+
# Preprocess audio file
19+
y = AudioPreprocessor.remove_noise(y=y, sr=sr)
20+
y = AudioPreprocessor.remove_silence(y=y)
21+
# frame-duration: 0.2 s, overlap: 0.1 s
22+
frames = AudioPreprocessor.create_frames(y=y, frame_size=int(sr / 5), overlap=int(sr / 10))
23+
windowed_frames = AudioPreprocessor.window_frames(frames=frames)
24+
25+
# Extract features
26+
feature_extractor = FeatureExtractor(windowed_frames, sr)
27+
# Create LPC features with 13 coefficients per frame and no derivatives
28+
extraction_pattern = [
29+
[Feature.LPC, 13, []]
30+
]
31+
features = feature_extractor.extract_features(extraction_pattern)
832

933
if __name__ == "__main__":
1034
main()

0 commit comments

Comments
 (0)