> On Fri, Mar 22, 2002 at 01:08:11AM +0100, Rainer Canavan wrote:
[...]
> There's nothing which says you can't do that. However, you're going to
> have to use a threading model; create a child thread to perform the
> actual mixing of and shoving bits out to the pcm device.
> I used the callback mechanisms in SDL and ALSA because they're much
> simpler from an application perspective.
>
> Let me know if you want me to go into a bit more detail.
Just have a look at what I've done ;-) I haven't played with pthreads
for a long time, so this is bound to be ugly. Sorry about the rather
bad patches, they may need some help by hand to apply.
> (Ya know, I'm surprised that the Irix AL doesn't have a callback
> mechanism.. it's usually a sign of a mature API)
It may be not so bad if threading has almost always been there. You may get
into trouble with library calls from a callback function, but hopefully
everything is thread safe, so one should not expect trouble with threads.
Then again, thread-safe environments should be callback-safe. Callbacks
leave a bland taste in my mouth since the bad old days of DOS interrupts.
Rainer
-- Attached file included as plaintext by Listar --
-- File: configure.in.patch
-- Desc: configure.in.patch
--- ../../3/freesci/configure.in Sun Mar 10 13:58:53 2002
+++ configure.in Sat Mar 23 00:37:45 2002
@@ -93,6 +93,18 @@
esac
fi
+AC_CHECK_HEADERS(dmedia/audio.h)
+
+if test "${ac_cv_header_dmedia_audio_h}" = "yes"; then
+ case ${host_os} in
+ irix*)
+ found_sound=yes
+ AC_DEFINE(HAVE_DMEDIA_AUDIO_H)
+ LIBS="-laudio -lpthread $LIBS"
+ esac
+fi
+
+
AC_ARG_WITH(sdl, [ --without-sdl Do not build the SDL driver])
if test x"$with_sdl" != xno; then
-- Attached file included as plaintext by Listar --
-- File: src_include_pcmout.h.patch
-- Desc: src_include_pcmout.h.patch
--- ../../../../3/freesci/src/include/pcmout.h Thu Feb 14 05:21:38 2002
+++ pcmout.h Fri Mar 22 00:11:01 2002
@@ -47,12 +46,24 @@
#ifdef HAVE_ALSA
extern pcmout_driver_t pcmout_driver_alsa;
#endif
+#ifdef HAVE_DMEDIA_AUDIO_H
+extern pcmout_driver_t pcmout_driver_al;
+#endif
+
extern DLLEXTERN pcmout_driver_t *pcmout_drivers[];
int pcmout_open();
int pcmout_close();
-- Attached file included as plaintext by Listar --
-- File: src_sound_Makefile.am.patch
-- Desc: src_sound_Makefile.am.patch
--- Makefile.am Thu Mar 21 23:16:51 2002
+++ ../../../../3/freesci/src/sound/Makefile.am Sun Mar 10 13:59:06 2002
@@ -3,7 +3,7 @@
LDADD = -lc
EXTRA_DIST = sfx_save.cfsml soundserver_dos.c
noinst_LIBRARIES = libscisound.a
-libscisound_a_SOURCES = song_iterator.c oldmidi.c sound.c sfx_save.c midi_mt32.c
midiout.c midiout_unixraw.c midiout_alsaraw.c midi_device.c midi_mt32gm.c
midiout_ossseq.c midiout_ossopl3.c polled_ss_sdl.c soundserver.c midi_adlib.c
midi_adlibemu.c fmopl.c polled_ss_unix.c polled_ss_win32.c midiout_win32mci.c
polled_ss.c pcmout.c pcmout_sdl.c pcmout_alsa.c midiout_irixmd.c pcmout_al.c
+libscisound_a_SOURCES = song_iterator.c oldmidi.c sound.c sfx_save.c midi_mt32.c
+midiout.c midiout_unixraw.c midiout_alsaraw.c midi_device.c midi_mt32gm.c
+midiout_ossseq.c midiout_ossopl3.c polled_ss_sdl.c soundserver.c midi_adlib.c
+midi_adlibemu.c fmopl.c polled_ss_unix.c polled_ss_win32.c midiout_win32mci.c
+polled_ss.c pcmout.c pcmout_sdl.c midiout_irixmd.c
sfx_save.c: sfx_save.cfsml
cat sfx_save.cfsml | ../engine/cfsml.pl @CFSML_FLAGS@ -f sfx_save.cfsml >
sfx_save.c
-- Attached file included as plaintext by Listar --
-- File: src_sound_pcmout.c.patch
-- Desc: src_sound_pcmout.c.patch
--- ../../../../3/freesci/src/sound/pcmout.c Thu Feb 14 05:21:38 2002
+++ pcmout.c Fri Mar 22 00:15:45 2002
@@ -22,40 +22,45 @@
#ifdef HAVE_SDL
&pcmout_driver_sdl,
#endif
+#ifdef HAVE_DMEDIA_AUDIO_H
+ &pcmout_driver_al,
+#endif
&pcmout_driver_null,
NULL
};
-- Attached file included as plaintext by Listar --
-- File: pcmout_al.c
-- Desc: pcmout_al.c
/***************************************************************************
pcmout_al.c Copyright (C) 2002 Solomon Peachy (And Claudio Matsuoka)
This program may be modified and copied freely according to the terms of
the GNU general public license (GPL), as long as the above copyright
notice and the licensing information contained herein are preserved.
Please refer to www.gnu.org for licensing details.
This work is provided AS IS, without warranty of any kind, expressed or
implied, including but not limited to the warranties of merchantibility,
noninfringement, and fitness for a specific purpose. The author will not
be held liable for any damage caused by this work or derivatives of it.
By using this source code, you agree to the licensing terms as stated
above.
***************************************************************************/
#include <pcmout.h>
#ifdef HAVE_DMEDIA_AUDIO_H
#include <dmedia/audio.h>
#include <pthread.h>
static ALconfig alconfig;
static ALport alport;
static int alfd;
static fd_set alfdset;
pthread_attr_t althreadattr;
pthread_t althread;
static guint16 *buffer;
static guint16 largebuffer[BUFFER_SIZE*4];
void* althreadplay(void* arg)
{
GTimeVal timeout = {1, 1};
int nframes;
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
do {
nframes=mix_sound(BUFFER_SIZE);
if (alfd>0) { /* untested */
FD_ZERO(&alfdset);
FD_SET(alfd,&alfdset);
alSetFillPoint(alport,BUFFER_SIZE>>1);
select(alfd+1, NULL, &alfdset, NULL, (struct timeval *)&timeout);
}
alWriteFrames(alport, buffer, nframes);
pthread_testcancel();
} while (alport!=0);
pthread_exit(NULL);
}
static int pcmout_al_open(guint16 *b, guint16 rate)
{
ALpv alparam;
int aldev, alitf;
buffer=b;
alconfig=alNewConfig();
if (!alconfig) {
fprintf(stderr, "sgiAL: Couldn't create config: %s\n",
alGetErrorString(oserror()));
return -1;
}
alSetSampFmt(alconfig, AL_SAMPFMT_TWOSCOMP);
alSetWidth(alconfig, AL_SAMPLE_16);
alSetChannels(alconfig, 2);
aldev=alGetResourceByName(AL_SYSTEM, "out.analog", AL_DEVICE_TYPE);
if (!aldev) {
fprintf(stderr, "sgiAL: invalid device: \n");
return -1;
}
if (alitf=alGetResourceByName(AL_SYSTEM, "out.analog", AL_INTERFACE_TYPE)) {
alparam.param=AL_INTERFACE;
alparam.value.i=alitf;
if (alSetParams(aldev, &alparam, 1) < 0) {
fprintf(stderr, "sgiAL: invalid ALinterface \n");
return -1;
}
}
alSetDevice(alconfig, aldev);
alport=alOpenPort("FreeSCI", "w", alconfig);
if (!alport) {
fprintf(stderr, "sigAL: Couldn't open ALport: %s\n",
alGetErrorString(oserror()));
return -1;
}
alparam.param=AL_RATE;
alparam.value.i=rate;
if (alSetParams(aldev, &alparam, 1) < 0) {
fprintf(stderr, "sgiAL: invalid sampling rate: %i \n", rate);
alClosePort(alport);
return -1;
}
alfd = alGetFD(alport); /* get a fd to wait for */
if (alfd = -1) {
fprintf(stderr, "sgiAL: Can't get File Descriptor: %s \n",
alGetErrorString(oserror()));
}
pthread_attr_init(&althreadattr);
if (pthread_create(&althread, &althreadattr, &althreadplay, NULL)!=0) {
fprintf(stderr, "sgiAL: couldn't create thread! \n");
alClosePort(alport);
return -1;
}
return 0;
}
static int pcmout_al_close()
{
pthread_cancel(althread);
alClosePort(alport);
pthread_attr_destroy(&althreadattr);
alfd=-1;
alport=0;
return 0;
}
pcmout_driver_t pcmout_driver_al = {
"irixal",
"v0.01",
(int (*)(struct _pcmout_driver*, char*, char*))NULL,
&pcmout_al_open,
&pcmout_al_close
};
#endif