Skip to content

Commit 3a6fb19

Browse files
Merge pull request #13 from schuler-henry/7-lpc-and-lpcc-feature-extraction
7 lpc and lpcc feature extraction
2 parents 8915ab4 + 7450c7c commit 3a6fb19

File tree

14 files changed

+513
-24
lines changed

14 files changed

+513
-24
lines changed

chapter/Grundlagen.tex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ \section{Grundlagen}\label{sec:Grundlagen}
22
Der Schwerpunkt dieser Arbeit unterteilt sich in zwei Teile, die Signalvorverarbeitung und das \ac{LPC} Verfahren.
33
Im Folgenden werden die theoretischen Grundlagen für beide Prozesse beschrieben.
44

5-
\subsection{Signalvorverarbeitung}
5+
\subsection{Signalvorverarbeitung}\label{sec:Signalvorverarbeitung}
66
Um ein gegebenes Audiosignal einheitlich verarbeiten zu können, muss dieses zunächst mittels verschiedener Verfahren vorbereitet werden.
77
Ziel dieser Vorverarbeitung ist es, die Effizienz und Effektivität des anschließenden Verarbeitungsprozesses zu erhöhen und somit ein verbessertes Ergebnis zu erzielen \autocite[vgl.][S. 11672]{lokesh_speech_2019}.
88
Die Vorverarbeitung im Rahmen dieser Arbeit beinhaltet die vier Schritte Rauschreduzierung, Pausen entfernen, Framing und Windowing, welche in den folgenden Unterkapiteln genauer erläutert werden.
99

10-
\subsubsection{Rauschreduzierung}
10+
\subsubsection{Rauschreduzierung}\label{sec:Rauschreduzierung}
1111
Um störende Frequenzen aus dem Audiosignal zu entfernen wird eine Rauschreduzierungsfunktion verwendet.
1212
Die in dieser Arbeit verwendete Funktion nutzt den sogenannten Spectral Noise Gate Algorithmus.
1313
Dabei wird zunächst die Signatur des Rauschens ermittelt.

chapter/TechnischeUmsetzung.tex

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,25 @@
1-
\section{Technische Umsetzung}\label{sec:TechnischeUmsetzung}
1+
\section{Technische Umsetzung}\label{sec:TechnischeUmsetzung}
2+
% TODO: Optional: Quellen hinzufügen wenn Platz vorhanden ist.
3+
Da die Zuordnung der erzeugten \ac{LPC} Koeffizienten zu einem spezifischen Sprecher mittels eines \acp{NN} umgesetzt wird, wird auf die Programmiersprache Python zurückgegriffen.
4+
Diese ermöglicht die Verwendung des von Google entwickelten Machine Learning Frameworks TensorFlow.
5+
Folglich findet auch die Implementierung der Signalvorverarbeitung, sowie der \ac{LPC} Berechnung mit Hilfe der Sprache Python statt.
6+
7+
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, sowie die Bibliothek \textKlasse{librosa} für Audio spezifische Funktionen wie das Laden von WAV Dateien.
9+
10+
\subsection{Klasse AudioPreprocessor}
11+
Die Klasse \textKlasse{AudioPreprocessor} (vgl. Quellcode~\ref{code:AudioPreprocessor}) beinhaltet die Funktionen für die Schritte der Signalvorverarbeitung (vgl. Kapitel~\ref{sec:Signalvorverarbeitung}).
12+
Die Funktion \textFunktion{remove\_noise} implementiert die Rauschreduzierung unter Verwendung der Bibliothek \textKlasse{noisereduce}.
13+
Für die Funktion \textFunktion{remove\_silence} wurde wie bereits erwähnt ein eigener Algorithmus entwickelt (vgl. Zeile~\ref{line:removeSilenceStart}-\ref{line:removeSilenceEnd}), der in Kapitel~\ref{sec:Rauschreduzierung} genauer erläutert ist.
14+
Die Abschließende Unterteilung des Audiosignals in Frames, sowie das Windowing der Frames findet mit Hilfe von \textKlasse{numpy} Operationen in den Funktionen \textFunktion{create\_frames} und \textFunktion{window\_frames} statt.
15+
Die passende Fensterfunktion wird dabei ebenfalls durch die \textKlasse{numpy} Bibliothek bereitgestellt (vgl. Zeile~\ref{line:windowFunction}).
16+
17+
\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: 12 additions & 12 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

@@ -57,7 +57,14 @@ def float_to_int(array, type=np.int16, divide_max_abs=True):
5757
return array
5858

5959
@staticmethod
60-
def remove_silence(y):
60+
def remove_noise(y, sr):
61+
# prop_decrease 0.8 only reduces noise by 0.8 -> sound quality is better than at 1.0
62+
y_ = nr.reduce_noise(y=y, sr=sr, prop_decrease=0.8)
63+
64+
return y_
65+
66+
@staticmethod
67+
def remove_silence(y): #(*@\label{line:removeSilenceStart}@*)
6168
threshold = 0.005
6269
pause_length_in_ms = 200
6370
keep_at_start_and_end = 50
@@ -79,14 +86,7 @@ def remove_silence(y):
7986

8087
y_ = np.delete(y, indices_to_remove)
8188

82-
return y_
83-
84-
@staticmethod
85-
def remove_noise(y, sr):
86-
# prop_decrease 0.8 only reduces noise by 0.8 -> sound quality is better than at 1.0
87-
y_ = nr.reduce_noise(y=y, sr=sr, prop_decrease=0.8)
88-
89-
return y_
89+
return y_ #(*@\label{line:removeSilenceEnd}@*)
9090

9191
@staticmethod
9292
def create_frames(y, frame_size, overlap):
@@ -104,7 +104,7 @@ def create_frames(y, frame_size, overlap):
104104
return frames
105105

106106
@staticmethod
107-
def window_frames(frames, window_function=np.hanning):
107+
def window_frames(frames, window_function=np.hanning): #(*@\label{line:windowFunction}@*)
108108
windowed_frames = []
109109

110110
for frame in frames:
@@ -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/main.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,34 @@
1-
from preprocessing.AudioPreprocessor import AudioPreprocessor
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]
211

312
def main():
4-
frames = AudioPreprocessor.load_preprocessed_frames("./audio.wav")
5-
print(frames)
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)
632

733
if __name__ == "__main__":
834
main()

0 commit comments

Comments
 (0)