Hallo, ich bin noch ein ziemlicher Neuling in Sachen programmieren und muss nun, zumindest für mich, schwierige Programmieraufgabe lösen: Es geht darum WAV Dateien in c++ zu manipulieren. Wir haben einen framework zur Verfügung gestellt bekommen, wo schon wesentliche Funktionen enthalten sind, müssen aber noch fertig erstellt werden. -Die erste Aufgabe besteht darin, die "readWaveHeader" und printWaveheader" Funktionen so zu implementieren, dass sie Informationen zu einem WAV-File nach folgendem Schema ausgeben: Codec: PCM, 44100Hz, 16bitm 1 channel: Length 9.81 sec -In Aufgabe zwei soll die "readWaveHeader" so umprogrammiert werden, dass sie eine Fehlermeldung ausgibt, wenn eine WAV-Datei nicht die Eigenschaften: "Codec: PCM, 44100Hz, 16bit, 1 channel" erfüllt. -Dann soll als drittens die "writeWaveHeader" so implementiert werden, dass sie ein Waveheader in einen Output-Stream schreibt. -Dann ist noch angegeben, dass das Programm folgendes Unterstüzen sollte: 1.) Wenn das Programm mit dem -totext Parameter aufgerufen wird, soll eine Textdatei (out.text) erzeugt werden, welche die einzelnen Samples(short) als ASCII Zahl auflistet. 2.) Wenn das Programm mit dem -volume Parameter aufgerufen wird, soll das Programm die Lautstärke der Eingabedatei ändern. Ein float Parameter soll den Faktor angeben. 3.) Wenn das Programm mit dem -mix Parameter aufgerufen wird, kann es zwei Audiodateien mischen. 4.) Wenn das Programm mit dem -echo Parameter aufgerufen wird, soll ein Echoeffekt erzeugt werden. Der erste Parameter soll die Verzögerung, der zweite die Lautstärke des Echos angeben. Hier ist das noch das vorgegebene Framework: [cpp][code] /******************************************************************** purpose: A simple PCM Wave File Editing TOOL created: 2010/11/08 filename: audio_tmpl.cpp author: *********************************************************************/ #include <iostream> #include <fstream> #include <sstream> #include <string> #include <cstring> #include <limits.h> #include <stdlib.h> using namespace std; struct WAVEHEADER { char ChunkID[4]; // Contains the letters "RIFF" in ASCII form int ChunkSize; int Format; char Subchunk1ID[4]; int Subchunk1Size; short AudioFormat; short NumChannels; int SampleRate; int ByteRate; short BlockAlign; short BitsPerSample; char Subchunk2ID[4]; int Subchunk2Size; }; //--------------------------------------------------------- // helper functions //--------------------------------------------------------- /* * Gibt wave file header Informationen in der Console aus; * \param hdr: wavefile hdr */ void printWaveHeaderInfos( WAVEHEADER *hdr) { if(NULL == hdr) { cerr << "Keine Waveheaderinformationen gefunden" << endl; } // outpout // codec, sampling rate, sampling precision, channels, length /* TODO */ } /* * Liest den Waveheader und checkt ob das Format unterstuetzt wird; * \param fin: ifstream. * \return: NULL in case of error, waveheader else */ WAVEHEADER *readWaveHeader(ifstream *fin) { WAVEHEADER *hdr = NULL; //benutze die read Funktion um binaere Daten zu lesen hdr = new WAVEHEADER; fin.read((char*)&hdr, sizeof(WAVEHEADER)) /* TODO */ printWaveHeaderInfos(hdr); return hdr; } /* * Schreibt den Waveheader * \param fin: ifstream. * \param hdr: wavefile hdr * \return: false in case of an write error */ bool writeWaveHeader(ofstream *fout, WAVEHEADER *hdr) { if(NULL == hdr) return false; // save hdr into file /* TODO */ return true; } //--------------------------------------------------------- // Commands //--------------------------------------------------------- /* * Fuer den Commando -info * \param fin: ifstream. */ void waveFileInfo( char * filename ) { //oeffne die Datei filename als binaere Datei (fin) ifstream fin(filename, ios::in | ios::binary); if( !fin.is_open() ) { cerr << filename << " not found." << endl; } else { WAVEHEADER *hdr = readWaveHeader(&fin); delete hdr; } } void convertWaveFile( char infile[], char outfile[] ) { cout << "Trying to convert wavefile to text:" << endl; /* TODO */ cout << "done" << endl; } void volumeWaveFile( char infile[], char outfile[], double gain ) { cout << "Changing Volume:" << endl; /* TODO */ cout << "done" << endl; } void mixWaveFiles( char infile1[], char infile2[], char outfile[] ) { cout << "Mixing 2 audio files:" << endl; /* TODO */ cout << "done" << endl; } void echoWaveFile( char infile[], char outfile[], double delay, double echo_gain ) { cout << "Adding echo:" << endl; /* TODO */ cout << "done" << endl; } //--------------------------------------------------------- // main //--------------------------------------------------------- int main(int argc, char *argv[]) { readWaveHeader(); char *command = "-info"; char **parms = &argv[1]; int parms_count = argc - 1; if(argc > 1 && argv[1][0] == '-') { command = argv[1]; parms = &argv[2]; parms_count--; } // -info command standard case prints info of the given file if(!strcmp(command, "-info")) { if(parms_count >= 1) { waveFileInfo(parms[0]); return 0; } else { cerr << "Call " << endl; cerr << argv[0] << " [-info] wavefile" << endl; cerr << argv[0] << " -help : \tfor more help" << endl; return 1; } } // -help command if(!strcmp(command, "-help")) { cout << "Help:" << endl; cout << argv[0] << " -totext wavfile_in textfile_out" << endl; cout << argv[0] << " -volume gain wavfile_in wavfile_out" << endl; cout << argv[0] << " -mix wavfile1_in wavfile2_in wavfile_out" << endl; cout << argv[0] << " -echo delay strength wavfile_in wavfile_out" << endl; return 0; } // -totext command if(!strcmp(command, "-totext")) { if(parms_count >= 2) { convertWaveFile( parms[0], parms[1]); return 0; } else { cerr << "Not enough parameters" << endl; return 1; } } // -vol command if(!strcmp(command, "-volume")) { if(parms_count >= 3) { volumeWaveFile( parms[1], parms[2], atof(parms[0])); return 0; } else { cerr << "Not enough parameters" << endl; return 1; } } // -mix command if(!strcmp(command, "-mix")) { if(parms_count >= 3) { mixWaveFiles( parms[0], parms[1], parms[2]); return 0; } else { cerr << "Not enough parameters" << endl; return 1; } } // -echo command if(!strcmp(command, "-echo")) { if(parms_count >= 4) { echoWaveFile( parms[2], parms[3], atof(parms[0]), atof(parms[1])); return 0; } else { cerr << "Not enough parameters" << endl; return 1; } } return 0; } [/cpp] Die Funktion "readWaveHeader();" in der Main habe ich bereits eingefügt, ebenfalls habe ich bereits die Zeile "fin.read((char*)&hdr, sizeof(WAVEHEADER))" in WAVEHEADER *readWaveHeader(ifstream *fin) {..} eingeführt, jedoch kommt schon da die erste Fehlermedlung. Ich hoffe mir kann jemand ein paar Tipps zu den einzelnen Aufgaben geben. mfg Hans
Hans Lüthi schrieb: > Ich hoffe mir kann jemand ein paar Tipps zu den einzelnen Aufgaben > geben. Mach deine Hausaufgaben selbst?
Was hast du schon selbst gemacht und wo liegt ein konkretes Problem?
Hans Lüthi schrieb: > eingeführt, jedoch kommt schon da die erste Fehlermedlung. Dann lies die Fehlermeldung. Meistens (nicht immer) ist die ein guter Hinweis darauf, wo du die Regeln der Sprache verletzt hast. Schau dir den Code an und versuche die Fehlermeldung mit dem Code in Übereinstimmung zu bringen und dann korrigiere den Fehler. > Ich hoffe mir kann jemand ein paar Tipps zu den einzelnen Aufgaben > geben. Fang bei der ersten Nummer an und arbeite dich sukzessive durch die Aufgabe durch. Deine Aufgabe ist nicht schwer und wenn du in deinem Kurs aufgepasst hast, ist das ziemlich einfach zu lösen. Da werden Konstrukte verwendet, die ganz sicher nicht in der ersten Stunde Programmieren benutzt werden. Von daher kann man mit Sichereheit sagen: Wenn dich da bei einer Zeile einfügen eine Fehlermeldung soweit aus dem Konzept wirft, dass du noch nicht mal den Text der Fehlermeldung weißt bzw. dir bewusst ist, dass dieser Text wichtig ist, dann hast du in der Vergangenheit in deinem Kurs, tja, geschlafen oder Karten gespielt oder was weiß ich. Auf jeden Fall kannst du nicht viele Hausaufgaben selbst gemacht haben. Und das rächt sich jetzt.
So, ich glaube Aufgabe 1 habe ich soweit gelöst: void printWaveHeaderInfos( WAVEHEADER *hdr) { if(NULL == hdr) { cerr << "Keine Waveheaderinformationen gefunden" << endl; } else { cout << "Codec: "; cout << "PCM, "; cout << hdr->SampleRate << " Hz, "; cout << hdr->BitsPerSample << "bit, "; cout << hdr->NumChannels << " channel, "; cout << "Length " << hdr->ByteRate << " sec" << endl; } // outpout // codec, sampling rate, sampling precision, channels, length /* TODO */ } /* * Liest den Waveheader und checkt ob das Format unterstuetzt wird; * \param fin: ifstream. * \return: NULL in case of error, waveheader else */ WAVEHEADER *readWaveHeader(ifstream *fin) { WAVEHEADER *hdr = NULL; //benutze die read Funktion um binaere Daten zu lesen hdr = new WAVEHEADER; fin->read((char*)&hdr, sizeof(WAVEHEADER)); /* TODO */ printWaveHeaderInfos(hdr); return hdr; } Nun habe ich aber folgenden Fehler, aber erst beim Ausführen: "a.exe": "C:\Users\Hans\Desktop\Aufgaben c++\a\Debug\a.exe" geladen, Symbole wurden geladen. "a.exe": "C:\Windows\SysWOW64\ntdll.dll" geladen, Cannot find or open the PDB file "a.exe": "C:\Windows\SysWOW64\kernel32.dll" geladen, Cannot find or open the PDB file "a.exe": "C:\Windows\SysWOW64\KernelBase.dll" geladen, Cannot find or open the PDB file "a.exe": "C:\Windows\SysWOW64\msvcp100d.dll" geladen, Symbole wurden geladen. "a.exe": "C:\Windows\SysWOW64\msvcr100d.dll" geladen, Symbole wurden geladen. Das Programm "[4196] a.exe: Systemeigen" wurde mit Code 1 (0x1) beendet. Die WAV Daten habe ich aber im gleichen File wie die .exe oder die .cpp Als Programmierumgebung habe ich VS2008
Hans Lüthi schrieb: > Nun habe ich aber folgenden Fehler, aber erst beim Ausführen: > > "a.exe": "C:\Users\Hans\Desktop\Aufgaben c++\a\Debug\a.exe" geladen, > Symbole wurden geladen. > "a.exe": "C:\Windows\SysWOW64\ntdll.dll" geladen, Cannot find or open > the PDB file > "a.exe": "C:\Windows\SysWOW64\kernel32.dll" geladen, Cannot find or open > the PDB file > "a.exe": "C:\Windows\SysWOW64\KernelBase.dll" geladen, Cannot find or > open the PDB file > "a.exe": "C:\Windows\SysWOW64\msvcp100d.dll" geladen, Symbole wurden > geladen. > "a.exe": "C:\Windows\SysWOW64\msvcr100d.dll" geladen, Symbole wurden > geladen. > Das Programm "[4196] a.exe: Systemeigen" wurde mit Code 1 (0x1) beendet. Kannst du alle ignorieren. Das sind Meldungen vom Debugger, dass er keine Debuginfo für die Teile deines Programmes gefunden hat, die eigentlich WIndows Funktionen sind. Du wirst daher nicht in Windows-Funktionen reinsteppen können, was du aber sowieso nicht vor hast. > cout << "Codec: "; > cout << "PCM, "; Echt? Dein Codec ist immer PCM?
Karl Heinz Buchegger schrieb: >> cout << "Codec: "; >> cout << "PCM, "; > > Echt? Dein Codec ist immer PCM? Schau mal hier rein http://www.sonicspot.com/guide/wavefiles.html Das was bei dir "AudioFormat" heißt, heißt in dieser Beschreibung "Compression Code" und da gibt es eine schöne Tabelle über mögliche Werte.
Ok, dass mit dem PCM muss ich noch ändern: if (hdr->AudioFormat == 1) { cout << "PCM, "; } else { cout << "This is not a PCM file! "; } Ich bin mir unschlüssig wie ich die fin.open Argumente von der Mainfunktion nach WAVEHEADER *readWaveHeader(ifstream *fin) {...} übergeben kann. Ich habe es bisher soweit gebracht: ifstream fin; fin.open("audio1.wav"); readWaveHeader(); fin.close; Ich weiss aber nicht was für ein Argument ich in die Klammern von "readWaveHeader()" tu soll.
Hans Lüthi schrieb: > Ich bin mir unschlüssig wie ich die fin.open Argumente von der > Mainfunktion > nach WAVEHEADER *readWaveHeader(ifstream *fin) {...} übergeben kann. Die Funktion sagt es dir doch. Sie will einen Pointer auf ein ifstream Objekt. > Ich habe es bisher soweit gebracht: > > ifstream fin; > fin.open("audio1.wav"); > readWaveHeader(); dein ifstream Objekt heißt fin. Und readWaveHeader will einen Pointer darauf. Also: readWaveHeader( &fin );
Ok, danke Kompilieren tut es ohne probleme, jedoch kommt ein Fehler: Durch einen Pufferüberlauf in a.exe wurde der interne Programmzustand beschädigt. Klicken Sie auf "Unterbrechen", um das Programm zu debuggen, oder auf "Weiter", um es zu beenden. Weitere Informationen finden Sie im Hilfethema "Gewusst wie: Debugging von Pufferüberlaufproblemen". Meine Funktionen sehen nun so aus: void printWaveHeaderInfos( WAVEHEADER *hdr) { if(NULL == hdr) { cerr << "Keine Waveheaderinformationen gefunden" << endl; } if(hdr->AudioFormat == 1 && hdr->SampleRate == 44100 && hdr->BitsPerSample == 16 && hdr->NumChannels ==1 ) { cout << "Codec: "; if (hdr->AudioFormat == 1) { cout << "PCM, "; } else { cout << "This is not a PCM file! "; } cout << hdr->SampleRate << " Hz, "; cout << hdr->BitsPerSample << "bit, "; cout << hdr->NumChannels << " channel, "; cout << "Length " << ((hdr->Subchunk2Size * 8.0) / (hdr->BitsPerSample) / (hdr->NumChannels) / (hdr->SampleRate)) << " sec" << endl; } else { cout << "Keine Waveheaderinformationen gefunden"; } // outpout // codec, sampling rate, sampling precision, channels, length } WAVEHEADER *readWaveHeader(ifstream *fin) { WAVEHEADER *hdr = NULL; //benutze die read Funktion um binaere Daten zu lesen hdr = new WAVEHEADER; fin->read((char*)&hdr, sizeof(WAVEHEADER)); /* TODO */ printWaveHeaderInfos(hdr); return hdr; } int main(int argc, char *argv[]){ ifstream fin; fin.open("audio1.wav"); readWaveHeader(&fin); fin.close(); }
Überleg mal was der new operator zurück gibt und danach schau dir nochmal genau die Zeile mit dem read() an. Speicher der mit new alloziert wurde sollte auch irgendwann mit delete wieder freigegeben werden. Ansonsten kommt es zu häßlichen Memoryleaks.
Willkommen in der Programmierung. Jetzt machst du das erste mal Bekanntschaft mit deinem Debugger und seinen Möglichkeiten. Du startest dein Programm jetzt nicht mehr mit F5, sondern mittels F10. F10 führt genau einen Programmschritt aus. Danach kannst du dir zb Variableninhalte ansehen: einfach mit der Maus drauf zeigen. F11 macht etwas ähnliches: es führt einen Programmschritt aus. Der Unterschied zu F10: F10 fasst einen Funktionsaufruf als einen Schritt auf und macht den Schritt über die Funktion hinweg. D.h. F10 meldet sich erst wieder, wenn die Funktion retourniert. F11 hingegen macht einen Programmschritt in die Funktion hinein, so dass du auch dort wieder in Einzelschritten dein Programm durchgehen kannst. Und damit findest du erst mal heraus, WO (bei welcher Anweisung) das Problem entsteht.
So, habe es mir nochmal angeschaut und ein bisschen den Debugger angeschaut, komme aber leider mit dem Debbuger noch nicht zurecht, werde ich noch besser anschauen müssen. Habe jetzt bei noch folgendes verändert: WAVEHEADER *readWaveHeader(ifstream *fin) { WAVEHEADER *hdr = NULL; //benutze die read Funktion um binaere Daten zu lesen hdr = new WAVEHEADER; fin->read((char*)hdr, sizeof(WAVEHEADER)); /* TODO */ if (fin->eof() || fin->fail() || fin->bad()){ WAVEHEADER *hdr = NULL; } printWaveHeaderInfos(hdr); return hdr; delete [] hdr; Bei Read hdr habe ich den Adressoperator weggelassen, am Schluss delete ich nun noch die hdr.
Hans Lüthi schrieb: > am Schluss delete > ich nun noch die hdr. Nö... du löscht die niemals da der Programmfluss dort nie ankommt, sollte dir der Compiler auch anmeckern... Außerdem ist es extrem unklug den Speicher zu löschen wenn du ihn zurückgibst. Hier würde ich lieber einen Autopointer zurückgeben. Außerdem solltest du den Inputstream lieber als Referenz übergeben (wozu der Pointer?) oder wenigsten auf != 0 prüfen...
Habe auch bei Cellier Vorlesung, der TODO Teil den du noch nicht hast bei readWaveHeader sollte so aussehen: if (hdr -> Subchunk1Size != 16 || hdr -> SampleRate != 44100 || hdr -> BitsPerSample != 16 || hdr -> NumChannels !=1) { cout <<"Wrong format!"<< endl; return NULL; } dann else if (fin-> eof( etc. ; return NULL;} und dann else {printWaveHeaderInfos(hdr); return hdr; delete hdr;} Die -totext Option sollte in etwa so aussehen: void convertWaveFile( char infile[], char outfile[] ) { cout << "Trying to convert wavefile to text:" << endl; ifstream fin(infile, ios::in | ios::binary); ofstream fout(outfile); WAVEHEADER *hdr = readWaveHeader(&fin); int samples = hdr -> Subchunk2Size * 8 / hdr ->BitsPerSample / hdr -> NumChannels; for(int i = 0; i<samples ;i++) { short s; fin.read((char*)&s, sizeof(s)); fout <<s<< endl; } cout << "done" << endl; delete hdr; } dann kannst du das erstellte out.txt öffnen, diese Werte in eine Exceltabelle kopieren und als Diagramm anzeigen um zu kontrollieren obs stimmt... Weiter bin ich selbst auch noch nicht, aber schau dir mal die Präsentationen der Assistenten an, hat z.T. gute Hilfe dabei: http://www.inf.ethz.ch/personal/fcellier/Lect/InfI/Ex/Inf1_ex_praes.html
Ist das das was man an der ETH Programmiereinstieg im 1. Semester nennt? WENN ja, da muss ich persönlich sagen, dass C++ und die dürftigen Erklärungen in den Folien didaktisch nicht grad die Höhe sind... da stelle ich mir die Lernkurve schon steil vor, wenn man vorher noch keinen Dunst hatte.
Suri schrieb: > Habe auch bei Cellier Vorlesung, der TODO Teil den du noch nicht hast > bei readWaveHeader sollte so aussehen: Prima, jetzt hat er endlich den Dummen gefunden der ihm die Hausaufgabe macht. Wenn dann in der Klauser ne 5 rauskommt war natürlich der Prof schuld.
Ne 5 is in der Schweiz eine 2... Im übrigen komme ich selbst auch nicht weiter und habe ihm geholfen, weil ich hoffe, dass er jetzt eine gute Idee hat und mir weiterhelfen kann. Nur weil du hier im Internet anonym bist, sind solche Kommentare trotzdem unproduktiv und unerwünscht.
Suri schrieb: > Nur weil du hier im Internet anonym bist, sind solche Kommentare > trotzdem unproduktiv und unerwünscht. 1. Du bist anonym, ich nicht. ich bin nicht als Gast angemeldet. 2. gibt es hier ein von den meisten praktiziertes stilles Übereinkommen, daß man Hilfe zur Selbsthilfe gibt und nicht einfach Leuten die dreist hier ihre Hausaufgaben reinstellen diese macht. 3. Sieh dir an was er selbst gemacht hat. Ich glaube nicht daß du vom ihm irgendeinen Rücklauf bekommst, drücke dir trotzdem die Daumen.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.