Avatar billede Panum Nybegynder
02. august 2011 - 00:07 Der er 4 kommentarer

Indlæsning af PCM data (.WAV)

Hejsa,

Jeg står i den situation, at jeg prøver at læse selve lyd-dataen fra en .WAV-fil (bedre kendt som PCM data). Jeg er udemærket klarover at ikke alle WAV-filer er ens, men er 100% sikker på den jeg har brugt af, følger strukturen beskrevet her: https://ccrma.stanford.edu/courses/422/projects/WaveFormat/

Mit problem er i at når jeg læser samples (som i følge den linkede hjemmeside) er signed ints, og jegprøver at bruge .read() på min .wav fil, får jeg umildbart ikke nogle tal som giver mening.

Har også kigget her: http://princessblade.net/SmallHost/CWaveFile_Information.html

Hvor der påståes at der skal bruges short ints (grundet 16-bit), men intet giver det ønskede billede eller det rigtige output af waveformen :(

Her er min wavfil.cpp klasse:

[code]
#include <fstream>
#include <math.h>
#include <string>
#include <algorithm>

using namespace std;

class wavfile {
string path;
unsigned int bitsPerSample, sampleRate, filesize, bytesPerSecond, filelength;
fstream file;
float* samples;
public:
wavfile (string);
unsigned int bitspersample ();
unsigned int samplerate ();
unsigned int size ();
unsigned int length ();
unsigned int byterate ();
private:
void instantiate ();
void sampleArray (int, int);



};

wavfile::wavfile(const string p){
    path = p;
    wavfile::instantiate();
}

void wavfile::instantiate(){
            file.open(path.c_str(), ios::in|ios::binary);
            file.seekg(0, ios::end);
           
            filesize = (int) file.tellg();
           
            file.seekg(24, ios::beg);
            file.read ((char *)&sampleRate, sizeof(sampleRate));
           
            file.seekg(34, ios::beg);
            bitsPerSample = (unsigned int) file.get();
           
            file.seekg (28, ios::beg);
            file.read ((char *)&bytesPerSecond, sizeof(bytesPerSecond));
           
            filelength = ceil((double )(filesize-44)/ (double) bytesPerSecond);
           
           
            samples = new float[300];
           
            sampleArray(300, 256);
           
            for(unsigned int i = 0; i < 300; i++){
                            cout << samples[i] << endl;
                        }   
           
       
}

unsigned int wavfile::bitspersample(){
    return bitsPerSample;
}
unsigned int wavfile::samplerate(){
    return sampleRate;
}
unsigned int wavfile::size(){
    return filesize;
}
unsigned int wavfile::length(){
    return filelength;
}
unsigned int wavfile::byterate(){
    return bytesPerSecond;
}
void wavfile::sampleArray(int amount, int precision){
   
    //Sikre at hvert skridt er et multiplicit af 4, sådan så vi rammer et sample (og ikke lander midt i ét)
    unsigned int steplength = (((filesize-44) / (amount*precision))/4)*4;
   
    unsigned int stepAmount = amount*precision;
   
    unsigned int counter = 0;
    int pcounter = 1;
    int currentValue = 0;
    for(unsigned int i = 0; i < stepAmount; i++){
        file.seekg(44+(i*steplength), ios::beg);
       
        short int left;
        short int right;
       
        file.read ((char *)&left, 2);
        file.read ((char *)&right, 2);
       
        int tempValue = max(left, right);
       
           
        if(tempValue > currentValue){
                    currentValue = tempValue;
        }
               
        if(pcounter ==  precision){
                   
       
                    samples[counter] = (float) currentValue / (float) 32767;
                    pcounter = 1;
                    counter++;
                } else {
                    pcounter++;
                }
       
    }
   
   
   
}



[/code]
Avatar billede bertelbrander Praktikant
02. august 2011 - 01:09 #1
Jeg tror du skal starte med at fortælle os hvad det er du forsøger at gøre i wavfile::sampleArray. jeg forstår ikke rigtigt hvad denne linje skal gøre:
unsigned int steplength = (((filesize-44) / (amount*precision))/4)*4;

Hvis filen ikke er ret stor, bliver steplength 0
Avatar billede Panum Nybegynder
02. august 2011 - 01:47 #2
Hej,

Ja, det er klart. Men diverse checks bliver lavet senere, det er som sagt bare en skits til et færdigt program.

Håbede at kommentare kunne forklare det, men så prøver jeg lidt mere uddybende:

(filesize-44) -> Den aktuelle størrelse af selve dataen (uden diverse chunks).

(amount*precision) -> Hvor mange samples der skal benyttes.


2-kanals PCM data er struktureret således:  (L -> Left channel, R -> Right channel)

            L        L            R              R            L        L

Byte    44      45          46          47          48      49  ... osv.

Et sampel består af 4 bytes (LL + RR). Hvert sample starter på 44 + (4 * n)    n = {0, 1, 2 ... }

Det er det som steplength sikre (ie, sådan vi ikke hopper ind på en adresse, hvor vi lander midt i et sample)

Hele mit problem er at jeg ikke har verdens største erfaring med C++ og indlæsningen af binære ting. Synes bare jeg har prøvet så mange ting, så nu måtte jeg prøve at skrive her.
Avatar billede bertelbrander Praktikant
02. august 2011 - 02:02 #3
Umiddelbart tror jeg at du læser rigtigt.
Du skal checke at steplength ikke bliver 0, for så vil du læse den første sample hver eneste gang.

Men prøv at udskrive værdierne på de samples du læser ind, så du kan se om du læser rigtigt.
Avatar billede Michael Johansen Nybegynder
30. august 2011 - 15:35 #4
Hvis du koder på windows, så kan det anbefales at bruge mmio-funktionerne til det:
http://www.bcbjournal.com/articles/vol2/9807/Low-level_wave_audio__Part_I.htm
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester