Wave (*.wav) Bibliothek/Funktion



  • Hallo,

    In der Wikipedia heißt es:

    Audiodateien enthalten die digitalisierte Form eines akustischen Signals, also eine diskrete Darstellung des zeitlichen Verlaufs einer Schwingung. Es wird zu bestimmten Zeitpunkten die Auslenkung (Elongation) einer Schwingung festgehalten.

    Ich suche eine Bibliothek/Funktion oder was auch immer, mit der ich also die Elongation der in einer beliebigen *.wav-Datei gespeicherten Schwingung zu einer beliebigen Zeit auslesen kann. Falls das aus der Beschreibung der Dateistruktur in der Wikipedia hervorgeht, sorry, aber den Abschnitt habe ich nicht wirklich verstanden.

    Vielen Dank schonmal

    Felix



  • Was ich also im Prinzip suche ist folgendes:

    #include "WavLibrary"
    int main(void)
    {
        WavDatei theFile("Test.wav");
        double elong = theFile.elongation(3.0);
    }
    

    bzw.

    #include "WavLibrary"
    int main(void)
    {
        WavDatei theFile("Test.wav");
        vector<double> theVector;
        double SamplingRate = theFile.fillVector(theVector);
    }
    

    Im ersten Beispiel soll dann in elong die Elongation der gespeicherten Schwingung zur Zeit 3.0 (Sekunden oder was auch immer) nach Anfang der Datei, bzw. 3 SamplingRaten nach Anfang der Datei sein. Im zweiten Beispiel sollte die Sampling Rate dann in SamplingRate stehen und der Vektor mit den ganzen Elongationen gespeichert sein, wobei theVektor[0] der Elongation zur ersten SamplingZeit, theVektor[1] der Elongation zur 2. Sampling Zeit entspricht usw.

    Es würde auch reichen, wenn mir jemand erklären würde, was im Wikipedia Artikel mit Chunk und diesen Sachen gemeint ist.



  • Schau dir mal libsndfile an. Ist ne recht schlanke API.



  • Danke für den Tipp,

    ich habe mir mal libsndfile runtergeladen, das scheint auch genau das zu sein, was ich brauche, alerdings habe ich jetzt ein anderes Problem:

    Ich arbeite unter Windows mit CodeBlocks und dem Gnu GCC Compiler, ich habe halt nur noch nie was mit anderen Bibliotheken als der Standardbibliothek gemacht...

    Kennst dich vielleicht jemand damit aus, was ich da einstellen muss...

    Aus der Dokumentation werde ich in Bezug auf das Kompilieren auch nicht viel schlauer. Da steht nur

    You can use libsndfile with Free Software, Open Source, proprietary, shareware or other closed source applications as long as libsndfile is used as a dynamically loaded library and you abide by a small number of other conditions (read the LGPL for more info). With applications released under the GNU GPL you can also use libsndfile statically linked to your application.

    Also müsste ich es auch statisch gelinkt verwenden können, falls das (hoffentlich) irgendwie einfacher ist, weil das nur ein Schul-Projekt ist.

    Schonmal danke...

    Felix



  • Du kannst ja erstmal den Header einlesen, der fängt mit "RIFF" und "WAVE" an und so und in dem stehen die Länge, Anzahl der Kanäle, SamplingRate, und Auflösung (bps).

    Und im Datenteil ist der Krempel einfach aneinandergereiht.

    Bei 8 Bit mono dann halt

    S1 S2 S3 S4 S5 ... (S1 = sample eins, mit sizeof == 1 Byte (8 Bit))

    Bei 16 Bit stereo dann halt

    S1LL S1LH S1RL S1RH S2LL S2LH S2RL ... (S1LL = sample eins, left channel, low-teil -- zusammen mit dem High-Teil dann 2 Byte (16 Bit) pro Kanal)

    Ansonsten halt google. Bei Wikipedia steht unter WAV oder WAVE bestimmt auch noch was.



  • Sgt. Nukem hat den Finger ziemlich genau drauf:

    Hier findest du den Aufbau einer Wave Datei.

    in c habe ich das so gemacht

    typedef struct tagWAVEHEADER
    {
    	char Riff[4];			/*Muss "RIFF" sein*/
    	DWORD FileSize;		/*Groese der Datei minus 8 Bytes*/
    
    	char Wave[4];			/*Muss "WAVE" sein*/
    
    	char Fmt[4];			/*Muss "fmt " sein*/
    	DWORD HeaderSize;		/*Muss 16 betragen*/
    	WORD PCM;				/*Sollte 1 sein für wirklich unkomprimiete PCM Dateien*/
    	WORD Channels;			/*Anzahl Kanaele*/
    	DWORD Samplingrate;	/*Anzahl Amplitudenwerte pro Sekunde (zB 22050,44100)*/
    	DWORD Average;		/*Durchschnittle Datenbytes pro Sekunde. Bei Wave uninteressant*/
    	WORD BlockAlignment;
    	WORD BpS;				/*Bits pro Abtastwert (8 oder 16)*/
    
    	char Data[4];			/*MUSS "data" sein*/
    	DWORD DataSize;		/*Groesse der Datei ohne Header*/
    
    }WAVEHEADER,*PWAVEHEADER;
    
    PWAVEHEADER staslReadWaveFile(const char * szFileName)
    {
    	PWAVEHEADER pret = (PWAVEHEADER) malloc(sizeof(WAVEHEADER));
    	FILE * fp = fopen(szFileName,"rb");
    
    	fread(pret->Riff, sizeof(char), 4, fp);
    	if(!strcmp((pret->Riff),"RIFF"+'\0'))
    		return 0;
    
    	fread(&(pret->FileSize),sizeof(DWORD),1,fp);
    
    	fread(&(pret->Wave),sizeof(char),4,fp);
    	if(!strcmp("WAVE",(pret->Wave)))
    		return 0;
    
    	fread(&(pret->Fmt),sizeof(char),4,fp);
    	if(!strcmp("Fmt ",(pret->Fmt)))
    		return 0;
    
    	fread(&(pret->HeaderSize),sizeof(DWORD),1,fp);
    	fread(&(pret->PCM),sizeof(WORD),1,fp);
    	fread(&(pret->Channels),sizeof(WORD),1,fp);
    	fread(&(pret->Samplingrate),sizeof(DWORD),1,fp);
    	fread(&(pret->Average),sizeof(DWORD),1,fp);
    	fread(&(pret->BlockAlignment),sizeof(WORD),1,fp);
    	fread(&(pret->BpS),sizeof(WORD),1,fp);
    
    	fread(&(pret->Data),sizeof(char),4,fp);
    	fread(&(pret->DataSize),sizeof(DWORD),1,fp);
    	fclose(fp);
    	return pret;
    }
    
    void staslFreeWave(PWAVEHEADER pWaveHeader)
    {
       free(pWaveHeader);
    }
    

    das ist jetzt zumindest ein guter anfang. das ding liest schon den Header ein. Den rest kann ich dir jetzt nicht posten, da der in der Schule liegt und ich es verpeilt habe mir das ding mitzunehmen.
    Aber du willst ja auch noch was machen 😃
    Du musst jetzt nur noch die daten einlesen. Heraus kommen lauter Bytes. Diese kannst du dann mittels FourierAnalyse weiter verwenden und du kriegst, wenn cih das verstanden habe, die Frequenz und die Elongation.
    Wie das mit der fourieranalyse funzt kann ich dir nicht sagen, ich weiß gerademal seit gestern das es das gibt 😮 😮



  • Ohh habe vergessen dir den Link zu posten, da ist er nun:
    http://www.ringthis.com/dev/wave_format.htm

    Und die Strings sind alle NICHT NULLTERMINIERT, deswegen habe cih bei dem strcmp(...+'\0'); geschrieben.
    Es funktioniert zwar auch ohne aber ich weiß nicht warum.
    Kann mir das jemand sagen?
    Mein Lehrer meinte es müsse nicht immer funktionieren 😕



  • So, danke nochmal für das bisherige. Ich habe jetzt folgendes gemacht:

    #include <windows.h>
    #include <string>
    #include <exception>
    
    //16 bit mono
    class WavDatei
    {
        private:
        WORD Channels;            /*Anzahl Kanaele*/
        DWORD Samplingrate;    /*Anzahl Amplitudenwerte pro Sekunde (zB 22050,44100)*/
        WORD BpS;                /*Bits pro Abtastwert (8 oder 16)*/
        FILE *datei;
        public:
        WavDatei(const std::string &);
        ~WavDatei(void);
        WORD GetChannels(void);
        DWORD GetSamplingRate(void);
        double ReadNextValue(void);
    };
    
    class WavException : public std::exception
    {
        private:
        std::string text_;
        public:
        WavException(const std::string &);
        virtual ~WavException(void) throw();
        virtual const char *what() const throw();
    };
    
    #include "wav.h"
    #include <cstdio>
    using namespace std;
    
    WavException::WavException(const std::string &text) : exception()
    {
        text_ = text;
    }
    
    WavException::~WavException(void) throw()
    {
    }
    
    const char *WavException::what() const throw()
    {
        return text_.c_str();
    }
    
    WavDatei::WavDatei(const string &name)
    {
        datei = fopen(name.c_str(),"rb");
        if(!datei)
        {
            throw WavException("Datei ist keine Wav-Datei!");
        }
        char Riff[5];
        Riff[4] = '\0';
        fread(Riff, sizeof(char), 4, datei);
        if(strcmp(Riff,"RIFF"))
        {
            throw WavException("Datei ist keine Wav-Datei!");
        }
        DWORD FileSize;
        fread(&FileSize,sizeof(DWORD),1,datei);
        char Wave[5];
        Wave[4] = '\0';
        fread(Wave,sizeof(char),4,datei);
        if(strcmp(Wave,"WAVE"))
        {
            throw WavException("Datei ist keine Wav-Datei!");
        }
        char Fmt[5];
        Fmt[4] = '\0';
        fread(Fmt,sizeof(char),4,datei);
        if(strcmp(Fmt, "Fmt "))
        {
            throw WavException("Datei ist keine Wav-Datei!");
        }
        DWORD HeaderSize;
        fread(&HeaderSize,sizeof(DWORD),1,datei);
        WORD PCM;
        fread(&PCM,sizeof(WORD),1,datei);
        fread(&Channels,sizeof(WORD),1,datei);
        fread(&Samplingrate,sizeof(DWORD),1,datei);
        DWORD Average;
        fread(&Average,sizeof(DWORD),1,datei);
        WORD BlockAlignment;
        fread(&BlockAlignment,sizeof(WORD),1,datei);
        fread(&BpS,sizeof(WORD),1,datei);
        char Data[5];
        Data[4] = '\0';
        fread(Data,sizeof(char),4,datei);
        DWORD DataSize;
        fread(&DataSize,sizeof(DWORD),1,datei);
    }
    
    WavDatei::~WavDatei(void)
    {
       free(datei);
    }
    
    WORD WavDatei::GetChannels(void)
    {
        return Channels;
    }
    
    DWORD WavDatei::GetSamplingRate(void)
    {
        return Samplingrate;
    }
    
    int WavDatei::ReadNextValue(void)
    {
        //Was kommt hier hin?
    }
    

    Jetzt bleiben noch ein paar Fragen:

    1. DWORD ist ja praktisch das gleiche wie unsigned int. Ist dann WORD das gleiche wie unsigned short??

    2. Wie lese ich jetzt genau nacheinander die gesampelten Elongationen aus? Die sind ja irgendwie nach dem Little-Endian-Standard gespeichert, d.h. man kann die nicht einfach mit

    fread(&var,sizeof(int),1,datei);
    

    auslesen. Wie macht man das dann? Ich will nur Wav-Dateien verwenden, die 16 Bit und Mono sind, falls es das einfacher macht.

    Nochmal Danke im Voraus (nur ein r 🤡 ) und sorry, dass ich das nicht so ganz verstehe...

    Felix

    P.S: Das mit der Fourier-Analyse ist ja das Eigentliche, was ich machen will, nur muss ich halt dafür die dumme Wav-Datei auslesen...



  • Bis auf das sizeof(int) habe ich das so gemacht. verwende statt int, char oder byte. Und statt der Anzahl 1 setzt du halt Datasize, was du ja aus dem Header entnommen hast.
    Dann hast du halt viele Bytes. Die müsstest du dann mit der FourierAnalyse weiterverabeiten.

    mfg



  • Phoemuex schrieb:

    2. Wie lese ich jetzt genau nacheinander die gesampelten Elongationen aus? Die sind ja irgendwie nach dem Little-Endian-Standard gespeichert, d.h. man kann die nicht einfach mit

    fread(&var,sizeof(int),1,datei);
    

    auslesen.

    if(sex == LITTLE_ENDIAN)
    {
        fread(&bytelow,  1, 1, datei);
        fread(&bytehigh, 1, 1, datei);
    }
    else
    {
        fread(&bytehigh, 1, 1, datei);
        fread(&bytelow,  1, 1, datei);
    }
    WORD DoubleByte = (bytehigh << 8) | bytelow;
    

    So ungefähr...




Anmelden zum Antworten