🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: pl.comp.lang.delphi
17 messages
17 total messages Started by stchebel Mon, 05 Sep 2016 23:25
Odtwarzanie Audio - trochę inaczej (D6)
#345173
Author: stchebel
Date: Mon, 05 Sep 2016 23:25
37 lines
3035 bytes
Witam,
Mam "zgryza" jak to zrobić. Zagadnienie jest następujące: 

1) Jest urządzenie, które generuje sygnał w zakresie częstotliwości akustycznych (słyszalnych dla humanoida), czyli od kilkudziesięciu Hz, do kilku KHz.

2) Sygnał jest próbkowany "na zewnątrz", czyli poza pecetem z częstotliwością spełniającą warunek Nyquista i jest dostępny w postaci cyfrowej np. poprzez USB.
Dla obeznanych w warunkach czasowych protokołu USB, natychmiast pojawi się problem synchronizacji. To zupełnie inna bajka, załóżmy że tego problemu nie ma.

3) Załóżmy, że przychodzi mi czysty sinus o częstotliwości dajmy na to 1kHz, próbkowany z interwałem czasowym 10ms. Słowo w kodzie U2, więc 12-to bitowe (Najstarszy bit, to znak +/-). 

4) Z odczytem danych przez USB (układ FT2232H) nie ma problemów. Problem jest z "wyświetleniem" danych na głośniku. 

5) Dla uproszczenia zagadnienia/pytania, zróbmy takie coś (sinus 1kHz):

t:=0;
DeltaT:=10; // 10 ms - Częstotlwość odczytu=próbkowania (takie założenie)
f:=1000; // Częstotliwość 1kHz
repeat
 a:=Round(2047*sin(2*pi*f*t/1000)); // dzielimy/1000, bo DeltaT jest w ms
 WyslijNaKarteDzwiekowa(a);
 t:=t+DeltaT;
 sleep(DeltaT);
until CosTam;

=============

Pytanie/Prośba:

Jakich zaklęć użyć w procedure WyslijNaKarteDzwiekowa(a:word);

Chyba trzeba wykorzystać jakieś windowsowe API, ale kompletnie się na tym nie znam. Myślałem też o buforowaniu danych w FIFO o pewnej głębokości, natępnie o szybkim odczycie i konwersji na plik np. WMV. Też co prawda nie wiem jak tego dokonać, ale obawiam się, że soft mógłby mieć "czkawkę". 

Zagadnienie jest typu: [mikrofon/wzmacniacz/ADC]=>[USB]=>[Karta Dźwiękowa/głośnik] .

Jak to zrobić? Oczywiście, "gotowiec" najmilej widziany, ale wszelakie wskazówki również.

Pzdr., Stachu 
Re: Odtwarzanie Audio - trochę inaczej (D6)
#345174
Author: stchebel
Date: Mon, 05 Sep 2016 23:40
50 lines
3776 bytes
W dniu wtorek, 6 września 2016 01:25:52 UTC+2 użytkownik stch...@gmail.com napisał:
> Witam,
> Mam "zgryza" jak to zrobić. Zagadnienie jest następujące: 
> 
> 1) Jest urządzenie, które generuje sygnał w zakresie częstotliwości akustycznych (słyszalnych dla humanoida), czyli od kilkudziesięciu Hz, do kilku KHz.
> 
> 2) Sygnał jest próbkowany "na zewnątrz", czyli poza pecetem z częstotliwością spełniającą warunek Nyquista i jest dostępny w postaci cyfrowej np. poprzez USB.
> Dla obeznanych w warunkach czasowych protokołu USB, natychmiast pojawi się problem synchronizacji. To zupełnie inna bajka, załóżmy że tego problemu nie ma.
> 
> 3) Załóżmy, że przychodzi mi czysty sinus o częstotliwości dajmy na to 1kHz, próbkowany z interwałem czasowym 10ms. Słowo w kodzie U2, więc 12-to bitowe (Najstarszy bit, to znak +/-). 
> 
> 4) Z odczytem danych przez USB (układ FT2232H) nie ma problemów. Problem jest z "wyświetleniem" danych na głośniku. 
> 
> 5) Dla uproszczenia zagadnienia/pytania, zróbmy takie coś (sinus 1kHz):
> 
> t:=0;
> DeltaT:=10; // 10 ms - Częstotlwość odczytu=próbkowania (takie założenie)
> f:=1000; // Częstotliwość 1kHz
> repeat
>  a:=Round(2047*sin(2*pi*f*t/1000)); // dzielimy/1000, bo DeltaT jest w ms
>  WyslijNaKarteDzwiekowa(a);
>  t:=t+DeltaT;
>  sleep(DeltaT);
> until CosTam;
> 
> =============
> 
> Pytanie/Prośba:
> 
> Jakich zaklęć użyć w procedure WyslijNaKarteDzwiekowa(a:word);
> 
> Chyba trzeba wykorzystać jakieś windowsowe API, ale kompletnie się na tym nie znam. Myślałem też o buforowaniu danych w FIFO o pewnej głębokości, natępnie o szybkim odczycie i konwersji na plik np. WMV. Też co prawda nie wiem jak tego dokonać, ale obawiam się, że soft mógłby mieć "czkawkę". 
> 
> Zagadnienie jest typu: [mikrofon/wzmacniacz/ADC]=>[USB]=>[Karta Dźwiękowa/głośnik] .
> 
> Jak to zrobić? Oczywiście, "gotowiec" najmilej widziany, ale wszelakie wskazówki również.
> 
> Pzdr., Stachu

==================

Poprawka :

Jest:

3) Załóżmy, że przychodzi mi czysty sinus o częstotliwości dajmy na to 1kHz, próbkowany z interwałem czasowym 10ms. Słowo w kodzie U2, więc 12-to bitowe (Najstarszy bit, to znak +/-).

Powinno być:

3) Załóżmy, że przychodzi mi czysty sinus o częstotliwości dajmy na to 1kHz, próbkowany z interwałem czasowym 10ms. Słowo w kodzie U2, więc 12-to bitowe (Najstarszy bit, to znak +/-) jest z zakresu (-2048,2047).
Re: Odtwarzanie Audio - trochę inaczej (D6)
#345182
Author: arivald
Date: Tue, 06 Sep 2016 04:35
58 lines
2876 bytes
W dniu 2016-09-06 o 01:25, stchebel@gmail.com pisze:
> Witam,
> Mam "zgryza" jak to zrobić. Zagadnienie jest następujące:
>
> 1) Jest urządzenie, które generuje sygnał w zakresie częstotliwości akustycznych
>  (słyszalnych dla humanoida), czyli od kilkudziesięciu Hz, do kilku KHz.
>
> 2) Sygnał jest próbkowany "na zewnątrz", czyli poza pecetem z częstotliwością
>  spełniającą warunek Nyquista i jest dostępny w postaci cyfrowej np. 
poprzez USB.
> Dla obeznanych w warunkach czasowych protokołu USB, natychmiast pojawi się
>  problem synchronizacji. To zupełnie inna bajka, załóżmy że tego 
problemu nie ma.
>
> 3) Załóżmy, że przychodzi mi czysty sinus o częstotliwości dajmy na to 1kHz,
>  próbkowany z interwałem czasowym 10ms. Słowo w kodzie U2, więc 12-to 
bitowe
>  (Najstarszy bit, to znak +/-).
>
> 4) Z odczytem danych przez USB (układ FT2232H) nie ma problemów. Problem jes
>t z "wyświetleniem" danych na głośniku.
>
> 5) Dla uproszczenia zagadnienia/pytania, zróbmy takie coś (sinus 1kHz):
>
> t:=0;
> DeltaT:=10; // 10 ms - Częstotlwość odczytu=próbkowania (takie założenie)
> f:=1000; // Częstotliwość 1kHz
> repeat
>  a:=Round(2047*sin(2*pi*f*t/1000)); // dzielimy/1000, bo DeltaT jest w ms
>  WyslijNaKarteDzwiekowa(a);
>  t:=t+DeltaT;
>  sleep(DeltaT);
> until CosTam;
>
> =============
>
> Pytanie/Prośba:
>
> Jakich zaklęć użyć w procedure WyslijNaKarteDzwiekowa(a:word);
>

https://msdn.microsoft.com/en-us/library/windows/desktop/dd743834(v=vs.85).aspx

Najpierw waveOutOpen, potem seria waveOutWrite, i na koniec waveOutClose.

Generalnie swoje sample zbierasz w buforze (jeden wątek), a w drugim, na 
callbacku, przekazujesz zebrane fragmenty do odtwarzania.

Tu masz podobny przykład: 
http://4programmers.net/Delphi/Artyku%C5%82y/Odtwarzanie_wave_z_WinAPI


Jest też "gotowiec", ale nie wiem jak tego się używa.
TLiveAudioPlayer z biblioteki 
http://www.delphiarea.com/products/delphi-packages/waveaudio/

