kategoria: ANSI C
[#31] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@mateusz_s, post #30

spróbuje inaczej zrobić. Zmiejsze bufor o polowe do 256b a zrobie ich 4 zamiast 2. Wtedy bedzie czas na uruchomienie kolejego pomimo waittof, może tak..
1
[#32] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@mateusz_s, post #31

W moich playerach, gdzie bylo miksowanie lub odgrywanie malych probek z chipu, to bodaj SetIntVector byl uzywany, zadnego waitu nie bylo.
Aud0 jako prowadzace przerwanie, mozesz sobie zobaczyc zrodla playerow lub customowych modow ze strony Wanted Team.

link
7V, 8V, NTSP system, on Escapee i pare innych o ile dobrze pamietam.

Aud0 ma wysoki priorytet, wiec zawsze jest wykonywane.
Chyba onEscapee lub NTSP bedzie najlatwiejsze do zrozumienia, bo to sa krotkie zrodla.
1
[#33] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Don_Adan, post #32

dzięki poczytam..
1
[#34] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@mateusz_s, post #30

Ja mam pytanie dlaczego w pętli głównej masz WaitTOF ? Jak systemowo to powinno być w głównej pętli Wait (tak według mnie).
1
[#35] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@mateusz_s, post #30

Użycie Wait() nie działa w tym tasku z jakiegoś powodu
Gdy system umieszcza przychodzącą wiadomość w message porcie, a ten ma ustawioną flagę PA_SIGNAL (typowy przypadek), to wysyła sygnał ustawiony w mp_SigBit do tasku w mp_SigTask. Jeżeli port został stworzony przez CreateMsgPort(), to mp_SigTask jest ustawiany na task, który wywołał CreateMsgPort() i sygnał jest alokowany dla tego właśnie tasku.

Zatem zasadą jest, że port powinien być tworzony (i usuwany) przez ten task, który będzie czekał na jego sygnał i odbierał wiadomości.
2
[#36] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@asman, post #34

W pętli głównej mam logikę i renderowanie gry, c2p, obsluge zdarzen okna i gameportu, wyświetlanie i muszę uzywac waittof() zeby była płynna grafika..
1
[#37] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Krashan, post #35

Dzieki za info..
1
[#38] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Don_Adan, post #32

No i ja raczej bym zwiekszyl pojedynczy bufor do 1024 bajtow, a nie zmniejszal.
Jest cos takiego jak narzut z kazdego przerwania, im czesciej jest wywolywane tym wiecej czasu procesora jest potrzebne.
Choc jezeli to sa miksowane SFX a nie muzyka, to moze mniejszy jest ok.
Zakladam, ze miksujesz je albo na 11kHz, albo na max 22 kHz.
Wiec jak uzywasz WaitTOF, to po prostu stworz takiej wielkosci bufor miksujacy, ktory jest odgrywany akurat w czasie jednej ramki.
Mozesz to sobie zobaczyc jak jest wyliczany taki bufor dla jakiegos 7V playera.
W skrocie to jest 20 bajty na 1 kHz.
Ale procedura wyliczajaca jest bardziej dokladna i sprawdzona przeze mnie na roznych wartosciach miksujacych.
2
[#39] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Don_Adan, post #38

I jezeli bys robil takie miksowanie o wielkosci okolo 20 bajtow na 1kHz, to prawdopodobnie wystarczy procedure miksujaca umiescic we wlasciwym miejscu.
Sprawdzilbym tuz za WaitTOF, albo na samym koncu glownej petli.
Tak mi sie przynajmniej wydaje, ale nigdy sie grafika nie zajmowalem, wiec mozliwe ze zle mysle.
1
[#40] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Don_Adan, post #39

Spróbuje na razie zainicjować w osobnym tasku cała obsługę audio IORequestów,
tak żeby w nim były wyłapywane sygnały i tam było oczekiwanie..
[#41] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@mateusz_s, post #40

Na razie wygląda na to że wszystko działa jak należy OK
Przerzuciłem wszsytko zwiazane z audio tj. iorequesty i porty oraz ich inicjowanie i usuwanie
do osobnego taska. I teraz jest oczekiewanie na Wait() tak jak powinno być i nie zamula.

Nie mam potrzeby wysyłania żadnych requestów czy sygnałów z poziomu petli głownej do tego taska,
on tam ma swoja petlę - teraz już nie "busy loop", i sobie po prostu na zmiena puszcza te bufory.

Na razie jest ok.. ale dopiero jak to wstawie w projekt to zobacze czy tak wszsytko smiga jak nalezy i nie majkis dropów w fps ogólnie.. OK

Ostatnia aktualizacja: 30.09.2025 19:35:47 przez mateusz_s
1
[#42] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@mateusz_s, post #41

Hej,
Jeżeli mam dwa IO Audio Requestery MUS i SFX
i chcę żeby MUS grało rownoczenie na LEFT_1 i RIGHT_1
a SFX równocześnie na LEFT_2 i RIGHT_2

To który sposób jest prawidłowy?

01.
- Zrobić ADCMD_ALLOCATE podczas otweirania audio.device dla wartosci { 15 }
czyli alokacja wszystkich 4 kanałów.
- A następnie blokowi MUS, przypisac ioa_Request.io_Unit = (APTR)(LEFT_1 | RIGHT_1);
- A blokowi SFX ioa_Request.io_Unit = (APTR)(LEFT_1 | RIGHT_1);

czy

02.
- Otworzyć audio.device.
- Zrobić ADCMD_ALLOCATE dla bloku MUS - LEFT_1 | RIGHT_1
- A dla bloku SFX tez zrobic ADCMD_ALLOCATE ale dla: LEFT_2 | RIGHT_2

To pierwsze mi teoretycznie działa,
to drugie nie udało mi sie zrobić bo się zawieszało.

Nie jestem pewny czy to pierwsze działa poprawnie, bo nawet jak dam zeby grało tylko z LEFT_1 albo tylko z RIGHT_1
to tak jaby grało z oby dwóch..
[wyróżniony] [#43] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@mateusz_s, post #42

Moim zdaniem żaden sposób nie jest prawidłowy, bo CMD_WRITE działa zawsze tylko na jeden kanał i nie wiem co się stanie, jeżeli w io_Unit będzie ustawiony więcej niż jeden bit. Jak chcesz mieć to samo w jednym L i jednym R (czyli mono), to potrzebujesz 2 requestów i jednego bufora. I trzeba je puścić na synchro, czyli CMD_STOP na oba używane kanały, potem CMD_WRITE dwa razy i potem CMD_START na te kanały.
[wyróżniony] [#44] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@mateusz_s, post #42

W ASM to ja bym sprobowal zaalokowac audio.device dla wszystkich 4 kanalow, tylko po to, zeby inne programy wiedzialy, ze kanaly sa zajete.
A potem za pomoca SetInterVector uzyl Aud0 i Aud2.
Aud0 do muzyki na LEFT1 i RIGHT1.
Aud2 do SFX na LEFT2 I RIGHT2
Ogolnie z tego co pamietam, to kiedys probowalem uzywac jeszcze Aud1 i Aud3, do odgrywania tego samego dzwieku.
Czyli np. przerwanie Aud1, gralo to samo co Aud0.
Ale po paru minutach takiego odgrywania, glosy tracily synchronizacje.
Dlatego pozniej zmienilem koncepcje.
Na glos/kanal prowadzacy.
I jest jedno przerwanie dla 2 takich samych glosow (dokladnie te same dane tylko dla drugiego kanalu audio), a nie 2 takie same przerwania.
Wtedy juz nie bylo, zadnych problemow z synchronizacja lewego i prawego kanalu.
[#45] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Krashan, post #43

no właśnie tak miałem wcześniej - przez co miałem więcej tych requestów do obsługi.
Teraz mam jeden - i jak się skończy to tylko wskazuje mu który bufor ma teraz grać i daje BeginIO()
z ciągłością odtwarzania nie mam problemów nic nie przycina.. właśnie chciałem żeby dany iorequest grał po prostu równocześnie LEFT1+RIGHT1.
[#46] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Don_Adan, post #44

To chyba tak robię w tym momencie, tylko że ja w C i za pomocą funkcji systemowych.

Ostatnia aktualizacja: 09.10.2025 12:33:54 przez mateusz_s
[#47] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Krashan, post #43

Bo chyba można tez w taki sposób, że wskazujemy podczas alokacji co nas intersuje do zaalokowania,
np. wszsytkie pary L+R, i system wybierze pierwsze dostępne.

channels = { 
LEFT_1 | RIGHT_1,
LEFT_1 | RIGHT_2,
LEFT_2 | RIGHT_1,
LEFT_2 | RIGHT_2 }


Tylko teraz znów powinno się to powtorzyć, dla drugiego requestera
i system powinien wybrać pozostałe wolne..
[#48] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@mateusz_s, post #46

Jak to w C napisac to nie wiem, ale ogolnie o sama koncepcje mi chodzi, jeden glos/kanal obslugujacy lewy i prawy kanal rownoczesnie.
Bo jak 2 glosy byly osobno obslugiwane to nawet jak je wystartujesz rownoczesnie to synchronizacja po jakims czasie nawalala, po paru lub parunastu minutach.
Zwykle tego nie slychac, bo rzadko, ktos slucha tego sam utwor parenascie minut lub dluzej.
No i nie zapomnij zwolnic audio.device na wyjsciu z programu.
Takze przy jakis bledach.
Bo czesc programow ma z tym problem, i nie zwalnia wszystkich zaalokowanych zasobow na wyjsciu z programu.
Przy wyjsciu z bledem tez.

Ostatnia aktualizacja: 09.10.2025 13:28:58 przez Don_Adan
1
[#49] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@mateusz_s, post #47

Opiszę jak to robię w QoaPlay. Kanały Pauli rezerwuję przy otwieraniu audio.device. Potrzebuję dowolnego prawego i dowolnego lewego, więc robię tak jak napisałeś, 4 kombinacje. Oryginalny request, którym otwieram device, pozostaje do wykonywania komend takich jak CMD_STOP, czy CMD_START, bo tam mam od razu ustawioną maskę "moich" kanałów. Natomiast tworzę 4 kopie tego requesta (4, bo mam podwójne buforowanie), dwa dostają kanał lewy, dwa prawy (czyli maskuję odpowiednio ich pola io_Unit). Jeżeli odtwarzam utwór mono, to każda para requestów LR dostaje ten sam bufor w io_Data. Na początku daję CMD_STOP, potem za pomocą dwóch CMD_WRITE wysyłam pierwszą parę requestów i zaraz za nią drugą parę (przypominam - podwójne buforowanie). Następnie idzie CMD_START, co zapewnia synchroniczny start obu kanałów.

Potem następuje typowa pętla, Wait() oczekuje na powracające requesty i gdy tylko wrócą oba z pary, dekoduję do nich kolejny kawałek audio i robię 2 razy CMD_WRITE. Wbrew temu co pisze DonAdan, nie ma ryzyka desynca, chyba, że procesor nie wyrobi się z dekodowaniem i nie wyśle requestów zanim poprzednia para skończy grać. Mam plik QOA, który trwa 30 minut i nie zaobserwowałem desynców.
1
[#50] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Krashan, post #49

Jak nie ma ryzyka desychronizacji?
Na 68000 testowalem i jest.
Oczywiscie testowalem z uzyciem audio interrupt (a nie audio.device), jesli 2 kanaly Audio odgrywaja niezaleznie i dlugotrwale te same dane to po pewnym czasie nastepuje desynchronizacja.
Nawet znalazlem przykladowy modul na Aminecie:

Pierwsza wersja:

link

Druga wersja, poprawiona:

link

Oczywiscie audio.device ma tez problemy z DMA wait, ale zeby to stwierdzic to trzeba miec szybki procesor jak 68030 /68060.
Byc moze kick mapowany do fastu i skomplikowany player, dzialajacy pod audio.device, jak oryginalna wersja MaxTrax.
[#51] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Krashan, post #49

Ale jednego nie rozumiem, przecież jeśli dam CMD_WRITE i prześlę to BeginIO() to dzwiek zaczyna grać od razu. Chyba że jak dałeś wczesniej CMD_STOP to wtedy nie? I trzeba dać CMD_START, tak?
[wyróżniony] [#52] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@mateusz_s, post #51

jeśli dam CMD_WRITE i prześlę to BeginIO() to dzwiek zaczyna grać od razu.
Zgadza się.
Chyba że jak dałeś wczesniej CMD_STOP to wtedy nie? I trzeba dać CMD_START, tak?
Dokładnie tak. Taka sekwencja komend: STOP na kilku kanałach, zestaw WRITE do tych kanałów, START na tych kanałach, służy do synchronicznego wystartowania kilku kanałów (z dokładnością do 1 sampla). Jest to opisane w dokumentacji systemu.
[#53] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Krashan, post #52

dzieki.. to dorzuce te dodatkowe requestery w takim razie, no nic..
[#54] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Don_Adan, post #50

Oczywiscie testowalem z uzyciem audio interrupt (a nie audio.device)
A to nie wiem. Nie zajmuję się programowaniem Pauli na poziomie rejestrów. Jak stwierdzę jakiś problem, będę się zastanawiał. Na razie nie stwierdziłem.
[#55] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Krashan, post #54

A to mozesz (jak chcesz) sprawdzic pierwsza wersje tego customa, czy u Ciebie tez bedzie problem z synchronizacja po pewnym czasie.
Bo moze to jeszcze od czegos innego zalezy, jak np. kickstart, czy jakis uklad Amigi.
Albo cos zle wtedy robilem w obsludze tej muzyki,
Ja mialem kick 2.0 (bodaj 2.04).

Nie wiem, czy znasz ten watek:

link

Tutaj zdaje sie pomyslodawca polegl na niemoznosci (?) synchronizacji lewego i prawego kanalu audio Amigi, zeby uzyskac 14.5 bit.
Bo podobno aktualna wersja 14 bit to maximum 11 bit w rzeczywistosci jest tylko.
[#56] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Don_Adan, post #55

A to mozesz (jak chcesz) sprawdzic pierwsza wersje tego customa,
Nie mam czasu na debugowanie błędów w czyimś kodzie...
Tutaj zdaje sie pomyslodawca polegl na niemoznosci (?) synchronizacji lewego i prawego kanalu audio Amigi
To jest stałe przesunięcie między parą 0-3 i parą 1-2 wynoszące około 6 mikrosekund. Czyli przykładowo dla próbkowania 44,1 kHz to jest opóźnienie o mniej niż 1/3 sampla. To może mieć znaczenie przy tym pracowitym składaniu bitów, żeby mieć pseudo 14-bit, ale nie ma żadnego znaczenia przy odtwarzaniu normalnych danych 8-bitowych.
[#57] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Krashan, post #56

Nie znam sie az tak bardzo, ale chyba da sie odgrywajac i wylaczajac (byc moze parokrotnie w jednej liniii) empty sampel na tym drugim kanale, za pomoca zmiany czestotliwosci/okresu ustawic odpowiednie opoznienie pomiedzy kanalami.
Niektore playery uzywaja okresu 1 jako DMA wait, tylko, ze robia to zwykle tylko 1 raz, a mozna to pare razy zrobic.
[#58] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Krashan, post #56

Ja jestem ciekawy, czy na innych Amigach tez sie traci synchronìzacje po pewnym czasie.
Bo debugowac to tam nie ma raczej czego.
Ta sama procedura byla uzywana w customach, ktore odgrywaja muzyke w stereo i nie ma wtedy, zadnych problemow z synchronizacja bo inne dane sa na kazdym kanale.
Jedyne co mi teraz przychodzi do glowy (w zwiazku z tymi 14.5 bitami) ze bardzo precyzyjny start obu kanalow jest wtedy wymagany.
Ale to raczej bylby wtedy overkill.
[#59] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@Don_Adan, post #58

Na razie brzmi dobrze.
Muzyka jest buforowana z fast i grana na L1+R1,
a sfx-y mieszane w fast i grane na L2+R2.

Całość działa w osobnym tasku nie martwiąc sie WaitTOF()-em w głównej pętli.

Operuje na kawałkach 512b.
Gdy próbka 512b zakończy odtwarzanie następuje równoczesne
'odpalenie' wszystkich kanałów i skopiowanie kolejnego 512b dla muzyki i 512b dla sfx.
Czyli łącznie 1024b na iteracje.
W pętli jest Wait() wiec operacja jest tylko jak dostaniemy sygnal o zakoczeniu grania próbki.

Ale dopiero jak włącze to w shootera to zobaczymy czy mie na jakis fps drop albo czy nie przerywa.
Na razie trzasków nie słychać gdy by w grze sie pojawiły to trzeba by oprawke do miksowania wstawić -
na ten moment tylko sumuje próbki.



Podrzucam kod, może sie przyda komus (jeszcze musze opisy poprawić),
a może jakiegoś babola znajdziecie :P
// Amiga includes.
#include <proto/exec.h>
#include <proto/dos.h>
#include <devices/audio.h>
#include <clib/alib_protos.h>
#include <graphics/gfxbase.h>

// Standard includes.
#include <stdlib.h>

// ---------------
// --- Globals ---
// ---------------
#define sys_audio__FREQUENCY                    22050   // Fixed frequency for all sounds.

#define sys_audio__CHUNK_SIZE                   512                                                                     // Operational chunk size in bytes for music. This amount will be copied each frame to one of the buffers. 

#define sys_audio__MUS_CHIP_BUFFER_SIZE         (sys_audio__CHUNK_SIZE * 2)

#define sys_audio__SFX_CHIP_BUFFER_SIZE			(sys_audio__CHUNK_SIZE * 2)                                         // Continuous buffer in CHIP mem. made of two chunks.           
#define sys_audio__SFX_FAST_BUFFER_SIZE			(sys_audio__CHUNK_SIZE * 50 * 3)                                    // Size in bytes. Chunks multiplied by 50*3, that gives ~2 secs. of space. This determines the maximum sample lenght.

// Amiga audio channel allocation bits.
#define sys_audio__CHANNEL_LEFT_1     			1
#define sys_audio__CHANNEL_RIGHT_1    			2
#define sys_audio__CHANNEL_RIGHT_2     			4
#define sys_audio__CHANNEL_LEFT_2    			8

static UBYTE    sys_audio__channels[] = { 15 };     // 15 for allocating all channels.

// Enumerating all IO Audio request blocks we need.
enum {  sys_audio__CONTROL,     // For volume control.

        sys_audio__MUS_LEFT,     // For switching music buffers.
        sys_audio__MUS_RIGHT,     // For switching music buffers.

        sys_audio__SFX_LEFT,     // For switching sfx buffers.
        sys_audio__SFX_RIGHT,     // For switching sfx buffers.

		sys_audio__COUNT };

// Message ports and signal masks.
// One message port for each io audio request block.
static struct MsgPort* sys_audio__mp[sys_audio__COUNT];
static ULONG           sys_audio__mp_signal_mask[sys_audio__COUNT];

// IO Audio request blocks.
static struct IOAudio* sys_audio__io[sys_audio__COUNT];

// Buffer in fast ram that will be used for mixing sfx samples
// and hold them until they are copied to chip ram.
static BYTE     *sys_audio__fast_buf;

// One continuous buffer in CHIP mem. that will be splitted
// into two equal buffers for music and two equal for sfx.
static BYTE     *sys_audio__chip_buf__mus[2];
static BYTE     *sys_audio__chip_buf__sfx[2];

struct Task*    sys_audio__main_task;
struct Task*    sys_audio__audio_task;

static ULONG    sys_audio__audio_task__result;
BYTE            sys_audio__audio_task__signal;
ULONG           sys_audio__audio_task__signal_mask;
LONG            sys_audio__audio_task__loop;

static ULONG    sys_audio__audio_device_result;
volatile LONG   sys_audio__chunk_offset;

static char*    sys_audio__mus_source;
static LONG     sys_audio__mus_size;
static LONG     sys_audio__mus_started;
static LONG     sys_audio__mus_chunk_offset;

int test  = -1;

// ------------------------------------
// --- Private function definitions ---
// ------------------------------------
int     sys_audio__audio_task__create(void)
{
    // Get clock value, PAL or NTSC. 
    LONG gfxbase_clock;

    struct GfxBase *GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L);
    if (GfxBase == 0L)
        return 0;

    if (GfxBase->DisplayFlags & PAL)    gfxbase_clock = 3546895L;     // PAL clock
    else                                gfxbase_clock = 3579545L;     // NTSC clock

    if (GfxBase)
        CloseLibrary( (struct Library *) GfxBase);

    // 01.
    // Alloc fast ram buffer that will be used for mixing and holding mixed samples.
    sys_audio__fast_buf = (BYTE*)AllocMem( sys_audio__SFX_FAST_BUFFER_SIZE, MEMF_PUBLIC | MEMF_CLEAR );
    if (sys_audio__fast_buf == NULL) 
		return 0;

    // 02.
    // Allocate one continuous buffer and assign correct pointers.
    // Sound samples to be played, must be in CHIP mem.
    sys_audio__chip_buf__mus[0] = (BYTE*)AllocMem( sys_audio__MUS_CHIP_BUFFER_SIZE + sys_audio__SFX_CHIP_BUFFER_SIZE, MEMF_CHIP | MEMF_CLEAR );
    if (sys_audio__chip_buf__mus[0] == NULL) 
		return 0;

    // 03. 
    // Assign correct pointers.       
    sys_audio__chip_buf__mus[1] = sys_audio__chip_buf__mus[0] + (sys_audio__MUS_CHIP_BUFFER_SIZE / 2);
    sys_audio__chip_buf__sfx[0] = sys_audio__chip_buf__mus[1] + (sys_audio__SFX_CHIP_BUFFER_SIZE / 2);
    sys_audio__chip_buf__sfx[1] = sys_audio__chip_buf__sfx[0] + (sys_audio__SFX_CHIP_BUFFER_SIZE / 2);

    if (sys_audio__chip_buf__mus[1] == NULL || sys_audio__chip_buf__sfx[0] == NULL || sys_audio__chip_buf__sfx[1] == NULL)
        return 0;

    // 04.
    // Create message ports.
    for (int i = 0; i < sys_audio__COUNT; i++)
    {
        sys_audio__mp[i] = CreateMsgPort();    
	    if (sys_audio__mp[i] == NULL) 
            return 0;
    }

    // Save the signal masks.
    for (int i = 0; i < sys_audio__COUNT; i++)
        sys_audio__mp_signal_mask[i] = 1L << sys_audio__mp[i]->mp_SigBit;

    // 05.
    // Alloc memory for IO Audio Request Blocks.
    // One continuous block that will be splitted.
 	sys_audio__io[sys_audio__CONTROL] = (struct IOAudio *)AllocMem( sizeof(struct IOAudio) * sys_audio__COUNT, MEMF_PUBLIC | MEMF_CLEAR );
	if (sys_audio__io[sys_audio__CONTROL] == NULL) 
        return 0;

    // 06.
    // Assign correct pointers.
    sys_audio__io[sys_audio__MUS_LEFT] = sys_audio__io[sys_audio__CONTROL] + 1;
    sys_audio__io[sys_audio__MUS_RIGHT] = sys_audio__io[sys_audio__MUS_LEFT] + 1;
	
    sys_audio__io[sys_audio__SFX_LEFT] = sys_audio__io[sys_audio__MUS_RIGHT] + 1;
    sys_audio__io[sys_audio__SFX_RIGHT] = sys_audio__io[sys_audio__SFX_LEFT] + 1;

    if (    sys_audio__io[sys_audio__MUS_LEFT] == NULL || sys_audio__io[sys_audio__MUS_RIGHT] == NULL ||
            sys_audio__io[sys_audio__SFX_LEFT] == NULL || sys_audio__io[sys_audio__SFX_RIGHT] == NULL )
        return 0;

    // Lets open audio device using MUS_CONTROL.
	sys_audio__io[sys_audio__CONTROL]->ioa_Request.io_Message.mn_Node.ln_Type   	= 127;
    sys_audio__io[sys_audio__CONTROL]->ioa_Request.io_Message.mn_ReplyPort	   		= sys_audio__mp[sys_audio__CONTROL];
    sys_audio__io[sys_audio__CONTROL]->ioa_Request.io_Message.mn_Length		        = sizeof(struct IOAudio);
    sys_audio__io[sys_audio__CONTROL]->ioa_Request.io_Command				    	= ADCMD_ALLOCATE;
    sys_audio__io[sys_audio__CONTROL]->ioa_Request.io_Flags				            = ADIOF_NOWAIT;
    sys_audio__io[sys_audio__CONTROL]->ioa_Length						        	= sizeof(sys_audio__channels);
    sys_audio__io[sys_audio__CONTROL]->ioa_Data						                = sys_audio__channels;

    // 07.
  	sys_audio__audio_device_result = OpenDevice("audio.device", 0, (struct IORequest*)sys_audio__io[sys_audio__CONTROL], 0);
    if (sys_audio__audio_device_result != 0)  
        return 0;

    // Copy all sttucture to the remaining structures. Keeping the generated allocation key.
    *sys_audio__io[sys_audio__MUS_LEFT]     = *sys_audio__io[sys_audio__CONTROL];
    *sys_audio__io[sys_audio__MUS_RIGHT]    = *sys_audio__io[sys_audio__CONTROL];

    *sys_audio__io[sys_audio__SFX_LEFT]     = *sys_audio__io[sys_audio__CONTROL];
    *sys_audio__io[sys_audio__SFX_RIGHT]    = *sys_audio__io[sys_audio__CONTROL];

    // Setup MUS_CONTROL.
    sys_audio__io[sys_audio__CONTROL]->ioa_Request.io_Message.mn_ReplyPort     = sys_audio__mp[sys_audio__CONTROL];
    sys_audio__io[sys_audio__CONTROL]->ioa_Request.io_Unit                     = (APTR)(sys_audio__CHANNEL_LEFT_1 | sys_audio__CHANNEL_RIGHT_1 | sys_audio__CHANNEL_LEFT_2 | sys_audio__CHANNEL_RIGHT_2);

    // Setup MUS_LEFT.
    // Using LEFT 1 audio channel.
    sys_audio__io[sys_audio__MUS_LEFT]->ioa_Request.io_Message.mn_ReplyPort     = sys_audio__mp[sys_audio__MUS_LEFT];
	sys_audio__io[sys_audio__MUS_LEFT]->ioa_Request.io_Command  				= CMD_WRITE;
	sys_audio__io[sys_audio__MUS_LEFT]->ioa_Request.io_Flags					= ADIOF_PERVOL;
    sys_audio__io[sys_audio__MUS_LEFT]->ioa_Request.io_Unit                     = (APTR)(sys_audio__CHANNEL_LEFT_1);
	sys_audio__io[sys_audio__MUS_LEFT]->ioa_Period			    				= (UWORD)( gfxbase_clock / sys_audio__FREQUENCY );
	sys_audio__io[sys_audio__MUS_LEFT]->ioa_Volume			    				= 48;
	sys_audio__io[sys_audio__MUS_LEFT]->ioa_Cycles			    				= 1;
	sys_audio__io[sys_audio__MUS_LEFT]->ioa_Length			   					= (sys_audio__MUS_CHIP_BUFFER_SIZE / 2);
	sys_audio__io[sys_audio__MUS_LEFT]->ioa_Data   								= sys_audio__chip_buf__mus[0];

    // Setup MUS_RIGHT.
    // Same as MUS_LEFT, but using RIGHT 1 sudio channel
    // and separate message port.
    *sys_audio__io[sys_audio__MUS_RIGHT] = *sys_audio__io[sys_audio__MUS_LEFT];

    sys_audio__io[sys_audio__MUS_RIGHT]->ioa_Request.io_Message.mn_ReplyPort    = sys_audio__mp[sys_audio__MUS_RIGHT];
    sys_audio__io[sys_audio__MUS_RIGHT]->ioa_Request.io_Unit                    = (APTR)(sys_audio__CHANNEL_RIGHT_1);

    // Setup SFX_LEFT.
    // Using LEFT 2 audio channel.
    sys_audio__io[sys_audio__SFX_LEFT]->ioa_Request.io_Message.mn_ReplyPort     = sys_audio__mp[sys_audio__SFX_LEFT];
	sys_audio__io[sys_audio__SFX_LEFT]->ioa_Request.io_Command  				= CMD_WRITE;
	sys_audio__io[sys_audio__SFX_LEFT]->ioa_Request.io_Flags					= ADIOF_PERVOL;
    sys_audio__io[sys_audio__SFX_LEFT]->ioa_Request.io_Unit                     = (APTR)(sys_audio__CHANNEL_LEFT_2);
	sys_audio__io[sys_audio__SFX_LEFT]->ioa_Period			    				= (UWORD)( gfxbase_clock / sys_audio__FREQUENCY );
	sys_audio__io[sys_audio__SFX_LEFT]->ioa_Volume			    				= 48;
	sys_audio__io[sys_audio__SFX_LEFT]->ioa_Cycles			    				= 1;
	sys_audio__io[sys_audio__SFX_LEFT]->ioa_Length			   					= sys_audio__CHUNK_SIZE;
	sys_audio__io[sys_audio__SFX_LEFT]->ioa_Data   								= sys_audio__chip_buf__sfx[0];

    // Setup SFX_RIGHT.
    // Same as SFX_LEFT, but using RIGHT 2 sudio channel
    // and separate message port.
    *sys_audio__io[sys_audio__SFX_RIGHT] = *sys_audio__io[sys_audio__SFX_LEFT];

    sys_audio__io[sys_audio__SFX_RIGHT]->ioa_Request.io_Message.mn_ReplyPort    = sys_audio__mp[sys_audio__SFX_RIGHT];
    sys_audio__io[sys_audio__SFX_RIGHT]->ioa_Request.io_Unit                    = (APTR)(sys_audio__CHANNEL_RIGHT_2);

    return 1;
}
void    sys_audio__audio_task__destroy(void)
{
    for (int i = 0; i < sys_audio__COUNT; i ++)
        AbortIO((struct IORequest*)sys_audio__io[i]);

    // Unqueqe message ports.
    for (int i = 0; i < sys_audio__COUNT; i ++)
        while (GetMsg(sys_audio__mp[i])) {};

    // 07.
	if (sys_audio__audio_device_result == 0)
	    CloseDevice( (struct IORequest*)sys_audio__io[sys_audio__CONTROL] );

    // 06.
    sys_audio__io[sys_audio__MUS_LEFT] = NULL;  
    sys_audio__io[sys_audio__MUS_RIGHT] = NULL;  

    sys_audio__io[sys_audio__SFX_LEFT] = NULL;  
    sys_audio__io[sys_audio__SFX_RIGHT] = NULL;  

    // 05.
	if (sys_audio__io[sys_audio__CONTROL])
    {
		FreeMem( sys_audio__io[sys_audio__CONTROL], sizeof(struct IOAudio) * sys_audio__COUNT );
        sys_audio__io[sys_audio__CONTROL] = NULL;
    }

    // 04.
    for (int i = 0; i < sys_audio__COUNT; i ++)
        if (sys_audio__mp[i]) 
        {
            DeleteMsgPort(sys_audio__mp[i]);
            sys_audio__mp[i] = NULL;
        }


    // 03.
    sys_audio__chip_buf__sfx[1] = NULL;
    sys_audio__chip_buf__sfx[0] = NULL; 
    sys_audio__chip_buf__mus[1] = NULL; 

    // 02.
    if (sys_audio__chip_buf__mus[0])
    {
        FreeMem( sys_audio__chip_buf__mus[0], sys_audio__MUS_CHIP_BUFFER_SIZE + sys_audio__SFX_CHIP_BUFFER_SIZE );
        sys_audio__chip_buf__mus[0] = NULL;
    }
    
    // 01.
    if (sys_audio__fast_buf)
    {
        FreeMem( sys_audio__fast_buf, sys_audio__SFX_FAST_BUFFER_SIZE );
        sys_audio__fast_buf = NULL;
    }
}
void    sys_audio__audio_task__func(void)
{
    sys_audio__audio_task__result = sys_audio__audio_task__create();

    if (sys_audio__audio_task__result == 0)
    {
        sys_audio__audio_task__destroy();
        return;
    }

    // Send the signal to main task, that initialization is finished
    // and the result can be checked.
    Signal(sys_audio__main_task, sys_audio__audio_task__signal_mask);

    // ----------------------------
    // --- Audio task main loop --- 
    // ----------------------------

	LONG swap_sfx = 0;
    LONG chunk_offset_to_erase = 0;

    sys_audio__chunk_offset = 0;

    // Trigger SFX_BUFFERS to start the routine.
    sys_audio__io[sys_audio__CONTROL]->ioa_Request.io_Command = CMD_STOP;
    DoIO((struct IORequest*)sys_audio__io[sys_audio__CONTROL]);

	BeginIO((struct IORequest*)sys_audio__io[sys_audio__SFX_LEFT]);
    BeginIO((struct IORequest*)sys_audio__io[sys_audio__SFX_RIGHT]);

    sys_audio__io[sys_audio__CONTROL]->ioa_Request.io_Command = CMD_START;
    DoIO((struct IORequest*)sys_audio__io[sys_audio__CONTROL]);

    // To break the loop before closing up everything,
    // the main program will set sys_audio__audio_task__loop to 0
    // and send a simple IO request to sys_audio__MUS_CONTROL to move out from Wait()
    // and check the while condition.
    sys_audio__audio_task__loop = 1;

    while(sys_audio__audio_task__loop)
    {
	    ULONG signals = Wait(   sys_audio__mp_signal_mask[sys_audio__CONTROL]       |

                                sys_audio__mp_signal_mask[sys_audio__MUS_LEFT]      |
                                sys_audio__mp_signal_mask[sys_audio__MUS_RIGHT]     |

                                sys_audio__mp_signal_mask[sys_audio__SFX_LEFT]      |
                                sys_audio__mp_signal_mask[sys_audio__SFX_RIGHT] );
        
        // -----------------------------------------
        // --- Getting a signal from MUS_CONTROL ---
        // -----------------------------------------

        if ( signals & sys_audio__mp_signal_mask[sys_audio__CONTROL] )
            while(GetMsg(sys_audio__mp[sys_audio__CONTROL]));

        // ---------------------------------------
        // --- Getting a signal from SFX_RIGHT ---
        // ---------------------------------------

        // Only dispatching the message port.
        if ( signals & sys_audio__mp_signal_mask[sys_audio__MUS_RIGHT] )
            while(GetMsg(sys_audio__mp[sys_audio__MUS_RIGHT]));

        if ( signals & sys_audio__mp_signal_mask[sys_audio__MUS_LEFT] )
            while(GetMsg(sys_audio__mp[sys_audio__MUS_LEFT]));

        // ---------------------------------------
        // --- Getting a signal from SFX_RIGHT ---
        // ---------------------------------------

        // Only dispatching the message port.
        if ( signals & sys_audio__mp_signal_mask[sys_audio__SFX_RIGHT] )
            while(GetMsg(sys_audio__mp[sys_audio__SFX_RIGHT]));

        // --------------------------------------
        // --- Getting a signal from SFX_LEFT ---
        // --------------------------------------

        // When signal is recieved, SFX_LEFT (and most probably also SFX_RIGHT) request has finished playing.
        // To keep both channels synchronized first we send CMD_STOP to SFX_CONTROL - it works on both channels,
        // so both channels will stop play but also the CMD_WRITE from BeginIO() wont trigger them. 
        // We can swap the buffers and set CMD_WRITE thru BeginIO() for both.
        // Now sending CMD_START will play both channels the same time.

        // Also its time to copy new chunk from fast to not used chip buffer
        // and erase previous chunk from fast buffer.
        
        if ( signals & sys_audio__mp_signal_mask[sys_audio__SFX_LEFT] ) 
		{
            // Dispatching the message port.
			while(GetMsg(sys_audio__mp[sys_audio__SFX_LEFT]));

            // Stop playing both SFX channels.
            sys_audio__io[sys_audio__CONTROL]->ioa_Request.io_Command = CMD_STOP;
            DoIO((struct IORequest*)sys_audio__io[sys_audio__CONTROL]);

            // Swap buffers and send request.
            // Now the info is written but the channels wont play.
            sys_audio__io[sys_audio__SFX_LEFT]->ioa_Data = sys_audio__chip_buf__sfx[swap_sfx^1];
            sys_audio__io[sys_audio__SFX_RIGHT]->ioa_Data = sys_audio__chip_buf__sfx[swap_sfx^1];

            sys_audio__io[sys_audio__MUS_LEFT]->ioa_Data = sys_audio__chip_buf__mus[swap_sfx^1];
            sys_audio__io[sys_audio__MUS_RIGHT]->ioa_Data = sys_audio__chip_buf__mus[swap_sfx^1];

            BeginIO((struct IORequest*)sys_audio__io[sys_audio__SFX_LEFT]);
            BeginIO((struct IORequest*)sys_audio__io[sys_audio__SFX_RIGHT]);

            BeginIO((struct IORequest*)sys_audio__io[sys_audio__MUS_LEFT]);
            BeginIO((struct IORequest*)sys_audio__io[sys_audio__MUS_RIGHT]);
            

            // Now start playing both channels at the same time.
            sys_audio__io[sys_audio__CONTROL]->ioa_Request.io_Command = CMD_START;
            DoIO((struct IORequest*)sys_audio__io[sys_audio__CONTROL]);

            // Copy chunk of mixed data from fast to not using chip buffer.
            memcpy(sys_audio__chip_buf__sfx[swap_sfx], sys_audio__fast_buf + sys_audio__chunk_offset, sys_audio__CHUNK_SIZE);

            // Is it safe to increase the offset?
            // This value is used in main program - dont optimize it. Never exceed the max offset.
            if (sys_audio__chunk_offset < sys_audio__SFX_FAST_BUFFER_SIZE - sys_audio__CHUNK_SIZE)
            {
                sys_audio__chunk_offset += sys_audio__CHUNK_SIZE;
                
                if (sys_audio__chunk_offset > 0)    chunk_offset_to_erase = sys_audio__chunk_offset - sys_audio__CHUNK_SIZE;
                else                                chunk_offset_to_erase = sys_audio__SFX_FAST_BUFFER_SIZE - sys_audio__CHUNK_SIZE;
            }
            else
            {
                sys_audio__chunk_offset = 0;
                chunk_offset_to_erase = sys_audio__SFX_FAST_BUFFER_SIZE - sys_audio__CHUNK_SIZE;
            }
        
            // Clear previous chunk in fast mem. So we won't mix in future with some trash.
            memset(sys_audio__fast_buf + chunk_offset_to_erase, 0, sys_audio__CHUNK_SIZE);


            if (sys_audio__mus_started)
            {
                sys_audio__mus_chunk_offset += sys_audio__CHUNK_SIZE;
                memcpy(sys_audio__chip_buf__mus[swap_sfx], sys_audio__mus_source + sys_audio__mus_chunk_offset, sys_audio__CHUNK_SIZE);
            }


            swap_sfx ^= 1;
        }
    }

    // Cleanup.
    sys_audio__audio_task__destroy();

    // After everything is cleaned up send the signal to the main task.
    Signal(sys_audio__main_task, sys_audio__audio_task__signal_mask);

    // Dont finish the task.
    // It will be deleted in the main task.
    Wait(0);

    return;
}

// -----------------------------------
// --- Public function definitions ---
// -----------------------------------
int     SYSTEM_audio__create(void)
{
    sys_audio__mus_started = 0;

    // Create separate thread/task for switching audio buffers and double buffer routines.
    // It's because this can't be affected by WaitTOF() in the main game loop.
 
    // Find main task.
    sys_audio__main_task = FindTask(NULL);

    // Create a signal to communicate with audio task.
    sys_audio__audio_task__signal = AllocSignal(-1);
    sys_audio__audio_task__signal_mask = 1L << sys_audio__audio_task__signal;

    // Create separate audio task.
    sys_audio__audio_task = (struct Task*)CreateTask("audio_task", 10, (APTR)sys_audio__audio_task__func, 4096);
	if (sys_audio__audio_task == NULL) return 0;

    // Wait for a signal from the audio task, while it is initializing.
    Wait(sys_audio__audio_task__signal_mask);

    // The result of initialisation.
    if (sys_audio__audio_task__result == 0)
        return 0;

    return 1;
}
void    SYSTEM_audio__destroy(void)
{
    // Send signal to audio task to finish its audio main loop.
    sys_audio__audio_task__loop = 0;
    Signal(sys_audio__audio_task, sys_audio__mp_signal_mask[sys_audio__CONTROL]);

    // Now wait for signal fro audio task.
    // It will send signal when it finish cleaning up.
    Wait(sys_audio__audio_task__signal_mask);

    // Finish audio task manually.
    if (sys_audio__audio_task)
    {
        Forbid();
        DeleteTask(sys_audio__audio_task);
        Permit();
        sys_audio__audio_task = NULL;
    }

    FreeSignal(sys_audio__audio_task__signal);
}

void    SYSTEM_audio__mus_play(char* _sample, int _size)
{
    sys_audio__mus_source = _sample;
    sys_audio__mus_size = _size;
    sys_audio__mus_started = 1;
}
void    SYSTEM_audio__sfx_play(char* _sample, int _size)
{
    // Copy desired sample from source fast buffer to mixing fast buffer
    // and perform the mixing.

    // Checking if the desired sample will fit into fast buffer.
    // Current position in fast buffer is: sys_audio__chunk_offset.

    volatile LONG chunk_offset = sys_audio__chunk_offset;

    LONG size_remain = (sys_audio__SFX_FAST_BUFFER_SIZE - chunk_offset);
	LONG difference = size_remain - _size;

    if (difference > 0)
    {
        // Will fit.
       BYTE *ptr = sys_audio__fast_buf + chunk_offset;

        // Mix to the end of sample. We wont exceed the fast buffer.
        for (int i = 0; i < _size; i++)
            ptr[i] += _sample[i];
    }
    else
    {
        // Won't fit, lets split.
        BYTE *ptr = sys_audio__fast_buf + chunk_offset;

        // Mix to the end of fast buffer.
        for (int i = 0; i < size_remain; i++)
            ptr[i] += _sample[i];

        // Mix the rest from the start of fast buffer.
       for (int i = 0; i < -difference; i++)
            sys_audio__fast_buf[i] += _sample[size_remain + i];
    }
}
[#60] Re: [C] Kilka pytań odnośnie używania muzyki i dzwięków..

@mateusz_s, post #59

zastanawiam się tylko czy w przypadku muzyki operowanie na dwóch buforach po 512b to nie za mało.
Przy sfx się sprawdza, ale może muzyka powinna mieć większy zapas.
Musiałbym wtedy przenieść buforowanie muzyki z tego osobnego tasku do pętli głównej żeby sobie co klatke uzupełłniało wiekszy bufor..
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