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.