Odczyt .wav

0

Witam, cos nie moge odtworzyc .wav
Co robie nie tak ;< ?

FILE  *wavFile;
              wavFile = fopen(FileDialog1->GetPath(), "rb");   
              if( wavFile == NULL )
              {
              
              }
              else
              {



                typedef struct  WAV_HEADER{
    char                RIFF[4];       
    unsigned long       ChunkSize;      
    char                WAVE[4];        
    char                fmt[4];        
    unsigned long       Subchunk1Size; 
    unsigned short      AudioFormat;    
    unsigned short      NumOfChan;      
    unsigned long       SamplesPerSec;  
    unsigned long       BytesPerSec;    
    unsigned short      BlockAlign;    
    unsigned short      BitsPerSample;  
    char                Subchunk2ID[4]; 
    unsigned long       Subchunk2Size;  

                                            }wav_hdr;

                    wav_hdr wavHeader;
                    int headerSize = sizeof(wav_hdr),filelength = 0;
                    fread(&wavHeader,headerSize,1,wavFile);
                    fclose(wavFile);


SAMPLE_RATE = wavHeader.SamplesPerSec;
NUM_CHANNELS = wavHeader.NumOfChan; 

data.frameIndex = 0;
numSamples = ((8 * wavHeader.Subchunk2Size)/wavHeader.BitsPerSample  );
totalFrames = (numSamples / NUM_CHANNELS);
NUM_SECONDS = (totalFrames / SAMPLE_RATE);


fread( data.recordedSamples, wavHeader.Subchunk2Size, totalFrames, wavFile );
                fclose( wavFile );
1

Jaki konkretnie jest problem?

Czy przed odczytem pliku, wskaźnik data.recordedSamples wskazuje na przydzieloną tablicę o wielkości przynajmniej taką, jak wavHeader.Subchunk2Size*totalFrames? Najpierw należy przydzielić pamięć za pomoca malloc (C) lub new (C++), a dopiero potem odczytać dane wpisując je do tej tablicy.

W Twoim kodzie nie widzę momentu przydzielenia pamięci do tablicy pod wskaźnikiem data.recordedSamples.

0

dodałem, ale dalej nie działa ;<

numBytes = numSamples * sizeof(SAMPLE);
if( data.recordedSamples != nullptr )
                free(data.recordedSamples);
                data.recordedSamples = (SAMPLE *) malloc( numBytes );

kompiluje się ale dźwięk jaki odtwarza to jakis szmer(bardziej pyknięcie) i koniec

1

Ale tak nie można. WAV nie ma takiego nagłówka. Poczytaj o formacie RIFF i jak go należy analizować.

0

jak nie ma ;O
jak ja tak zapisałem http://4programmers.net/Forum/C_i_C++/247224-wav_zapis_probek_audio
to co teraz robię to całkowicie nie ma sensu ?

1

jak nie ma ;O

znajdź specyfikację formatu WAV i się do niej stosuj. przykładowo, pomiędzy chunkiem fmt a data może istnieć nieokreślona liczba chunków z metadanymi.
do tego nigdzie nie sprawdzasz pola AudioFormat. a co jeśli WAV jest skompresowany i zawiera strumień np. mp3? oczywiście możesz takiego wave'a odrzucić i obsługiwać tylko nieskompresowane, ale wypadałoby sprawdzać wartość pola i odrzucić taki plik, a nie na siłę z niego czytać.

jak ja tak zapisałem
zależy czy program ma obsługiwać prawdziwe wave'y wygenerowane dowolnym programem zapisującym wave'y, czy tylko pliki wave'opodobne wygenerowane wyłącznie twoim programem z tamtego wątka.

plik WAV jest szczególnym przypadkiem pliku RIFF. to coś jakby binarny XML. nie można takiego pliku traktować jako nagłówek+dane, powinno się analizować dane na poziomie RIFF.

0

o kurczę...
To może najpierw zrobię to ,żeby czytał te wave'opodobne wygenerowane wyłącznie z mojego programu.
A później zajmę się prawidłowym zapisywaniem, odczytywaniem normalnego wave. Dziękuje bardzo za zwrócenie uwgai
W takim razie w tym zapisie do odczytania "mojego wave" (kod powyżej) co jest nie tak ?

2

Tu masz kod czytający poprawnie plik wav:

ifstream is("d:\\plik.wav", ios_base::binary);

char		sign[4];
uint32_t	chunk_size;

is.read(sign, 4).read((char*)&chunk_size, 4);
if(memcmp(sign, "RIFF", 4) != 0) return -1;
is.read(sign, 4);
if(memcmp(sign, "WAVE", 4) != 0) return -1;

while( is.read(sign, 4).read((char*)&chunk_size, 4) )
{
	if(memcmp(sign, "fmt ", 4) == 0)
	{
		vector<char> fmt(chunk_size, 0);
		is.read(&fmt.front(), chunk_size);

		WAVEFORMATEX *pwf = (WAVEFORMATEX*)&fmt.front();
		if(pwf->wFormatTag != WAVE_FORMAT_PCM && pwf->wFormatTag != 3 /* WAVE_FORMAT_IEEE_FLOAT */)
		{
			/* prawdopodobnie kompresja */
			return -1;
		}

		/* tu czytasz parametry z pwf do swoich zmiennych */

		continue;
	}


	if(memcmp(sign, "data", 4) == 0)
	{
		/* tu czytasz 'chunk_size' bajtów próbek */

		break;
	}

	is.seekg(chunk_size, ios::cur); // resztę bloków pomijamy
}

return is ? 0 : -1;

return -1 znaczy że jest błąd i powinieneś przerwać procedurę czytania. Sam sobie dorób odpowiednią obsługę błędów.

0

dziękuje, returny już sobie pozmieniałem, ale
/* tu czytasz parametry z pwf do swoich zmiennych */
hm, mam pobierać tak jak robiłem tam wyżej ? czyli muszę tą strukture dać ?

1

Rób jak Ci wygodnie.

0

hmm to będzie bez sesnu jak zrobie tak samo, jak wcześniej, bo znow to będzie statyczne i odczyta tylko moje nagrania czy nie ?

moze inaczej jak czytac z pwf ?
/* tu czytasz parametry z pwf do swoich zmiennych */

1

Nie rozumiem o co Ci chodzi. W pwf masz wszystkie niezbędne parametry, które będziesz musiał podać funkcji Pa_OpenStream, żeby otworzyć dźwięk zapisany w pliku. W przypadku liczby kanałów i częstotliwości sprawa jest jasna, w przypadku ilości bitów powinieneś zrobić tak:

PaSampleFormat smp_format = 0;
...

if(pwf->wFormatTag == WAVE_FORMAT_PCM)
{
	switch(pwf->wBitsPerSample)
	{
	case 8:  smp_format = paUInt8 ; break;
	case 16: smp_format = paInt16; break;
	case 24: smp_format = paInt24; break;
	case 32: smp_format = paInt32; break;
	};
}	
else smp_format = paFloat32; 

Jeszcze jedno: w WAVEFORMATEX masz pole nBlockAlign, które mówi o wielkości jednej ramki/próbki. Przy pomocy tej wartości możesz wyliczyć ile próbek masz w bloku data

0

oo chodziło mi o to
pwf->wBitsPerSample
ze nie znam tyh nazw pól (jak ,wBitsPerSample ,nBlockAlign)
ale już okej

typedef struct {
  WORD  wFormatTag;
  WORD  nChannels;
  DWORD nSamplesPerSec;
  DWORD nAvgBytesPerSec;
  WORD  nBlockAlign;
  WORD  wBitsPerSample;
  WORD  cbSize;
} WAVEFORMATEX;
0
0x666 napisał(a):

Jeszcze jedno: w WAVEFORMATEX masz pole nBlockAlign, które mówi o wielkości jednej ramki/próbki. Przy pomocy tej wartości możesz wyliczyć ile próbek masz w bloku data

czyli >

unsigned short      BlockAlign;
...
BlockAlign = pwf->nBlockAlign;
                numSamples = ((8 * chunk_size)/BitsPerSample  );
                totalFrames = (numSamples / al.NUM_CHANNELS);

lub mogę od razu

    totalFrames = (chunk_size/BlockAlgin);

teraz żeby to dało się odtworzyć muszę przydzielić pamięć

   numBytes = numSamples * sizeof(SAMPLE);
                if( data.recordedSamples != nullptr )
                free(data.recordedSamples);
                data.recordedSamples = (SAMPLE *) malloc( numBytes );

                fread( data.recordedSamples, al.NUM_CHANNELS * sizeof(SAMPLE), totalFrames, wavFile );
                fclose( wavFile );

i tu muszę zastapic SAMPLE , hmm ale czym

1

i tu muszę zastapic SAMPLE , hmm ale czym

Niczym. SAMPLE nie ma tutaj zastosowania. Nie musisz liczyć numBytes, wystarczy, że weźmiesz rozmiar bloku 'data' (chunk_size).

0

próbowałem coś takeigo, ale nic nie daje

char*           Buffer = NULL;
Buffer = new char [chunk_size];
fread( Buffer, chunk_size, totalFrames, wavFile );
fclose( wavFile );
delete[] Buffer;
1

W jakim sensie "nic nie daje"?

0

nie odczytuje tego ;< wgl nie wczytuje tego pliku, jest tylko szmer, a wczytuje dobrze bo jak daje

 numBytes = numSamples * sizeof(SAMPLE);
                if( data.recordedSamples != nullptr )
                free(data.recordedSamples);
                data.recordedSamples = (SAMPLE *) malloc( numBytes );
 
                fread( data.recordedSamples, al.NUM_CHANNELS * sizeof(SAMPLE), totalFrames, wavFile );
                fclose( wavFile );

to odczytuje(oczywiscie jesli wczeniej nacisne start), ( no i tylko tyle sekund ile nagrywalem)

0

Jeśli tworzysz bufor, wczytujesz do niego dane, po czym go usuwasz (delete[] Buffer;), to czego innego się spodziewasz niż "szmer"? (w sumie to i tak sukces)

0

jak to pominę delete[] Buffer;
to i tak nic sie nie dzieje jesli probuje wczytac to nic nie ma...
a jak biore start , a nastepnie wczytaj, to nic sie nie dzieje dalej (ta nagrana probka) sie odtwarza

0

A przypisałeś chociaż ten nowy bufor do data.recordedSamples?

Trudno powiedzieć, co jest problemem, bo nie wiem, jak ten twój kod teraz wygląda. Są jakieś skrawki, z których niewiele wynika. Dostałeś ode mnie kod czytający wavy z wykorzystaniem strumienia ifstream, a z tego co widzę cały czas używasz strumieni z C. Więc nie wiem, w jaki sposób i czy w ogóle poprawnie czytasz plik.

0

ifstream is(FileDialog1->GetPath(), ios_base::binary);

char        sign[4];
uint32_t    chunk_size;
unsigned short      BitsPerSample;
unsigned long       SamplesPerSec;
//unsigned short      BlockAlign; //
smp_format = 0;

is.read(sign, 4).read((char*)&chunk_size, 4);
if(memcmp(sign, "RIFF", 4) != 0)
{
    wxString msg = "Nie moge odtworzyć pliku ";
    wxMessageBox(msg, _("Aplikacja"));

}
is.read(sign, 4);
if(memcmp(sign, "WAVE", 4) != 0)
{
    wxString msg = "Nie moge odtworzyć pliku ";
    wxMessageBox(msg, _("Aplikacja"));

}

while( is.read(sign, 4).read((char*)&chunk_size, 4) )
{
    if(memcmp(sign, "fmt ", 4) == 0)
    {
        vector<char> fmt(chunk_size, 0);
        is.read(&fmt.front(), chunk_size);

        WAVEFORMATEX *pwf = (WAVEFORMATEX*)&fmt.front();
        if(pwf->wFormatTag != WAVE_FORMAT_PCM && pwf->wFormatTag != 3 /* WAVE_FORMAT_IEEE_FLOAT */)
        {
            /* prawdopodobnie kompresja */
            wxString msg = "Nie moge odtworzyć pliku ";
            wxMessageBox(msg, _("Aplikacja"));

        }

        /* tu czytasz parametry z pwf do swoich zmiennych */

        if(pwf->wFormatTag == WAVE_FORMAT_PCM)
        {
            switch(pwf->wBitsPerSample)
            {
                case 8:  smp_format = paUInt8 ; break;
                case 16: smp_format = paInt16; break;
                case 24: smp_format = paInt24; break;
                case 32: smp_format = paInt32; break;
            };
        }
            else smp_format = paFloat32;

        al.NUM_CHANNELS = pwf->nChannels ;
        da.SAMPLE_RATE = pwf->nSamplesPerSec;
   //      pwf->nAvgBytesPerSec;
  //     BlockAlign = pwf->nBlockAlign;   //
        SamplesPerSec = pwf->nSamplesPerSec;
        BitsPerSample = pwf->wBitsPerSample;




        continue;
    }


    if(memcmp(sign, "data", 4) == 0)
    {
        /* tu czytasz 'chunk_size' bajtów próbek */

        break;
    }

    is.seekg(chunk_size, ios::cur); // resztę bloków pomijamy
}

                data.frameIndex = 0;
                numSamples = ((8 * chunk_size)/BitsPerSample  );
                totalFrames = (numSamples / al.NUM_CHANNELS);
            //    totalFrames = (chunk_size/BlockAlgin);         //-> 2 mozliwosc
                da.NUM_SECONDS = (totalFrames / da.SAMPLE_RATE);


/// mysle nad tym
                //numBytes = numSamples * sizeof(SAMPLE);
               // if( data.recordedSamples != nullptr )
              //  free(data.recordedSamples);
              
                    
                //    numBytes = chunk_size;
                 //   data.recordedSamples = (SAMPLE *) malloc( numBytes );
                  //    unsigned int    BufferSize = 0;
                       char*           Buffer = NULL;
                      Buffer = new char [chunk_size];
                      char* buffer = new char[chunk_size];
                       fread( Buffer, chunk_size, totalFrames, wavFile );
              //  data.recordedSamples = (SAMPLE *) chunk_size;
               // fread( data.recordedSamples, chunk_size, totalFrames, wavFile );
              //  fread( data.recordedSamples, al.NUM_CHANNELS * sizeof(SAMPLE), totalFrames, wavFile );
                    fclose( wavFile );
1

Kompletnie nie zrozumiałeś kodu, który dostałeś. Jakim cudem to miało działać?! Tam gdzie miałeś czytać dane nic nie wstałeś, z kolei na końcu dodałeś jakieś śmieci. Jeśli czytasz strumieniem ifstream, to nie czytasz z niego funkcją fread, bo to funkcja z innego strumienia. Zamieniłeś returny na messageboxy, problem w tym, że to kompletnie usunęło obsługę błędów - już przy pierwszym warunku kod, poza komunikatem, leci dalej, a powinien przerwać czytanie pliku! Po to tam były te returny.

Niestety zabrałeś się za coś, co wymaga przynajmniej solidnego opanowania podstaw języka.

Tu masz przykład czytania próbek do bufora:

if(memcmp(sign, "data", 4) == 0)
{
	delete[] data.recordedSamples;
	data.recordedSamples = new char[chunk_size];
	is.read(data.recordedSamples, chunk_size);
	totalFrames = chunk_size / BlockAlign;
	break;
}
0

ajaj
przy

data.recordedSamples = new char[chunk_size];

wyskakuje
error: cannot convert 'char*' to 'SAMPLE* {aka short int*}' in assignment|

wychodzi na to, że musi być 1data.recordedSamples =(SAMPLE *) chunk_size; ` ??

1

Rzutuj na SAMPLE*.

0

tam gdzię miałem komunikaty dodałem return; (i wczytujac plik, (zwykly tekstowy z ustawionym rozszerzeniem .wav elegancko wyskakuje jednokrotnie powiadomienie bez wysypywania się programu)

        delete[] data.recordedSamples;
        data.recordedSamples = (SAMPLE *) chunk_size;
        is.read(data.recordedSamples, chunk_size);
        totalFrames = chunk_size / BlockAlign;
        break;

teraz przy is.read(data.recordedSamples, chunk_size);
error: no matching function for call to 'std::basic_ifstream<char>::read(SAMPLE*&, uint32_t&)

1

Ręce opadają.

    data.recordedSamples = (SAMPLE *) chunk_size;

Co to jest?!

Co do read - rzutuj. Zapomniałem, że data.recordedSamples to SAMPLE* a nie char*.

0
  delete[] data.recordedSamples;

        data.recordedSamples = new SAMPLE[chunk_size];;
        is.read((char *)data.recordedSamples, chunk_size);
        totalFrames = chunk_size / BlockAlign;
       da.NUM_SECONDS = (totalFrames / da.SAMPLE_RATE);
        break;

dalej wczytuje tylko i wyłącznie kiedy nacisnę start ( i tyle sekund co tamto nagranie)

1

Ech...

data.recordedSamples = (SAMPLE*) new char[chunk_size];

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