Wczytywanie pliku wav do tablicy c++

Odpowiedz Nowy wątek
2016-01-16 11:58

Rejestracja: 4 lata temu

Ostatnio: 4 lata temu

0

Czy jest możliwość wczytania pliku dźwiękowego w formacie wav w taki sposób żeby każdy kanał był w osobnej tablicy. Jeżeli tak to w jaki sposób można to zrobić?
Z góry dziękuję za pomoc :)

Pozostało 580 znaków

2016-01-16 12:02

Rejestracja: 6 lat temu

Ostatnio: 16 godzin temu

1

Jak najbardziej można, zapoznaj się ze specyfikacją formatu http://soundfile.sapp.org/doc/WaveFormat/ i przetraw sobie ten plik odpowiednio.

Pozostało 580 znaków

2016-01-16 13:01

Rejestracja: 16 lat temu

Ostatnio: 17 minut temu

2

ja dodam, że pomiędzy fmt a data mogą się znajdować inne “chunki”, które trzeba przeskoczyć.

długość chunka jest zawsze parzysta: jeśli w polu długości jest liczba nieparzysta, trzeba „zakrąglić w górę” do parzystej; na końcu wtedy jest jeden nieużywany bajt.
https://en.wikipedia.org/wiki/Resource_Interchange_File_Format

poza tym trzeba sprawdzić wartości w fmt, czy jesteśmy w stanie przetrawić dany plik. konkretnie czy AudioFormat jest równe 1, i stosować się do wartości podanych w NumChannels, SampleRate, BlockAlign itd.

Pozostało 580 znaków

2016-01-18 13:47

Rejestracja: 4 lata temu

Ostatnio: 4 lata temu

0

Zrobiłem odczytywanie nagłówka wave. Teraz nie wiem jak czytać kanały do tablicy. Mam to czytać po 4 bajty w pętli czy jak?


#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

int main()
{
 //odczyt nagłówka wave
    typedef unsigned int UINT;
    FILE* fp = fopen("bird2.wav","r");
    if(!fp)
    {
        perror ("ERROR");
    }
    else
    {
        char type[5];
        type[4]='\0';
        unsigned int size,chunkSize,sampleRate,avgBytesPerSec,dataSize=0;
        short formatType,channels,bytesPerSample,bitesPerSample=0;

        fread(type,sizeof(char),4,fp);
        if(memcmp(type,"RIFF",4)!=0)
        {
            perror ("ERROR");
        }
        else
        {
            fread(&size,sizeof(unsigned int),1,fp);

            fread(type,sizeof(char),4,fp);
            if(memcmp(type,"WAVE",4)!=0)
            {
                perror ("ERROR");

            }
            else
            {
                fread(type,sizeof(char),4,fp);
                fread(&chunkSize,sizeof(UINT),1,fp);
                fread(&formatType,sizeof(short),1,fp);          //1 = PCM
                fread(&channels,sizeof(short),1,fp);
                fread(&sampleRate,sizeof(UINT),1,fp);
                fread(&avgBytesPerSec,sizeof(UINT),1,fp);
                fread(&bytesPerSample,sizeof(short),1,fp);
                fread(&bitesPerSample,sizeof(short),1,fp);

                fread(type,sizeof(char),4,fp);
                if(memcmp(type,"data",4)!=0)
                {
                    perror ("ERROR");
                }
                else
                {
                    fread(&dataSize,sizeof(unsigned int),1,fp);

                }
            }
        }
    }
}

Pozostało 580 znaków

2016-01-18 14:10

Rejestracja: 16 lat temu

Ostatnio: 17 minut temu

0

fread(type,sizeof(char),4,fp);
fread(&chunkSize,sizeof(UINT),1,fp);

Nagłówek może mieć różną długość, właśnie ją odczytałeś, ale nie dopilnowujesz by przeczytać tyle ile w pliku podano (z zaokrągleniem w górę do parzystej).

fread(type,sizeof(char),4,fp);
if(memcmp(type,"data",4)!=0)

Jak już wspominałem, przed data mogą być inne “chunki”. Więc jeśli trafiłeś na coś innego niż data, należy odczytać rozmiar, przeskoczyć, i zobaczyć czy następny to nie data. I do skutku (a raczej do końca chunka RIFF).