-- 
Arivald
Re: Odtwarzanie Audio - trochę inaczej (D6)
#345175
Author: alex.cianciara
Date: Tue, 06 Sep 2016 10:02
13 lines
2384 bytes
W dniu wtorek, 6 września 2016 01:25:52 UTC+2 użytkownik stch...@gmail.com napisał:

> 2) Sygnał jest próbkowany "na zewnątrz", czyli poza pecetem z częstotliwością spełniającą warunek Nyquista i jest dostępny w postaci cyfrowej np. poprzez USB.
[...]
> 3) Załóżmy, że przychodzi mi czysty sinus o częstotliwości dajmy na to 1kHz, próbkowany z interwałem czasowym 10ms. Słowo w kodzie U2, więc 12-to bitowe (Najstarszy bit, to znak +/-). 


8)
Oj kolega Nyquist to się w grobie przewraca... 1 kHz to okres 1 ms, czyli wzorem Nyquista max 500 us krok próbkowania. A jak chcesz tak do 20 kHz to 25 us będzie bardziej odpowiednie. Jak chcesz dźwięk lepszej jakości to i 10 us nie będzie za dużo.
I teraz pytanie jak oprogramować PCta aby utrzymać równomierny takt 25 us. Napewno nie w takiej pętelce, a już użycie Sleep() to zbrodnia. :)

Pozdrawiam
AC
Re: Odtwarzanie Audio - trochę inaczej (D6)
#345181
Author: wloochacz
Date: Tue, 06 Sep 2016 11:06
7 lines
1356 bytes
W dniu 2016-09-06 o 12:02, alex.cianciara@gmail.com pisze:
> I teraz pytanie jak oprogramować PCta aby utrzymać równomierny takt 25 us. Napewno nie w takiej pętelce, a już użycie Sleep() to zbrodnia. :)
https://github.com/LaKraven/LKSL
Szukać "High Precision Threads".

-- 
wloochacz
Re: Odtwarzanie Audio - trochę inaczej (D6)
#345176
Author: stchebel
Date: Tue, 06 Sep 2016 11:20
18 lines
2700 bytes
W dniu wtorek, 6 września 2016 12:02:56 UTC+2 użytkownik alex.ci...@gmail.com napisał:
> W dniu wtorek, 6 września 2016 01:25:52 UTC+2 użytkownik stch...@gmail.com napisał:
> 
> > 2) Sygnał jest próbkowany "na zewnątrz", czyli poza pecetem z częstotliwością spełniającą warunek Nyquista i jest dostępny w postaci cyfrowej np. poprzez USB.
> [...]
> > 3) Załóżmy, że przychodzi mi czysty sinus o częstotliwości dajmy na to 1kHz, próbkowany z interwałem czasowym 10ms. Słowo w kodzie U2, więc 12-to bitowe (Najstarszy bit, to znak +/-). 
> 
> 
> 8)
> Oj kolega Nyquist to się w grobie przewraca... 1 kHz to okres 1 ms, czyli wzorem Nyquista max 500 us krok próbkowania. A jak chcesz tak do 20 kHz to 25 us będzie bardziej odpowiednie. Jak chcesz dźwięk lepszej jakości to i 10 us nie będzie za dużo.
> I teraz pytanie jak oprogramować PCta aby utrzymać równomierny takt 25 us. Napewno nie w takiej pętelce, a już użycie Sleep() to zbrodnia. :)
> 
> Pozdrawiam
> AC

========

