OpenAL sound code fixes (no longer needs SDL_sound, uses vorbis directly and mikmod integrated), commandline options for sound quality

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@157 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
gewlitys
2002-10-27 03:20:08 +00:00
parent 1b898b151f
commit e07a2e5df4
44 changed files with 12145 additions and 259 deletions
+134 -2
View File
@@ -50,7 +50,7 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib SDL_sound.lib OpenAL32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"msvcrtd.lib" /out:"../../Content/Starcon2.exe"
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"msvcrtd.lib" /out:"../../Content/Starcon2.exe"
!ELSEIF "$(CFG)" == "Starcon2 - Win32 Debug"
@@ -74,7 +74,7 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo /o"Starcon2.bsc"
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib SDL_sound.lib OpenAL32.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"../../Content/Starcon2Debug.exe" /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"../../Content/Starcon2Debug.exe" /pdbtype:sept
# SUBTRACT LINK32 /nodefaultlib
!ENDIF
@@ -426,6 +426,138 @@ SOURCE=..\sc2code\libs\sound\openal\stream.h
SOURCE=..\sc2code\libs\sound\openal\trackplayer.c
# End Source File
# Begin Group "decoders"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\decoder.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\decoder.h
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\wav.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\wav.h
# End Source File
# Begin Group "mikmod"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\drv_nos.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\drv_openal.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\load_mod.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\mdreg.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\mdriver.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\mikmod.h
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\mikmod_build.h
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\mikmod_internal.h
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\mloader.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\mlreg.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\mlutil.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\mmalloc.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\mmerror.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\mmio.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\munitrk.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\mplayer.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\mwav.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\npertab.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\sloader.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\virtch.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\virtch2.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\openal\decoders\mikmod\virtch_common.c
# End Source File
# End Group
# End Group
# End Group
# Begin Group "sdlmixer"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\sc2code\libs\sound\sdl\modfuncs.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\sdl\play.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\sdl\sound.c
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\sound\sdl\trackplayer.c
# End Source File
# End Group
# Begin Source File
@@ -0,0 +1,472 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* Sound file decoder for .wav, .mod, .ogg (to be used with OpenAL)
* API is heavily influenced by SDL_sound.
* By Mika Kolehmainen, 2002-10-27
*/
#ifdef SOUNDMODULE_OPENAL
#ifdef WIN32
#include <io.h>
#include <fcntl.h>
#endif
#include <stdio.h>
#include "decoder.h"
#include "wav.h"
#include "libs/sound/sound_common.h"
#include "mikmod/mikmod.h"
#include "vorbis/codec.h"
#include "vorbis/vorbisfile.h"
MIKMODAPI extern struct MDRIVER drv_openal;
static char *decoder_info_wav = "Wav";
static char *decoder_info_mod = "MikMod";
static char *decoder_info_ogg = "Ogg Vorbis";
static int file_exists (char *filename)
{
FILE *fp;
if ((fp = fopen(filename, "rb")) == NULL)
return 0;
fclose (fp);
return 1;
}
static size_t ogg_read (void *ptr, size_t size, size_t nmemb, void *datasource)
{
return fread (ptr, size, nmemb, datasource);
}
static int ogg_seek (void *datasource, ogg_int64_t offset, int whence)
{
long off = (long) offset;
return fseek (datasource, off, whence);
}
static int ogg_close (void *datasource)
{
return fclose (datasource);
}
static long ogg_tell(void *datasource)
{
return ftell (datasource);
}
static const ov_callbacks ogg_callbacks =
{
ogg_read,
ogg_seek,
ogg_close,
ogg_tell,
};
ALint SoundDecoder_Init (int flags)
{
MikMod_RegisterDriver (&drv_openal);
MikMod_RegisterAllLoaders ();
if (flags & TFB_SOUNDFLAGS_HQAUDIO)
{
md_mode = DMODE_HQMIXER|DMODE_STEREO|DMODE_16BITS|DMODE_INTERP|DMODE_SURROUND;
md_mixfreq = 44100;
md_reverb = 1;
}
else if (flags & TFB_SOUNDFLAGS_LQAUDIO)
{
md_mode = DMODE_SOFT_MUSIC|DMODE_STEREO|DMODE_16BITS;
md_mixfreq = 22050;
md_reverb = 0;
}
else
{
md_mode = DMODE_SOFT_MUSIC|DMODE_STEREO|DMODE_16BITS|DMODE_INTERP;
md_mixfreq = 44100;
md_reverb = 0;
}
md_pansep = 96;
if (MikMod_Init (""))
{
fprintf (stderr, "SoundDecoder_Init(): MikMod_Init failed, %s\n",
MikMod_strerror (MikMod_errno));
return 1;
}
return 0;
}
void SoundDecoder_Uninit (void)
{
MikMod_Exit ();
}
TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size)
{
int i;
if (!file_exists (filename))
{
fprintf (stderr, "SoundDecoder_Load(): %s doesn't exist\n", filename);
return NULL;
}
i = strlen (filename) - 3;
if (!strcmp (&filename[i], "wav"))
{
TFB_SoundDecoder *decoder;
//fprintf (stderr, "SoundDecoder_Load(): %s interpreted as wav\n", filename);
decoder = (TFB_SoundDecoder *) malloc (sizeof (TFB_SoundDecoder));
decoder->buffer = NULL;
decoder->buffer_size = 0;
decoder->format = 0;
decoder->frequency = 0;
decoder->looping = AL_FALSE;
decoder->error = SOUNDDECODER_OK;
decoder->decoder_info = decoder_info_wav;
decoder->type = SOUNDDECODER_WAV;
decoder->filename = (char *) malloc (strlen (filename) + 1);
strcpy (decoder->filename, filename);
return decoder;
}
else if (!strcmp (&filename[i], "mod"))
{
TFB_SoundDecoder *decoder;
MODULE *mod;
//fprintf (stderr, "SoundDecoder_Load(): %s interpreted as mod\n", filename);
mod = Player_Load (filename, 4, 0);
if (!mod)
{
fprintf (stderr, "SoundDecoder_Load(): couldn't load %s\n", filename);
return NULL;
}
mod->extspd = 1;
mod->panflag = 1;
mod->wrap = 0;
mod->loop = 0;
decoder = (TFB_SoundDecoder *) malloc (sizeof (TFB_SoundDecoder));
decoder->buffer = malloc (buffer_size);
decoder->buffer_size = buffer_size;
decoder->format = AL_FORMAT_STEREO16;
decoder->frequency = md_mixfreq;
decoder->looping = AL_FALSE;
decoder->error = SOUNDDECODER_OK;
decoder->decoder_info = decoder_info_mod;
decoder->type = SOUNDDECODER_MOD;
decoder->filename = (char *) malloc (strlen (filename) + 1);
strcpy (decoder->filename, filename);
decoder->data = mod;
return decoder;
}
else if (!strcmp (&filename[i], "ogg"))
{
int rc;
FILE *vfp;
OggVorbis_File *vf;
vorbis_info *vinfo;
TFB_SoundDecoder *decoder;
//fprintf (stderr, "SoundDecoder_Load(): %s interpreted as ogg\n", filename);
vf = (OggVorbis_File *) malloc (sizeof (OggVorbis_File));
if (!vf)
{
fprintf (stderr, "SoundDecoder_Load(): couldn't allocate mem for OggVorbis_File\n");
return NULL;
}
if ((vfp = fopen (filename, "r")) == NULL)
{
fprintf (stderr, "SoundDecoder_Load(): couldn't open %s\n", filename);
free (vf);
return NULL;
}
#ifdef WIN32
_setmode( _fileno(vfp), _O_BINARY);
#endif
rc = ov_open_callbacks (vfp, vf, NULL, 0, ogg_callbacks);
if (rc != 0)
{
fprintf (stderr, "SoundDecoder_Load(): ov_open_callbacks failed for %s, error code %d\n", filename, rc);
fclose (vfp);
free (vf);
return NULL;
}
vinfo = ov_info (vf, -1);
if (!vinfo)
{
fprintf (stderr, "SoundDecoder_Load(): failed to retrieve ogg bitstream info\n");
ov_clear (vf);
free (vf);
return NULL;
}
//fprintf (stderr, "SoundDecoder_Load(): ogg bitstream version %d, channels %d, rate %d, length %.2f seconds\n", vinfo->version, vinfo->channels, vinfo->rate, ov_time_total (vf, -1));
decoder = (TFB_SoundDecoder *) malloc (sizeof (TFB_SoundDecoder));
decoder->buffer = malloc (buffer_size);
decoder->buffer_size = buffer_size;
if (vinfo->channels == 1)
decoder->format = AL_FORMAT_MONO16;
else
decoder->format = AL_FORMAT_STEREO16;
decoder->frequency = vinfo->rate;
decoder->looping = AL_FALSE;
decoder->error = SOUNDDECODER_OK;
decoder->decoder_info = decoder_info_ogg;
decoder->type = SOUNDDECODER_OGG;
decoder->filename = (char *) malloc (strlen (filename) + 1);
strcpy (decoder->filename, filename);
decoder->data = vf;
return decoder;
}
else
{
fprintf (stderr, "SoundDecoder_Load(): %s file format is unsupported\n", filename);
}
return NULL;
}
ALuint SoundDecoder_Decode (TFB_SoundDecoder *decoder)
{
switch (decoder->type)
{
case SOUNDDECODER_WAV:
{
fprintf (stderr, "SoundDecoder_Decode(): unimplemented for wav\n");
break;
}
case SOUNDDECODER_MOD:
{
MODULE *mod = (MODULE *) decoder->data;
Player_Start (mod);
if (!Player_Active())
{
if (decoder->looping)
{
//fprintf (stderr, "SoundDecoder_Decode(): looping %s\n", decoder->filename);
Player_SetPosition (0);
Player_Start (mod);
}
else
{
//fprintf (stderr, "SoundDecoder_Decode(): eof for %s\n", decoder->filename);
decoder->error = SOUNDDECODER_EOF;
return 0;
}
}
decoder->error = SOUNDDECODER_OK;
return ((ALuint) VC_WriteBytes (decoder->buffer, decoder->buffer_size));
}
case SOUNDDECODER_OGG:
{
OggVorbis_File *vf = (OggVorbis_File *) decoder->data;
ALuint decoded_bytes = 0, count = 0;
long rc;
int bitstream;
char *buffer = (char *) decoder->buffer;
while (decoded_bytes < decoder->buffer_size)
{
rc = ov_read (vf, &buffer[decoded_bytes], decoder->buffer_size - decoded_bytes, 0, 2, 1, &bitstream);
if (rc < 0)
{
decoder->error = SOUNDDECODER_ERROR;
fprintf (stderr, "SoundDecoder_Decode(): error decoding %s, code %d\n", decoder->filename, rc);
return decoded_bytes;
}
if (rc == 0)
{
if (decoder->looping)
{
if (ov_raw_seek (vf, 0) != 0)
{
fprintf (stderr, "SoundDecoder_Decode(): tried to loop %s but couldn't rewind\n", decoder->filename);
}
else
{
//fprintf (stderr, "SoundDecoder_Decode(): looping %s\n", decoder->filename);
count++;
continue;
}
}
//fprintf (stderr, "SoundDecoder_Decode(): eof for %s\n", decoder->filename);
decoder->error = SOUNDDECODER_EOF;
return decoded_bytes;
}
decoded_bytes += rc;
//fprintf (stderr, "iter %d rc %d decoded_bytes %d remaining %d\n", count, rc, decoded_bytes, decoder->buffer_size - decoded_bytes);
count++;
}
decoder->error = SOUNDDECODER_OK;
//fprintf (stderr, "SoundDecoder_Decode(): decoded %d bytes from %s\n", decoded_bytes, decoder->filename);
return decoded_bytes;
}
default:
{
fprintf (stderr, "SoundDecoder_Decode(): unknown type %d\n", decoder->type);
break;
}
}
decoder->error = SOUNDDECODER_ERROR;
return 0;
}
ALuint SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder)
{
switch (decoder->type)
{
case SOUNDDECODER_WAV:
{
ALboolean loop;
LoadWAVFile(decoder->filename ,&decoder->format, &decoder->buffer,
&decoder->buffer_size, &decoder->frequency, &loop);
if (decoder->buffer_size != 0)
decoder->error = SOUNDDECODER_OK;
else
decoder->error = SOUNDDECODER_ERROR;
return decoder->buffer_size;
}
case SOUNDDECODER_MOD:
{
fprintf (stderr, "SoundDecoder_DecodeAll(): unimplemented for mod\n");
break;
}
case SOUNDDECODER_OGG:
{
fprintf (stderr, "SoundDecoder_DecodeAll(): unimplemented for ogg\n");
break;
}
default:
{
fprintf (stderr, "SoundDecoder_DecodeAll(): unknown type %d\n", decoder->type);
break;
}
}
decoder->error = SOUNDDECODER_ERROR;
return 0;
}
void SoundDecoder_Rewind (TFB_SoundDecoder *decoder)
{
switch (decoder->type)
{
case SOUNDDECODER_WAV:
{
fprintf (stderr, "SoundDecoder_Rewind(): unimplemented for wav\n");
break;
}
case SOUNDDECODER_MOD:
{
MODULE *mod = (MODULE *)decoder->data;
Player_Start (mod);
Player_SetPosition (0);
//fprintf (stderr, "SoundDecoder_Rewind(): rewinded %s\n", decoder->filename);
decoder->error = SOUNDDECODER_OK;
return;
}
case SOUNDDECODER_OGG:
{
OggVorbis_File *vf = (OggVorbis_File *) decoder->data;
if (ov_raw_seek (vf, 0) != 0)
{
fprintf (stderr, "SoundDecoder_Rewind(): couldn't rewind %s\n", decoder->filename);
break;
}
//fprintf (stderr, "SoundDecoder_Rewind(): rewinded %s\n", decoder->filename);
decoder->error = SOUNDDECODER_OK;
return;
}
default:
{
fprintf (stderr, "SoundDecoder_Rewind(): unknown type %d\n", decoder->type);
break;
}
}
decoder->error = SOUNDDECODER_ERROR;
}
void SoundDecoder_Free (TFB_SoundDecoder *decoder)
{
if (!decoder)
{
return;
}
switch (decoder->type)
{
case SOUNDDECODER_WAV:
{
//fprintf (stderr, "SoundDecoder_Free(): freeing %s\n", decoder->filename);
break;
}
case SOUNDDECODER_MOD:
{
MODULE *mod = (MODULE *) decoder->data;
//fprintf (stderr, "SoundDecoder_Free(): freeing %s\n", decoder->filename);
Player_Free (mod);
break;
}
case SOUNDDECODER_OGG:
{
OggVorbis_File *vf = (OggVorbis_File *) decoder->data;
//fprintf (stderr, "SoundDecoder_Free(): freeing %s\n", decoder->filename);
ov_clear (vf);
free (vf);
break;
}
default:
{
fprintf (stderr, "SoundDecoder_Free(): unknown type %d\n", decoder->type);
break;
}
}
free (decoder->buffer);
free (decoder->filename);
free (decoder);
}
#endif
@@ -0,0 +1,74 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* Sound file decoder for .wav, .mod, .ogg (to be used with OpenAL)
* API is heavily influenced by SDL_sound.
* By Mika Kolehmainen, 2002-10-27
*/
#ifndef DECODER_H
#define DECODER_H
#ifdef WIN32
#include <al.h>
#pragma comment (lib, "vorbisfile.lib")
#else
#include <AL/al.h>
#endif
typedef struct tfb_sounddecoder
{
// public
void *buffer;
ALuint buffer_size;
ALenum format;
ALuint frequency;
ALboolean looping;
ALint error;
char *decoder_info;
// semi-private
ALint type;
char *filename;
void *data;
} TFB_SoundDecoder;
// return values
enum
{
SOUNDDECODER_OK,
SOUNDDECODER_ERROR,
SOUNDDECODER_EOF,
};
// types
enum
{
SOUNDDECODER_NONE,
SOUNDDECODER_WAV,
SOUNDDECODER_MOD,
SOUNDDECODER_OGG,
};
ALint SoundDecoder_Init (int flags);
void SoundDecoder_Uninit (void);
TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size);
ALuint SoundDecoder_Decode (TFB_SoundDecoder *decoder);
ALuint SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder);
void SoundDecoder_Rewind (TFB_SoundDecoder *decoder);
void SoundDecoder_Free (TFB_SoundDecoder *decoder);
#endif
@@ -0,0 +1,115 @@
libmikmod main authors
----------------------
* Jean-Paul Mikkers (MikMak) <mikmak@via.nl>
wrote MikMod and maintained it until version 3.
* Jake Stine (Air Richter) <dracoirs@epix.net> [email doesn't work anymore...]
made decisive contributions to the code (esp. IT support) and maintained
MikMod version 3 until it was discontinued. He still works on the WinAmp
module plugin, roughly based on MikMod.
* Miodrag Vallat <miodrag@mikmod.darkorb.net>
current libmikmod maintainer (since version 3.0.4), made an audit of the
code resulting in many bugs fixed.
Previous Unix maintainers
-------------------------
* Steve McIntyre <steven@chiark.greenend.org.uk>
maintained MikMod'Unix version 2.
* Peter Amstutz <tetron@student.umass.edu>
maintained MikMod'Unix version 3.0.
General contributors
--------------------
* Arne de Bruijn <arne@knoware.nl>
wrote the compressed IT sample support.
* Claudio Matsuoka <claudio@helllabs.org>
wrote the STX loader and submitted bug fixes.
* Sebastiaan A. Megens <samegens@xs4all.nl>
fixed various bugs (memory leaks, endianness issues, etc).
* ``UFO'' <ufo303@poczta.onet.pl>
wrote the OKT loader.
* Kev Vance <kvance@zeux.org>
wrote the GDM loader.
* Paul Fisher made decisive contributions and improvements.
* Alexander Kerkhove fixed an ULT panning effect bug.
* ``Kodiak'' helped on the interfaces of libmikmod.
* Sylvain Marchand make MikMod more portable and GCC compilable.
Contributors on the Unix side
-----------------------------
* Douglas Carmichael <dcarmich@mcs.com>
made MikMod work under FreeBSD.
* Chris Conn <cconn@tohs.abacom.com>
wrote the OSS driver.
* Roine Gustaffson <e93_rog@e.kth.se>
wrote the Digital AudioFile driver.
* Stephan Kanthak <kanthak@informatik.rwth-aachen.de>
wrote the SGI driver.
* Lutz Vieweg <lkv@mania.robin.de>
wrote the AIX and HP-UX drivers.
* Valtteri Vuorikoski <vuori@sci.fi>
wrote the Sun driver.
* Andy Lo A Foe <andy@alsa-project.org>
wrote the Ultra driver (for the Gravis Ultrasound sound card).
* C Ray C <crayc@pyro.net>
updated the Ultra driver to work with libmikmod 3.
* ``MenTaLguY'' <mental@kludge.org>
autoconfized the Unix libmikmod distribution.
* Tobias Gloth <gloth@geomagic.com>
created the new I/O interface, made the code MT-safe and submitted bug fixes.
* Simon Hosie <gumboot@clear.net.nz>
wrote the piped output driver, and submitted speed optimizations and bugfixes
for the software mixer.
* Gerd Rausch <gerd@alf.gun.de>
wrote the sam9407 driver.
Contributors on the Windows side
--------------------------------
* Brian McKinney <Brian.McKinney@colorado.edu>
created the DirectSound driver.
* Bjornar Henden <bhenden@online.no>
created the Multimedia API windows driver.
Contributors on the Dos side
----------------------------
Their code isn't there anymore, but they contributed to the success of
libmikmod...
* Jean-Philippe Ajirent wrote the EMS memory routines.
* Peter Breitling ported MikMod to DJGPP.
* Arnout Cosman wrote the PAS driver.
* Mario Koeppen wrote the WSS driver.
* Mike Leibow wrote the GUS driver.
* Jeremy McDonald wrote a fast assembly-language mixer.
* Steffen Rusitschka and Vince Vu wrote the AWE driver.
Contributors on the Macintosh side
----------------------------------
* Anders Bjoerklund <afb@algonet.se>
ported libmikmod to the Macintosh.
Contributors on the OS/2 side
-----------------------------
* Stefan Tibus <Stefan_Tibus@ThePentagon.com>
ported libmikmod to OS/2.
* Andrew Zabolotny <bit@eltech.ru>
improved the existing OS/2 drivers.
Contributors on the BeOS side
-----------------------------
* Thomas Neumann <tneumann@polycode.dk>
integrated libmikmod into his BeOS APlayer, and contributed many bug fixes.
--
If your name is missing, don't hesitate to remind me at
<miodrag@mikmod.darkorb.net>
@@ -0,0 +1,7 @@
NOTE by UQM developers: this is a modified version of mikmod what was
included in SDL_mixer 1.2.4, so some code are (c) Sam Lantinga.
--> MikMod Sound Libraries Version 3.1.9a
This version of the library is based on the official UNIX MikMod
library version 3.1.9, found at: http://www.mikmod.org/
@@ -0,0 +1,111 @@
/* MikMod sound library
(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
Driver for no output
==============================================================================*/
/*
Written by Jean-Paul Mikkers <mikmak@via.nl>
*/
#ifdef SOUNDMODULE_OPENAL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "mikmod_internals.h"
#define ZEROLEN 32768
static SBYTE *zerobuf=NULL;
static BOOL NS_IsThere(void)
{
return 1;
}
static BOOL NS_Init(void)
{
zerobuf=(SBYTE*)_mm_malloc(ZEROLEN);
return VC_Init();
}
static void NS_Exit(void)
{
VC_Exit();
_mm_free(zerobuf);
}
static void NS_Update(void)
{
if (zerobuf)
VC_WriteBytes(zerobuf,ZEROLEN);
}
MIKMODAPI MDRIVER drv_nos={
NULL,
"No Sound",
"Nosound Driver v3.0",
255,255,
"nosound",
NULL,
NS_IsThere,
VC_SampleLoad,
VC_SampleUnload,
VC_SampleSpace,
VC_SampleLength,
NS_Init,
NS_Exit,
NULL,
VC_SetNumVoices,
VC_PlayStart,
VC_PlayStop,
NS_Update,
NULL,
VC_VoiceSetVolume,
VC_VoiceGetVolume,
VC_VoiceSetFrequency,
VC_VoiceGetFrequency,
VC_VoiceSetPanning,
VC_VoiceGetPanning,
VC_VoicePlay,
VC_VoiceStop,
VC_VoiceStopped,
VC_VoiceGetPosition,
VC_VoiceRealVolume
};
/* ex:set ts=4: */
#endif
@@ -0,0 +1,74 @@
// OpenAL driver for mikmod
// based on SDL driver (c) Sam Lantinga
#ifdef SOUNDMODULE_OPENAL
#include "mikmod_internals.h"
static BOOL ALDRV_IsThere(void)
{
return 1;
}
static BOOL ALDRV_Init(void)
{
md_mode |= DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX;
return(VC_Init());
}
static void ALDRV_Exit(void)
{
VC_Exit();
}
static void ALDRV_Update(void)
{
/* does nothing, buffers are updated in the background */
}
static BOOL ALDRV_Reset(void)
{
return 0;
}
MIKMODAPI MDRIVER drv_openal =
{ NULL,
"OpenAL",
"MikMod OpenAL driver v1.0",
0,255,
"OpenAL",
NULL,
ALDRV_IsThere,
VC_SampleLoad,
VC_SampleUnload,
VC_SampleSpace,
VC_SampleLength,
ALDRV_Init,
ALDRV_Exit,
ALDRV_Reset,
VC_SetNumVoices,
VC_PlayStart,
VC_PlayStop,
ALDRV_Update,
NULL, /* FIXME: Pause */
VC_VoiceSetVolume,
VC_VoiceGetVolume,
VC_VoiceSetFrequency,
VC_VoiceGetFrequency,
VC_VoiceSetPanning,
VC_VoiceGetPanning,
VC_VoicePlay,
VC_VoiceStop,
VC_VoiceStopped,
VC_VoiceGetPosition,
VC_VoiceRealVolume
};
#endif
@@ -0,0 +1,460 @@
/* MikMod sound library
(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
Generic MOD loader (Protracker, StarTracker, FastTracker, etc)
==============================================================================*/
#ifdef SOUNDMODULE_OPENAL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <ctype.h>
#include <string.h>
#include "mikmod_internals.h"
/*========== Module structure */
typedef struct MSAMPINFO {
CHAR samplename[23]; /* 22 in module, 23 in memory */
UWORD length;
UBYTE finetune;
UBYTE volume;
UWORD reppos;
UWORD replen;
} MSAMPINFO;
typedef struct MODULEHEADER {
CHAR songname[21]; /* the songname.. 20 in module, 21 in memory */
MSAMPINFO samples[31]; /* all sampleinfo */
UBYTE songlength; /* number of patterns used */
UBYTE magic1; /* should be 127 */
UBYTE positions[128]; /* which pattern to play at pos */
UBYTE magic2[4]; /* string "M.K." or "FLT4" or "FLT8" */
} MODULEHEADER;
typedef struct MODTYPE {
CHAR id[5];
UBYTE channels;
CHAR *name;
} MODTYPE;
typedef struct MODNOTE {
UBYTE a, b, c, d;
} MODNOTE;
/*========== Loader variables */
#define MODULEHEADERSIZE 0x438
static CHAR protracker[] = "Protracker";
static CHAR startrekker[] = "Startrekker";
static CHAR fasttracker[] = "Fasttracker";
static CHAR oktalyser[] = "Oktalyser";
static CHAR oktalyzer[] = "Oktalyzer";
static CHAR taketracker[] = "TakeTracker";
static CHAR orpheus[] = "Imago Orpheus (MOD format)";
static MODULEHEADER *mh = NULL;
static MODNOTE *patbuf = NULL;
static int modtype = 0;
/*========== Loader code */
/* given the module ID, determine the number of channels and the tracker
description ; also alters modtype */
static BOOL MOD_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr)
{
/* Protracker and variants */
if ((!memcmp(id, "M.K.", 4)) || (!memcmp(id, "M!K!", 4))) {
*descr = protracker;
modtype = 0;
*numchn = 4;
return 1;
}
/* Star Tracker */
if (((!memcmp(id, "FLT", 3)) || (!memcmp(id, "EXO", 3))) &&
(isdigit(id[3]))) {
*descr = startrekker;
modtype = 1;
*numchn = id[3] - '0';
if (*numchn == 4)
return 1;
#ifdef MIKMOD_DEBUG
if (*numchn == 8)
fprintf(stderr, "\rFLT8 modules not supported yet\n");
else
fprintf(stderr, "\rUnknown FLT%d module type\n", *numchn);
#endif
return 0;
}
/* Oktalyzer (Amiga) */
if (!memcmp(id, "OKTA", 4)) {
*descr = oktalyzer;
modtype = 1;
*numchn = 8;
return 1;
}
/* Oktalyser (Atari) */
if (!memcmp(id, "CD81", 4)) {
*descr = oktalyser;
modtype = 1;
*numchn = 8;
return 1;
}
/* Fasttracker */
if ((!memcmp(id + 1, "CHN", 3)) && (isdigit(id[0]))) {
*descr = fasttracker;
modtype = 1;
*numchn = id[0] - '0';
return 1;
}
/* Fasttracker or Taketracker */
if (((!memcmp(id + 2, "CH", 2)) || (!memcmp(id + 2, "CN", 2)))
&& (isdigit(id[0])) && (isdigit(id[1]))) {
if (id[3] == 'H') {
*descr = fasttracker;
modtype = 2; /* this can also be Imago Orpheus */
} else {
*descr = taketracker;
modtype = 1;
}
*numchn = (id[0] - '0') * 10 + (id[1] - '0');
return 1;
}
return 0;
}
static BOOL MOD_Test(void)
{
UBYTE id[4], numchn;
CHAR *descr;
_mm_fseek(modreader, MODULEHEADERSIZE, SEEK_SET);
if (!_mm_read_UBYTES(id, 4, modreader))
return 0;
if (MOD_CheckType(id, &numchn, &descr))
return 1;
return 0;
}
static BOOL MOD_Init(void)
{
if (!(mh = (MODULEHEADER *)_mm_malloc(sizeof(MODULEHEADER))))
return 0;
return 1;
}
static void MOD_Cleanup(void)
{
_mm_free(mh);
_mm_free(patbuf);
}
/*
Old (amiga) noteinfo:
_____byte 1_____ byte2_ _____byte 3_____ byte4_
/ \ / \ / \ / \
0000 0000-00000000 0000 0000-00000000
Upper four 12 bits for Lower four Effect command.
bits of sam- note period. bits of sam-
ple number. ple number.
*/
static void ConvertNote(MODNOTE *n)
{
UBYTE instrument, effect, effdat, note;
UWORD period;
UBYTE lastnote = 0;
/* extract the various information from the 4 bytes that make up a note */
instrument = (n->a & 0x10) | (n->c >> 4);
period = (((UWORD)n->a & 0xf) << 8) + n->b;
effect = n->c & 0xf;
effdat = n->d;
/* Convert the period to a note number */
note = 0;
if (period) {
for (note = 0; note < 7 * OCTAVE; note++)
if (period >= npertab[note])
break;
if (note == 7 * OCTAVE)
note = 0;
else
note++;
}
if (instrument) {
/* if instrument does not exist, note cut */
if ((instrument > 31) || (!mh->samples[instrument - 1].length)) {
UniPTEffect(0xc, 0);
if (effect == 0xc)
effect = effdat = 0;
} else {
/* Protracker handling */
if (!modtype) {
/* if we had a note, then change instrument... */
if (note)
UniInstrument(instrument - 1);
/* ...otherwise, only adjust volume... */
else {
/* ...unless an effect was specified, which forces a new
note to be played */
if (effect || effdat) {
UniInstrument(instrument - 1);
note = lastnote;
} else
UniPTEffect(0xc,
mh->samples[instrument -
1].volume & 0x7f);
}
} else {
/* Fasttracker handling */
UniInstrument(instrument - 1);
if (!note)
note = lastnote;
}
}
}
if (note) {
UniNote(note + 2 * OCTAVE - 1);
lastnote = note;
}
/* Convert pattern jump from Dec to Hex */
if (effect == 0xd)
effdat = (((effdat & 0xf0) >> 4) * 10) + (effdat & 0xf);
/* Volume slide, up has priority */
if ((effect == 0xa) && (effdat & 0xf) && (effdat & 0xf0))
effdat &= 0xf0;
/* Handle ``heavy'' volumes correctly */
if ((effect == 0xc) && (effdat > 0x40))
effdat = 0x40;
/* Ignore 100, 200 and 300 (there is no porta memory in mod files) */
if ((!effdat) && ((effect == 1)||(effect == 2)||(effect ==3)))
effect = 0;
UniPTEffect(effect, effdat);
}
static UBYTE *ConvertTrack(MODNOTE *n)
{
int t;
UniReset();
for (t = 0; t < 64; t++) {
ConvertNote(n);
UniNewline();
n += of.numchn;
}
return UniDup();
}
/* Loads all patterns of a modfile and converts them into the 3 byte format. */
static BOOL ML_LoadPatterns(void)
{
int t, s, tracks = 0;
if (!AllocPatterns())
return 0;
if (!AllocTracks())
return 0;
/* Allocate temporary buffer for loading and converting the patterns */
if (!(patbuf = (MODNOTE *)_mm_calloc(64U * of.numchn, sizeof(MODNOTE))))
return 0;
for (t = 0; t < of.numpat; t++) {
/* Load the pattern into the temp buffer and convert it */
for (s = 0; s < (64U * of.numchn); s++) {
patbuf[s].a = _mm_read_UBYTE(modreader);
patbuf[s].b = _mm_read_UBYTE(modreader);
patbuf[s].c = _mm_read_UBYTE(modreader);
patbuf[s].d = _mm_read_UBYTE(modreader);
}
for (s = 0; s < of.numchn; s++)
if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s)))
return 0;
}
return 1;
}
static BOOL MOD_Load(BOOL curious)
{
int t, scan;
SAMPLE *q;
MSAMPINFO *s;
CHAR *descr;
/* try to read module header */
_mm_read_string((CHAR *)mh->songname, 20, modreader);
mh->songname[20] = 0; /* just in case */
for (t = 0; t < 31; t++) {
s = &mh->samples[t];
_mm_read_string(s->samplename, 22, modreader);
s->samplename[22] = 0; /* just in case */
s->length = _mm_read_M_UWORD(modreader);
s->finetune = _mm_read_UBYTE(modreader);
s->volume = _mm_read_UBYTE(modreader);
s->reppos = _mm_read_M_UWORD(modreader);
s->replen = _mm_read_M_UWORD(modreader);
}
mh->songlength = _mm_read_UBYTE(modreader);
mh->magic1 = _mm_read_UBYTE(modreader);
_mm_read_UBYTES(mh->positions, 128, modreader);
_mm_read_UBYTES(mh->magic2, 4, modreader);
if (_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* set module variables */
of.initspeed = 6;
of.inittempo = 125;
if (!(MOD_CheckType(mh->magic2, &of.numchn, &descr))) {
_mm_errno = MMERR_NOT_A_MODULE;
return 0;
}
of.songname = DupStr(mh->songname, 21, 1);
of.numpos = mh->songlength;
of.reppos = 0;
/* Count the number of patterns */
of.numpat = 0;
for (t = 0; t < of.numpos; t++)
if (mh->positions[t] > of.numpat)
of.numpat = mh->positions[t];
/* since some old modules embed extra patterns, we have to check the
whole list to get the samples' file offsets right - however we can find
garbage here, so check carefully */
scan = 1;
for (t = of.numpos; t < 128; t++)
if (mh->positions[t] >= 0x80)
scan = 0;
if (scan)
for (t = of.numpos; t < 128; t++) {
if (mh->positions[t] > of.numpat)
of.numpat = mh->positions[t];
if ((curious) && (mh->positions[t]))
of.numpos = t + 1;
}
of.numpat++;
of.numtrk = of.numpat * of.numchn;
if (!AllocPositions(of.numpos))
return 0;
for (t = 0; t < of.numpos; t++)
of.positions[t] = mh->positions[t];
/* Finally, init the sampleinfo structures */
of.numins = of.numsmp = 31;
if (!AllocSamples())
return 0;
s = mh->samples;
q = of.samples;
for (t = 0; t < of.numins; t++) {
/* convert the samplename */
q->samplename = DupStr(s->samplename, 23, 1);
/* init the sampleinfo variables and convert the size pointers */
q->speed = finetune[s->finetune & 0xf];
q->volume = s->volume & 0x7f;
q->loopstart = (ULONG)s->reppos << 1;
q->loopend = q->loopstart + ((ULONG)s->replen << 1);
q->length = (ULONG)s->length << 1;
q->flags = SF_SIGNED;
/* Imago Orpheus creates MODs with 16 bit samples, check */
if ((modtype == 2) && (s->volume & 0x80)) {
q->flags |= SF_16BITS;
descr = orpheus;
}
if (s->replen > 2)
q->flags |= SF_LOOP;
/* fix replen if repend > length */
if (q->loopend > q->length)
q->loopend = q->length;
s++;
q++;
}
of.modtype = strdup(descr);
if (!ML_LoadPatterns())
return 0;
return 1;
}
static CHAR *MOD_LoadTitle(void)
{
CHAR s[21];
_mm_fseek(modreader, 0, SEEK_SET);
if (!_mm_read_UBYTES(s, 20, modreader))
return NULL;
s[20] = 0; /* just in case */
return (DupStr(s, 21, 1));
}
/*========== Loader information */
MIKMODAPI MLOADER load_mod = {
NULL,
"Standard module",
"MOD (31 instruments)",
MOD_Init,
MOD_Test,
MOD_Load,
MOD_Cleanup,
MOD_LoadTitle
};
/* ex:set ts=4: */
#endif
@@ -0,0 +1,61 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
Routine for registering all drivers in libmikmod for the current platform.
==============================================================================*/
#ifdef SOUNDMODULE_OPENAL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
MIKMODAPI extern struct MDRIVER drv_openal;
void _mm_registeralldrivers(void)
{
_mm_registerdriver(&drv_openal);
_mm_registerdriver(&drv_nos);
}
void MikMod_RegisterAllDrivers(void)
{
MUTEX_LOCK(lists);
_mm_registeralldrivers();
MUTEX_UNLOCK(lists);
}
void MikMod_UnregisterAllDrivers(void)
{
MUTEX_LOCK(lists);
_mm_unregisterdrivers();
MUTEX_UNLOCK(lists);
}
/* ex:set ts=4: */
#endif
@@ -0,0 +1,934 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
These routines are used to access the available soundcard drivers.
==============================================================================*/
#ifdef SOUNDMODULE_OPENAL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef unix
#include <pwd.h>
#include <sys/stat.h>
#endif
#include <string.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include "mikmod_internals.h"
static MDRIVER *firstdriver=NULL;
MDRIVER *md_driver=NULL;
extern MODULE *pf; /* modfile being played */
UWORD md_device = 0;
UWORD md_mixfreq = 44100;
UWORD md_mode = DMODE_STEREO | DMODE_16BITS | DMODE_SURROUND
|DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX;
UBYTE md_pansep = 128; /* 128 == 100% (full left/right) */
UBYTE md_reverb = 6; /* Reverb */
UBYTE md_volume = 128; /* Global sound volume (0-128) */
UBYTE md_musicvolume = 128; /* volume of song */
UBYTE md_sndfxvolume = 128; /* volume of sound effects */
UWORD md_bpm = 125;
/* Do not modify the numchn variables yourself! use MD_SetVoices() */
UBYTE md_numchn=0,md_sngchn=0,md_sfxchn=0;
UBYTE md_hardchn=0,md_softchn=0;
void (*md_player)(void) = Player_HandleTick;
static BOOL isplaying=0, initialized = 0;
static UBYTE *sfxinfo;
static int sfxpool;
static SAMPLE **md_sample = NULL;
/* Previous driver in use */
static UWORD idevice;
/* Limits the number of hardware voices to the specified amount.
This function should only be used by the low-level drivers. */
static void LimitHardVoices(int limit)
{
int t=0;
if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit;
if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit;
if (!(md_mode & DMODE_SOFT_SNDFX))
md_hardchn=md_sfxchn;
else
md_hardchn=0;
if (!(md_mode & DMODE_SOFT_MUSIC)) md_hardchn += md_sngchn;
while (md_hardchn>limit) {
if (++t & 1) {
if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--;
} else {
if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--;
}
if (!(md_mode & DMODE_SOFT_SNDFX))
md_hardchn=md_sfxchn;
else
md_hardchn=0;
if (!(md_mode & DMODE_SOFT_MUSIC))
md_hardchn+=md_sngchn;
}
md_numchn=md_hardchn+md_softchn;
}
/* Limits the number of hardware voices to the specified amount.
This function should only be used by the low-level drivers. */
static void LimitSoftVoices(int limit)
{
int t=0;
if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit;
if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit;
if (md_mode & DMODE_SOFT_SNDFX)
md_softchn=md_sfxchn;
else
md_softchn=0;
if (md_mode & DMODE_SOFT_MUSIC) md_softchn+=md_sngchn;
while (md_softchn>limit) {
if (++t & 1) {
if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--;
} else {
if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--;
}
if (!(md_mode & DMODE_SOFT_SNDFX))
md_softchn=md_sfxchn;
else
md_softchn=0;
if (!(md_mode & DMODE_SOFT_MUSIC))
md_softchn+=md_sngchn;
}
md_numchn=md_hardchn+md_softchn;
}
/* Note: 'type' indicates whether the returned value should be for music or for
sound effects. */
ULONG MD_SampleSpace(int type)
{
if(type==MD_MUSIC)
type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;
else if(type==MD_SNDFX)
type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;
return md_driver->FreeSampleSpace(type);
}
ULONG MD_SampleLength(int type,SAMPLE* s)
{
if(type==MD_MUSIC)
type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;
else
if(type==MD_SNDFX)
type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;
return md_driver->RealSampleLength(type,s);
}
CHAR* MikMod_InfoDriver(void)
{
int t,len=0;
MDRIVER *l;
CHAR *list=NULL;
MUTEX_LOCK(lists);
/* compute size of buffer */
for(l=firstdriver;l;l=l->next)
if(l->Version)
len+=4+(l->next?1:0)+strlen(l->Version);
if(len)
if((list=_mm_malloc(len*sizeof(CHAR)))) {
list[0]=0;
/* list all registered device drivers : */
for(t=1,l=firstdriver;l;l=l->next,t++)
if(l->Version)
sprintf(list,(l->next)?"%s%2d %s\n":"%s%2d %s",
list,t,l->Version);
}
MUTEX_UNLOCK(lists);
return list;
}
void _mm_registerdriver(struct MDRIVER* drv)
{
MDRIVER *cruise = firstdriver;
if(cruise) {
while(cruise->next) cruise=cruise->next;
cruise->next=drv;
} else
firstdriver = drv;
}
void _mm_unregisterdrivers(void)
{
MDRIVER *cruise=firstdriver, *drv;
while ( cruise ) {
drv = cruise;
cruise = cruise->next;
drv->next = NULL;
}
firstdriver = NULL;
}
void MikMod_RegisterDriver(struct MDRIVER* drv)
{
/* if we try to register an invalid driver, or an already registered driver,
ignore this attempt */
if ((!drv)||(drv->next))
return;
MUTEX_LOCK(lists);
_mm_registerdriver(drv);
MUTEX_UNLOCK(lists);
}
int MikMod_DriverFromAlias(CHAR *alias)
{
int rank=1;
MDRIVER *cruise;
MUTEX_LOCK(lists);
cruise=firstdriver;
while(cruise) {
if (cruise->Alias) {
if (!(strcasecmp(alias,cruise->Alias))) break;
rank++;
}
cruise=cruise->next;
}
if(!cruise) rank=0;
MUTEX_UNLOCK(lists);
return rank;
}
SWORD MD_SampleLoad(SAMPLOAD* s, int type)
{
SWORD result;
if(type==MD_MUSIC)
type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;
else if(type==MD_SNDFX)
type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;
SL_Init(s);
result=md_driver->SampleLoad(s,type);
SL_Exit(s);
return result;
}
void MD_SampleUnload(SWORD handle)
{
md_driver->SampleUnload(handle);
}
MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t player)
{
MikMod_player_t result;
MUTEX_LOCK(vars);
result=md_player;
md_player=player;
MUTEX_UNLOCK(vars);
return result;
}
void MikMod_Update(void)
{
MUTEX_LOCK(vars);
if(isplaying) {
if((!pf)||(!pf->forbid))
md_driver->Update();
else {
if (md_driver->Pause)
md_driver->Pause();
}
}
MUTEX_UNLOCK(vars);
}
void Voice_SetVolume_internal(SBYTE voice,UWORD vol)
{
ULONG tmp;
if((voice<0)||(voice>=md_numchn)) return;
/* range checks */
if(md_musicvolume>128) md_musicvolume=128;
if(md_sndfxvolume>128) md_sndfxvolume=128;
if(md_volume>128) md_volume=128;
tmp=(ULONG)vol*(ULONG)md_volume*
((voice<md_sngchn)?(ULONG)md_musicvolume:(ULONG)md_sndfxvolume);
md_driver->VoiceSetVolume(voice,tmp/16384UL);
}
void Voice_SetVolume(SBYTE voice,UWORD vol)
{
MUTEX_LOCK(vars);
Voice_SetVolume_internal(voice,vol);
MUTEX_UNLOCK(vars);
}
UWORD Voice_GetVolume(SBYTE voice)
{
UWORD result=0;
MUTEX_LOCK(vars);
if((voice>=0)&&(voice<md_numchn))
result=md_driver->VoiceGetVolume(voice);
MUTEX_UNLOCK(vars);
return result;
}
void Voice_SetFrequency_internal(SBYTE voice,ULONG frq)
{
if((voice<0)||(voice>=md_numchn)) return;
if((md_sample[voice])&&(md_sample[voice]->divfactor))
frq/=md_sample[voice]->divfactor;
md_driver->VoiceSetFrequency(voice,frq);
}
void Voice_SetFrequency(SBYTE voice,ULONG frq)
{
MUTEX_LOCK(vars);
Voice_SetFrequency_internal(voice,frq);
MUTEX_UNLOCK(vars);
}
ULONG Voice_GetFrequency(SBYTE voice)
{
ULONG result=0;
MUTEX_LOCK(vars);
if((voice>=0)&&(voice<md_numchn))
result=md_driver->VoiceGetFrequency(voice);
MUTEX_UNLOCK(vars);
return result;
}
void Voice_SetPanning_internal(SBYTE voice,ULONG pan)
{
if((voice<0)||(voice>=md_numchn)) return;
if(pan!=PAN_SURROUND) {
if(md_pansep>128) md_pansep=128;
if(md_mode & DMODE_REVERSE) pan=255-pan;
pan = (((SWORD)(pan-128)*md_pansep)/128)+128;
}
md_driver->VoiceSetPanning(voice, pan);
}
void Voice_SetPanning(SBYTE voice,ULONG pan)
{
#ifdef MIKMOD_DEBUG
if((pan!=PAN_SURROUND)&&((pan<0)||(pan>255)))
fprintf(stderr,"\rVoice_SetPanning called with pan=%ld\n",(long)pan);
#endif
MUTEX_LOCK(vars);
Voice_SetPanning_internal(voice,pan);
MUTEX_UNLOCK(vars);
}
ULONG Voice_GetPanning(SBYTE voice)
{
ULONG result=PAN_CENTER;
MUTEX_LOCK(vars);
if((voice>=0)&&(voice<md_numchn))
result=md_driver->VoiceGetPanning(voice);
MUTEX_UNLOCK(vars);
return result;
}
void Voice_Play_internal(SBYTE voice,SAMPLE* s,ULONG start)
{
ULONG repend;
if((voice<0)||(voice>=md_numchn)) return;
md_sample[voice]=s;
repend=s->loopend;
if(s->flags&SF_LOOP)
/* repend can't be bigger than size */
if(repend>s->length) repend=s->length;
md_driver->VoicePlay(voice,s->handle,start,s->length,s->loopstart,repend,s->flags);
}
void Voice_Play(SBYTE voice,SAMPLE* s,ULONG start)
{
if(start>s->length) return;
MUTEX_LOCK(vars);
Voice_Play_internal(voice,s,start);
MUTEX_UNLOCK(vars);
}
void Voice_Stop_internal(SBYTE voice)
{
if((voice<0)||(voice>=md_numchn)) return;
if(voice>=md_sngchn)
/* It is a sound effects channel, so flag the voice as non-critical! */
sfxinfo[voice-md_sngchn]=0;
md_driver->VoiceStop(voice);
}
void Voice_Stop(SBYTE voice)
{
MUTEX_LOCK(vars);
Voice_Stop_internal(voice);
MUTEX_UNLOCK(vars);
}
BOOL Voice_Stopped_internal(SBYTE voice)
{
if((voice<0)||(voice>=md_numchn)) return 0;
return(md_driver->VoiceStopped(voice));
}
BOOL Voice_Stopped(SBYTE voice)
{
BOOL result;
MUTEX_LOCK(vars);
result=Voice_Stopped_internal(voice);
MUTEX_UNLOCK(vars);
return result;
}
SLONG Voice_GetPosition(SBYTE voice)
{
SLONG result=0;
MUTEX_LOCK(vars);
if((voice>=0)&&(voice<md_numchn))
result=(md_driver->VoiceGetPosition(voice));
MUTEX_UNLOCK(vars);
return result;
}
ULONG Voice_RealVolume(SBYTE voice)
{
ULONG result=0;
MUTEX_LOCK(vars);
if((voice>=0)&&(voice<md_numchn))
result=(md_driver->VoiceRealVolume(voice));
MUTEX_UNLOCK(vars);
return result;
}
static BOOL _mm_init(CHAR *cmdline)
{
UWORD t;
_mm_critical = 1;
/* if md_device==0, try to find a device number */
if(!md_device) {
cmdline=NULL;
for(t=1,md_driver=firstdriver;md_driver;md_driver=md_driver->next,t++)
if(md_driver->Version)
if(md_driver->IsPresent()) break;
if(!md_driver) {
_mm_errno = MMERR_DETECTING_DEVICE;
if(_mm_errorhandler) _mm_errorhandler();
md_driver = &drv_nos;
return 1;
}
md_device = t;
} else {
/* if n>0, use that driver */
for(t=1,md_driver=firstdriver;(md_driver)&&(t!=md_device);md_driver=md_driver->next)
if(md_driver->Version)
t++;
if(!md_driver) {
_mm_errno = MMERR_INVALID_DEVICE;
if(_mm_errorhandler) _mm_errorhandler();
md_driver = &drv_nos;
return 1;
}
/* arguments here might be necessary for the presence check to succeed */
if(cmdline&&(md_driver->CommandLine))
md_driver->CommandLine(cmdline);
if(!md_driver->IsPresent()) {
_mm_errno = MMERR_DETECTING_DEVICE;
if(_mm_errorhandler) _mm_errorhandler();
md_driver = &drv_nos;
return 1;
}
}
if(md_driver->Init()) {
md_driver->Exit();
MikMod_Exit_internal();
if(_mm_errorhandler) _mm_errorhandler();
return 1;
}
initialized=1;
_mm_critical=0;
return 0;
}
BOOL MikMod_Init(CHAR *cmdline)
{
BOOL result;
MUTEX_LOCK(vars);
MUTEX_LOCK(lists);
result=_mm_init(cmdline);
MUTEX_UNLOCK(lists);
MUTEX_UNLOCK(vars);
return result;
}
void MikMod_Exit_internal(void)
{
MikMod_DisableOutput_internal();
md_driver->Exit();
md_numchn = md_sfxchn = md_sngchn = 0;
md_driver = &drv_nos;
if(sfxinfo) free(sfxinfo);
if(md_sample) free(md_sample);
md_sample = NULL;
sfxinfo = NULL;
initialized = 0;
}
void MikMod_Exit(void)
{
MUTEX_LOCK(vars);
MUTEX_LOCK(lists);
MikMod_Exit_internal();
MUTEX_UNLOCK(lists);
MUTEX_UNLOCK(vars);
}
/* Reset the driver using the new global variable settings.
If the driver has not been initialized, it will be now. */
static BOOL _mm_reset(CHAR *cmdline)
{
if(!initialized) return _mm_init(cmdline);
if((!md_driver->Reset)||(md_device != idevice)) {
/* md_driver->Reset was NULL, or md_device was changed, so do a full
reset of the driver. */
if(isplaying) md_driver->PlayStop();
md_driver->Exit();
if(_mm_init(cmdline)) {
MikMod_Exit_internal();
if(_mm_errno)
if(_mm_errorhandler) _mm_errorhandler();
return 1;
}
if(isplaying) md_driver->PlayStart();
} else {
if(md_driver->Reset()) {
MikMod_Exit_internal();
if(_mm_errno)
if(_mm_errorhandler) _mm_errorhandler();
return 1;
}
}
return 0;
}
BOOL MikMod_Reset(CHAR *cmdline)
{
BOOL result;
MUTEX_LOCK(vars);
MUTEX_LOCK(lists);
result=_mm_reset(cmdline);
MUTEX_UNLOCK(lists);
MUTEX_UNLOCK(vars);
return result;
}
/* If either parameter is -1, the current set value will be retained. */
BOOL MikMod_SetNumVoices_internal(int music, int sfx)
{
BOOL resume = 0;
int t, oldchn = 0;
if((!music)&&(!sfx)) return 1;
_mm_critical = 1;
if(isplaying) {
MikMod_DisableOutput_internal();
oldchn = md_numchn;
resume = 1;
}
if(sfxinfo) free(sfxinfo);
if(md_sample) free(md_sample);
md_sample = NULL;
sfxinfo = NULL;
if(music!=-1) md_sngchn = music;
if(sfx!=-1) md_sfxchn = sfx;
md_numchn = md_sngchn + md_sfxchn;
LimitHardVoices(md_driver->HardVoiceLimit);
LimitSoftVoices(md_driver->SoftVoiceLimit);
if(md_driver->SetNumVoices()) {
MikMod_Exit_internal();
if(_mm_errno)
if(_mm_errorhandler!=NULL) _mm_errorhandler();
md_numchn = md_softchn = md_hardchn = md_sfxchn = md_sngchn = 0;
return 1;
}
if(md_sngchn+md_sfxchn)
md_sample=(SAMPLE**)_mm_calloc(md_sngchn+md_sfxchn,sizeof(SAMPLE*));
if(md_sfxchn)
sfxinfo = (UBYTE *)_mm_calloc(md_sfxchn,sizeof(UBYTE));
/* make sure the player doesn't start with garbage */
for(t=oldchn;t<md_numchn;t++) Voice_Stop_internal(t);
sfxpool = 0;
if(resume) MikMod_EnableOutput_internal();
_mm_critical = 0;
return 0;
}
BOOL MikMod_SetNumVoices(int music, int sfx)
{
BOOL result;
MUTEX_LOCK(vars);
result=MikMod_SetNumVoices_internal(music,sfx);
MUTEX_UNLOCK(vars);
return result;
}
BOOL MikMod_EnableOutput_internal(void)
{
_mm_critical = 1;
if(!isplaying) {
if(md_driver->PlayStart()) return 1;
isplaying = 1;
}
_mm_critical = 0;
return 0;
}
BOOL MikMod_EnableOutput(void)
{
BOOL result;
MUTEX_LOCK(vars);
result=MikMod_EnableOutput_internal();
MUTEX_UNLOCK(vars);
return result;
}
void MikMod_DisableOutput_internal(void)
{
if(isplaying && md_driver) {
isplaying = 0;
md_driver->PlayStop();
}
}
void MikMod_DisableOutput(void)
{
MUTEX_LOCK(vars);
MikMod_DisableOutput_internal();
MUTEX_UNLOCK(vars);
}
BOOL MikMod_Active_internal(void)
{
return isplaying;
}
BOOL MikMod_Active(void)
{
BOOL result;
MUTEX_LOCK(vars);
result=MikMod_Active_internal();
MUTEX_UNLOCK(vars);
return result;
}
/* Plays a sound effects sample. Picks a voice from the number of voices
allocated for use as sound effects (loops through voices, skipping all active
criticals).
Returns the voice that the sound is being played on. */
SBYTE Sample_Play_internal(SAMPLE *s,ULONG start,UBYTE flags)
{
int orig=sfxpool;/* for cases where all channels are critical */
int c;
if(!md_sfxchn) return -1;
if(s->volume>64) s->volume = 64;
/* check the first location after sfxpool */
do {
if(sfxinfo[sfxpool]&SFX_CRITICAL) {
if(md_driver->VoiceStopped(c=sfxpool+md_sngchn)) {
sfxinfo[sfxpool]=flags;
Voice_Play_internal(c,s,start);
md_driver->VoiceSetVolume(c,s->volume<<2);
Voice_SetPanning_internal(c,s->panning);
md_driver->VoiceSetFrequency(c,s->speed);
sfxpool++;
if(sfxpool>=md_sfxchn) sfxpool=0;
return c;
}
} else {
sfxinfo[sfxpool]=flags;
Voice_Play_internal(c=sfxpool+md_sngchn,s,start);
md_driver->VoiceSetVolume(c,s->volume<<2);
Voice_SetPanning_internal(c,s->panning);
md_driver->VoiceSetFrequency(c,s->speed);
sfxpool++;
if(sfxpool>=md_sfxchn) sfxpool=0;
return c;
}
sfxpool++;
if(sfxpool>=md_sfxchn) sfxpool = 0;
} while(sfxpool!=orig);
return -1;
}
SBYTE Sample_Play(SAMPLE *s,ULONG start,UBYTE flags)
{
SBYTE result;
MUTEX_LOCK(vars);
result=Sample_Play_internal(s,start,flags);
MUTEX_UNLOCK(vars);
return result;
}
long MikMod_GetVersion(void)
{
return LIBMIKMOD_VERSION;
}
/*========== MT-safe stuff */
#ifdef HAVE_PTHREAD
#define INIT_MUTEX(name) \
pthread_mutex_t _mm_mutex_##name=PTHREAD_MUTEX_INITIALIZER
#elif defined(__OS2__)||defined(__EMX__)
#define INIT_MUTEX(name) \
HMTX _mm_mutex_##name
#elif defined(WIN32)
#define INIT_MUTEX(name) \
HANDLE _mm_mutex_##name
#else
#define INIT_MUTEX(name)
#endif
INIT_MUTEX(vars);
INIT_MUTEX(lists);
BOOL MikMod_InitThreads(void)
{
static int firstcall=1;
static int result=0;
if (firstcall) {
firstcall=0;
#ifdef HAVE_PTHREAD
result=1;
#elif defined(__OS2__)||defined(__EMX__)
if(DosCreateMutexSem((PSZ)NULL,&_mm_mutex_lists,0,0) ||
DosCreateMutexSem((PSZ)NULL,&_mm_mutex_vars,0,0)) {
_mm_mutex_lists=_mm_mutex_vars=(HMTX)NULL;
result=0;
} else
result=1;
#elif defined(WIN32)
if((!(_mm_mutex_lists=CreateMutex(NULL,FALSE,"libmikmod(lists)")))||
(!(_mm_mutex_vars=CreateMutex(NULL,FALSE,"libmikmod(vars)"))))
result=0;
else
result=1;
#endif
}
return result;
}
void MikMod_Unlock(void)
{
MUTEX_UNLOCK(lists);
MUTEX_UNLOCK(vars);
}
void MikMod_Lock(void)
{
MUTEX_LOCK(vars);
MUTEX_LOCK(lists);
}
/*========== Parameter extraction helper */
CHAR *MD_GetAtom(CHAR *atomname,CHAR *cmdline,BOOL implicit)
{
CHAR *ret=NULL;
if(cmdline) {
CHAR *buf=strstr(cmdline,atomname);
if((buf)&&((buf==cmdline)||(*(buf-1)==','))) {
CHAR *ptr=buf+strlen(atomname);
if(*ptr=='=') {
for(buf=++ptr;(*ptr)&&((*ptr)!=',');ptr++);
ret=_mm_malloc((1+ptr-buf)*sizeof(CHAR));
if(ret)
strncpy(ret,buf,ptr-buf);
} else if((*ptr==',')||(!*ptr)) {
if(implicit) {
ret=_mm_malloc((1+ptr-buf)*sizeof(CHAR));
if(ret)
strncpy(ret,buf,ptr-buf);
}
}
}
}
return ret;
}
#ifdef unix
#include <unistd.h>
/*========== Posix helper functions */
/* Check if the file is a regular or nonexistant file (or a link to a such a
file), and that, should the calling program be setuid, the access rights are
reasonable. Returns 1 if it is safe to rewrite the file, 0 otherwise.
The goal is to prevent a setuid root libmikmod application from overriding
files like /etc/passwd with digital sound... */
BOOL MD_Access(CHAR *filename)
{
struct stat buf;
if(!stat(filename,&buf)) {
/* not a regular file ? */
if(!S_ISREG(buf.st_mode)) return 0;
/* more than one hard link to the file ? */
if(buf.st_nlink>1) return 0;
/* check access rights with the real user and group id */
if(getuid()==buf.st_uid) {
if(!(buf.st_mode&S_IWUSR)) return 0;
} else if(getgid()==buf.st_gid) {
if(!(buf.st_mode&S_IWGRP)) return 0;
} else
if(!(buf.st_mode&S_IWOTH)) return 0;
}
return 1;
}
/* Drop all root privileges we might have */
BOOL MD_DropPrivileges(void)
{
if(!geteuid()) {
if(getuid()) {
/* we are setuid root -> drop setuid to become the real user */
if(setuid(getuid())) return 1;
} else {
/* we are run as root -> drop all and become user 'nobody' */
struct passwd *nobody;
int uid;
if(!(nobody=getpwnam("nobody"))) return 1; /* no such user ? */
uid=nobody->pw_uid;
if (!uid) /* user 'nobody' has root privileges ? weird... */
return 1;
if (setuid(uid)) return 1;
}
}
return 0;
}
#endif
/* ex:set ts=4: */
#endif
@@ -0,0 +1,710 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
MikMod sound library include file
==============================================================================*/
#ifndef _MIKMOD_H_
#define _MIKMOD_H_
#include <stdio.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* ========== Compiler magic for shared libraries
*/
#if defined(WIN32) && 0 /* We're not building a shared library */
#ifdef DLL_EXPORTS
#define MIKMODAPI __declspec(dllexport)
#else
#define MIKMODAPI __declspec(dllimport)
#endif
#else
#define MIKMODAPI
#endif
/*
* ========== Library version
*/
#define LIBMIKMOD_VERSION_MAJOR 3
#define LIBMIKMOD_VERSION_MINOR 1
#define LIBMIKMOD_REVISION 8
#define LIBMIKMOD_VERSION \
((LIBMIKMOD_VERSION_MAJOR<<16)| \
(LIBMIKMOD_VERSION_MINOR<< 8)| \
(LIBMIKMOD_REVISION))
MIKMODAPI extern long MikMod_GetVersion(void);
/*
* ========== Platform independent-type definitions
*/
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <io.h>
#endif
#if defined(__OS2__)||defined(__EMX__)
#define INCL_DOSSEMAPHORES
#include <os2.h>
#else
#ifndef WIN32
typedef char CHAR;
#endif
#endif
/*@DOES_NOT_HAVE_SIGNED@*/
#if defined(__alpha)
/* 64 bit architectures */
typedef signed char SBYTE; /* 1 byte, signed */
typedef unsigned char UBYTE; /* 1 byte, unsigned */
typedef signed short SWORD; /* 2 bytes, signed */
typedef unsigned short UWORD; /* 2 bytes, unsigned */
typedef signed int SLONG; /* 4 bytes, signed */
typedef unsigned int ULONG; /* 4 bytes, unsigned */
typedef int BOOL; /* 0=false, <>0 true */
#else
/* 32 bit architectures */
typedef signed char SBYTE; /* 1 byte, signed */
typedef unsigned char UBYTE; /* 1 byte, unsigned */
typedef signed short SWORD; /* 2 bytes, signed */
typedef unsigned short UWORD; /* 2 bytes, unsigned */
typedef signed long SLONG; /* 4 bytes, signed */
#if !defined(__OS2__)&&!defined(__EMX__)&&!defined(WIN32)
typedef unsigned long ULONG; /* 4 bytes, unsigned */
typedef int BOOL; /* 0=false, <>0 true */
#endif
#endif
/*
* ========== Error codes
*/
enum {
MMERR_OPENING_FILE = 1,
MMERR_OUT_OF_MEMORY,
MMERR_DYNAMIC_LINKING,
MMERR_SAMPLE_TOO_BIG,
MMERR_OUT_OF_HANDLES,
MMERR_UNKNOWN_WAVE_TYPE,
MMERR_LOADING_PATTERN,
MMERR_LOADING_TRACK,
MMERR_LOADING_HEADER,
MMERR_LOADING_SAMPLEINFO,
MMERR_NOT_A_MODULE,
MMERR_NOT_A_STREAM,
MMERR_MED_SYNTHSAMPLES,
MMERR_ITPACK_INVALID_DATA,
MMERR_DETECTING_DEVICE,
MMERR_INVALID_DEVICE,
MMERR_INITIALIZING_MIXER,
MMERR_OPENING_AUDIO,
MMERR_8BIT_ONLY,
MMERR_16BIT_ONLY,
MMERR_STEREO_ONLY,
MMERR_ULAW,
MMERR_NON_BLOCK,
MMERR_AF_AUDIO_PORT,
MMERR_AIX_CONFIG_INIT,
MMERR_AIX_CONFIG_CONTROL,
MMERR_AIX_CONFIG_START,
MMERR_GUS_SETTINGS,
MMERR_GUS_RESET,
MMERR_GUS_TIMER,
MMERR_HP_SETSAMPLESIZE,
MMERR_HP_SETSPEED,
MMERR_HP_CHANNELS,
MMERR_HP_AUDIO_OUTPUT,
MMERR_HP_AUDIO_DESC,
MMERR_HP_BUFFERSIZE,
MMERR_OSS_SETFRAGMENT,
MMERR_OSS_SETSAMPLESIZE,
MMERR_OSS_SETSTEREO,
MMERR_OSS_SETSPEED,
MMERR_SGI_SPEED,
MMERR_SGI_16BIT,
MMERR_SGI_8BIT,
MMERR_SGI_STEREO,
MMERR_SGI_MONO,
MMERR_SUN_INIT,
MMERR_OS2_MIXSETUP,
MMERR_OS2_SEMAPHORE,
MMERR_OS2_TIMER,
MMERR_OS2_THREAD,
MMERR_DS_PRIORITY,
MMERR_DS_BUFFER,
MMERR_DS_FORMAT,
MMERR_DS_NOTIFY,
MMERR_DS_EVENT,
MMERR_DS_THREAD,
MMERR_DS_UPDATE,
MMERR_WINMM_HANDLE,
MMERR_WINMM_ALLOCATED,
MMERR_WINMM_DEVICEID,
MMERR_WINMM_FORMAT,
MMERR_WINMM_UNKNOWN,
MMERR_MAC_SPEED,
MMERR_MAC_START,
MMERR_MAX
};
/*
* ========== Error handling
*/
typedef void (MikMod_handler)(void);
typedef MikMod_handler *MikMod_handler_t;
MIKMODAPI extern int MikMod_errno;
MIKMODAPI extern BOOL MikMod_critical;
MIKMODAPI extern char *MikMod_strerror(int);
MIKMODAPI extern MikMod_handler_t MikMod_RegisterErrorHandler(MikMod_handler_t);
/*
* ========== Library initialization and core functions
*/
struct MDRIVER;
MIKMODAPI extern void MikMod_RegisterAllDrivers(void);
MIKMODAPI extern void MikMod_UnregisterAllDrivers(void);
MIKMODAPI extern CHAR* MikMod_InfoDriver(void);
MIKMODAPI extern void MikMod_RegisterDriver(struct MDRIVER*);
MIKMODAPI extern int MikMod_DriverFromAlias(CHAR*);
MIKMODAPI extern BOOL MikMod_Init(CHAR*);
MIKMODAPI extern void MikMod_Exit(void);
MIKMODAPI extern BOOL MikMod_Reset(CHAR*);
MIKMODAPI extern BOOL MikMod_SetNumVoices(int,int);
MIKMODAPI extern BOOL MikMod_Active(void);
MIKMODAPI extern BOOL MikMod_EnableOutput(void);
MIKMODAPI extern void MikMod_DisableOutput(void);
MIKMODAPI extern void MikMod_Update(void);
MIKMODAPI extern BOOL MikMod_InitThreads(void);
MIKMODAPI extern void MikMod_Lock(void);
MIKMODAPI extern void MikMod_Unlock(void);
/*
* ========== Reader, Writer
*/
typedef struct MREADER {
BOOL (*Seek)(struct MREADER*,long,int);
long (*Tell)(struct MREADER*);
BOOL (*Read)(struct MREADER*,void*,size_t);
int (*Get)(struct MREADER*);
BOOL (*Eof)(struct MREADER*);
} MREADER;
typedef struct MWRITER {
BOOL (*Seek)(struct MWRITER*,long,int);
long (*Tell)(struct MWRITER*);
BOOL (*Write)(struct MWRITER*,void*,size_t);
BOOL (*Put)(struct MWRITER*,int);
} MWRITER;
/*
* ========== Samples
*/
/* Sample playback should not be interrupted */
#define SFX_CRITICAL 1
/* Sample format [loading and in-memory] flags: */
#define SF_16BITS 0x0001
#define SF_STEREO 0x0002
#define SF_SIGNED 0x0004
#define SF_BIG_ENDIAN 0x0008
#define SF_DELTA 0x0010
#define SF_ITPACKED 0x0020
#define SF_FORMATMASK 0x003F
/* General Playback flags */
#define SF_LOOP 0x0100
#define SF_BIDI 0x0200
#define SF_REVERSE 0x0400
#define SF_SUSTAIN 0x0800
#define SF_PLAYBACKMASK 0x0C00
/* Module-only Playback Flags */
#define SF_OWNPAN 0x1000
#define SF_UST_LOOP 0x2000
#define SF_EXTRAPLAYBACKMASK 0x3000
/* Panning constants */
#define PAN_LEFT 0
#define PAN_CENTER 128
#define PAN_RIGHT 255
#define PAN_SURROUND 512 /* panning value for Dolby Surround */
typedef struct SAMPLE {
SWORD panning; /* panning (0-255 or PAN_SURROUND) */
ULONG speed; /* Base playing speed/frequency of note */
UBYTE volume; /* volume 0-64 */
UWORD inflags; /* sample format on disk */
UWORD flags; /* sample format in memory */
ULONG length; /* length of sample (in samples!) */
ULONG loopstart; /* repeat position (relative to start, in samples) */
ULONG loopend; /* repeat end */
ULONG susbegin; /* sustain loop begin (in samples) \ Not Supported */
ULONG susend; /* sustain loop end / Yet! */
/* Variables used by the module player only! (ignored for sound effects) */
UBYTE globvol; /* global volume */
UBYTE vibflags; /* autovibrato flag stuffs */
UBYTE vibtype; /* Vibratos moved from INSTRUMENT to SAMPLE */
UBYTE vibsweep;
UBYTE vibdepth;
UBYTE vibrate;
CHAR* samplename; /* name of the sample */
/* Values used internally only */
UWORD avibpos; /* autovibrato pos [player use] */
UBYTE divfactor; /* for sample scaling, maintains proper period slides */
ULONG seekpos; /* seek position in file */
SWORD handle; /* sample handle used by individual drivers */
} SAMPLE;
/* Sample functions */
MIKMODAPI extern SAMPLE *Sample_Load(CHAR*);
MIKMODAPI extern SAMPLE *Sample_LoadFP(FILE*);
MIKMODAPI extern SAMPLE *Sample_LoadGeneric(MREADER*);
MIKMODAPI extern void Sample_Free(SAMPLE*);
MIKMODAPI extern SBYTE Sample_Play(SAMPLE*,ULONG,UBYTE);
MIKMODAPI extern void Voice_SetVolume(SBYTE,UWORD);
MIKMODAPI extern UWORD Voice_GetVolume(SBYTE);
MIKMODAPI extern void Voice_SetFrequency(SBYTE,ULONG);
MIKMODAPI extern ULONG Voice_GetFrequency(SBYTE);
MIKMODAPI extern void Voice_SetPanning(SBYTE,ULONG);
MIKMODAPI extern ULONG Voice_GetPanning(SBYTE);
MIKMODAPI extern void Voice_Play(SBYTE,SAMPLE*,ULONG);
MIKMODAPI extern void Voice_Stop(SBYTE);
MIKMODAPI extern BOOL Voice_Stopped(SBYTE);
MIKMODAPI extern SLONG Voice_GetPosition(SBYTE);
MIKMODAPI extern ULONG Voice_RealVolume(SBYTE);
/*
* ========== Internal module representation (UniMod)
*/
/*
Instrument definition - for information only, the only field which may be
of use in user programs is the name field
*/
/* Instrument note count */
#define INSTNOTES 120
/* Envelope point */
typedef struct ENVPT {
SWORD pos;
SWORD val;
} ENVPT;
/* Envelope point count */
#define ENVPOINTS 32
/* Instrument structure */
typedef struct INSTRUMENT {
CHAR* insname;
UBYTE flags;
UWORD samplenumber[INSTNOTES];
UBYTE samplenote[INSTNOTES];
UBYTE nnatype;
UBYTE dca; /* duplicate check action */
UBYTE dct; /* duplicate check type */
UBYTE globvol;
UWORD volfade;
SWORD panning; /* instrument-based panning var */
UBYTE pitpansep; /* pitch pan separation (0 to 255) */
UBYTE pitpancenter; /* pitch pan center (0 to 119) */
UBYTE rvolvar; /* random volume varations (0 - 100%) */
UBYTE rpanvar; /* random panning varations (0 - 100%) */
/* volume envelope */
UBYTE volflg; /* bit 0: on 1: sustain 2: loop */
UBYTE volpts;
UBYTE volsusbeg;
UBYTE volsusend;
UBYTE volbeg;
UBYTE volend;
ENVPT volenv[ENVPOINTS];
/* panning envelope */
UBYTE panflg; /* bit 0: on 1: sustain 2: loop */
UBYTE panpts;
UBYTE pansusbeg;
UBYTE pansusend;
UBYTE panbeg;
UBYTE panend;
ENVPT panenv[ENVPOINTS];
/* pitch envelope */
UBYTE pitflg; /* bit 0: on 1: sustain 2: loop */
UBYTE pitpts;
UBYTE pitsusbeg;
UBYTE pitsusend;
UBYTE pitbeg;
UBYTE pitend;
ENVPT pitenv[ENVPOINTS];
} INSTRUMENT;
struct MP_CONTROL;
struct MP_VOICE;
/* Module flags */
#define UF_XMPERIODS 0x0001 /* XM periods / finetuning */
#define UF_LINEAR 0x0002 /* LINEAR periods (UF_XMPERIODS must be set) */
#define UF_INST 0x0004 /* Instruments are used */
#define UF_NNA 0x0008 /* IT: NNA used, set numvoices rather than numchn */
#define UF_S3MSLIDES 0x0010 /* uses old S3M volume slides */
#define UF_BGSLIDES 0x0020 /* continue volume slides in the background */
#define UF_HIGHBPM 0x0040 /* MED: can use >255 bpm */
#define UF_NOWRAP 0x0080 /* XM-type (i.e. illogical) pattern brk semantics */
#define UF_ARPMEM 0x0100 /* IT: need arpeggio memory */
#define UF_FT2QUIRKS 0x0200 /* emulate some FT2 replay quirks */
typedef struct MODULE {
/* general module information */
CHAR* songname; /* name of the song */
CHAR* modtype; /* string type of module loaded */
CHAR* comment; /* module comments */
UWORD flags; /* See module flags above */
UBYTE numchn; /* number of module channels */
UBYTE numvoices; /* max # voices used for full NNA playback */
UWORD numpos; /* number of positions in this song */
UWORD numpat; /* number of patterns in this song */
UWORD numins; /* number of instruments */
UWORD numsmp; /* number of samples */
struct INSTRUMENT* instruments; /* all instruments */
struct SAMPLE* samples; /* all samples */
UBYTE realchn; /* real number of channels used */
UBYTE totalchn; /* total number of channels used (incl NNAs) */
/* playback settings */
UWORD reppos; /* restart position */
UBYTE initspeed; /* initial song speed */
UWORD inittempo; /* initial song tempo */
UBYTE initvolume; /* initial global volume (0 - 128) */
UWORD panning[64]; /* 64 panning positions */
UBYTE chanvol[64]; /* 64 channel positions */
UWORD bpm; /* current beats-per-minute speed */
UWORD sngspd; /* current song speed */
SWORD volume; /* song volume (0-128) (or user volume) */
BOOL extspd; /* extended speed flag (default enabled) */
BOOL panflag; /* panning flag (default enabled) */
BOOL wrap; /* wrap module ? (default disabled) */
BOOL loop; /* allow module to loop ? (default enabled) */
BOOL fadeout; /* volume fade out during last pattern */
UWORD patpos; /* current row number */
SWORD sngpos; /* current song position */
ULONG sngtime; /* current song time in 2^-10 seconds */
SWORD relspd; /* relative speed factor */
/* internal module representation */
UWORD numtrk; /* number of tracks */
UBYTE** tracks; /* array of numtrk pointers to tracks */
UWORD* patterns; /* array of Patterns */
UWORD* pattrows; /* array of number of rows for each pattern */
UWORD* positions; /* all positions */
BOOL forbid; /* if true, no player update! */
UWORD numrow; /* number of rows on current pattern */
UWORD vbtick; /* tick counter (counts from 0 to sngspd) */
UWORD sngremainder;/* used for song time computation */
struct MP_CONTROL* control; /* Effects Channel info (size pf->numchn) */
struct MP_VOICE* voice; /* Audio Voice information (size md_numchn) */
UBYTE globalslide; /* global volume slide rate */
UBYTE pat_repcrazy;/* module has just looped to position -1 */
UWORD patbrk; /* position where to start a new pattern */
UBYTE patdly; /* patterndelay counter (command memory) */
UBYTE patdly2; /* patterndelay counter (real one) */
SWORD posjmp; /* flag to indicate a jump is needed... */
} MODULE;
/*
* ========== Module loaders
*/
struct MLOADER;
MIKMODAPI extern CHAR* MikMod_InfoLoader(void);
MIKMODAPI extern void MikMod_RegisterAllLoaders(void);
MIKMODAPI extern void MikMod_UnregisterAllLoaders(void);
MIKMODAPI extern void MikMod_RegisterLoader(struct MLOADER*);
MIKMODAPI extern struct MLOADER load_669; /* 669 and Extended-669 (by Tran/Renaissance) */
MIKMODAPI extern struct MLOADER load_amf; /* DMP Advanced Module Format (by Otto Chrons) */
MIKMODAPI extern struct MLOADER load_dsm; /* DSIK internal module format */
MIKMODAPI extern struct MLOADER load_far; /* Farandole Composer (by Daniel Potter) */
MIKMODAPI extern struct MLOADER load_gdm; /* General DigiMusic (by Edward Schlunder) */
MIKMODAPI extern struct MLOADER load_it; /* Impulse Tracker (by Jeffrey Lim) */
MIKMODAPI extern struct MLOADER load_imf; /* Imago Orpheus (by Lutz Roeder) */
MIKMODAPI extern struct MLOADER load_med; /* Amiga MED modules (by Teijo Kinnunen) */
MIKMODAPI extern struct MLOADER load_m15; /* Soundtracker 15-instrument */
MIKMODAPI extern struct MLOADER load_mod; /* Standard 31-instrument Module loader */
MIKMODAPI extern struct MLOADER load_mtm; /* Multi-Tracker Module (by Renaissance) */
MIKMODAPI extern struct MLOADER load_stm; /* ScreamTracker 2 (by Future Crew) */
MIKMODAPI extern struct MLOADER load_stx; /* STMIK 0.2 (by Future Crew) */
MIKMODAPI extern struct MLOADER load_s3m; /* ScreamTracker 3 (by Future Crew) */
MIKMODAPI extern struct MLOADER load_ult; /* UltraTracker (by MAS) */
MIKMODAPI extern struct MLOADER load_uni; /* MikMod and APlayer internal module format */
MIKMODAPI extern struct MLOADER load_xm; /* FastTracker 2 (by Triton) */
/*
* ========== Module player
*/
/* SDL_RWops compatability */
#ifdef USE_RWOPS
#include "SDL_rwops.h"
MIKMODAPI extern MODULE* Player_LoadRW(SDL_RWops*,int,BOOL);
#endif /* USE_RWOPS */
/* End SDL_RWops compatability */
MIKMODAPI extern MODULE* Player_Load(CHAR*,int,BOOL);
MIKMODAPI extern MODULE* Player_LoadFP(FILE*,int,BOOL);
MIKMODAPI extern MODULE* Player_LoadGeneric(MREADER*,int,BOOL);
MIKMODAPI extern CHAR* Player_LoadTitle(CHAR*);
MIKMODAPI extern void Player_Free(MODULE*);
MIKMODAPI extern void Player_Start(MODULE*);
MIKMODAPI extern BOOL Player_Active(void);
MIKMODAPI extern void Player_Stop(void);
MIKMODAPI extern void Player_TogglePause(void);
MIKMODAPI extern BOOL Player_Paused(void);
MIKMODAPI extern void Player_NextPosition(void);
MIKMODAPI extern void Player_PrevPosition(void);
MIKMODAPI extern void Player_SetPosition(UWORD);
MIKMODAPI extern BOOL Player_Muted(UBYTE);
MIKMODAPI extern void Player_SetVolume(SWORD);
MIKMODAPI extern MODULE* Player_GetModule(void);
MIKMODAPI extern void Player_SetSpeed(UWORD);
MIKMODAPI extern void Player_SetTempo(UWORD);
MIKMODAPI extern void Player_Unmute(SLONG,...);
MIKMODAPI extern void Player_Mute(SLONG,...);
MIKMODAPI extern void Player_ToggleMute(SLONG,...);
MIKMODAPI extern int Player_GetChannelVoice(UBYTE);
MIKMODAPI extern UWORD Player_GetChannelPeriod(UBYTE);
MIKMODAPI extern void Player_SetSynchroValue(int);
MIKMODAPI extern int Player_GetSynchroValue(void);
typedef void (MikMod_player)(void);
typedef MikMod_player *MikMod_player_t;
MIKMODAPI extern MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t);
#define MUTE_EXCLUSIVE 32000
#define MUTE_INCLUSIVE 32001
/*
* ========== Drivers
*/
enum {
MD_MUSIC = 0,
MD_SNDFX
};
enum {
MD_HARDWARE = 0,
MD_SOFTWARE
};
/* Mixing flags */
/* These ones take effect only after MikMod_Init or MikMod_Reset */
#define DMODE_16BITS 0x0001 /* enable 16 bit output */
#define DMODE_STEREO 0x0002 /* enable stereo output */
#define DMODE_SOFT_SNDFX 0x0004 /* Process sound effects via software mixer */
#define DMODE_SOFT_MUSIC 0x0008 /* Process music via software mixer */
#define DMODE_HQMIXER 0x0010 /* Use high-quality (slower) software mixer */
/* These take effect immediately. */
#define DMODE_SURROUND 0x0100 /* enable surround sound */
#define DMODE_INTERP 0x0200 /* enable interpolation */
#define DMODE_REVERSE 0x0400 /* reverse stereo */
struct SAMPLOAD;
typedef struct MDRIVER {
struct MDRIVER* next;
CHAR* Name;
CHAR* Version;
UBYTE HardVoiceLimit; /* Limit of hardware mixer voices */
UBYTE SoftVoiceLimit; /* Limit of software mixer voices */
CHAR* Alias;
void (*CommandLine) (CHAR*);
BOOL (*IsPresent) (void);
SWORD (*SampleLoad) (struct SAMPLOAD*,int);
void (*SampleUnload) (SWORD);
ULONG (*FreeSampleSpace) (int);
ULONG (*RealSampleLength) (int,struct SAMPLE*);
BOOL (*Init) (void);
void (*Exit) (void);
BOOL (*Reset) (void);
BOOL (*SetNumVoices) (void);
BOOL (*PlayStart) (void);
void (*PlayStop) (void);
void (*Update) (void);
void (*Pause) (void);
void (*VoiceSetVolume) (UBYTE,UWORD);
UWORD (*VoiceGetVolume) (UBYTE);
void (*VoiceSetFrequency)(UBYTE,ULONG);
ULONG (*VoiceGetFrequency)(UBYTE);
void (*VoiceSetPanning) (UBYTE,ULONG);
ULONG (*VoiceGetPanning) (UBYTE);
void (*VoicePlay) (UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
void (*VoiceStop) (UBYTE);
BOOL (*VoiceStopped) (UBYTE);
SLONG (*VoiceGetPosition) (UBYTE);
ULONG (*VoiceRealVolume) (UBYTE);
} MDRIVER;
/* These variables can be changed at ANY time and results will be immediate */
MIKMODAPI extern UBYTE md_volume; /* global sound volume (0-128) */
MIKMODAPI extern UBYTE md_musicvolume; /* volume of song */
MIKMODAPI extern UBYTE md_sndfxvolume; /* volume of sound effects */
MIKMODAPI extern UBYTE md_reverb; /* 0 = none; 15 = chaos */
MIKMODAPI extern UBYTE md_pansep; /* 0 = mono; 128 == 100% (full left/right) */
/* The variables below can be changed at any time, but changes will not be
implemented until MikMod_Reset is called. A call to MikMod_Reset may result
in a skip or pop in audio (depending on the soundcard driver and the settings
changed). */
MIKMODAPI extern UWORD md_device; /* device */
MIKMODAPI extern UWORD md_mixfreq; /* mixing frequency */
MIKMODAPI extern UWORD md_mode; /* mode. See DMODE_? flags above */
/* The following variable should not be changed! */
MIKMODAPI extern MDRIVER* md_driver; /* Current driver in use. */
/* Known drivers list */
MIKMODAPI extern struct MDRIVER drv_nos; /* no sound */
MIKMODAPI extern struct MDRIVER drv_pipe; /* piped output */
MIKMODAPI extern struct MDRIVER drv_raw; /* raw file disk writer [music.raw] */
MIKMODAPI extern struct MDRIVER drv_stdout; /* output to stdout */
MIKMODAPI extern struct MDRIVER drv_wav; /* RIFF WAVE file disk writer [music.wav] */
MIKMODAPI extern struct MDRIVER drv_ultra; /* Linux Ultrasound driver */
MIKMODAPI extern struct MDRIVER drv_AF; /* Dec Alpha AudioFile */
MIKMODAPI extern struct MDRIVER drv_aix; /* AIX audio device */
MIKMODAPI extern struct MDRIVER drv_alsa; /* Advanced Linux Sound Architecture (ALSA) */
MIKMODAPI extern struct MDRIVER drv_esd; /* Enlightened sound daemon (EsounD) */
MIKMODAPI extern struct MDRIVER drv_hp; /* HP-UX audio device */
MIKMODAPI extern struct MDRIVER drv_oss; /* OpenSound System (Linux,FreeBSD...) */
MIKMODAPI extern struct MDRIVER drv_sgi; /* SGI audio library */
MIKMODAPI extern struct MDRIVER drv_sun; /* Sun/NetBSD/OpenBSD audio device */
MIKMODAPI extern struct MDRIVER drv_dart; /* OS/2 Direct Audio RealTime */
MIKMODAPI extern struct MDRIVER drv_os2; /* OS/2 MMPM/2 */
MIKMODAPI extern struct MDRIVER drv_ds; /* Win32 DirectSound driver */
MIKMODAPI extern struct MDRIVER drv_win; /* Win32 multimedia API driver */
MIKMODAPI extern struct MDRIVER drv_mac; /* Macintosh Sound Manager driver */
/*========== Virtual channel mixer interface (for user-supplied drivers only) */
MIKMODAPI extern BOOL VC_Init(void);
MIKMODAPI extern void VC_Exit(void);
MIKMODAPI extern BOOL VC_SetNumVoices(void);
MIKMODAPI extern ULONG VC_SampleSpace(int);
MIKMODAPI extern ULONG VC_SampleLength(int,SAMPLE*);
MIKMODAPI extern BOOL VC_PlayStart(void);
MIKMODAPI extern void VC_PlayStop(void);
MIKMODAPI extern SWORD VC_SampleLoad(struct SAMPLOAD*,int);
MIKMODAPI extern void VC_SampleUnload(SWORD);
MIKMODAPI extern ULONG VC_WriteBytes(SBYTE*,ULONG);
MIKMODAPI extern ULONG VC_SilenceBytes(SBYTE*,ULONG);
MIKMODAPI extern void VC_VoiceSetVolume(UBYTE,UWORD);
MIKMODAPI extern UWORD VC_VoiceGetVolume(UBYTE);
MIKMODAPI extern void VC_VoiceSetFrequency(UBYTE,ULONG);
MIKMODAPI extern ULONG VC_VoiceGetFrequency(UBYTE);
MIKMODAPI extern void VC_VoiceSetPanning(UBYTE,ULONG);
MIKMODAPI extern ULONG VC_VoiceGetPanning(UBYTE);
MIKMODAPI extern void VC_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
MIKMODAPI extern void VC_VoiceStop(UBYTE);
MIKMODAPI extern BOOL VC_VoiceStopped(UBYTE);
MIKMODAPI extern SLONG VC_VoiceGetPosition(UBYTE);
MIKMODAPI extern ULONG VC_VoiceRealVolume(UBYTE);
#ifdef __cplusplus
}
#endif
#endif
/* ex:set ts=4: */
@@ -0,0 +1,9 @@
#include "mikmod.h"
#if defined(WIN32) && !defined(__STDC__)
# define __STDC__ 1
#endif
#if defined(WIN32) && defined(_MSC_VER)
# pragma warning(disable: 4018 4244)
#endif
@@ -0,0 +1,712 @@
/* MikMod sound library
(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
MikMod sound library internal definitions
==============================================================================*/
#ifndef _MIKMOD_INTERNALS_H
#define _MIKMOD_INTERNALS_H
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#include <stdarg.h>
#if defined(__OS2__)||defined(__EMX__)||defined(WIN32)
#define strcasecmp(s,t) stricmp(s,t)
#endif
#include "mikmod_build.h"
#ifdef macintosh
#ifndef __MWERKS__
#define __STDC__=1
#endif
static char *strdup(const char *str)
{
char *newstr;
newstr = (char *)malloc(strlen(str)+1);
if ( newstr != NULL ) {
strcpy(newstr, str);
}
return(newstr);
}
#endif
#ifdef WIN32
#ifndef __STDC__
#define __STDC__
#endif
#pragma warning(disable:4761)
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*========== More type definitions */
/* SLONGLONG: 64bit, signed */
#if defined(__alpha)
typedef long SLONGLONG;
#define NATIVE_64BIT_INT
#elif defined(__WATCOMC__)
typedef __int64 SLONGLONG;
#elif defined(WIN32) && !defined(__MWERKS__)
typedef LONGLONG SLONGLONG;
#else
typedef long long SLONGLONG;
#endif
/*========== Error handling */
#define _mm_errno MikMod_errno
#define _mm_critical MikMod_critical
extern MikMod_handler_t _mm_errorhandler;
/*========== Memory allocation */
extern void* _mm_malloc(size_t);
extern void* _mm_calloc(size_t,size_t);
#define _mm_free(p) { if (p) free(p); p = NULL; }
/*========== MT stuff */
#ifdef HAVE_PTHREAD
#if defined(__OpenBSD__) && !defined(_POSIX_THREADS)
#define _POSIX_THREADS
#endif
#include <pthread.h>
#define DECLARE_MUTEX(name) \
extern pthread_mutex_t _mm_mutex_##name
#define MUTEX_LOCK(name) \
pthread_mutex_lock(&_mm_mutex_##name)
#define MUTEX_UNLOCK(name) \
pthread_mutex_unlock(&_mm_mutex_##name)
#elif defined(__OS2__)||defined(__EMX__)
#define DECLARE_MUTEX(name) \
extern HMTX _mm_mutex_##name
#define MUTEX_LOCK(name) \
if(_mm_mutex_##name) \
DosRequestMutexSem(_mm_mutex_##name,SEM_INDEFINITE_WAIT)
#define MUTEX_UNLOCK(name) \
if(_mm_mutex_##name) \
DosReleaseMutexSem(_mm_mutex_##name)
#elif defined(WIN32)
#include <windows.h>
#define DECLARE_MUTEX(name) \
extern HANDLE _mm_mutex_##name
#define MUTEX_LOCK(name) \
if(_mm_mutex_##name) \
WaitForSingleObject(_mm_mutex_##name,INFINITE)
#define MUTEX_UNLOCK(name) \
if(_mm_mutex_##name) \
ReleaseMutex(_mm_mutex_##name)
#else
#define DECLARE_MUTEX(name)
#define MUTEX_LOCK(name)
#define MUTEX_UNLOCK(name)
#endif
DECLARE_MUTEX(lists);
DECLARE_MUTEX(vars);
/*========== Portable file I/O */
/* SDL_RWops compatability */
#ifdef USE_RWOPS
extern MREADER *_mm_new_rwops_reader(SDL_RWops * rw);
extern void _mm_delete_rwops_reader (MREADER*);
#endif /* USE_RWOPS */
/* End SDL_RWops compatability */
extern MREADER* _mm_new_file_reader(FILE* fp);
extern void _mm_delete_file_reader(MREADER*);
extern MWRITER* _mm_new_file_writer(FILE *fp);
extern void _mm_delete_file_writer(MWRITER*);
extern BOOL _mm_FileExists(CHAR *fname);
#define _mm_write_SBYTE(x,y) y->Put(y,(int)x)
#define _mm_write_UBYTE(x,y) y->Put(y,(int)x)
#define _mm_read_SBYTE(x) (SBYTE)x->Get(x)
#define _mm_read_UBYTE(x) (UBYTE)x->Get(x)
#define _mm_write_SBYTES(x,y,z) z->Write(z,(void *)x,y)
#define _mm_write_UBYTES(x,y,z) z->Write(z,(void *)x,y)
#define _mm_read_SBYTES(x,y,z) z->Read(z,(void *)x,y)
#define _mm_read_UBYTES(x,y,z) z->Read(z,(void *)x,y)
#define _mm_fseek(x,y,z) x->Seek(x,y,z)
#define _mm_ftell(x) x->Tell(x)
#define _mm_rewind(x) _mm_fseek(x,0,SEEK_SET)
#define _mm_eof(x) x->Eof(x)
extern void _mm_iobase_setcur(MREADER*);
extern void _mm_iobase_revert(void);
extern FILE *_mm_fopen(CHAR*,CHAR*);
extern void _mm_write_string(CHAR*,MWRITER*);
extern int _mm_read_string (CHAR*,int,MREADER*);
extern SWORD _mm_read_M_SWORD(MREADER*);
extern SWORD _mm_read_I_SWORD(MREADER*);
extern UWORD _mm_read_M_UWORD(MREADER*);
extern UWORD _mm_read_I_UWORD(MREADER*);
extern SLONG _mm_read_M_SLONG(MREADER*);
extern SLONG _mm_read_I_SLONG(MREADER*);
extern ULONG _mm_read_M_ULONG(MREADER*);
extern ULONG _mm_read_I_ULONG(MREADER*);
extern int _mm_read_M_SWORDS(SWORD*,int,MREADER*);
extern int _mm_read_I_SWORDS(SWORD*,int,MREADER*);
extern int _mm_read_M_UWORDS(UWORD*,int,MREADER*);
extern int _mm_read_I_UWORDS(UWORD*,int,MREADER*);
extern int _mm_read_M_SLONGS(SLONG*,int,MREADER*);
extern int _mm_read_I_SLONGS(SLONG*,int,MREADER*);
extern int _mm_read_M_ULONGS(ULONG*,int,MREADER*);
extern int _mm_read_I_ULONGS(ULONG*,int,MREADER*);
extern void _mm_write_M_SWORD(SWORD,MWRITER*);
extern void _mm_write_I_SWORD(SWORD,MWRITER*);
extern void _mm_write_M_UWORD(UWORD,MWRITER*);
extern void _mm_write_I_UWORD(UWORD,MWRITER*);
extern void _mm_write_M_SLONG(SLONG,MWRITER*);
extern void _mm_write_I_SLONG(SLONG,MWRITER*);
extern void _mm_write_M_ULONG(ULONG,MWRITER*);
extern void _mm_write_I_ULONG(ULONG,MWRITER*);
extern void _mm_write_M_SWORDS(SWORD*,int,MWRITER*);
extern void _mm_write_I_SWORDS(SWORD*,int,MWRITER*);
extern void _mm_write_M_UWORDS(UWORD*,int,MWRITER*);
extern void _mm_write_I_UWORDS(UWORD*,int,MWRITER*);
extern void _mm_write_M_SLONGS(SLONG*,int,MWRITER*);
extern void _mm_write_I_SLONGS(SLONG*,int,MWRITER*);
extern void _mm_write_M_ULONGS(ULONG*,int,MWRITER*);
extern void _mm_write_I_ULONGS(ULONG*,int,MWRITER*);
/*========== Samples */
/* This is a handle of sorts attached to any sample registered with
SL_RegisterSample. Generally, this only need be used or changed by the
loaders and drivers of mikmod. */
typedef struct SAMPLOAD {
struct SAMPLOAD *next;
ULONG length; /* length of sample (in samples!) */
ULONG loopstart; /* repeat position (relative to start, in samples) */
ULONG loopend; /* repeat end */
UWORD infmt,outfmt;
int scalefactor;
SAMPLE* sample;
MREADER* reader;
} SAMPLOAD;
/*========== Sample and waves loading interface */
extern void SL_HalveSample(SAMPLOAD*,int);
extern void SL_Sample8to16(SAMPLOAD*);
extern void SL_Sample16to8(SAMPLOAD*);
extern void SL_SampleSigned(SAMPLOAD*);
extern void SL_SampleUnsigned(SAMPLOAD*);
extern BOOL SL_LoadSamples(void);
extern SAMPLOAD* SL_RegisterSample(SAMPLE*,int,MREADER*);
extern BOOL SL_Load(void*,SAMPLOAD*,ULONG);
extern BOOL SL_Init(SAMPLOAD*);
extern void SL_Exit(SAMPLOAD*);
/*========== Internal module representation (UniMod) interface */
/* number of notes in an octave */
#define OCTAVE 12
extern void UniSetRow(UBYTE*);
extern UBYTE UniGetByte(void);
extern UWORD UniGetWord(void);
extern UBYTE* UniFindRow(UBYTE*,UWORD);
extern void UniSkipOpcode(UBYTE);
extern void UniReset(void);
extern void UniWriteByte(UBYTE);
extern void UniWriteWord(UWORD);
extern void UniNewline(void);
extern UBYTE* UniDup(void);
extern BOOL UniInit(void);
extern void UniCleanup(void);
extern void UniEffect(UWORD,UWORD);
#define UniInstrument(x) UniEffect(UNI_INSTRUMENT,x)
#define UniNote(x) UniEffect(UNI_NOTE,x)
extern void UniPTEffect(UBYTE,UBYTE);
extern void UniVolEffect(UWORD,UBYTE);
/*========== Module Commands */
enum {
/* Simple note */
UNI_NOTE = 1,
/* Instrument change */
UNI_INSTRUMENT,
/* Protracker effects */
UNI_PTEFFECT0, /* arpeggio */
UNI_PTEFFECT1, /* porta up */
UNI_PTEFFECT2, /* porta down */
UNI_PTEFFECT3, /* porta to note */
UNI_PTEFFECT4, /* vibrato */
UNI_PTEFFECT5, /* dual effect 3+A */
UNI_PTEFFECT6, /* dual effect 4+A */
UNI_PTEFFECT7, /* tremolo */
UNI_PTEFFECT8, /* pan */
UNI_PTEFFECT9, /* sample offset */
UNI_PTEFFECTA, /* volume slide */
UNI_PTEFFECTB, /* pattern jump */
UNI_PTEFFECTC, /* set volume */
UNI_PTEFFECTD, /* pattern break */
UNI_PTEFFECTE, /* extended effects */
UNI_PTEFFECTF, /* set speed */
/* Scream Tracker effects */
UNI_S3MEFFECTA, /* set speed */
UNI_S3MEFFECTD, /* volume slide */
UNI_S3MEFFECTE, /* porta down */
UNI_S3MEFFECTF, /* porta up */
UNI_S3MEFFECTI, /* tremor */
UNI_S3MEFFECTQ, /* retrig */
UNI_S3MEFFECTR, /* tremolo */
UNI_S3MEFFECTT, /* set tempo */
UNI_S3MEFFECTU, /* fine vibrato */
UNI_KEYOFF, /* note off */
/* Fast Tracker effects */
UNI_KEYFADE, /* note fade */
UNI_VOLEFFECTS, /* volume column effects */
UNI_XMEFFECT4, /* vibrato */
UNI_XMEFFECTA, /* volume slide */
UNI_XMEFFECTE1, /* fine porta up */
UNI_XMEFFECTE2, /* fine porta down */
UNI_XMEFFECTEA, /* fine volume slide up */
UNI_XMEFFECTEB, /* fine volume slide down */
UNI_XMEFFECTG, /* set global volume */
UNI_XMEFFECTH, /* global volume slide */
UNI_XMEFFECTL, /* set envelope position */
UNI_XMEFFECTP, /* pan slide */
UNI_XMEFFECTX1, /* extra fine porta up */
UNI_XMEFFECTX2, /* extra fine porta down */
/* Impulse Tracker effects */
UNI_ITEFFECTG, /* porta to note */
UNI_ITEFFECTH, /* vibrato */
UNI_ITEFFECTI, /* tremor (xy not incremented) */
UNI_ITEFFECTM, /* set channel volume */
UNI_ITEFFECTN, /* slide / fineslide channel volume */
UNI_ITEFFECTP, /* slide / fineslide channel panning */
UNI_ITEFFECTT, /* slide tempo */
UNI_ITEFFECTU, /* fine vibrato */
UNI_ITEFFECTW, /* slide / fineslide global volume */
UNI_ITEFFECTY, /* panbrello */
UNI_ITEFFECTZ, /* resonant filters */
UNI_ITEFFECTS0,
/* UltraTracker effects */
UNI_ULTEFFECT9, /* Sample fine offset */
/* OctaMED effects */
UNI_MEDSPEED,
UNI_MEDEFFECTF1, /* play note twice */
UNI_MEDEFFECTF2, /* delay note */
UNI_MEDEFFECTF3, /* play note three times */
UNI_XMEFFECTZ, /* XM Z synchro */
UNI_LAST
};
extern UWORD unioperands[UNI_LAST];
/* IT / S3M Extended SS effects: */
enum {
SS_GLISSANDO = 1,
SS_FINETUNE,
SS_VIBWAVE,
SS_TREMWAVE,
SS_PANWAVE,
SS_FRAMEDELAY,
SS_S7EFFECTS,
SS_PANNING,
SS_SURROUND,
SS_HIOFFSET,
SS_PATLOOP,
SS_NOTECUT,
SS_NOTEDELAY,
SS_PATDELAY
};
/* IT Volume column effects */
enum {
VOL_VOLUME = 1,
VOL_PANNING,
VOL_VOLSLIDE,
VOL_PITCHSLIDEDN,
VOL_PITCHSLIDEUP,
VOL_PORTAMENTO,
VOL_VIBRATO
};
/* IT resonant filter information */
#define FILT_CUT 0x80
#define FILT_RESONANT 0x81
typedef struct FILTER {
UBYTE filter,inf;
} FILTER;
/*========== Instruments */
/* Instrument format flags */
#define IF_OWNPAN 1
#define IF_PITCHPAN 2
/* Envelope flags: */
#define EF_ON 1
#define EF_SUSTAIN 2
#define EF_LOOP 4
#define EF_VOLENV 8
/* New Note Action Flags */
#define NNA_CUT 0
#define NNA_CONTINUE 1
#define NNA_OFF 2
#define NNA_FADE 3
#define NNA_MASK 3
#define DCT_OFF 0
#define DCT_NOTE 1
#define DCT_SAMPLE 2
#define DCT_INST 3
#define DCA_CUT 0
#define DCA_OFF 1
#define DCA_FADE 2
#define KEY_KICK 0
#define KEY_OFF 1
#define KEY_FADE 2
#define KEY_KILL (KEY_OFF|KEY_FADE)
#define KICK_ABSENT 0
#define KICK_NOTE 1
#define KICK_KEYOFF 2
#define KICK_ENV 4
#define AV_IT 1 /* IT vs. XM vibrato info */
/*========== Playing */
#define POS_NONE (-2) /* no loop position defined */
typedef struct ENVPR {
UBYTE flg; /* envelope flag */
UBYTE pts; /* number of envelope points */
UBYTE susbeg; /* envelope sustain index begin */
UBYTE susend; /* envelope sustain index end */
UBYTE beg; /* envelope loop begin */
UBYTE end; /* envelope loop end */
SWORD p; /* current envelope counter */
UWORD a; /* envelope index a */
UWORD b; /* envelope index b */
ENVPT* env; /* envelope points */
} ENVPR;
typedef struct MP_CONTROL {
INSTRUMENT* i;
SAMPLE* s;
UBYTE sample; /* which sample number */
UBYTE note; /* the audible note as heard, direct rep of period */
SWORD outvolume; /* output volume (vol + sampcol + instvol) */
SBYTE chanvol; /* channel's "global" volume */
UWORD fadevol; /* fading volume rate */
SWORD panning; /* panning position */
UBYTE kick; /* if true = sample has to be restarted */
UWORD period; /* period to play the sample at */
UBYTE nna; /* New note action type + master/slave flags */
UBYTE volflg; /* volume envelope settings */
UBYTE panflg; /* panning envelope settings */
UBYTE pitflg; /* pitch envelope settings */
UBYTE keyoff; /* if true = fade out and stuff */
SWORD handle; /* which sample-handle */
UBYTE notedelay; /* (used for note delay) */
SLONG start; /* The starting byte index in the sample */
struct MP_VOICE*slave; /* Audio Slave of current effects control channel */
UBYTE slavechn; /* Audio Slave of current effects control channel */
UBYTE muted; /* if set, channel not played */
UWORD ultoffset; /* fine sample offset memory */
UBYTE anote; /* the note that indexes the audible */
UBYTE oldnote;
SWORD ownper;
SWORD ownvol;
UBYTE dca; /* duplicate check action */
UBYTE dct; /* duplicate check type */
UBYTE* row; /* row currently playing on this channel */
SBYTE retrig; /* retrig value (0 means don't retrig) */
ULONG speed; /* what finetune to use */
SWORD volume; /* amiga volume (0 t/m 64) to play the sample at */
SWORD tmpvolume; /* tmp volume */
UWORD tmpperiod; /* tmp period */
UWORD wantedperiod; /* period to slide to (with effect 3 or 5) */
UBYTE arpmem; /* arpeggio command memory */
UBYTE pansspd; /* panslide speed */
UWORD slidespeed;
UWORD portspeed; /* noteslide speed (toneportamento) */
UBYTE s3mtremor; /* s3m tremor (effect I) counter */
UBYTE s3mtronof; /* s3m tremor ontime/offtime */
UBYTE s3mvolslide; /* last used volslide */
SBYTE sliding;
UBYTE s3mrtgspeed; /* last used retrig speed */
UBYTE s3mrtgslide; /* last used retrig slide */
UBYTE glissando; /* glissando (0 means off) */
UBYTE wavecontrol;
SBYTE vibpos; /* current vibrato position */
UBYTE vibspd; /* "" speed */
UBYTE vibdepth; /* "" depth */
SBYTE trmpos; /* current tremolo position */
UBYTE trmspd; /* "" speed */
UBYTE trmdepth; /* "" depth */
UBYTE fslideupspd;
UBYTE fslidednspd;
UBYTE fportupspd; /* fx E1 (extra fine portamento up) data */
UBYTE fportdnspd; /* fx E2 (extra fine portamento dn) data */
UBYTE ffportupspd; /* fx X1 (extra fine portamento up) data */
UBYTE ffportdnspd; /* fx X2 (extra fine portamento dn) data */
ULONG hioffset; /* last used high order of sample offset */
UWORD soffset; /* last used low order of sample-offset (effect 9) */
UBYTE sseffect; /* last used Sxx effect */
UBYTE ssdata; /* last used Sxx data info */
UBYTE chanvolslide; /* last used channel volume slide */
UBYTE panbwave; /* current panbrello waveform */
UBYTE panbpos; /* current panbrello position */
SBYTE panbspd; /* "" speed */
UBYTE panbdepth; /* "" depth */
UWORD newsamp; /* set to 1 upon a sample / inst change */
UBYTE voleffect; /* Volume Column Effect Memory as used by IT */
UBYTE voldata; /* Volume Column Data Memory */
SWORD pat_reppos; /* patternloop position */
UWORD pat_repcnt; /* times to loop */
} MP_CONTROL;
/* Used by NNA only player (audio control. AUDTMP is used for full effects
control). */
typedef struct MP_VOICE {
INSTRUMENT* i;
SAMPLE* s;
UBYTE sample; /* which instrument number */
UBYTE note; /* the audible note (as heard, direct rep of period) */
SWORD volume; /* output volume (vol + sampcol + instvol) */
SBYTE chanvol; /* channel's "global" volume */
UWORD fadevol; /* fading volume rate */
SWORD panning; /* panning position */
UBYTE kick; /* if true = sample has to be restarted */
UWORD period; /* period to play the sample at */
UBYTE nna; /* New note action type + master/slave flags */
UBYTE volflg; /* volume envelope settings */
UBYTE panflg; /* panning envelope settings */
UBYTE pitflg; /* pitch envelope settings */
UBYTE keyoff; /* if true = fade out and stuff */
SWORD handle; /* which sample-handle */
SLONG start; /* The start byte index in the sample */
/* Below here is info NOT in MP_CONTROL!! */
ENVPR venv;
ENVPR penv;
ENVPR cenv;
UWORD avibpos; /* autovibrato pos */
UWORD aswppos; /* autovibrato sweep pos */
ULONG totalvol; /* total volume of channel (before global mixings) */
BOOL mflag;
SWORD masterchn;
UWORD masterperiod;
MP_CONTROL* master; /* index of "master" effects channel */
} MP_VOICE;
/*========== Loaders */
typedef struct MLOADER {
struct MLOADER* next;
CHAR* type;
CHAR* version;
BOOL (*Init)(void);
BOOL (*Test)(void);
BOOL (*Load)(BOOL);
void (*Cleanup)(void);
CHAR* (*LoadTitle)(void);
} MLOADER;
/* internal loader variables */
extern MREADER* modreader;
extern UWORD finetune[16];
extern MODULE of; /* static unimod loading space */
extern UWORD npertab[7*OCTAVE]; /* used by the original MOD loaders */
extern SBYTE remap[64]; /* for removing empty channels */
extern UBYTE* poslookup; /* lookup table for pattern jumps after
blank pattern removal */
extern UBYTE poslookupcnt;
extern UWORD* origpositions;
extern BOOL filters; /* resonant filters in use */
extern UBYTE activemacro; /* active midi macro number for Sxx */
extern UBYTE filtermacros[16]; /* midi macros settings */
extern FILTER filtersettings[256]; /* computed filter settings */
extern int* noteindex;
/*========== Internal loader interface */
extern BOOL ReadComment(UWORD);
extern BOOL ReadLinedComment(UWORD,UWORD);
extern BOOL AllocPositions(int);
extern BOOL AllocPatterns(void);
extern BOOL AllocTracks(void);
extern BOOL AllocInstruments(void);
extern BOOL AllocSamples(void);
extern CHAR* DupStr(CHAR*,UWORD,BOOL);
/* loader utility functions */
extern int* AllocLinear(void);
extern void FreeLinear(void);
extern int speed_to_finetune(ULONG,int);
extern void S3MIT_ProcessCmd(UBYTE,UBYTE,BOOL);
extern void S3MIT_CreateOrders(BOOL);
/* used to convert c4spd to linear XM periods (IT and IMF loaders). */
extern UWORD getlinearperiod(UWORD,ULONG);
extern ULONG getfrequency(UBYTE,ULONG);
/* loader shared data */
#define STM_NTRACKERS 3
extern CHAR *STM_Signatures[STM_NTRACKERS];
/*========== Player interface */
extern BOOL Player_Init(MODULE*);
extern void Player_Exit(MODULE*);
extern void Player_HandleTick(void);
/*========== Drivers */
/* max. number of handles a driver has to provide. (not strict) */
#define MAXSAMPLEHANDLES 384
/* These variables can be changed at ANY time and results will be immediate */
extern UWORD md_bpm; /* current song / hardware BPM rate */
/* Variables below can be changed via MD_SetNumVoices at any time. However, a
call to MD_SetNumVoicess while the driver is active will cause the sound to
skip slightly. */
extern UBYTE md_numchn; /* number of song + sound effects voices */
extern UBYTE md_sngchn; /* number of song voices */
extern UBYTE md_sfxchn; /* number of sound effects voices */
extern UBYTE md_hardchn; /* number of hardware mixed voices */
extern UBYTE md_softchn; /* number of software mixed voices */
/* This is for use by the hardware drivers only. It points to the registered
tickhandler function. */
extern void (*md_player)(void);
extern SWORD MD_SampleLoad(SAMPLOAD*,int);
extern void MD_SampleUnload(SWORD);
extern ULONG MD_SampleSpace(int);
extern ULONG MD_SampleLength(int,SAMPLE*);
/* uLaw conversion */
extern void unsignedtoulaw(char *,int);
/* Parameter extraction helper */
extern CHAR *MD_GetAtom(CHAR*,CHAR*,BOOL);
/* Internal software mixer stuff */
extern void VC_SetupPointers(void);
extern BOOL VC1_Init(void);
extern BOOL VC2_Init(void);
#ifdef unix
/* POSIX helper functions */
extern BOOL MD_Access(CHAR *);
extern BOOL MD_DropPrivileges(void);
#endif
/* Macro to define a missing driver, yet allowing binaries to dynamically link
with the library without missing symbol errors */
#define MISSING(a) MDRIVER a = { NULL, NULL, NULL, 0, 0 }
/*========== Prototypes for non-MT safe versions of some public functions */
extern void _mm_registerdriver(struct MDRIVER*);
extern void _mm_unregisterdrivers(void);
extern void _mm_registerloader(struct MLOADER*);
extern void _mm_unregisterloaders(void);
extern BOOL MikMod_Active_internal(void);
extern void MikMod_DisableOutput_internal(void);
extern BOOL MikMod_EnableOutput_internal(void);
extern void MikMod_Exit_internal(void);
extern BOOL MikMod_SetNumVoices_internal(int,int);
extern void Player_Exit_internal(MODULE*);
extern void Player_Stop_internal(void);
extern BOOL Player_Paused_internal(void);
extern void Sample_Free_internal(SAMPLE*);
extern void Voice_Play_internal(SBYTE,SAMPLE*,ULONG);
extern void Voice_SetFrequency_internal(SBYTE,ULONG);
extern void Voice_SetPanning_internal(SBYTE,ULONG);
extern void Voice_SetVolume_internal(SBYTE,UWORD);
extern void Voice_Stop_internal(SBYTE);
extern BOOL Voice_Stopped_internal(SBYTE);
#ifdef __cplusplus
}
#endif
#endif
/* ex:set ts=4: */
@@ -0,0 +1,564 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
These routines are used to access the available module loaders
==============================================================================*/
#ifdef SOUNDMODULE_OPENAL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
MREADER *modreader;
MODULE of;
static MLOADER *firstloader=NULL;
UWORD finetune[16]={
8363,8413,8463,8529,8581,8651,8723,8757,
7895,7941,7985,8046,8107,8169,8232,8280
};
CHAR* MikMod_InfoLoader(void)
{
int len=0;
MLOADER *l;
CHAR *list=NULL;
MUTEX_LOCK(lists);
/* compute size of buffer */
for(l=firstloader;l;l=l->next) len+=1+(l->next?1:0)+strlen(l->version);
if(len)
if((list=_mm_malloc(len*sizeof(CHAR)))) {
list[0]=0;
/* list all registered module loders */
for(l=firstloader;l;l=l->next)
sprintf(list,(l->next)?"%s%s\n":"%s%s",list,l->version);
}
MUTEX_UNLOCK(lists);
return list;
}
void _mm_registerloader(MLOADER* ldr)
{
MLOADER *cruise=firstloader;
if(cruise) {
while(cruise->next) cruise = cruise->next;
cruise->next=ldr;
} else
firstloader=ldr;
}
void _mm_unregisterloaders(void)
{
MLOADER *cruise=firstloader, *ldr;
while ( cruise ) {
ldr = cruise;
cruise = cruise->next;
ldr->next = NULL;
}
firstloader = NULL;
}
void MikMod_RegisterLoader(struct MLOADER* ldr)
{
/* if we try to register an invalid loader, or an already registered loader,
ignore this attempt */
if ((!ldr)||(ldr->next))
return;
MUTEX_LOCK(lists);
_mm_registerloader(ldr);
MUTEX_UNLOCK(lists);
}
BOOL ReadComment(UWORD len)
{
if(len) {
int i;
if(!(of.comment=(CHAR*)_mm_malloc(len+1))) return 0;
_mm_read_UBYTES(of.comment,len,modreader);
/* translate IT linefeeds */
for(i=0;i<len;i++)
if(of.comment[i]=='\r') of.comment[i]='\n';
of.comment[len]=0; /* just in case */
}
if(!of.comment[0]) {
free(of.comment);
of.comment=NULL;
}
return 1;
}
BOOL ReadLinedComment(UWORD lines,UWORD linelen)
{
CHAR *tempcomment,*line,*storage;
UWORD total=0,t,len=lines*linelen;
int i;
if (lines) {
if(!(tempcomment=(CHAR*)_mm_malloc(len+1))) return 0;
if(!(storage=(CHAR*)_mm_malloc(linelen+1))) {
free(tempcomment);
return 0;
}
_mm_read_UBYTES(tempcomment,len,modreader);
/* compute message length */
for(line=tempcomment,total=t=0;t<lines;t++,line+=linelen) {
for(i=linelen;(i>=0)&&(line[i]==' ');i--) line[i]=0;
for(i=0;i<linelen;i++) if (!line[i]) break;
total+=1+i;
}
if(total>lines) {
if(!(of.comment=(CHAR*)_mm_malloc(total+1))) {
free(storage);
free(tempcomment);
return 0;
}
/* convert message */
for(line=tempcomment,t=0;t<lines;t++,line+=linelen) {
for(i=0;i<linelen;i++) if(!(storage[i]=line[i])) break;
storage[i]=0; /* if (i==linelen) */
strcat(of.comment,storage);strcat(of.comment,"\r");
}
free(storage);
free(tempcomment);
}
}
return 1;
}
BOOL AllocPositions(int total)
{
if(!total) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
if(!(of.positions=_mm_calloc(total,sizeof(UWORD)))) return 0;
return 1;
}
BOOL AllocPatterns(void)
{
int s,t,tracks = 0;
if((!of.numpat)||(!of.numchn)) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
/* Allocate track sequencing array */
if(!(of.patterns=(UWORD*)_mm_calloc((ULONG)(of.numpat+1)*of.numchn,sizeof(UWORD)))) return 0;
if(!(of.pattrows=(UWORD*)_mm_calloc(of.numpat+1,sizeof(UWORD)))) return 0;
for(t=0;t<=of.numpat;t++) {
of.pattrows[t]=64;
for(s=0;s<of.numchn;s++)
of.patterns[(t*of.numchn)+s]=tracks++;
}
return 1;
}
BOOL AllocTracks(void)
{
if(!of.numtrk) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
if(!(of.tracks=(UBYTE **)_mm_calloc(of.numtrk,sizeof(UBYTE *)))) return 0;
return 1;
}
BOOL AllocInstruments(void)
{
int t,n;
if(!of.numins) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
if(!(of.instruments=(INSTRUMENT*)_mm_calloc(of.numins,sizeof(INSTRUMENT))))
return 0;
for(t=0;t<of.numins;t++) {
for(n=0;n<INSTNOTES;n++) {
/* Init note / sample lookup table */
of.instruments[t].samplenote[n] = n;
of.instruments[t].samplenumber[n] = t;
}
of.instruments[t].globvol = 64;
}
return 1;
}
BOOL AllocSamples(void)
{
UWORD u;
if(!of.numsmp) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
if(!(of.samples=(SAMPLE*)_mm_calloc(of.numsmp,sizeof(SAMPLE)))) return 0;
for(u=0;u<of.numsmp;u++) {
of.samples[u].panning = 128; /* center */
of.samples[u].handle = -1;
of.samples[u].globvol = 64;
of.samples[u].volume = 64;
}
return 1;
}
static BOOL ML_LoadSamples(void)
{
SAMPLE *s;
int u;
for(u=of.numsmp,s=of.samples;u;u--,s++)
if(s->length) SL_RegisterSample(s,MD_MUSIC,modreader);
return 1;
}
/* Creates a CSTR out of a character buffer of 'len' bytes, but strips any
terminating non-printing characters like 0, spaces etc. */
CHAR *DupStr(CHAR* s,UWORD len,BOOL strict)
{
UWORD t;
CHAR *d=NULL;
/* Scan for last printing char in buffer [includes high ascii up to 254] */
while(len) {
if(s[len-1]>0x20) break;
len--;
}
/* Scan forward for possible NULL character */
if(strict) {
for(t=0;t<len;t++) if (!s[t]) break;
if (t<len) len=t;
}
/* When the buffer wasn't completely empty, allocate a cstring and copy the
buffer into that string, except for any control-chars */
if((d=(CHAR*)_mm_malloc(sizeof(CHAR)*(len+1)))) {
for(t=0;t<len;t++) d[t]=(s[t]<32)?'.':s[t];
d[len]=0;
}
return d;
}
static void ML_XFreeSample(SAMPLE *s)
{
if(s->handle>=0)
MD_SampleUnload(s->handle);
if(s->samplename) free(s->samplename);
}
static void ML_XFreeInstrument(INSTRUMENT *i)
{
if(i->insname) free(i->insname);
}
static void ML_FreeEx(MODULE *mf)
{
UWORD t;
if(mf->songname) free(mf->songname);
if(mf->comment) free(mf->comment);
if(mf->modtype) free(mf->modtype);
if(mf->positions) free(mf->positions);
if(mf->patterns) free(mf->patterns);
if(mf->pattrows) free(mf->pattrows);
if(mf->tracks) {
for(t=0;t<mf->numtrk;t++)
if(mf->tracks[t]) free(mf->tracks[t]);
free(mf->tracks);
}
if(mf->instruments) {
for(t=0;t<mf->numins;t++)
ML_XFreeInstrument(&mf->instruments[t]);
free(mf->instruments);
}
if(mf->samples) {
for(t=0;t<mf->numsmp;t++)
if(mf->samples[t].length) ML_XFreeSample(&mf->samples[t]);
free(mf->samples);
}
memset(mf,0,sizeof(MODULE));
if(mf!=&of) free(mf);
}
static MODULE *ML_AllocUniMod(void)
{
MODULE *mf;
return (mf=_mm_malloc(sizeof(MODULE)));
}
void Player_Free_internal(MODULE *mf)
{
if(mf) {
Player_Exit_internal(mf);
ML_FreeEx(mf);
}
}
void Player_Free(MODULE *mf)
{
MUTEX_LOCK(vars);
Player_Free_internal(mf);
MUTEX_UNLOCK(vars);
}
static CHAR* Player_LoadTitle_internal(MREADER *reader)
{
MLOADER *l;
modreader=reader;
_mm_errno = 0;
_mm_critical = 0;
_mm_iobase_setcur(modreader);
/* Try to find a loader that recognizes the module */
for(l=firstloader;l;l=l->next) {
_mm_rewind(modreader);
if(l->Test()) break;
}
if(!l) {
_mm_errno = MMERR_NOT_A_MODULE;
if(_mm_errorhandler) _mm_errorhandler();
return NULL;
}
return l->LoadTitle();
}
CHAR* Player_LoadTitle(CHAR* filename)
{
CHAR* result=NULL;
FILE* fp;
MREADER* reader;
if((fp=_mm_fopen(filename,"rb"))) {
if((reader=_mm_new_file_reader(fp))) {
MUTEX_LOCK(lists);
result=Player_LoadTitle_internal(reader);
MUTEX_UNLOCK(lists);
_mm_delete_file_reader(reader);
}
fclose(fp);
}
return result;
}
/* Loads a module given an reader */
MODULE* Player_LoadGeneric_internal(MREADER *reader,int maxchan,BOOL curious)
{
int t;
MLOADER *l;
BOOL ok;
MODULE *mf;
modreader = reader;
_mm_errno = 0;
_mm_critical = 0;
_mm_iobase_setcur(modreader);
/* Try to find a loader that recognizes the module */
for(l=firstloader;l;l=l->next) {
_mm_rewind(modreader);
if(l->Test()) break;
}
if(!l) {
_mm_errno = MMERR_NOT_A_MODULE;
if(_mm_errorhandler) _mm_errorhandler();
_mm_rewind(modreader);_mm_iobase_revert();
return NULL;
}
/* init unitrk routines */
if(!UniInit()) {
if(_mm_errorhandler) _mm_errorhandler();
_mm_rewind(modreader);_mm_iobase_revert();
return NULL;
}
/* load the song using the song's loader variable */
memset(&of,0,sizeof(MODULE));
of.initvolume = 128;
/* init panning array */
for(t=0; t<64; t++) of.panning[t] = ((t+1)&2) ? 255 : 0;
for(t=0; t<64; t++) of.chanvol[t] = 64;
/* init module loader and load the header / patterns */
if(l->Init()) {
_mm_rewind(modreader);
ok = l->Load(curious);
} else
ok = 0;
/* free loader and unitrk allocations */
l->Cleanup();
UniCleanup();
if(!ok) {
ML_FreeEx(&of);
if(_mm_errorhandler) _mm_errorhandler();
_mm_rewind(modreader);_mm_iobase_revert();
return NULL;
}
if(!ML_LoadSamples()) {
ML_FreeEx(&of);
if(_mm_errorhandler) _mm_errorhandler();
_mm_rewind(modreader);_mm_iobase_revert();
return NULL;
}
if(!(mf=ML_AllocUniMod())) {
ML_FreeEx(&of);
_mm_rewind(modreader);_mm_iobase_revert();
if(_mm_errorhandler) _mm_errorhandler();
return NULL;
}
/* Copy the static MODULE contents into the dynamic MODULE struct. */
memcpy(mf,&of,sizeof(MODULE));
_mm_iobase_revert();
if(maxchan>0) {
if(!(mf->flags&UF_NNA)&&(mf->numchn<maxchan))
maxchan = mf->numchn;
else
if((mf->numvoices)&&(mf->numvoices<maxchan))
maxchan = mf->numvoices;
if(maxchan<mf->numchn) mf->flags |= UF_NNA;
if(MikMod_SetNumVoices_internal(maxchan,-1)) {
Player_Free(mf);
return NULL;
}
}
if(SL_LoadSamples()) {
Player_Free_internal(mf);
return NULL;
}
if(Player_Init(mf)) {
Player_Free_internal(mf);
mf=NULL;
}
return mf;
}
MODULE* Player_LoadGeneric(MREADER *reader,int maxchan,BOOL curious)
{
MODULE* result;
MUTEX_LOCK(vars);
MUTEX_LOCK(lists);
result=Player_LoadGeneric_internal(reader,maxchan,curious);
MUTEX_UNLOCK(lists);
MUTEX_UNLOCK(vars);
return result;
}
/* Loads a module given a file pointer.
File is loaded from the current file seek position. */
MODULE* Player_LoadFP(FILE* fp,int maxchan,BOOL curious)
{
MODULE* result=NULL;
struct MREADER* reader=_mm_new_file_reader (fp);
if (reader) {
result=Player_LoadGeneric(reader,maxchan,curious);
_mm_delete_file_reader(reader);
}
return result;
}
/* Open a module via its filename. The loader will initialize the specified
song-player 'player'. */
MODULE* Player_Load(CHAR* filename,int maxchan,BOOL curious)
{
FILE *fp;
MODULE *mf=NULL;
if((fp=_mm_fopen(filename,"rb"))) {
mf=Player_LoadFP(fp,maxchan,curious);
fclose(fp);
}
return mf;
}
/* SDL_RWops compatability */
#ifdef USE_RWOPS
/* Open a module via an SDL_rwop. The loader will initialize the specified
song-player 'player'. */
MODULE* Player_LoadRW(SDL_RWops *rw,int maxchan,BOOL curious)
{
MODULE* result=NULL;
struct MREADER* reader=_mm_new_rwops_reader (rw);
if (reader) {
result=Player_LoadGeneric(reader,maxchan,curious);
_mm_delete_rwops_reader(reader);
}
return result;
}
#endif /* USE_RWOPS */
/* End SDL_RWops compatability */
/* ex:set ts=4: */
#endif
@@ -0,0 +1,58 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
Routine for registering all loaders in libmikmod for the current platform.
==============================================================================*/
#ifdef SOUNDMODULE_OPENAL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
void MikMod_RegisterAllLoaders_internal(void)
{
_mm_registerloader(&load_mod);
}
void MikMod_RegisterAllLoaders(void)
{
MUTEX_LOCK(lists);
MikMod_RegisterAllLoaders_internal();
MUTEX_UNLOCK(lists);
}
void MikMod_UnregisterAllLoaders(void)
{
MUTEX_LOCK(lists);
_mm_unregisterloaders();
MUTEX_UNLOCK(lists);
}
/* ex:set ts=4: */
#endif
@@ -0,0 +1,309 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
Utility functions for the module loader
==============================================================================*/
#ifdef SOUNDMODULE_OPENAL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
SBYTE remap[64]; /* for removing empty channels */
UBYTE* poslookup=NULL; /* lookup table for pattern jumps after blank
pattern removal */
UBYTE poslookupcnt;
UWORD* origpositions=NULL;
BOOL filters; /* resonant filters in use */
UBYTE activemacro; /* active midi macro number for Sxx,xx<80h */
UBYTE filtermacros[16]; /* midi macros settings */
FILTER filtersettings[256]; /* computed filter settings */
/*========== Linear periods stuff */
int* noteindex=NULL; /* remap value for linear period modules */
static int noteindexcount=0;
int *AllocLinear(void)
{
if(of.numsmp>noteindexcount) {
noteindexcount=of.numsmp;
noteindex=realloc(noteindex,noteindexcount*sizeof(int));
}
return noteindex;
}
void FreeLinear(void)
{
if(noteindex) {
free(noteindex);
noteindex=NULL;
}
noteindexcount=0;
}
int speed_to_finetune(ULONG speed,int sample)
{
int ctmp=0,tmp,note=1,finetune=0;
speed>>=1;
while((tmp=getfrequency(of.flags,getlinearperiod(note<<1,0)))<speed) {
ctmp=tmp;
note++;
}
if(tmp!=(int)speed) {
if((tmp-speed)<(speed-ctmp))
while(tmp>speed)
tmp=getfrequency(of.flags,getlinearperiod(note<<1,--finetune));
else {
note--;
while(ctmp<speed)
ctmp=getfrequency(of.flags,getlinearperiod(note<<1,++finetune));
}
}
noteindex[sample]=note-4*OCTAVE;
return finetune;
}
/*========== Order stuff */
/* handles S3M and IT orders */
void S3MIT_CreateOrders(BOOL curious)
{
int t;
of.numpos = 0;
memset(of.positions,0,poslookupcnt*sizeof(UWORD));
memset(poslookup,-1,256);
for(t=0;t<poslookupcnt;t++) {
of.positions[of.numpos]=origpositions[t];
poslookup[t]=of.numpos; /* bug fix for freaky S3Ms / ITs */
if(origpositions[t]<254) of.numpos++;
else
/* end of song special order */
if((of.positions[t]==255)&&(!(curious--))) break;
}
}
/*========== Effect stuff */
/* handles S3M and IT effects */
void S3MIT_ProcessCmd(UBYTE cmd,UBYTE inf,BOOL oldeffect)
{
UBYTE hi,lo;
lo=inf&0xf;
hi=inf>>4;
/* process S3M / IT specific command structure */
if(cmd!=255) {
switch(cmd) {
case 1: /* Axx set speed to xx */
UniEffect(UNI_S3MEFFECTA,inf);
break;
case 2: /* Bxx position jump */
if (inf<poslookupcnt) {
/* switch to curious mode if necessary, for example
sympex.it, deep joy.it */
if(((SBYTE)poslookup[inf]<0)&&(origpositions[inf]!=255))
S3MIT_CreateOrders(1);
if(!((SBYTE)poslookup[inf]<0))
UniPTEffect(0xb,poslookup[inf]);
}
break;
case 3: /* Cxx patternbreak to row xx */
if(oldeffect==1)
UniPTEffect(0xd,(inf>>4)*10+(inf&0xf));
else
UniPTEffect(0xd,inf);
break;
case 4: /* Dxy volumeslide */
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 5: /* Exy toneslide down */
UniEffect(UNI_S3MEFFECTE,inf);
break;
case 6: /* Fxy toneslide up */
UniEffect(UNI_S3MEFFECTF,inf);
break;
case 7: /* Gxx Tone portamento, speed xx */
UniEffect(UNI_ITEFFECTG,inf);
break;
case 8: /* Hxy vibrato */
if(oldeffect&1)
UniPTEffect(0x4,inf);
else
UniEffect(UNI_ITEFFECTH,inf);
break;
case 9: /* Ixy tremor, ontime x, offtime y */
if(oldeffect&1)
UniEffect(UNI_S3MEFFECTI,inf);
else
UniEffect(UNI_ITEFFECTI,inf);
break;
case 0xa: /* Jxy arpeggio */
UniPTEffect(0x0,inf);
break;
case 0xb: /* Kxy Dual command H00 & Dxy */
if(oldeffect&1)
UniPTEffect(0x4,0);
else
UniEffect(UNI_ITEFFECTH,0);
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 0xc: /* Lxy Dual command G00 & Dxy */
if(oldeffect&1)
UniPTEffect(0x3,0);
else
UniEffect(UNI_ITEFFECTG,0);
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 0xd: /* Mxx Set Channel Volume */
UniEffect(UNI_ITEFFECTM,inf);
break;
case 0xe: /* Nxy Slide Channel Volume */
UniEffect(UNI_ITEFFECTN,inf);
break;
case 0xf: /* Oxx set sampleoffset xx00h */
UniPTEffect(0x9,inf);
break;
case 0x10: /* Pxy Slide Panning Commands */
UniEffect(UNI_ITEFFECTP,inf);
break;
case 0x11: /* Qxy Retrig (+volumeslide) */
UniWriteByte(UNI_S3MEFFECTQ);
if(inf && !lo && !(oldeffect&1))
UniWriteByte(1);
else
UniWriteByte(inf);
break;
case 0x12: /* Rxy tremolo speed x, depth y */
UniEffect(UNI_S3MEFFECTR,inf);
break;
case 0x13: /* Sxx special commands */
if (inf>=0xf0) {
/* change resonant filter settings if necessary */
if((filters)&&((inf&0xf)!=activemacro)) {
activemacro=inf&0xf;
for(inf=0;inf<0x80;inf++)
filtersettings[inf].filter=filtermacros[activemacro];
}
} else
UniEffect(UNI_ITEFFECTS0,inf);
break;
case 0x14: /* Txx tempo */
if(inf>=0x20)
UniEffect(UNI_S3MEFFECTT,inf);
else {
if(!(oldeffect&1))
/* IT Tempo slide */
UniEffect(UNI_ITEFFECTT,inf);
}
break;
case 0x15: /* Uxy Fine Vibrato speed x, depth y */
if(oldeffect&1)
UniEffect(UNI_S3MEFFECTU,inf);
else
UniEffect(UNI_ITEFFECTU,inf);
break;
case 0x16: /* Vxx Set Global Volume */
UniEffect(UNI_XMEFFECTG,inf);
break;
case 0x17: /* Wxy Global Volume Slide */
UniEffect(UNI_ITEFFECTW,inf);
break;
case 0x18: /* Xxx amiga command 8xx */
if(oldeffect&1) {
if(inf>128)
UniEffect(UNI_ITEFFECTS0,0x91); /* surround */
else
UniPTEffect(0x8,(inf==128)?255:(inf<<1));
} else
UniPTEffect(0x8,inf);
break;
case 0x19: /* Yxy Panbrello speed x, depth y */
UniEffect(UNI_ITEFFECTY,inf);
break;
case 0x1a: /* Zxx midi/resonant filters */
if(filtersettings[inf].filter) {
UniWriteByte(UNI_ITEFFECTZ);
UniWriteByte(filtersettings[inf].filter);
UniWriteByte(filtersettings[inf].inf);
}
break;
}
}
}
/*========== Unitrk stuff */
/* Generic effect writing routine */
void UniEffect(UWORD eff,UWORD dat)
{
if((!eff)||(eff>=UNI_LAST)) return;
UniWriteByte(eff);
if(unioperands[eff]==2)
UniWriteWord(dat);
else
UniWriteByte(dat);
}
/* Appends UNI_PTEFFECTX opcode to the unitrk stream. */
void UniPTEffect(UBYTE eff, UBYTE dat)
{
#ifdef MIKMOD_DEBUG
if (eff>=0x10)
fprintf(stderr,"UniPTEffect called with incorrect eff value %d\n",eff);
else
#endif
if((eff)||(dat)) UniEffect(UNI_PTEFFECT0+eff,dat);
}
/* Appends UNI_VOLEFFECT + effect/dat to unistream. */
void UniVolEffect(UWORD eff,UBYTE dat)
{
if((eff)||(dat)) { /* don't write empty effect */
UniWriteByte(UNI_VOLEFFECTS);
UniWriteByte(eff);UniWriteByte(dat);
}
}
/* ex:set ts=4: */
#endif
@@ -0,0 +1,63 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
Dynamic memory routines
==============================================================================*/
#ifdef SOUNDMODULE_OPENAL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
/* Same as malloc, but sets error variable _mm_error when fails */
void* _mm_malloc(size_t size)
{
void *d;
if(!(d=calloc(1,size))) {
_mm_errno = MMERR_OUT_OF_MEMORY;
if(_mm_errorhandler) _mm_errorhandler();
}
return d;
}
/* Same as calloc, but sets error variable _mm_error when fails */
void* _mm_calloc(size_t nitems,size_t size)
{
void *d;
if(!(d=calloc(nitems,size))) {
_mm_errno = MMERR_OUT_OF_MEMORY;
if(_mm_errorhandler) _mm_errorhandler();
}
return d;
}
/* ex:set ts=4: */
#endif
@@ -0,0 +1,201 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
Error handling functions.
Register an error handler with _mm_RegisterErrorHandler() and you're all set.
==============================================================================*/
/*
The global variables _mm_errno, and _mm_critical are set before the error
handler in called. See below for the values of these variables.
*/
#ifdef SOUNDMODULE_OPENAL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
CHAR *_mm_errmsg[MMERR_MAX+1] =
{
/* No error */
"No error",
/* Generic errors */
"Could not open requested file",
"Out of memory",
"Dynamic linking failed",
/* Sample errors */
"Out of memory to load sample",
"Out of sample handles to load sample",
"Sample format not recognized",
/* Module errors */
"Failure loading module pattern",
"Failure loading module track",
"Failure loading module header",
"Failure loading sampleinfo",
"Module format not recognized",
"Module sample format not recognized",
"Synthsounds not supported in MED files",
"Compressed sample is invalid",
/* Driver errors: */
"Sound device not detected",
"Device number out of range",
"Software mixer failure",
"Could not open sound device",
"This driver supports 8 bit linear output only",
"This driver supports 16 bit linear output only",
"This driver supports stereo output only",
"This driver supports uLaw output (8 bit mono, 8 kHz) only",
"Unable to set non-blocking mode for audio device",
/* AudioFile driver errors */
"Cannot find suitable AudioFile audio port",
/* AIX driver errors */
"Configuration (init step) of audio device failed",
"Configuration (control step) of audio device failed",
"Configuration (start step) of audio device failed",
/* ALSA driver errors */
/* EsounD driver errors */
/* Ultrasound driver errors */
"Ultrasound driver only works in 16 bit stereo 44 KHz",
"Ultrasound card could not be reset",
"Could not start Ultrasound timer",
/* HP driver errors */
"Unable to select 16bit-linear sample format",
"Could not select requested sample-rate",
"Could not select requested number of channels",
"Unable to select audio output",
"Unable to get audio description",
"Could not set transmission buffer size",
/* Open Sound System driver errors */
"Could not set fragment size",
"Could not set sample size",
"Could not set mono/stereo setting",
"Could not set sample rate",
/* SGI driver errors */
"Unsupported sample rate",
"Hardware does not support 16 bit sound",
"Hardware does not support 8 bit sound",
"Hardware does not support stereo sound",
"Hardware does not support mono sound",
/* Sun driver errors */
"Sound device initialization failed",
/* OS/2 drivers errors */
"Could not set mixing parameters",
"Could not create playback semaphores",
"Could not create playback timer",
"Could not create playback thread",
/* DirectSound driver errors */
"Could not set playback priority",
"Could not create playback buffers",
"Could not set playback format",
"Could not register callback",
"Could not register event",
"Could not create playback thread",
"Could not initialize playback thread",
/* Windows Multimedia API driver errors */
"Invalid device handle",
"The resource is already allocated",
"Invalid device identifier",
"Unsupported output format",
"Unknown error",
/* Macintosh driver errors */
"Unsupported sample rate",
"Could not start playback",
/* Invalid error */
"Invalid error code"
};
char *MikMod_strerror(int code)
{
if ((code<0)||(code>MMERR_MAX)) code=MMERR_MAX+1;
return _mm_errmsg[code];
}
/* User installed error callback */
MikMod_handler_t _mm_errorhandler = NULL;
int _mm_errno = 0;
BOOL _mm_critical = 0;
MikMod_handler_t _mm_registererrorhandler(MikMod_handler_t proc)
{
MikMod_handler_t oldproc=_mm_errorhandler;
_mm_errorhandler = proc;
return oldproc;
}
MikMod_handler_t MikMod_RegisterErrorHandler(MikMod_handler_t proc)
{
MikMod_handler_t result;
MUTEX_LOCK(vars);
result=_mm_registererrorhandler(proc);
MUTEX_UNLOCK(vars);
return result;
}
/* ex:set ts=4: */
#endif
@@ -0,0 +1,445 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
Portable file I/O routines
==============================================================================*/
/*
The way this module works:
- _mm_fopen will call the errorhandler [see mmerror.c] in addition to
setting _mm_errno on exit.
- _mm_iobase is for internal use. It is used by Player_LoadFP to
ensure that it works properly with wad files.
- _mm_read_I_* and _mm_read_M_* differ : the first is for reading data
written by a little endian (intel) machine, and the second is for reading
big endian (Mac, RISC, Alpha) machine data.
- _mm_write functions work the same as the _mm_read functions.
- _mm_read_string is for reading binary strings. It is basically the same
as an fread of bytes.
*/
/* FIXME
the _mm_iobase variable ought to be MREADER-specific. It will eventually
become a private field of the MREADER structure, but this will require a
soname version bump.
In the meantime, the drawback is that if you use the xxx_LoadFP functions,
you can't have several MREADER objects with different iobase values.
*/
#ifdef SOUNDMODULE_OPENAL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <string.h>
#include "mikmod_internals.h"
#define COPY_BUFSIZE 1024
static long _mm_iobase=0,temp_iobase=0;
/*
This section is added to use SDL_rwops for IO
-Matt Campbell (matt@campbellhome.dhs.org) April 2000
*/
#ifdef USE_RWOPS
typedef struct MRWOPSREADER {
MREADER core;
SDL_RWops* rw;
int end;
} MRWOPSREADER;
static BOOL _mm_RWopsReader_Eof(MREADER* reader)
{
if ( ((MRWOPSREADER*)reader)->end ==
SDL_RWtell(((MRWOPSREADER*)reader)->rw) ) return 1;
else return 0;
}
static BOOL _mm_RWopsReader_Read(MREADER* reader,void* ptr,size_t size)
{
return SDL_RWread(((MRWOPSREADER*)reader)->rw, ptr, size, 1);
}
static int _mm_RWopsReader_Get(MREADER* reader)
{
char buf;
if ( SDL_RWread(((MRWOPSREADER*)reader)->rw, &buf, 1, 1) != 1 ) return EOF;
else return (int)buf;
}
static BOOL _mm_RWopsReader_Seek(MREADER* reader,long offset,int whence)
{
return SDL_RWseek(((MRWOPSREADER*)reader)->rw,
(whence==SEEK_SET)?offset+_mm_iobase:offset,whence);
}
static long _mm_RWopsReader_Tell(MREADER* reader)
{
return SDL_RWtell(((MRWOPSREADER*)reader)->rw) - _mm_iobase;
}
MREADER *_mm_new_rwops_reader(SDL_RWops * rw)
{
int here;
MRWOPSREADER* reader=(MRWOPSREADER*)_mm_malloc(sizeof(MRWOPSREADER));
if (reader) {
reader->core.Eof =&_mm_RWopsReader_Eof;
reader->core.Read=&_mm_RWopsReader_Read;
reader->core.Get =&_mm_RWopsReader_Get;
reader->core.Seek=&_mm_RWopsReader_Seek;
reader->core.Tell=&_mm_RWopsReader_Tell;
reader->rw=rw;
/* RWops does not explicitly support an eof check, so we shall find
the end manually - this requires seek support for the RWop */
here = SDL_RWtell(rw);
reader->end = SDL_RWseek(rw, 0, SEEK_END);
SDL_RWseek(rw, here, SEEK_SET); /* Move back */
}
return (MREADER*)reader;
}
void _mm_delete_rwops_reader (MREADER* reader)
{
if(reader) free(reader);
}
#endif /* USE_RWOPS */
/*
End SDL_rwops section
*/
FILE* _mm_fopen(CHAR* fname,CHAR* attrib)
{
FILE *fp;
if(!(fp=fopen(fname,attrib))) {
_mm_errno = MMERR_OPENING_FILE;
if(_mm_errorhandler) _mm_errorhandler();
}
return fp;
}
BOOL _mm_FileExists(CHAR* fname)
{
FILE *fp;
if(!(fp=fopen(fname,"r"))) return 0;
fclose(fp);
return 1;
}
/* Sets the current file-position as the new _mm_iobase */
void _mm_iobase_setcur(MREADER* reader)
{
temp_iobase=_mm_iobase; /* store old value in case of revert */
_mm_iobase=reader->Tell(reader);
}
/* Reverts to the last known _mm_iobase value. */
void _mm_iobase_revert(void)
{
_mm_iobase=temp_iobase;
}
/*========== File Reader */
typedef struct MFILEREADER {
MREADER core;
FILE* file;
} MFILEREADER;
static BOOL _mm_FileReader_Eof(MREADER* reader)
{
return feof(((MFILEREADER*)reader)->file);
}
static BOOL _mm_FileReader_Read(MREADER* reader,void* ptr,size_t size)
{
return fread(ptr,size,1,((MFILEREADER*)reader)->file);
}
static int _mm_FileReader_Get(MREADER* reader)
{
return fgetc(((MFILEREADER*)reader)->file);
}
static BOOL _mm_FileReader_Seek(MREADER* reader,long offset,int whence)
{
return fseek(((MFILEREADER*)reader)->file,
(whence==SEEK_SET)?offset+_mm_iobase:offset,whence);
}
static long _mm_FileReader_Tell(MREADER* reader)
{
return ftell(((MFILEREADER*)reader)->file)-_mm_iobase;
}
MREADER *_mm_new_file_reader(FILE* fp)
{
MFILEREADER* reader=(MFILEREADER*)_mm_malloc(sizeof(MFILEREADER));
if (reader) {
reader->core.Eof =&_mm_FileReader_Eof;
reader->core.Read=&_mm_FileReader_Read;
reader->core.Get =&_mm_FileReader_Get;
reader->core.Seek=&_mm_FileReader_Seek;
reader->core.Tell=&_mm_FileReader_Tell;
reader->file=fp;
}
return (MREADER*)reader;
}
void _mm_delete_file_reader (MREADER* reader)
{
if(reader) free(reader);
}
/*========== File Writer */
typedef struct MFILEWRITER {
MWRITER core;
FILE* file;
} MFILEWRITER;
static BOOL _mm_FileWriter_Seek(MWRITER* writer,long offset,int whence)
{
return fseek(((MFILEWRITER*)writer)->file,offset,whence);
}
static long _mm_FileWriter_Tell(MWRITER* writer)
{
return ftell(((MFILEWRITER*)writer)->file);
}
static BOOL _mm_FileWriter_Write(MWRITER* writer,void* ptr,size_t size)
{
return (fwrite(ptr,size,1,((MFILEWRITER*)writer)->file)==size);
}
static BOOL _mm_FileWriter_Put(MWRITER* writer,int value)
{
return fputc(value,((MFILEWRITER*)writer)->file);
}
MWRITER *_mm_new_file_writer(FILE* fp)
{
MFILEWRITER* writer=(MFILEWRITER*)_mm_malloc(sizeof(MFILEWRITER));
if (writer) {
writer->core.Seek =&_mm_FileWriter_Seek;
writer->core.Tell =&_mm_FileWriter_Tell;
writer->core.Write=&_mm_FileWriter_Write;
writer->core.Put =&_mm_FileWriter_Put;
writer->file=fp;
}
return (MWRITER*) writer;
}
void _mm_delete_file_writer (MWRITER* writer)
{
if(writer) free (writer);
}
/*========== Write functions */
void _mm_write_string(CHAR* data,MWRITER* writer)
{
if(data)
_mm_write_UBYTES(data,strlen(data),writer);
}
void _mm_write_M_UWORD(UWORD data,MWRITER* writer)
{
_mm_write_UBYTE(data>>8,writer);
_mm_write_UBYTE(data&0xff,writer);
}
void _mm_write_I_UWORD(UWORD data,MWRITER* writer)
{
_mm_write_UBYTE(data&0xff,writer);
_mm_write_UBYTE(data>>8,writer);
}
void _mm_write_M_ULONG(ULONG data,MWRITER* writer)
{
_mm_write_M_UWORD(data>>16,writer);
_mm_write_M_UWORD(data&0xffff,writer);
}
void _mm_write_I_ULONG(ULONG data,MWRITER* writer)
{
_mm_write_I_UWORD(data&0xffff,writer);
_mm_write_I_UWORD(data>>16,writer);
}
void _mm_write_M_SWORD(SWORD data,MWRITER* writer)
{
_mm_write_M_UWORD((UWORD)data,writer);
}
void _mm_write_I_SWORD(SWORD data,MWRITER* writer)
{
_mm_write_I_UWORD((UWORD)data,writer);
}
void _mm_write_M_SLONG(SLONG data,MWRITER* writer)
{
_mm_write_M_ULONG((ULONG)data,writer);
}
void _mm_write_I_SLONG(SLONG data,MWRITER* writer)
{
_mm_write_I_ULONG((ULONG)data,writer);
}
#ifdef __STDC__
#define DEFINE_MULTIPLE_WRITE_FUNCTION(type_name,type) \
void _mm_write_##type_name##S (type *buffer,int number,MWRITER* writer) \
{ \
while(number-->0) \
_mm_write_##type_name(*(buffer++),writer); \
}
#else
#define DEFINE_MULTIPLE_WRITE_FUNCTION(type_name,type) \
void _mm_write_/**/type_name/**/S (type *buffer,int number,MWRITER* writer) \
{ \
while(number-->0) \
_mm_write_/**/type_name(*(buffer++),writer); \
}
#endif
DEFINE_MULTIPLE_WRITE_FUNCTION(M_SWORD,SWORD)
DEFINE_MULTIPLE_WRITE_FUNCTION(M_UWORD,UWORD)
DEFINE_MULTIPLE_WRITE_FUNCTION(I_SWORD,SWORD)
DEFINE_MULTIPLE_WRITE_FUNCTION(I_UWORD,UWORD)
DEFINE_MULTIPLE_WRITE_FUNCTION(M_SLONG,SLONG)
DEFINE_MULTIPLE_WRITE_FUNCTION(M_ULONG,ULONG)
DEFINE_MULTIPLE_WRITE_FUNCTION(I_SLONG,SLONG)
DEFINE_MULTIPLE_WRITE_FUNCTION(I_ULONG,ULONG)
/*========== Read functions */
int _mm_read_string(CHAR* buffer,int number,MREADER* reader)
{
return reader->Read(reader,buffer,number);
}
UWORD _mm_read_M_UWORD(MREADER* reader)
{
UWORD result=((UWORD)_mm_read_UBYTE(reader))<<8;
result|=_mm_read_UBYTE(reader);
return result;
}
UWORD _mm_read_I_UWORD(MREADER* reader)
{
UWORD result=_mm_read_UBYTE(reader);
result|=((UWORD)_mm_read_UBYTE(reader))<<8;
return result;
}
ULONG _mm_read_M_ULONG(MREADER* reader)
{
ULONG result=((ULONG)_mm_read_M_UWORD(reader))<<16;
result|=_mm_read_M_UWORD(reader);
return result;
}
ULONG _mm_read_I_ULONG(MREADER* reader)
{
ULONG result=_mm_read_I_UWORD(reader);
result|=((ULONG)_mm_read_I_UWORD(reader))<<16;
return result;
}
SWORD _mm_read_M_SWORD(MREADER* reader)
{
return((SWORD)_mm_read_M_UWORD(reader));
}
SWORD _mm_read_I_SWORD(MREADER* reader)
{
return((SWORD)_mm_read_I_UWORD(reader));
}
SLONG _mm_read_M_SLONG(MREADER* reader)
{
return((SLONG)_mm_read_M_ULONG(reader));
}
SLONG _mm_read_I_SLONG(MREADER* reader)
{
return((SLONG)_mm_read_I_ULONG(reader));
}
#ifdef __STDC__
#define DEFINE_MULTIPLE_READ_FUNCTION(type_name,type) \
int _mm_read_##type_name##S (type *buffer,int number,MREADER* reader) \
{ \
while(number-->0) \
*(buffer++)=_mm_read_##type_name(reader); \
return !reader->Eof(reader); \
}
#else
#define DEFINE_MULTIPLE_READ_FUNCTION(type_name,type) \
int _mm_read_/**/type_name/**/S (type *buffer,int number,MREADER* reader) \
{ \
while(number-->0) \
*(buffer++)=_mm_read_/**/type_name(reader); \
return !reader->Eof(reader); \
}
#endif
DEFINE_MULTIPLE_READ_FUNCTION(M_SWORD,SWORD)
DEFINE_MULTIPLE_READ_FUNCTION(M_UWORD,UWORD)
DEFINE_MULTIPLE_READ_FUNCTION(I_SWORD,SWORD)
DEFINE_MULTIPLE_READ_FUNCTION(I_UWORD,UWORD)
DEFINE_MULTIPLE_READ_FUNCTION(M_SLONG,SLONG)
DEFINE_MULTIPLE_READ_FUNCTION(M_ULONG,ULONG)
DEFINE_MULTIPLE_READ_FUNCTION(I_SLONG,SLONG)
DEFINE_MULTIPLE_READ_FUNCTION(I_ULONG,ULONG)
/* ex:set ts=4: */
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,305 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
All routines dealing with the manipulation of UNITRK streams
==============================================================================*/
#ifdef SOUNDMODULE_OPENAL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "mikmod_internals.h"
/* Unibuffer chunk size */
#define BUFPAGE 128
UWORD unioperands[UNI_LAST]={
0, /* not used */
1, /* UNI_NOTE */
1, /* UNI_INSTRUMENT */
1, /* UNI_PTEFFECT0 */
1, /* UNI_PTEFFECT1 */
1, /* UNI_PTEFFECT2 */
1, /* UNI_PTEFFECT3 */
1, /* UNI_PTEFFECT4 */
1, /* UNI_PTEFFECT5 */
1, /* UNI_PTEFFECT6 */
1, /* UNI_PTEFFECT7 */
1, /* UNI_PTEFFECT8 */
1, /* UNI_PTEFFECT9 */
1, /* UNI_PTEFFECTA */
1, /* UNI_PTEFFECTB */
1, /* UNI_PTEFFECTC */
1, /* UNI_PTEFFECTD */
1, /* UNI_PTEFFECTE */
1, /* UNI_PTEFFECTF */
1, /* UNI_S3MEFFECTA */
1, /* UNI_S3MEFFECTD */
1, /* UNI_S3MEFFECTE */
1, /* UNI_S3MEFFECTF */
1, /* UNI_S3MEFFECTI */
1, /* UNI_S3MEFFECTQ */
1, /* UNI_S3MEFFECTR */
1, /* UNI_S3MEFFECTT */
1, /* UNI_S3MEFFECTU */
0, /* UNI_KEYOFF */
1, /* UNI_KEYFADE */
2, /* UNI_VOLEFFECTS */
1, /* UNI_XMEFFECT4 */
1, /* UNI_XMEFFECTA */
1, /* UNI_XMEFFECTE1 */
1, /* UNI_XMEFFECTE2 */
1, /* UNI_XMEFFECTEA */
1, /* UNI_XMEFFECTEB */
1, /* UNI_XMEFFECTG */
1, /* UNI_XMEFFECTH */
1, /* UNI_XMEFFECTL */
1, /* UNI_XMEFFECTP */
1, /* UNI_XMEFFECTX1 */
1, /* UNI_XMEFFECTX2 */
1, /* UNI_ITEFFECTG */
1, /* UNI_ITEFFECTH */
1, /* UNI_ITEFFECTI */
1, /* UNI_ITEFFECTM */
1, /* UNI_ITEFFECTN */
1, /* UNI_ITEFFECTP */
1, /* UNI_ITEFFECTT */
1, /* UNI_ITEFFECTU */
1, /* UNI_ITEFFECTW */
1, /* UNI_ITEFFECTY */
2, /* UNI_ITEFFECTZ */
1, /* UNI_ITEFFECTS0 */
2, /* UNI_ULTEFFECT9 */
2, /* UNI_MEDSPEED */
0, /* UNI_MEDEFFECTF1 */
0, /* UNI_MEDEFFECTF2 */
0, /* UNI_MEDEFFECTF3 */
1 /* UNI_XMEFFECTZ */
};
/* Sparse description of the internal module format
------------------------------------------------
A UNITRK stream is an array of bytes representing a single track of a pattern.
It's made up of 'repeat/length' bytes, opcodes and operands (sort of a assembly
language):
rrrlllll
[REP/LEN][OPCODE][OPERAND][OPCODE][OPERAND] [REP/LEN][OPCODE][OPERAND]..
^ ^ ^
|-------ROWS 0 - 0+REP of a track---------| |-------ROWS xx - xx+REP of a track...
The rep/len byte contains the number of bytes in the current row, _including_
the length byte itself (So the LENGTH byte of row 0 in the previous example
would have a value of 5). This makes it easy to search through a stream for a
particular row. A track is concluded by a 0-value length byte.
The upper 3 bits of the rep/len byte contain the number of times -1 this row
is repeated for this track. (so a value of 7 means this row is repeated 8 times)
Opcodes can range from 1 to 255 but currently only opcodes 1 to 52 are being
used. Each opcode can have a different number of operands. You can find the
number of operands to a particular opcode by using the opcode as an index into
the 'unioperands' table.
*/
/*========== Reading routines */
static UBYTE *rowstart; /* startadress of a row */
static UBYTE *rowend; /* endaddress of a row (exclusive) */
static UBYTE *rowpc; /* current unimod(tm) programcounter */
void UniSetRow(UBYTE* t)
{
rowstart = t;
rowpc = rowstart;
rowend = t?rowstart+(*(rowpc++)&0x1f):t;
}
UBYTE UniGetByte(void)
{
return (rowpc<rowend)?*(rowpc++):0;
}
UWORD UniGetWord(void)
{
return ((UWORD)UniGetByte()<<8)|UniGetByte();
}
void UniSkipOpcode(UBYTE op)
{
if(op<UNI_LAST) {
UWORD t=unioperands[op];
while(t--) UniGetByte();
}
}
/* Finds the address of row number 'row' in the UniMod(tm) stream 't' returns
NULL if the row can't be found. */
UBYTE *UniFindRow(UBYTE* t,UWORD row)
{
UBYTE c,l;
if(t)
while(1) {
c = *t; /* get rep/len byte */
if(!c) return NULL; /* zero ? -> end of track.. */
l = (c>>5)+1; /* extract repeat value */
if(l>row) break; /* reached wanted row? -> return pointer */
row -= l; /* haven't reached row yet.. update row */
t += c&0x1f; /* point t to the next row */
}
return t;
}
/*========== Writing routines */
static UBYTE *unibuf; /* pointer to the temporary unitrk buffer */
static UWORD unimax; /* buffer size */
static UWORD unipc; /* buffer cursor */
static UWORD unitt; /* current row index */
static UWORD lastp; /* previous row index */
/* Resets index-pointers to create a new track. */
void UniReset(void)
{
unitt = 0; /* reset index to rep/len byte */
unipc = 1; /* first opcode will be written to index 1 */
lastp = 0; /* no previous row yet */
unibuf[0] = 0; /* clear rep/len byte */
}
/* Expands the buffer */
static BOOL UniExpand(int wanted)
{
if ((unipc+wanted)>=unimax) {
UBYTE *newbuf;
/* Expand the buffer by BUFPAGE bytes */
newbuf=(UBYTE*)realloc(unibuf,(unimax+BUFPAGE)*sizeof(UBYTE));
/* Check if realloc succeeded */
if(newbuf) {
unibuf = newbuf;
unimax+=BUFPAGE;
return 1;
} else
return 0;
}
return 1;
}
/* Appends one byte of data to the current row of a track. */
void UniWriteByte(UBYTE data)
{
if (UniExpand(1))
/* write byte to current position and update */
unibuf[unipc++]=data;
}
void UniWriteWord(UWORD data)
{
if (UniExpand(2)) {
unibuf[unipc++]=data>>8;
unibuf[unipc++]=data&0xff;
}
}
static BOOL MyCmp(UBYTE* a,UBYTE* b,UWORD l)
{
UWORD t;
for(t=0;t<l;t++)
if(*(a++)!=*(b++)) return 0;
return 1;
}
/* Closes the current row of a unitrk stream (updates the rep/len byte) and sets
pointers to start a new row. */
void UniNewline(void)
{
UWORD n,l,len;
n = (unibuf[lastp]>>5)+1; /* repeat of previous row */
l = (unibuf[lastp]&0x1f); /* length of previous row */
len = unipc-unitt; /* length of current row */
/* Now, check if the previous and the current row are identical.. when they
are, just increase the repeat field of the previous row */
if(n<8 && len==l && MyCmp(&unibuf[lastp+1],&unibuf[unitt+1],len-1)) {
unibuf[lastp]+=0x20;
unipc = unitt+1;
} else {
if (UniExpand(unitt-unipc)) {
/* current and previous row aren't equal... update the pointers */
unibuf[unitt] = len;
lastp = unitt;
unitt = unipc++;
}
}
}
/* Terminates the current unitrk stream and returns a pointer to a copy of the
stream. */
UBYTE* UniDup(void)
{
UBYTE *d;
if (!UniExpand(unitt-unipc)) return NULL;
unibuf[unitt] = 0;
if(!(d=(UBYTE *)_mm_malloc(unipc))) return NULL;
memcpy(d,unibuf,unipc);
return d;
}
BOOL UniInit(void)
{
unimax = BUFPAGE;
if(!(unibuf=(UBYTE*)_mm_malloc(unimax*sizeof(UBYTE)))) return 0;
return 1;
}
void UniCleanup(void)
{
if(unibuf) free(unibuf);
unibuf = NULL;
}
/* ex:set ts=4: */
#endif
@@ -0,0 +1,194 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
WAV sample loader
==============================================================================*/
/*
FIXME: Stereo .WAV files are not yet supported as samples.
*/
#ifdef SOUNDMODULE_OPENAL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "mikmod_internals.h"
typedef struct WAV {
CHAR rID[4];
ULONG rLen;
CHAR wID[4];
CHAR fID[4];
ULONG fLen;
UWORD wFormatTag;
UWORD nChannels;
ULONG nSamplesPerSec;
ULONG nAvgBytesPerSec;
UWORD nBlockAlign;
UWORD nFormatSpecific;
} WAV;
SAMPLE* Sample_LoadGeneric_internal(MREADER* reader)
{
SAMPLE *si=NULL;
WAV wh;
BOOL have_fmt=0;
/* read wav header */
_mm_read_string(wh.rID,4,reader);
wh.rLen = _mm_read_I_ULONG(reader);
_mm_read_string(wh.wID,4,reader);
/* check for correct header */
if(_mm_eof(reader)|| memcmp(wh.rID,"RIFF",4) || memcmp(wh.wID,"WAVE",4)) {
_mm_errno = MMERR_UNKNOWN_WAVE_TYPE;
return NULL;
}
/* scan all RIFF blocks until we find the sample data */
for(;;) {
CHAR dID[4];
ULONG len,start;
_mm_read_string(dID,4,reader);
len = _mm_read_I_ULONG(reader);
/* truncated file ? */
if (_mm_eof(reader)) {
_mm_errno=MMERR_UNKNOWN_WAVE_TYPE;
return NULL;
}
start = _mm_ftell(reader);
/* sample format block
should be present only once and before a data block */
if(!memcmp(dID,"fmt ",4)) {
wh.wFormatTag = _mm_read_I_UWORD(reader);
wh.nChannels = _mm_read_I_UWORD(reader);
wh.nSamplesPerSec = _mm_read_I_ULONG(reader);
wh.nAvgBytesPerSec = _mm_read_I_ULONG(reader);
wh.nBlockAlign = _mm_read_I_UWORD(reader);
wh.nFormatSpecific = _mm_read_I_UWORD(reader);
#ifdef MIKMOD_DEBUG
fprintf(stderr,"\rwavloader : wFormatTag=%04x blockalign=%04x nFormatSpc=%04x\n",
wh.wFormatTag,wh.nBlockAlign,wh.nFormatSpecific);
#endif
if((have_fmt)||(wh.nChannels>1)) {
_mm_errno=MMERR_UNKNOWN_WAVE_TYPE;
return NULL;
}
have_fmt=1;
} else
/* sample data block
should be present only once and after a format block */
if(!memcmp(dID,"data",4)) {
if(!have_fmt) {
_mm_errno=MMERR_UNKNOWN_WAVE_TYPE;
return NULL;
}
if(!(si=(SAMPLE*)_mm_malloc(sizeof(SAMPLE)))) return NULL;
si->speed = wh.nSamplesPerSec/wh.nChannels;
si->volume = 64;
si->length = len;
if(wh.nBlockAlign == 2) {
si->flags = SF_16BITS | SF_SIGNED;
si->length >>= 1;
}
si->inflags = si->flags;
SL_RegisterSample(si,MD_SNDFX,reader);
SL_LoadSamples();
/* skip any other remaining blocks - so in case of repeated sample
fragments, we'll return the first anyway instead of an error */
break;
}
/* onto next block */
_mm_fseek(reader,start+len,SEEK_SET);
if (_mm_eof(reader))
break;
}
return si;
}
SAMPLE* Sample_LoadGeneric(MREADER* reader)
{
SAMPLE* result;
MUTEX_LOCK(vars);
result=Sample_LoadGeneric_internal(reader);
MUTEX_UNLOCK(vars);
return result;
}
SAMPLE* Sample_LoadFP(FILE *fp)
{
SAMPLE* result=NULL;
MREADER* reader;
if((reader=_mm_new_file_reader(fp))) {
result=Sample_LoadGeneric(reader);
_mm_delete_file_reader(reader);
}
return result;
}
SAMPLE* Sample_Load(CHAR* filename)
{
FILE *fp;
SAMPLE *si=NULL;
if(!(md_mode & DMODE_SOFT_SNDFX)) return NULL;
if((fp=_mm_fopen(filename,"rb"))) {
si = Sample_LoadFP(fp);
fclose(fp);
}
return si;
}
void Sample_Free(SAMPLE* si)
{
if(si) {
MD_SampleUnload(si->handle);
free(si);
}
}
void Sample_Free_internal(SAMPLE *si)
{
MUTEX_LOCK(vars);
Sample_Free(si);
MUTEX_UNLOCK(vars);
}
/* ex:set ts=4: */
#endif
@@ -0,0 +1,51 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
MOD format period table. Used by both the MOD and M15 (15-inst mod) Loaders.
==============================================================================*/
#ifdef SOUNDMODULE_OPENAL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
UWORD npertab[7*OCTAVE]={
/* -> Tuning 0 */
1712,1616,1524,1440,1356,1280,1208,1140,1076,1016, 960, 906,
856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453,
428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226,
214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113,
107, 101, 95, 90, 85, 80, 75, 71, 67, 63, 60, 56,
53, 50, 47, 45, 42, 40, 37, 35, 33, 31, 30, 28,
27, 25, 24, 22, 21, 20, 19, 18, 17, 16, 15, 14
};
/* ex:set ts=4: */
#endif
@@ -0,0 +1,519 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
Routines for loading samples. The sample loader utilizes the routines
provided by the "registered" sample loader.
==============================================================================*/
#ifdef SOUNDMODULE_OPENAL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
static int sl_rlength;
static SWORD sl_old;
static SWORD *sl_buffer=NULL;
static SAMPLOAD *musiclist=NULL,*sndfxlist=NULL;
/* size of the loader buffer in words */
#define SLBUFSIZE 2048
/* IT-Compressed status structure */
typedef struct ITPACK {
UWORD bits; /* current number of bits */
UWORD bufbits; /* bits in buffer */
SWORD last; /* last output */
UBYTE buf; /* bit buffer */
} ITPACK;
BOOL SL_Init(SAMPLOAD* s)
{
if(!sl_buffer)
if(!(sl_buffer=_mm_malloc(SLBUFSIZE*sizeof(SWORD)))) return 0;
sl_rlength = s->length;
if(s->infmt & SF_16BITS) sl_rlength>>=1;
sl_old = 0;
return 1;
}
void SL_Exit(SAMPLOAD *s)
{
if(sl_rlength>0) _mm_fseek(s->reader,sl_rlength,SEEK_CUR);
if(sl_buffer) {
free(sl_buffer);
sl_buffer=NULL;
}
}
/* unpack a 8bit IT packed sample */
static BOOL read_itcompr8(ITPACK* status,MREADER *reader,SWORD *sl_buffer,UWORD count,UWORD* incnt)
{
SWORD *dest=sl_buffer,*end=sl_buffer+count;
UWORD x,y,needbits,havebits,new_count=0;
UWORD bits = status->bits;
UWORD bufbits = status->bufbits;
SBYTE last = status->last;
UBYTE buf = status->buf;
while (dest<end) {
needbits=new_count?3:bits;
x=havebits=0;
while (needbits) {
/* feed buffer */
if (!bufbits) {
if((*incnt)--)
buf=_mm_read_UBYTE(reader);
else
buf=0;
bufbits=8;
}
/* get as many bits as necessary */
y = needbits<bufbits?needbits:bufbits;
x|= (buf & ((1<<y)- 1))<<havebits;
buf>>=y;
bufbits-=y;
needbits-=y;
havebits+=y;
}
if (new_count) {
new_count = 0;
if (++x >= bits)
x++;
bits = x;
continue;
}
if (bits<7) {
if (x==(1<<(bits-1))) {
new_count = 1;
continue;
}
}
else if (bits<9) {
y = (0xff >> (9-bits)) - 4;
if ((x>y)&&(x<=y+8)) {
if ((x-=y)>=bits)
x++;
bits = x;
continue;
}
}
else if (bits<10) {
if (x>=0x100) {
bits=x-0x100+1;
continue;
}
} else {
/* error in compressed data... */
_mm_errno=MMERR_ITPACK_INVALID_DATA;
return 0;
}
if (bits<8) /* extend sign */
x = ((SBYTE)(x <<(8-bits))) >> (8-bits);
*(dest++)= (last+=x) << 8; /* convert to 16 bit */
}
status->bits = bits;
status->bufbits = bufbits;
status->last = last;
status->buf = buf;
return dest-sl_buffer;
}
/* unpack a 16bit IT packed sample */
static BOOL read_itcompr16(ITPACK *status,MREADER *reader,SWORD *sl_buffer,UWORD count,UWORD* incnt)
{
SWORD *dest=sl_buffer,*end=sl_buffer+count;
SLONG x,y,needbits,havebits,new_count=0;
UWORD bits = status->bits;
UWORD bufbits = status->bufbits;
SWORD last = status->last;
UBYTE buf = status->buf;
while (dest<end) {
needbits=new_count?4:bits;
x=havebits=0;
while (needbits) {
/* feed buffer */
if (!bufbits) {
if((*incnt)--)
buf=_mm_read_UBYTE(reader);
else
buf=0;
bufbits=8;
}
/* get as many bits as necessary */
y=needbits<bufbits?needbits:bufbits;
x|=(buf &((1<<y)-1))<<havebits;
buf>>=y;
bufbits-=y;
needbits-=y;
havebits+=y;
}
if (new_count) {
new_count = 0;
if (++x >= bits)
x++;
bits = x;
continue;
}
if (bits<7) {
if (x==(1<<(bits-1))) {
new_count=1;
continue;
}
}
else if (bits<17) {
y=(0xffff>>(17-bits))-8;
if ((x>y)&&(x<=y+16)) {
if ((x-=y)>=bits)
x++;
bits = x;
continue;
}
}
else if (bits<18) {
if (x>=0x10000) {
bits=x-0x10000+1;
continue;
}
} else {
/* error in compressed data... */
_mm_errno=MMERR_ITPACK_INVALID_DATA;
return 0;
}
if (bits<16) /* extend sign */
x = ((SWORD)(x<<(16-bits)))>>(16-bits);
*(dest++)=(last+=x);
}
status->bits = bits;
status->bufbits = bufbits;
status->last = last;
status->buf = buf;
return dest-sl_buffer;
}
static BOOL SL_LoadInternal(void* buffer,UWORD infmt,UWORD outfmt,int scalefactor,ULONG length,MREADER* reader,BOOL dither)
{
SBYTE *bptr = (SBYTE*)buffer;
SWORD *wptr = (SWORD*)buffer;
int stodo,t,u;
int result,c_block=0; /* compression bytes until next block */
ITPACK status;
UWORD incnt;
while(length) {
stodo=(length<SLBUFSIZE)?length:SLBUFSIZE;
if(infmt&SF_ITPACKED) {
sl_rlength=0;
if (!c_block) {
status.bits = (infmt & SF_16BITS) ? 17 : 9;
status.last = status.bufbits = 0;
incnt=_mm_read_I_UWORD(reader);
c_block = (infmt & SF_16BITS) ? 0x4000 : 0x8000;
if(infmt&SF_DELTA) sl_old=0;
}
if (infmt & SF_16BITS) {
if(!(result=read_itcompr16(&status,reader,sl_buffer,stodo,&incnt)))
return 1;
} else {
if(!(result=read_itcompr8(&status,reader,sl_buffer,stodo,&incnt)))
return 1;
}
if(result!=stodo) {
_mm_errno=MMERR_ITPACK_INVALID_DATA;
return 1;
}
c_block -= stodo;
} else {
if(infmt&SF_16BITS) {
if(infmt&SF_BIG_ENDIAN)
_mm_read_M_SWORDS(sl_buffer,stodo,reader);
else
_mm_read_I_SWORDS(sl_buffer,stodo,reader);
} else {
SBYTE *src;
SWORD *dest;
reader->Read(reader,sl_buffer,sizeof(SBYTE)*stodo);
src = (SBYTE*)sl_buffer;
dest = sl_buffer;
src += stodo;dest += stodo;
for(t=0;t<stodo;t++) {
src--;dest--;
*dest = (*src)<<8;
}
}
sl_rlength-=stodo;
}
if(infmt & SF_DELTA)
for(t=0;t<stodo;t++) {
sl_buffer[t] += sl_old;
sl_old = sl_buffer[t];
}
if((infmt^outfmt) & SF_SIGNED)
for(t=0;t<stodo;t++)
sl_buffer[t]^= 0x8000;
if(scalefactor) {
int idx = 0;
SLONG scaleval;
/* Sample Scaling... average values for better results. */
t= 0;
while(t<stodo && length) {
scaleval = 0;
for(u=scalefactor;u && t<stodo;u--,t++)
scaleval+=sl_buffer[t];
sl_buffer[idx++]=scaleval/(scalefactor-u);
length--;
}
stodo = idx;
} else
length -= stodo;
if (dither) {
if((infmt & SF_STEREO) && !(outfmt & SF_STEREO)) {
/* dither stereo to mono, average together every two samples */
SLONG avgval;
int idx = 0;
t=0;
while(t<stodo && length) {
avgval=sl_buffer[t++];
avgval+=sl_buffer[t++];
sl_buffer[idx++]=avgval>>1;
length-=2;
}
stodo = idx;
}
}
if(outfmt & SF_16BITS) {
for(t=0;t<stodo;t++)
*(wptr++)=sl_buffer[t];
} else {
for(t=0;t<stodo;t++)
*(bptr++)=sl_buffer[t]>>8;
}
}
return 0;
}
BOOL SL_Load(void* buffer,SAMPLOAD *smp,ULONG length)
{
return SL_LoadInternal(buffer,smp->infmt,smp->outfmt,smp->scalefactor,
length,smp->reader,0);
}
/* Registers a sample for loading when SL_LoadSamples() is called. */
SAMPLOAD* SL_RegisterSample(SAMPLE* s,int type,MREADER* reader)
{
SAMPLOAD *news,**samplist,*cruise;
if(type==MD_MUSIC) {
samplist = &musiclist;
cruise = musiclist;
} else
if (type==MD_SNDFX) {
samplist = &sndfxlist;
cruise = sndfxlist;
} else
return NULL;
/* Allocate and add structure to the END of the list */
if(!(news=(SAMPLOAD*)_mm_malloc(sizeof(SAMPLOAD)))) return NULL;
if(cruise) {
while(cruise->next) cruise=cruise->next;
cruise->next = news;
} else
*samplist = news;
news->infmt = s->flags & SF_FORMATMASK;
news->outfmt = news->infmt;
news->reader = reader;
news->sample = s;
news->length = s->length;
news->loopstart = s->loopstart;
news->loopend = s->loopend;
return news;
}
static void FreeSampleList(SAMPLOAD* s)
{
SAMPLOAD *old;
while(s) {
old = s;
s = s->next;
free(old);
}
}
/* Returns the total amount of memory required by the samplelist queue. */
static ULONG SampleTotal(SAMPLOAD* samplist,int type)
{
int total = 0;
while(samplist) {
samplist->sample->flags=
(samplist->sample->flags&~SF_FORMATMASK)|samplist->outfmt;
total += MD_SampleLength(type,samplist->sample);
samplist=samplist->next;
}
return total;
}
static ULONG RealSpeed(SAMPLOAD *s)
{
return(s->sample->speed/(s->scalefactor?s->scalefactor:1));
}
static BOOL DitherSamples(SAMPLOAD* samplist,int type)
{
SAMPLOAD *c2smp=NULL;
ULONG maxsize, speed;
SAMPLOAD *s;
if(!samplist) return 0;
if((maxsize=MD_SampleSpace(type)*1024))
while(SampleTotal(samplist,type)>maxsize) {
/* First Pass - check for any 16 bit samples */
s = samplist;
while(s) {
if(s->outfmt & SF_16BITS) {
SL_Sample16to8(s);
break;
}
s=s->next;
}
/* Second pass (if no 16bits found above) is to take the sample with
the highest speed and dither it by half. */
if(!s) {
s = samplist;
speed = 0;
while(s) {
if((s->sample->length) && (RealSpeed(s)>speed)) {
speed=RealSpeed(s);
c2smp=s;
}
s=s->next;
}
if (c2smp)
SL_HalveSample(c2smp,2);
}
}
/* Samples dithered, now load them ! */
s = samplist;
while(s) {
/* sample has to be loaded ? -> increase number of samples, allocate
memory and load sample. */
if(s->sample->length) {
if(s->sample->seekpos)
_mm_fseek(s->reader, s->sample->seekpos, SEEK_SET);
/* Call the sample load routine of the driver module. It has to
return a 'handle' (>=0) that identifies the sample. */
s->sample->handle = MD_SampleLoad(s, type);
s->sample->flags = (s->sample->flags & ~SF_FORMATMASK) | s->outfmt;
if(s->sample->handle<0) {
FreeSampleList(samplist);
if(_mm_errorhandler) _mm_errorhandler();
return 1;
}
}
s = s->next;
}
FreeSampleList(samplist);
return 0;
}
BOOL SL_LoadSamples(void)
{
BOOL ok;
_mm_critical = 0;
if((!musiclist)&&(!sndfxlist)) return 0;
ok=DitherSamples(musiclist,MD_MUSIC)||DitherSamples(sndfxlist,MD_SNDFX);
musiclist=sndfxlist=NULL;
return ok;
}
void SL_Sample16to8(SAMPLOAD* s)
{
s->outfmt &= ~SF_16BITS;
s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
}
void SL_Sample8to16(SAMPLOAD* s)
{
s->outfmt |= SF_16BITS;
s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
}
void SL_SampleSigned(SAMPLOAD* s)
{
s->outfmt |= SF_SIGNED;
s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
}
void SL_SampleUnsigned(SAMPLOAD* s)
{
s->outfmt &= ~SF_SIGNED;
s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
}
void SL_HalveSample(SAMPLOAD* s,int factor)
{
s->scalefactor=factor>0?factor:2;
s->sample->divfactor = s->scalefactor;
s->sample->length = s->length / s->scalefactor;
s->sample->loopstart = s->loopstart / s->scalefactor;
s->sample->loopend = s->loopend / s->scalefactor;
}
/* ex:set ts=4: */
#endif
@@ -0,0 +1,836 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
Sample mixing routines, using a 32 bits mixing buffer.
==============================================================================*/
/*
Optional features include:
(a) 4-step reverb (for 16 bit output only)
(b) Interpolation of sample data during mixing
(c) Dolby Surround Sound
*/
#ifdef SOUNDMODULE_OPENAL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stddef.h>
#include <string.h>
#include "mikmod_internals.h"
/*
Constant definitions
====================
BITSHIFT
Controls the maximum volume of the sound output. All data is shifted
right by BITSHIFT after being mixed. Higher values result in quieter
sound and less chance of distortion.
REVERBERATION
Controls the duration of the reverb. Larger values represent a shorter
reverb loop. Smaller values extend the reverb but can result in more of
an echo-ish sound.
*/
#define BITSHIFT 9
#define REVERBERATION 110000L
#define FRACBITS 11
#define FRACMASK ((1L<<FRACBITS)-1L)
#define TICKLSIZE 8192
#define TICKWSIZE (TICKLSIZE<<1)
#define TICKBSIZE (TICKWSIZE<<1)
#define CLICK_SHIFT 6
#define CLICK_BUFFER (1L<<CLICK_SHIFT)
#ifndef MIN
#define MIN(a,b) (((a)<(b)) ? (a) : (b))
#endif
typedef struct VINFO {
UBYTE kick; /* =1 -> sample has to be restarted */
UBYTE active; /* =1 -> sample is playing */
UWORD flags; /* 16/8 bits looping/one-shot */
SWORD handle; /* identifies the sample */
ULONG start; /* start index */
ULONG size; /* samplesize */
ULONG reppos; /* loop start */
ULONG repend; /* loop end */
ULONG frq; /* current frequency */
int vol; /* current volume */
int pan; /* current panning position */
int rampvol;
int lvolsel,rvolsel; /* Volume factor in range 0-255 */
int oldlvol,oldrvol;
SLONGLONG current; /* current index in the sample */
SLONGLONG increment; /* increment value */
} VINFO;
static SWORD **Samples;
static VINFO *vinf=NULL,*vnf;
static long tickleft,samplesthatfit,vc_memory=0;
static int vc_softchn;
static SLONGLONG idxsize,idxlpos,idxlend;
static SLONG *vc_tickbuf=NULL;
static UWORD vc_mode;
/* Reverb control variables */
static int RVc1, RVc2, RVc3, RVc4, RVc5, RVc6, RVc7, RVc8;
static ULONG RVRindex;
/* For Mono or Left Channel */
static SLONG *RVbufL1=NULL,*RVbufL2=NULL,*RVbufL3=NULL,*RVbufL4=NULL,
*RVbufL5=NULL,*RVbufL6=NULL,*RVbufL7=NULL,*RVbufL8=NULL;
/* For Stereo only (Right Channel) */
static SLONG *RVbufR1=NULL,*RVbufR2=NULL,*RVbufR3=NULL,*RVbufR4=NULL,
*RVbufR5=NULL,*RVbufR6=NULL,*RVbufR7=NULL,*RVbufR8=NULL;
#ifdef NATIVE_64BIT_INT
#define NATIVE SLONGLONG
#else
#define NATIVE SLONG
#endif
/*========== 32 bit sample mixers - only for 32 bit platforms */
#ifndef NATIVE_64BIT_INT
static SLONG Mix32MonoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
{
SWORD sample;
while(todo--) {
sample = srce[index >> FRACBITS];
index += increment;
*dest++ += vnf->lvolsel * sample;
}
return index;
}
static SLONG Mix32StereoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
{
SWORD sample;
while(todo--) {
sample=srce[index >> FRACBITS];
index += increment;
*dest++ += vnf->lvolsel * sample;
*dest++ += vnf->rvolsel * sample;
}
return index;
}
static SLONG Mix32SurroundNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
{
SWORD sample;
while(todo--) {
sample = srce[index >> FRACBITS];
index += increment;
if(vnf->lvolsel>=vnf->rvolsel) {
*dest++ += vnf->lvolsel*sample;
*dest++ -= vnf->lvolsel*sample;
} else {
*dest++ -= vnf->rvolsel*sample;
*dest++ += vnf->rvolsel*sample;
}
}
return index;
}
static SLONG Mix32MonoInterp(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
{
SLONG sample;
while(todo--) {
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
if(vnf->rampvol) {
*dest++ += (((SLONG)vnf->lvolsel<<CLICK_SHIFT) +
(SLONG)(vnf->oldlvol-vnf->lvolsel)*vnf->rampvol
)*sample>>CLICK_SHIFT;
vnf->rampvol--;
} else
*dest++ += vnf->lvolsel * sample;
}
return index;
}
static SLONG Mix32StereoInterp(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
{
SLONG sample;
while(todo--) {
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
if(vnf->rampvol) {
*dest++ += (((SLONG)vnf->lvolsel<<CLICK_SHIFT)+
(SLONG)(vnf->oldlvol-vnf->lvolsel)*vnf->rampvol
)*sample>>CLICK_SHIFT;
*dest++ += (((SLONG)vnf->rvolsel<<CLICK_SHIFT)+
(SLONG)(vnf->oldrvol-vnf->rvolsel)*vnf->rampvol
)*sample>>CLICK_SHIFT;
vnf->rampvol--;
} else {
*dest++ += vnf->lvolsel * sample;
*dest++ += vnf->rvolsel * sample;
}
}
return index;
}
static SLONG Mix32SurroundInterp(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
{
SLONG sample;
while(todo--) {
int oldvol,vol;
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
if(vnf->lvolsel>=vnf->rvolsel) {
vol=vnf->lvolsel;oldvol=vnf->oldlvol;
} else {
vol=vnf->rvolsel;oldvol=vnf->oldrvol;
}
if(vnf->rampvol) {
sample=(((SLONG)vnf->lvolsel<<CLICK_SHIFT)+
(SLONG)(vnf->oldlvol-vnf->lvolsel)*vnf->rampvol
)*sample>>CLICK_SHIFT;
*dest++ += sample;
*dest++ -= sample;
vnf->rampvol--;
} else {
*dest++ += vol*sample;
*dest++ -= vol*sample;
}
}
return index;
}
#endif
/*========== 64 bit sample mixers - all platforms */
static SLONGLONG MixMonoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
{
SWORD sample;
while(todo--) {
sample = srce[index >> FRACBITS];
index += increment;
*dest++ += vnf->lvolsel * sample;
}
return index;
}
static SLONGLONG MixStereoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
{
SWORD sample;
while(todo--) {
sample=srce[index >> FRACBITS];
index += increment;
*dest++ += vnf->lvolsel * sample;
*dest++ += vnf->rvolsel * sample;
}
return index;
}
static SLONGLONG MixSurroundNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
{
SWORD sample;
while(todo--) {
sample = srce[index >> FRACBITS];
index += increment;
if(vnf->lvolsel>=vnf->rvolsel) {
*dest++ += vnf->lvolsel*sample;
*dest++ -= vnf->lvolsel*sample;
} else {
*dest++ -= vnf->rvolsel*sample;
*dest++ += vnf->rvolsel*sample;
}
}
return index;
}
static SLONGLONG MixMonoInterp(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
{
SLONG sample;
while(todo--) {
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
if(vnf->rampvol) {
*dest++ += (((SLONG)vnf->lvolsel<<CLICK_SHIFT)+
(SLONG)(vnf->oldlvol-vnf->lvolsel)*vnf->rampvol
)*sample>>CLICK_SHIFT;
vnf->rampvol--;
} else
*dest++ += vnf->lvolsel * sample;
}
return index;
}
static SLONGLONG MixStereoInterp(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
{
SLONG sample;
while(todo--) {
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
if(vnf->rampvol) {
*dest++ +=(((SLONG)vnf->lvolsel<<CLICK_SHIFT)+
(SLONG)(vnf->oldlvol-vnf->lvolsel)*vnf->rampvol
)*sample>>CLICK_SHIFT;
*dest++ +=(((SLONG)vnf->rvolsel<<CLICK_SHIFT)+
(SLONG)(vnf->oldrvol-vnf->rvolsel)*vnf->rampvol
)*sample>>CLICK_SHIFT;
vnf->rampvol--;
} else {
*dest++ += vnf->lvolsel * sample;
*dest++ += vnf->rvolsel * sample;
}
}
return index;
}
static SLONGLONG MixSurroundInterp(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
{
SLONG sample;
while(todo--) {
int oldvol,vol;
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
if(vnf->lvolsel>=vnf->rvolsel) {
vol=vnf->lvolsel;oldvol=vnf->oldlvol;
} else {
vol=vnf->rvolsel;oldvol=vnf->oldrvol;
}
if(vnf->rampvol) {
sample=(((SLONG)vnf->lvolsel<<CLICK_SHIFT)+
(SLONG)(vnf->oldlvol-vnf->lvolsel)*vnf->rampvol
)*sample>>CLICK_SHIFT;
*dest++ += sample;
*dest++ -= sample;
vnf->rampvol--;
} else {
*dest++ += vol*sample;
*dest++ -= vol*sample;
}
}
return index;
}
static void (*MixReverb)(SLONG* srce,NATIVE count);
/* Reverb macros */
#define COMPUTE_LOC(n) loc##n = RVRindex % RVc##n
#define COMPUTE_LECHO(n) RVbufL##n [loc##n ]=speedup+((ReverbPct*RVbufL##n [loc##n ])>>7)
#define COMPUTE_RECHO(n) RVbufR##n [loc##n ]=speedup+((ReverbPct*RVbufR##n [loc##n ])>>7)
static void MixReverb_Normal(SLONG* srce,NATIVE count)
{
unsigned int speedup;
int ReverbPct;
unsigned int loc1,loc2,loc3,loc4;
unsigned int loc5,loc6,loc7,loc8;
ReverbPct=58+(md_reverb<<2);
COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);
COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);
while(count--) {
/* Compute the left channel echo buffers */
speedup = *srce >> 3;
COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4);
COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8);
/* Prepare to compute actual finalized data */
RVRindex++;
COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);
COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);
/* left channel */
*srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+
RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];
}
}
static void MixReverb_Stereo(SLONG* srce,NATIVE count)
{
unsigned int speedup;
int ReverbPct;
unsigned int loc1, loc2, loc3, loc4;
unsigned int loc5, loc6, loc7, loc8;
ReverbPct = 92+(md_reverb<<1);
COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);
COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);
while(count--) {
/* Compute the left channel echo buffers */
speedup = *srce >> 3;
COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4);
COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8);
/* Compute the right channel echo buffers */
speedup = srce[1] >> 3;
COMPUTE_RECHO(1); COMPUTE_RECHO(2); COMPUTE_RECHO(3); COMPUTE_RECHO(4);
COMPUTE_RECHO(5); COMPUTE_RECHO(6); COMPUTE_RECHO(7); COMPUTE_RECHO(8);
/* Prepare to compute actual finalized data */
RVRindex++;
COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);
COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);
/* left channel then right channel */
*srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+
RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];
*srce++ +=RVbufR1[loc1]-RVbufR2[loc2]+RVbufR3[loc3]-RVbufR4[loc4]+
RVbufR5[loc5]-RVbufR6[loc6]+RVbufR7[loc7]-RVbufR8[loc8];
}
}
/* Mixing macros */
#define EXTRACT_SAMPLE(var,size) var=*srce++>>(BITSHIFT+16-size)
#define CHECK_SAMPLE(var,bound) var=(var>=bound)?bound-1:(var<-bound)?-bound:var
#define PUT_SAMPLE(var) *dste++=var
static void Mix32To16(SWORD* dste,SLONG* srce,NATIVE count)
{
SLONG x1,x2,x3,x4;
int remain;
remain=count&3;
for(count>>=2;count;count--) {
EXTRACT_SAMPLE(x1,16); EXTRACT_SAMPLE(x2,16);
EXTRACT_SAMPLE(x3,16); EXTRACT_SAMPLE(x4,16);
CHECK_SAMPLE(x1,32768); CHECK_SAMPLE(x2,32768);
CHECK_SAMPLE(x3,32768); CHECK_SAMPLE(x4,32768);
PUT_SAMPLE(x1); PUT_SAMPLE(x2); PUT_SAMPLE(x3); PUT_SAMPLE(x4);
}
while(remain--) {
EXTRACT_SAMPLE(x1,16);
CHECK_SAMPLE(x1,32768);
PUT_SAMPLE(x1);
}
}
static void Mix32To8(SBYTE* dste,SLONG* srce,NATIVE count)
{
SWORD x1,x2,x3,x4;
int remain;
remain=count&3;
for(count>>=2;count;count--) {
EXTRACT_SAMPLE(x1,8); EXTRACT_SAMPLE(x2,8);
EXTRACT_SAMPLE(x3,8); EXTRACT_SAMPLE(x4,8);
CHECK_SAMPLE(x1,128); CHECK_SAMPLE(x2,128);
CHECK_SAMPLE(x3,128); CHECK_SAMPLE(x4,128);
PUT_SAMPLE(x1+128); PUT_SAMPLE(x2+128);
PUT_SAMPLE(x3+128); PUT_SAMPLE(x4+128);
}
while(remain--) {
EXTRACT_SAMPLE(x1,8);
CHECK_SAMPLE(x1,128);
PUT_SAMPLE(x1+128);
}
}
static void AddChannel(SLONG* ptr,NATIVE todo)
{
SLONGLONG end,done;
SWORD *s;
if(!(s=Samples[vnf->handle])) {
vnf->current = vnf->active = 0;
return;
}
/* update the 'current' index so the sample loops, or stops playing if it
reached the end of the sample */
while(todo>0) {
SLONGLONG endpos;
if(vnf->flags & SF_REVERSE) {
/* The sample is playing in reverse */
if((vnf->flags&SF_LOOP)&&(vnf->current<idxlpos)) {
/* the sample is looping and has reached the loopstart index */
if(vnf->flags & SF_BIDI) {
/* sample is doing bidirectional loops, so 'bounce' the
current index against the idxlpos */
vnf->current = idxlpos+(idxlpos-vnf->current);
vnf->flags &= ~SF_REVERSE;
vnf->increment = -vnf->increment;
} else
/* normal backwards looping, so set the current position to
loopend index */
vnf->current=idxlend-(idxlpos-vnf->current);
} else {
/* the sample is not looping, so check if it reached index 0 */
if(vnf->current < 0) {
/* playing index reached 0, so stop playing this sample */
vnf->current = vnf->active = 0;
break;
}
}
} else {
/* The sample is playing forward */
if((vnf->flags & SF_LOOP) && (vnf->current >= idxlend)) {
/* the sample is looping, check the loopend index */
if(vnf->flags & SF_BIDI) {
/* sample is doing bidirectional loops, so 'bounce' the
current index against the idxlend */
vnf->flags |= SF_REVERSE;
vnf->increment = -vnf->increment;
vnf->current = idxlend-(vnf->current-idxlend);
} else
/* normal backwards looping, so set the current position
to loopend index */
vnf->current=idxlpos+(vnf->current-idxlend);
} else {
/* sample is not looping, so check if it reached the last
position */
if(vnf->current >= idxsize) {
/* yes, so stop playing this sample */
vnf->current = vnf->active = 0;
break;
}
}
}
end=(vnf->flags&SF_REVERSE)?(vnf->flags&SF_LOOP)?idxlpos:0:
(vnf->flags&SF_LOOP)?idxlend:idxsize;
/* if the sample is not blocked... */
if((end==vnf->current)||(!vnf->increment))
done=0;
else {
done=MIN((end-vnf->current)/vnf->increment+1,todo);
if(done<0) done=0;
}
if(!done) {
vnf->active = 0;
break;
}
endpos=vnf->current+done*vnf->increment;
if(vnf->vol) {
#ifndef NATIVE_64BIT_INT
/* use the 32 bit mixers as often as we can (they're much faster) */
if((vnf->current<0x7fffffff)&&(endpos<0x7fffffff)) {
if((md_mode & DMODE_INTERP)) {
if(vc_mode & DMODE_STEREO) {
if((vnf->pan==PAN_SURROUND)&&(vc_mode&DMODE_SURROUND))
vnf->current=Mix32SurroundInterp
(s,ptr,vnf->current,vnf->increment,done);
else
vnf->current=Mix32StereoInterp
(s,ptr,vnf->current,vnf->increment,done);
} else
vnf->current=Mix32MonoInterp
(s,ptr,vnf->current,vnf->increment,done);
} else if(vc_mode & DMODE_STEREO) {
if((vnf->pan==PAN_SURROUND)&&(vc_mode&DMODE_SURROUND))
vnf->current=Mix32SurroundNormal
(s,ptr,vnf->current,vnf->increment,done);
else
vnf->current=Mix32StereoNormal
(s,ptr,vnf->current,vnf->increment,done);
} else
vnf->current=Mix32MonoNormal
(s,ptr,vnf->current,vnf->increment,done);
} else
#endif
{
if((md_mode & DMODE_INTERP)) {
if(vc_mode & DMODE_STEREO) {
if((vnf->pan==PAN_SURROUND)&&(vc_mode&DMODE_SURROUND))
vnf->current=MixSurroundInterp
(s,ptr,vnf->current,vnf->increment,done);
else
vnf->current=MixStereoInterp
(s,ptr,vnf->current,vnf->increment,done);
} else
vnf->current=MixMonoInterp
(s,ptr,vnf->current,vnf->increment,done);
} else if(vc_mode & DMODE_STEREO) {
if((vnf->pan==PAN_SURROUND)&&(vc_mode&DMODE_SURROUND))
vnf->current=MixSurroundNormal
(s,ptr,vnf->current,vnf->increment,done);
else
vnf->current=MixStereoNormal
(s,ptr,vnf->current,vnf->increment,done);
} else
vnf->current=MixMonoNormal
(s,ptr,vnf->current,vnf->increment,done);
}
} else
/* update sample position */
vnf->current=endpos;
todo-=done;
#if 1
if ( vc_mode & DMODE_STEREO )
ptr += done*2;
else
ptr += done;
#else
ptr +=(vc_mode & DMODE_STEREO)?(done<<1):done;
#endif
}
}
#define _IN_VIRTCH_
#include "virtch_common.c"
#undef _IN_VIRTCH_
void VC1_WriteSamples(SBYTE* buf,ULONG todo)
{
int left,portion=0,count;
SBYTE *buffer;
int t, pan, vol;
while(todo) {
if(!tickleft) {
if(vc_mode & DMODE_SOFT_MUSIC) md_player();
tickleft=(md_mixfreq*125L)/(md_bpm*50L);
}
left = MIN(tickleft, todo);
buffer = buf;
tickleft -= left;
todo -= left;
buf += samples2bytes(left);
while(left) {
portion = MIN(left, samplesthatfit);
count = (vc_mode & DMODE_STEREO)?(portion<<1):portion;
memset(vc_tickbuf, 0, count<<2);
for(t=0;t<vc_softchn;t++) {
vnf = &vinf[t];
if(vnf->kick) {
vnf->current=((SLONGLONG)vnf->start)<<FRACBITS;
vnf->kick =0;
vnf->active =1;
}
if(!vnf->frq) vnf->active = 0;
if(vnf->active) {
vnf->increment=((SLONGLONG)(vnf->frq<<FRACBITS))/md_mixfreq;
if(vnf->flags&SF_REVERSE) vnf->increment=-vnf->increment;
vol = vnf->vol; pan = vnf->pan;
vnf->oldlvol=vnf->lvolsel;vnf->oldrvol=vnf->rvolsel;
if(vc_mode & DMODE_STEREO) {
if(pan != PAN_SURROUND) {
vnf->lvolsel=(vol*(PAN_RIGHT-pan))>>8;
vnf->rvolsel=(vol*pan)>>8;
} else
vnf->lvolsel=vnf->rvolsel=vol/2;
} else
vnf->lvolsel=vol;
idxsize = (vnf->size)? ((SLONGLONG)vnf->size << FRACBITS)-1 : 0;
idxlend = (vnf->repend)? ((SLONGLONG)vnf->repend << FRACBITS)-1 : 0;
idxlpos = (SLONGLONG)vnf->reppos << FRACBITS;
AddChannel(vc_tickbuf, portion);
}
}
if(md_reverb) {
if(md_reverb>15) md_reverb=15;
MixReverb(vc_tickbuf, portion);
}
if(vc_mode & DMODE_16BITS)
Mix32To16((SWORD*) buffer, vc_tickbuf, count);
else
Mix32To8((SBYTE*) buffer, vc_tickbuf, count);
buffer += samples2bytes(portion);
left -= portion;
}
}
}
BOOL VC1_Init(void)
{
VC_SetupPointers();
if (md_mode&DMODE_HQMIXER)
return VC2_Init();
if(!(Samples=(SWORD**)_mm_calloc(MAXSAMPLEHANDLES,sizeof(SWORD*)))) {
_mm_errno = MMERR_INITIALIZING_MIXER;
return 1;
}
if(!vc_tickbuf)
if(!(vc_tickbuf=(SLONG*)_mm_malloc((TICKLSIZE+32)*sizeof(SLONG)))) {
_mm_errno = MMERR_INITIALIZING_MIXER;
return 1;
}
MixReverb=(md_mode&DMODE_STEREO)?MixReverb_Stereo:MixReverb_Normal;
vc_mode = md_mode;
return 0;
}
BOOL VC1_PlayStart(void)
{
samplesthatfit=TICKLSIZE;
if(vc_mode & DMODE_STEREO) samplesthatfit >>= 1;
tickleft = 0;
RVc1 = (5000L * md_mixfreq) / REVERBERATION;
RVc2 = (5078L * md_mixfreq) / REVERBERATION;
RVc3 = (5313L * md_mixfreq) / REVERBERATION;
RVc4 = (5703L * md_mixfreq) / REVERBERATION;
RVc5 = (6250L * md_mixfreq) / REVERBERATION;
RVc6 = (6953L * md_mixfreq) / REVERBERATION;
RVc7 = (7813L * md_mixfreq) / REVERBERATION;
RVc8 = (8828L * md_mixfreq) / REVERBERATION;
if(!(RVbufL1=(SLONG*)_mm_calloc((RVc1+1),sizeof(SLONG)))) return 1;
if(!(RVbufL2=(SLONG*)_mm_calloc((RVc2+1),sizeof(SLONG)))) return 1;
if(!(RVbufL3=(SLONG*)_mm_calloc((RVc3+1),sizeof(SLONG)))) return 1;
if(!(RVbufL4=(SLONG*)_mm_calloc((RVc4+1),sizeof(SLONG)))) return 1;
if(!(RVbufL5=(SLONG*)_mm_calloc((RVc5+1),sizeof(SLONG)))) return 1;
if(!(RVbufL6=(SLONG*)_mm_calloc((RVc6+1),sizeof(SLONG)))) return 1;
if(!(RVbufL7=(SLONG*)_mm_calloc((RVc7+1),sizeof(SLONG)))) return 1;
if(!(RVbufL8=(SLONG*)_mm_calloc((RVc8+1),sizeof(SLONG)))) return 1;
if(!(RVbufR1=(SLONG*)_mm_calloc((RVc1+1),sizeof(SLONG)))) return 1;
if(!(RVbufR2=(SLONG*)_mm_calloc((RVc2+1),sizeof(SLONG)))) return 1;
if(!(RVbufR3=(SLONG*)_mm_calloc((RVc3+1),sizeof(SLONG)))) return 1;
if(!(RVbufR4=(SLONG*)_mm_calloc((RVc4+1),sizeof(SLONG)))) return 1;
if(!(RVbufR5=(SLONG*)_mm_calloc((RVc5+1),sizeof(SLONG)))) return 1;
if(!(RVbufR6=(SLONG*)_mm_calloc((RVc6+1),sizeof(SLONG)))) return 1;
if(!(RVbufR7=(SLONG*)_mm_calloc((RVc7+1),sizeof(SLONG)))) return 1;
if(!(RVbufR8=(SLONG*)_mm_calloc((RVc8+1),sizeof(SLONG)))) return 1;
RVRindex = 0;
return 0;
}
void VC1_PlayStop(void)
{
if(RVbufL1) free(RVbufL1);
if(RVbufL2) free(RVbufL2);
if(RVbufL3) free(RVbufL3);
if(RVbufL4) free(RVbufL4);
if(RVbufL5) free(RVbufL5);
if(RVbufL6) free(RVbufL6);
if(RVbufL7) free(RVbufL7);
if(RVbufL8) free(RVbufL8);
RVbufL1=RVbufL2=RVbufL3=RVbufL4=RVbufL5=RVbufL6=RVbufL7=RVbufL8=NULL;
if(RVbufR1) free(RVbufR1);
if(RVbufR2) free(RVbufR2);
if(RVbufR3) free(RVbufR3);
if(RVbufR4) free(RVbufR4);
if(RVbufR5) free(RVbufR5);
if(RVbufR6) free(RVbufR6);
if(RVbufR7) free(RVbufR7);
if(RVbufR8) free(RVbufR8);
RVbufR1=RVbufR2=RVbufR3=RVbufR4=RVbufR5=RVbufR6=RVbufR7=RVbufR8=NULL;
}
BOOL VC1_SetNumVoices(void)
{
int t;
if(!(vc_softchn=md_softchn)) return 0;
if(vinf) free(vinf);
if(!(vinf= _mm_calloc(sizeof(VINFO),vc_softchn))) return 1;
for(t=0;t<vc_softchn;t++) {
vinf[t].frq=10000;
vinf[t].pan=(t&1)?PAN_LEFT:PAN_RIGHT;
}
return 0;
}
/* ex:set ts=4: */
#endif
@@ -0,0 +1,907 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
High-quality sample mixing routines, using a 32 bits mixing buffer,
interpolation, and sample smoothing to improve sound quality and remove
clicks.
==============================================================================*/
/*
Future Additions:
Low-Pass filter to remove annoying staticy buzz.
*/
#ifdef SOUNDMODULE_OPENAL
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stddef.h>
#include <string.h>
#include "mikmod_internals.h"
#if defined(macintosh) || defined(__APPLE__)
#define NO_64BIT_MIXER
#endif
/*
Constant Definitions
====================
MAXVOL_FACTOR (was BITSHIFT in virtch.c)
Controls the maximum volume of the output data. All mixed data is
divided by this number after mixing, so larger numbers result in
quieter mixing. Smaller numbers will increase the likeliness of
distortion on loud modules.
REVERBERATION
Larger numbers result in shorter reverb duration. Longer reverb
durations can cause unwanted static and make the reverb sound more
like a crappy echo.
SAMPLING_SHIFT
Specified the shift multiplier which controls by how much the mixing
rate is multiplied while mixing. Higher values can improve quality by
smoothing the sound and reducing pops and clicks. Note, this is a shift
value, so a value of 2 becomes a mixing-rate multiplier of 4, and a
value of 3 = 8, etc.
FRACBITS
The number of bits per integer devoted to the fractional part of the
number. Generally, this number should not be changed for any reason.
!!! IMPORTANT !!! All values below MUST ALWAYS be greater than 0
*/
#define MAXVOL_FACTOR (1<<9)
#define REVERBERATION 11000L
#define SAMPLING_SHIFT 2
#define SAMPLING_FACTOR (1UL<<SAMPLING_SHIFT)
#define FRACBITS 28
#define FRACMASK ((1UL<<FRACBITS)-1UL)
#define TICKLSIZE 8192
#define TICKWSIZE (TICKLSIZE * 2)
#define TICKBSIZE (TICKWSIZE * 2)
#define CLICK_SHIFT_BASE 6
#define CLICK_SHIFT (CLICK_SHIFT_BASE + SAMPLING_SHIFT)
#define CLICK_BUFFER (1L << CLICK_SHIFT)
#ifndef MIN
#define MIN(a,b) (((a)<(b)) ? (a) : (b))
#endif
typedef struct VINFO {
UBYTE kick; /* =1 -> sample has to be restarted */
UBYTE active; /* =1 -> sample is playing */
UWORD flags; /* 16/8 bits looping/one-shot */
SWORD handle; /* identifies the sample */
ULONG start; /* start index */
ULONG size; /* samplesize */
ULONG reppos; /* loop start */
ULONG repend; /* loop end */
ULONG frq; /* current frequency */
int vol; /* current volume */
int pan; /* current panning position */
int click;
int rampvol;
SLONG lastvalL,lastvalR;
int lvolsel,rvolsel; /* Volume factor in range 0-255 */
int oldlvol,oldrvol;
SLONGLONG current; /* current index in the sample */
SLONGLONG increment; /* increment value */
} VINFO;
static SWORD **Samples;
static VINFO *vinf=NULL,*vnf;
static long tickleft,samplesthatfit,vc_memory=0;
static int vc_softchn;
static SLONGLONG idxsize,idxlpos,idxlend;
static SLONG *vc_tickbuf=NULL;
static UWORD vc_mode;
/* Reverb control variables */
static int RVc1, RVc2, RVc3, RVc4, RVc5, RVc6, RVc7, RVc8;
static ULONG RVRindex;
/* For Mono or Left Channel */
static SLONG *RVbufL1=NULL,*RVbufL2=NULL,*RVbufL3=NULL,*RVbufL4=NULL,
*RVbufL5=NULL,*RVbufL6=NULL,*RVbufL7=NULL,*RVbufL8=NULL;
/* For Stereo only (Right Channel) */
static SLONG *RVbufR1=NULL,*RVbufR2=NULL,*RVbufR3=NULL,*RVbufR4=NULL,
*RVbufR5=NULL,*RVbufR6=NULL,*RVbufR7=NULL,*RVbufR8=NULL;
#ifdef NATIVE_64BIT_INT
#define NATIVE SLONGLONG
#else
#define NATIVE SLONG
#endif
/*========== 32 bit sample mixers - only for 32 bit platforms */
#ifndef NATIVE_64BIT_INT
static SLONG Mix32MonoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
{
SWORD sample=0;
SLONG i,f;
while(todo--) {
i=index>>FRACBITS,f=index&FRACMASK;
sample=(((SLONG)(srce[i]*(FRACMASK+1L-f)) +
((SLONG)srce[i+1]*f)) >> FRACBITS);
index+=increment;
if(vnf->rampvol) {
*dest++ += (long)(
( ( (SLONG)(vnf->oldlvol*vnf->rampvol) +
(vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *
(SLONG)sample ) >> CLICK_SHIFT );
vnf->rampvol--;
} else
if(vnf->click) {
*dest++ += (long)(
( ( ((SLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
(SLONG)sample ) +
(vnf->lastvalL*vnf->click) ) >> CLICK_SHIFT );
vnf->click--;
} else
*dest++ +=vnf->lvolsel*sample;
}
vnf->lastvalL=vnf->lvolsel * sample;
return index;
}
static SLONG Mix32StereoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,ULONG todo)
{
SWORD sample=0;
SLONG i,f;
while(todo--) {
i=index>>FRACBITS,f=index&FRACMASK;
sample=((((SLONG)srce[i]*(FRACMASK+1L-f)) +
((SLONG)srce[i+1] * f)) >> FRACBITS);
index += increment;
if(vnf->rampvol) {
*dest++ += (long)(
( ( ((SLONG)vnf->oldlvol*vnf->rampvol) +
(vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol))
) * (SLONG)sample ) >> CLICK_SHIFT );
*dest++ += (long)(
( ( ((SLONG)vnf->oldrvol*vnf->rampvol) +
(vnf->rvolsel*(CLICK_BUFFER-vnf->rampvol))
) * (SLONG)sample ) >> CLICK_SHIFT );
vnf->rampvol--;
} else
if(vnf->click) {
*dest++ += (long)(
( ( (SLONG)(vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
(SLONG)sample ) + (vnf->lastvalL * vnf->click) )
>> CLICK_SHIFT );
*dest++ += (long)(
( ( ((SLONG)vnf->rvolsel*(CLICK_BUFFER-vnf->click)) *
(SLONG)sample ) + (vnf->lastvalR * vnf->click) )
>> CLICK_SHIFT );
vnf->click--;
} else {
*dest++ +=vnf->lvolsel*sample;
*dest++ +=vnf->rvolsel*sample;
}
}
vnf->lastvalL=vnf->lvolsel*sample;
vnf->lastvalR=vnf->rvolsel*sample;
return index;
}
static SLONG Mix32StereoSurround(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,ULONG todo)
{
SWORD sample=0;
long whoop;
SLONG i, f;
while(todo--) {
i=index>>FRACBITS,f=index&FRACMASK;
sample=((((SLONG)srce[i]*(FRACMASK+1L-f)) +
((SLONG)srce[i+1]*f)) >> FRACBITS);
index+=increment;
if(vnf->rampvol) {
whoop=(long)(
( ( (SLONG)(vnf->oldlvol*vnf->rampvol) +
(vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *
(SLONG)sample) >> CLICK_SHIFT );
*dest++ +=whoop;
*dest++ -=whoop;
vnf->rampvol--;
} else
if(vnf->click) {
whoop = (long)(
( ( ((SLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
(SLONG)sample) +
(vnf->lastvalL * vnf->click) ) >> CLICK_SHIFT );
*dest++ +=whoop;
*dest++ -=whoop;
vnf->click--;
} else {
*dest++ +=vnf->lvolsel*sample;
*dest++ -=vnf->lvolsel*sample;
}
}
vnf->lastvalL=vnf->lvolsel*sample;
vnf->lastvalR=vnf->lvolsel*sample;
return index;
}
#endif
/*========== 64 bit mixers */
#ifndef NO_64BIT_MIXER
static SLONGLONG MixMonoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
{
SWORD sample=0;
SLONGLONG i,f;
while(todo--) {
i=index>>FRACBITS,f=index&FRACMASK;
sample=(((SLONGLONG)(srce[i]*(FRACMASK+1L-f)) +
((SLONGLONG)srce[i+1]*f)) >> FRACBITS);
index+=increment;
if(vnf->rampvol) {
*dest++ += (long)(
( ( (SLONGLONG)(vnf->oldlvol*vnf->rampvol) +
(vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *
(SLONGLONG)sample ) >> CLICK_SHIFT );
vnf->rampvol--;
} else
if(vnf->click) {
*dest++ += (long)(
( ( ((SLONGLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
(SLONGLONG)sample ) +
(vnf->lastvalL*vnf->click) ) >> CLICK_SHIFT );
vnf->click--;
} else
*dest++ +=vnf->lvolsel*sample;
}
vnf->lastvalL=vnf->lvolsel * sample;
return index;
}
static SLONGLONG MixStereoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,ULONG todo)
{
SWORD sample=0;
SLONGLONG i,f;
while(todo--) {
i=index>>FRACBITS,f=index&FRACMASK;
sample=((((SLONGLONG)srce[i]*(FRACMASK+1L-f)) +
((SLONGLONG)srce[i+1] * f)) >> FRACBITS);
index += increment;
if(vnf->rampvol) {
*dest++ += (long)(
( ( ((SLONGLONG)vnf->oldlvol*vnf->rampvol) +
(vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol))
) * (SLONGLONG)sample ) >> CLICK_SHIFT );
*dest++ += (long)(
( ( ((SLONGLONG)vnf->oldrvol*vnf->rampvol) +
(vnf->rvolsel*(CLICK_BUFFER-vnf->rampvol))
) * (SLONGLONG)sample ) >> CLICK_SHIFT );
vnf->rampvol--;
} else
if(vnf->click) {
*dest++ += (long)(
( ( (SLONGLONG)(vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
(SLONGLONG)sample ) + (vnf->lastvalL * vnf->click) )
>> CLICK_SHIFT );
*dest++ += (long)(
( ( ((SLONGLONG)vnf->rvolsel*(CLICK_BUFFER-vnf->click)) *
(SLONGLONG)sample ) + (vnf->lastvalR * vnf->click) )
>> CLICK_SHIFT );
vnf->click--;
} else {
*dest++ +=vnf->lvolsel*sample;
*dest++ +=vnf->rvolsel*sample;
}
}
vnf->lastvalL=vnf->lvolsel*sample;
vnf->lastvalR=vnf->rvolsel*sample;
return index;
}
static SLONGLONG MixStereoSurround(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,ULONG todo)
{
SWORD sample=0;
long whoop;
SLONGLONG i, f;
while(todo--) {
i=index>>FRACBITS,f=index&FRACMASK;
sample=((((SLONGLONG)srce[i]*(FRACMASK+1L-f)) +
((SLONGLONG)srce[i+1]*f)) >> FRACBITS);
index+=increment;
if(vnf->rampvol) {
whoop=(long)(
( ( (SLONGLONG)(vnf->oldlvol*vnf->rampvol) +
(vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *
(SLONGLONG)sample) >> CLICK_SHIFT );
*dest++ +=whoop;
*dest++ -=whoop;
vnf->rampvol--;
} else
if(vnf->click) {
whoop = (long)(
( ( ((SLONGLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
(SLONGLONG)sample) +
(vnf->lastvalL * vnf->click) ) >> CLICK_SHIFT );
*dest++ +=whoop;
*dest++ -=whoop;
vnf->click--;
} else {
*dest++ +=vnf->lvolsel*sample;
*dest++ -=vnf->lvolsel*sample;
}
}
vnf->lastvalL=vnf->lvolsel*sample;
vnf->lastvalR=vnf->lvolsel*sample;
return index;
}
#endif /* NO_64BIT_MIXER */
static void(*Mix32to16)(SWORD* dste,SLONG* srce,NATIVE count);
static void(*Mix32to8)(SBYTE* dste,SLONG* srce,NATIVE count);
static void(*MixReverb)(SLONG* srce,NATIVE count);
/* Reverb macros */
#define COMPUTE_LOC(n) loc##n = RVRindex % RVc##n
#define COMPUTE_LECHO(n) RVbufL##n [loc##n ]=speedup+((ReverbPct*RVbufL##n [loc##n ])>>7)
#define COMPUTE_RECHO(n) RVbufR##n [loc##n ]=speedup+((ReverbPct*RVbufR##n [loc##n ])>>7)
static void MixReverb_Normal(SLONG* srce,NATIVE count)
{
NATIVE speedup;
int ReverbPct;
unsigned int loc1,loc2,loc3,loc4,loc5,loc6,loc7,loc8;
ReverbPct=58+(md_reverb*4);
COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);
COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);
while(count--) {
/* Compute the left channel echo buffers */
speedup = *srce >> 3;
COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4);
COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8);
/* Prepare to compute actual finalized data */
RVRindex++;
COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);
COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);
/* left channel */
*srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+
RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];
}
}
static void MixReverb_Stereo(SLONG *srce,NATIVE count)
{
NATIVE speedup;
int ReverbPct;
unsigned int loc1,loc2,loc3,loc4,loc5,loc6,loc7,loc8;
ReverbPct=58+(md_reverb*4);
COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);
COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);
while(count--) {
/* Compute the left channel echo buffers */
speedup = *srce >> 3;
COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4);
COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8);
/* Compute the right channel echo buffers */
speedup = srce[1] >> 3;
COMPUTE_RECHO(1); COMPUTE_RECHO(2); COMPUTE_RECHO(3); COMPUTE_RECHO(4);
COMPUTE_RECHO(5); COMPUTE_RECHO(6); COMPUTE_RECHO(7); COMPUTE_RECHO(8);
/* Prepare to compute actual finalized data */
RVRindex++;
COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);
COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);
/* left channel */
*srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+
RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];
/* right channel */
*srce++ +=RVbufR1[loc1]-RVbufR2[loc2]+RVbufR3[loc3]-RVbufR4[loc4]+
RVbufR5[loc5]-RVbufR6[loc6]+RVbufR7[loc7]-RVbufR8[loc8];
}
}
/* Mixing macros */
#define EXTRACT_SAMPLE(var,attenuation) var=*srce++/(MAXVOL_FACTOR*attenuation)
#define CHECK_SAMPLE(var,bound) var=(var>=bound)?bound-1:(var<-bound)?-bound:var
static void Mix32To16_Normal(SWORD* dste,SLONG* srce,NATIVE count)
{
NATIVE x1,x2,tmpx;
int i;
for(count/=SAMPLING_FACTOR;count;count--) {
tmpx=0;
for(i=SAMPLING_FACTOR/2;i;i--) {
EXTRACT_SAMPLE(x1,1); EXTRACT_SAMPLE(x2,1);
CHECK_SAMPLE(x1,32768); CHECK_SAMPLE(x2,32768);
tmpx+=x1+x2;
}
*dste++ =tmpx/SAMPLING_FACTOR;
}
}
static void Mix32To16_Stereo(SWORD* dste,SLONG* srce,NATIVE count)
{
NATIVE x1,x2,x3,x4,tmpx,tmpy;
int i;
for(count/=SAMPLING_FACTOR;count;count--) {
tmpx=tmpy=0;
for(i=SAMPLING_FACTOR/2;i;i--) {
EXTRACT_SAMPLE(x1,1); EXTRACT_SAMPLE(x2,1);
EXTRACT_SAMPLE(x3,1); EXTRACT_SAMPLE(x4,1);
CHECK_SAMPLE(x1,32768); CHECK_SAMPLE(x2,32768);
CHECK_SAMPLE(x3,32768); CHECK_SAMPLE(x4,32768);
tmpx+=x1+x3;
tmpy+=x2+x4;
}
*dste++ =tmpx/SAMPLING_FACTOR;
*dste++ =tmpy/SAMPLING_FACTOR;
}
}
static void Mix32To8_Normal(SBYTE* dste,SLONG* srce,NATIVE count)
{
NATIVE x1,x2,tmpx;
int i;
for(count/=SAMPLING_FACTOR;count;count--) {
tmpx = 0;
for(i=SAMPLING_FACTOR/2;i;i--) {
EXTRACT_SAMPLE(x1,256); EXTRACT_SAMPLE(x2,256);
CHECK_SAMPLE(x1,128); CHECK_SAMPLE(x2,128);
tmpx+=x1+x2;
}
*dste++ =(tmpx/SAMPLING_FACTOR)+128;
}
}
static void Mix32To8_Stereo(SBYTE* dste,SLONG* srce,NATIVE count)
{
NATIVE x1,x2,x3,x4,tmpx,tmpy;
int i;
for(count/=SAMPLING_FACTOR;count;count--) {
tmpx=tmpy=0;
for(i=SAMPLING_FACTOR/2;i;i--) {
EXTRACT_SAMPLE(x1,256); EXTRACT_SAMPLE(x2,256);
EXTRACT_SAMPLE(x3,256); EXTRACT_SAMPLE(x4,256);
CHECK_SAMPLE(x1,128); CHECK_SAMPLE(x2,128);
CHECK_SAMPLE(x3,128); CHECK_SAMPLE(x4,128);
tmpx+=x1+x3;
tmpy+=x2+x4;
}
*dste++ =(tmpx/SAMPLING_FACTOR)+128;
*dste++ =(tmpy/SAMPLING_FACTOR)+128;
}
}
static void AddChannel(SLONG* ptr,NATIVE todo)
{
SLONGLONG end,done;
SWORD *s;
if(!(s=Samples[vnf->handle])) {
vnf->current = vnf->active = 0;
vnf->lastvalL = vnf->lastvalR = 0;
return;
}
/* update the 'current' index so the sample loops, or stops playing if it
reached the end of the sample */
while(todo>0) {
SLONGLONG endpos;
if(vnf->flags & SF_REVERSE) {
/* The sample is playing in reverse */
if((vnf->flags&SF_LOOP)&&(vnf->current<idxlpos)) {
/* the sample is looping and has reached the loopstart index */
if(vnf->flags & SF_BIDI) {
/* sample is doing bidirectional loops, so 'bounce' the
current index against the idxlpos */
vnf->current = idxlpos+(idxlpos-vnf->current);
vnf->flags &= ~SF_REVERSE;
vnf->increment = -vnf->increment;
} else
/* normal backwards looping, so set the current position to
loopend index */
vnf->current=idxlend-(idxlpos-vnf->current);
} else {
/* the sample is not looping, so check if it reached index 0 */
if(vnf->current < 0) {
/* playing index reached 0, so stop playing this sample */
vnf->current = vnf->active = 0;
break;
}
}
} else {
/* The sample is playing forward */
if((vnf->flags & SF_LOOP) && (vnf->current >= idxlend)) {
/* the sample is looping, check the loopend index */
if(vnf->flags & SF_BIDI) {
/* sample is doing bidirectional loops, so 'bounce' the
current index against the idxlend */
vnf->flags |= SF_REVERSE;
vnf->increment = -vnf->increment;
vnf->current = idxlend-(vnf->current-idxlend);
} else
/* normal backwards looping, so set the current position
to loopend index */
vnf->current=idxlpos+(vnf->current-idxlend);
} else {
/* sample is not looping, so check if it reached the last
position */
if(vnf->current >= idxsize) {
/* yes, so stop playing this sample */
vnf->current = vnf->active = 0;
break;
}
}
}
end=(vnf->flags&SF_REVERSE)?(vnf->flags&SF_LOOP)?idxlpos:0:
(vnf->flags&SF_LOOP)?idxlend:idxsize;
/* if the sample is not blocked... */
if((end==vnf->current)||(!vnf->increment))
done=0;
else {
done=MIN((end-vnf->current)/vnf->increment+1,todo);
if(done<0) done=0;
}
if(!done) {
vnf->active = 0;
break;
}
endpos=vnf->current+done*vnf->increment;
if(vnf->vol || vnf->rampvol) {
#ifndef NATIVE_64BIT_INT
/* use the 32 bit mixers as often as we can (they're much faster) */
if((vnf->current<0x7fffffff)&&(endpos<0x7fffffff)) {
if(vc_mode & DMODE_STEREO) {
if((vnf->pan==PAN_SURROUND)&&(vc_mode&DMODE_SURROUND))
vnf->current=Mix32StereoSurround
(s,ptr,vnf->current,vnf->increment,done);
else
vnf->current=Mix32StereoNormal
(s,ptr,vnf->current,vnf->increment,done);
} else
vnf->current=Mix32MonoNormal
(s,ptr,vnf->current,vnf->increment,done);
} else
#endif
#ifdef NO_64BIT_MIXER
/* Uh oh, the 64-bit mixers don't compile... */;
#else
{
if(vc_mode & DMODE_STEREO) {
if((vnf->pan==PAN_SURROUND)&&(vc_mode&DMODE_SURROUND))
vnf->current=MixStereoSurround
(s,ptr,vnf->current,vnf->increment,done);
else
vnf->current=MixStereoNormal
(s,ptr,vnf->current,vnf->increment,done);
} else
vnf->current=MixMonoNormal
(s,ptr,vnf->current,vnf->increment,done);
}
#endif
} else {
vnf->lastvalL = vnf->lastvalR = 0;
/* update sample position */
vnf->current=endpos;
}
todo -= done;
#if 1
if ( vc_mode & DMODE_STEREO ) {
ptr += done*2;
} else {
ptr += done;
}
#else
ptr +=(vc_mode & DMODE_STEREO)?(done<<1):done;
#endif
}
}
#define _IN_VIRTCH_
#define VC1_SilenceBytes VC2_SilenceBytes
#define VC1_WriteSamples VC2_WriteSamples
#define VC1_WriteBytes VC2_WriteBytes
#define VC1_Exit VC2_Exit
#define VC1_VoiceSetVolume VC2_VoiceSetVolume
#define VC1_VoiceGetVolume VC2_VoiceGetVolume
#define VC1_VoiceSetPanning VC2_VoiceSetPanning
#define VC1_VoiceGetPanning VC2_VoiceGetPanning
#define VC1_VoiceSetFrequency VC2_VoiceSetFrequency
#define VC1_VoiceGetFrequency VC2_VoiceGetFrequency
#define VC1_VoicePlay VC2_VoicePlay
#define VC1_VoiceStop VC2_VoiceStop
#define VC1_VoiceStopped VC2_VoiceStopped
#define VC1_VoiceGetPosition VC2_VoiceGetPosition
#define VC1_SampleUnload VC2_SampleUnload
#define VC1_SampleLoad VC2_SampleLoad
#define VC1_SampleSpace VC2_SampleSpace
#define VC1_SampleLength VC2_SampleLength
#define VC1_VoiceRealVolume VC2_VoiceRealVolume
#include "virtch_common.c"
#undef _IN_VIRTCH_
void VC2_WriteSamples(SBYTE* buf,ULONG todo)
{
int left,portion=0;
SBYTE *buffer;
int t,pan,vol;
todo*=SAMPLING_FACTOR;
while(todo) {
if(!tickleft) {
if(vc_mode & DMODE_SOFT_MUSIC) md_player();
tickleft=(md_mixfreq*125L*SAMPLING_FACTOR)/(md_bpm*50L);
tickleft&=~(SAMPLING_FACTOR-1);
}
left = MIN(tickleft, todo);
buffer = buf;
tickleft -= left;
todo -= left;
buf += samples2bytes(left)/SAMPLING_FACTOR;
while(left) {
portion = MIN(left, samplesthatfit);
memset(vc_tickbuf,0,portion<<((vc_mode&DMODE_STEREO)?3:2));
for(t=0;t<vc_softchn;t++) {
vnf = &vinf[t];
if(vnf->kick) {
vnf->current=((SLONGLONG)(vnf->start))<<FRACBITS;
vnf->kick = 0;
vnf->active = 1;
vnf->click = CLICK_BUFFER;
vnf->rampvol = 0;
}
if(!vnf->frq) vnf->active = 0;
if(vnf->active) {
vnf->increment=((SLONGLONG)(vnf->frq)<<(FRACBITS-SAMPLING_SHIFT))
/md_mixfreq;
if(vnf->flags&SF_REVERSE) vnf->increment=-vnf->increment;
vol = vnf->vol; pan = vnf->pan;
vnf->oldlvol=vnf->lvolsel;vnf->oldrvol=vnf->rvolsel;
if(vc_mode & DMODE_STEREO) {
if(pan!=PAN_SURROUND) {
vnf->lvolsel=(vol*(PAN_RIGHT-pan))>>8;
vnf->rvolsel=(vol*pan)>>8;
} else {
vnf->lvolsel=vnf->rvolsel=(vol * 256L) / 480;
}
} else
vnf->lvolsel=vol;
idxsize=(vnf->size)?((SLONGLONG)(vnf->size)<<FRACBITS)-1:0;
idxlend=(vnf->repend)?((SLONGLONG)(vnf->repend)<<FRACBITS)-1:0;
idxlpos=(SLONGLONG)(vnf->reppos)<<FRACBITS;
AddChannel(vc_tickbuf,portion);
}
}
if(md_reverb) {
if(md_reverb>15) md_reverb=15;
MixReverb(vc_tickbuf,portion);
}
if(vc_mode & DMODE_16BITS)
Mix32to16((SWORD*)buffer,vc_tickbuf,portion);
else
Mix32to8((SBYTE*)buffer,vc_tickbuf,portion);
buffer += samples2bytes(portion) / SAMPLING_FACTOR;
left -= portion;
}
}
}
BOOL VC2_Init(void)
{
VC_SetupPointers();
if (!(md_mode&DMODE_HQMIXER))
return VC1_Init();
if(!(Samples=(SWORD**)_mm_calloc(MAXSAMPLEHANDLES,sizeof(SWORD*)))) {
_mm_errno = MMERR_INITIALIZING_MIXER;
return 1;
}
if(!vc_tickbuf)
if(!(vc_tickbuf=(SLONG*)_mm_malloc((TICKLSIZE+32)*sizeof(SLONG)))) {
_mm_errno = MMERR_INITIALIZING_MIXER;
return 1;
}
if(md_mode & DMODE_STEREO) {
Mix32to16 = Mix32To16_Stereo;
Mix32to8 = Mix32To8_Stereo;
MixReverb = MixReverb_Stereo;
} else {
Mix32to16 = Mix32To16_Normal;
Mix32to8 = Mix32To8_Normal;
MixReverb = MixReverb_Normal;
}
md_mode |= DMODE_INTERP;
vc_mode = md_mode;
return 0;
}
BOOL VC2_PlayStart(void)
{
md_mode|=DMODE_INTERP;
samplesthatfit = TICKLSIZE;
if(vc_mode & DMODE_STEREO) samplesthatfit >>= 1;
tickleft = 0;
RVc1 = (5000L * md_mixfreq) / (REVERBERATION * 10);
RVc2 = (5078L * md_mixfreq) / (REVERBERATION * 10);
RVc3 = (5313L * md_mixfreq) / (REVERBERATION * 10);
RVc4 = (5703L * md_mixfreq) / (REVERBERATION * 10);
RVc5 = (6250L * md_mixfreq) / (REVERBERATION * 10);
RVc6 = (6953L * md_mixfreq) / (REVERBERATION * 10);
RVc7 = (7813L * md_mixfreq) / (REVERBERATION * 10);
RVc8 = (8828L * md_mixfreq) / (REVERBERATION * 10);
if(!(RVbufL1=(SLONG*)_mm_calloc((RVc1+1),sizeof(SLONG)))) return 1;
if(!(RVbufL2=(SLONG*)_mm_calloc((RVc2+1),sizeof(SLONG)))) return 1;
if(!(RVbufL3=(SLONG*)_mm_calloc((RVc3+1),sizeof(SLONG)))) return 1;
if(!(RVbufL4=(SLONG*)_mm_calloc((RVc4+1),sizeof(SLONG)))) return 1;
if(!(RVbufL5=(SLONG*)_mm_calloc((RVc5+1),sizeof(SLONG)))) return 1;
if(!(RVbufL6=(SLONG*)_mm_calloc((RVc6+1),sizeof(SLONG)))) return 1;
if(!(RVbufL7=(SLONG*)_mm_calloc((RVc7+1),sizeof(SLONG)))) return 1;
if(!(RVbufL8=(SLONG*)_mm_calloc((RVc8+1),sizeof(SLONG)))) return 1;
if(!(RVbufR1=(SLONG*)_mm_calloc((RVc1+1),sizeof(SLONG)))) return 1;
if(!(RVbufR2=(SLONG*)_mm_calloc((RVc2+1),sizeof(SLONG)))) return 1;
if(!(RVbufR3=(SLONG*)_mm_calloc((RVc3+1),sizeof(SLONG)))) return 1;
if(!(RVbufR4=(SLONG*)_mm_calloc((RVc4+1),sizeof(SLONG)))) return 1;
if(!(RVbufR5=(SLONG*)_mm_calloc((RVc5+1),sizeof(SLONG)))) return 1;
if(!(RVbufR6=(SLONG*)_mm_calloc((RVc6+1),sizeof(SLONG)))) return 1;
if(!(RVbufR7=(SLONG*)_mm_calloc((RVc7+1),sizeof(SLONG)))) return 1;
if(!(RVbufR8=(SLONG*)_mm_calloc((RVc8+1),sizeof(SLONG)))) return 1;
RVRindex = 0;
return 0;
}
void VC2_PlayStop(void)
{
if(RVbufL1) free(RVbufL1);
if(RVbufL2) free(RVbufL2);
if(RVbufL3) free(RVbufL3);
if(RVbufL4) free(RVbufL4);
if(RVbufL5) free(RVbufL5);
if(RVbufL6) free(RVbufL6);
if(RVbufL7) free(RVbufL7);
if(RVbufL8) free(RVbufL8);
if(RVbufR1) free(RVbufR1);
if(RVbufR2) free(RVbufR2);
if(RVbufR3) free(RVbufR3);
if(RVbufR4) free(RVbufR4);
if(RVbufR5) free(RVbufR5);
if(RVbufR6) free(RVbufR6);
if(RVbufR7) free(RVbufR7);
if(RVbufR8) free(RVbufR8);
RVbufL1=RVbufL2=RVbufL3=RVbufL4=RVbufL5=RVbufL6=RVbufL7=RVbufL8=NULL;
RVbufR1=RVbufR2=RVbufR3=RVbufR4=RVbufR5=RVbufR6=RVbufR7=RVbufR8=NULL;
}
BOOL VC2_SetNumVoices(void)
{
int t;
md_mode|=DMODE_INTERP;
if(!(vc_softchn=md_softchn)) return 0;
if(vinf) free(vinf);
if(!(vinf=_mm_calloc(sizeof(VINFO),vc_softchn))) return 1;
for(t=0;t<vc_softchn;t++) {
vinf[t].frq=10000;
vinf[t].pan=(t&1)?PAN_LEFT:PAN_RIGHT;
}
return 0;
}
/* ex:set ts=4: */
#endif
@@ -0,0 +1,453 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id$
Common source parts between the two software mixers.
This file is probably the ugliest part of libmikmod...
==============================================================================*/
#ifdef SOUNDMODULE_OPENAL
#ifndef _IN_VIRTCH_
#include "mikmod_internals.h"
extern BOOL VC1_Init(void);
extern BOOL VC2_Init(void);
static BOOL (*VC_Init_ptr)(void)=VC1_Init;
extern void VC1_Exit(void);
extern void VC2_Exit(void);
static void (*VC_Exit_ptr)(void)=VC1_Exit;
extern BOOL VC1_SetNumVoices(void);
extern BOOL VC2_SetNumVoices(void);
static BOOL (*VC_SetNumVoices_ptr)(void);
extern ULONG VC1_SampleSpace(int);
extern ULONG VC2_SampleSpace(int);
static ULONG (*VC_SampleSpace_ptr)(int);
extern ULONG VC1_SampleLength(int,SAMPLE*);
extern ULONG VC2_SampleLength(int,SAMPLE*);
static ULONG (*VC_SampleLength_ptr)(int,SAMPLE*);
extern BOOL VC1_PlayStart(void);
extern BOOL VC2_PlayStart(void);
static BOOL (*VC_PlayStart_ptr)(void);
extern void VC1_PlayStop(void);
extern void VC2_PlayStop(void);
static void (*VC_PlayStop_ptr)(void);
extern SWORD VC1_SampleLoad(struct SAMPLOAD*,int);
extern SWORD VC2_SampleLoad(struct SAMPLOAD*,int);
static SWORD (*VC_SampleLoad_ptr)(struct SAMPLOAD*,int);
extern void VC1_SampleUnload(SWORD);
extern void VC2_SampleUnload(SWORD);
static void (*VC_SampleUnload_ptr)(SWORD);
extern ULONG VC1_WriteBytes(SBYTE*,ULONG);
extern ULONG VC2_WriteBytes(SBYTE*,ULONG);
static ULONG (*VC_WriteBytes_ptr)(SBYTE*,ULONG);
extern ULONG VC1_SilenceBytes(SBYTE*,ULONG);
extern ULONG VC2_SilenceBytes(SBYTE*,ULONG);
static ULONG (*VC_SilenceBytes_ptr)(SBYTE*,ULONG);
extern void VC1_VoiceSetVolume(UBYTE,UWORD);
extern void VC2_VoiceSetVolume(UBYTE,UWORD);
static void (*VC_VoiceSetVolume_ptr)(UBYTE,UWORD);
extern UWORD VC1_VoiceGetVolume(UBYTE);
extern UWORD VC2_VoiceGetVolume(UBYTE);
static UWORD (*VC_VoiceGetVolume_ptr)(UBYTE);
extern void VC1_VoiceSetFrequency(UBYTE,ULONG);
extern void VC2_VoiceSetFrequency(UBYTE,ULONG);
static void (*VC_VoiceSetFrequency_ptr)(UBYTE,ULONG);
extern ULONG VC1_VoiceGetFrequency(UBYTE);
extern ULONG VC2_VoiceGetFrequency(UBYTE);
static ULONG (*VC_VoiceGetFrequency_ptr)(UBYTE);
extern void VC1_VoiceSetPanning(UBYTE,ULONG);
extern void VC2_VoiceSetPanning(UBYTE,ULONG);
static void (*VC_VoiceSetPanning_ptr)(UBYTE,ULONG);
extern ULONG VC1_VoiceGetPanning(UBYTE);
extern ULONG VC2_VoiceGetPanning(UBYTE);
static ULONG (*VC_VoiceGetPanning_ptr)(UBYTE);
extern void VC1_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
extern void VC2_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
static void (*VC_VoicePlay_ptr)(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
extern void VC1_VoiceStop(UBYTE);
extern void VC2_VoiceStop(UBYTE);
static void (*VC_VoiceStop_ptr)(UBYTE);
extern BOOL VC1_VoiceStopped(UBYTE);
extern BOOL VC2_VoiceStopped(UBYTE);
static BOOL (*VC_VoiceStopped_ptr)(UBYTE);
extern SLONG VC1_VoiceGetPosition(UBYTE);
extern SLONG VC2_VoiceGetPosition(UBYTE);
static SLONG (*VC_VoiceGetPosition_ptr)(UBYTE);
extern ULONG VC1_VoiceRealVolume(UBYTE);
extern ULONG VC2_VoiceRealVolume(UBYTE);
static ULONG (*VC_VoiceRealVolume_ptr)(UBYTE);
#ifdef __STDC__
#define VC_PROC0(suffix) \
void VC_##suffix (void) { VC_##suffix##_ptr(); }
#define VC_FUNC0(suffix,ret) \
ret VC_##suffix (void) { return VC_##suffix##_ptr(); }
#define VC_PROC1(suffix,typ1) \
void VC_##suffix (typ1 a) { VC_##suffix##_ptr(a); }
#define VC_FUNC1(suffix,ret,typ1) \
ret VC_##suffix (typ1 a) { return VC_##suffix##_ptr(a); }
#define VC_PROC2(suffix,typ1,typ2) \
void VC_##suffix (typ1 a,typ2 b) { VC_##suffix##_ptr(a,b); }
#define VC_FUNC2(suffix,ret,typ1,typ2) \
ret VC_##suffix (typ1 a,typ2 b) { return VC_##suffix##_ptr(a,b); }
#else
#define VC_PROC0(suffix) \
void VC_/**/suffix/**/(void) { VC_/**/suffix/**/_ptr(); }
#define VC_FUNC0(suffix,ret) \
ret VC_/**/suffix/**/(void) { return VC_/**/suffix/**/_ptr(); }
#define VC_PROC1(suffix,typ1) \
void VC_/**/suffix/**/(typ1 a) { VC_/**/suffix/**/_ptr(a); }
#define VC_FUNC1(suffix,ret,typ1) \
ret VC_/**/suffix/**/(typ1 a) { return VC_/**/suffix/**/_ptr(a); }
#define VC_PROC2(suffix,typ1,typ2) \
void VC_/**/suffix/**/(typ1 a,typ2 b) { VC_/**/suffix/**/_ptr(a,b); }
#define VC_FUNC2(suffix,ret,typ1,typ2) \
ret VC_/**/suffix/**/(typ1 a,typ2 b) { return VC_/**/suffix/**/_ptr(a,b); }
#endif
VC_FUNC0(Init,BOOL);
VC_PROC0(Exit)
VC_FUNC0(SetNumVoices,BOOL)
VC_FUNC1(SampleSpace,ULONG,int)
VC_FUNC2(SampleLength,ULONG,int,SAMPLE*)
VC_FUNC0(PlayStart,BOOL)
VC_PROC0(PlayStop)
VC_FUNC2(SampleLoad,SWORD,struct SAMPLOAD*,int)
VC_PROC1(SampleUnload,SWORD)
VC_FUNC2(WriteBytes,ULONG,SBYTE*,ULONG)
VC_FUNC2(SilenceBytes,ULONG,SBYTE*,ULONG)
VC_PROC2(VoiceSetVolume,UBYTE,UWORD)
VC_FUNC1(VoiceGetVolume,UWORD,UBYTE)
VC_PROC2(VoiceSetFrequency,UBYTE,ULONG)
VC_FUNC1(VoiceGetFrequency,ULONG,UBYTE)
VC_PROC2(VoiceSetPanning,UBYTE,ULONG)
VC_FUNC1(VoiceGetPanning,ULONG,UBYTE)
void VC_VoicePlay(UBYTE a,SWORD b,ULONG c,ULONG d,ULONG e,ULONG f,UWORD g)
{ VC_VoicePlay_ptr(a,b,c,d,e,f,g); }
VC_PROC1(VoiceStop,UBYTE)
VC_FUNC1(VoiceStopped,BOOL,UBYTE)
VC_FUNC1(VoiceGetPosition,SLONG,UBYTE)
VC_FUNC1(VoiceRealVolume,ULONG,UBYTE)
void VC_SetupPointers(void)
{
if (md_mode&DMODE_HQMIXER) {
VC_Init_ptr=VC2_Init;
VC_Exit_ptr=VC2_Exit;
VC_SetNumVoices_ptr=VC2_SetNumVoices;
VC_SampleSpace_ptr=VC2_SampleSpace;
VC_SampleLength_ptr=VC2_SampleLength;
VC_PlayStart_ptr=VC2_PlayStart;
VC_PlayStop_ptr=VC2_PlayStop;
VC_SampleLoad_ptr=VC2_SampleLoad;
VC_SampleUnload_ptr=VC2_SampleUnload;
VC_WriteBytes_ptr=VC2_WriteBytes;
VC_SilenceBytes_ptr=VC2_SilenceBytes;
VC_VoiceSetVolume_ptr=VC2_VoiceSetVolume;
VC_VoiceGetVolume_ptr=VC2_VoiceGetVolume;
VC_VoiceSetFrequency_ptr=VC2_VoiceSetFrequency;
VC_VoiceGetFrequency_ptr=VC2_VoiceGetFrequency;
VC_VoiceSetPanning_ptr=VC2_VoiceSetPanning;
VC_VoiceGetPanning_ptr=VC2_VoiceGetPanning;
VC_VoicePlay_ptr=VC2_VoicePlay;
VC_VoiceStop_ptr=VC2_VoiceStop;
VC_VoiceStopped_ptr=VC2_VoiceStopped;
VC_VoiceGetPosition_ptr=VC2_VoiceGetPosition;
VC_VoiceRealVolume_ptr=VC2_VoiceRealVolume;
} else {
VC_Init_ptr=VC1_Init;
VC_Exit_ptr=VC1_Exit;
VC_SetNumVoices_ptr=VC1_SetNumVoices;
VC_SampleSpace_ptr=VC1_SampleSpace;
VC_SampleLength_ptr=VC1_SampleLength;
VC_PlayStart_ptr=VC1_PlayStart;
VC_PlayStop_ptr=VC1_PlayStop;
VC_SampleLoad_ptr=VC1_SampleLoad;
VC_SampleUnload_ptr=VC1_SampleUnload;
VC_WriteBytes_ptr=VC1_WriteBytes;
VC_SilenceBytes_ptr=VC1_SilenceBytes;
VC_VoiceSetVolume_ptr=VC1_VoiceSetVolume;
VC_VoiceGetVolume_ptr=VC1_VoiceGetVolume;
VC_VoiceSetFrequency_ptr=VC1_VoiceSetFrequency;
VC_VoiceGetFrequency_ptr=VC1_VoiceGetFrequency;
VC_VoiceSetPanning_ptr=VC1_VoiceSetPanning;
VC_VoiceGetPanning_ptr=VC1_VoiceGetPanning;
VC_VoicePlay_ptr=VC1_VoicePlay;
VC_VoiceStop_ptr=VC1_VoiceStop;
VC_VoiceStopped_ptr=VC1_VoiceStopped;
VC_VoiceGetPosition_ptr=VC1_VoiceGetPosition;
VC_VoiceRealVolume_ptr=VC1_VoiceRealVolume;
}
}
#else
#ifndef _VIRTCH_COMMON_
#define _VIRTCH_COMMON_
static ULONG samples2bytes(ULONG samples)
{
if(vc_mode & DMODE_16BITS) samples <<= 1;
if(vc_mode & DMODE_STEREO) samples <<= 1;
return samples;
}
static ULONG bytes2samples(ULONG bytes)
{
if(vc_mode & DMODE_16BITS) bytes >>= 1;
if(vc_mode & DMODE_STEREO) bytes >>= 1;
return bytes;
}
/* Fill the buffer with 'todo' bytes of silence (it depends on the mixing mode
how the buffer is filled) */
ULONG VC1_SilenceBytes(SBYTE* buf,ULONG todo)
{
todo=samples2bytes(bytes2samples(todo));
/* clear the buffer to zero (16 bits signed) or 0x80 (8 bits unsigned) */
if(vc_mode & DMODE_16BITS)
memset(buf,0,todo);
else
memset(buf,0x80,todo);
return todo;
}
void VC1_WriteSamples(SBYTE*,ULONG);
/* Writes 'todo' mixed SBYTES (!!) to 'buf'. It returns the number of SBYTES
actually written to 'buf' (which is rounded to number of samples that fit
into 'todo' bytes). */
ULONG VC1_WriteBytes(SBYTE* buf,ULONG todo)
{
if(!vc_softchn)
return VC1_SilenceBytes(buf,todo);
todo = bytes2samples(todo);
VC1_WriteSamples(buf,todo);
return samples2bytes(todo);
}
void VC1_Exit(void)
{
if(vc_tickbuf) free(vc_tickbuf);
if(vinf) free(vinf);
if(Samples) free(Samples);
vc_tickbuf = NULL;
vinf = NULL;
Samples = NULL;
VC_SetupPointers();
}
UWORD VC1_VoiceGetVolume(UBYTE voice)
{
return vinf[voice].vol;
}
ULONG VC1_VoiceGetPanning(UBYTE voice)
{
return vinf[voice].pan;
}
void VC1_VoiceSetFrequency(UBYTE voice,ULONG frq)
{
vinf[voice].frq=frq;
}
ULONG VC1_VoiceGetFrequency(UBYTE voice)
{
return vinf[voice].frq;
}
void VC1_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags)
{
vinf[voice].flags = flags;
vinf[voice].handle = handle;
vinf[voice].start = start;
vinf[voice].size = size;
vinf[voice].reppos = reppos;
vinf[voice].repend = repend;
vinf[voice].kick = 1;
}
void VC1_VoiceStop(UBYTE voice)
{
vinf[voice].active = 0;
}
BOOL VC1_VoiceStopped(UBYTE voice)
{
return(vinf[voice].active==0);
}
SLONG VC1_VoiceGetPosition(UBYTE voice)
{
return(vinf[voice].current>>FRACBITS);
}
void VC1_VoiceSetVolume(UBYTE voice,UWORD vol)
{
/* protect against clicks if volume variation is too high */
if(abs((int)vinf[voice].vol-(int)vol)>32)
vinf[voice].rampvol=CLICK_BUFFER;
vinf[voice].vol=vol;
}
void VC1_VoiceSetPanning(UBYTE voice,ULONG pan)
{
/* protect against clicks if panning variation is too high */
if(abs((int)vinf[voice].pan-(int)pan)>48)
vinf[voice].rampvol=CLICK_BUFFER;
vinf[voice].pan=pan;
}
/*========== External mixer interface */
void VC1_SampleUnload(SWORD handle)
{
if (Samples && handle<MAXSAMPLEHANDLES) {
if (Samples[handle])
free(Samples[handle]);
Samples[handle]=NULL;
}
}
SWORD VC1_SampleLoad(struct SAMPLOAD* sload,int type)
{
SAMPLE *s = sload->sample;
int handle;
ULONG t, length,loopstart,loopend;
if(type==MD_HARDWARE) return -1;
/* Find empty slot to put sample address in */
for(handle=0;handle<MAXSAMPLEHANDLES;handle++)
if(!Samples[handle]) break;
if(handle==MAXSAMPLEHANDLES) {
_mm_errno = MMERR_OUT_OF_HANDLES;
return -1;
}
length = s->length;
loopstart = s->loopstart;
loopend = s->loopend;
SL_SampleSigned(sload);
SL_Sample8to16(sload);
if(!(Samples[handle]=(SWORD*)_mm_malloc((length+20)<<1))) {
_mm_errno = MMERR_SAMPLE_TOO_BIG;
return -1;
}
/* read sample into buffer */
if (SL_Load(Samples[handle],sload,length))
return -1;
/* Unclick sample */
if(s->flags & SF_LOOP) {
if(s->flags & SF_BIDI)
for(t=0;t<16;t++)
Samples[handle][loopend+t]=Samples[handle][(loopend-t)-1];
else
for(t=0;t<16;t++)
Samples[handle][loopend+t]=Samples[handle][t+loopstart];
} else
for(t=0;t<16;t++)
Samples[handle][t+length]=0;
return handle;
}
ULONG VC1_SampleSpace(int type)
{
return vc_memory;
}
ULONG VC1_SampleLength(int type,SAMPLE* s)
{
if (!s) return 0;
return (s->length*((s->flags&SF_16BITS)?2:1))+16;
}
ULONG VC1_VoiceRealVolume(UBYTE voice)
{
ULONG i,s,size;
int k,j;
SWORD *smp;
SLONG t;
t = vinf[voice].current>>FRACBITS;
if(!vinf[voice].active) return 0;
s = vinf[voice].handle;
size = vinf[voice].size;
i=64; t-=64; k=0; j=0;
if(i>size) i = size;
if(t<0) t = 0;
if(t+i > size) t = size-i;
i &= ~1; /* make sure it's EVEN. */
smp = &Samples[s][t];
for(;i;i--,smp++) {
if(k<*smp) k = *smp;
if(j>*smp) j = *smp;
}
return abs(k-j);
}
#endif
#endif
/* ex:set ts=4: */
#endif
@@ -0,0 +1,177 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2000 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
/* NOTE by Mika: Wav loader, (c) Creative, taken from their OpenAL
* implementation and modified.
*/
#ifdef SOUNDMODULE_OPENAL
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "wav.h"
#if defined _MSC_VER
#pragma pack (push,1) /* Turn off alignment */
#elif defined __GNUC__
#define PADOFF_VAR __attribute__((packed))
#endif
#ifndef PADOFF_VAR
#define PADOFF_VAR
#endif
typedef struct /* WAV File-header */
{
ALubyte Id[4] PADOFF_VAR;
ALsizei Size PADOFF_VAR;
ALubyte Type[4] PADOFF_VAR;
} WAVFileHdr_Struct;
typedef struct /* WAV Fmt-header */
{
ALushort Format PADOFF_VAR;
ALushort Channels PADOFF_VAR;
ALuint SamplesPerSec PADOFF_VAR;
ALuint BytesPerSec PADOFF_VAR;
ALushort BlockAlign PADOFF_VAR;
ALushort BitsPerSample PADOFF_VAR;
} WAVFmtHdr_Struct;
typedef struct /* WAV FmtEx-header */
{
ALushort Size PADOFF_VAR;
ALushort SamplesPerBlock PADOFF_VAR;
} WAVFmtExHdr_Struct;
typedef struct /* WAV Smpl-header */
{
ALuint Manufacturer PADOFF_VAR;
ALuint Product PADOFF_VAR;
ALuint SamplePeriod PADOFF_VAR;
ALuint Note PADOFF_VAR;
ALuint FineTune PADOFF_VAR;
ALuint SMPTEFormat PADOFF_VAR;
ALuint SMPTEOffest PADOFF_VAR;
ALuint Loops PADOFF_VAR;
ALuint SamplerData PADOFF_VAR;
struct
{
ALuint Identifier PADOFF_VAR;
ALuint Type PADOFF_VAR;
ALuint Start PADOFF_VAR;
ALuint End PADOFF_VAR;
ALuint Fraction PADOFF_VAR;
ALuint Count PADOFF_VAR;
} Loop[1] PADOFF_VAR;
} WAVSmplHdr_Struct;
typedef struct /* WAV Chunk-header */
{
ALubyte Id[4] PADOFF_VAR;
ALuint Size PADOFF_VAR;
} WAVChunkHdr_Struct;
#ifdef PADOFF_VAR /* Default alignment */
#undef PADOFF_VAR
#endif
#if defined _MSC_VER
#pragma pack (pop)
#endif
void LoadWAVFile (ALbyte *file, ALenum *format, ALvoid **data, ALsizei *size, ALsizei *freq, ALboolean *loop)
{
WAVChunkHdr_Struct ChunkHdr;
WAVFmtExHdr_Struct FmtExHdr;
WAVFileHdr_Struct FileHdr;
WAVSmplHdr_Struct SmplHdr;
WAVFmtHdr_Struct FmtHdr;
FILE *Stream;
*format=AL_FORMAT_MONO16;
*data=NULL;
*size=0;
*freq=22050;
*loop=AL_FALSE;
if (file)
{
Stream=fopen(file,"rb");
if (Stream)
{
fread(&FileHdr,1,sizeof(WAVFileHdr_Struct),Stream);
FileHdr.Size=((FileHdr.Size+1)&~1)-4;
while ((FileHdr.Size!=0)&&(fread(&ChunkHdr,1,sizeof(WAVChunkHdr_Struct),Stream)))
{
if (!memcmp(ChunkHdr.Id,"fmt ",4))
{
fread(&FmtHdr,1,sizeof(WAVFmtHdr_Struct),Stream);
if (FmtHdr.Format==0x0001)
{
*format=(FmtHdr.Channels==1?
(FmtHdr.BitsPerSample==8?AL_FORMAT_MONO8:AL_FORMAT_MONO16):
(FmtHdr.BitsPerSample==8?AL_FORMAT_STEREO8:AL_FORMAT_STEREO16));
*freq=FmtHdr.SamplesPerSec;
fseek(Stream,ChunkHdr.Size-sizeof(WAVFmtHdr_Struct),SEEK_CUR);
}
else
{
fread(&FmtExHdr,1,sizeof(WAVFmtExHdr_Struct),Stream);
fseek(Stream,ChunkHdr.Size-sizeof(WAVFmtHdr_Struct)-sizeof(WAVFmtExHdr_Struct),SEEK_CUR);
}
}
else if (!memcmp(ChunkHdr.Id,"data",4))
{
if (FmtHdr.Format==0x0001)
{
*size=ChunkHdr.Size;
*data=malloc(ChunkHdr.Size+31);
if (*data) fread(*data,FmtHdr.BlockAlign,ChunkHdr.Size/FmtHdr.BlockAlign,Stream);
memset(((char *)*data)+ChunkHdr.Size,0,31);
}
else if (FmtHdr.Format==0x0011)
{
//IMA ADPCM
}
else if (FmtHdr.Format==0x0055)
{
//MP3 WAVE
}
}
else if (!memcmp(ChunkHdr.Id,"smpl",4))
{
fread(&SmplHdr,1,sizeof(WAVSmplHdr_Struct),Stream);
*loop = (SmplHdr.Loops ? AL_TRUE : AL_FALSE);
fseek(Stream,ChunkHdr.Size-sizeof(WAVSmplHdr_Struct),SEEK_CUR);
}
else fseek(Stream,ChunkHdr.Size,SEEK_CUR);
fseek(Stream,ChunkHdr.Size&1,SEEK_CUR);
FileHdr.Size-=(((ChunkHdr.Size+1)&~1)+8);
}
fclose(Stream);
}
}
}
#endif
@@ -0,0 +1,36 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2000 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
/* NOTE by Mika: Wav loader, (c) Creative, taken from their OpenAL
* implementation and modified.
*/
#ifndef WAV_H
#define WAV_H
#ifdef WIN32
#include <al.h>
#else
#include <AL/al.h>
#endif
void LoadWAVFile (ALbyte *file,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq, ALboolean *loop);
#endif
+10 -7
View File
@@ -156,20 +156,22 @@ _GetMusicData (FILE *fp, DWORD length)
}
fprintf (stderr, "_GetMusicData(): loading %s\n", filename);
if (((*pmus)->decoder = Sound_NewSampleFromFile (filename, NULL, 4096)) == 0)
if (((*pmus)->decoder = SoundDecoder_Load (filename, 16384)) == 0)
{
fprintf (stderr, "_GetMusicData(): couldn't load %s\n", filename);
UnlockMusicData (h);
mem_release (h);
h = 0;
HFree (*pmus);
}
else
{
fprintf (stderr, "decoder %s rate %d channels %d\n", (*pmus)->decoder->decoder->description,
(*pmus)->decoder->actual.rate, (*pmus)->decoder->actual.channels);
alGenBuffers (NUM_SOUNDBUFFERS, (*pmus)->buffer);
fprintf (stderr, " decoder: %s, rate %d format %x\n", (*pmus)->decoder->decoder_info,
(*pmus)->decoder->frequency, (*pmus)->decoder->format);
(*pmus)->num_buffers = 16;
(*pmus)->buffer = (ALuint *) HMalloc (sizeof (ALuint) * (*pmus)->num_buffers);
alGenBuffers ((*pmus)->num_buffers, (*pmus)->buffer);
}
}
@@ -199,8 +201,9 @@ _ReleaseMusicData (MEM_HANDLE handle)
}
UnlockMutex (soundSource[MUSIC_SOURCE].stream_mutex);
Sound_FreeSample ((*pmus)->decoder);
alDeleteBuffers (NUM_SOUNDBUFFERS, (*pmus)->buffer);
SoundDecoder_Free ((*pmus)->decoder);
alDeleteBuffers ((*pmus)->num_buffers, (*pmus)->buffer);
HFree ((*pmus)->buffer);
}
HFree (*pmus);
+16 -19
View File
@@ -31,10 +31,7 @@ void
PlayChannel (COUNT channel, PVOID sample, COUNT sample_length, COUNT loop_begin,
COUNT loop_length, unsigned char priority)
{
TFB_SoundSample *tfb_sample = *(TFB_SoundSample**) sample;
//fprintf (stderr, "PlayChannel %d tfb_sample %x\n", channel, tfb_sample);
TFB_SoundSample *tfb_sample = *(TFB_SoundSample**) sample;
soundSource[channel].sample = tfb_sample;
alSourceRewind (soundSource[channel].handle);
alSourcei (soundSource[channel].handle, AL_BUFFER, tfb_sample->buffer[0]);
@@ -138,7 +135,7 @@ _GetSoundBankData (FILE *fp, DWORD length)
fprintf (stderr, "_GetSoundBankData(): loading %s\n", filename);
sndfx[snd_ct] = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
sndfx[snd_ct]->decoder = Sound_NewSampleFromFile (filename, NULL, 4096);
sndfx[snd_ct]->decoder = SoundDecoder_Load (filename, 4096);
if (!sndfx[snd_ct]->decoder)
{
fprintf (stderr, "_GetSoundBankData(): couldn't load %s\n", filename);
@@ -146,20 +143,19 @@ _GetSoundBankData (FILE *fp, DWORD length)
}
else
{
Uint32 decoded_bytes;
ALenum format;
decoded_bytes = Sound_DecodeAll (sndfx[snd_ct]->decoder);
//fprintf (stderr, "decoded_bytes %d\n", decoded_bytes);
format = DetermineALFormat (sndfx[snd_ct]->decoder);
ALuint decoded_bytes;
alGenBuffers (NUM_SOUNDBUFFERS, sndfx[snd_ct]->buffer);
alBufferData (sndfx[snd_ct]->buffer[0], format,
decoded_bytes = SoundDecoder_DecodeAll (sndfx[snd_ct]->decoder);
//fprintf (stderr, "_GetSoundBankData(): decoded_bytes %d\n", decoded_bytes);
sndfx[snd_ct]->num_buffers = 1;
sndfx[snd_ct]->buffer = (ALuint *) HMalloc (sizeof (ALuint) * sndfx[snd_ct]->num_buffers);
alGenBuffers (sndfx[snd_ct]->num_buffers, sndfx[snd_ct]->buffer);
alBufferData (sndfx[snd_ct]->buffer[0], sndfx[snd_ct]->decoder->format,
sndfx[snd_ct]->decoder->buffer, decoded_bytes,
sndfx[snd_ct]->decoder->actual.rate);
sndfx[snd_ct]->decoder->frequency);
Sound_FreeSample (sndfx[snd_ct]->decoder);
SoundDecoder_Free (sndfx[snd_ct]->decoder);
sndfx[snd_ct]->decoder = NULL;
++snd_ct;
@@ -192,7 +188,7 @@ _GetSoundBankData (FILE *fp, DWORD length)
while (snd_ct--)
{
if (sndfx[snd_ct]->decoder)
Sound_FreeSample (sndfx[snd_ct]->decoder);
SoundDecoder_Free (sndfx[snd_ct]->decoder);
HFree (sndfx[snd_ct]);
}
@@ -236,8 +232,9 @@ _ReleaseSoundBankData (MEM_HANDLE Snd)
while (snd_ct--)
{
if ((*sptr)->decoder)
Sound_FreeSample ((*sptr)->decoder);
alDeleteBuffers (NUM_SOUNDBUFFERS, (*sptr)->buffer);
SoundDecoder_Free ((*sptr)->decoder);
alDeleteBuffers ((*sptr)->num_buffers, (*sptr)->buffer);
HFree ((*sptr)->buffer);
HFree (*sptr);
*sptr++ = 0;
}
+8 -62
View File
@@ -31,7 +31,7 @@ static Task StreamDecoderTask;
int
TFB_InitSound (int driver, int flags, int frequency)
TFB_InitSound (int driver, int flags)
{
int i;
@@ -64,34 +64,12 @@ TFB_InitSound (int driver, int flags, int frequency)
fprintf (stderr, " renderer: %s\n", alGetString (AL_RENDERER));
fprintf (stderr, " device: %s\n",
alcGetString (alcDevice, ALC_DEFAULT_DEVICE_SPECIFIER));
fprintf (stderr, " extensions: %s\n", alGetString (AL_EXTENSIONS));
fprintf (stderr, "Initializing SDL_sound.\n");
if (!Sound_Init())
{
fprintf(stderr, "SDL_sound initialization failed: %s\n", Sound_GetError());
exit (-1);
}
else
{
const Sound_DecoderInfo **sdi;
Sound_Version compiled, linked;
SOUND_VERSION (&compiled);
Sound_GetLinkedVersion (&linked);
fprintf (stderr, "SDL_sound initialized.\n");
fprintf (stderr, " compiled version: %d.%d.%d linked version: %d.%d.%d\n",
compiled.major, compiled.minor, compiled.patch,
linked.major, linked.minor, linked.patch);
for (sdi = Sound_AvailableDecoders(); *sdi != NULL; ++sdi)
{
fprintf (stderr, " supported format: %s\n",
(*sdi)->description);
}
}
//fprintf (stderr, " extensions: %s\n", alGetString (AL_EXTENSIONS));
fprintf (stderr, "Initializing sound decoders.\n");
SoundDecoder_Init (flags);
fprintf (stderr, "Sound decoders initialized.\n");
alListenerfv (AL_POSITION, listenerPos);
alListenerfv (AL_VELOCITY, listenerVel);
alListenerfv (AL_ORIENTATION, listenerOri);
@@ -107,7 +85,6 @@ TFB_InitSound (int driver, int flags, int frequency)
alSourcefv (soundSource[i].handle, AL_DIRECTION, zero);
soundSource[i].sample = NULL;
soundSource[i].stream_looping = FALSE;
soundSource[i].stream_should_be_playing = FALSE;
soundSource[i].stream_mutex = CreateMutex ();
}
@@ -134,6 +111,8 @@ TFB_UninitSound (void)
alcContext = NULL;
alcCloseDevice (alcDevice);
alcDevice = NULL;
SoundDecoder_Uninit ();
}
void
@@ -188,39 +167,6 @@ UninitSound (void)
{
}
ALenum
DetermineALFormat (Sound_Sample *sample)
{
ALenum format;
if (sample->actual.channels == 1)
{
if (sample->actual.format == AUDIO_U8 ||
sample->actual.format == AUDIO_S8)
{
format = AL_FORMAT_MONO8;
}
else
{
format = AL_FORMAT_MONO16;
}
}
else
{
if (sample->actual.format == AUDIO_U8 ||
sample->actual.format == AUDIO_S8)
{
format = AL_FORMAT_STEREO8;
}
else
{
format = AL_FORMAT_STEREO16;
}
}
return format;
}
void SetSFXVolume (float volume)
{
int i;
+11 -12
View File
@@ -17,23 +17,23 @@
/* OpenAL specific code by Mika Kolehmainen, 2002-10-23
*/
#include "libs/strings/strintrn.h"
#include "libs/sound/sndintrn.h"
#include "libs/graphics/sdl/sdl_common.h"
#include "libs/sound/sound_common.h"
#ifdef WIN32
#include <al.h>
#include <alc.h>
#include <SDL_sound.h>
#pragma comment (lib, "OpenAL32.lib")
#else
#include <AL/al.h>
#include <AL/alc.h>
#include <SDL/SDL_sound.h>
#endif
#include "starcon.h"
#include "misc.h"
#include "libs/strings/strintrn.h"
#include "libs/sound/sndintrn.h"
#include "libs/sound/sound_common.h"
#include "decoders/decoder.h"
#define NUM_SOUNDBUFFERS 10
#define FIRST_SFX_SOURCE 0
#define LAST_SFX_SOURCE 4
#define MUSIC_SOURCE (LAST_SFX_SOURCE + 1)
@@ -43,8 +43,9 @@
// audio data
typedef struct tfb_soundsample
{
Sound_Sample *decoder; // if != NULL, sound is streamed
ALuint buffer[NUM_SOUNDBUFFERS]; // if not streamed, only buffer[0] is used
TFB_SoundDecoder *decoder; // if != NULL, sound is streamed
ALuint *buffer;
ALuint num_buffers;
} TFB_SoundSample;
// equivalent to channel in legacy sound code
@@ -52,7 +53,6 @@ typedef struct tfb_soundsource
{
TFB_SoundSample *sample;
ALuint handle;
BOOLEAN stream_looping;
BOOLEAN stream_should_be_playing;
Mutex stream_mutex;
} TFB_SoundSource;
@@ -65,7 +65,6 @@ extern ALfloat listenerVel[]; // listener velocity (3 floats)
extern ALfloat listenerOri[]; // listener orientation (two 3 float vectors, "look at" and "up")
extern TFB_SoundSource soundSource[];
ALenum DetermineALFormat (Sound_Sample *sample);
void SetSFXVolume (float volume);
void SetSpeechVolume (float volume);
+76 -88
View File
@@ -1,21 +1,21 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* By Mika Kolehmainen, 2002-10-23
*/
*/
#ifdef SOUNDMODULE_OPENAL
@@ -25,38 +25,39 @@ BOOLEAN speech_advancetrack = FALSE;
void
PlayStream (TFB_SoundSample *sample, ALuint source, BOOLEAN looping)
PlayStream (TFB_SoundSample *sample, ALuint source, ALboolean looping)
{
int i;
ALenum format = DetermineALFormat (sample->decoder);
ALuint i;
if (!sample)
return;
StopStream (source);
Sound_Rewind (sample->decoder);
SoundDecoder_Rewind (sample->decoder);
soundSource[source].sample = sample;
soundSource[source].sample->decoder->looping = looping;
alSourcei (soundSource[source].handle, AL_LOOPING, AL_FALSE);
for (i = 0; i < NUM_SOUNDBUFFERS; ++i)
for (i = 0; i < sample->num_buffers; ++i)
{
Uint32 decoded_bytes;
ALuint decoded_bytes;
if (sample->decoder->flags & SOUND_SAMPLEFLAG_EOF ||
sample->decoder->flags & SOUND_SAMPLEFLAG_ERROR)
break;
decoded_bytes = Sound_Decode (sample->decoder);
decoded_bytes = SoundDecoder_Decode (sample->decoder);
//fprintf (stderr, "PlayStream(): source %d sample %x decoded_bytes %d\n", source, sample, decoded_bytes);
if (decoded_bytes == 0)
break;
alBufferData (sample->buffer[i], format, sample->decoder->buffer,
decoded_bytes, sample->decoder->actual.rate);
alBufferData (sample->buffer[i], sample->decoder->format, sample->decoder->buffer,
decoded_bytes, sample->decoder->frequency);
alSourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]);
if (sample->decoder->error)
break;
}
soundSource[source].stream_looping = looping;
soundSource[source].stream_should_be_playing = TRUE;
alSourcePlay (soundSource[source].handle);
}
@@ -73,12 +74,14 @@ StopStream (ALuint source)
alGetSourcei (soundSource[source].handle, AL_BUFFERS_PROCESSED, &processed);
alGetSourcei (soundSource[source].handle, AL_BUFFERS_QUEUED, &queued);
//fprintf (stderr, "StopStream(): source %d processed %d queued %d NUM_SOUNDBUFFERS %d\n",
// source, processed, queued, NUM_SOUNDBUFFERS);
buffer = (ALuint *) HMalloc (sizeof (ALuint) * processed);
alSourceUnqueueBuffers (soundSource[source].handle, processed, buffer);
HFree (buffer);
//fprintf (stderr, "StopStream(): source %d processed %d queued %d num_buffers %d\n", source, processed, queued, soundSource[source].sample->num_buffers);
if (processed != 0)
{
buffer = (ALuint *) HMalloc (sizeof (ALuint) * processed);
alSourceUnqueueBuffers (soundSource[source].handle, processed, buffer);
HFree (buffer);
}
}
void
@@ -114,8 +117,7 @@ StreamDecoderTaskFunc (void *data)
for (i = MUSIC_SOURCE; i < NUM_SOUNDSOURCES; ++i)
{
ALuint processed;
ALuint queued;
ALuint processed, queued;
ALint state;
ALboolean finished = AL_FALSE;
ALboolean do_speech_advancetrack = AL_FALSE;
@@ -125,8 +127,7 @@ StreamDecoderTaskFunc (void *data)
if (!soundSource[i].sample ||
!soundSource[i].sample->decoder ||
!soundSource[i].stream_should_be_playing ||
soundSource[i].sample->decoder->flags & SOUND_SAMPLEFLAG_EOF ||
soundSource[i].sample->decoder->flags & SOUND_SAMPLEFLAG_ERROR)
soundSource[i].sample->decoder->error == SOUNDDECODER_ERROR)
{
UnlockMutex (soundSource[i].stream_mutex);
continue;
@@ -138,86 +139,72 @@ StreamDecoderTaskFunc (void *data)
alGetSourcei (soundSource[i].handle, AL_SOURCE_STATE, &state);
if (state != AL_PLAYING)
{
//fprintf (stderr, "StreamDecoderTaskFunc(): forcing alSourcePlay on %d\n", i);
alSourcePlay (soundSource[i].handle);
if (soundSource[i].sample->decoder->error == SOUNDDECODER_EOF)
{
soundSource[i].stream_should_be_playing = FALSE;
if (i == SPEECH_SOURCE && speech_advancetrack)
{
do_speech_advancetrack = AL_TRUE;
}
}
else
{
fprintf (stderr, "StreamDecoderTaskFunc(): buffer underrun when playing %s, source %d\n", soundSource[i].sample->decoder->filename, i);
alSourcePlay (soundSource[i].handle);
}
}
}
alGetSourcei (soundSource[i].handle, AL_BUFFERS_QUEUED, &queued);
if (queued != NUM_SOUNDBUFFERS)
{
fprintf (stderr, "StreamDecoderTaskFunc(): warning, queued %d != NUM_SOUNDBUFFERS %d\n",
queued, NUM_SOUNDBUFFERS);
}
alGetSourcei (soundSource[i].handle, AL_BUFFERS_QUEUED, &queued);
//fprintf (stderr, "StreamDecoderTaskFunc(): source %d, processed %d queued %d\n", i, processed, queued);
while (processed && !finished)
{
ALenum format, error;
ALenum error;
ALuint buffer;
Uint32 decoded_bytes;
ALuint decoded_bytes;
alGetError (); // clear error state
alSourceUnqueueBuffers (soundSource[i].handle, 1, &buffer);
if ((error = alGetError()) != AL_NO_ERROR)
{
fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alSourceUnqueueBuffers: %x, source %d\n", error, i);
fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alSourceUnqueueBuffers: %x, file %s, source %d\n", error, soundSource[i].sample->decoder->filename, i);
break;
}
decoded_bytes = Sound_Decode (soundSource[i].sample->decoder);
//fprintf (stderr, "StreamDecoderTaskFunc(): decoded_bytes %d, source %d\n", decoded_bytes, i);
if (soundSource[i].sample->decoder->flags & SOUND_SAMPLEFLAG_EOF)
if (soundSource[i].sample->decoder->error)
{
if (i == SPEECH_SOURCE && speech_advancetrack)
if (soundSource[i].sample->decoder->error == SOUNDDECODER_EOF)
{
finished = AL_TRUE;
soundSource[i].stream_should_be_playing = FALSE;
do_speech_advancetrack = AL_TRUE;
//fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is eof for %s\n", soundSource[i].sample->decoder->filename);
}
else
{
if (soundSource[i].stream_looping)
{
if ((Sound_Rewind (soundSource[i].sample->decoder)) == 0)
{
fprintf (stderr, "StreamDecoderTaskFunc(): Sound_Rewind error %s, source %d\n",
Sound_GetError(), i);
finished = AL_TRUE;
soundSource[i].stream_should_be_playing = FALSE;
}
else if (decoded_bytes == 0)
{
decoded_bytes = Sound_Decode (soundSource[i].sample->decoder);
}
}
else
{
finished = AL_TRUE;
soundSource[i].stream_should_be_playing = FALSE;
}
//fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is %d for %s\n", soundSource[i].sample->decoder->error, soundSource[i].sample->decoder->filename);
}
processed--;
continue;
}
else if (soundSource[i].sample->decoder->flags & SOUND_SAMPLEFLAG_ERROR)
decoded_bytes = SoundDecoder_Decode (soundSource[i].sample->decoder);
if (soundSource[i].sample->decoder->error == SOUNDDECODER_ERROR)
{
fprintf (stderr, "StreamDecoderTaskFunc(): Sound_Decode error %s, source %d\n",
Sound_GetError(), i);
fprintf (stderr, "StreamDecoderTaskFunc(): SoundDecoder_Decode error %d, file %s, source %d\n", soundSource[i].sample->decoder->error, soundSource[i].sample->decoder->filename, i);
soundSource[i].stream_should_be_playing = FALSE;
break;
processed--;
continue;
}
if (decoded_bytes > 0)
{
format = DetermineALFormat (soundSource[i].sample->decoder);
alBufferData (buffer, format, soundSource[i].sample->decoder->buffer,
decoded_bytes, soundSource[i].sample->decoder->actual.rate);
alBufferData (buffer, soundSource[i].sample->decoder->format,
soundSource[i].sample->decoder->buffer, decoded_bytes,
soundSource[i].sample->decoder->frequency);
if ((error = alGetError()) != AL_NO_ERROR)
{
fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alBufferData: %x, source %d, decoded_bytes %d\n", error, i, decoded_bytes);
fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alBufferData: %x, file %s, source %d, decoded_bytes %d\n",
error, soundSource[i].sample->decoder->filename, i, decoded_bytes);
finished = AL_TRUE;
}
else
@@ -226,7 +213,8 @@ StreamDecoderTaskFunc (void *data)
if ((error = alGetError()) != AL_NO_ERROR)
{
fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alSourceQueueBuffers: %x, source %d, decoded_bytes %d\n", error, i, decoded_bytes);
fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alSourceQueueBuffers: %x, file %s, source %d, decoded_bytes %d\n",
error, i, soundSource[i].sample->decoder->filename, decoded_bytes);
finished = AL_TRUE;
}
}
+1 -1
View File
@@ -20,7 +20,7 @@
#ifndef STREAM_H
#define STREAM_H
void PlayStream (TFB_SoundSample *sample, ALuint source, BOOLEAN looping);
void PlayStream (TFB_SoundSample *sample, ALuint source, ALboolean looping);
void StopStream (ALuint source);
void PauseStream (ALuint source);
void ResumeStream (ALuint source);
+12 -10
View File
@@ -153,8 +153,9 @@ StopTrack ()
{
if (track_clip[tct].sample->decoder)
{
Sound_FreeSample (track_clip[tct].sample->decoder);
alDeleteBuffers (NUM_SOUNDBUFFERS, track_clip[tct].sample->buffer);
SoundDecoder_Free (track_clip[tct].sample->decoder);
alDeleteBuffers (track_clip[tct].sample->num_buffers, track_clip[tct].sample->buffer);
HFree (track_clip[tct].sample->buffer);
}
HFree (track_clip[tct].sample);
track_clip[tct].sample = 0;
@@ -199,21 +200,22 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText)
fprintf (stderr, "SpliceTrack(): loading %s\n", TrackName);
track_clip[tct].sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
track_clip[tct].sample->decoder = Sound_NewSampleFromFile (TrackName, NULL, 4096);
track_clip[tct].sample->decoder = SoundDecoder_Load (TrackName, 4096);
if (track_clip[tct].sample->decoder)
{
fprintf (stderr, "decoder %s rate %d channels %d\n",
track_clip[tct].sample->decoder->decoder->description,
track_clip[tct].sample->decoder->actual.rate,
track_clip[tct].sample->decoder->actual.channels);
fprintf (stderr, " decoder: %s, rate %d format %x\n",
track_clip[tct].sample->decoder->decoder_info,
track_clip[tct].sample->decoder->frequency,
track_clip[tct].sample->decoder->format);
alGenBuffers (NUM_SOUNDBUFFERS, track_clip[tct].sample->buffer);
track_clip[tct].sample->num_buffers = 8;
track_clip[tct].sample->buffer = HMalloc (sizeof (ALuint) * track_clip[tct].sample->num_buffers);
alGenBuffers (track_clip[tct].sample->num_buffers, track_clip[tct].sample->buffer);
}
else
{
fprintf (stderr, "SpliceTrack(): couldn't load %s: %s\n",
TrackName, Sound_GetError());
fprintf (stderr, "SpliceTrack(): couldn't load %s\n", TrackName);
HFree (track_clip[tct].sample);
track_clip[tct].sample = NULL;
}
+6 -4
View File
@@ -18,17 +18,19 @@
#ifdef SOUNDMODULE_SDL
#ifdef WIN32
#include <io.h>
#endif
#include <fcntl.h>
#include "libs/strings/strintrn.h"
#include "libs/sound/sndintrn.h"
#include "libs/graphics/sdl/sdl_common.h"
#include "libs/sound/sound_common.h"
#include "options.h"
#ifdef WIN32
#include <io.h>
#include <SDL_mixer.h>
#else
#include <SDL/SDL_mixer.h>
#endif
MEM_HANDLE
+5 -1
View File
@@ -19,10 +19,14 @@
#ifdef SOUNDMODULE_SDL
#include "libs/sound/sndintrn.h"
#include "libs/graphics/sdl/sdl_common.h"
#include "libs/sound/sound_common.h"
#ifdef WIN32
#include <SDL_mixer.h>
#else
#include <SDL/SDL_mixer.h>
#endif
static MUSIC_REF curMusicRef;
+36 -9
View File
@@ -20,17 +20,19 @@
#include "libs/graphics/sdl/sdl_common.h"
#include "libs/sound/sound_common.h"
#ifdef WIN32
#include <SDL_mixer.h>
#pragma comment (lib, "SDL_mixer.lib")
#else
#include <SDL/SDL_mixer.h>
#endif
int
TFB_InitSound (int driver, int flags, int frequency)
TFB_InitSound (int driver, int flags)
{
// NOTE: SDL_sound should be compiled without mikmod support
// or potential lockup occurs because both
// SDL_mixer and SDL_sound try to initialize it
char SoundcardName[256];
int audio_rate,audio_channels;
int audio_rate, audio_channels, audio_bufsize;
Uint16 audio_format;
SDL_version compile_version;
@@ -42,20 +44,40 @@ TFB_InitSound (int driver, int flags, int frequency)
}
fprintf (stderr, "SDL audio subsystem initialized.\n");
if (flags & TFB_SOUNDFLAGS_HQAUDIO)
{
audio_rate = 44100;
audio_channels = 2;
audio_bufsize = 2048;
}
else if (flags & TFB_SOUNDFLAGS_LQAUDIO)
{
audio_rate = 22050;
audio_channels = 2;
audio_bufsize = 1024;
}
else
{
audio_rate = 44100;
audio_channels = 2;
audio_bufsize = 2048;
}
fprintf (stderr, "Initializing SDL_mixer.\n");
if (Mix_OpenAudio(frequency, AUDIO_S16, 2, 2048))
if (Mix_OpenAudio(audio_rate, AUDIO_S16, audio_channels, audio_bufsize))
{
fprintf (stderr, "Unable to open audio: %s\n", Mix_GetError());
exit (-1);
}
fprintf (stderr, "SDL_mixer initialized.\n");
atexit (Mix_CloseAudio);
atexit (TFB_UninitSound);
SDL_AudioDriverName (SoundcardName, sizeof (SoundcardName));
Mix_QuerySpec (&audio_rate, &audio_format, &audio_channels);
fprintf (stderr, " opened %s at %d Hz %d bit %s, %d bytes audio buffer\n",
SoundcardName, audio_rate, audio_format & 0xFF,
audio_channels > 1 ? "stereo" : "mono", 2048);
audio_channels > 1 ? "stereo" : "mono", audio_bufsize);
MIX_VERSION (&compile_version);
fprintf (stderr, " compiled with SDL_mixer version: %d.%d.%d\n",
compile_version.major,
@@ -69,6 +91,11 @@ TFB_InitSound (int driver, int flags, int frequency)
return 0;
}
void
TFB_UninitSound (void)
{
Mix_CloseAudio ();
}
//Status: Unimplemented
void
@@ -21,7 +21,12 @@
#include "libs/graphics/sdl/sdl_common.h"
#include "libs/sound/sound_common.h"
#include "libs/sound/trackplayer.h"
#ifdef WIN32
#include <SDL_mixer.h>
#else
#include <SDL/SDL_mixer.h>
#endif
#define VOICE_CHANNEL 0
+4 -2
View File
@@ -26,9 +26,11 @@ enum
};
// flags for TFB_InitSound
//#define TFB_SOUNDFLAGS_ETC (1<<0)
#define TFB_SOUNDFLAGS_HQAUDIO (1<<0) // high quality audio
#define TFB_SOUNDFLAGS_MQAUDIO (1<<1) // medium quality audio
#define TFB_SOUNDFLAGS_LQAUDIO (1<<2) // low quality audio
int TFB_InitSound (int driver, int flags, int frequency);
int TFB_InitSound (int driver, int flags);
void TFB_UninitSound (void);
extern int musicVolume;
+35 -18
View File
@@ -51,10 +51,12 @@ main (int argc, char *argv[])
{
int gfxdriver = TFB_GFXDRIVER_SDL_PURE;
int gfxflags = 0;
int soundflags = TFB_SOUNDFLAGS_MQAUDIO;
int width = 640, height = 480, bpp = 16;
int frequency = 44100;
int vol;
char contentdir[1000];
char str[1000];
int option_index = 0, c;
static struct option long_options[] =
@@ -64,7 +66,6 @@ main (int argc, char *argv[])
{"fullscreen", 0, NULL, 'f'},
{"opengl", 0, NULL, 'o'},
{"bilinear", 0, NULL, 'b'},
{"frequency", 1, NULL, 'q'},
{"fps", 0, NULL, 'p'},
{"tv", 0, NULL, 't'},
{"contentdir", 1, NULL, 'c'},
@@ -74,6 +75,7 @@ main (int argc, char *argv[])
{"speechvol", 1, NULL, 'T'},
{"3domusic", 0, NULL, 'e'},
{"pcmusic", 0, NULL, 'm'},
{"audioquality", 1, NULL, 'q'},
{0, 0, 0, 0}
};
@@ -83,7 +85,7 @@ main (int argc, char *argv[])
strcpy (contentdir, "../../content");
#endif
while ((c = getopt_long(argc, argv, "r:d:fobq:ptc:?hM:S:T:em", long_options, &option_index)) != -1)
while ((c = getopt_long(argc, argv, "r:d:fob:ptc:?hM:S:T:emq:", long_options, &option_index)) != -1)
{
switch (c) {
case 'r':
@@ -101,9 +103,6 @@ main (int argc, char *argv[])
case 'b':
gfxflags |= TFB_GFXFLAGS_BILINEAR_FILTERING;
break;
case 'q':
sscanf(optarg, "%d", &frequency);
break;
case 'p':
gfxflags |= TFB_GFXFLAGS_SHOWFPS;
break;
@@ -143,26 +142,44 @@ main (int argc, char *argv[])
case 'm':
optWhichMusic = MUSIC_PC;
break;
case 'q':
sscanf(optarg, "%s", str);
if (!strcmp (str, "high"))
{
soundflags &= ~(TFB_SOUNDFLAGS_MQAUDIO|TFB_SOUNDFLAGS_LQAUDIO);
soundflags |= TFB_SOUNDFLAGS_HQAUDIO;
}
else if (!strcmp (str, "medium"))
{
soundflags &= ~(TFB_SOUNDFLAGS_HQAUDIO|TFB_SOUNDFLAGS_LQAUDIO);
soundflags |= TFB_SOUNDFLAGS_MQAUDIO;
}
else if (!strcmp (str, "low"))
{
soundflags &= ~(TFB_SOUNDFLAGS_HQAUDIO|TFB_SOUNDFLAGS_MQAUDIO);
soundflags |= TFB_SOUNDFLAGS_LQAUDIO;
}
break;
default:
printf ("\nOption %s not found!\n", long_options[option_index].name);
case '?':
case 'h':
printf("\nThe Ur-Quan Masters\n");
printf("Options:\n");
printf(" -r, --res=WIDTHxHEIGHT\n");
printf(" -d, --bpp=BITSPERPIXEL\n");
printf(" -f, --fullscreen\n");
printf(" -o, --opengl\n");
printf(" -b, --bilinear\n");
printf(" -q, --frequency=FREQUENCY\n");
printf(" -p, --fps\n");
printf(" -t, --tv\n");
printf(" -r, --res=WIDTHxHEIGHT (default 640x480, others work only with --opengl)\n");
printf(" -d, --bpp=BITSPERPIXEL (default 16)\n");
printf(" -f, --fullscreen (default off)\n");
printf(" -o, --opengl (default off, usage recommended if TNT2 or better gfx card)\n");
printf(" -b, --bilinear (default off, only works with --opengl)\n");
printf(" -p, --fps (default off)\n");
printf(" -t, --tv (default off, only works with --opengl\n");
printf(" -c, --contentdir=CONTENTDIR\n");
printf(" -M, --musicvol=VOLUME (0-100)\n");
printf(" -S, --sfxvol=VOLUME (0-100)\n");
printf(" -T, --speechvol=VOLUME (0-100)\n");
printf(" -e, --3domusic\n");
printf(" -M, --musicvol=VOLUME (0-100, default 100)\n");
printf(" -S, --sfxvol=VOLUME (0-100, default 100)\n");
printf(" -T, --speechvol=VOLUME (0-100, default 100)\n");
printf(" -e, --3domusic (default)\n");
printf(" -m, --pcmusic\n");
printf(" -q, --audioquality=QUALITY (high, medium or low, default medium)\n");
return 0;
break;
}
@@ -179,7 +196,7 @@ main (int argc, char *argv[])
mem_init ();
TFB_InitGraphics (gfxdriver, gfxflags, width, height, bpp);
TFB_InitSound (TFB_SOUNDDRIVER_SDL, 0, frequency);
TFB_InitSound (TFB_SOUNDDRIVER_SDL, soundflags);
TFB_InitInput (TFB_INPUTDRIVER_SDL, 0);
AssignTask (Starcon2Main, 1024, "Starcon2Main");