.wav zapis próbek audio

0

chce zpisac nagranie t w .WAV probuje dodac naglowek ale cos mi nie wychodzi (sorki za nazwe zmiennych ale testuje to nie przykladam wiekszej wagi do nich
wzorowałem się na http://www.kartydzwiekowe.republika.pl/pliki/wave1/wave2.htm

 numSamples = totalFrames * NUM_CHANNELS;
 numBytes = numSamples * sizeof(SAMPLE);
        
                    int czopi = 16;
                    int komp = 1;
                    int mono = 1;
                    int ster = 2;
                    int rozd = 16;
                    int czeba = ((SAMPLE_RATE * NUM_CHANNELS * 16)/8);
                    int rozpro = ((NUM_CHANNELS * 16)/8);
                    int bytess = (36+(numSamples* NUM_CHANNELS*2));
                  

                    int ostat = (2*numSamples*NUM_CHANNELS);

                    fwrite("RIFF", 4, 1, fid );
                    fwrite(&bytess, 4, 1, fid);
                    fwrite("WAVE", 4, 1, fid);
                    fwrite("fmt", 4, 1, fid);
                    fwrite(&czopi, 4, 1, fid);
                    fwrite(&komp, 2, 1, fid);
                    fwrite(&ster, 2, 1, fid);
                    fwrite(&SAMPLE_RATE, 4, 1, fid);
                    fwrite(&czeba, 4, 1, fid);
                    fwrite(&rozpro , 2, 1, fid);
                    fwrite(&rozd, 2, 1, fid);
                    fwrite("data", 4, 1, fid);
                    fwrite(&ostat, 4, 1, fid);
                    fwrite( data.recordedSamples, NUM_CHANNELS * sizeof(SAMPLE), totalFrames, fid );
                    fclose( fid );

edit:
przy okazji zapytam, jak z odtwarzaniem jak to wyłuskać z tego nagłówka :)

3
fwrite("fmt", 4, 1, fid);

Nie "fmt", tylko "fmt ".

1

A może dobrze by było to w strukturę opakować i zapisać za jednym razem? Będzie chyba wygodniej, to raz.
Dwa - zwróć uwagę, że część danych jest 32bitowa, część 16. Zainkluduj <stdint.h> albo <inttypes.h> i używaj dla bezpieczeństwa (u)int32_t i (u)int16_t zamiast zwykłych intów.

3
alagner napisał(a):

A może dobrze by było to w strukturę opakować i zapisać za jednym razem? Będzie chyba wygodniej, to raz.
Dwa - zwróć uwagę, że część danych jest 32bitowa, część 16. Zainkluduj <stdint.h> albo <inttypes.h> i używaj dla bezpieczeństwa (u)int32_t i (u)int16_t zamiast zwykłych intów.

To jest zbyt ryzykowne z powodu zachowania kompilatora.

  1. kompilatory wyrównują dane dla optymalizacji kodu (dodają puste przestrzenie między zmiennymi) (trzeba dłubać w ustawieniach kompilatora)
  2. architektura 32/64 zmienna wielkość int-a (nawet są różnice między kompilatorami)

Do tego jest jeszcze problem z endianą, ale ten problem występuje też w pierwotnym kodzie.

0

jaaaaa, kilka godzin siedziałem a to ta spacja. Działa dziękuje bardzo ;) Tylko nie wiem dlaczego gdy odtwarzam to innym programem dźwiek jest zniekształcony

1

@MarekR22
ad.1 Nie robiłbym z tego aż takiego problemu. Ale fakt, trzeba o tym wiedzieć. Założyłem (może trochę bezsensownie) że jest to znany Autorowi problem.
ad.2 Tzn. zgadzamy się tutaj, czy Twoim zdaniem int32_t jest nadal groźny? Popraw jeśli mylę, ale groźny to byłby chyba int_least32_t [czy jakoś podobnie].

Endianess - no tutaj to w ogóle może być sajgon i prosto tego raczej nie będzie dało się obejść, prawda [prosto = bez dodatkowych funkcji zapisujących/różnych implemetacji dla różnych maszyn]?

1
eryczzek napisał(a):

Tylko nie wiem dlaczego gdy odtwarzam to innym programem dźwiek jest zniekształcony

Jaki charakter mają te zniekształcenia? Może format zapisany w pliku (w bloku fmt ) różni się od rzeczywistego.

0
0x666 napisał(a):

Jaki charakter mają te zniekształcenia?

po pierwsze, dźwięk zamiast 2 sekund ma długość 6 sekund, mega szum i dzwiek jest spowolniony .

0x666 napisał(a):

Może format zapisany w pliku (w bloku fmt ) różni się od rzeczywistego.

Nie wiem czy dobrze zrozumiałem, ale gdzie nastawiam format w bloku fmt ?

0

NUM_CHANNELS== 2 ? Jakie masz SAMPLE_RATE?

1

(...) ale gdzie nastawiam format w bloku fmt ?

Piszesz kod i nie wiesz co piszesz?

fwrite("fmt", 4, 1, fid);
fwrite(&czopi, 4, 1, fid);
fwrite(&komp, 2, 1, fid);
fwrite(&ster, 2, 1, fid);
fwrite(&SAMPLE_RATE, 4, 1, fid);
fwrite(&czeba, 4, 1, fid);
fwrite(&rozpro , 2, 1, fid);
fwrite(&rozd, 2, 1, fid);

Generalnie chodzi mi o to, czy SAMPLE_RATE, NUM_CHANNELS i liczba bitów jest taka sama co przy otwieraniu strumienia (port)audio.

Następny bład:

numSamples = totalFrames * NUM_CHANNELS;
...

int ostat = (2 * numSamples * NUM_CHANNELS);
...

fwrite("data", 4, 1, fid);
fwrite(&ostat, 4, 1, fid);

Dlaczego mnożysz dwa razy przez NUM_CHANNELS, jeśli numSamples to liczba sampli "mono". ostat (czyli rozmiar bloku data) powinno być w bajtach.

Zacznij o początku nazywać zmienne jakoś sensowniej to może łatwiej będzie Ci się połapać w tym wszystkim.

0
0x666 napisał(a):

Generalnie chodzi mi o to, czy SAMPLE_RATE, NUM_CHANNELS i liczba bitów jest taka sama co przy otwieraniu strumienia (port)audio.

Tylko, że ja plik otwieram Windows Media Player

1

A jesteś pewny że same dane generujesz odpowiednio?

0

tak, jedynie to w tym kodzie co wkleilem moga byc bledy

1

@eryczzek, nie zrozumiałeś mnie. Chodzi mi o to, czy sample, które wpisujesz do pliku są w takim samym formacie co deklarujesz w bloku fmt .

p.s. w poprzednim poście pokazałem inny błąd, poprawiłeś go?

0
0x666 napisał(a):

@eryczzek, nie zrozumiałeś mnie. Chodzi mi o to, czy sample, które wpisujesz do pliku są w takim samym formacie co deklarujesz w bloku fmt .

SAMPLE_RATE, NUM_CHANNELS sie zgadzaja
i

#define PA_SAMPLE_TYPE  paFloat32
#define SAMPLE_SILENCE  (0.0f)
#define PRINTF_S_FORMAT "%.8f"

zmienilem nazwy

      data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE;
                    data.frameIndex = 0;
                    numSamples = totalFrames * NUM_CHANNELS;
                    numBytes = numSamples * sizeof(SAMPLE);


                    int chunkSize = 16;
                    int audioFormat = 1;
                    int BitsPerSample = 16;
                    int ByteRate = ((SAMPLE_RATE * NUM_CHANNELS * BitsPerSample)/8);  
                    int BlockAlign = ((NUM_CHANNELS * BitsPerSample)/8);
                    int DataSize = ((numSamples*BitsPerSample)/8);
                    int totalSize = (36 + DataSize);

                    fwrite("RIFF", 4, 1, fid );
                    fwrite(&totalSize, 4, 1, fid);
                    fwrite("WAVE", 4, 1, fid);
                    fwrite("fmt ", 4, 1, fid);
                    fwrite(&chunkSize, 4, 1, fid);
                    fwrite(&audioFormat, 2, 1, fid);
                    fwrite(&NUM_CHANNELS, 2, 1, fid);
                    fwrite(&SAMPLE_RATE, 4, 1, fid);
                    fwrite(&ByteRate, 4, 1, fid);
                    fwrite(&BlockAlign , 2, 1, fid);
                    fwrite(&BitsPerSample, 2, 1, fid);
                    fwrite("data", 4, 1, fid);
                    fwrite(&DataSize, 4, 1, fid);
                    fwrite( data.recordedSamples, NUM_CHANNELS * sizeof(SAMPLE), totalFrames, fid );
                    fclose( fid );
2

Podany kod sugeruje sample w formacie float, a stronka ktora podales mowi o int16. Na pewno tak ma byc?

0

dokładnie tak jak mówisz ;)
poprawka, działa

dla jasności zmieniłem na

#define PA_SAMPLE_TYPE  paInt16
#define SAMPLE_SILENCE  (0)
#define PRINTF_S_FORMAT "%d"
0

Żeby kompilator zapisał całą strukturę o dokładnie takim rozmiarze jak ona jest (bez optymalizacji adresów tj. dodawaniu "pustych miejsc") trzeba dodac:
dla MVSC: #pragma pack /opcje/
dla GCC: attribute ((packed))

Nie trzeba zmieniać żadnych opcji.

Pozdrawiam

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