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'; +} + + +