fread(&formatType,sizeof(short),1,fp); //1 = PCM

Fajnie, tylko przydałoby się sprawdzić to PCM.

Mam to czytać po 4 bajty w pętli czy jak?

Nie cztery, tylko BlockAlign bajtów.

Poza tym sprawdź ile jest kanałów. nie zawsze są dwa. może być jeden (mono), a może być np. sześć (5.1). Bitów na sampel też nie musi być 16, może być 8 albo 24. Możesz oczywiście olać obsługę 8-bitowych plików 5.1 (to byłoby niezłe WTF, ale możliwe), ale mimo wszystko sprawdzaj czy plik jest zjadliwy, bo lepiej wyświetlić błąd niż śmieci (albo wywalić program, a już w ogóle niewybaczalne jest puścić jakieś śmieci w złym formacie na głośniki).

W standardowym 16-bitowym PCM stereo będziesz miał cztery bajty - dwie liczby short, jedna na lewy kanał druga na prawy (nie pamiętam kolejności).

Tu masz przykład rzeczywistego nagłówka pliku WAV. twój program powinien takie coś być w stanei przemielić i znaleźć dane, nawet jeśli akurat 5.1 cię nie interesuje:
http://www.jensign.com/multichannel/multichannelformat.html

I pamiętaj że na końcu pliku też mogą być dodatkowe rzeczy. Dlatego nie czytaj danych do końca pliku, a tylko tyle, ile masz wskazane w rozmiarze chunka data.

EDIT: wyczytałem że formatType równe 1 dopuszcza tylko jeden albo dwa kanały i max 16 bitów. Więcej kanałów wymaga innej wartości, nawet jeśli to jest PCM. Więc zacznij od sprawdzenia tego pola.
Wtedy też nagłówek (fmt) jest krótki, bez dodatkowych pól na końcu. Ale i tak bym - dla zasady - przestrzegał podanego rozmiaru chunka.

edytowany 6x, ostatnio: Azarien, 2016-01-18 14:44
Pokaż pozostałe 8 komentarzy
no i akurat te niezgodne ze specyfikacją są oznaczone gwiazdką i dopiskiem "will not play with Windows Media Player"... ciekawe dlaczego :) - Azarien 2016-01-20 19:53
obsługę (odczyt) takich plików można we własnym programie zaimplementować. zapisywać nowe pliki powinno się zgodnie ze specyfikacją. - Azarien 2016-01-20 19:55
Nie wiem jak twój WMP, ale mój odtwarza ;) - _0x666_ 2016-01-20 20:01
Jeszcze dodam cytat z dokumentacji: "To describe a PCM format for which the number of valid bits per sample is less than the sample container size (for example, a 20-bit sample stored in a three-byte container) requires WAVEFORMATEXTENSIBLE, which specifies both the number of valid sample bits and the sample container size." Zatem dla 24 bitów nie muszę używać WAVEFORMATEXTENSIBLE, ponieważ "container size" jest dokładnie taki sam jak rozmiar próbki. Mam nadzieję, że to rozwiało wątpliwości. - _0x666_ 2016-01-21 11:14
nie rozwiało, bo wątpliwości nie ma: dokumentacja WAVEFORMATEX wyraźnie pisze o mono/stereo i 8/16 bitach, a dokumentacja WAVEFORMATEXTENSIBLE defines the format of waveform-audio data for formats having more than two channels or higher sample resolutions than allowed by WAVEFORMATEX. pliki wave które się z tego wyłamują są niestandardowe. - Azarien 2016-01-21 11:19

Pozostało 580 znaków

2016-01-19 16:00

Rejestracja: 8 lat temu

Ostatnio: 2 tygodnie temu

0

Ja używam do tego biblioteki bass.
http://pastebin.com/UH1FQGwu
Dokładniej zainteresuj się funkcją UpdateSpectrum z przykładu, a jeszcze dokładniej BASS_ChannelGetData().

Pozostało 580 znaków

2016-01-20 10:49

Rejestracja: 14 lat temu

Ostatnio: 22 godziny temu

1

Temat czytania plików WAV był wielokrotnie poruszany. Tu masz kod poprawnie czytający ten format -> http://4programmers.net/Forum/1113605

Pozostało 580 znaków

Odpowiedz

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0