Wysokość dźwięku

Odpowiedz Nowy wątek
2010-06-29 00:06
0

Ostatnio zacząłem zajmować się plikami dźwiękowymi (programuję w JavaME) i po zapoznaniu się z formatem WAV naszła mnie myśl, czy dałoby się (tzn. wiadomo, że by się dało, tylko jak ;-)) określić wysokość dźwięku w danym momencie na podstawie jego próbek. W tematyce audio jestem na razie zupełnie zielony, więc cieszyłbym się, gdyby ktoś napisał w czym rzecz.

Piszę w tym dziale, bo w końcu zagadnienie dość nietypowe.

Pozostało 580 znaków

2010-06-29 11:39
0

Witam,

Jeżeli plik WAV zawiera próbki jakiegoś dźwięku złożonego ( muzyki , mowy , itp. ),
to o wysokości takiego dźwięku decyduje częstotliwość najniższego składnika <ort>we</ort> widmie
takiego sygnału. Zatem trzeba wstępnie dokonać analizy widmowej wczytanego ciągu próbek
( operacja FFT ), a następnie przeskalować częstotliwość tego składnika na skalę wysokości.
W psychoakaustyce wysokość dźwięku mierzy się w jednostkach zwanych "melami", a o relacji
pomiędzy częstotliwością a wysokością mówią poniższe strony WWW :

http://en.wikipedia.org/wiki/Mel_scale

http://www.ling.su.se/staff/hartmut/bark.htm#conv

http://openlearn.open.ac.uk/mod/resource/view.php?id=287553

Jako środowisko programistyczne do wszelkich eksperymentów z dźwiękiem przydają się znakomicie
takie pakiety programowe jak Matlab czy Scilab ( ten pierwszy jest programem komercyjnym, ten
drugi jest darmowym programem typu OPEN ). Z obydwoma pakietami jest sprzężony interpreter
swoistego języka programowania ( bardzo podobnego do języka C oraz do języków skryptowych ).
W językach programowania tych pakietów istnieją specyficzne funkcje typu "wavread" ( wczytywanie
ciągu próbek z pliku typu *.WAV wraz z odrębnym wczytywaniem częstotliwości próbkowania ),
funkcje "fft" ( analiza widmowa ) oraz inne, bardziej wyspecjalizowane funkcje do przeprowadzania
analizy widmowej.

                                                                  Pozdrawiam

                                                                   JK

Pozostało 580 znaków

2010-06-29 13:37
0

Mam w takim razie jeszcze jedno pytanie. Czym tak właściwie są próbki? Gdzieś w internecie przeczytałem, że próbka, to częstotliwość dźwięku w danym momencie. Ale przecież w praktyce taka np. 16-bitowa próbka to tylko liczba (z przedziału bodajże od -32768 do 32767). Jak na podstawie takiej liczby określić częstotliwość dźwięku?

Pozostało 580 znaków

2010-06-29 14:32
0

Zatem trzeba wstępnie dokonać analizy widmowej wczytanego ciągu próbek
( operacja FFT ),

Po co?
Jeśli to jeden dominujący dźwięk jest, np. dźwięk struny gitary, to wystarczy odfiltrować składową stałą, wrzucić na komparator dyskryminujący zliczający liczbę przejść przez 0 i podzielić przed czas trwania pomiaru. Tak działają częstościomierze. Proste, szybsze i co najważniejsze dużo dokładniejsze niż FFT.

Gdzieś w internecie przeczytałem, że próbka, to częstotliwość dźwięku w danym momencie.

To bzdurę jakąś wyczytałeś. Próbka to wartość sygnału odczytana w danym momencie (a zapewne średnia wartość tego sygnału z jakiegoś krótkiego przedziału czasu, zwanego okresem próbkowania).

Pozostało 580 znaków

2010-06-29 15:47
0

Witam,

Królik napisał :

"Po co? Jeśli to jeden dominujący dźwięk jest, np. dźwięk struny gitary,
to wystarczy odfiltrować składową stałą, wrzucić na komparator dyskryminujący
zliczający liczbę przejść przez 0 i podzielić przed czas trwania pomiaru.
Tak działają częstościomierze. Proste, szybsze i co najważniejsze dużo dokładniejsze niż FFT."

To nie do końca jest takie proste. W przypadku dźwięku struny gitary ta metoda
akurat może się sprawdzić ( ale z ograniczoną dokładnością ! ), ponieważ widmo
dźwięku struny gitarowej jest widmem harmonicznym, w którym składowa o częstotliwości
podstawowej dominuje ( pod względem amplitudy ) nad pozostałymi ( wyższymi ) składowymi
harmonicznymi. Na tej zasadzie działają nie tylko częstościomierze, ale również tzw.
tonometry, czyli przyrządy służące do wyznaczania 'tonu podstawowego' ( tonu
krtaniowego ) sygnału mowy ludzkiej. W przypadku tonów mowy ton podstawowy był
poddawany "sztucznemu uwypuklaniu" dzięki poddaniu analizowanego sygnału mowy
wstępnej ( tj. jeszcze przed dokonaniem analizy przejść przez zero ) filtracji
filtrem dolnoprzepustowym odpowiednio wysokiego rzędu. Więcej o takich metodach :

http://sound.eti.pg.gda.pl/student/eim/synteza/leszczyna/

Zatem w przypadku jakiegoś dźwięku "bardziej egzotycznego" warto zrobić FFT ( przynajmniej
jako operację "wstępną" ), aby wstępnie się zorientować, "z czym mamy do czynienia".
Czym jest próbka sygnału ? Bardzo dawno temu, w niektórych sklepach papierniczych można
było dostać coś, co nazywało się kalką milimetrową. Założymy, że na tej kalce rysujemy
wąskie słupki - "okienka". Kalkę z owymi słupkami - okienkami nakładamy na wykres sinusoidy
lub innego przebiegu. W jakiś sposób wyliczamy średnią wysokość krzywej widzianej w danym
"okienku - słupku" i tworzymy tabelkę tak wyznaczonych wielkości. Możemy uznać, że sygnał,
którego wykresem była ta krzywa ( np. sinusoida ), został poddany próbkowaniu ; każda liczba
z owej tabelki stanowić będzie "próbkę" sygnału. W praktycę taką funkcję realizują układy
typu "sample & hold", które są wstępnymi podukładami przetwornika analogowo-cyfrowego i które
uśredniają sygnał elektryczny w krótkotrwałym "okienku".

                                                                       Pozdrawiam

                                                                         JK

Pozostało 580 znaków

2010-06-29 23:04
0

No cóż, prawdę mówiąc chodziło mi właśnie o coś takiego, o czym pisze Krolik - miałem zamiar napisać stroik do gitary. Nie bardzo jednak orientuję się, na czym polega odfiltrowanie stałej składowej i czym jest komparator dyskryminujący... Łopatologicznie, mam tabicę z próbkami i daną częstotliwość próbkowania. Co mam z tym zrobić, żeby wyliczyć częstotliwość dźwięku?

O ile oczywiście da się to tak prosto wyjaśnić;)

Pozostało 580 znaków

2010-06-30 10:55
0

Witam,

Odfiltrować składową stałą można np. przez poddanie sygnału operacji różniczkowania.
Programując w środowisku Matlaba lub w środowisku Scilaba mamy do dyspozycji funkcję
"diff", która generuje nowy wektor ( nową tablicę czy nową listę ) na zasadzie
odejmowania wartości poprzedniej od wartości następnej. Jeżeli do początkowego ciągu
próbek zostanie dodana jakaś liczba ( właśnie składowa stała ), to w wyniku takiej
operacji "różnicowej" jej udział zostanie żredukowany do zera. W innym języku programowania
trzeba taką funkcję napisać we własnym zakresie. Komparator dyskryminujacy ma ( w najprostzsym
rozwiązaniu ) dwa wejścia analogowe i jedno wyjście logiczne ( np. w standardzie TTL bądź w
standardzie CMOS ). Jeżeli na oba wejścia podamy dwa różne napięcia, to na wyjściu komparatora
pojawi się stan wysoki ; jeżeli na wejściach komparatora będą równe napięcia, to na jego wyjściu
będzie stan niski. Oprócz takich komparatorów istnieją jeszcze komparatory "okienkowe" , ale Królik
niepotrzebnie wprowadził pojęcia z zakresu elektroniki. W przypadku programowania trzeba zliczyć liczbę próbek pomiędzy kolejnymi ( sąsiednimi ) przejściami przez zero. Tę liczbę należy następnie przeliczyć ( na podstawie znajomości częstotliwości próbkowania ) na interwał czasu ; ten interwał czasu będzie równy półokresowi składowej podstawowej przebiegu. Szukając przejść przez zero należy zwracać uwagę nie tylko na próbki, które przyjmują wartość zero, ale również na takie, które zmieniają znak na przeciwny ( bo przy większej częstotliwości próbkowania pomiędzy nimi znalazłaby się próbka o wartości zerowej ).

                                                                      Pozdrawiam

                                                                       JK

Pozostało 580 znaków

2010-06-30 11:52
0

Dobrze, zliczanie przejść przez zero jest dla mnie jasne, nie bardzo jednak rozumiem jeszcze odejmowanie stałej składowej. Chodzi o coś takiego?

for (int i=1; i < samples.length; i++) {
   samples[i] -= samples[i-1];
}

Albo inaczej:

for (int i=samples.length-1; i > 0; i--) {
   samples[i] -= samples[i-1];
}

Czy też może jeszcze inaczej?

Pozostało 580 znaków

2010-06-30 12:37
0

Te twoje przykłady nie są równoważne! W jednym przypadku masz zależność pomiędzy kolejnymi iteracjami!
To co próbujesz tu zrobi to jest różniczkowanie, więc składowa stała daje automatycznie zero.
Szukając miejsc zerowych dra zróżniczkowanego przebiegu tak naprawdę obliczysz miejsca ekstremów (ale wynik będzie ten sam przy założeniu, że kolejne harmoniczne są dużo mniejsze).


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.

Pozostało 580 znaków

2010-06-30 12:46
0

Składową stała najprościej obliczysz uśredniając wartości wszystkich próbek (suma/ilość).
Do uśredniania warto przepuścić próbki przez np. hanning window filter, by łagownie odciąć próbki z poczatku i końca bufora, które zazwyzaj nie zaczynają/kończą się w zerze.

Natomiast przejścia przez zero wykrywasz programowym przerzutnikiem schmitta, który zmienia stan dopiero gdy sygnał wejściowy przekroczy jakiś dodatni lub ujemny poziom.

Tu masz przykład najprostszego miernika częstotliwości, w C

#include <windows.h>
#include <conio.h>
#pragma comment(lib, "winmm")

#define RECORD_TIME 1000 // sekunda
short buffer[441*RECORD_TIME/10];

int main()
{
    static WAVEFORMATEX format = {WAVE_FORMAT_PCM,1,44100,88200,2,16,0};
    HWAVEIN hSound;
    HANDLE hEvent = CreateEvent(0,0,0,0);

    if (!waveInOpen(&hSound, WAVE_MAPPER, &format, (DWORD_PTR)hEvent, 0, CALLBACK_EVENT))
    {
        WAVEHDR hdr = {(LPSTR)buffer, sizeof(buffer), 0, 0, WHDR_BEGINLOOP|WHDR_ENDLOOP, 0, 0};

        WaitForSingleObject(hEvent, RECORD_TIME/10);

        if (!waveInPrepareHeader(hSound, &hdr, sizeof(hdr)))
        {
            int a, state=0, count;

            waveInStart(hSound);

            while (!_kbhit() && !waveInAddBuffer(hSound, &hdr, sizeof(hdr)))
            {
                short peak = 0;
                WaitForSingleObject(hEvent, RECORD_TIME+(RECORD_TIME/10));
                count = 0;
                for (a=0; a<(sizeof(buffer)/2); a++)
                {
                    if (buffer[a] > peak) peak = buffer[a];
                    if (!state && buffer[a]>300)
                    {
                        state = 1;
                        count++;
                    }
                    else if (state && buffer[a]<-300)
                    {
                        state = 0;
                    }
                }
                printf("frequency: %d Hz  peak: %d\n", (count*1000)/RECORD_TIME, peak);
            }
            waveInUnprepareHeader(hSound, &hdr, sizeof(hdr));
        }
        waveInClose(hSound);
    }
    CloseHandle(hEvent);
    return 0;
}

Wartość 300 określa próg czułości, i powinna być większa od poziomu szumu toru dźwiękowego, oraz szumu tła odbieranego przez mikrofon. Nie ma tutaj usuwania składowej stałej, ani filtra okienka (np. hanning), bo w tak prostym mierniku filtr okna by spowodował przekłamanie wyniku, zmniejszajac ilość przejść przez zero w jednostce czasu.

Pozostało 580 znaków

2010-06-30 13:10
0
towe napisał(a)

Mam w takim razie jeszcze jedno pytanie. Czym tak właściwie są próbki? Gdzieś w internecie przeczytałem, że próbka, to częstotliwość dźwięku w danym momencie.
Nie. Próbka to względne ciśnienie powietrza w danym momencie, gdzie ciśnieniu średniemu (panującemu aktualnie w otoczeniu) odpowiada wartość 0.
Próbka to także stopień wychylenia membrany głośnika względem magnesu, gdzie 0 odpowiada położeniu neutralnemu, a wartości skrajne — maksymalnemu wychyleniu do przodu i do tyłu.

Liczenie przejść przez zero albo ekstremów nadaje się tylko do czystej fali sinusoidalnej. Żaden naturalny dźwięk nie ma takiej charakterystyki. Prawidłowe postępowanie to transformacja FFT i szukanie maksimum w otrzymanym widmie.

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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