wave-daten und array
-
hey,
wie kann ich die daten einer wave datei auslesen und in einem array speichern?
Komme an die header ran und die geben mir auch das richtige ergebnis. Allerdings erhalte ich nur einen wert in data (wie komme ich an die anderen ran?)
danke für jeden tipp,
bacco
-
Ich verstehe das Problem nicht. Du musst dir RIFF Struktur parsen, dann findest du irgendwann einen "data" Chunk, den liest du einfach als ganzer ein, alle "Nutzdaten" in dem Chunk (also alles bis auf die Chunk Kennung und die Länge) sind Samples. Wie die zu interpretieren sind (8 Bit Mono, 16 Bit Stereo, ...) steht im "fmt " Chunk.
-
das problem, das ich habe ist an die einzelnen werte heran zu kommen.
wenn ich auf meine struktur datchunk (darin ist data als long definiert) ausführe
fread(&datChunk, sizeof(datchunk),1,WaveDatei);
printf("%i", datChunk.data)
dann bekomme ich logischerweise nur einen wert zurück (wert ist 1634074624).wie komme ich nun aber an die anderen werte ran?
gruß bacco
-
hat vllt noch jemand einen hinsweis? wie greife ich auf den nächsten datensatz zu?
-
Ein wenig Pseudo-Code wie man ein RIFF File richtig einliest:
DWORD riff_header[3]; DWORD chunk_header[2]; open_file(); // read RIFF header read(riff_header, 12); if(riff_header[0] != 'FFIR') // "RIFF" error(); if(riff_header[2] != 'EVAW') // "WAVE" error(); // check RIFF size riff_size = riff_header[1]; if(riff_size > file_size) error(); // read all chunks offset = 12; while((offset + 8) <= riff_size) { // read next chunk header seek(offset); read(chunk_header, 8); offset += 8; chunk_data_size = chunk_header[1]; chunk_data_offset = offset; // make offset for next chunk offset += chunk_data_size; if(offset > riff_size) error(); if(offset & 1) offset++; // always make even offset // see what kind of chunk we have found switch(chunk_header[0]) { case ' tmf': // "fmt " seek(chunk_data_offset); // read "fmt " chunk data // ... break; case 'atad': // "data" seek(chunk_data_offset); // read "data" chunk data if(samples) error(); // 2nd "data" chunk found -> invalid file samples = new char[chunk_data_size]; read(samples, chunk_data_size); break; default: // unknown chunk -> ignore break; } }Also. Du musst als erstes die RIFF Header auswerten, das sind 3 DWORDs, das erste muss immer "RIFF" sein, das zweite ist die grösse der gültigen RIFF Daten im File, und das dritte ist der "RIFF Typ", in diesem Fall muss das "WAVE" sein.
Dann fängst du ab Offset 12 an, und liest alle Chunks ein. Eine Chunk header besteht aus 2 DWORDs, das erste ist der Chunk-Typ und das 2. die grösse der Daten in diesem Chunk, wobei die 8 Byte der Chunk Header *nicht* mitgezählt werden. Die Chunk Daten beginnen unmittelbar nach der Header, und danach folgt der nächste Chunk, wobei der Offset jedes Chunks immer auf eine gerade Adresse gebracht wird, also +1 falls der Offset ungerade wird. Wenn du dann den "data" Chunk findest liest du einfach die ganzen Daten ein, das sind dann die Samples. Wie diese Samples zu interpretieren sind steht im "fmt " Chunk, den musst du also auch einlesen, sonst wirst du mit den Sample-Daten nix anfangen können.
-
Hey hustbaer,
vielen Dank, dass du dir die Zeit genommen hast den Pseudocode hinzuschreiben. Mich schlägt aber leider noch immer ziemlich stark die Unwissenheit, da doch noch ein Newb. Wäre super, wenn du mir noch einmal unter die Arme greifen könntest.
Habe unter anderem Probleme mit dem _read und fseek (ob ich da die Parameter richtig gesetzt habe).
Und dann kann ich mit samples nicht viel anfangen. Zumal ich mir dann immer noch nicht sicher bin, wo und in was genau die Daten gespeichert sind...Vielen Dank für die Unterstützung,
bacco/// Testbereich int fd; DWORD riff_header[3]; DWORD chunk_header[2]; long riff_size,fill_size; long offset; // open_file("c:\\test.wav"); WAVFile = fopen(WavDatName, "rb"); // read RIFF header if ( (fd= _open( "c:\\test.wav", _O_RDONLY )) == -1) printf("Fehler beim Öffnen!"); _read(fd, riff_header, 12); // fread(&RIFFChunk, sizeof(RIFFChunk), 1, WAVFile); if(riff_header[0] != 'FFIR') // "RIFF" printf("Fehler"); else printf("scheint zu gehen"); if(riff_header[2] != 'EVAW') printf("Keine Wave"); else printf("Wave erkannt"); // Riff Groesse wird gecheckt - ob kleiner als filesize riff_size = riff_header[1]; //if (riff_size>file_size) // { // printf("Fehler: Riff-Size grösser als Datei-Groesse! -- Abbruch --"); // return(-9); //} long chunk_data_size; long chunk_data_offset; // lesen der chunks offset = 12; printf("\noffset: %i", offset); printf("\nriff_size: %i", riff_size); while((offset + 8) <=riff_size) { // lesen des nächsten chunk headers fseek(WAVFile,offset, SEEK_SET); _read(fd, chunk_header, 8); offset +=8; printf("\noffset nach fseek und read: %i", offset); chunk_data_size = chunk_header[1]; chunk_data_offset = offset; // offset für naechsten chunk vorbereiten offset += chunk_data_size; if (offset > riff_size) { printf("Offset ist groesser als Riff-Size! -- Abbruch --"); return(-10); } if (offset & 1) { printf("\noffset wird angeglichen"); offset++; } // nachschauen was fuer chunk da sind switch (chunk_header[0]) { case ' tmf': fseek(WAVFile,chunk_data_offset, SEEK_SET); // lesen der "fmt " chunk daten break; case 'atad': fseek(WAVFile, chunk_data_offset, SEEK_SET); // lesen der data chunks // if (samples) { printf("Fehler, 2ten daten chunk gefunden"); return(-11); } // samples = new char[chunk_data_size]; // _read(fd, samples, chunk_data_size); break; default: // unbekannter chunk return(-12); break; } } /// Ende Testbereich
-
Ok. Ähm. Hüstel. Ich hatte da einen kleinen Fehler drinnen, und zwar zählen die ersten beiden DWORDs - das "RIFF" und die RIFF-grösse - bei eben dieser RIFF-grösse nicht mit. Also muss man noch 8 Byte draufzählen. Habe das korrigiert. Davon abgesehen funktioniert der Code aber - zumindest mit dem einen Wave-File mit dem ich es getestet habe

