diff -upNr tintin++/README.msp tintin++-msp/README.msp
--- tintin++/README.msp Thu Jan 1 01:00:00 1970
+++ tintin++-msp/README.msp Fri Apr 10 18:02:50 1998
@@ -0,0 +1,115 @@
+Release Notes (April 10th, 1998)
+=-=-=-=-=-=-=
+
+*** ***
+* NOTE! This software is provided with ABSOLUTELY NO warranty. If something *
+* breaks, you keep both parts. Usage implies acceptance of these terms. *
+*** ***
+
+ -- Read this, please.
+
+
+NEW COMMANDS:
+
+#msp
+This command toggles on and off msp support. Enabled by default, but you
+can add it to your startup file if you want to disable it.
+
+
+RELEASE NOTES:
+
+Sounds are expected to be found at /usr/local/share/sounds/ , and inside
+that directory, two more called samples (where the .wav files go) and
+modules (where the .uni files go). To successfully compile this patch,
+you need the MikMod 3.0.3 library available at sunsite.unc.edu (but you
+have to rebuild it, the normal build wont do). Or if you dont want to
+compile, why dont you just download the binary version? Midi files are
+NOT supported and prolly will never be: who would want to hear those ugly
+and cpu expensive files when they can have nice multichannel modules?
+This means the default extension for music files isnt .mid but .uni . As
+well, the maximum filename length is 32 bytes. Please put null.uni in its
+right directory when installing and dont delete it.. optionally, you
+might rename some other module as null.uni, and it will be played as
+background when no other music has been selected.
+
+.uni is the native module format for the mikmod library functions. I
+suggest you to use mikcvt to convert your old modules to .uni modules.
+This way, mikmod wont have to convert the modules over and over to its
+internal format when it loads a new one. mikcvt 3.0 is supplied with this
+patch, since for some weird reason it was left out of the 3.0.x UNIX / Linux
+libraries.
+
+!!SOUND Formats supported: wav
+!!MUSIC Formats supported: it xm s3m mod mtm stm dsm med far ult 669 uni
+
+The patch leaves lots of room for improvement.. it just works, doesn't
+aspire for efficience or elegance. I would had liked to add mixing of
+multiple sound effects, but msp only supports one at a time *mutter*
+If you have any patches for the patch or problems running with it, let me
+know.. I don't make promises, but I'll try to give you a hand.
+
+
+COMPILING:
+
+To compile, apply the patch and compile tintin as normal, and then
+
+gcc -O2 -s -DMSP_FINAL sndserver.c -o sndserver -Lmikmod/lib -lmikmod -lmmio
+
+Copy this file to the same directory where the new tintin is, and
+remember to copy null.uni to /usr/local/share/sounds/modules/
+
+You can compile mikcvt too:
+gcc -O2 -s mikcvt.c -o mikcvf -Lmikmod/lib -lmikmod -lmmio
+
+
+KNOWN PROBLEMS:
+
+Note that in some development kernels sound support is broken (2.1.53 to
+2.1.94, current last one), and for others you must manually insert the
+sound module (as in 2.1.43) before starting tintin. If tintin freezes
+just when it starts up at the point that you cant see what you are
+typing, that means it's still waiting for sndserver.. make sure its in
+the correct place. Btw this isn't tested: it compiles, it runs, you can
+turn it off in case of problems.. what else do you want for what you are
+paying? :)
+
+
+OTHER CHANGES:
+
+The other of the changes that come with this patch is that color is
+ignored when matchiing text and triggers. That is,
+
+Isildur's backstab ANNIHILATES you!
+ ^^^^^^^^^^^
+
+If the underlined word was, say, in red, an action trigger with the text
+{devastates you} wouldnt work before. Not too good :)
+
+Thats all, beta tester ;)
+
+
+PLUG:
+
+Btw, if you'd like to try a very unique MUD with non stock high quality
+areas, with all the good features and none of the silly ones, and a good
+role playing atmosphere with non abusing hard working underpaid imms
+and nice players, try:
+
+ ARCADIA 2 (Beta)
+ telnet://arcadia.net:6000
+
+ http://www.arcadia.net
+
+
+CONTACT INFO:
+
+Ragnar Hojland Espinosa | Since it's untested, I'd appreciate some
+ | feedback: Does it work for you? Or maybe
+http://www.lightside.ddns.org | It doesn't? Why not? How did you fix it?
+ragnar@lightside.ddns.org | .. Don't be like Nezmor, write something
+tech.support@redestb.es | that does make sense ;)
+
+____/| Ragnar Hojland Fingerprint 94C4B
+\ o.O| 2F0D27DE025BE2302C
+ =(_)= "Thou shalt not follow the NULL pointer for 104B78C56 B72F0822
+ U chaos and madness await thee at its end." hkp://keys.pgp.com
diff -upNr tintin++/src/Makefile tintin++-msp/src/Makefile
--- tintin++/src/Makefile Mon Apr 25 13:32:04 1994
+++ tintin++-msp/src/Makefile Fri Apr 10 17:54:48 1998
@@ -5,8 +5,8 @@
# I'm using GNU's gcc compiler. The most important is that the
# compiler is ANSI-compatible. If gcc isn't installed on your
# system, then try change the 'gcc' below to 'cc' If
-#CC = cc -O
-CC = gcc -O
+#CC = cc -O
+CC = gcc
# Some people's ANSI-compiler somehow don't have the full
# ANSI-defined standard-library. Uncomment the lines below
@@ -23,7 +23,7 @@ CC = gcc -O
# If you are using a SYS V varient unix (IRIX <sgi>, HP/UX <hp>, Linux, etc.)
# define F3 so that term echoing will function properly. If you are using a
# BSD varient (SunOS, 386BSD, BSD/I, FreeBSD, etc..) leave F3 commented out.
-#F3 = -DSYSV
+F3 = -DSYSV
# If you plan on doing debugging (with gdb), it is very helpful to turn all
# the alarms off so that you can step through the code without having to
@@ -35,8 +35,12 @@ CC = gcc -O
#F5 = -DSOCK_FIX
-CFLAGS= $(F1) $(F2) $(F3) $(F4) $(F5)
-LFLAGS= -s
+FMSP = -DDEFAULT_SOUND_PATH=\"/usr/local/share/sounds/\" \
+ -Imikmod/include -DMSP_FINAL -O2 -g0
+
+CFLAGS= $(F1) $(F2) $(F3) $(F4) $(F5) $(FMSP)
+LFLAGS= -Lmikmod/lib -g0 -s
+MSPLIB=-lmikmod -lmmio
# BINDIR is the directory you wish tt++ to be placed if you wish to use
# make install.
@@ -57,8 +61,8 @@ OFILES = main.o parse.o action.o alias.o
files.o history.o ticks.o misc.o path.o net.o llist.o utils.o echo.o \
variables.o highlight.o antisub.o ivars.o help.o text.o glob.o
-tintin++: $(OFILES)
- $(CC) $(CFLAGS) $(LFLAGS) -o ../tt++ $(OFILES) $(LIB)
+tintin++: $(OFILES)
+ $(CC) $(CFLAGS) $(LFLAGS) -o tt++ $(OFILES) $(LIB)
main.o: tintin.h
parse.o: tintin.h
diff -upNr tintin++/src/action.c tintin++-msp/src/action.c
--- tintin++/src/action.c Sun Apr 24 21:00:37 1994
+++ tintin++-msp/src/action.c Fri Apr 10 17:54:48 1998
@@ -270,6 +270,36 @@ int check_a_action(line, action, ses)
char result[BUFFER_SIZE];
char *temp2, *tptr, *lptr, *lptr2;
int i,flag_anchor, count, len, flag;
+
+#if !defined NO_COLORSTRIP
+ char color_stripped[BUFFER_SIZE];
+ if (1)
+ {
+ char *cs = &color_stripped[0], *cslp = line;
+
+ while (*cslp)
+ {
+ if (*cslp == 27)
+ {
+ while (*(++cslp) && *cslp != 'm' && *cslp != ' ')
+ {
+ /* empty body */
+ }
+ }
+ else
+ {
+ *(cs++) = *(cslp);
+ }
+
+ cslp++;
+ }
+
+ *cs = '\0';
+ line = &color_stripped[0];
+ }
+#endif
+
+
for (i=0; i<10; i++) var_len[i]=-1;
flag_anchor=FALSE;
lptr=line;
diff -upNr tintin++/src/b.c tintin++-msp/src/b.c
--- tintin++/src/b.c Thu Jan 1 01:00:00 1970
+++ tintin++-msp/src/b.c Fri Apr 10 17:54:48 1998
@@ -0,0 +1,32 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "a.h"
+
+// server
+int main()
+{
+ char buf[255];
+ int fd, fd2;
+
+ mkfifo (MSP_PIPE_1, S_IRUSR|S_IWUSR);
+ mkfifo (MSP_PIPE_2, S_IRUSR|S_IWUSR);
+
+ fd = open (MSP_PIPE_1, O_RDONLY);
+
+ while (read (fd, buf, 1) < 1) ;
+ puts ("there you are!");
+
+ fd2 = open (MSP_PIPE_2, O_WRONLY);
+
+// sprintf (buf, "1\na.mod\n2\n1\n3\n1\nnot.wav\n2\n0\n3\n");
+// sprintf (buf, "1\n/tmp/ENIGMA.uni\n2\n1\n3\n");
+ sprintf(buf, "1\n/usr/local/share/sounds/samples/not.wav\n2\n0\n5\n-1\n3\n");
+ write (fd2, buf, strlen(buf)+1);
+ sleep (10000);
+
+ return 0;
+}
diff -upNr tintin++/src/main.c tintin++-msp/src/main.c
--- tintin++/src/main.c Mon Apr 25 13:34:15 1994
+++ tintin++-msp/src/main.c Fri Apr 10 18:09:48 1998
@@ -9,16 +9,21 @@
#include <signal.h>
#include "tintin.h"
#include <stdlib.h>
-#if IRIX
-#include <time.h>
+#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
-#include <sys/time.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#if IRIX
+#include <time.h>
#endif
-
+#include <ctype.h>
#ifndef BADSIG
#define BADSIG (void (*)())-1
#endif
+#include <fcntl.h>
+#include "msp.h"
+
/*************** globals ******************/
int term_echoing=TRUE;
int echo=DEFAULT_ECHO;
@@ -39,7 +44,8 @@ int antisubnum=0;
int verbatim=0;
char homepath[1025];
char E=27;
-
+char soundpath[1025];
+int msp=TRUE;
struct session *sessionlist, *activesession;
struct listnode *common_aliases, *common_actions, *common_subs, *common_myvars;
struct listnode *common_highs, *common_antisubs, *common_pathdirs;
@@ -62,6 +68,9 @@ void snoop();
void tintin_puts2();
int interpret_buffer();
+int msp_fdi;
+int msp_fdo;
+
/************ externs *************/
extern int ticker_interrupted, time0;
extern int tick_size, sec_to_tick;
@@ -77,8 +86,8 @@ extern struct listnode *init_list();
extern void term_noecho();
extern void read_complete();
extern void syserr();
-extern int time();
-extern void alarm();
+extern int mytime();
+//extern void alarm();
extern int do_one_antisub();
extern void do_one_sub();
extern void do_one_high();
@@ -123,6 +132,341 @@ void tstphandler(sig, code, scp, addr)
/* main() - show title - setup signals - init lists - readcoms - tintin() */
/**************************************************************************/
+typedef struct msp_song msp_song;
+struct msp_song
+{
+ char file[0xff-12];
+ int vol;
+ int repeats;
+ int cont;
+};
+
+typedef struct msp_sample msp_sample;
+struct msp_sample
+{
+ msp_sample *next;
+ char file[0xff-24];
+ int vol;
+ int repeats;
+ int priority;
+ int voice;
+ int cont;
+};
+
+msp_sample *msp_queue;
+msp_song actual_song;
+msp_sample actual_sample;
+
+void msp_fork()
+{
+ tintin_puts2 ("Waiting for soundserver.. ",NULL);
+#ifdef MSP_FINAL
+ if (fork() == 0) {
+ if (execlp ("./sndserver", "./sndserver", 0) < 0) {
+ tintin_puts2 ("Couldn't start sndserver.",NULL);
+ };
+ exit(1);
+ }
+#endif
+}
+
+// return a number between 0 and n-1 included
+#define RANDOM_RAGNAR(n) ((int) ((float)(n)*rand()/(RAND_MAX+1.0)))
+
+void init_msp()
+{
+ char buf[0xf];
+ msp_queue = 0;
+
+ actual_song.file[0] = 0;
+ actual_song.repeats = 0;
+ actual_song.vol = 0;
+ actual_song.cont = 0;
+
+ actual_sample.file[0] = 0;
+ actual_sample.repeats = 0;
+ actual_sample.vol = 0;
+ actual_sample.cont = 0;
+ actual_sample.priority = -1;
+ actual_sample.voice = -1;
+
+ mkfifo (MSP_PIPE_1, S_IRUSR|S_IWUSR);
+ mkfifo (MSP_PIPE_2, S_IRUSR|S_IWUSR);
+ msp_fdi = open (MSP_PIPE_1, O_RDONLY);
+ while (read (msp_fdi, buf, 1) < 1) ;
+ msp_fdo = open (MSP_PIPE_2, O_WRONLY);
+
+ srand (time(NULL) ^ getpid());
+}
+
+void end_msp()
+{
+ close (msp_fdo);
+ close (msp_fdi);
+}
+
+msp_sample* new_msp_sample()
+{
+ return (msp_sample*) malloc(sizeof(msp_sample));
+}
+
+void msp_find_file (const char *file, char *dest, int sound)
+{
+ DIR *d;
+ struct dirent *de;
+ char files[256][32];
+ int max = 0;
+ char buf[256];
+ char *p = &buf[0];
+
+ strcpy (dest, DEFAULT_SOUND_PATH);
+ strcat (dest, sound ? "/samples/" : "/modules/");
+ strcpy (buf, file);
+
+ while (*p && *p != '*') {
+ ++p;
+ }
+
+ if (!p) {
+ p = &buf[0];
+ while (*p && *p != '.') {
+ ++p;
+ }
+ strcat (dest, file);
+ if (!p) {
+ strcat (dest, sound ? ".wav" : ".uni");
+ }
+ return;
+ }
+
+ *p = 0;
+ d = opendir (dest);
+
+ // cheap way.. forget about glob or scandir, mallocs or frees
+ while (1) {
+ de = readdir (d);
+ if (!de || max == 256) {
+ break;
+ }
+ if (strstr (de->d_name, file) == &de->d_name[0]) {
+ strncpy (files[max], de->d_name, 32);
+ files[max++][31] = 0;
+ }
+ }
+
+ strcat (dest, max ? files[RANDOM_RAGNAR(max)] : file );
+ closedir (d);
+}
+
+void msp_request_sample (char *file, int vol, int repeats, int priority, int cont)
+{
+ char buf[0xff];
+
+ if (file[0] && !strcmp (file, "Off") && actual_sample.voice >= 0) {
+ sprintf (buf, "%d\n%d\n%d\n%d\n%d\n",
+ MSP_TYPE, MSP_TYPE_SOUND,
+ MSP_OFF, actual_sample.voice,
+ MSP_APPLY);
+ actual_sample.file[0] = 0;
+ actual_sample.voice = -1;
+ } else {
+
+ sprintf (buf, "%d\n%d\n%d\n%d\n",
+ MSP_TYPE, MSP_TYPE_SOUND,
+ MSP_PLAYING, actual_sample.voice);
+ write (msp_fdo, buf, strlen(buf)+1);
+ read (msp_fdi, buf, 32);
+
+ if (atoi(buf) == FALSE ) { // worked with 1 too
+ // clean sample if sound is over
+ actual_sample.priority = -1;
+ actual_sample.file[0] = 0;
+ actual_sample.voice = -1;
+ }
+
+ if (actual_sample.voice > -1) {
+ if (priority < actual_sample.priority) {
+ return;
+ }
+ }
+
+ msp_find_file (file, &buf[0], 1);
+
+ if (!strcmp(buf, actual_sample.file) && actual_sample.cont) {
+ actual_sample.repeats = repeats;
+ actual_sample.vol = vol;
+ sprintf (buf, "%d\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n",
+ MSP_RESET,
+ MSP_TYPE, MSP_TYPE_SOUND,
+ MSP_VOLUME, 128 * actual_sample.vol / 100,
+ MSP_COUNT, actual_sample.repeats,
+ MSP_APPLY);
+ } else {
+ strcpy (actual_sample.file, buf);
+ actual_sample.vol = vol;
+ actual_sample.repeats = repeats;
+ actual_sample.cont = cont;
+ actual_sample.priority = priority;
+
+ sprintf (buf, "%d\n%s\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n",
+ MSP_FILE, actual_sample.file,
+ MSP_TYPE, MSP_TYPE_SOUND,
+ MSP_VOLUME, 128 * actual_sample.vol / 100,
+ MSP_COUNT, actual_sample.repeats,
+ MSP_PLAY);
+
+ write (msp_fdo, buf, strlen(buf)+1);
+ read (msp_fdi, buf, 32);
+ actual_sample.voice = atoi (buf);
+ return;
+ }
+ }
+
+ write (msp_fdo, buf, strlen(buf)+1);
+}
+
+void msp_request_music (char *file, int vol, int repeats, int priority, int cont)
+{
+ char buf[0xff];
+
+ if (!strcmp (file, "Off")) {
+ sprintf (buf, "%d\n%d\n%d\n%d\n",
+ MSP_TYPE, MSP_TYPE_MUSIC,
+ MSP_OFF,
+ MSP_APPLY);
+ actual_song.file[0] = 0;
+ } else {
+
+ msp_find_file (file, &buf[0], 0);
+
+ if (!strcmp(buf, actual_song.file) && actual_song.cont) {
+ actual_song.repeats = repeats;
+ actual_song.vol = vol;
+ sprintf (buf, "%d\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n",
+ MSP_RESET,
+ MSP_TYPE, MSP_TYPE_MUSIC,
+ MSP_VOLUME, 128 * actual_song.vol / 100,
+ MSP_COUNT, actual_song.repeats,
+ MSP_APPLY);
+ } else {
+ strcpy (actual_song.file, buf);
+ actual_song.vol = vol;
+ actual_song.repeats = repeats;
+ actual_song.cont = cont;
+
+ sprintf (buf, "%d\n%s\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n",
+ MSP_FILE, actual_song.file,
+ MSP_TYPE, MSP_TYPE_MUSIC,
+ MSP_VOLUME, 128 * actual_song.vol / 100,
+ MSP_COUNT, actual_song.repeats,
+ MSP_PLAY);
+ }
+ }
+
+ write (msp_fdo, buf, strlen(buf)+1);
+}
+
+
+int check_msp (char *arg)
+{
+ char sound;
+ char file[0xff];
+ char buf[0xff];
+ int vol = 100;
+ int repeats = 1;
+ int priority = 50;
+ int cont = 1;
+ int *what;
+
+ char *h = arg;
+ char *p;
+
+ if (!msp || arg[0] != '!') {
+ return FALSE;
+ }
+
+ if (strstr(arg, "!!SOUND(")) {
+ sound = 1;
+ } else if (strstr(arg, "!!MUSIC(")) {
+ sound = 0;
+ } else {
+ return FALSE;
+ }
+
+ while (*h && *h != ')') {
+ ++h;
+ }
+
+ if (!h) {
+ return FALSE;
+ }
+
+ h = arg;
+
+ while (isspace(*h) || *h != '(') {
+ ++h;
+ }
+ ++h;
+
+ p = &file[0];
+ while (*h != ')' && !isspace(*h)) {
+ *(p++) = *(h++);
+ }
+ *p = 0;
+
+ while (1) {
+ p = &buf[0];
+ while (*h && (isspace(*h) || *h == '=')) {
+ ++h;
+ }
+ if (!*h || *h == ')') {
+ break;
+ }
+ switch (*h) {
+ case 'V':
+ what = &vol; break;
+ case 'L':
+ what = &repeats; break;
+ case 'P':
+ what = &priority; break;
+ case 'C':
+ what = &cont; break;
+ case 'T':
+ default:
+// what = NULL; return FALSE;
+ while (*h && !isspace(*(h++))) ;
+ continue;
+ }
+
+ // if (!what) {
+ // while (!isspace(*h) || *h == '=') {
+ // ++h;
+ // };
+ // } else {
+ while (!isdigit(*h) && *h != '-') {
+ ++h;
+ }
+
+ while (!isspace(*h) && *h != ')') {
+ *(p++) = *(h++);
+ }
+ *p = 0;
+ *what = atoi (buf);
+
+ }
+
+ if (sound) {
+ msp_request_sample (file, vol, repeats, priority, cont);
+ } else {
+ msp_request_music (file, vol, repeats, priority, cont);
+ }
+
+ // we choose to ignore the rest of the line
+ arg[0] = '.'; arg[1] = 0;
+ return TRUE;
+}
+
+
void main(argc, argv, environ)
int argc;
char **argv;
@@ -131,6 +475,9 @@ void main(argc, argv, environ)
struct session *ses;
char *strptr, temp[BUFFER_SIZE];
int arg_num;
+
+ msp_fork();
+
#if defined(SYSV)
init_echo();
#endif
@@ -158,6 +505,8 @@ void main(argc, argv, environ)
syserr("signal SIGINT");
if(signal(SIGALRM, tick_func)==BADSIG)
syserr("signal SIGALRM");
+ if(signal(SIGPIPE, myquitsig)==BADSIG)
+ syserr("signal SIGPIPE");
/* CHANGED to get rid of double-echoing bug when tintin++ gets suspended */
if(signal(SIGTSTP, tstphandler)==BADSIG)
syserr("signal SIGTSTP");
@@ -183,8 +532,9 @@ void main(argc, argv, environ)
mesvar[5]=DEFAULT_VARIABLE_MESS;
mesvar[6]=DEFAULT_PATHDIR_MESS;
*homepath='\0';
+ *soundpath='\0';
if (!strcmp(DEFAULT_FILE_DIR, "HOME"))
- if (strptr = getenv("HOME"))
+ if ( (strptr = getenv("HOME")) )
strcpy(homepath, strptr);
else *homepath = '\0';
else strcpy(homepath, DEFAULT_FILE_DIR);
@@ -195,6 +545,7 @@ void main(argc, argv, environ)
verbose=TRUE;
}
}
+ strcpy (soundpath, DEFAULT_SOUND_PATH);
if(argc > arg_num && argv[arg_num]) {
activesession=read_command(argv[arg_num], NULL);
}
@@ -203,6 +554,7 @@ void main(argc, argv, environ)
strcat(temp,"/.tintinrc");
activesession=read_command(temp, NULL);
}
+ init_msp();
tintin();
}
@@ -214,16 +566,19 @@ void tintin()
char buffer[BUFFER_SIZE], strng[80];
int didget;
int readfdmask, done;
+ signed int sel;
struct session *sesptr;
*k_input='\0';
+
while(TRUE) {
readfdmask=1;
for(sesptr=sessionlist; sesptr; sesptr=sesptr->next)
readfdmask|=sesptr->socketbit;
ticker_interrupted=FALSE;
- if(select(32, &readfdmask, 0, 0, 0)<0 && !ticker_interrupted)
- syserr("select");
+ sel = select (32, &readfdmask, 0, 0, 0);
+ if(sel<0 && !ticker_interrupted)
+ syserr("select");
if(ticker_interrupted)
ticker_interrupted=FALSE;
else {
@@ -624,6 +979,9 @@ void do_one_line(line, ses)
char *line;
struct session *ses;
{
+ if (check_msp(line)) {
+ return;
+ }
if (!presub && !ses->ignore)
check_all_actions(line,ses);
if (!togglesubs)
@@ -785,10 +1143,13 @@ static void myquitsig()
if (is_split)
write(1, strng, strlen(strng));
+ end_msp();
printf("\n\rYour fireball hits TINTIN with full force, causing an immediate death.\n\r");
printf("TINTIN is dead! R.I.P.\n\r");
printf("Your blood freezes as you hear TINTIN's death cry.\n\r");
term_echo();
+ unlink (MSP_PIPE_1);
+ unlink (MSP_PIPE_2);
exit(0);
}
diff -upNr tintin++/src/mikcvt.c tintin++-msp/src/mikcvt.c
--- tintin++/src/mikcvt.c Thu Jan 1 01:00:00 1970
+++ tintin++-msp/src/mikcvt.c Fri Apr 10 18:08:24 1998
@@ -0,0 +1,388 @@
+/*
+
+ --> Mikmod UniFormat Conversion Utility
+ -> Version 3.0 -- Released August 20th, 1997.
+
+FileName: MIKCVT.C
+
+Description:
+Program to convert any supported module into a UniMOD [.UNI] module.
+If compiled and run under DOS/Windows, this MIKCVT.C does not sup-
+port wildcards. This feature is intentionally left out for now to
+maintain easy portability to the Unix platform.
+
+DOS users can add wildcard support themselves by following the ngetopt
+example in MIKMOD.C.
+
+
+Portability:
+All systems - all compilers
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mikmod/include/mikmod.h"
+
+
+// Declare external loaders:
+
+
+static FILE *fpi, *fpo;
+static UBYTE unitag[] = "UN06\x1A";
+
+
+/***************************************************************************
+***************************************************************************/
+
+BOOL TrkCmp(UBYTE * t1, UBYTE * t2)
+{
+ UWORD l1, l2;
+
+ if((t1 == NULL) || (t2 == NULL))
+ return 0;
+
+ l1 = TrkLen(t1);
+ l2 = TrkLen(t2);
+
+ if (l1 != l2)
+ return 0;
+
+ return (MyCmp(t1, t2, l1));
+}
+
+
+
+void ReplaceTrack(UNIMOD * mf, int t1, int t2)
+{
+ int t;
+
+ for(t=0; t<mf->numpat*mf->numchn; t++)
+ { if(mf->patterns[t] == t1)
+ mf->patterns[t] = t2;
+ }
+}
+
+
+
+void OptimizeTracks(UNIMOD * mf)
+
+// Optimizes the number of tracks in a modfile by removing tracks with
+// identical contents.
+
+{
+ int t, u, same, newcnt = 0;
+ UBYTE *ta;
+ UBYTE **newtrk;
+
+ if (!(newtrk = (UBYTE **)malloc(mf->numtrk * sizeof(UBYTE *)))) return;
+
+ for(t=0; t<mf->numtrk; t++)
+ { // ta is track to examine
+
+ ta = mf->tracks[t];
+
+ // does ta look familiar ?
+
+ for(same = u = 0; u<newcnt; u++)
+ { if(TrkCmp(ta, newtrk[u]))
+ { same = 1;
+ break;
+ }
+ }
+
+ if(same)
+ { ReplaceTrack(mf, t, u);
+ } else
+ { ReplaceTrack(mf, t, newcnt);
+ newtrk[newcnt++] = ta;
+ }
+
+ printf("\rOptimizing: %d\%", (t * 100L) / mf->numtrk);
+ }
+
+ printf("\rOptimized : %d tracks -> %d tracks\n", mf->numtrk, newcnt);
+
+ free(mf->tracks);
+ mf->tracks = newtrk;
+ mf->numtrk = newcnt;
+}
+
+
+/***************************************************************************
+***************************************************************************/
+
+CHAR *stripname(CHAR *path, CHAR *ext)
+
+// Strips the filename from a path, and replaces or adds
+// a new extension to it.
+
+{
+ CHAR *n, *m;
+ static CHAR newname[256];
+
+ // extract the filename from the path
+
+#ifdef unix
+ n = ((n = strrchr(path, '/')) == NULL) ? path : n + 1;
+#else
+ n = ((n = strrchr(path, '\\')) == NULL) ? path : n + 1;
+ if(m = strrchr(n, ':')) n=m+1;
+#endif
+
+ // copy the filename into 'newname'
+ strncpy(newname,n,255);
+ newname[255] = 0;
+
+ // remove the extension
+ if (n = strrchr(newname, '.'))
+ *n = 0;
+
+ // and tack on the new extension
+ return strcat(newname, ext);
+}
+
+
+/***************************************************************************
+***************************************************************************/
+
+int main(int argc, char *argv[])
+{
+ UNIMOD *mf;
+ SAMPLE *s;
+ INSTRUMENT *i;
+ int t, v, w, strip = 0, numsmp, numins;
+ CHAR *outname;
+
+
+
+ puts("\n"
+ "MIKCVT v3.0 - MikMod UniFormat Conversion Utility\n"
+ "=================================================\n");
+
+
+ // Register the NoSound driver only - the modules will not be played.
+
+ MikMod_RegisterDriver(drv_nos);
+ MikMod_RegisterAllLoaders();
+
+ MD_Init(); // nosound driver HAS to initialize!
+
+
+ if(argc < 2)
+ { // display a usage message
+
+ puts("Usage: MIKCVT [-strip] <fletch.mod> ...\n\n"
+ "-strip: Leave all text out from the UNI file.\n\n");
+
+ exit(-1);
+ }
+
+ for (t=1; t<argc; t++)
+ { if((t == 1) && (!strcmp(argv[1], "-strip")))
+ {
+ strip = 1;
+ puts("Stripping all text.\n");
+
+ continue;
+ }
+
+ // Open the first file (source module)
+
+ printf("In file : %s\n", argv[t]);
+ if((fpi = fopen(argv[t], "rb")) == NULL)
+ { printf("MikCvt Error: Error opening input file\n");
+ break;
+ }
+
+ // Open the desination module
+
+ outname = stripname(argv[t], ".uni");
+ printf("Out file: %s\n", outname);
+ if ((fpo = fopen(outname, "wb")) == NULL)
+ { printf("MikCvt Error: Error opening output file\n");
+ break;
+ }
+
+ // load the module .. maxchan of 0, because we won't be playing
+ // anything.
+
+ mf = ML_LoadFP(fpi,0);
+
+ // didn't work -> exit with error
+
+ if (mf == NULL)
+ { printf("MikCvt Error: %s\n", _mm_errmsg[_mm_errno]);
+ fclose(fpi);
+ break;
+ }
+
+ printf("Songname: %s\n"
+ "Modtype : %s\n",
+ mf->songname,
+ mf->modtype);
+
+ numsmp = mf->numsmp;
+ numins = mf->numins;
+ OptimizeTracks(mf);
+
+
+ // Write UNI header
+ // UNI format version 3.00 (#6)
+
+ _mm_write_UBYTES(unitag, 5, fpo);
+
+ _mm_write_M_UWORD(mf->flags, fpo);
+ _mm_write_UBYTE(mf->numchn, fpo);
+ _mm_write_UBYTE(mf->numvoices, fpo);
+ _mm_write_M_UWORD(mf->numpos, fpo);
+ _mm_write_M_UWORD(mf->numpat, fpo);
+ _mm_write_M_UWORD(mf->numtrk, fpo);
+ _mm_write_M_UWORD(numins, fpo);
+ _mm_write_M_UWORD(numsmp, fpo);
+ _mm_write_M_UWORD(mf->reppos, fpo);
+ _mm_write_UBYTE(mf->initspeed, fpo);
+ _mm_write_UBYTE(mf->inittempo, fpo);
+ _mm_write_UBYTE(mf->initvolume, fpo);
+
+ StringWrite(strip ? NULL : mf->songname, fpo);
+ StringWrite(strip ? NULL : mf->composer, fpo);
+ StringWrite(strip ? NULL : mf->comment, fpo);
+
+ _mm_write_UBYTES(mf->positions, mf->numpos, fpo);
+ _mm_write_M_UWORDS(mf->panning, mf->numchn, fpo);
+ _mm_write_UBYTES(mf->chanvol, mf->numchn, fpo);
+
+ // Write sample information
+
+ puts("Writing sample header information.. ");
+
+ s = mf->samples;
+ for(v=0; v<numsmp; v++, s++)
+ { _mm_write_M_UWORD(s->flags, fpo);
+ _mm_write_M_ULONG(s->speed, fpo);
+ _mm_write_UBYTE(s->volume, fpo);
+ _mm_write_M_UWORD(s->panning, fpo);
+ _mm_write_M_ULONG(s->length, fpo);
+ _mm_write_M_ULONG(s->loopstart, fpo);
+ _mm_write_M_ULONG(s->loopend, fpo);
+ _mm_write_M_ULONG(s->susbegin, fpo);
+ _mm_write_M_ULONG(s->susend, fpo);
+
+ _mm_write_UBYTE(s->globvol, fpo);
+ _mm_write_UBYTE(s->vibflags, fpo);
+ _mm_write_UBYTE(s->vibtype, fpo);
+ _mm_write_UBYTE(s->vibsweep, fpo);
+ _mm_write_UBYTE(s->vibdepth, fpo);
+ _mm_write_UBYTE(s->vibrate, fpo);
+
+ StringWrite(strip ? NULL : s->samplename, fpo);
+ }
+
+
+ // Write instruments
+
+ if(mf->flags & UF_INST)
+ { // This module uses instrument information, so save it out
+
+ puts("Writing instrument header information.. ");
+
+ i = mf->instruments;
+ for(v=0; v<numins; v++, i++)
+ { _mm_write_UBYTE(i->flags, fpo);
+ _mm_write_UBYTE(i->nnatype, fpo);
+ _mm_write_UBYTE(i->dca, fpo);
+ _mm_write_UBYTE(i->dct, fpo);
+ _mm_write_UBYTE(i->globvol, fpo);
+ _mm_write_M_UWORD(i->panning, fpo);
+
+ _mm_write_UBYTE(i->pitpansep, fpo);
+ _mm_write_UBYTE(i->pitpancenter, fpo);
+ _mm_write_UBYTE(i->rvolvar, fpo);
+ _mm_write_UBYTE(i->rpanvar, fpo);
+
+ _mm_write_M_UWORD(i->volfade, fpo);
+
+ // Dump out the volume envelope
+
+ _mm_write_UBYTE(i->volflg, fpo);
+ _mm_write_UBYTE(i->volpts, fpo);
+ _mm_write_UBYTE(i->volsusbeg, fpo);
+ _mm_write_UBYTE(i->volsusend, fpo);
+ _mm_write_UBYTE(i->volbeg, fpo);
+ _mm_write_UBYTE(i->volend, fpo);
+
+ for(w=0; w<i->volpts; w++)
+ { _mm_write_M_SWORD(i->volenv[w].pos, fpo);
+ _mm_write_M_SWORD(i->volenv[w].val, fpo);
+ }
+
+ // Dump out the panning envelope
+
+ _mm_write_UBYTE(i->panflg, fpo);
+ _mm_write_UBYTE(i->panpts, fpo);
+ _mm_write_UBYTE(i->pansusbeg, fpo);
+ _mm_write_UBYTE(i->pansusend, fpo);
+ _mm_write_UBYTE(i->panbeg, fpo);
+ _mm_write_UBYTE(i->panend, fpo);
+
+ for(w=0; w<i->panpts; w++)
+ { _mm_write_M_SWORD(i->panenv[w].pos, fpo);
+ _mm_write_M_SWORD(i->panenv[w].val, fpo);
+ }
+
+ // Dump out the pitch envelope
+
+ _mm_write_UBYTE(i->pitflg, fpo);
+ _mm_write_UBYTE(i->pitpts, fpo);
+ _mm_write_UBYTE(i->pitsusbeg, fpo);
+ _mm_write_UBYTE(i->pitsusend, fpo);
+ _mm_write_UBYTE(i->pitbeg, fpo);
+ _mm_write_UBYTE(i->pitend, fpo);
+
+ for(w=0; w<i->pitpts; w++)
+ { _mm_write_M_SWORD(i->pitenv[w].pos, fpo);
+ _mm_write_M_SWORD(i->pitenv[w].val, fpo);
+ }
+
+ _mm_write_UBYTES(i->samplenumber, 120, fpo);
+ _mm_write_UBYTES(i->samplenote, 120, fpo);
+
+ StringWrite(strip ? NULL : i->insname, fpo);
+ }
+ }
+
+ // Write pattern information
+
+ _mm_write_M_UWORDS(mf->pattrows, mf->numpat, fpo);
+ _mm_write_M_UWORDS(mf->patterns, mf->numpat * mf->numchn, fpo);
+
+ // Write track information
+
+ for(v=0; v<mf->numtrk; v++)
+ { _mm_write_M_UWORD(TrkLen(mf->tracks[v]), fpo);
+ _mm_write_UBYTES(mf->tracks[v], TrkLen(mf->tracks[v]), fpo);
+ }
+
+
+ // Now dump out the sampled data
+
+ s = mf->samples;
+ for(v=0; v<numsmp; v++, s++)
+ { if(s->seekpos) _mm_fseek(fpi, s->seekpos, SEEK_SET);
+ _mm_copyfile(fpi, fpo, s->length * ((s->flags & SF_16BITS) ? 2 : 1));
+ }
+
+ puts("Done.");
+
+ // and clean up
+
+ fclose(fpo);
+ fclose(fpi);
+ MikMod_FreeSong(mf);
+ }
+ return 0;
+}
+
diff -upNr tintin++/src/misc.c tintin++-msp/src/misc.c
--- tintin++/src/misc.c Sun Apr 24 21:00:52 1994
+++ tintin++-msp/src/misc.c Fri Apr 10 17:54:48 1998
@@ -29,6 +29,7 @@ extern int togglesubs;
extern char vars[10][BUFFER_SIZE]; /* the %0, %1, %2,....%9 variables */
extern int mesvar[7];
extern int verbatim;
+extern int msp;
/****************************/
/* the cr command */
/****************************/
@@ -322,6 +323,16 @@ void snoop_command(arg, ses)
}
else
tintin_puts("#NO SESSION ACTIVE => NO SNOOPING", ses);
+}
+
+void msp_command(ses)
+ struct session *ses;
+{
+ msp=!msp;
+ if(msp)
+ tintin_puts("#MSP IS NOW ON.", ses);
+ else
+ tintin_puts("#MSP IS NOW OFF.", ses);
}
/**************************/
diff -upNr tintin++/src/msp.h tintin++-msp/src/msp.h
--- tintin++/src/msp.h Thu Jan 1 01:00:00 1970
+++ tintin++-msp/src/msp.h Fri Apr 10 17:54:48 1998
@@ -0,0 +1,22 @@
+#define MSP_POLL_USECS 100000
+#define MSPSND_MUSIC_CHANNELS 16
+
+#define MSP_FILE 1
+#define MSP_TYPE 2
+#define MSP_PLAY 3
+#define MSP_VOLUME 4
+#define MSP_COUNT 5
+#define MSP_OFF 6
+#define MSP_RESET 7
+#define MSP_APPLY 8
+#define MSP_PLAYING 9
+
+#define MSP_TYPE_SOUND 0
+#define MSP_TYPE_MUSIC 1
+
+#define TYPE_IGNORE 0
+#define TYPE_INT 1
+#define TYPE_STR 2
+
+#define MSP_PIPE_1 "/tmp/tintin++.msp-1"
+#define MSP_PIPE_2 "/tmp/tintin++.msp-2"
diff -upNr tintin++/src/parse.c tintin++-msp/src/parse.c
--- tintin++/src/parse.c Mon Apr 25 13:51:30 1994
+++ tintin++-msp/src/parse.c Fri Apr 10 17:54:48 1998
@@ -428,6 +428,9 @@ struct session *parse_tintin_command(com
else if(is_abrev(command, "zap"))
ses=zap_command(ses);
+ else if(is_abrev(command, "msp"))
+ msp_command(ses);
+
else {
tintin_puts("#UNKNOWN TINTIN-COMMAND.", ses);
prompt(NULL);
diff -upNr tintin++/src/sndserver.c tintin++-msp/src/sndserver.c
--- tintin++/src/sndserver.c Thu Jan 1 01:00:00 1970
+++ tintin++-msp/src/sndserver.c Fri Apr 10 17:58:38 1998
@@ -0,0 +1,396 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "mikmod/include/mikmod.h"
+#include "msp.h"
+
+// should we reset the structure upon startup?
+
+#define UNSET -0x33
+
+void msp_init();
+void msp_end();
+void msp_update();
+int msp_play();
+void read_str (int fd, char *buf);
+void msp_music_off();
+void msp_sound_off (int v);
+
+int eof_str = 1;
+
+struct msp_object
+{
+ char file[0xff];
+ int type;
+ UNIMOD *mf;
+ SAMPLE *sample;
+ int volume;
+ int count;
+ int voice;
+};
+
+typedef struct msp_object msp_object;
+
+msp_object obj;
+msp_object song;
+msp_object sound;
+
+int main (int argc, char *argv[])
+{
+ char str[0xff];
+ char *where_str;
+ int *where_i;
+ int fdo, fdi;
+ int type;
+ int what;
+ int v;
+ struct timeval tv;
+ fd_set readfds;
+ int s;
+
+ song.mf = 0;
+ song.count = 0;
+ sound.sample = 0;
+ sound.voice = -1;
+ sound.count = 0;
+
+#ifdef MSP_FINAL
+ close (STDOUT_FILENO);
+#endif
+
+ msp_init();
+
+ mkfifo (MSP_PIPE_1, S_IRUSR|S_IWUSR);
+ mkfifo (MSP_PIPE_2, S_IRUSR|S_IWUSR);
+
+ fdo = open (MSP_PIPE_1, O_WRONLY);
+
+ // say hi
+ str[0] = 33;
+ write (fdo, str, 1);
+ str[0] = 0;
+ fdi = open (MSP_PIPE_2, O_RDONLY);
+
+ type = TYPE_IGNORE;
+ while (1) {
+ if (type == TYPE_STR) {
+ read_str (fdi, &where_str[0]);
+ printf ("%d %s\n", what, where_str);
+ type = TYPE_IGNORE;
+ continue;
+ } else if (type == TYPE_INT) {
+ read_str (fdi, &str[0]);
+ *where_i = atoi (str);
+ printf ("%d %d\n", what, *where_i);
+ type = TYPE_IGNORE;
+ continue;
+ }
+
+ do {
+ tv.tv_sec = 0;
+ tv.tv_usec = MSP_POLL_USECS;
+
+ FD_ZERO (&readfds);
+ FD_SET (fdi, &readfds);
+ s = select (fdi+1, &readfds, NULL, NULL, &tv);
+
+// puts ("update!");
+ msp_update();
+
+ if (s < 0) {
+ exit(1);
+ }
+
+ } while (eof_str && (s < 1 || !FD_ISSET (fdi, &readfds)));
+
+ read_str(fdi, &str[0]);
+ printf ("incoming: %s<<\n", str);
+
+ what = atoi(str);
+ switch (what) {
+ default:
+ type = TYPE_IGNORE;
+ where_str = &str[0];
+ break;
+ case MSP_FILE:
+ type = TYPE_STR;
+ where_str = &obj.file[0];
+ break;
+ case MSP_TYPE:
+ type = TYPE_INT;
+ where_i = &obj.type;
+ break;
+ case MSP_VOLUME:
+ type = TYPE_INT;
+ where_i = &obj.volume;
+ break;
+ case MSP_PLAYING:
+ type = TYPE_IGNORE;
+ if (obj.type == MSP_TYPE_SOUND) {
+ read_str (fdi, &str[0]);
+ sprintf (str, Voice_Stopped (atoi(str)) ? "0" : "1");
+ } else {
+ sprintf (str, "1");
+ }
+ write (fdo, str, strlen(str)+1);
+ break;
+ case MSP_COUNT:
+ type = TYPE_INT;
+ where_i = &obj.count;
+ break;
+ case MSP_RESET:
+ type = TYPE_IGNORE;
+ obj.file[0] = 0;
+ obj.type = MSP_TYPE_SOUND;
+ obj.mf = 0;
+ obj.volume = UNSET;
+ obj.count = UNSET;
+ break;
+ case MSP_APPLY:
+ if (obj.type == MSP_TYPE_SOUND) {
+ if (obj.volume != UNSET) {
+ // ick!
+ }
+ if (obj.count != UNSET) {
+ // ick!
+ }
+ } else {
+ if (obj.volume != UNSET) {
+ song.volume = obj.volume;
+ md_musicvolume = song.volume;
+ }
+ if (obj.count != UNSET) {
+ song.count = obj.count;
+ }
+ }
+ break;
+ case MSP_OFF:
+ if (obj.type == MSP_TYPE_SOUND) {
+ read_str (fdi, &str[0]);
+// Voice_Stop (atoi (str));
+ msp_sound_off (atoi(str));
+ printf ("Silencing voice %s\n", str);
+ } else {
+ msp_music_off();
+ printf ("Silencing music\n");
+ }
+ break;
+ case MSP_PLAY:
+ type = TYPE_IGNORE;
+ if (obj.type == MSP_TYPE_SOUND) {
+ v = msp_play();
+ printf ("using voice: %d\n", v);
+ sprintf (str, "%d\n", v);
+ write (fdo, str, strlen(str)+1);
+ } else if (obj.type == MSP_TYPE_MUSIC) {
+ printf ("playing song\n");
+ msp_play();
+ }
+ break;
+ }
+
+ }
+}
+
+
+void msp_init()
+{
+ md_mixfreq = 44100;
+ md_dmabufsize = 32768;
+ md_device = 0;
+ md_volume = 128;
+ md_musicvolume = 128;
+ md_sndfxvolume = 128;
+ md_pansep = 128;
+ md_reverb = 0;
+ md_mode = DMODE_16BITS | DMODE_STEREO | DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX;
+// MikMod_RegisterLoader(load_mod);
+ MikMod_RegisterDriver(drv_oss);
+ MikMod_RegisterAllLoaders();
+// MikMod_RegisterAllDrivers();
+ MikMod_Init();
+ MikMod_SetNumVoices (MSPSND_MUSIC_CHANNELS, 8);
+ msp_music_off();
+}
+
+// ideally we should look for the sound that is using voice v, but since
+// msp is dumb enough to only support one sample channel, we dont have to.
+void msp_sound_off (int v)
+{
+ if (sound.voice == -1) {
+ return;
+ }
+
+ Voice_Stop (sound.voice);
+ sound.voice = -1;
+}
+
+void msp_music_off()
+{
+ UNIMOD *mf;
+
+ // this return should be enabled only if loop is set on below
+ if (!strcmp(song.file, "/usr/local/share/sounds/modules/null.uni")) {
+ return;
+ }
+
+ strcpy (song.file, "/usr/local/share/sounds/modules/null.uni");
+ mf = MikMod_LoadSong (song.file, MSPSND_MUSIC_CHANNELS);
+ if (!mf) {
+ puts ("msp_music_off: !mf");
+ return;
+ }
+ if (song.mf) {
+ MikMod_FreeSong (song.mf);
+ }
+ song.mf = mf;
+ song.volume = 0;
+ md_musicvolume = song.volume;
+ mf->loop = 1;
+ Player_Start (song.mf);
+}
+
+void msp_end()
+{
+ Player_Stop();
+ MikMod_FreeSong (song.mf);
+ MikMod_Exit();
+ // :TODO: we need something else here?
+}
+
+
+// has to return voice
+int msp_play (void)
+{
+ if (obj.type == MSP_TYPE_SOUND) {
+ SAMPLE *sample;
+ sample = WAV_LoadFN (obj.file);
+ if (!sample) {
+ puts ("msp_play: !sample");
+ return -1;
+ }
+ if (sound.voice > -1) {
+ Voice_Stop (sound.voice);
+ }
+ if (sound.sample) {
+ WAV_Free (sound.sample);
+ }
+ sound.sample = sample;
+ sound.voice = MikMod_PlaySample (sound.sample, 0, 0);
+ sound.count = obj.count;
+ sound.volume = obj.volume;
+ return sound.voice;
+
+ } else if (obj.type == MSP_TYPE_MUSIC) {
+ UNIMOD *mf;
+ mf = MikMod_LoadSong (obj.file, MSPSND_MUSIC_CHANNELS);
+ if (!mf) {
+ puts ("msp_play: !mf");
+ return -1;
+ }
+ Player_Stop();
+ if (song.mf) {
+ MikMod_FreeSong (song.mf);
+ }
+ song.mf = mf;
+ song.volume = obj.volume;
+ md_musicvolume = song.volume;
+// md_musicvolume = 120;
+ mf->loop = 0;
+ Player_Start (song.mf);
+// md_musicvolume = 120;
+ sound.count = obj.count;
+ return 0;
+ }
+
+ puts ("msp_play: !obj.type");
+ return -1;
+}
+
+// calling this instead of something else might not make much sense, but
+// i tried _everything_ else and mikmod refuses to continue playing it
+void msp_voice_restart()
+{
+ if (sound.voice < 1) {
+ return;
+ }
+
+ // heh
+ Voice_Stop (sound.voice);
+
+ if (sound.sample) {
+ WAV_Free (sound.sample);
+ }
+
+ sound.sample = WAV_LoadFN (obj.file);
+ sound.voice = MikMod_PlaySample (sound.sample, 0, 0);
+}
+
+void msp_update()
+{
+ // update music
+ if (!Player_Active()) {
+ printf ("!active\n");
+ if (song.count != 0) {
+ if (song.count > 0) {
+ --song.count;
+ }
+ Player_SetPosition(0);
+ } else {
+ msp_music_off();
+ }
+
+ msp_voice_restart();
+ }
+
+ // update sounds. see comment in msp_sound_off()
+ // this thing is a mess.. clean up
+ if (sound.voice != -1 && Voice_Stopped (sound.voice)) {
+ if (sound.count >= -1) {
+ --sound.count;
+ if (sound.count == -1) {
+ sound.voice = -1;
+ } else {
+ if (sound.count == -2) {
+ sound.count++;
+ }
+ Voice_Play (sound.voice, sound.sample, 0);
+ // looks like mikmod needs this
+ printf ("idle wait \n");
+ while (Voice_Stopped (sound.voice)) {
+ MikMod_Update();
+ usleep(1000);
+ }
+ printf ("replaying sample on voice %d\n", sound.voice);
+ }
+ }
+ }
+
+ MikMod_Update();
+}
+
+
+void read_str (int fd, char *buf)
+{
+ static char b[0xff];
+ static char *p = &b[0];
+
+ if (!*p) {
+ if (read (fd, b, 0xff) <= 0) {
+ exit(1);
+ };
+ p = &b[0];
+ }
+
+ while (*p != '\n' && *p != '\0') {
+ *(buf++) = *(p++);
+ }
+
+ eof_str = (*(++p) == '\0');
+ *buf = '\0';
+}
+
+
+