Odczyt .wav

ER
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:168
0

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

Kopiuj
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 );
edytowany 3x, ostatnio: eryczzek
AN
  • Rejestracja:około 19 lat
  • Ostatnio:około 16 godzin
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.

edytowany 2x, ostatnio: andrzejlisek
ER
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:168
0

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

Kopiuj
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

edytowany 2x, ostatnio: eryczzek
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:24 minuty
1

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

ER
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:168
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 ?

Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:24 minuty
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.

ER
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:168
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 ?

edytowany 1x, ostatnio: eryczzek
06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
2

Tu masz kod czytający poprawnie plik wav:

Kopiuj
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.

Azarien
czy to dobrze seekuje jeśli bieżący chunk częściowo odczytano? (więc kursor nie jest na początku chunka)
06
jeśli częściowo, to nie, ale 'fmt' czytany jest w całości, a 'data' jest ostatnim blokiem, więc nie ma wpływu.
ER
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:168
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ć ?

edytowany 1x, ostatnio: eryczzek
06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
1

Rób jak Ci wygodnie.

ER
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:168
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 */

edytowany 1x, ostatnio: eryczzek
06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
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:

Kopiuj
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

edytowany 2x, ostatnio: _0x666_
ER
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:168
0

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

Kopiuj
typedef struct {
  WORD  wFormatTag;
  WORD  nChannels;
  DWORD nSamplesPerSec;
  DWORD nAvgBytesPerSec;
  WORD  nBlockAlign;
  WORD  wBitsPerSample;
  WORD  cbSize;
} WAVEFORMATEX;
edytowany 1x, ostatnio: eryczzek
06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
1
ER
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:168
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 >

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

lub mogę od razu

Kopiuj
    totalFrames = (chunk_size/BlockAlgin);

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

Kopiuj
   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

edytowany 4x, ostatnio: eryczzek
06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
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).

ER
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:168
0

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

Kopiuj
char*           Buffer = NULL;
Buffer = new char [chunk_size];
fread( Buffer, chunk_size, totalFrames, wavFile );
fclose( wavFile );
delete[] Buffer;
06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
1

W jakim sensie "nic nie daje"?

ER
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:168
0

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

Kopiuj
 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)

edytowany 1x, ostatnio: eryczzek
06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
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)

edytowany 1x, ostatnio: _0x666_
ER
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:168
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

06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
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.

ER
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:168
0
Kopiuj

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 );
06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
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:

Kopiuj
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;
}
ER
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:168
0

ajaj
przy

Kopiuj
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; ` ??

edytowany 1x, ostatnio: eryczzek
06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
1

Rzutuj na SAMPLE*.

ER
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:168
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)

Kopiuj
        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&)

06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
1

Ręce opadają.

Kopiuj
    data.recordedSamples = (SAMPLE *) chunk_size;

Co to jest?!

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

ER
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 7 lat
  • Postów:168
0
Kopiuj
  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)

edytowany 1x, ostatnio: eryczzek
06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
1

Ech...

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

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.