O Q... !!  Tak to jest, jak się bierze dane "z sufitu" bez grama pomyślunku i rachunku. Racja po Twojej stronie, po mojej czerwony rumieniec na pysku. Co do sleep(), nie ma się co czepiać, bo nie w tym problem. Oczywiście masz rację co do stabilności, a raczej jej braku w takim "zegarze", nie mniej jednak chodzi mi tylko o "wyświetlanie" danych na głośniku.
Re: Odtwarzanie Audio - trochę inaczej (D6)
#345177
Author: stchebel
Date: Tue, 06 Sep 2016 11:29
23 lines
2967 bytes
W dniu wtorek, 6 września 2016 13:20:15 UTC+2 użytkownik stch...@gmail.com napisał:
> W dniu wtorek, 6 września 2016 12:02:56 UTC+2 użytkownik alex.ci...@gmail.com napisał:
> > W dniu wtorek, 6 września 2016 01:25:52 UTC+2 użytkownik stch...@gmail.com napisał:
> > 
> > > 2) Sygnał jest próbkowany "na zewnątrz", czyli poza pecetem z częstotliwością spełniającą warunek Nyquista i jest dostępny w postaci cyfrowej np. poprzez USB.
> > [...]
> > > 3) Załóżmy, że przychodzi mi czysty sinus o częstotliwości dajmy na to 1kHz, próbkowany z interwałem czasowym 10ms. Słowo w kodzie U2, więc 12-to bitowe (Najstarszy bit, to znak +/-). 
> > 
> > 
> > 8)
> > Oj kolega Nyquist to się w grobie przewraca... 1 kHz to okres 1 ms, czyli wzorem Nyquista max 500 us krok próbkowania. A jak chcesz tak do 20 kHz to 25 us będzie bardziej odpowiednie. Jak chcesz dźwięk lepszej jakości to i 10 us nie będzie za dużo.
> > I teraz pytanie jak oprogramować PCta aby utrzymać równomierny takt 25 us. Napewno nie w takiej pętelce, a już użycie Sleep() to zbrodnia. :)
> > 
> > Pozdrawiam
> > AC
> 
> ========
> 
> O Q... !!  Tak to jest, jak się bierze dane "z sufitu" bez grama pomyślunku i rachunku. Racja po Twojej stronie, po mojej czerwony rumieniec na pysku. Co do sleep(), nie ma się co czepiać, bo nie w tym problem. Oczywiście masz rację co do stabilności, a raczej jej braku w takim "zegarze", nie mniej jednak chodzi mi tylko o "wyświetlanie" danych na głośniku.

============

Oczywiście zmieniam na f=100Hz i sleep(1). Teraz Pan Nyquist może spać spokojnie.
Re: Odtwarzanie Audio - trochę inaczej (D6)
#345178
Author: alex.cianciara
Date: Tue, 06 Sep 2016 13:13
41 lines
3915 bytes
W dniu wtorek, 6 września 2016 13:29:15 UTC+2 użytkownik stch...@gmail.com napisał:
> W dniu wtorek, 6 września 2016 13:20:15 UTC+2 użytkownik stch...@gmail.com napisał:
> > W dniu wtorek, 6 września 2016 12:02:56 UTC+2 użytkownik alex.ci...@gmail.com napisał:
> > > W dniu wtorek, 6 września 2016 01:25:52 UTC+2 użytkownik stch...@gmail.com napisał:
> > > 
> > > > 2) Sygnał jest próbkowany "na zewnątrz", czyli poza pecetem z częstotliwością spełniającą warunek Nyquista i jest dostępny w postaci cyfrowej np. poprzez USB.
> > > [...]
> > > > 3) Załóżmy, że przychodzi mi czysty sinus o częstotliwości dajmy na to 1kHz, próbkowany z interwałem czasowym 10ms. Słowo w kodzie U2, więc 12-to bitowe (Najstarszy bit, to znak +/-). 
> > > 
> > > 
> > > 8)
> > > Oj kolega Nyquist to się w grobie przewraca... 1 kHz to okres 1 ms, czyli wzorem Nyquista max 500 us krok próbkowania. A jak chcesz tak do 20 kHz to 25 us będzie bardziej odpowiednie. Jak chcesz dźwięk lepszej jakości to i 10 us nie będzie za dużo.
> > > I teraz pytanie jak oprogramować PCta aby utrzymać równomierny takt 25 us. Napewno nie w takiej pętelce, a już użycie Sleep() to zbrodnia. :)
> > > 
> > > Pozdrawiam
> > > AC
> > 
> > ========
> > 
> > O Q... !!  Tak to jest, jak się bierze dane "z sufitu" bez grama pomyślunku i rachunku. Racja po Twojej stronie, po mojej czerwony rumieniec na pysku. Co do sleep(), nie ma się co czepiać, bo nie w tym problem. Oczywiście masz rację co do stabilności, a raczej jej braku w takim "zegarze", nie mniej jednak chodzi mi tylko o "wyświetlanie" danych na głośniku.
> 
> ============
> 
> Oczywiście zmieniam na f=100Hz i sleep(1). Teraz Pan Nyquist może spać spokojnie.

Obawiam się, że nie do końca. Z moich testów czas wykonania sleep(1) bardzo zależy od komputera.
Na moim trwa od 1,02 do prawie 3 ms, ale jak wykonywałem testy na innych to czas trwania wynosił od prawie 0 ms do 20 ms.
Test wykonywany w pętli x 1000. Fragment testowy:
[...]
  for i := 0 to ile_prob - 1 do
  begin
    QueryPerformanceCounter( istart );
    Sleep( czas );
    QueryPerformanceCounter( istop );
    wartosci[ i ] := istop - istart;
  end;
// aby policzyć czas potrzeba jeszcze wykonać
  QueryPerformanceFrequency( frq );
// czas to (istop - istart) / frq * 1000 [ms]

AC
Re: Odtwarzanie Audio - trochę inaczej (D6)
#345179
Author: wloochacz
Date: Tue, 06 Sep 2016 13:21
17 lines
1815 bytes
W dniu 2016-09-06 o 15:13, alex.cianciara@gmail.com pisze:
/ciach/
> Obawiam się, że nie do końca. Z moich testów czas wykonania sleep(1) bardzo zależy od komputera.
/ciach/

To zależy nie tyle od komputera, co od OSu. Windows to nie jest system 
czasu rzeczywistego i *nigdy* nie będzie pewności co do tego ile to ma 
trwać. Nie da się i koniec.
Można to tylko lepiej lub gorzej aproksymować.
Gorzej to sleep(100)
Lepiej to sleep(1) i GetTickCount.

A w tym co podałem jest to zrobione jeszcze lepiej, ale to i tak nie 
jest idealne.

-- 
wloochacz
Re: Odtwarzanie Audio - trochę inaczej (D6)
#345183
Author: Sebastian Biały
Date: Tue, 06 Sep 2016 18:11
35 lines
2138 bytes
On 2016-09-06 01:25, stchebel@gmail.com wrote:
> Jakich zaklęć użyć w procedure WyslijNaKarteDzwiekowa(a:word);

Ogolnie tego się tak nie robi.

Karty dzwiękowe posiadają zazwyczaj dwa bufory wyjściwe (tak samo 
zazwyczaj DMA w mikrokontrolerach). Podstawowy i nastepny. Jak karta 
skończy wysylac próbki w podstawowym to generuje przerwanie i jedzie 
dalej z nastepnym jako podstawowym. W tym czasie CPU ma obowiązek 
wypełnić znowu bufor.

Robi się to jakoś tak:

WyślijBuforNaKartę( dane, rozmiar );
WyślijBuforNaKartę( nastepneDane, rozmiar );

while( true )
{
	...
	if ( przerwanieKacieZabrakoDanychWPodstawowymBuforze )
		WysliBuforNaKartę( następneDane + rozmiar );

	nastepneDane += ...
}

Problemy czasu rzeczywistego zostawia się karcie. Tylko ona jest w 
stanie wyrzucać dzwięk z okresloną prędkością.

Rozmiar bufora zależy od sytuacji w systemie operacyjnym w przypadku 
windwosa jak zabranie RAM i zacznie swapować dowolnie długi bufor jest 
za mały.

Zagadnienie, jak to z APi windowsa jest, tylko pozornie proste. Tu więcej:

http://blogersii.pl/2016/02/24/niskopoziomowa-obsluga-audio-w-windows/
Re: Odtwarzanie Audio - trochę inaczej (D6)
#345184
Author: stchebel
Date: Wed, 07 Sep 2016 00:29
51 lines
3515 bytes
W dniu wtorek, 6 września 2016 20:11:32 UTC+2 użytkownik Sebastian Biały napisał:
> On 2016-09-06 01:25, stchebel@gmail.com wrote:
> > Jakich zaklęć użyć w procedure WyslijNaKarteDzwiekowa(a:word);
> 
> Ogolnie tego się tak nie robi.
> 
> Karty dzwiękowe posiadają zazwyczaj dwa bufory wyjściwe (tak samo 
> zazwyczaj DMA w mikrokontrolerach). Podstawowy i nastepny. Jak karta 
> skończy wysylac próbki w podstawowym to generuje przerwanie i jedzie 
> dalej z nastepnym jako podstawowym. W tym czasie CPU ma obowiązek 
> wypełnić znowu bufor.

Na pewno WYJŚCIOWE? Chyba raczej WEJŚCIOWE?!  Karta dźwiękowa to SLAVE, pecet jest MASTER. Pecet/uC/czy_cokolwiek_innego podaje dane do karty audio. Być może "literówka" Ci się przytrafiła, jeżeli TAK, to póki co rozumiemy się. 

> 
> Robi się to jakoś tak:
> 
> WyślijBuforNaKartę( dane, rozmiar );
> WyślijBuforNaKartę( nastepneDane, rozmiar );

No tyle to ja wiem. Przeczytaj główny wątek jeszcze raz. 


