kategoria: ANSI C
[#1] Granie przez audio.device
Czy chcac odtwarzac dzwiek przez Paule musze dla kazdego kanalu oddzielnie otwierac audio.device z wlasnym IORequestem. Czy tez da sie to zrobic inaczej?
Kazdy tutorial na ten temat konczy sie na odtwarzaniu dzwieku z jednego kanalu.

Ostatnia aktualizacja: 24.07.2016 20:14:37 przez Phibrizzo
[#2] Re: Granie przez audio.device

@Phibrizzo, post #1

Otwierasz raz dla wszystkich kanałów, ale później tworzysz 4 ioaudio (lub 8 jeżeli używasz double buffer) modyfikując unit. Przy zamykaniu znowu modyfikujesz unit. Aczkolwiek nie wiem czy metoda jest poprawna.
[#3] Re: Granie przez audio.device

@Phibrizzo, post #1

Nie trzeba otwierać za każdym razem audio.device. Urządzenie otwierasz dokładnie raz.

Podczas alokacji kanałów przypisywany jest klucz alokacji AllocKey, którego później używasz, żeby audio.device "wiedziało", że polecenia są od Ciebie.

Żeby IOAudio był zaakceptowany przez audio.device musi zawierać odpowiednio ustawiony AllocKey. Wystarczy skopiować to pole z IOAudio, którego używałeś przy alokacji kanałów.

Podczas alokacji również zwracana jest maska bitowa reprezentująca zaalokowane kanały w polu Unit. Bity od 0 do 3 reprezentują odpowiednie kanały.

W polu Unit struktury IORequest określasz których kanałów dotyczy polecenie. Po prostu zapalasz bit reprezentujący kanał, który Ciebie interesuje.

Może się zdarzyć, że masz kilka bitów zapalonych. Jeśli odgrywasz sampel za pomocą CMD_WRITE to najmłodszy ustawiony bit jest brany pod uwagę.

Oczywiście musisz utworzyć tyle egzemplarzy IOAudio ile chcesz równocześnie odgrywać dźwięków. Każdy taki IOAudio musi mieć poprawny AllocKey oraz odpowiedni Unit.

Podczas zwalniania musisz ustawić w Unit kanały, które chcesz zwolnić (np. te zwrócone podczas alokacji).

Ostatnia aktualizacja: 24.07.2016 23:20:38 przez Hexmage960
[#4] Re: Granie przez audio.device

@Hexmage960, post #3

Tyle tylko ze cos sie nie zgadza. Wg dokumentacji, faktycznie w polu io_Unit ma znajdowac sie maska bitowa zaalokowanych kanalow. Jednak wg definicji, pole io_Unit jest struktura. I nijak nie moge pojac jak mam to zrobic , o czym piszesz.
[wyróżniony] [#5] Re: Granie przez audio.device

@Phibrizzo, post #4

Po prostu potraktuj pole io_Unit jako liczbę całkowitą.

ioa->ioa_Request.io_Unit = (APTR)0x01;

Rzeczywiście io_Unit to adres struktury, ale w przypadku audio.device określa ono kanały, na których ma być wykonana procedura. Tak piszą w dokumentacji i ja jestem pewien, że sam podobnie odgrywałem dźwięki w swoich grach.

Dla pewności sprawdź co umieszczone jest w polu io_Unit po alokacji kanałów. Powinna być maska pomyślnie zaalokowanych kanałów.

EDIT: Sprawdziłem, jest tak jak piszę.

Ostatnia aktualizacja: 25.07.2016 21:01:03 przez Hexmage960
[#6] Re: Granie przez audio.device

@Hexmage960, post #5

Faktycznie. Zadzialalo bezblednie OK
[#7] Re: Granie przez audio.device

@Hexmage960, post #3

Zastanawia mnie jeszcze jedna sprawa. Bo program mi sie troche wiesza.

Czy aby wszystko bylo zgodnie ze sztuka to powinienem to w nastepukacy sposob:
0. Stworzyc AudioPort przez CreateMsgPort()
1. Stworzyc IOAudio przez CreateIORequest() z w/w portem
2. Uzupelnic opdpowiednie pola dla IOAudio (otwierma 4 kanaly)
3. Otworzyc audio.device z w/w requestem
4. Dodac trzy nowe reuesty z kluczem wygenerowanym przy otwarciu deviceja
5. Kazdy kanal obslugiwac wlasnym requestem
?

Ja poszedlem troche na skroty i chcialem grac na cztrech kanalach wykozystujac jeden request, modyfikujac tylko unit przy wywolaniu odpowieniego kanalu.
Dla dwoch pierwszych kanalow wszystko jest ok (ale to pewnie przypadek). Jednak przy probie zagrania czegos na trzech lub czterech kanalach po kilku odegraniach dzwieku system siie zawiesza. Dlatego pytanie czy taki system odgrywania jest niepoprawny?
[#8] Re: Granie przez audio.device

@Phibrizzo, post #7

chcialem grac na cztrech kanalach wykozystujac jeden request, modyfikujac tylko unit przy wywolaniu odpowieniego kanalu
Jeżeli wyślesz request do urządzenia, to nie możesz z nim nic robić dopóki nie wróci. Jeżeli go wyślesz drugi raz przed powrotem, to zwis masz w zasadzie gwarantowany. W strukturze requesta masz Node, który służy do kolejkowania requestów. Wysłanie go dwa razy to umieszczenie tego samego Node na dwóch listach jednocześnie, w tym momencie pierwsza lista staje się uszkodzona.
[#9] Re: Granie przez audio.device

@Phibrizzo, post #7

Z tego co pamiętam należy używać oddzielnego IORequest dla każdego kanału, bo przecież jak czekasz na koniec dźwięku, to system musi wiedzieć, o który kanał nam chodzi.

@Krashan

Zgadza się.

Zastanawia mnie tylko jeszcze jeden przypadek - zmiana głośności i wysokości dźwięku za pomocą polecenia ADCMD_PERVOL. Z tego co pamiętam, to akurat to możesz wysyłać na tym samym IORequeście, co odgrywasz dźwięk, ale synchronicznie za pomocą DoIO() z ustawioną flagą IOF_QUICK.

--
@Phibrizzo
Jeszcze, żeby nie było żadnych niejasności zapytam: czy do odgrywania dźwięków używasz BeginIO()? I, czy czekasz na zakończenie sampla przez Wait() lub WaitPort() oraz GetMsg()?

Ostatnia aktualizacja: 02.08.2016 18:51:26 przez Hexmage960
[#10] Re: Granie przez audio.device

@Hexmage960, post #9

@Krashan
Czyli wszystko jasne.

@Hexmage
Do odgrywania uzywam BeginIO, dokladnie tak jak w artykule Asmana z papierowego PPA. Tyle tylko ze dodatmkowo okreslam unit. Ogolnie nie czekam na zakonczenie sampla. Jesli musze puscic cos na tym samym kanale poprstu wstrzymuje to co grane bylo w tym czasie.

Ale wracam do pytania: czy powinienem to zrobic tak jak wypunktowalem?
[#11] Re: Granie przez audio.device

@Phibrizzo, post #10

Ale wracam do pytania: czy powinienem to zrobic tak jak wypunktowalem?

Tak.
[#12] Re: Granie przez audio.device

@Hexmage960, post #9

Zastanawia mnie tylko jeszcze jeden przypadek - zmiana głośności i wysokości dźwięku za pomocą polecenia ADCMD_PERVOL. Z tego co pamiętam, to akurat to możesz wysyłać na tym samym IORequeście, co odgrywasz dźwięk, ale synchronicznie za pomocą DoIO() z ustawioną flagą IOF_QUICK.
Tak, bo ta flaga powoduje, że request nie jest wstawiany do kolejki, więc jego struktura Node nie podlega modyfikacji. Z drugiej strony ja bym na wszelki wypadek użył kopii requesta, to raptem kilkadziesiąt bajtów...
[#13] Re: Granie przez audio.device

@Krashan, post #12

OK.
[#14] Re: Granie przez audio.device

@Hexmage960, post #11

To mam jeszcze dwa kontrolne pytania:
1. dla tych dodatkowych requestow jak ustawic ioa_Data i ioa_Length? Tak samo jak dla tego z ktorego wywolywalem audio.device czy mozna podac konkretny kanal?

2. rozumiem ze kazdy request powinien miec wlasny audioport wykreowany przez CreateMSGPort()?
[#15] Re: Granie przez audio.device

@Phibrizzo, post #14

1. To są adresy i długości sampli, więc ustawiasz takie, jaki chcesz odegrać. Przy wywołaniu audio.device jest to całkiem coś innego.
2. Audioport jest ten sam dla wszystkich requestów.
[#16] Re: Granie przez audio.device

@cholok, post #15

Czy moglby ktos rzucic okiem na moj kod? Bo dalej mam problem z wiecej niz jednym kanalem i chcialbym wiedziec co robie zle. Pierwszy kanal mi dziala, ale zagranie na nastepmych powoduje GURU.

link
[#17] Re: Granie przez audio.device

@Phibrizzo, post #16

Na oko wygląda ok, z tym, że ja posyłałem zwykłe AbortIO zamiast FINISH. Może problem jest w pętli playera i GetMsg.
[#18] Re: Granie przez audio.device

@cholok, post #17

Kod wygląda generalnie OK.

Potencjalne problemy może sprawiać CheckIO() i WaitIO().

Z tego co pamiętam CheckIO() powinno być używane z requestami, które co najmniej raz zostały przesłane.

Jak się upewnię to dam znać.

I ważne - do czekania na IORequest z audio.device nie używaj WaitIO(), tylko WaitPort() lub Wait() i GetMsg(). Tak jest napisane w dokumentacji.
[#19] Re: Granie przez audio.device

@Phibrizzo, post #16

Jak by projekt nie był top sekret, to wyślij mi całość na mojego mejla, to obejrze sprawę.

@Hexmage960
Możesz mi wskazać gdzie to jest, że nie można używać WaitIO, bo ja kompletnie tego nie pamiętam. Dzięki.

Ostatnia aktualizacja: 03.08.2016 21:08:03 przez asman
[#20] Re: Granie przez audio.device

@asman, post #19

@Phibrizzo

Według tego opisu spróbuj ustawić pole ln_Type struktury IORequest na 0.

CheckIO can hang if called on an IORequest that has never been used.
This occurs if LN_TYPE of the IORequest is set to "NT_MESSAGE".
Instead simply set LN_TYPE to 0.


Sądzę też, że parę BeginIO()/WaitIO() zastąp po prostu przez DoIO() z ustawioną flagą IOF_QUICK (lub całość polecenia ADCMD_FINISH przez AbortIO() jak mówił Cholok), bo nie wolno wywoływać drugi raz BeginIO() z jednego IORequest przed zakończeniem tego pierwszego (o czym już była mowa).

Ja bym również dla świętego spokoju stworzył oddzielny port komunikacyjny dla każdego kanału. Nie wiem, czy jest mowa o tym w dokumentacji.

@Asman

Tutaj oraz tutaj.

Wait() and WaitPort() will not remove the message from the reply port.
You must use GetMsg() to remove it.

You must always use Wait() or WaitPort() to wait for I/O to finish with
the audio device.
[#21] Re: Granie przez audio.device

@Hexmage960, post #20

Dzięki raz jeszcze. Faktycznie można taki wniosek wysnuć. Ale co ciekawe ja używałem u siebie WaitIO, być może to jest błąd.


Co do ustawiania LN_TYPE na 0, to ja to chyba robiłem, ale podczas testów jakoś mi się kojarzy że mi się wieszał program, ale głowy nie dam. Dobrze by było gdyby ktoś zweryfikował czy to faktycznie pomaga.
[#22] Re: Granie przez audio.device

@asman, post #21

Ja ustawiałem NT_REPLAYMSG specjalnie dla CheckIO. Było tak w jakimś przykładzie.
[#23] Re: Granie przez audio.device

@asman, post #19

Zadna tajemnica, ot poprstu proby w podszkoleniu sie w programowaniu.

Caly kod jest tutaj

link

Ponadto, chyba udalo mi sie rozwiazac problem z reszta kanalow. Poprostu zrobilem zwykle copymem() glownego requesta do pozostalych i pomoglo.

Ale jesli ktos moglby zerkac (skompilowac) i podpowiedziec co i gdzie zmienic. Podejrzewam ze funkcja KillPaula() tez powinna miec AbortIO przy zakonczeniu odtwarzania.
[#24] Re: Granie przez audio.device

@Phibrizzo, post #1

Podbijam temat.

Myslalem ze juz wiem wszystko na ten temat, jednak znowu poleglem na dziwnym przypadku.

Mam taki oto kod:
#define KANAL_LEWY  0
#define KANAL_PRAWY 1

BOOL PaulaInit(void)
{
        UBYTE Channel[] = {3};

        if(AudioPort = CreateMsgPort())
        {
                AudioIO[0] = (struct IOAudio*)CreateIORequest(AudioPort, sizeof(struct IOAudio));
                AudioIO[1] = (struct IOAudio*)CreateIORequest(AudioPort, sizeof(struct IOAudio));

                if(AudioIO[1])
                {
                        AudioIO[0]->ioa_Request.io_Message.mn_ReplyPort   = AudioPort;
                        AudioIO[0]->ioa_Request.io_Message.mn_Node.ln_Pri = 127;
                        AudioIO[0]->ioa_Request.io_Command                = ADCMD_ALLOCATE;
                        AudioIO[0]->ioa_Request.io_Flags                  = ADIOF_NOWAIT;
                        AudioIO[0]->ioa_AllocKey                          = 0;
                        AudioIO[0]->ioa_Data                              = Channel;
                        AudioIO[0]->ioa_Length                            = sizeof(Channel);

                        if(OpenDevice(AUDIONAME, 0L, (struct IORequest*)AudioIO[0], 0L) == NULL)
                        {
                                CopyMem(AudioIO[0], AudioIO[1], sizeof(struct IOAudio));
                                
                                return(TRUE);
                        }
                }
        }
     
        return(FALSE);
}

void PaulaKill(void)
{
        if(AudioIO[1] &&
           AudioIO[1]->ioa_Request.io_Device)
        {
                AbortIO((struct IORequest*)AudioIO[1]);
        }

        if(AudioIO[0] &&
           AudioIO[0]->ioa_Request.io_Device)
        {
                AbortIO((struct IORequest*)AudioIO[0]);
                
                CloseDevice((struct IORequest*)AudioIO[0]);
        }        

        if(AudioIO[1])
        {
                DeleteIORequest(AudioIO[0]);
                DeleteIORequest(AudioIO[1]);
        }

        if(AudioPort) DeleteMsgPort(AudioPort);
}

void PaulaPlay(int sfx, BYTE unit)
{
        if(CheckIO((struct IORequest*)AudioIO[unit]) == NULL)
        {
                AbortIO((struct IORequest*)AudioIO[unit]);
        }
        
        AudioIO[unit]->ioa_Request.io_Command = CMD_WRITE;
        AudioIO[unit]->ioa_Request.io_Flags   = ADIOF_PERVOL;
        AudioIO[unit]->ioa_Request.io_Unit    = (APTR)(1 << unit);
        AudioIO[unit]->ioa_Data               = Dzwieki[sfx].Adres;
        AudioIO[unit]->ioa_Length             = Dzwieki[sfx].Len;
        AudioIO[unit]->ioa_Period             = (UWORD)(Dzwieki[sfx].Period);
        AudioIO[unit]->ioa_Volume             = (UWORD)(63);
        AudioIO[unit]->ioa_Cycles             = 1;
        
        BeginIO((struct IORequest*)AudioIO[unit]);
}


Problem polega na tym ze jesli odegram ten sam sampel w taki spowob:

PaulaPlay(Sampel1, KANAL_LEWY);
PaulaPlay(Sampel1, KANAL_PRAWY);

To czestym wynikiem jest freez systemu mimo ze dziwiek gra. Nie GURU ani restart.
Jesli gram na pojedynczych kanalach ale nie w tym samym czasie to jest OK.

Ktos cos poradzi?

Ostatnia aktualizacja: 07.02.2017 18:34:06 przez Phibrizzo
[#25] Re: Granie przez audio.device

@Phibrizzo, post #24

1. Zaalokuj MsgPort po jednym dla obu IORequestów.

2. Pamiętaj, że AbortIO() nie pobiera wiadomości z portu. Trzeba to zrobić ręcznie za pomocą WaitIO() lub GetMsg(). Musisz zrobić to zarówno w funkcji odgrywania jak i zamykania audio.device.
[#26] Re: Granie przez audio.device

@Hexmage960, post #25

Dodanie drugiego AudioPortu chyba rozwiazalo problem.
[#27] Re: Granie przez audio.device

@Phibrizzo, post #26

Chyba zgubiłeś WaitIO po AbortIO, przynajmniej tak było w moim artykule. Inna sprawa, że być może są błędy w tymże artykule. Nie zamierzam chować głwoy w piasek co często czynię ale na ten czas nie mam czasu by to ogarnąć.

Edit: Nie rozumiem czemu sprawdzasz czy udało się stworzyć iorequest dla AudioIO[1] a dla Audio[0] już nie. Po za tym nie musisz sprawdzać czy się powiodło stworzenie message portu bo nawet jeśli zwróci null, to CreateIORequest wyjdzie z nullem jak dobrze pamiętam. Wtedy to uprości kod.

Ostatnia aktualizacja: 08.02.2017 08:32:05 przez asman
[#28] Re: Granie przez audio.device

@asman, post #27

Chyba zgubiłeś WaitIO po AbortIO, przynajmniej tak było w moim artykule.


Po kazdym AbortIO powinno byc WaitIO albo kombinacja WaitPort/GetMsg. AbortIO po ktorym od razu jest CloseDevice to proszenie sie o klopoty
[#29] Re: Granie przez audio.device

@mschulz, post #28

A propos kombinacji WaitPort/GetMsg, to masz na myśli WaitPort a potem w pętli odbieranie wiadomości GetMsg aż będzię null ?
[#30] Re: Granie przez audio.device

@asman, post #29

Pisałem o tym w poście #25.

Prawdopodobnie wystarczy po AbortIO() jeden GetMsg().
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem