Wysokość dźwięku

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.

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! 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
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?

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

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
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ć;)

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
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?

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

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.

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.

0

Witam po raz kolejny

Spróbuję uporządkować trochę tę dyskusję :

  1. Składowa stała
    Warto byłoby się zastanowić, czy celowe jest wyznaczanie tej składowej stałej i jej ewentualne usuwanie. Jeżeli do sinusoidy doda się jakąś niedużą ( mnniejszą od amplitudy ), stałą liczbę dodatnią, to dodatni półokres tej sinusoidy będzie poszerzony, natomiast jej ujemny półokres będzie zaniżony. Można zatem albo uśredniać dwa sąsiednie półokresy, albo zliczać odstęp bądź pomiędzy "co drugim" przejściem przez zero ( np. "parzystym" przejściem przez zero ) bądź pomiedzy "co drugim" ekstremum przebiegu sinusoidy. Wówczas analizowanie i usuwanie składowej stałej stanie się zbędne.

  2. Przerzutnik Schmitta
    Jeżeli trzymać się tych analogii i rozwiązań elektronicznych, to już lepszy był pomysł Królika, aby wykorzystać komparator. Przerzutnik Schmitta też do tego celu nadawałby się, ale wykorzystanie komparatora dałoby dokładniejsze wyniki. Każdy przerzutnik Schmitta ( czy to sprzętowy, czy programowy ) charakteryzuje się tzw. "pętlą histerezy" ( która w większym lub mniejszym stopniu ogranicza dokładność ).

  3. Próbki , proces próbkowania
    Próbkowanie sygnału niekoniecznie musi być kojarzone z ciśnieniem akustycznym lub z amplitudą wychyleń membrany głośnika. Próbkować można przecież przebieg pochodzący np. z akcelerometru, czyli przyrządu rejestrującego przyspieszenie w ruchu drgającym. Proponuję parę linków :

    http://pl.wikipedia.org/wiki/Pr%C3%B3bkowanie

    http://www.pwsz.legnica.edu.pl/~dudaj/mw10.pdf

Próbkowanie sygnału odbywa się w dziedzinie czasu, natomiast jego kwantowanie w dziedzinie amplitud. Próbkowanie polega na uśrednieniu wartości sygnału ( np. wartości napięcia, ciśnienia akustycznego, itp. ) w bardzo krótkim interwale czasu ( dużo krótszym od okresu składowej przebiegu o najwyższej częstotliwości ), a następnie na zamianie tej uśrednionej wartości na liczbę ( zapisaną binarnie i "dającą się czytać" np. przez szynę danych procesora ). Takiego uśredniania dokonują specjalizowane układy "sample & hold" stanowiące zazwyczaj integralną część przetwornika analogowo-cyfrowego :

    http://en.wikipedia.org/wiki/Sample_and_hold
    
Próbkowaniu zatem może być poddany sygnał pochodzący np. z przetwornika gitary elektrycznej
  1. Porównanie dwóch metod : "przejścia przez zero" czy FFT
    Warto może powrócić na początek tej dyskusji, aby dwaj dyskutanci ( "Królik" i "Azarien" ) skonfrontowali swoje rozbieżne w tej materii poglądy. Azarien ma rację mówiąc, że metoda "przejść przez zero" daje idealnie dokładne wyniki jedynie w przypadku "czystego" przebiegu sinusoidalnego. Ale tę metodę można także stosować w przypadku przebiegu bardziej złożonego ( niż czysty ton sinusoidalny ), kiedy amplituda składnika o najniższej amplitudzie jest znacznie większa od amplitudy pozostałych składników ( a tak jest w przypadku dźwięku struny gitarowej ). W innych przypadkach ( np. w przypadku sygnału mowy ) poddaje się analizowany sygnał wstępnej filtracji filtrem dolnoprzepustowym, aby "uwypuklić" składnik o najniższej częstotliwości.

                                                                             Pozdrawiam
    
                                                                                JK
    
0
koniaku napisał(a)

kiedy amplituda składnika o najniższej amplitudzie jest znacznie większa od amplitudy pozostałych składników

chciałeś powiedzieć „kiedy amplituda składnika o najniższej częstotliwości jest znacznie większa od amplitudy pozostałych składników”.

0

Dzięki za poprawę ; to właśnie miałem na myśli ! Jeżeli amplituda składnika o najniższej częstotliwości jest zdecydowanie wyższa od amplitudy pozostałych składników ( o wyższych częstotliwościach ) wówczas można wyznaczać tę częstotliwość metodą "przejść przez zero" ze skończoną, ograniczoną dokładnością ( mniejszą dokładnością aniżeli w przypadku analizowania tą metodą"czystego" tonu sinusoidalnego ). Taki dwuton, w którym niższy składnik dominuje pod względem amplitudy nad składnikiem wyższym można sobie wyobrazić jak sinusoidę o wyższej częstotliwości nawiniętą ( niczym spirala ) na sinusoidę o niższej częstotliwości ; tak wyglądałoby to na ekranie oscyloskopu. A propos oscyloskopu, autorowi tego tematu ("towe" ) można polecić oscyloskop programowy ( z wbudowaną funkcją FFT ), dzięki któremu będzie mógł sprawdzić swoje dokonania :

   http://www.zelscope.com/
                                                                         Pozdrawiam

                                                                                  JK
0

W przypadku dźwięku gitary, ton jest dość dobrze sinusoidalny (poza tym, że gasnący) - tzn. pozostałe składowe mają amplitudę znacznie mniejszą niż amplituda tonu podstawowego.

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