> 
> while( true )
> {
> 	...
> 	if ( przerwanieKacieZabrakoDanychWPodstawowymBuforze )
> 		WysliBuforNaKartę( następneDane + rozmiar );
> 
> 	nastepneDane += ...
> }

Rozumiem powyższe, ale..  Na tej grupie pisze się w Pascalu.

> 
> Problemy czasu rzeczywistego zostawia się karcie. Tylko ona jest w 
> stanie wyrzucać dzwięk z okresloną prędkością.
> 
> Rozmiar bufora zależy od sytuacji w systemie operacyjnym w przypadku 
> windwosa jak zabranie RAM i zacznie swapować dowolnie długi bufor jest 
> za mały.

Problem czasowy, to zupełnie inna bajka. Czytaj ze zrozumieniem główny wątek (z poprawkami). Zostawmy w spokoju sleep(). Załóżmy, że działa bez zarzutu. Chodzi mi tylko o "wyświetlenie" danych na głośniku.

> 
> Zagadnienie, jak to z APi windowsa jest, tylko pozornie proste. Tu więcej:
> 
> http://blogersii.pl/2016/02/24/niskopoziomowa-obsluga-audio-w-windows/

Chyba dobry namiar - Dzięki. Jutro to przetrawię, i jakby co będę dalej tutaj  marudził.
Re: Odtwarzanie Audio - trochę inaczej (D6)
#345180
Author: stchebel
Date: Wed, 07 Sep 2016 01:05
22 lines
2475 bytes
W dniu wtorek, 6 września 2016 15:21:01 UTC+2 użytkownik wloochacz napisał:
> W dniu 2016-09-06 o 15:13, alex.cianciara@gmail.com pisze:
> /ciach/
> > Obawiam się, że nie do końca. Z moich testów czas wykonania sleep(1) bardzo zależy od komputera.
> /ciach/
> 
> To zależy nie tyle od komputera, co od OSu. Windows to nie jest system 
> czasu rzeczywistego i *nigdy* nie będzie pewności co do tego ile to ma 
> trwać. Nie da się i koniec.
> Można to tylko lepiej lub gorzej aproksymować.
> Gorzej to sleep(100)
> Lepiej to sleep(1) i GetTickCount.
> 
> A w tym co podałem jest to zrobione jeszcze lepiej, ale to i tak nie 
> jest idealne.
> 
> -- 
> wloochacz

====================

Zostawmy problemy czsowe na inny wątek. W głównym wątku poczyniłem drobny, aczkolwiek istotny błąd (Nyquist). Nie w tym rzecz. Chodzi o "wyświetlenie" jakiejś tam wartości na głośniku. Częstotliwość powtarzania owego "wyświetlania", to zupełnie inna bajka.
Re: Odtwarzanie Audio - trochę inaczej (D6)
#345185
Author: Sebastian Biały
Date: Wed, 07 Sep 2016 15:59
38 lines
2495 bytes
On 2016-09-07 02:29, stchebel@gmail.com wrote:
>> Karty dzwiękowe posiadają zazwyczaj dwa bufory wyjściwe (tak samo
>> zazwyczaj DMA w mikrokontrolerach). Podstawowy i nastepny. Jak karta
>> skończy wysylac próbki w podstawowym to generuje przerwanie i jedzie
>> dalej z nastepnym jako podstawowym. W tym czasie CPU ma obowiązek
>> wypełnić znowu bufor.
>
> Na pewno WYJŚCIOWE?

Tak. Dane z tych buforów znajdą się na *wyjściu* karty i dlatego są 
wyjściowe.

> Chyba raczej WEJŚCIOWE?!

Są również takie. Do line-in/mikrofonu.

>  Karta dźwiękowa to SLAVE, pecet jest MASTER.

Nie patrz na peceta. Patrz na kartę. Od zawsze bufor który zostanie 
wysłany na wyjście karty nazywa się wyjsciowym. W kazdym  DMA jest to 
tak samo nazywane.

> Rozumiem powyższe, ale..  Na tej grupie pisze się w Pascalu.

Zapis klamrowy jest bardziej zwięzly.

>> Rozmiar bufora zależy od sytuacji w systemie operacyjnym w przypadku
>> windwosa jak zabranie RAM i zacznie swapować dowolnie długi bufor jest
>> za mały.

> Problem czasowy, to zupełnie inna bajka. Czytaj ze zrozumieniem główny wątek (z poprawkami). Zostawmy w spokoju sleep().

Poprawny algorytm nie zawiera sleep.

> Załóżmy, że działa bez zarzutu. Chodzi mi tylko o "wyświetlenie" danych na głośniku.

