| diff -ur xglk/Makefile xglk+hack/Makefile | |
| --- xglk/Makefile Sat Apr 15 21:13:28 2000 | |
| +++ xglk+hack/Makefile Wed Aug 8 22:53:51 2001 | |
| @@ -37,8 +37,9 @@ | |
| # definitions for SGI / Irix | |
| #SYSTEMFLAGS = | |
| -# definitions for Linux | |
| -#SYSTEMFLAGS = | |
| +# definitions for Linux. _BSD_SOURCE may be necessary for struct timezone. | |
| +# At least that is my experience with Debian and glibc 2.2.3. | |
| +SYSTEMFLAGS = -D_BSD_SOURCE | |
| # -------------------- | |
| @@ -54,13 +55,13 @@ | |
| # directories could be just about anywhere. Sigh. | |
| # for Debian Linux | |
| -#XINCLUDE = -I/usr/X11R6/include/X11 | |
| -#XLIB = -L/usr/X11R6/lib -lX11 | |
| - | |
| -# for Red Hat Linux | |
| XINCLUDE = -I/usr/X11R6/include/X11 | |
| XLIB = -L/usr/X11R6/lib -lX11 | |
| +# for Red Hat Linux | |
| +#XINCLUDE = -I/usr/X11R6/include/X11 | |
| +#XLIB = -L/usr/X11R6/lib -lX11 | |
| + | |
| # for SparcStation / Solaris | |
| #XINCLUDE = -I/usr/openwin/include | |
| #XLIB = -R/usr/openwin/lib -L/usr/openwin/lib/ -lX11 | |
| @@ -78,15 +79,21 @@ | |
| # If there is no JPEG lib available, uncomment this line. | |
| # JPEGFLAG = -DNO_JPEG_AVAILABLE | |
| +# definitions for the MikMod library. Will MIKMODCFLAGS have to be included | |
| +# in the Make.xglk file? How? | |
| +MIKMODCFLAGS = \$$\(shell libmikmod-config --cflags\) | |
| +MIKMODLDFLAGS = \$$\(shell libmikmod-config --ldadd\) | |
| +MIKMODLIB = \$$\(shell libmikmod-config --libs\) | |
| + | |
| # -------------------- | |
| # Pick a C compiler. | |
| #CC = cc | |
| CC = gcc | |
| -CFLAGS = -O -ansi $(PNGFLAG) $(JPEGFLAG) $(PNGINCLUDE) $(JPEGINCLUDE) -Wall -Wmissing-prototypes -Wstrict-prototypes -Wno-unused -Wbad-function-cast $(SYSTEMFLAGS) $(XINCLUDE) | |
| -LDFLAGS = | |
| -LIBS = $(XLIB) $(PNGLIB) $(JPEGLIB) $(SYSTEMLIBS) | |
| +CFLAGS = -O -ansi $(PNGFLAG) $(JPEGFLAG) $(PNGINCLUDE) $(JPEGINCLUDE) $(MIKMODINCLUDE) -Wall -Wmissing-prototypes -Wstrict-prototypes -Wno-unused -Wbad-function-cast $(SYSTEMFLAGS) $(XINCLUDE) | |
| +LDFLAGS = $(MIKMODLDFLAGS) | |
| +LIBS = $(XLIB) $(PNGLIB) $(JPEGLIB) $(MIKMODLIB) $(SYSTEMLIBS) | |
| OBJS = main.o xglk.o xglk_vars.o xglk_prefs.o xglk_loop.o xglk_init.o \ | |
| xglk_scrap.o xglk_msg.o xglk_key.o xglk_weggie.o xglk_pict.o \ | |
| diff -ur xglk/xg_event.c xglk+hack/xg_event.c | |
| --- xglk/xg_event.c Sun Jun 6 18:07:45 1999 | |
| +++ xglk+hack/xg_event.c Wed Aug 8 22:51:49 2001 | |
| @@ -38,5 +38,5 @@ | |
| void glk_tick() | |
| { | |
| - /* Nothing for us to do. */ | |
| + gli_tick_schannels(); | |
| } | |
| diff -ur xglk/xg_gestalt.c xglk+hack/xg_gestalt.c | |
| --- xglk/xg_gestalt.c Tue Jul 11 04:04:16 2000 | |
| +++ xglk+hack/xg_gestalt.c Wed Aug 8 21:50:52 2001 | |
| @@ -91,7 +91,7 @@ | |
| case gestalt_SoundVolume: | |
| case gestalt_SoundNotify: | |
| case gestalt_SoundMusic: | |
| - return FALSE; | |
| + return TRUE; | |
| case gestalt_Hyperlinks: { | |
| return TRUE; | |
| diff -ur xglk/xg_internal.h xglk+hack/xg_internal.h | |
| --- xglk/xg_internal.h Thu Apr 13 02:51:23 2000 | |
| +++ xglk+hack/xg_internal.h Thu Aug 9 22:36:45 2001 | |
| @@ -2,6 +2,11 @@ | |
| #define _XG_INTERNAL_H | |
| #include <X11/X.h> | |
| + | |
| +#ifdef GLK_MODULE_SOUND | |
| +#include <mikmod.h> | |
| +#endif | |
| + | |
| #include "gi_dispa.h" | |
| /* --- General declarations --- */ | |
| @@ -12,6 +17,7 @@ | |
| typedef struct glk_window_struct window_t; | |
| typedef struct glk_stream_struct stream_t; | |
| typedef struct glk_fileref_struct fileref_t; | |
| +typedef struct glk_schannel_struct channel_t; | |
| typedef struct stylehints_struct stylehints_t; | |
| extern int gli_special_typable_table[keycode_MAXVAL+1]; | |
| @@ -131,6 +137,25 @@ | |
| extern int init_gli_filerefs(void); | |
| +/* --- Sound channels --- */ | |
| + | |
| +struct glk_schannel_struct { | |
| + glui32 rock; | |
| + | |
| + MODULE *module; | |
| + glui32 snd; | |
| + glui32 vol; | |
| + glui32 notify; | |
| + | |
| + gidispatch_rock_t disprock; | |
| + channel_t *chain_next, *chain_prev; | |
| +}; | |
| + | |
| +extern int init_gli_schannels(void); | |
| +extern void exit_gli_schannels(void); | |
| +extern void gli_tick_schannels(void); | |
| +extern Bool gli_eventloop_schannels(void); | |
| + | |
| /* --- Styles --- */ | |
| typedef struct styleval_struct { | |
| @@ -155,6 +180,18 @@ | |
| extern void gli_styles_compute(fontset_t *font, stylehints_t *hints); | |
| /* --- Events --- */ | |
| + | |
| +/* This is the granularity at which we check for timer events; measured | |
| + in microseconds. 1/20 second sounds good, but if we have sound support | |
| + this may be too long. The documentation is a bit vague, but does say | |
| + that we never need to do more than a few hundred updates per second. | |
| + Based on the MikMod example programs, I've decided to set it at 1/100 | |
| + seconds. */ | |
| +#ifdef GLK_MODULE_SOUND | |
| +#define TICKLENGTH (10000) | |
| +#else | |
| +#define TICKLENGTH (50000) | |
| +#endif | |
| extern void eventloop_setevent(glui32 type, window_t *win, | |
| glui32 val1, glui32 val2); | |
| diff -ur xglk/xg_misc.c xglk+hack/xg_misc.c | |
| --- xglk/xg_misc.c Sun Jun 6 18:07:45 1999 | |
| +++ xglk+hack/xg_misc.c Wed Aug 8 21:49:04 2001 | |
| @@ -123,6 +123,8 @@ | |
| (*func)(); | |
| } | |
| + exit_gli_schannels(); | |
| + | |
| exit(1); | |
| } | |
| @@ -176,6 +178,8 @@ | |
| return ((stream_t *)obj)->disprock; | |
| case gidisp_Class_Fileref: | |
| return ((fileref_t *)obj)->disprock; | |
| + case gidisp_Class_Schannel: | |
| + return ((channel_t *)obj)->disprock; | |
| default: { | |
| gidispatch_rock_t dummy; | |
| dummy.num = 0; | |
| diff -ur xglk/xg_schan.c xglk+hack/xg_schan.c | |
| --- xglk/xg_schan.c Thu Jul 22 00:49:01 1999 | |
| +++ xglk+hack/xg_schan.c Fri Aug 10 00:42:46 2001 | |
| @@ -1,61 +1,351 @@ | |
| +#include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| +#include <sys/time.h> | |
| #include "xglk.h" | |
| #include "xg_internal.h" | |
| -/* The whole sound-channel situation is very simple for us; | |
| - we don't support it. */ | |
| - | |
| #ifdef GLK_MODULE_SOUND | |
| -schanid_t glk_schannel_create(glui32 rock) | |
| +#define DEBUG_MODULE_SOUND 1 | |
| + | |
| +/* TODO: The code assumes in several places that only the MOD player will | |
| + be active. Obviously this has to change when we add the ability to | |
| + play samples. */ | |
| + | |
| +/* Partial sound support, courtesy of MikMod (http://www.mikmod.org) */ | |
| + | |
| +#include "gi_blorb.h" | |
| + | |
| +#define giblorb_ID_MOD (giblorb_make_id('M', 'O', 'D', ' ')) | |
| + | |
| +static channel_t *gli_channellist = NULL; | |
| +static struct timeval last_update = { 0, 0 }; | |
| + | |
| +int init_gli_schannels() | |
| { | |
| - return NULL; | |
| +#if DEBUG_MODULE_SOUND | |
| + char *buf; | |
| +#endif | |
| + | |
| + gli_channellist = NULL; | |
| + | |
| + MikMod_RegisterAllDrivers(); | |
| + MikMod_RegisterAllLoaders(); | |
| + if (MikMod_Init("")) { | |
| + fprintf(stderr, "Could not initialize sound, reason: %s\n", | |
| + MikMod_strerror(MikMod_errno)); | |
| + return FALSE; | |
| + } | |
| + | |
| +#if DEBUG_MODULE_SOUND | |
| + printf("MikMod version %ld.%ld.%ld\n", | |
| + LIBMIKMOD_VERSION_MAJOR, | |
| + LIBMIKMOD_VERSION_MINOR, | |
| + LIBMIKMOD_REVISION); | |
| + buf = MikMod_InfoDriver(); | |
| + if (buf) { | |
| + printf("Available drivers:\n%s\n", buf); | |
| + free(buf); | |
| + } | |
| + printf("Using: %s\n", md_driver->Name); | |
| +#endif | |
| + | |
| + return TRUE; | |
| +} | |
| + | |
| +void exit_gli_schannels() | |
| +{ | |
| + MikMod_Exit(); | |
| +} | |
| + | |
| +#if DEBUG_MODULE_SOUND | |
| +static long last_message_sec = 0; | |
| +static long tick_count = 0; | |
| +static long update_count = 0; | |
| +static long pot_update_count = 0; | |
| +#endif | |
| + | |
| +void gli_tick_schannels() | |
| +{ | |
| + struct timeval curtime; | |
| + struct timezone tz; | |
| + long difftime; | |
| + | |
| + /* We need to call MikMod_Update() often enough, or sound will be choppy. | |
| + | |
| + Damn, this is much harder than I thought. I want there to be a nice and | |
| + steady stream of potential updates, and it works fine most of the time. | |
| + | |
| + The scrolling map in the Zeta Space demo is a problem. Here I will get | |
| + large number of ticks, meaning that the VM is under heavier-than-usual | |
| + load, but relatively few potential updates. | |
| + | |
| + Despite several rewrites, I have not been able to do anything about | |
| + this. By the time it is discovered that too much time has passed since | |
| + the last update, it's already too late to compensate for it. | |
| + | |
| + I guess we have a bottleneck somewhere in the graphics handling. Perhaps | |
| + it just isn't possible to get this right without a separate thread... */ | |
| + | |
| + gettimeofday(&curtime, &tz); | |
| + | |
| +#if DEBUG_MODULE_SOUND | |
| + tick_count++; | |
| +#endif | |
| + | |
| + if (curtime.tv_sec - last_update.tv_sec <= 1) { | |
| + if (curtime.tv_sec == last_update.tv_sec) | |
| + difftime = curtime.tv_usec - last_update.tv_usec; | |
| + else | |
| + difftime = curtime.tv_usec + (1000000 - last_update.tv_usec); | |
| + } else | |
| + difftime = TICKLENGTH; | |
| + | |
| + if (difftime >= (9 * TICKLENGTH) / 10) { | |
| + if (Player_Active()) { | |
| + MikMod_Update(); | |
| +#if DEBUG_MODULE_SOUND | |
| + update_count++; | |
| +#endif | |
| + } | |
| + | |
| + last_update.tv_sec = curtime.tv_sec; | |
| + last_update.tv_usec = curtime.tv_usec; | |
| +#if DEBUG_MODULE_SOUND | |
| + pot_update_count++; | |
| +#endif | |
| + } | |
| + | |
| +#if DEBUG_MODULE_SOUND | |
| + if (curtime.tv_sec - last_message_sec >= 20) { | |
| + fprintf(stderr, | |
| + "%ld.%06ld: %ld ticks, %ld (%ld) updates\n", | |
| + curtime.tv_sec, curtime.tv_usec, tick_count, pot_update_count, | |
| + update_count); | |
| + tick_count = 0; | |
| + update_count = 0; | |
| + pot_update_count = 0; | |
| + last_message_sec = curtime.tv_sec; | |
| + } | |
| +#endif | |
| +} | |
| + | |
| +/* It is assumed that this function is only called from the event loop. | |
| + Break the assumption if you like, but don't blame me if you lose sound | |
| + events... */ | |
| + | |
| +Bool gli_eventloop_schannels() | |
| +{ | |
| + channel_t *chan = gli_channellist; | |
| + | |
| + gli_tick_schannels(); | |
| + | |
| + if (Player_Active()) | |
| + return FALSE; | |
| + | |
| + while (chan) { | |
| + if (chan->module) { | |
| + Player_Free(chan->module); | |
| + chan->module = NULL; | |
| + if (chan->notify != 0) { | |
| + eventloop_setevent(evtype_SoundNotify, NULL, chan->snd, chan->notify); | |
| + chan->notify = 0; | |
| + return TRUE; | |
| + } | |
| + } | |
| + chan = chan->chain_next; | |
| + } | |
| + | |
| + return FALSE; | |
| } | |
| -void glk_schannel_destroy(schanid_t chan) | |
| +channel_t *glk_schannel_create(glui32 rock) | |
| { | |
| + channel_t *chan = (channel_t *)malloc(sizeof(channel_t)); | |
| + | |
| + if (!chan) | |
| + return NULL; | |
| + | |
| + chan->rock = rock; | |
| + chan->module = NULL; | |
| + chan->vol = 0x10000; | |
| + | |
| + chan->chain_prev = NULL; | |
| + chan->chain_next = gli_channellist; | |
| + gli_channellist = chan; | |
| + if (chan->chain_next) { | |
| + chan->chain_next->chain_prev = chan; | |
| + } | |
| + | |
| + if (gli_register_obj) | |
| + chan->disprock = (*gli_register_obj)(chan, gidisp_Class_Schannel); | |
| + else | |
| + chan->disprock.ptr = NULL; | |
| + | |
| + return chan; | |
| +} | |
| + | |
| +void glk_schannel_destroy(channel_t *chan) | |
| +{ | |
| + channel_t *prev, *next; | |
| + | |
| + if (!chan) { | |
| + gli_strict_warning("schannel_destroy: invalid id."); | |
| + return; | |
| + } | |
| + | |
| + if (gli_unregister_obj) | |
| + (*gli_unregister_obj)(chan, gidisp_Class_Schannel, chan->disprock); | |
| + | |
| + if (chan->module) { | |
| + Player_Free(chan->module); | |
| + chan->module = NULL; | |
| + } | |
| + | |
| + prev = chan->chain_prev; | |
| + next = chan->chain_next; | |
| + chan->chain_prev = NULL; | |
| + chan->chain_next = NULL; | |
| + | |
| + if (prev) | |
| + prev->chain_next = next; | |
| + else | |
| + gli_channellist = next; | |
| + if (next) | |
| + next->chain_prev = prev; | |
| + | |
| + free(chan); | |
| } | |
| -schanid_t glk_schannel_iterate(schanid_t chan, glui32 *rockptr) | |
| +channel_t *glk_schannel_iterate(channel_t *chan, glui32 *rock) | |
| { | |
| - if (rockptr) | |
| - *rockptr = 0; | |
| + if (!chan) { | |
| + chan = gli_channellist; | |
| + } else { | |
| + chan = chan->chain_next; | |
| + } | |
| + | |
| + if (chan) { | |
| + if (rock) | |
| + *rock = chan->rock; | |
| + return chan; | |
| + } | |
| + | |
| + if (rock) | |
| + *rock = 0; | |
| return NULL; | |
| } | |
| -glui32 glk_schannel_get_rock(schanid_t chan) | |
| +glui32 glk_schannel_get_rock(channel_t *chan) | |
| { | |
| - gli_strict_warning("schannel_get_rock: invalid id."); | |
| - return 0; | |
| + if (!chan) { | |
| + gli_strict_warning("schannel_get_rock: invalid id."); | |
| + return 0; | |
| + } | |
| + return chan->rock; | |
| } | |
| glui32 glk_schannel_play(schanid_t chan, glui32 snd) | |
| { | |
| - gli_strict_warning("schannel_play: invalid id."); | |
| - return 0; | |
| + /* Error messages will be slightly wrong, but I'm lazy... */ | |
| + return glk_schannel_play_ext(chan, snd, 1, 0); | |
| } | |
| glui32 glk_schannel_play_ext(schanid_t chan, glui32 snd, glui32 repeats, | |
| glui32 notify) | |
| { | |
| - gli_strict_warning("schannel_play_ext: invalid id."); | |
| - return 0; | |
| + FILE *fl; | |
| + long pos; | |
| + glui32 chunktype; | |
| + | |
| + if (!chan) { | |
| + gli_strict_warning("schannel_play_ext: invalid id."); | |
| + return 0; | |
| + } | |
| + | |
| + /* Another channel is already playing? */ | |
| + if (!chan->module && Player_Active()) { | |
| + gli_strict_warning("schannel_play_exit: player can only handle one MOD at a time"); | |
| + return 0; | |
| + } | |
| + | |
| + /* TODO: Add picture_find()-style reading and caching, but that's beyond | |
| + the scope of this implementation. */ | |
| + if (!xres_is_resource_map()) { | |
| + gli_strict_warning("schannel_play_ext: no resource map."); | |
| + return 0; | |
| + } | |
| + | |
| + xres_get_resource(giblorb_ID_Snd, snd, &fl, &pos, NULL, &chunktype); | |
| + | |
| + if (!fl) { | |
| + gli_strict_warning("schannel_play_ext: internal error - no file pointer."); | |
| + return 0; | |
| + } | |
| + | |
| + /* MikMod can play samples. This may or may not include AIFF, but at | |
| + present I only have test data for MOD. I'm not even going to try and | |
| + implement SONG... */ | |
| + if (chunktype != giblorb_ID_MOD) { | |
| + gli_strict_warning("schannel_play_ext: unsupported sound format"); | |
| + return 0; | |
| + } | |
| + | |
| + if (chan->module) { | |
| + Player_Free(chan->module); | |
| + chan->module = NULL; | |
| + } | |
| + | |
| + if (repeats != 0) { | |
| + fseek(fl, pos, 0); | |
| + chan->module = Player_LoadFP(fl, 64, 0); | |
| + chan->snd = snd; | |
| + chan->notify = notify; | |
| + if (!chan->module) { | |
| + gli_strict_warning("schannel_play_ext: module loader failure"); | |
| + return 0; | |
| + } | |
| + | |
| + /* For now, only handle infinite looping. Laziness strikes again... */ | |
| + if (repeats == -1) | |
| + chan->module->wrap = 1; | |
| + | |
| + Player_Start(chan->module); | |
| + Player_SetVolume(chan->vol / 512); | |
| + } | |
| + | |
| + return 1; | |
| } | |
| void glk_schannel_stop(schanid_t chan) | |
| { | |
| - gli_strict_warning("schannel_stop: invalid id."); | |
| + if (!chan) { | |
| + gli_strict_warning("schannel_stop: invalid id."); | |
| + return; | |
| + } | |
| + | |
| + if (chan->module) { | |
| + Player_Free(chan->module); | |
| + chan->module = NULL; | |
| + } | |
| } | |
| void glk_schannel_set_volume(schanid_t chan, glui32 vol) | |
| { | |
| - gli_strict_warning("schannel_set_volume: invalid id."); | |
| + if (!chan) { | |
| + gli_strict_warning("schannel_set_volume: invalid id."); | |
| + return; | |
| + } | |
| + | |
| + chan->vol = vol; | |
| + if (chan->module) | |
| + Player_SetVolume(chan->vol / 512); | |
| } | |
| void glk_sound_load_hint(glui32 snd, glui32 flag) | |
| { | |
| - gli_strict_warning("schannel_sound_load_hint: invalid id."); | |
| + /* I doubt this will make any difference, so make it a no-op for now. */ | |
| } | |
| #endif /* GLK_MODULE_SOUND */ | |
| diff -ur xglk/xglk.c xglk+hack/xglk.c | |
| --- xglk/xglk.c Thu Apr 13 05:00:50 2000 | |
| +++ xglk+hack/xglk.c Wed Aug 8 21:49:04 2001 | |
| @@ -58,6 +58,8 @@ | |
| return FALSE; | |
| if (!init_gli_filerefs()) | |
| return FALSE; | |
| + if (!init_gli_schannels()) | |
| + return FALSE; | |
| if (!init_gli_windows()) | |
| return FALSE; | |
| diff -ur xglk/xglk_loop.c xglk+hack/xglk_loop.c | |
| --- xglk/xglk_loop.c Sun Jun 6 18:07:45 1999 | |
| +++ xglk+hack/xglk_loop.c Thu Aug 9 23:35:38 2001 | |
| @@ -7,10 +7,6 @@ | |
| #include "xglk.h" | |
| #include "xg_internal.h" | |
| -/* This is the granularity at which we check for timer events; measured | |
| - in microseconds. 1/20 second sounds good. */ | |
| -#define TICKLENGTH (50000) | |
| - | |
| static event_t *eventloop_event = NULL; | |
| static struct timeval lasttime = {0, 0}; | |
| @@ -78,6 +74,9 @@ | |
| } | |
| while (ev->type == evtype_None) { | |
| + | |
| + if (gli_eventloop_schannels()) | |
| + continue; | |
| if (xio_any_invalid) { | |
| xglk_redraw(); | |
Xet Storage Details
- Size:
- 15.1 kB
- Xet hash:
- bbd88a3988ce60275cef0a11a20108033e6ec283a4ce4563fb46bc32e8a8ed42
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.