Und wo die Daten stehen? Na im "data" chunk eben, also das was auf die header des "data" chunks folgt sind die Daten. Allerdings fängst du damit alleine noch nix an, du musst natürlich auch noch den "fmt " Chunk lesen und auswerten, die Daten in so einem Wave File können ja in allen möglichen und unmöglichen Formaten da drinnen stehen, du musst z.B. wissen ob die 8 oder 16 Bit sind, Mono oder Stereo etc.
BTW: der Code ist etwas unsauber, ich bin einfach von dem ausgegangen was du geschrieben hast. Fehlerbehandlung wäre schöner mit Exceptions, und natürlich könnte/sollte man das ganze in eine Klasse packen und in einige Unterfunktionen zerteilen. Ist halt greislicher Spaghetticode, aber funktioniert, und "schöner machen" kannst du es ja immer nocht.
#include <cstdlib> #include <cstdio> #include <cassert> #include <conio.h> // für _getch() int WaveReadTest(char const* waveName) { int result = -1; // file aufmachen long file_size; unsigned long riff_header[3]; unsigned long riff_size; unsigned long chunk_header[2]; unsigned long chunk_data_size; unsigned long chunk_data_offset; unsigned long offset = 12; bool have_fmt = false; bool have_data = false; unsigned char* sample_data = 0; FILE* file = fopen(waveName, "rb"); if(!file) { printf("fopen fehler.\n"); result = -2; goto exit; } // file size ermitteln if(fseek(file, 0, SEEK_END) != 0) { printf("fseek (grösse ermitteln) fehler.\n"); result = -3; goto exit; } file_size = ftell(file); if(file_size < 0) { printf("ftell fehler.\n"); result = -4; goto exit; } if(fseek(file, 0, SEEK_SET) != 0) { printf("fseek (riff-header) fehler.\n"); result = -5; goto exit; } assert(sizeof(riff_header) == 12); if(fread(riff_header, sizeof(riff_header), 1, file) != 1) { printf("fread (riff-header) fehler.\n"); result = -6; goto exit; } if(riff_header[0] != 'FFIR') // "RIFF" { printf("kein RIFF file.\n"); result = -7; goto exit; } if(riff_header[2] != 'EVAW') { printf("kein WAVE file.\n"); result = -8; goto exit; } // grösse checken riff_size = riff_header[1] + 8; if(riff_size > static_cast<unsigned long>(file_size)) { printf("kaputtes RIFF/WAVE file (RIFF länge ist grösser als das file).\n"); result = -9; goto exit; } printf("file size: %d\n", file_size); printf("RIFF size: %d\n", riff_size); // lesen der chunks offset = 12; printf("lese chunks...\n"); while((offset + 8) <= riff_size) { printf("\n"); printf("lese naechste chunk-header (offset = %d)...\n", offset); // lesen des nächsten chunk headers if(fseek(file, offset, SEEK_SET) != 0) { printf("fseek (chunk-header) fehler.\n"); result = -10; } assert(sizeof(chunk_header) == 8); if(fread(chunk_header, sizeof(chunk_header), 1, file) != 1) { printf("fread (chunk-header) fehler.\n"); result = -11; goto exit; } printf("chunk '%c%c%c%c'.\n", chunk_header[0] & 0xFF, (chunk_header[0] >> 8) & 0xFF, (chunk_header[0] >> 16) & 0xFF, (chunk_header[0] >> 24) & 0xFF); printf("(offset: %d, length: %d)\n", offset, chunk_header[1]); // chunk header überspringen offset += 8; // chunk daten position & grösse merken chunk_data_size = chunk_header[1]; chunk_data_offset = offset; // chunk daten grösse checken & offset für naechsten chunk vorbereiten offset += chunk_data_size; if (offset > riff_size) { printf("chunk daten zu gross.\n"); result = -12; goto exit; } if(offset & 1) { printf("offset wird angeglichen...\n"); offset++; } // zu chunk daten springen if(fseek(file, chunk_data_offset, SEEK_SET) != 0) { printf("fseek (chunk-data) fehler.\n"); result = -13; } // nachschauen was für nen chunk wir gefunden haben... switch(chunk_header[0]) { case ' tmf': printf("fmt chunk gefunden.\n"); if(have_fmt) { printf("zweiter fmt chunk gefunden -> fehler.\n"); result = -14; goto exit; } // TODO: lesen der "fmt " chunk daten have_fmt = true; break; case 'atad': printf("data chunk gefunden.\n"); if(have_data) { printf("zweiter data chunk gefunden -> fehler.\n"); result = -14; goto exit; } // lesen des data chunks printf("lese daten..."); assert(sample_data == 0); // hier holen wir uns speicher (RAM) wo wir die samples reinklatschen können sample_data = new unsigned char[chunk_data_size]; // hier lesen wir diese samples (die "bytes" eben die auf die "data" chunk header folgen // eben die "daten" des "data" chunks) if(fread(sample_data, 1, chunk_data_size, file) != chunk_data_size) { printf("fread (data) fehler.\n"); result = -15; goto exit; } printf("OK.\n"); have_data = true; break; default: // unbekannter chunk -> das ist OK, den ignorieren wir einfach! printf("unbekannter chunk '%c%c%c%c' gefunden -> den ignorieren wir.\n", chunk_header[0] & 0xFF, (chunk_header[0] >> 8) & 0xFF, (chunk_header[0] >> 16) & 0xFF, (chunk_header[0] >> 24) & 0xFF); break; } if(have_fmt && have_data) { printf("(habe fmt und data. wir koennten hier einfach mit 'break' schluss machen, aber weils so lustig ist machen wir weiter)\n"); } } printf("\n"); printf("fertig mit chunks lesen.\n"); if(!have_fmt) { printf("fmt chunk fehlt.\n"); result = -100; goto exit; } if(!have_data) { printf("data chunk fehlt.\n"); result = -101; goto exit; } // juche! result = 0; exit: delete [] sample_data; if(file) fclose(file); return result; } int main(int argc, char** argv) { WaveReadTest("c:\\test.wav"); _getch(); return 0; }
-
hey hustbaer,
nochmal vielen dank für deine hilfe. ich bin schon froh, dass ich einigermaßen verstehe was da gemacht wird, komme allerdings nicht weiter mit den daten auslesen.
wäre super, wenn du da noch den letzten schliff für die daten und dem array geben könntest, denn ich sitze da total auf dem schlauch.ist mir zugegeben auch unangenehm dich damit so lange zu belästigen (habe mich gestern und heute noch einmal bemüht den rest zu programmieren, allerdings ist das recht lachhaft), das ding muss leider fertig werden und es ist mir über. würde mich also sehr freuen, wenn du dein wissen mit mir teilen könntest.
vielen dank,
:xmas1:
bacco
-
Es wäre Hilfreich zu wissen was du mit den Wavedaten anfangen willst. Also was das Programm tun soll. Und in welchem Zusammenhang. Das "Daten auslesen" steht ja schon da, also daran kanns eigentlich nimmer liegen.
Evtl. wärst du auch mit einer Library besser dran die das alles für dich macht, bloss hat deine ursprüngliche Frage so geklungen als ob du das lieber selbst programmieren würdest.
Eine Möglichkeit wäre die "libsndfile" (LGPL):
http://www.mega-nerd.com/libsndfile/
oder evtl. auch "BASS", wenn sich die Lizenz miz dem was du machst verträgt ("free for non-commercial use" - sonst musste zahlen):
http://www.un4seen.com/Die "libsndfile" war 2005 etwas "eingeschlafen", aber seit Anfang 2006 gibts wieder ein paar neue Releases, ist also denke ich nicht als "tot" einzustufen

-
hey hustbaer,
ist nicht nur ein lieber - eher ein selber programmieren müssen. und daher nützen mir die libs dann auch recht wenig.
brauche ein array, in dem die Daten der wave-file enthalten sind. weiss ja, dass die unterschiedlich vorliegen (je nach mono/stereo, bitanzahl, etc), aber ich kann das mit meinem wissen nicht umsetzen.
das array soll (array muss) dann an eine andere funktion übergeben werden, in der es dann ausgewertet und entsprechend grafisch dargestellt wird.weihnachtliche grüße,
bacco
-
Hm. Müssen. Klingt nach Aufgabe. Aufgaben mach ich aber keine. Ausserdem hast du alles was du brauchst.
-
Ist ein versprechen, das ich an nen freund gegeben habe. so gesehen ist es eine aufgabe. habe sie mir nur wesentlich leichter vorgestellt - und mich daher auch so darauf festgelegt.
im nächsten schritt sollten sie dann per open-gl aufgearbeitet werden, aber das wollte er dann machen.Danke dir auf jeden fall für deine unterstützung. werde versuchen mir den rest zu erbasteln.
frohes festle,
bacco