Meyda mit
Plotly zu verbinden ist ein wenig komplizierter, da man die erhobenen
Werte erst in einem Text zwischenspeichern muss, aber es funktioniert
auch in 7 Schritten:
1.
Einbettung der Meyda- und der Plotly-Library
Zunächst
werden im <head>
der Seite die Meyda- und Plotly-Javascript-Bibliotheken eingebettet:
Dann wird
im <head> der Seite
ein Script zur Steuerung des Audioplayers angelegt:
<script>
function spielAudio()
{ // Funktion zum Abspielen des Audioplayers
var meinplayer = document.getElementById('audio'); //
finde über
// getElementById() den Audioplayer mit der id "audio" und übergebe
ihn an die Variable meinPlayer.
meinplayer.play(); // starte den so gefundenen
Audioplayer
document.getElementById("levelNumber").innerHTML=
""; // Suche das Element
// "levelNumber" via getElementById() und lösche den Text
darin via innerHTML.
document.getElementById("centroidNumber").innerHTML= "";
// Suche das Element
// "centroidNumber"
via getElementById() und
lösche den Text darin via innerHTML.
document.getElementById("zcrNumber").innerHTML= "";
// Suche das Element
// "zcrNumber"
via getElementById() und
lösche den Text darin via innerHTML.
document.getElementById("spectralFlatnessNumber").innerHTML=
""; // Suche // das Element "spectralFlatnessNumber"
via getElementById() und
lösche den Text darin via
// innerHTML.
document.getElementById("energyNumber").innerHTML= "";
// Suche das Element
// "energyNumber"
via getElementById() und
lösche den Text darin via innerHTML.
document.getElementById("spectralSlopeNumber").innerHTML= "";
// Suche das // Element "spectralSlopeNumber"
via getElementById() und
lösche den Text darin via innerHTML.
document.getElementById("spectralRolloffNumber").innerHTML=
"";// Suche das // Element "spectralRolloffNumber"
via getElementById() und
lösche den Text darin via innerHTML.
document.getElementById("spectralSpreadNumber").innerHTML= "";//
Suche das // Element "spectralSpreadNumber"
via getElementById() und
lösche den Text darin via innerHTML.
document.getElementById("spectralSkewnessNumber").innerHTML=
""; // Suche
// das Element "spectralSkewnessNumber"
via getElementById() und
lösche den Text darin via
// innerHTML.
document.getElementById("spectralKurtosisNumber").innerHTML=
""; // Suche
// das Element "spectralKurtosisNumber"
via getElementById() und
lösche den Text darin via
// innerHTML.
document.getElementById("perceptualSpreadNumber").innerHTML=
""; // Suche
// das Element "perceptualSpreadNumber"
via getElementById() und
lösche den Text darin via
// innerHTML.
document.getElementById("perceptualSharpnessNumber").innerHTML=
"";
// Suche das Element "perceptualSharpnessNumber"
via getElementById() und
lösche den Text darin via
// innerHTML.
}
function stopAudio()
{ // Funktion zum Stoppen des Audioplayers
var meinplayer = document.getElementById('audio'); //
finde über
// getElementById() den Audioplayer mit der id "audio" und übergebe
ihn an die Variable meinPlayer.
meinplayer.pause(); // pausiere den Player
meinplayer.currentTime = 0; // setze ihn
auf den Anfang des Stücks
}
</script>
3.
Einbettung eines Audioplayers mit id und Steuerungsmöglichkeit
Im <body>
der Seite wird der Player angelegt sowie die Auslöser zum Starten
und Stoppen des Players:
4.
Einbettung eines Bereichs, in dem die Daten visualisiert werden sollen
Unter dem
Audioplayer wird innerhalb eines <DIV>-Tag
ein Bereich (hier mit der id "AnzeigeDiv") festgelegt, in dem
die Audiodaten visualisiert werden sollen:
5.
Starten des WebAudioApi und Audio-Analyse mit Meyda
Darunter
wird das Script für die Analyse eingebaut.
<script defer> bedeutet, dass das Script nicht seriell im
Seitenaufbau eingebaut ist, sondern parallel zu den anderen Scripten und
Funktionen auf der Seite passiert:
<script defer>
const audioContext = new AudioContext(); //
erzeuge einen Audiokontext (ähnlich wie
// einen Canvas) für das WebAudioApi
const htmlAudioElement = document.getElementById("audio"); //
suche den
// Audioplayer via getElementById() und weise ihn der Variablen htmlAudioElement
zu.
const source = audioContext.createMediaElementSource(htmlAudioElement);
// füge den Audioplayer über
die Variable htmlAudioElement als Mediaquelle dem audioContext hinzu.
source.connect(audioContext.destination); //
verbinde den audioContext mit der
// Soundausgabe des Browsers/Computers.
csfaktor = audioContext.sampleRate/512; //
errechne über die Samplerate (geteilt
// durch 2 wegen Nyquist-Theorem) und den Audiobuffer (defaultmäßig
bei 512) einen Faktor
// (csfaktor), mit dem die Zahl für den SpectralCentroid multipliziert
werden muss, damit sie passt.
if (typeof Meyda ===
"undefined") { // falls die Meyda-Library
nicht erkannt wird:
alert("Meyda konnte nicht gefunden werden, wurde die Library nicht
eingebunden?"); // gebe eine Fehlermeldung
aus
} else { // in allen anderen Fällen:
const analyzer = Meyda.createMeydaAnalyzer({ //
erstelle einen Analyzer mit
// folgenden Eigenschaften:
"audioContext": audioContext, // audioContext,
auf den sich der Analyzer bezieht
"source": source, // Quelle auf
die sich der Analyzer bezieht (= der Audioplayer)
"bufferSize": 512, // Buffergröße
"featureExtractors": ["rms", "spectralCentroid",
"zcr", "spectralFlatness", "energy", "spectralSlope",
"spectralRolloff", "spectralSpread", "spectralSkewness",
"spectralKurtosis", "perceptualSpread", "perceptualSharpness"],
// Array (Liste) von zu analysierenden
// Eigenschaften
"callback": features => { //
Ausgabe der ermittelten Features
if (features.rms!=0){ // sobald die gemessene
Energie ungleich 0 ist = das Audio spielt
document.getElementById("levelNumber").innerHTML = document.getElementById("levelNumber").innerHTML
+ " " + Math.round(features.rms * 1000)/1000; //
Füge zur Ausgabe der RMS-Amplitude den
// nächsten Wert hinzu und runde ihn auf 3 Stellen
document.getElementById("centroidNumber").innerHTML = document.getElementById("centroidNumber").innerHTML
+ " " + Math.round(features.spectralCentroid*csfaktor);
// Füge zur Ausgabe des Spectral
// Centroids den
nächsten Wert hinzu
(multipliziert mit dem oben errechneten cf-Faktor und
// gerundet)
document.getElementById("zcrNumber").innerHTML = document.getElementById("zcrNumber").innerHTML
+ " " + Math.round(features.zcr * 1000)/1000; //
Füge zur Ausgabe der Zero
Crossing Rate
// den nächsten Wert hinzu und runde ihn auf 3 Stellen.
document.getElementById("spectralFlatnessNumber").innerHTML
= document.getElementById("spectralFlatnessNumber").innerHTML
+ " " + Math.round(features.spectralFlatness * 1000)/1000; //
Füge zur Ausgabe der
// Spectral Flatness den
nächsten Wert hinzu und runde ihn auf 3 Stellen.
document.getElementById("energyNumber").innerHTML = document.getElementById("energyNumber").innerHTML
+ " " + Math.round(features.energy * 1000)/1000; //
Füge zur Ausgabe der
Energy den
// nächsten Wert hinzu und runde ihn auf 3 Stellen.
document.getElementById("spectralSlopeNumber").innerHTML = document.getElementById("spectralSlopeNumber").innerHTML
+ " " + Math.round(features.spectralSlope * 1000000000)/1000000000;
//
Füge zur
// Ausgabe der
Spectral Slope
den
nächsten Wert hinzu und runde ihn auf 10 Stellen.
document.getElementById("spectralRolloffNumber").innerHTML =
document.getElementById("spectralRolloffNumber").innerHTML +
" " + Math.round(features.spectralRolloff * 1000)/1000; //
Füge zur
// Ausgabe des
Spectral Rolloffs den
nächsten Wert hinzu und runde ihn auf 3 Stellen.
document.getElementById("spectralSpreadNumber").innerHTML =
document.getElementById("spectralSpreadNumber").innerHTML +
" " + Math.round(features.spectralSpread * 1)/1;
//
Füge zur Ausgabe des
Spectral Spreads
// den nächsten Wert hinzu.
document.getElementById("spectralSkewnessNumber").innerHTML
= document.getElementById("spectralSkewnessNumber").innerHTML
+ " " + Math.round(features.spectralSkewness * 1000)/1000; //
Füge zur
// Ausgabe der
Spectral
Skewness
den
nächsten Wert hinzu und runde ihn auf 3 Stellen.
document.getElementById("spectralKurtosisNumber").innerHTML
= document.getElementById("spectralKurtosisNumber").innerHTML
+ " " + Math.round(features.spectralKurtosis * 1000)/1000;
//
Füge zur Ausgabe der
// Spectral Kurtosis
den nächsten Wert hinzu und runde ihn auf 3 Stellen.
document.getElementById("perceptualSpreadNumber").innerHTML
= document.getElementById("perceptualSpreadNumber").innerHTML
+ " " + Math.round(features.perceptualSpread * 1000)/1000; //
Füge zur Ausgabe des
// Perceptual Spreads den
nächsten Wert hinzu und runde ihn auf 3 Stellen.
document.getElementById("perceptualSharpnessNumber").innerHTML
= document.getElementById("perceptualSharpnessNumber").innerHTML
+ " " + Math.round(features.perceptualSharpness * 1000)/1000;
//
Füge zur Ausgabe der
Perceptual Sharpness den
nächsten Wert hinzu und runde ihn auf 3 Stellen.
}
}
});
analyzer.start(); // starte den Analyzer
}
</script>
6.
Trigger für den Start des Kurvenzeichnens
Wenn der
Player endet oder pausiert soll die Kurve gezeichnet werden. Dies geschieht
in der Funktion kurvezeichnen(),
die durch die Trigger .onended
und .onpause ausgelöst
wird:
var meinplayer = document.getElementById('audio');
// finde über
// getElementById() den Audioplayer mit der id "audio" und übergebe
ihn an die Variable meinplayer.
meinplayer.onended = function() { // wenn
der Audioplayer stoppt, dann
kurvezeichnen(); // rufe die Funktion kurvezeichnen()
auf
};
meinplayer.onpause = function() { // wenn
der Audioplayer pausiert, dann
kurvezeichnen(); // rufe die Funktion kurvezeichnen()
auf
};
function kurvezeichnen(){
zeit=[]; // erstelle ein leeres Array für
die Zeitachse (Anzahl der Elemente)
rms=document.getElementById("levelNumber").innerHTML; //
übergebe den Inhalt
// des Felds "levelNumber" in die Variable rms
rms_array=rms.split(" "); //
erzeuge ein Array daraus, indem der Text nach allen
// Leerzeichen in seine einzelen Elemente aufgeteilt wird.
sc=document.getElementById("centroidNumber").innerHTML; //
übergebe den Inhalt
// des Felds "centroidNumber" in die Variable sc
spectralcentroid_array=sc.split(" ");
// erzeuge ein Array daraus, indem der Text
// nach allen Leerzeichen in seine einzelen Elemente aufgeteilt wird.
zcr=document.getElementById("zcrNumber").innerHTML; //
übergebe den Inhalt
// des Felds "zcrNumber" in die Variable zcr
zeroCrossingRate_array=zcr.split(" "); //
erzeuge ein Array daraus, indem der Text
// nach allen Leerzeichen in seine einzelen Elemente aufgeteilt wird.
sf=document.getElementById("spectralFlatnessNumber").innerHTML;
// übergebe
// den Inhalt des Felds "spectralFlatnessNumber"
in die Variable sf
spectralFlatness_array=sf.split(" "); //
erzeuge ein Array daraus, indem der Text
// nach allen Leerzeichen in seine einzelen Elemente aufgeteilt wird.
en=document.getElementById("energyNumber").innerHTML; //
übergebe den Inhalt
// des Felds "energyNumber"
in die Variable en
energy_array=en.split(" "); //
erzeuge ein Array daraus, indem der Text nach allen
// Leerzeichen in seine einzelen Elemente aufgeteilt wird.
sl=document.getElementById("spectralSlopeNumber").innerHTML;
// übergebe
// den Inhalt des Felds "spectralSlopeNumber"
in die Variable sl
spectralSlope_array=sl.split(" "); //
erzeuge ein Array daraus, indem der Text nach
// allen Leerzeichen in seine einzelen Elemente aufgeteilt wird.
sr=document.getElementById("spectralRolloffNumber").innerHTML;
// übergebe
// den Inhalt des Felds "spectralRolloffNumber"
in die Variable sr
spectralRolloff_array=sr.split(" "); //
erzeuge ein Array daraus, indem der Text
// nach allen Leerzeichen in seine einzelen Elemente aufgeteilt wird.
ss=document.getElementById("spectralSpreadNumber").innerHTML;
// übergebe
// den Inhalt des Felds "spectralSpreadNumber"
in die Variable ss
spectralSpread_array=ss.split(" "); //
erzeuge ein Array daraus, indem der Text
// nach allen Leerzeichen in seine einzelen Elemente aufgeteilt wird.
ssk=document.getElementById("spectralSkewnessNumber").innerHTML;
// übergebe den Inhalt des Felds "spectralSkewnessNumber"
in die Variable ssk
spectralSkewness_array=ssk.split(" "); //
erzeuge ein Array daraus, indem der Text
// nach allen Leerzeichen in seine einzelen Elemente aufgeteilt wird.
sk=document.getElementById("spectralKurtosisNumber").innerHTML;
// übergebe
// den Inhalt des Felds "spectralFKurtosisNumber"
in die Variable sk
spectralKurtosis_array=sk.split(" "); //
erzeuge ein Array daraus, indem der Text
// nach allen Leerzeichen in seine einzelen Elemente aufgeteilt wird.
ps=document.getElementById("perceptualSpreadNumber").innerHTML;
// übergebe
// den Inhalt des Felds "perceptualSpreadNumber"
in die Variable ps
perceptualSpread_array=ps.split(" "); //
erzeuge ein Array daraus, indem der Text
// nach allen Leerzeichen in seine einzelen Elemente aufgeteilt wird.
psh=document.getElementById("perceptualSharpnessNumber").innerHTML;
// übergebe den Inhalt des Felds "perceptualSharpnessNumber"
in die Variable psh
perceptualSharpness_array=psh.split(" "); //
erzeuge ein Array daraus, indem der
// Text nach allen Leerzeichen in seine einzelen Elemente aufgeteilt wird.
for (var i = 0; i < rms_array.length; i++) { //
hole in einer Schleife in der
// Länge des Arrays rms_array jeden einzelnen Wert i aus dem Array
zeit.push(i); // und füge den jeweiligem
Wert i ins Array Zeit hinzu
}
7.
Mit Plotly die Daten aus den Arrays visualisieren
In diesem
Teil werden dann - wie auch sonst bei der Visualisierung mit Plotly -
aus den vorhadenen Arrays die traces
für die darzustellenden Kurven angelegt, diese dann in der Variable
data zusammengefasst und
nach der Festlegung des Layouts
mit Hilfe von Plotly.newPlot()
im vorher definierten Bereich "AnzeigeDiv"
ausgegeben:
var trace1 = { //
Variable für die erste Kurve
x: zeit, // auf der X-Achse sollen die
Werte aus dem Array Zeit erscheinen
y: rms_array, // auf der Y-Achse sollen
die Werte aus dem rms_array erscheinen
mode: 'lines', // die Werte sollen als
Linie visualsiert werden
type: 'scatter' , // sie sollen in einem
zweidimensionalen Graph visualisiert werden
name: 'Amplitude', // Name der Kurve
marker: { // Eigenschaften der Marker bzw.
der Linien
color: 'rgb(188, 48, 47)', // die Linie
soll dunkelrot sein
},
text: rms_array, // Beim MouseOver soll
Text aus dem rms_array angezeigt werden
};
var trace2 = { // Variable für die
zweite Kurve
x: zeit, // auf der X-Achse sollen die
Werte aus dem Array Zeit erscheinen
y: spectralcentroid_array, // auf der Y-Achse
sollen die Werte aus dem
// spectralcentroid_array erscheinen
mode: 'lines', // die Werte sollen als
Linie visualsiert werden
type: 'scatter' , // sie sollen in einem
zweidimensionalen Graph visualisiert werden
name: 'Spectral Centroid', // Name der
Kurve
marker: { // Eigenschaften der Marker bzw.
der Linien
color: 'rgb(48, 188, 48)', // die Linie
soll hellgrün sein
},
text: spectralcentroid_array, // Beim MouseOver
soll Text aus dem spectralcentroid_array
// angezeigt werden
};
var trace3 = { // Variable für die
dritte Kurve
x: zeit, // auf der X-Achse sollen die
Werte aus dem Array Zeit erscheinen
y: zeroCrossingRate_array, // auf der Y-Achse
sollen die Werte aus dem
// zrroCrossingRate_array erscheinen
mode: 'lines', // die Werte sollen als
Linie visualsiert werden
type: 'scatter' , // sie sollen in einem
zweidimensionalen Graph visualisiert werden
name: 'Zero Crossing Rate', // Name der
Kurve
marker: {
color: 'rgb(48, 48, 188)', // die Linie
soll dunkelblau sein
},
text: zeroCrossingRate_array, // Beim MouseOver
soll Text aus dem
// zeroCrossingRate_array
angezeigt werden
};
var trace4 = { // Variable für die
vierte Kurve
x: zeit, // auf der X-Achse sollen die
Werte aus dem Array Zeit erscheinen
y: spectralFlatness_array, // auf der Y-Achse
sollen die Werte aus dem
// spectralFlatness_array erscheinen
mode: 'lines', // die Werte sollen als
Linie visualsiert werden
type: 'scatter' , // sie sollen in einem
zweidimensionalen Graph visualisiert werden
name: 'Spectral Flatness', // Name der
Kurve
marker: {
color: 'rgb(255, 48, 188)', // die Linie
soll rosa sein
},
text: spectralFlatness_array, // Beim MouseOver
soll Text aus dem spectralFlatness_array
// angezeigt werden
};
var trace5 = { // Variable für die
fünfte Kurve
x: zeit, // auf der X-Achse sollen die
Werte aus dem Array Zeit erscheinen
y: energy_array, // auf der Y-Achse sollen
die Werte aus dem energy_array erscheinen
mode: 'lines', // die Werte sollen als
Linie visualsiert werden
type: 'scatter' , // sie sollen in einem
zweidimensionalen Graph visualisiert werden,
name: 'Energy', // Name der Kurve
text: energy_array, // Beim MouseOver soll
Text aus dem energy_array
angezeigt werden
};
var trace6 = { // Variable für die
sechste Kurve
x: zeit, // auf der X-Achse sollen die
Werte aus dem Array Zeit erscheinen
y: spectralSlope_array, // auf der Y-Achse
sollen die Werte aus dem
// spectralSlope_array erscheinen
mode: 'lines', // die Werte sollen als
Linie visualsiert werden
type: 'scatter' , // sie sollen in einem
zweidimensionalen Graph visualisiert werden
name: 'Spectral Slope', // Name der Kurve
text: spectralSlope_array, // Beim MouseOver
soll Text aus dem spectralSlope_array
// angezeigt werden
};
var trace7 = { // Variable für die
siebte Kurve
x: zeit, // auf der X-Achse sollen die
Werte aus dem Array Zeit erscheinen
y: spectralRolloff_array, // auf der Y-Achse
sollen die Werte aus dem
// spectralRolloff_array erscheinen
mode: 'lines', // die Werte sollen als
Linie visualsiert werden
type: 'scatter' , // sie sollen in einem
zweidimensionalen Graph visualisiert werden
name: 'spectral Rolloff', // Name der Kurve
text: spectralRolloff_array, // Beim MouseOver
soll Text aus dem spectralRolloff_array
// angezeigt werden
};
var trace8 = { // Variable für die
achte Kurve
x: zeit, // auf der X-Achse sollen die
Werte aus dem Array Zeit erscheinen
y: spectralSpread_array, // auf der Y-Achse
sollen die Werte aus dem
// spectralSpread_array erscheinen
mode: 'lines', // die Werte sollen als
Linie visualsiert werden
type: 'scatter' , // sie sollen in einem
zweidimensionalen Graph visualisiert werden
name: 'Spectral Spread', // Name der Kurve
text: spectralSpread_array, // Beim MouseOver
soll Text aus dem spectralSpread_array
// angezeigt werden
};
var trace9 = { // Variable für die
neunte Kurve
x: zeit, // auf der X-Achse sollen die
Werte aus dem Array Zeit erscheinen
y: spectralSkewness_array, // auf der Y-Achse
sollen die Werte aus dem
// spectralSkewness_array erscheinen
mode: 'lines', // die Werte sollen als
Linie visualsiert werden
type: 'scatter' , // sie sollen in einem
zweidimensionalen Graph visualisiert werden
name: 'spectral Skewness', // Name der
Kurve
text: spectralSkewness_array, // Beim MouseOver
soll Text aus dem spectralSkewness_array
// angezeigt werden
};
var trace10 = { // Variable für die
zehnte Kurve
x: zeit, // auf der X-Achse sollen die
Werte aus dem Array Zeit erscheinen
y: spectralKurtosis_array, // auf der Y-Achse
sollen die Werte aus dem
// spectralKurtosis_array erscheinen
mode: 'lines', // die Werte sollen als
Linie visualsiert werden
type: 'scatter' , // sie sollen in einem
zweidimensionalen Graph visualisiert werden
name: 'spectral Kurtosis', // Name der
Kurve
text: spectralKurtosis_array, // Beim MouseOver
soll Text aus dem spectralKurtosis_array
// angezeigt werden
};
var trace11 = { // Variable für die
elfte Kurve
x: zeit, // auf der X-Achse sollen die
Werte aus dem Array Zeit erscheinen
y: perceptualSpread_array, // auf der Y-Achse
sollen die Werte aus dem
// perceptualSpread_array erscheinen
mode: 'lines', // die Werte sollen als
Linie visualsiert werden
type: 'scatter' , // sie sollen in einem
zweidimensionalen Graph visualisiert werden
name: 'Perceptual Spread', // Name der
Kurve
text: perceptualSpread_array, // Beim MouseOver
soll Text aus dem perceptualSpread_array
// angezeigt werden
};
var trace12 = { // Variable für die
zwölfte Kurve
x: zeit, // auf der X-Achse sollen die
Werte aus dem Array Zeit erscheinen
y: perceptualSharpness_array, // auf der
Y-Achse sollen die Werte aus dem
// perceptualSharpness_array erscheinen
mode: 'lines', // die Werte sollen als
Linie visualsiert werden
type: 'scatter' , // sie sollen in einem
zweidimensionalen Graph visualisiert werden
name: 'Perceptual Sharpness', // Name der
Kurve
text: perceptualSharpness_array, // Beim
MouseOver soll Text aus dem
// perceptualSharpness_array
angezeigt werden
};
var data = [ trace1, trace2, trace3, trace4, trace5, trace6, trace7, trace8,
trace9, trace10, trace11, trace12]; //
füge alle Kurvenarrys in dem Array
// data zusammen
var layout = { //
bestimme das Layout der Visualisierung
showlegend: true, // zeige eine interaktive
Legende an der rechten Seite der Visualisierung
xaxis: { // Eigenschaften der X-Achse
title: 'Samples', // Beschriftung
},
yaxis: { // Eigenschaften der Y-Achse
title: 'Amount', // Beschriftung
},
legend: { // Eigenschaften der Y-Legende
font: { family: 'Verdana, sans-serif', size: 10, color: 'black', }
// Schriftart, -größe und -farbe
in der Legende
},
title: 'Timbre Features eines Fagotts', //
Titel für die Visualisierung
};
Plotly.newPlot('AnzeigeDiv',
data, layout, {displayModeBar: false});
// gebe den Graphen in dem Bereich AnzeigeDiv
aus und verwende dafür die Variablen aus data und
// layout, zeige dabei nicht die Werkzeugleiste von PlotLy an.
}
8.
Zwischenspeicherung der von Meyda ermittelten Werte
Ganz am Ende
der Seite werden via <DIV>-Tags
die Stellen markiert, an denen die Werte für die einzelnen Timbre-Features
zwischengespeichert werden, um später in die jeweiligen Arrays geschrieben
zu werden. Mit dem Zusatz style="display:none"
wird dafür gesorgt, dass diese Zwischenspeicherung als Textfeld im
Browser nicht sichtbar ist.