Dostaleś odpowiedź. Masz dwa bufory które naprzemiennie wysycasz danymi 
w miarę jak karta zglasza przerwania.
Re: Odtwarzanie Audio - trochę inaczej (D6)
#345186
Author: stchebel
Date: Wed, 07 Sep 2016 18:07
9 lines
1796 bytes
W dniu środa, 7 września 2016 18:00:11 UTC+2 użytkownik Sebastian Biały napisał:

> 
> > Załóżmy, że działa bez zarzutu. Chodzi mi tylko o "wyświetlenie" danych na głośniku.
> 
> Dostaleś odpowiedź. Masz dwa bufory które naprzemiennie wysycasz danymi 
> w miarę jak karta zglasza przerwania.

Jakoś nie widzę tej odpowiedzi jak wysłać dane(pojedyńcze słowo) na kartę audio.
Re: Odtwarzanie Audio - trochę inaczej (D6)
#345187
Author: Sebastian Biały
Date: Wed, 07 Sep 2016 18:44
24 lines
2509 bytes
On 2016-09-07 20:07, stchebel@gmail.com wrote:
>>> Załóżmy, że działa bez zarzutu. Chodzi mi tylko o "wyświetlenie" danych na głośniku.
>> Dostaleś odpowiedź. Masz dwa bufory które naprzemiennie wysycasz danymi
>> w miarę jak karta zglasza przerwania.
> Jakoś nie widzę tej odpowiedzi jak wysłać dane(pojedyńcze słowo) na kartę audio.

Jest to bezuzyteczne. Żaden duży system nie jest RT wiec nie ma po co 
robić takiego ficzera jak natychmiastowe sterowanie membraną glośnika 
ponieważ nie masz kontroli nad wywlaszczaniem i nie jesteś w stanie 
osiągnąć stabilnych odstepow. To zadanie dla DMA karty które jest 
stabilne bez względu na zachowanie OSa.

Oodpowiedź brzmi: funkcja "wyslij słowo na kartę" tak naprawdę dopisze 
do bufora i jak się on zapełni wysle go na kartę. nie wiem jak 
rozwiążesz problem aby tą funkcję wołać odpowiednio często aby nie 
zabrakło danych w buforach i odpowiednio nieczęsto aby nie przepełnić 
bufora.

Ewentualnie jeśli koniecznie potrzebujesz nonsensowną funkcję, to niech 
ona wypełnia bufor tą samą daną i wysyła ją do karty. Jak zawołasz z 
inna daną to anulujesz odtwarzanie i ponownie wypełnisz bufory nową daną.

A tak naprawdę: nie potrzebujesz i nie chcesz mieć funkcji 
"wyślijSłowoNaGłośnik". Chcesz mieć podwójne buforowanie.
Re: Odtwarzanie Audio - trochę inaczej (D6)
#345188
Author: arivald
Date: Wed, 07 Sep 2016 23:10
45 lines
3277 bytes
W dniu 2016-09-07 o 20:44, Sebastian Biały pisze:
> On 2016-09-07 20:07, stchebel@gmail.com wrote:
>>>> Załóżmy, że działa bez zarzutu. Chodzi mi tylko o "wyświetlenie"
>>>> danych na głośniku.
>>> Dostaleś odpowiedź. Masz dwa bufory które naprzemiennie wysycasz danymi
>>> w miarę jak karta zglasza przerwania.
>> Jakoś nie widzę tej odpowiedzi jak wysłać dane(pojedyńcze słowo) na
>> kartę audio.
>
> Jest to bezuzyteczne. Żaden duży system nie jest RT wiec nie ma po co
> robić takiego ficzera jak natychmiastowe sterowanie membraną glośnika
> ponieważ nie masz kontroli nad wywlaszczaniem i nie jesteś w stanie
> osiągnąć stabilnych odstepow. To zadanie dla DMA karty które jest
> stabilne bez względu na zachowanie OSa.
>
> Oodpowiedź brzmi: funkcja "wyslij słowo na kartę" tak naprawdę dopisze
> do bufora i jak się on zapełni wysle go na kartę. nie wiem jak
> rozwiążesz problem aby tą funkcję wołać odpowiednio często aby nie
> zabrakło danych w buforach i odpowiednio nieczęsto aby nie przepełnić
> bufora.
>
> Ewentualnie jeśli koniecznie potrzebujesz nonsensowną funkcję, to niech
> ona wypełnia bufor tą samą daną i wysyła ją do karty. Jak zawołasz z
> inna daną to anulujesz odtwarzanie i ponownie wypełnisz bufory nową daną.
>
> A tak naprawdę: nie potrzebujesz i nie chcesz mieć funkcji
> "wyślijSłowoNaGłośnik". Chcesz mieć podwójne buforowanie.
>

Albo, jak koniecznie potrzebujesz wysyłania sampla po samplu, zainwestuj 
w odpowiedni hardware.

Z prostych i tanich, kartę z dwoma portami równoległymi i 16-bitowy 
Covox. Albo zamiast portów równoległych kartę z 16-toma portami GPIO + 
Covox. Tylko pod Windows nie dasz rady tego poprawnie obsłużyć, nawet 
jak zarżniesz procesor w busy-loop, i tak system może twój proces 
wywłaszczyć i będzie przerwa.

Z lepszych rozwiązań, własną kartę PCIE z jakimś DACem (digital audio 
converter), plus sterownik sobie napiszesz, taki co wysyła pojedyncze 
sample. Bo AFAIK wszystkie gotowe rozwiązania, w tym te znane jako 
"karty dźwiękowe", używają buforowania, inaczej się nie da pod Windows.

-- 
Arivald
Re: Odtwarzanie Audio - trochę inaczej (D6)
#345189
Author: jh
Date: Mon, 12 Sep 2016 20:26
47 lines
3524 bytes
W dniu 2016-09-06 o 01:25, stchebel@gmail.com pisze:
> Pytanie/Prośba:
>
> Jakich zaklęć użyć w procedure WyslijNaKarteDzwiekowa(a:word);

waveOut i spółka (waveXXX).

> Chyba trzeba wykorzystać jakieś windowsowe API, ale kompletnie się na tym nie znam. Myślałem też o buforowaniu danych w FIFO o pewnej głębokości, natępnie o szybkim odczycie i konwersji na plik np. WMV. Też co prawda nie wiem jak tego dokonać, ale obawiam się, że soft mógłby mieć "czkawkę".

Z grubsza: otwierasz urządzenie wejściowe audio (waveInOpen), jeśli 
takie masz, zgodnie z wybranym formatem; przygotowujesz i formatujesz 
bufory (waveInPrepareHeader, WAVEHDR); dodajesz (waveInAddBuffer) je do 
kolejki urządzenia audio i uruchamiasz urządzenie (waveInStart). 
Urządzenie audio (sterownik) zapełnia Ci bufor i zwraca do aplikacji w 
callback, kopiujesz sobie bufor do swoich danych, jak najszybciej się 
da, zerujesz bufor, przygotowujesz go jak poprzednio i ponownie 
podsyłasz do urządzenia. Na koniec stopujesz urządzenie waveInStop, 
czekasz, aż wrócą wszystkie bufory, których już nie dodajesz do kolejki, 
a następnie zamykasz urządzenie waveInClose.

W drugą stronę robisz praktycznie to samo - różnica w funkcjach WaveAPI 
to waveOutXXX, a nie waveInXXX. W obu przypadkach obowiązuje zasada - im 
większy bufor i większa ich ilość tym bezpieczniej uniknąć buffer 
underrun, czyli jeśli spóźnisz się z dostawą buforów - masz dziurę i 
błąd. Ale większe bufory i większa ich liczba, to dłuższy czas na 
odebranie dźwięku lub jego "zagranie" przez urządzenie, oraz czas 
potrzebny do odczekania na powrót buforów przy stopowaniu urządzenia.


> Zagadnienie jest typu: [mikrofon/wzmacniacz/ADC]=>[USB]=>[Karta Dźwiękowa/głośnik] .

Generalnie jak chcesz oprzeć się o odczyt danych po USB w czasie 
rzeczywistym korzystając ze standardowych bibliotek to IMHO strata 
czasu. Potrzebujesz sterownika, który poradzi sobie z jitterem, będzie 
umiał się po ludzku zsynchronizować, a jednocześnie układ USB będzie 
posiadał własny bufor, inaczej na specyfikę łącza nie utrzymasz tak 
stabilnego zegara, jakbyś oczekiwał. Takie firmy jak np. RME robią 
własne układy do USB, które gwarantują dużą stabilność przy przesyłaniu 
naprawdę dużej ilości danych.

> Jak to zrobić? Oczywiście, "gotowiec" najmilej widziany, ale wszelakie wskazówki również.

https://github.com/CHERTS/newac

Masz wszystko, co potrzeba poza samym dostarczaniem danych od USB. Free.

jh
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads