kategoria: ANSI C
[#31] Re: Granie przez audio.device

@asman, post #29

A propos kombinacji WaitPort/GetMsg, to masz na myśli WaitPort a potem w pętli odbieranie wiadomości GetMsg aż będzię null ?


Teoretycznie tak, ale w tym wypadku wystarczy jedno GetMsg bez petli, bo grasz tylko jednym IORequestem :)

Swoja droga, w funkcji PaulaPlay jest ten sam blad. Wolana jest funkcja AbortIO a nastepnie IORequest jest *natychmiast* przerabiany, bez zadnego WaitIO().
[#32] Re: Granie przez audio.device

@mschulz, post #31

@Hexmage960, @mschulz

Dzięki za info.

Tak dla jasności trzeba zrobić WaitPort i jeden GetMsg w tym przypadku, bo na podstawie posta #20 trzeba zawsze używać WaitPort bądź Wait dla audio device.

Wniosek taki że w moim artykule jest błąd. Będę musiał popracować nad tym a co gorsza znaleźć na to czas.

Edit: I tak ogólnie to dzięki wszystkim udzielającym się, bo coś można z tego wynieść pozytywnego.

Ostatnia aktualizacja: 08.02.2017 10:21:16 przez asman
[#33] Re: Granie przez audio.device

@asman, post #27

Nie rozumiem czemu sprawdzasz czy udało się stworzyć iorequest dla AudioIO[1] a dla Audio[0] już nie.


Nie wiem czy dobrze zalozylem (bo w programowaniu nie mozna byc wszystkiego pewnym) ze jesli wykonuje po sobie ciag tych samych funkcji to jesli ostatnia sie powiodla to poprzednie tez musialy. Ale OK, zmienie to.

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.


Jesli jestes tego pewny to ten fragment tez zmienie dla uproszczenia.
[#34] Re: Granie przez audio.device

@Phibrizzo, post #33

Nie wiem czy dobrze zalozylem


Nie...

jesli wykonuje po sobie ciag tych samych funkcji to jesli ostatnia sie powiodla to poprzednie tez musialy.


Byc moze moglbys tak zalozyc programujac pod DOS na PC, albo pod jakis inny system bez wielozadaniowosci. Skoro programujesz pod system wielozadaniowy sprawdzaj kazda alokacje z osobna.

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.

Jesli jestes tego pewny to ten fragment tez zmienie dla uproszczenia.


Ma racje. Podanie NULL-a do CreateIORequest jest legalne i wtedy tez bedzie zwrocony NULL. Ale i tak jak dla mnie takie rozwiazanie jest nieeleganckie. Gdyby sprawdzenie stworzenia portu bylo jakies cholernie skomplikowane, zzeralo 100000 cykli cpu lub cos w ten desen to jeszcze bym ten argument zrozumial. Ale tak? Dwoch instrukcji CPU albo jednego if-a w C ci szkoda?
[#35] Re: Granie przez audio.device

@mschulz, post #34

Musze przyznać, że jakoś nad tym się nie zastanawiałem, myślałem że uniknięcie jednego ifa to świetna okazja by kod był prostszy. Ale w sumie jak ktoś zacznie go przeglądać to będzie się zastanawiał czy autor nie popełnił błędu bo nie ma sprawdzania w funkcji tworzącej coś.
Dzięki za naprostowanie mnie. :)
[#36] Re: Granie przez audio.device

@asman, post #35

Musze przyznać, że jakoś nad tym się nie zastanawiałem, myślałem że uniknięcie jednego ifa to świetna okazja by kod był prostszy.


W sumie tak, zwlaszcza kiedy trzeba upchac kod w miejscu o ograniczonej pojemnosci (kickstart). W takim miejscu przerzucenie jednego if-a/dwoch instrukcji do CreateIORequest na pewno pomoglo zaoszczedzic troche cennej pamieci, tak samo zreszta jak prywatna funkcja TaggedOpenLibrary w exec-u :)

Ale w sumie jak ktoś zacznie go przeglądać to będzie się zastanawiał czy autor nie popełnił błędu bo nie ma sprawdzania w funkcji tworzącej coś.


Albo autor sie przyzwyczai do niesprawdzania tego co mu funkcja systemowa zwrocila. Albo sie zapomni i pomiedzy CreateMsgPort a CreateIORequest zacznie z portu korzystac z jakiegos powodu bez sprawdzania czy dalo sie go alokowac. Albo jeszcze wiele innych "albo" :)
[#37] Re: Granie przez audio.device

@Hexmage960, post #30

Obawaim sie ze to chyba jednak nie tak.

Nie mozna dac po AbortIO zadnego Waita a tym bardziej GetMsg().
Gdy tak zrobilem, program wpadl w matrwa petle i takie zachowanie by sie zgadzalo z tym co napisali tu:

link

Zacytuje:

Wait() and WaitPort()
These functions can be used to put your task to sleep while a sound plays. Wait() takes a wake-up mask as its argument. The wake-up mask is usually the mp_SigBit of a MsgPort that you have set up to get replies back from the audio device.

WaitPort() will put your task to sleep while a sound plays. The argument to WaitPort() is a pointer to a MsgPort that you have set up to get replies back from the audio device.


Tak wiec po AbortIO mozna sobie czekac do smierci.

Ponadto:
AbortIO()
This function can be used to cancel requests for ADCMD_ALLOCATE, ADCMD_LOCK, CMD_WRITE, or ADCMD_WAITCYCLE. When used with the audio device, AbortIO() always succeeds.
[#38] Re: Granie przez audio.device

@Phibrizzo, post #37

Po AbortIO() powinieneś dać WaitIO(), a nie Wait(). Ta pierwsza funkcja natychmiast wychodzi, jeżeli request jest zakończony/przerwany.
[#39] Re: Granie przez audio.device

@Phibrizzo, post #37

Przede wszystkim dzięki za linka. I z tego co widzę to tam później jest kod o który mi chodzi
AbortIO((struct IORequest *)AudioIO);  /* Abort any pending requests */
WaitPort(AudioMP);                     /* Wait for abort message */
GetMsg(AudioMP);                       /* Get abort message */


Próbowałeś powyższego kodu ? Ja dopiero w piątek znajdę chwilę by to sprawdzić w Boxo i w Bobbo.
[#40] Re: Granie przez audio.device

@asman, post #39

Tak, probowalem. I dzieje sie dokladnie to samo czyli freez systemu, ale nie od razu tyllko za jakis czas, np po pieciokrotnym odtworzeniu sampla.

Z moich doswiadczen wynika ze najlepiej po AbortIO() nie dawac nic, nawet WaitIO() jak radzil Krashan (dokladne ten sam efekt).

Napewno ten problem rozwiazalo otwarcie dla drugiego kanalu drugiego portu jak radzil Hex.

Moze cos robie zle, sam juz nie wiem.

Jak dalej beda takie problemy to poprostu dwa razy otworze audio.device, po jeden na kanal. zobacze jaki bedzie efekt.

Ostatnia aktualizacja: 09.02.2017 16:48:05 przez Phibrizzo
[#41] Re: Granie przez audio.device

@Phibrizzo, post #40

Nie chcę gdybać i spekulować co jest źle bo mogę być w błędzie. Jeśli możesz to wyślij mi cały Twój projekt na mejla, to przysiądę do tego.
[#42] Re: Granie przez audio.device

@Phibrizzo, post #40

Również chciałbym pomóc, ale potrzebuję widzieć zaktualizowany kod źródłowy.

Być może WaitIO() w przypadku audio.device rzeczywiście nie jest potrzebne. Dlaczego? Dlatego, że to wynika pośrednio z poniższego fragmentu dokumentacji audio.device:

ADCMD_FINISH

The ADCMD_FINISH command aborts (calls AbortIO()) the current write request on a channel or channels. This is useful if you have something playing, such as a long buffer or some repetitions of a buffer, and you want to stop it.

Wygląda na to, że AbortIO() wystarczy.
Możesz też skorzystać z tego polecenia zamiast AbortIO() do zatrzymania odtwarzanego dźwięku.

Ostatnia aktualizacja: 09.02.2017 21:38:00 przez Hexmage960
[#43] Re: Granie przez audio.device

@Hexmage960, post #42

Bardzo mi przykro ale nie mogę zrozumieć co napisałeś, mimo szczerych chęci. Przecież w poście #20 napisałeś że w przypadku Audio device trzeba używać Wait lub WaitPort i nawet linki do doków podałeś. A teraz wypisujesz że WaitIO jest niepotrzebne. Potem na podstawie tego dochodzisz do absurdalnego wniosku, którego też nie mogę pojąć a czytałem to chyba ze 20 razy w każdą stronę. W jaki sposób nawet pośredni na podstawie tego co zacytowałeś o ADCMD_FINISH wynika że WaitIO nie jest potrzebne, przy błędnym założeniu że jednak możemy używać WaitIO. Na pewno nie wynika to z tego że WaitIO nie zostało wspomniane w tym cytacie.

Wczoraj sprawdziłem u siebie jak podchodzę do tematu audio.device w Bobbo (klonie Robbo) i tam wszystko działa jak trzeba z AbortIO, WaitPort i GetMsg. Tam też używam ADCMD_FINISH i też działa bez problemu (10 minut gry). Po zamianie na AbortIO WaitPort i GetMsg jest także ok. Problem leży w tym że ja używam jednego Portu i jednego IO requesta. A Phibrizzo używa jednego portu i dwóch IO requestów. Przy czym odbiera tylko jeden, bo tak mu też błędnie podpowiedziałem, za co przepraszam. W każdym razie mamy dwa requesty i musimy użyć pętli by odebrać wszystkie mesgi. Takie jest moje podejrzenie w tym temacie i to trzeba jeszcze sprawdzić. Poza tym trzeba wziąć jeszcze jedną rzecz pod uwagę, wysyłamy requesta a potem sprawdzamy czy możemy go przerwać za pomocą AbortIO, ale po prawdzie to który request mamy sprawdzać ? Ten który jest aktualnie wykonywany ? Dodatkowo z tego co widze to te dwa requesty są takie same nie różnią się Channelem a chyba powinny jeśli chcemy grać to na jednym a to na drugim.

Wklejam tu kod z Bobbo dotyczący audio.

Edit: Tam też jest kod dotyczący AHI - mówię to tak na wszelki przypadek żeby nie było pomyłki,

#include "sound.h"
#include "resources.h"

#include <clib/alib_protos.h>
#include <proto/exec.h>
#include <proto/exec.h>
#include <devices/audio.h>
#include <devices/ahi.h>

extern int g_bSoundType;
/*==========================================================================*/

typedef struct
{
	int prio;

} AudioChannel;

static struct MsgPort* m_pMsgAudioPort = NULL;
static struct IOAudio* m_pAudioIO = NULL;


static BYTE* m_SfxData[15];

static LONG m_clock = 3546895;	//clock constant for PAL

static UBYTE whichannel[] = { 1,2,4,8 };

static AudioChannel sfxChannel;


static int m_sfxTabPrio[15] =
{
	15,
	2,
	1,
	12,
	11,
	10,
	9,
	8,
	7,
	6,
	5,
	4,
	3,
	15,
	13,

	/*
		SND_BOOM = 0,
		SND_SHOT = 1,
		SND_STUK = 2,
		SND_TELEPORT = 3,
		SND_SCREW = 4,
		SND_LIFE = 5,
		SND_DOOR = 6,
		SND_BULLETS = 7,
		SND_BOX = 8,
		SND_KEY = 9,
		SND_KILL = 10,
		SND_BEGIN = 11,
		SND_UKN = 12,
		SND_EXIT = 13,
		SND_MAGNES = 14,
	*/

};

static void PlayAhiSfx(int sfxNumber);
static void PlayPaulaSfx(int sfxNumber);

/*------------------------------------------------------*/
static int initSoundPaula(void);
static void killSoundPaula(void);

static int initSoundAhi(void);
static void killSoundAhi(void);

static struct MsgPort* m_pAhiMp = NULL;
static struct AHIRequest* m_pAhiIO = NULL;
static BYTE m_AhiDevice = 0;
/*==========================================================================*/

void PlaySfx(int sfxNumber)
{
	if (SOUND_PAULA == g_bSoundType)
	{
		PlayPaulaSfx(sfxNumber);
	}
	else if (SOUND_AHI == g_bSoundType)
	{
		PlayAhiSfx(sfxNumber);
	}
}
/*==========================================================================*/
static void PlayAhiSfx(int sfxNumber)
{
	if (0 == CheckIO((struct IORequest*)m_pAhiIO))
	{
		int nPrio = m_sfxTabPrio[sfxNumber];

		if (nPrio < sfxChannel.prio)
		{
			return;
		}
		else
		{
			AbortIO((struct IORequest*)m_pAhiIO);
		}
	}

	WaitIO((struct IORequest*)m_pAhiIO);

	m_pAhiIO->ahir_Std.io_Message.mn_Node.ln_Pri = -50;
	m_pAhiIO->ahir_Std.io_Command = CMD_WRITE;
	m_pAhiIO->ahir_Std.io_Data = m_SfxData[sfxNumber];
	m_pAhiIO->ahir_Std.io_Length = m_sfxSize[sfxNumber];
	m_pAhiIO->ahir_Std.io_Offset = 0;
	m_pAhiIO->ahir_Frequency = 22050;
	m_pAhiIO->ahir_Type = AHIST_M8S;
	m_pAhiIO->ahir_Volume = 0x10000;
	m_pAhiIO->ahir_Position = 0x8000;
	m_pAhiIO->ahir_Link = 0;

	BeginIO((struct IORequest*)m_pAhiIO);

	sfxChannel.prio = m_sfxTabPrio[sfxNumber];

}
/*==========================================================================*/
static void PlayPaulaSfx(int sfxNumber)
{
	if (0 == CheckIO((struct IORequest*)m_pAudioIO))
	{
		int nPrio = m_sfxTabPrio[sfxNumber];

		if (nPrio < sfxChannel.prio)
		{
			return;
		}
		else
		{
			m_pAudioIO->ioa_Request.io_Command = ADCMD_FINISH;
			m_pAudioIO->ioa_Request.io_Flags = ADIOF_SYNCCYCLE;
			BeginIO((struct IORequest*)m_pAudioIO);

			//Też działa sprawdzone
			//AbortIO((struct IORequest*)m_pAudioIO);
			//WaitPort(m_pMsgAudioPort);
			//GetMsg(m_pMsgAudioPort); 

		}
	}

	WaitIO((struct IORequest*)m_pAudioIO);

	m_pAudioIO->ioa_Request.io_Command = CMD_WRITE;
	m_pAudioIO->ioa_Request.io_Flags = ADIOF_PERVOL;
	m_pAudioIO->ioa_Data = m_SfxData[sfxNumber];
	m_pAudioIO->ioa_Length = m_sfxSize[sfxNumber];
	m_pAudioIO->ioa_Volume = 64;
	m_pAudioIO->ioa_Cycles = 1;
	BeginIO((struct IORequest*)m_pAudioIO);


	sfxChannel.prio = m_sfxTabPrio[sfxNumber];
}
/*==========================================================================*/
int initSound(void)
{
	int iResult = 0;
	int i;
	UBYTE* pSfx;

	pSfx = g_pSoundsData;

	for (i = 0; i < 15; i++)
	{
		m_SfxData[i] = (BYTE*)pSfx;
		pSfx += m_sfxSize[i];
	}


	if (SOUND_PAULA == g_bSoundType)
	{
		iResult = initSoundPaula();
	}
	else if (SOUND_AHI == g_bSoundType)
	{
		iResult = initSoundAhi();
	}

	return iResult;
}
/*==========================================================================*/
void killSound(void)
{
	if (SOUND_PAULA == g_bSoundType)
	{
		killSoundPaula();
	}
	else if (SOUND_AHI == g_bSoundType)
	{
		killSoundAhi();
	}
}
/*==========================================================================*/
static int initSoundAhi(void)
{
	m_pAhiMp = CreateMsgPort();

	if (0 == m_pAhiMp)
	{
		return -1;
	}

	m_pAhiIO = CreateIORequest(m_pAhiMp, sizeof(struct AHIRequest));

	if (0 == m_pAhiIO)
	{
		return -1;
	}

	m_pAhiIO->ahir_Version = 4;

	m_AhiDevice = OpenDevice(AHINAME, AHI_DEFAULT_UNIT, (struct IORequest*)m_pAhiIO, 0UL);

	if (0 != m_AhiDevice)
	{
		return -1;
	}

	m_pAhiIO->ahir_Std.io_Message.mn_Node.ln_Pri = -50;
	m_pAhiIO->ahir_Std.io_Command = CMD_WRITE;
	m_pAhiIO->ahir_Std.io_Data = m_SfxData[SND_BOOM];
	m_pAhiIO->ahir_Std.io_Length = (ULONG)0;
	m_pAhiIO->ahir_Std.io_Offset = 0;
	m_pAhiIO->ahir_Std.io_Flags = 0;
	m_pAhiIO->ahir_Frequency = (ULONG)22050;
	m_pAhiIO->ahir_Type = AHIST_M8S;
	m_pAhiIO->ahir_Volume = 0x10000;
	m_pAhiIO->ahir_Position = 0x8000;
	m_pAhiIO->ahir_Link = NULL;

	SendIO((struct IORequest*)m_pAhiIO);

	return 0;
}
/*==========================================================================*/
static void killSoundAhi(void)
{
	if (m_AhiDevice)
	{
		AbortIO((struct IORequest*)m_pAhiIO);
		WaitPort(m_pAhiMp);
		GetMsg(m_pAhiMp);

		CloseDevice((struct IORequest*)m_pAhiIO);
	}

	if (m_pAhiIO)
	{
		DeleteIORequest(m_pAhiIO);
	}

	if (m_pAhiMp)
	{
		DeleteMsgPort(m_pAhiMp);
	}
}
/*==========================================================================*/
static int initSoundPaula(void)
{
	int i;
	LONG error;

	sfxChannel.prio = 0;

	m_pMsgAudioPort = CreateMsgPort();

	if (0 == m_pMsgAudioPort)
	{
		return -1;
	}

	m_pAudioIO = (struct IOAudio*)
		CreateIORequest(m_pMsgAudioPort, sizeof(struct IOAudio));

	if (0 == m_pAudioIO)
	{
		return -1;
	}

	m_pAudioIO->ioa_Request.io_Message.mn_ReplyPort = m_pMsgAudioPort;
	m_pAudioIO->ioa_Request.io_Message.mn_Node.ln_Pri = 127;
	m_pAudioIO->ioa_Request.io_Command = ADCMD_ALLOCATE;
	m_pAudioIO->ioa_Request.io_Flags = ADIOF_NOWAIT;
	m_pAudioIO->ioa_AllocKey = 0;
	m_pAudioIO->ioa_Data = whichannel;
	m_pAudioIO->ioa_Length = sizeof(whichannel);

	error = OpenDevice(AUDIONAME, 0L, (struct IORequest*)m_pAudioIO, 0L);

	if (0 != error)
	{
		return -1;
	}

	m_pAudioIO->ioa_Request.io_Message.mn_ReplyPort = m_pMsgAudioPort;
	m_pAudioIO->ioa_Request.io_Command = CMD_WRITE;
	m_pAudioIO->ioa_Request.io_Flags = ADIOF_PERVOL;
	m_pAudioIO->ioa_Data = m_SfxData[SND_STUK];
	m_pAudioIO->ioa_Length = 2;
	m_pAudioIO->ioa_Period = m_clock / 22050;
	m_pAudioIO->ioa_Volume = 64;
	m_pAudioIO->ioa_Cycles = 1;
	BeginIO((struct IORequest*)m_pAudioIO);

	return 0;
}
/*==========================================================================*/
static void killSoundPaula(void)
{
	if (m_pAudioIO && m_pAudioIO->ioa_Request.io_Device)
	{
		AbortIO((struct IORequest*)m_pAudioIO);
		WaitPort(m_pMsgAudioPort);
		GetMsg(m_pMsgAudioPort);

		CloseDevice((struct IORequest*)m_pAudioIO);
	}

	if (m_pAudioIO)
	{
		DeleteIORequest(m_pAudioIO);
	}

	if (m_pMsgAudioPort)
	{
		DeleteMsgPort(m_pMsgAudioPort);
	}
}
/*==========================================================================*/


Ostatnia aktualizacja: 10.02.2017 14:21:41 przez asman
[#44] Re: Granie przez audio.device

@asman, post #43

Dzieki, za kod. Mam pytania:
1. Czy Twoj kod gra tylko na jednym kanale
2. Czy chcac skozystac z wiecej kanalow niz jeden nie powinno byc wlasnie wiecej requestow.

W kazdym badz razie zrobilem to aktyalnie tak ze, otwarlem audio.device dla kazdego kanalu z osobna i rozbile dwie procedury odtwarzajace. Dla testu dalem tez WaitProt() i GetMsg(). Narazie nie ma problemu.

Oto moj aktualny kod:

BOOL PaulaInit(void)
{
        BOOL L = FALSE, P = FALSE;

        UBYTE ChannelL[] = {1};
        UBYTE ChannelP[] = {2};

        AudioPort[0] = CreateMsgPort();
        AudioPort[1] = CreateMsgPort();

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

                if(AudioIO[0] && AudioIO[1])
                {
                        AudioIO[0]->ioa_Request.io_Message.mn_ReplyPort   = AudioPort[0];
                        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                              = ChannelL;
                        AudioIO[0]->ioa_Length                            = sizeof(ChannelL);

                        if(OpenDevice(AUDIONAME, 0L, (struct IORequest*)AudioIO[0], 0L) == NULL)
                        {
                                L = TRUE;
                        }

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

                        if(OpenDevice(AUDIONAME, 0L, (struct IORequest*)AudioIO[1], 0L) == NULL)
                        {
                                P = TRUE;
                        }
                }          
        }
     
        return((BOOL)(L & P));
}

void PaulaKill(void)
{
        if(AudioIO[1] &&
           AudioIO[1]->ioa_Request.io_Device)
        {
                AbortIO ((struct IORequest*)AudioIO[1]);
//                WaitIO  ((struct IORequest*)AudioIO[1]);
                WaitPort(AudioPort[1]);
                GetMsg  (AudioPort[1]);

                CloseDevice((struct IORequest*)AudioIO[1]);
        }

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

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

        if(AudioPort[0]) DeleteMsgPort(AudioPort[0]);
        if(AudioPort[1]) DeleteMsgPort(AudioPort[1]);
}

void PaulaPlayL(int sfx)
{
        if(CheckIO((struct IORequest*)AudioIO[0]) == NULL)
        {
                AbortIO ((struct IORequest*)AudioIO[0]);
//                WaitIO  ((struct IORequest*)AudioIO[0]);
                WaitPort(AudioPort[0]);
                GetMsg  (AudioPort[0]);
        }
        
        AudioIO[0]->ioa_Request.io_Command = CMD_WRITE;
        AudioIO[0]->ioa_Request.io_Flags   = ADIOF_PERVOL;
        AudioIO[0]->ioa_Request.io_Unit    = (APTR)(1);
        AudioIO[0]->ioa_Data               = Dzwieki[sfx].Adres;
        AudioIO[0]->ioa_Length             = Dzwieki[sfx].Len;
        AudioIO[0]->ioa_Period             = (UWORD)(Dzwieki[sfx].Period);
        AudioIO[0]->ioa_Volume             = (UWORD)(63);
        AudioIO[0]->ioa_Cycles             = 1;
        
        BeginIO((struct IORequest*)AudioIO[0]);

void PaulaPlayP(int sfx)
{
        if(CheckIO((struct IORequest*)AudioIO[1]) == NULL)
        {
                AbortIO ((struct IORequest*)AudioIO[1]);
//                WaitIO  ((struct IORequest*)AudioIO[1]);
                WaitPort(AudioPort[1]);
                GetMsg  (AudioPort[1]);
        }
        
        AudioIO[1]->ioa_Request.io_Command = CMD_WRITE;
        AudioIO[1]->ioa_Request.io_Flags   = ADIOF_PERVOL;
        AudioIO[1]->ioa_Request.io_Unit    = (APTR)(2);
        AudioIO[1]->ioa_Data               = Dzwieki[sfx].Adres;
        AudioIO[1]->ioa_Length             = Dzwieki[sfx].Len;
        AudioIO[1]->ioa_Period             = (UWORD)(Dzwieki[sfx].Period);
        AudioIO[1]->ioa_Volume             = (UWORD)(63);
        AudioIO[1]->ioa_Cycles             = 1;
        
        BeginIO((struct IORequest*)AudioIO[1]);
}
[#45] Re: Granie przez audio.device

@Phibrizzo, post #44

1. Tak, grane jest na jednym kanale
2. Nie wiem czy dobrze zrozumiałem. Chcesz odgrywać na przykład jeden sampel na lewym kanale i na prawym kanale w tym samym czasie. Jeszcze tego nie sprawdzałem, dzisiaj to zrobię wieczorem, ale wydaje mi się że wystarczy dodać bity odpowiadające za kanały i powinno być dobrze, na przykład dać {3} albo {5} albo {10} {12} i sprawdzić czy na jednym requestrze to idzie.
[#46] Re: Granie przez audio.device

@asman, post #43

Mój post #20 pochodzi z sierpnia zeszłego roku, zapomniałem. Wyciągnąłem pochopne wnioski próbując rozwiązać problem podtrzymując tezę Phibrizzo o tym, że AbortIO() wystarczy, przepraszam.

Ostatnia aktualizacja: 10.02.2017 15:01:56 przez Hexmage960
[#47] Re: Granie przez audio.device

@asman, post #45

Sprawdziłem wczoraj z {5} i z tego co usłyszałem w słuchawkach to jest grane i na lewym i na prawym kanale. Zatem wystarczy jeden request.
Wczoraj też sprawdziłem jak się sprawa ma z dwoma requestami (dwa różne kanały)i jednym portem i jednym otwarciem audio.device. Do tego celu potrzeba było użyć ADCMD_ALLOCATE na dwóch requestach. Powiem tak, że to dosyć skomplikowane, nieopłacalne i po prawdzie to nie wiem czy poprawne, ze względu na specyfikę WaitPort, który czeka na zadanym porcie aż pojawi się msg, wtedy nie wiemy który przyszedł. Do odgrywania sampli w grze to bezużyteczne.
Według mnie najrozsądniej jeśli chodzi o dwa requesty to najlepiej mieć osobne porty, przynajmniej jeśli chodzi o audio.device. Nie potrzeba otwierać dwa razy OpenDevice. Można to zrobić na dwa sposoby. Pierwszy to otwarcie device z alokacją a potem na drugim też robimy alokacje, po uprzednim skopiowaniu pól: io_Device, io_Unit, ioa_AllocKey. I potem po wysłaniu i poczekaniu na port, odbraniu mesgów, sprawdzamy io_Error, jeśli zero to udało się zaalokować.
Drugi sposób to otwarcie device bez alokacji a później alokowanie. Czyli
m_pAudioIOLeft->ioa_Request.io_Message.mn_ReplyPort = m_pMsgAudioPortLeft;
	m_pAudioIOLeft->ioa_AllocKey = 0;

	error = OpenDevice(AUDIONAME, 0L, (struct IORequest*)m_pAudioIOLeft, 0L);

	if (0 != error)
	{
		return -1;
	}


I Alokowanie
static int tryToAllocateChannel(struct IOAudio* pIOAudio, struct MsgPort* pMsgPortAudio)
{
	pIOAudio->ioa_Request.io_Message.mn_ReplyPort = pMsgPortAudio;
	pIOAudio->ioa_Request.io_Message.mn_Node.ln_Pri = 127;
	pIOAudio->ioa_Request.io_Command = ADCMD_ALLOCATE;
	pIOAudio->ioa_Request.io_Flags = ADIOF_NOWAIT;
	pIOAudio->ioa_AllocKey = 0;
	/*
	** io_Device, io_Unit ,ioa_Data, ioa_Length, must be set earlier
	*/

	BeginIO((struct IORequest*)pIOAudio);
	WaitPort(pMsgPortAudio);
	while (TRUE)
	{
		if (0 == GetMsg(pMsgPortAudio))
		{
			break;
		}
	}

	return pIOAudio->ioa_Request.io_Error;
}

/***** tu przyklad alokowania ***/

	m_pAudioIOLeft->ioa_Data = channelLeft;
	m_pAudioIOLeft->ioa_Length = sizeof(channelLeft);
	error = tryToAllocateChannel(m_pAudioIOLeft, m_pMsgAudioPortLeft);

	if (0 != error)
	{
		return error;
	}

	m_pAudioIORight->ioa_AllocKey = m_pAudioIOLeft->ioa_AllocKey;
	m_pAudioIORight->ioa_Request.io_Device = m_pAudioIOLeft->ioa_Request.io_Device;
	m_pAudioIORight->ioa_Request.io_Unit = m_pAudioIOLeft->ioa_Request.io_Unit;
	m_pAudioIORight->ioa_Data = channelRight;
	m_pAudioIORight->ioa_Length = sizeof(channelRight);

	error = tryToAllocateChannel(m_pAudioIORight, m_pMsgAudioPortRight);
	if (0 != error)
	{
		return error;
	}


I jeszcze jedno, tam gdzie zamieściłem kod od Bobbo też jest WaitIO, trzeba by to zamienić na WaitPort i GetMsg. Poprawnie powinno być
static void PlayPaulaSfx(int sfxNumber)
{
	if (0 == CheckIO((struct IORequest*)m_pAudioIO))
	{
		int nPrio = m_sfxTabPrio[sfxNumber];

		if (nPrio < sfxChannel.prio)
		{
			return;
		}
		else
		{
			m_pAudioIO->ioa_Request.io_Command = ADCMD_FINISH;
			m_pAudioIO->ioa_Request.io_Flags = ADIOF_SYNCCYCLE;
			BeginIO((struct IORequest*)m_pAudioIO);
		}
	}

	WaitPort(m_pMsgAudioPort);
	GetMsg(m_pMsgAudioPort);

	m_pAudioIO->ioa_Request.io_Command = CMD_WRITE;
	m_pAudioIO->ioa_Request.io_Flags = ADIOF_PERVOL;
	m_pAudioIO->ioa_Data = m_SfxData[sfxNumber];
	m_pAudioIO->ioa_Length = m_sfxSize[sfxNumber];
	m_pAudioIO->ioa_Volume = 64;
	m_pAudioIO->ioa_Cycles = 1;
	BeginIO((struct IORequest*)m_pAudioIO);


	sfxChannel.prio = m_sfxTabPrio[sfxNumber];
}


W necie można znaleźć książkę Advanced_System_Programmers_Guide_for_the_Amiga i tam też jest co nieco o Audio.Device, są też tam błędy typu robienie DoIO w Audio.Device, trzeba być czujnym :)

Edit: Przy okazji dzięki Phibrizzo za pytania. Dzięki temu znalazłem parę błędów w Bobbo o których nie wiedziałem. Gdy przyjrzałem się baczniej to jest ich jeszcze więcej.


Ostatnia aktualizacja: 11.02.2017 10:51:25 przez asman
[#48] Re: Granie przez audio.device

@asman, post #47

Dzieki wielkie za testy. Teraz niektore sprawy wydaja sie bardziej jasniejsze.
Czuje sie jakbym na nowo odkrywal dawno utrcona wiedze o programowaniu Amigi :)
[#49] Re: Granie przez audio.device

@Phibrizzo, post #48

Że zapytam się dla jasności: wiadomo już czemu u Ciebie WaitPort() powodował zamrożenie co kilka odtwarzań?
[#50] Re: Granie przez audio.device

@Hexmage960, post #49

Wlasnie nie. Mozliwe wlasnie ze bylo to spowodowane nieodbieraniem sygnalow z konkretnego AudioPortu.
Ponadto odkrylem jeszcze cos innego. Wspominales o tym kilkanascie postow wczesniej, tylko jakos mi to umknelo.
Wiem dlaczego po AbortIO nie moglo byc WaitPort(). Okazalo sie ze faktycznie jesli gramy pierwszy raz to nie powinien byc sprawdzany CheckIO.
Jesli to zrobilem to WaitPort() po AbortIO czekal w nieskonczonosc.


Ostatnia aktualizacja: 11.02.2017 15:58:30 przez Phibrizzo
[#51] Re: Granie przez audio.device

@Phibrizzo, post #50

Ja poradziłem sobie z tym w ten sposób, że zaraz po otwarciu device'a wysyłam requesta :).
Nie wiem czy moje podejście jest eleganckie, bo można by robić jakąś ifolandie uskuteczniać ale to dla mnie już nieeleganckie. Chyba że ktoś zna jakiś lepszy sposób, przydatny w grach na ten przykład.
[#52] Re: Granie przez audio.device

@asman, post #51

Fakt, w dokumentacji jest mowa o tej cesze CheckIO(). Szczerze mówiąc musiałbym wdrożyć się lepiej w ten temat i sobie poprzypominać, żebym mógł w tej chwili coś więcej powiedzieć. Dawno temu napisałem grę, w której było odtwarzanie dźwięku przez audio.device. Był to Nurek bodajże. Wtedy chodziło to bez problemów.
[#53] Re: Granie przez audio.device

@Hexmage960, post #52

To super, mógłbyś wkleić kod dotyczący inicjacji, odtwarzania i kończenia dźwięku tutaj, tak bym mógł sobie podpatrzeć. Dzięki wielkie.

Wczoraj zacząłem się nad tym głębiej zastanawiać i doszedłem do zaskakującej myśli, że to jak to zrobiłem zarówno w Bobbo jak i w Boxo jest za bardzo przekombinowane. Poszukam jakieś lepszego rozwiązania.
[#54] Re: Granie przez audio.device

@asman, post #53

Bardzo mi przykro, ale kod Nurka przepadł. Zostało mi tylko trochę opracowań do edytora map do Benefactora na dyskietkach z backupem.

Przeczytawszy Twój post poszperałem nieco na płycie Amiga Developer CD v2.1 w poszukiwaniu przykładów odtwarzania przez audio.device, na których się kiedyś wzorowałem. Niestety póki co nie znalazłem.

Będę szukał dalej.

Jeśli chodzi o CheckIO() to jeśli sprawia problemy może warto zamiennie użyć ADCMD_FINISH oraz WaitIO() lub WaitPort() + GetMsg(). Z tego co pamiętam używałem tego ADCMD_FINISH.

Tak jak napisałem, musiałbym do tego przysiąść i przetestować, a obecnie piszę inny program na Amigę. Jeśli znajdę chwilę, to spróbuję napisać i przetestować odtwarzanie dźwięków.
[#55] Re: Granie przez audio.device

@Hexmage960, post #54

Na aminecie jest zestaw audiotools z AmigaWorld.
[#56] Re: Granie przez audio.device

@cholok, post #55

Chodzi o to: http://aminet.net/package/mus/misc/AudioTools ? - warto się temu przyjrzeć.

Ja nie pamiętam gdzie był kod na którym się wzorowałem, ale myślę że jeszcze uda mi się znaleźć.

Chciałem dodać jeszcze coś ważnego, co dziś przeczytałem. Ponieważ DoIO() jest odradzane dla audio.device, to synchroniczne wiadomości przesyła się również za pomocą BeginIO(). I tu uwaga: jeśli ustawimy flagę IOF_QUICK, wówczas rzeczywiście request jest synchroniczny i odpowiedź na ReplyPort nie nadchodzi (nie musimy czekać i odbierać wiadomości). Dotyczy to np. ADCMD_FINISH.

Dlatego optuję za takim zatrzymywaniem odgrywania sampli, a nie kombinacji CheckIO() i AbortIO(). Spróbuję samodzielnie to sprawdzić.

Można o IOF_QUICK przeczytać w opisie dowolnego polecenia audio.device w dokumentacji.

Ostatnia aktualizacja: 12.02.2017 10:41:45 przez Hexmage960
[#57] Re: Granie przez audio.device

@Hexmage960, post #54

A może masz do tego Nurka plik wykonywalny, to ja sobie zdeasembluje go i zobacze o co tam chodzi.
[#58] Re: Granie przez audio.device

@asman, post #57

Nie mam pliku wykonywalnego, zresztą nawet jakbym miał - nie katowałbym Cię deasemblacją.
[#59] Re: Granie przez audio.device

@Hexmage960, post #58

Dzięki za trud.
Powracając do tematu, to długich bojach udało mi się znaleźć rozwiązanie dobre dla gry.
Oto kawałek kodu z boxo
/*==========================================================================*/
void PlaySfx(int sfxNumber)
{
	if (0 == CheckIO((struct IORequest*)m_pAudioIO))
	{
		m_pAudioIO->ioa_Request.io_Command = ADCMD_FINISH;
		m_pAudioIO->ioa_Request.io_Flags = IOF_QUICK;
		BeginIO((struct IORequest*)m_pAudioIO);
	}

	m_pAudioIO->ioa_Request.io_Command = CMD_WRITE;
	m_pAudioIO->ioa_Request.io_Flags = ADIOF_PERVOL;
	m_pAudioIO->ioa_Data = m_sfx[sfxNumber].address;
	m_pAudioIO->ioa_Length = m_sfx[sfxNumber].length;
	m_pAudioIO->ioa_Volume = m_sfx[sfxNumber].volume;
	m_pAudioIO->ioa_Period = m_sfx[sfxNumber].period;
	m_pAudioIO->ioa_Cycles = 1;
	BeginIO((struct IORequest*)m_pAudioIO);

}
/*==========================================================================*/
static int initSoundPaula(void)
{
	LONG error;

	m_pMsgAudioPort = CreateMsgPort();

	if (0 == m_pMsgAudioPort)
	{
		return -1;
	}

	m_pAudioIO = (struct IOAudio*) 
		CreateIORequest(m_pMsgAudioPort, sizeof(struct IOAudio));

	if (0 == m_pAudioIO)
	{
		return -1;
	}

	g_nAudioPortSignal = 1L << m_pMsgAudioPort->mp_SigBit;

	error = OpenDevice(AUDIONAME, 0L, (struct IORequest*)m_pAudioIO, 0L);

	if (0 != error)
	{
		return -1;
	}

	m_pAudioIO->ioa_Request.io_Message.mn_Node.ln_Pri = 127;
	m_pAudioIO->ioa_Request.io_Message.mn_ReplyPort = m_pMsgAudioPort;
	m_pAudioIO->ioa_Request.io_Command = ADCMD_ALLOCATE;
	m_pAudioIO->ioa_Request.io_Flags = ADIOF_NOWAIT;
	m_pAudioIO->ioa_AllocKey = 0;
	m_pAudioIO->ioa_Data = m_whiChannel;
	m_pAudioIO->ioa_Length = sizeof(m_whiChannel);

	BeginIO((struct IORequest*)m_pAudioIO);

	if (0 != m_pAudioIO->ioa_Request.io_Error)
	{
		return -1;
	}


	return 0;
}
/*==========================================================================*/
static void killSoundPaula(void)
{
	if (m_pAudioIO)
	{
		if (m_pAudioIO->ioa_Request.io_Device)
		{
			if (0 == CheckIO((struct IORequest*)m_pAudioIO))
			{
				AbortIO((struct IORequest*)m_pAudioIO);
				WaitPort(m_pMsgAudioPort);
				GetMsg(m_pMsgAudioPort);
			}

			CloseDevice((struct IORequest*)m_pAudioIO);
		}

		DeleteIORequest(m_pAudioIO);
	}

	if (m_pMsgAudioPort)
	{
		DeleteMsgPort(m_pMsgAudioPort);
	}
}
/*==========================================================================*/
void GetSoundMsg(void)
{
	GetMsg(m_pMsgAudioPort);
}
/*==========================================================================*/


Wszelkie mesgi odbierane są za pomocą Wait w pętli głównej gry. Dzięki czemu nie ma przestojów w grze, co było widoczne gdy odtwarzany sampel był dłuższy

while (!g_bExitFromGame)
	{
		ULONG sigSet = 
			g_nWindowSignal | g_nMainTimerSig| g_nDemoTimerSig | g_nGamePortSignal | g_nAudioPortSignal | SIGBREAKF_CTRL_C;

		if (g_bEditMode)
		{
			sigSet |= g_nEditorWinSignal;
		}

		const ULONG signals = Wait(sigSet);

		if (signals & SIGBREAKF_CTRL_C)
		{
			g_bExitFromGame = TRUE;
		}

		if (signals & g_nAudioPortSignal)
		{
			GetSoundMsg();
		}
/* wywaliłem reszte rzeczy żeby nie zaciemniać */


Jeśli są jakiekolwiek pytania bądź wątpliwości to śmiało.
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