Tutorial *125*

In this tutorial, we will add support to Quake to allow it to play "Modules", of the music variety. To assist in this, we will be using the "Midas Sound System", in it's linkable form. This can be downloaded from http://www.s2.org/midas/ or the file directly from our Local Mirror

Okay, at the moment this tutorial has some limitations. The only one of any real importance, is the fact that Midas cannot read inside of pak files. Therefore .mod files will need to be kept inside id1, or the gamedir. Of course, someone can always download the source for Midas, and recompile it with the capability to read from .pak files.. I'm just far too lazy :)

First, download Midas. After this download completes, copy the "include\midaslib.h" file, from Midas, into the WinQuake source directory... Rename the file to "midas.h", just for looks. You will want to have a method of keeping track of whether or not a .mod is playing, so open quakedef.h
Add:




int midasplaying; // Ender: Midas Engine
to the bottom of this file.

Now, we need to call a function which will initilise the two new console commands we are adding, as well as the Midas system itself. We will add this where all the other DirectSound stuff is initilised. Open up snd_win.c, and find the function "SNDDMA_InitDirect". After the 'memset' add:



MOD_init(); // Ender: Midas Engine

Next, Midas needs to be 'polled' every one in a while, to update the sound buffer. And what better place to do it, than where all the other sound mixing is done. So open snd_mix.c and locate the function: "S_PaintChannels". Before the while loop, add:



if (midasplaying) MIDASpoll(); // Ender: Midas Engine

There are but three steps left, now. First, we will add the file containing all these nice MOD_ functions and stuff :) Create midas.c, and to it add the following functions:



#include "quakedef.h"

#include "winquake.h"

#include "midas.h"



MIDASmodule module;

MIDASmodulePlayHandle playHandle;

char *FindMod(char *file);

void MIDASerror(void) {

 Con_Printf("Midas Error: %s\n", MIDASgetErrorMessage(MIDASgetLastError()));

}



void MOD_stop(void) {

 if (midasplaying) {

  if (!MIDASstopModule(playHandle)) {MIDASerror(); return;}

  if (!MIDASfreeModule(module))     {MIDASerror(); return;}

  if (!MIDASclose())                {MIDASerror(); return;}

 }

 midasplaying = 0;

}



void MOD_play(void) {

 char modname[256];

 char modfile[256];



 strcpy(modname, Cmd_Argv(1));

 if (midasplaying)

   MOD_stop();

 if (strlen(modname) < 3) {

  Con_Print("Format: PlayMod <filename.ext>");

  return;

 }

 strcpy(modfile, FindMod(modname));

 if (strlen(modfile)<3) {Con_Printf("Unable to find %s\n", modname); return;}

 Con_Printf("Found %s\n", modfile);

 MIDASstartup();

 MIDASsetOption(MIDAS_OPTION_DSOUND_HWND, mainwindow);

 MIDASsetOption(MIDAS_OPTION_DSOUND_MODE, MIDAS_DSOUND_STREAM);

 if (!MIDASinit()) {MIDASerror(); return;}



 if ((module = MIDASloadModule(modfile)) == NULL) {MIDASerror(); return;}

 if ((playHandle = MIDASplayModule(module, TRUE)) == 0) {MIDASerror(); return;}

 MIDASsetMusicVolume(playHandle, (bgmvolume.value * 64));

 midasplaying = 1;

}



void MOD_init(void) {

 Cmd_AddCommand ("stopmod",MOD_stop);

 Cmd_AddCommand ("playmod",MOD_play);

};

Second last step. We need a way of locating the mod file within the gamepath. However, we can't use the NORMAL method of doing this, because that searches pack files as well. So we need to add a new function to common.c.. Add this code to the bottom of it:





char *FindMod(char *file) {

 searchpath_t    *search;

 char            netpath[MAX_OSPATH];

 int             findtime;



 search = com_searchpaths;

 for ( ; search ; search = search->next) {

  if (!search->pack) {

   sprintf (netpath, "%s\\%s",search->filename, file);

   findtime = Sys_FileTime (netpath);

   if (findtime == -1)  continue;

   return netpath;

  }

 }

 return "";

}

And the last step, is to add the midas library, as found in midas\lib\win32\vcretail\midas.dll, to the project.. And recompile.

A further note on implimentation. QuakeC coders will no doubt wish to add either a new "func_stopmod" and "func_playmod" entity.. .. To "stuffcmd(target, "playmod"); stuffcmd(target, self.modname); stuffcmd(target, "\n");", and "stuffcmd(target, "stopmod\n");" respectivly... Or add a new initial "module" field to worldspawn. These commands can also be manually used by the player from the console. And as a final note, the volume of the module is tied to the CD volume, but ONLY THE VOLUME AS OF THE TIME "Playmod" WAS RAN. Someone else can fix that if they wish.

Feedback appretiated :)
== Ender



 
Not logged in
Sign up
Login:
Passwd: