Wave File einlesen und in ein Array speichern
-
Guten Morgen,
ich möchte gerne ein .wave file unter c++ einlesen und die Informationen in ein Array speichern, damit ich mit diesen später weiter arbeiten kann.
Kann mir jmd. sagen, wie man so etwas "rel." einfach, ohne wiedergabefunktion etc., realisiert?
Vielen Dank und lieben Gruß
nano1
-
Guck dir mal die C++ Filestreams an. Stichworte: std::ifstream, std::ofstream
-
Hallo PI,
vielen Dank schon mal. Das schaue ich mir direkt mal an
-
Da gibt es ein weiteres Problem:
C++ hilft dir auf jeder Plattform Dateien zu lesen und zu schreiben. C++ hilft dir aber nicht, aus ein paar Bytes einen Klang zu errechnen. Das ist vom Dateiformat abhängig, welches du selbst programmieren musst (darfst).
-
Wenn du jedoch mit "in ein Array schreiben" einfach nur die Bytes aus einer Datei in den RAM bringen meinst, kann man das auch ohne Dateiformat-Parsing machen:
#include <string> #include <ifstream> #include <iostream> #include <vector> int main() { std::string Name("Filename.wav"); std::ifstream Input(Name.c_str()); if(!Input) { std::cerr << "Cannot read \"" << Name << "\"!"; return -1; } std::vector Data; while(Input) { char CurrentByte; Input >> CurrentByte; Data.push_back(CurrentByte); } }
-
ohha, ich hab es befürchtet. Ich möchte das Frequenzverhalten eines Stimmprofils mittels Fast Fourertransformation untersuchen um später sprecherspezifische Merkmale zu extrahieren. Das heißt, ich brauche die Sprecherdaten in einer auswertbaren Art und Weise. Und da schien mir ein Array am plausibelsten. In Matlab war das ganze relativ einfach zu gestallten. In C++ scheint mir das Ganze ein wenig komplizierter zu sein
-
Mit Arrays kommst du in C++ nicht weit. std::vector ist, was du suchst.
-
nano1 schrieb:
In C++ scheint mir das Ganze ein wenig komplizierter zu sein
In C++ wird es genau so einfach sein (nimm ich an), wenn du das Wave-File zuerst in einen
std::vector
voll mit Frequenzen gerechnet hast.
-
Hallo nano1,
Willkommen im C++-Forum.
nano1 schrieb:
ohha, ich hab es befürchtet.
Was genau hast Du befürchtet - und ist anscheinend eingetreten?
nano1 schrieb:
Ich möchte das Frequenzverhalten eines Stimmprofils mittels Fast Fourertransformation untersuchen um später sprecherspezifische Merkmale zu extrahieren. Das heißt, ich brauche die Sprecherdaten in einer auswertbaren Art und Weise. Und da schien mir ein Array am plausibelsten. In Matlab war das ganze relativ einfach zu gestallten. In C++ scheint mir das Ganze ein wenig komplizierter zu sein
Na ja - es ist überall das gleiche: um so besser man mit einem Werkzeug (C++ oder Matlab) umgehen kann, desto einfacher wird es.
Achte darauf, dass die Datei im binary-Mode geöffnet wird, da es sich bei den .WAVE-Dateien um Binärdateien handelt. D.h. dort können Zeichen mit beliebigen Werten drin stehen, die ansonsten miss interpretiert werden können.
Weiter darfst Du nicht formatiert lesen (ist ja kein Textformat da), sondern wenn schon byteweise dann alle Zeichen - vielleicht so:#include <fstream> #include <iostream> #include <vector> #include <iterator> // istreambuf_iterator int main() { using namespace std; const char* Name = "Filename.wav"; ifstream Input( Name, ios_base::binary ); if( !Input.is_open() ) { std::cerr << "Cannot read \"" << Name << "\"!"; return -1; } vector< char > Data( (istreambuf_iterator< char >( Input )), istreambuf_iterator< char >() ); // ab hier stehen jetzt die Bytes aus der Datei in Data zur Verfügung .. }
anschließend beginnt natürlich erst die Arbeit, dieses 'Data' aus einander zu pflücken.
Der C++-Way wäre hier ein eigener binärer Stream mit Extraktoren für rudimentäre Int2 und Int4-Werte sowie die verschieden Chunks der Wave-Datei. Aber das ist eine andere Geschichte.
Gruß
Werner
-
Vielen Dank Werner, sehr freundlich.
Was genau hast Du befürchtet - und ist anscheinend eingetreten?
Das sich das Einlesen nicht idealerweise via Array's realisieren lässt. Unter Matlab konnte man mit Hilfe von
waveread
wavfiles einlesen. Als Folge hatte man ein 1 dimensionales Datenfeld, welches aus sovielen Elementen bestand, wieviel Abtastwerte es auch gab. Mir leuchtet jedoch ein, dass man bei C++ ein wenig anders vorgehen muss um verwertbare Informationen aus den Audiodateien extrahieren zu können.
Na ja - es ist überall das gleiche: um so besser man mit einem Werkzeug (C++ oder Matlab) umgehen kann, desto einfacher wird es.
Da hast Du vollkommen recht. In Matlab konnte ich mich bis dato "ausreichend" einarbeiten. C++ hatte ich zwar damals auch ein paar Semester, jedoch sind mit der Zeit Erinnerungs- und Wissenslücken aufgetreten, welche es wieder zu schließen gilt.
Statt dem Dateinamen des Audiofiles wird doch auch ein Pfadname + Dateiname akzeptiert. Ich präferiere einen dynamischen bzw. relativen Pfad, weiß jedoch nicht mehr, von wo aus die Quelle betrachtet wird ... von dem Ort, wo die .exe liegt, oder die c++-Projektdatei?
Vielen Dank für all die Hinweise und Hilfen
-
Ich habe den Code nun in einer Funktion load() implementiert. Verstehe ich das richtig, dass 'Data' ein Vektor vom Typ Char ist und das ich dann bei der Funktion 'load()' auch char als Rückgabeparameter angeben muss?
#include <fstream> #include <iostream> #include <vector> #include <iterator> // istreambuf_iterator char load() { using namespace std; const char* Name = "Filename.wav"; ifstream Input( Name, ios_base::binary ); if( !Input.is_open() ) { std::cerr << "Cannot read \"" << Name << "\"!"; return -1; } vector< char > Data( (istreambuf_iterator< char >( Input )), istreambuf_iterator< char >() ); // ab hier stehen jetzt die Bytes aus der Datei in Data zur Verfügung .. return Data; }
In der Mainfunktion würde ich dann gerne die load() Funktion aufrufen. Ist das so ok?
int main() { char loadfile = load(); }
-
Benutz einfach ne Library, sonst wird das nie was. Hab kurz gegoogelt und das hier gefunden.
http://clam-project.org/wiki/Frequenly_Asked_Questions#What_does_CLAM_stand_for.3Fsieht so aus als wäre das genau was du brauchst damit kannst du auch direkt FFT usw. machen.
-
nano1 schrieb:
Ich habe den Code nun in einer Funktion load() implementiert. Verstehe ich das richtig, dass 'Data' ein Vektor vom Typ Char ist und das ich dann bei der Funktion 'load()' auch char als Rückgabeparameter angeben muss?
nicht ganz. Der Typ des Rückgabewertes ist std::vector<char>. Also ein dynamisches Array - wenn Du so willst. Dieses Array enthält aber nicht (nur) das Sample sondern die gesamte WAV-Datei.
nano1 schrieb:
In der Mainfunktion würde ich dann gerne die load() Funktion aufrufen. Ist das so ok?
int main() { char loadfile = load(); }
wenn dann so:
// ... std::vector< char > load() { // ... } int main() { using namespace std; vector< char > loadfile = load(); }
Tanren schrieb:
Benutz einfach ne Library, sonst wird das nie was.
Tanren hat Recht. Ist wahrscheinlich das beste, wenn Du etwas fertiges benutzt.
Ich habe auch noch was gefunden: 'A Simple C++ Class to Manipulate WAV Files' Ist leider sehr C-lastig, was das das Einlesen angeht, aber recht informativ.Gruß
Werner
-
@Tanren @ Werner,
vielen Dank. Beides ist sehr hilfreich.
Ich habe die Anwendungsdateien von CLAM mal installiert ... ich muss sagen, auf den ersten Blick ein mächtiges Werkzeug. Ich arbeite mich da jetzt mal ein. Ich habe auch gelesen, dass man auch den Sourcecode implementieren kann, bzw. eine lib einbinden.
Beschäftige mich gerade mit dem CLAM Network Editor. Vielleicht kann ich ja die Signalverarbeitung grafik-basierend verwalten und die Ergebnisse nachher irgendwo ablegen, einlesen oder speichern. Das wäre super.
Vielen Dank an Euch
-
Guten Morgen Zusammen,
konnte jmd. schon Erfahrungen mit dem CLAM Network Editor (framework) machen? Wenn ich ein network erstellen, also beispielsweise ein audiofile lade, in dem ich den 'AudioFileMemoryLoader' via Drag&Drop auf die Oberfläche ziehe und dieses via dem FFT-Modul transformiere. Wie bekomme ich nun die Informationen gespeichert? Lässt sich das Speichern auch noch unter dem Framework des Network Editor realisieren, oder muss ich das im C++ Editor machen durch Bibliotheken laden und Funktionen aufrufen?
Ist es schwierig, mit c++ eine Hardware, beispielsweise eine Steuerungseinheit anzusprechen? Dazu benötige ich doch eine I/O Karte, oder?
Viele Grüße