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:
+7
-8
@@ -13,7 +13,7 @@ For Windows version:
|
|||||||
Microsoft Visual C++ 6 or 7
|
Microsoft Visual C++ 6 or 7
|
||||||
|
|
||||||
Additionally, The Ur-Quan Masters requires the following libraries:
|
Additionally, The Ur-Quan Masters requires the following libraries:
|
||||||
(Dependancies can differ between different OS's)
|
Note that dependancies can differ between different OS's.
|
||||||
|
|
||||||
OpenGL v1.2 (if HAVE_OPENGL is defined, which is the default)
|
OpenGL v1.2 (if HAVE_OPENGL is defined, which is the default)
|
||||||
Win32 users should have all by default, following is for Linux version:
|
Win32 users should have all by default, following is for Linux version:
|
||||||
@@ -28,6 +28,7 @@ SDL v1.2
|
|||||||
The Simple Direct-Media Layer
|
The Simple Direct-Media Layer
|
||||||
A fairly good multiplatform low level graphics library.
|
A fairly good multiplatform low level graphics library.
|
||||||
Homepage: www.libsdl.org
|
Homepage: www.libsdl.org
|
||||||
|
Download: http://www.libsdl.org/download-1.2.php
|
||||||
Debian package: libsdl1.2-dev (and various runtime debs)
|
Debian package: libsdl1.2-dev (and various runtime debs)
|
||||||
|
|
||||||
SDL_image
|
SDL_image
|
||||||
@@ -45,18 +46,16 @@ SDL_mixer (Linux only)
|
|||||||
cvs -z3 -d:pserver:guest@libsdl.org:/home/sdlweb/libsdl.org/cvs co SDL_mixer
|
cvs -z3 -d:pserver:guest@libsdl.org:/home/sdlweb/libsdl.org/cvs co SDL_mixer
|
||||||
Debian packages: libsdl-mixer1.2 libsdl-mixer1.2-dev
|
Debian packages: libsdl-mixer1.2 libsdl-mixer1.2-dev
|
||||||
|
|
||||||
SDL_sound (Win32 only)
|
|
||||||
An audio format decoder library.
|
|
||||||
Homepage: http://www.icculus.org/SDL_sound/
|
|
||||||
Download: http://www.icculus.org/SDL_sound/downloads/
|
|
||||||
You maybe need to get few updated dll's from: http://www.cc.jyu.fi/~mimakole/sc2/sdl_sound_dlls.zip
|
|
||||||
If compiling this yourself, be sure ogg vorbis and libmikmod (or libmodplug) support is compiled in.
|
|
||||||
|
|
||||||
OpenAL (Win32 only)
|
OpenAL (Win32 only)
|
||||||
A cross-platform spatialized audio library.
|
A cross-platform spatialized audio library.
|
||||||
Homepage: http://www.openal.org
|
Homepage: http://www.openal.org
|
||||||
SDK download: ftp://opensource.creative.com/pub/sdk/OpenALSDK.exe
|
SDK download: ftp://opensource.creative.com/pub/sdk/OpenALSDK.exe
|
||||||
|
|
||||||
|
Ogg Vorbis (Win32 only)
|
||||||
|
Audio codec used for music and speech.
|
||||||
|
Homepage: http://www.xiph.org/ogg/vorbis/index.html
|
||||||
|
SDK download: http://www.vorbis.com/files/1.0/windows/OggVorbis-win32sdk-1.0.zip
|
||||||
|
|
||||||
|
|
||||||
If you find these aren't enough, or if you know the names
|
If you find these aren't enough, or if you know the names
|
||||||
of the corresponding RPM etc. packages, please report to
|
of the corresponding RPM etc. packages, please report to
|
||||||
|
|||||||
@@ -65,23 +65,10 @@ Glitches (don't crash the game, medium priority):
|
|||||||
complete battle (not just one fight). There's no permanent memory leak
|
complete battle (not just one fight). There's no permanent memory leak
|
||||||
though.
|
though.
|
||||||
- OpenAL sound code problems:
|
- OpenAL sound code problems:
|
||||||
- On Linux, volume control (AL_GAIN) doesn't work for streams.
|
|
||||||
This prevents also music fade in/out from working.
|
|
||||||
Most probably this is a Linux OpenAL implementation bug itself, and
|
|
||||||
authors have been informed.
|
|
||||||
- Occasional clipping/popping/etc artifacts
|
|
||||||
- Maybe caused by buggy soundcard drivers also
|
|
||||||
- Some unimplemented functions (for oscilloscope and dialogue seeking)
|
- Some unimplemented functions (for oscilloscope and dialogue seeking)
|
||||||
- When mod music is looping, there's some volume fade at the end of tune,
|
- Linux OpenAL implementation sucks, so for now we are using SDL_mixer
|
||||||
then it starts playing again. This shouldn't happen? (modplug only?)
|
on that platform.
|
||||||
- Stock SDL_sound package for VC is outdated and win32 users have to get
|
- Volume levels aren't maybe exactly as they should
|
||||||
few new .dll's to ensure proper operation
|
|
||||||
- Perhaps we should integrate mikmod to our code and use vorbis libs
|
|
||||||
directly to avoid depending on SDL_sound at all?
|
|
||||||
- If OpenAL causes too many problems, reverting to SDL_mixer is easy as
|
|
||||||
all code is preserved related to that, etc.. but SDL_mixer is pretty
|
|
||||||
sucky for various reasons so I'd like to avoid that.
|
|
||||||
|
|
||||||
|
|
||||||
Implementation bugs (low priority):
|
Implementation bugs (low priority):
|
||||||
|
|
||||||
|
|||||||
+134
-2
@@ -50,7 +50,7 @@ BSC32=bscmake.exe
|
|||||||
# ADD BSC32 /nologo
|
# ADD BSC32 /nologo
|
||||||
LINK32=link.exe
|
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 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"
|
!ELSEIF "$(CFG)" == "Starcon2 - Win32 Debug"
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ BSC32=bscmake.exe
|
|||||||
# ADD BSC32 /nologo /o"Starcon2.bsc"
|
# ADD BSC32 /nologo /o"Starcon2.bsc"
|
||||||
LINK32=link.exe
|
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 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
|
# SUBTRACT LINK32 /nodefaultlib
|
||||||
|
|
||||||
!ENDIF
|
!ENDIF
|
||||||
@@ -426,6 +426,138 @@ SOURCE=..\sc2code\libs\sound\openal\stream.h
|
|||||||
|
|
||||||
SOURCE=..\sc2code\libs\sound\openal\trackplayer.c
|
SOURCE=..\sc2code\libs\sound\openal\trackplayer.c
|
||||||
# End Source File
|
# 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
|
# End Group
|
||||||
# Begin Source File
|
# 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
|
||||||
@@ -156,20 +156,22 @@ _GetMusicData (FILE *fp, DWORD length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fprintf (stderr, "_GetMusicData(): loading %s\n", filename);
|
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);
|
fprintf (stderr, "_GetMusicData(): couldn't load %s\n", filename);
|
||||||
|
|
||||||
UnlockMusicData (h);
|
UnlockMusicData (h);
|
||||||
mem_release (h);
|
mem_release (h);
|
||||||
h = 0;
|
h = 0;
|
||||||
HFree (*pmus);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf (stderr, "decoder %s rate %d channels %d\n", (*pmus)->decoder->decoder->description,
|
fprintf (stderr, " decoder: %s, rate %d format %x\n", (*pmus)->decoder->decoder_info,
|
||||||
(*pmus)->decoder->actual.rate, (*pmus)->decoder->actual.channels);
|
(*pmus)->decoder->frequency, (*pmus)->decoder->format);
|
||||||
alGenBuffers (NUM_SOUNDBUFFERS, (*pmus)->buffer);
|
|
||||||
|
(*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);
|
UnlockMutex (soundSource[MUSIC_SOURCE].stream_mutex);
|
||||||
|
|
||||||
Sound_FreeSample ((*pmus)->decoder);
|
SoundDecoder_Free ((*pmus)->decoder);
|
||||||
alDeleteBuffers (NUM_SOUNDBUFFERS, (*pmus)->buffer);
|
alDeleteBuffers ((*pmus)->num_buffers, (*pmus)->buffer);
|
||||||
|
HFree ((*pmus)->buffer);
|
||||||
}
|
}
|
||||||
HFree (*pmus);
|
HFree (*pmus);
|
||||||
|
|
||||||
|
|||||||
@@ -32,9 +32,6 @@ PlayChannel (COUNT channel, PVOID sample, COUNT sample_length, COUNT loop_begin,
|
|||||||
COUNT loop_length, unsigned char priority)
|
COUNT loop_length, unsigned char priority)
|
||||||
{
|
{
|
||||||
TFB_SoundSample *tfb_sample = *(TFB_SoundSample**) sample;
|
TFB_SoundSample *tfb_sample = *(TFB_SoundSample**) sample;
|
||||||
|
|
||||||
//fprintf (stderr, "PlayChannel %d tfb_sample %x\n", channel, tfb_sample);
|
|
||||||
|
|
||||||
soundSource[channel].sample = tfb_sample;
|
soundSource[channel].sample = tfb_sample;
|
||||||
alSourceRewind (soundSource[channel].handle);
|
alSourceRewind (soundSource[channel].handle);
|
||||||
alSourcei (soundSource[channel].handle, AL_BUFFER, tfb_sample->buffer[0]);
|
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);
|
fprintf (stderr, "_GetSoundBankData(): loading %s\n", filename);
|
||||||
|
|
||||||
sndfx[snd_ct] = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
|
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)
|
if (!sndfx[snd_ct]->decoder)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "_GetSoundBankData(): couldn't load %s\n", filename);
|
fprintf (stderr, "_GetSoundBankData(): couldn't load %s\n", filename);
|
||||||
@@ -146,20 +143,19 @@ _GetSoundBankData (FILE *fp, DWORD length)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Uint32 decoded_bytes;
|
ALuint decoded_bytes;
|
||||||
ALenum format;
|
|
||||||
|
|
||||||
decoded_bytes = Sound_DecodeAll (sndfx[snd_ct]->decoder);
|
decoded_bytes = SoundDecoder_DecodeAll (sndfx[snd_ct]->decoder);
|
||||||
//fprintf (stderr, "decoded_bytes %d\n", decoded_bytes);
|
//fprintf (stderr, "_GetSoundBankData(): decoded_bytes %d\n", decoded_bytes);
|
||||||
|
|
||||||
format = DetermineALFormat (sndfx[snd_ct]->decoder);
|
sndfx[snd_ct]->num_buffers = 1;
|
||||||
|
sndfx[snd_ct]->buffer = (ALuint *) HMalloc (sizeof (ALuint) * sndfx[snd_ct]->num_buffers);
|
||||||
alGenBuffers (NUM_SOUNDBUFFERS, sndfx[snd_ct]->buffer);
|
alGenBuffers (sndfx[snd_ct]->num_buffers, sndfx[snd_ct]->buffer);
|
||||||
alBufferData (sndfx[snd_ct]->buffer[0], format,
|
alBufferData (sndfx[snd_ct]->buffer[0], sndfx[snd_ct]->decoder->format,
|
||||||
sndfx[snd_ct]->decoder->buffer, decoded_bytes,
|
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;
|
sndfx[snd_ct]->decoder = NULL;
|
||||||
|
|
||||||
++snd_ct;
|
++snd_ct;
|
||||||
@@ -192,7 +188,7 @@ _GetSoundBankData (FILE *fp, DWORD length)
|
|||||||
while (snd_ct--)
|
while (snd_ct--)
|
||||||
{
|
{
|
||||||
if (sndfx[snd_ct]->decoder)
|
if (sndfx[snd_ct]->decoder)
|
||||||
Sound_FreeSample (sndfx[snd_ct]->decoder);
|
SoundDecoder_Free (sndfx[snd_ct]->decoder);
|
||||||
HFree (sndfx[snd_ct]);
|
HFree (sndfx[snd_ct]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,8 +232,9 @@ _ReleaseSoundBankData (MEM_HANDLE Snd)
|
|||||||
while (snd_ct--)
|
while (snd_ct--)
|
||||||
{
|
{
|
||||||
if ((*sptr)->decoder)
|
if ((*sptr)->decoder)
|
||||||
Sound_FreeSample ((*sptr)->decoder);
|
SoundDecoder_Free ((*sptr)->decoder);
|
||||||
alDeleteBuffers (NUM_SOUNDBUFFERS, (*sptr)->buffer);
|
alDeleteBuffers ((*sptr)->num_buffers, (*sptr)->buffer);
|
||||||
|
HFree ((*sptr)->buffer);
|
||||||
HFree (*sptr);
|
HFree (*sptr);
|
||||||
*sptr++ = 0;
|
*sptr++ = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ static Task StreamDecoderTask;
|
|||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
TFB_InitSound (int driver, int flags, int frequency)
|
TFB_InitSound (int driver, int flags)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -64,33 +64,11 @@ TFB_InitSound (int driver, int flags, int frequency)
|
|||||||
fprintf (stderr, " renderer: %s\n", alGetString (AL_RENDERER));
|
fprintf (stderr, " renderer: %s\n", alGetString (AL_RENDERER));
|
||||||
fprintf (stderr, " device: %s\n",
|
fprintf (stderr, " device: %s\n",
|
||||||
alcGetString (alcDevice, ALC_DEFAULT_DEVICE_SPECIFIER));
|
alcGetString (alcDevice, ALC_DEFAULT_DEVICE_SPECIFIER));
|
||||||
fprintf (stderr, " extensions: %s\n", alGetString (AL_EXTENSIONS));
|
//fprintf (stderr, " extensions: %s\n", alGetString (AL_EXTENSIONS));
|
||||||
|
|
||||||
fprintf (stderr, "Initializing SDL_sound.\n");
|
fprintf (stderr, "Initializing sound decoders.\n");
|
||||||
if (!Sound_Init())
|
SoundDecoder_Init (flags);
|
||||||
{
|
fprintf (stderr, "Sound decoders initialized.\n");
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
alListenerfv (AL_POSITION, listenerPos);
|
alListenerfv (AL_POSITION, listenerPos);
|
||||||
alListenerfv (AL_VELOCITY, listenerVel);
|
alListenerfv (AL_VELOCITY, listenerVel);
|
||||||
@@ -107,7 +85,6 @@ TFB_InitSound (int driver, int flags, int frequency)
|
|||||||
alSourcefv (soundSource[i].handle, AL_DIRECTION, zero);
|
alSourcefv (soundSource[i].handle, AL_DIRECTION, zero);
|
||||||
|
|
||||||
soundSource[i].sample = NULL;
|
soundSource[i].sample = NULL;
|
||||||
soundSource[i].stream_looping = FALSE;
|
|
||||||
soundSource[i].stream_should_be_playing = FALSE;
|
soundSource[i].stream_should_be_playing = FALSE;
|
||||||
soundSource[i].stream_mutex = CreateMutex ();
|
soundSource[i].stream_mutex = CreateMutex ();
|
||||||
}
|
}
|
||||||
@@ -134,6 +111,8 @@ TFB_UninitSound (void)
|
|||||||
alcContext = NULL;
|
alcContext = NULL;
|
||||||
alcCloseDevice (alcDevice);
|
alcCloseDevice (alcDevice);
|
||||||
alcDevice = NULL;
|
alcDevice = NULL;
|
||||||
|
|
||||||
|
SoundDecoder_Uninit ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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)
|
void SetSFXVolume (float volume)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|||||||
@@ -17,23 +17,23 @@
|
|||||||
/* OpenAL specific code by Mika Kolehmainen, 2002-10-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
|
#ifdef WIN32
|
||||||
#include <al.h>
|
#include <al.h>
|
||||||
#include <alc.h>
|
#include <alc.h>
|
||||||
#include <SDL_sound.h>
|
#pragma comment (lib, "OpenAL32.lib")
|
||||||
#else
|
#else
|
||||||
#include <AL/al.h>
|
#include <AL/al.h>
|
||||||
#include <AL/alc.h>
|
#include <AL/alc.h>
|
||||||
#include <SDL/SDL_sound.h>
|
|
||||||
#endif
|
#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 FIRST_SFX_SOURCE 0
|
||||||
#define LAST_SFX_SOURCE 4
|
#define LAST_SFX_SOURCE 4
|
||||||
#define MUSIC_SOURCE (LAST_SFX_SOURCE + 1)
|
#define MUSIC_SOURCE (LAST_SFX_SOURCE + 1)
|
||||||
@@ -43,8 +43,9 @@
|
|||||||
// audio data
|
// audio data
|
||||||
typedef struct tfb_soundsample
|
typedef struct tfb_soundsample
|
||||||
{
|
{
|
||||||
Sound_Sample *decoder; // if != NULL, sound is streamed
|
TFB_SoundDecoder *decoder; // if != NULL, sound is streamed
|
||||||
ALuint buffer[NUM_SOUNDBUFFERS]; // if not streamed, only buffer[0] is used
|
ALuint *buffer;
|
||||||
|
ALuint num_buffers;
|
||||||
} TFB_SoundSample;
|
} TFB_SoundSample;
|
||||||
|
|
||||||
// equivalent to channel in legacy sound code
|
// equivalent to channel in legacy sound code
|
||||||
@@ -52,7 +53,6 @@ typedef struct tfb_soundsource
|
|||||||
{
|
{
|
||||||
TFB_SoundSample *sample;
|
TFB_SoundSample *sample;
|
||||||
ALuint handle;
|
ALuint handle;
|
||||||
BOOLEAN stream_looping;
|
|
||||||
BOOLEAN stream_should_be_playing;
|
BOOLEAN stream_should_be_playing;
|
||||||
Mutex stream_mutex;
|
Mutex stream_mutex;
|
||||||
} TFB_SoundSource;
|
} 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 ALfloat listenerOri[]; // listener orientation (two 3 float vectors, "look at" and "up")
|
||||||
extern TFB_SoundSource soundSource[];
|
extern TFB_SoundSource soundSource[];
|
||||||
|
|
||||||
ALenum DetermineALFormat (Sound_Sample *sample);
|
|
||||||
void SetSFXVolume (float volume);
|
void SetSFXVolume (float volume);
|
||||||
void SetSpeechVolume (float volume);
|
void SetSpeechVolume (float volume);
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* By Mika Kolehmainen, 2002-10-23
|
/* By Mika Kolehmainen, 2002-10-23
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef SOUNDMODULE_OPENAL
|
#ifdef SOUNDMODULE_OPENAL
|
||||||
|
|
||||||
@@ -25,38 +25,39 @@ BOOLEAN speech_advancetrack = FALSE;
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
PlayStream (TFB_SoundSample *sample, ALuint source, BOOLEAN looping)
|
PlayStream (TFB_SoundSample *sample, ALuint source, ALboolean looping)
|
||||||
{
|
{
|
||||||
int i;
|
ALuint i;
|
||||||
ALenum format = DetermineALFormat (sample->decoder);
|
|
||||||
|
if (!sample)
|
||||||
|
return;
|
||||||
|
|
||||||
StopStream (source);
|
StopStream (source);
|
||||||
|
|
||||||
Sound_Rewind (sample->decoder);
|
SoundDecoder_Rewind (sample->decoder);
|
||||||
soundSource[source].sample = sample;
|
soundSource[source].sample = sample;
|
||||||
|
soundSource[source].sample->decoder->looping = looping;
|
||||||
|
|
||||||
alSourcei (soundSource[source].handle, AL_LOOPING, AL_FALSE);
|
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 ||
|
decoded_bytes = SoundDecoder_Decode (sample->decoder);
|
||||||
sample->decoder->flags & SOUND_SAMPLEFLAG_ERROR)
|
|
||||||
break;
|
|
||||||
|
|
||||||
decoded_bytes = Sound_Decode (sample->decoder);
|
|
||||||
//fprintf (stderr, "PlayStream(): source %d sample %x decoded_bytes %d\n", source, sample, decoded_bytes);
|
//fprintf (stderr, "PlayStream(): source %d sample %x decoded_bytes %d\n", source, sample, decoded_bytes);
|
||||||
if (decoded_bytes == 0)
|
if (decoded_bytes == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
alBufferData (sample->buffer[i], format, sample->decoder->buffer,
|
alBufferData (sample->buffer[i], sample->decoder->format, sample->decoder->buffer,
|
||||||
decoded_bytes, sample->decoder->actual.rate);
|
decoded_bytes, sample->decoder->frequency);
|
||||||
|
|
||||||
alSourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]);
|
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;
|
soundSource[source].stream_should_be_playing = TRUE;
|
||||||
alSourcePlay (soundSource[source].handle);
|
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_PROCESSED, &processed);
|
||||||
alGetSourcei (soundSource[source].handle, AL_BUFFERS_QUEUED, &queued);
|
alGetSourcei (soundSource[source].handle, AL_BUFFERS_QUEUED, &queued);
|
||||||
|
|
||||||
//fprintf (stderr, "StopStream(): source %d processed %d queued %d NUM_SOUNDBUFFERS %d\n",
|
//fprintf (stderr, "StopStream(): source %d processed %d queued %d num_buffers %d\n", source, processed, queued, soundSource[source].sample->num_buffers);
|
||||||
// source, processed, queued, NUM_SOUNDBUFFERS);
|
|
||||||
|
|
||||||
buffer = (ALuint *) HMalloc (sizeof (ALuint) * processed);
|
if (processed != 0)
|
||||||
alSourceUnqueueBuffers (soundSource[source].handle, processed, buffer);
|
{
|
||||||
HFree (buffer);
|
buffer = (ALuint *) HMalloc (sizeof (ALuint) * processed);
|
||||||
|
alSourceUnqueueBuffers (soundSource[source].handle, processed, buffer);
|
||||||
|
HFree (buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -114,8 +117,7 @@ StreamDecoderTaskFunc (void *data)
|
|||||||
|
|
||||||
for (i = MUSIC_SOURCE; i < NUM_SOUNDSOURCES; ++i)
|
for (i = MUSIC_SOURCE; i < NUM_SOUNDSOURCES; ++i)
|
||||||
{
|
{
|
||||||
ALuint processed;
|
ALuint processed, queued;
|
||||||
ALuint queued;
|
|
||||||
ALint state;
|
ALint state;
|
||||||
ALboolean finished = AL_FALSE;
|
ALboolean finished = AL_FALSE;
|
||||||
ALboolean do_speech_advancetrack = AL_FALSE;
|
ALboolean do_speech_advancetrack = AL_FALSE;
|
||||||
@@ -125,8 +127,7 @@ StreamDecoderTaskFunc (void *data)
|
|||||||
if (!soundSource[i].sample ||
|
if (!soundSource[i].sample ||
|
||||||
!soundSource[i].sample->decoder ||
|
!soundSource[i].sample->decoder ||
|
||||||
!soundSource[i].stream_should_be_playing ||
|
!soundSource[i].stream_should_be_playing ||
|
||||||
soundSource[i].sample->decoder->flags & SOUND_SAMPLEFLAG_EOF ||
|
soundSource[i].sample->decoder->error == SOUNDDECODER_ERROR)
|
||||||
soundSource[i].sample->decoder->flags & SOUND_SAMPLEFLAG_ERROR)
|
|
||||||
{
|
{
|
||||||
UnlockMutex (soundSource[i].stream_mutex);
|
UnlockMutex (soundSource[i].stream_mutex);
|
||||||
continue;
|
continue;
|
||||||
@@ -138,86 +139,72 @@ StreamDecoderTaskFunc (void *data)
|
|||||||
alGetSourcei (soundSource[i].handle, AL_SOURCE_STATE, &state);
|
alGetSourcei (soundSource[i].handle, AL_SOURCE_STATE, &state);
|
||||||
if (state != AL_PLAYING)
|
if (state != AL_PLAYING)
|
||||||
{
|
{
|
||||||
//fprintf (stderr, "StreamDecoderTaskFunc(): forcing alSourcePlay on %d\n", i);
|
if (soundSource[i].sample->decoder->error == SOUNDDECODER_EOF)
|
||||||
alSourcePlay (soundSource[i].handle);
|
{
|
||||||
|
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);
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
//fprintf (stderr, "StreamDecoderTaskFunc(): source %d, processed %d queued %d\n", i, processed, queued);
|
//fprintf (stderr, "StreamDecoderTaskFunc(): source %d, processed %d queued %d\n", i, processed, queued);
|
||||||
|
|
||||||
while (processed && !finished)
|
while (processed && !finished)
|
||||||
{
|
{
|
||||||
ALenum format, error;
|
ALenum error;
|
||||||
ALuint buffer;
|
ALuint buffer;
|
||||||
Uint32 decoded_bytes;
|
ALuint decoded_bytes;
|
||||||
|
|
||||||
alGetError (); // clear error state
|
alGetError (); // clear error state
|
||||||
|
|
||||||
alSourceUnqueueBuffers (soundSource[i].handle, 1, &buffer);
|
alSourceUnqueueBuffers (soundSource[i].handle, 1, &buffer);
|
||||||
if ((error = alGetError()) != AL_NO_ERROR)
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
if (soundSource[i].sample->decoder->error)
|
||||||
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 (i == SPEECH_SOURCE && speech_advancetrack)
|
if (soundSource[i].sample->decoder->error == SOUNDDECODER_EOF)
|
||||||
{
|
{
|
||||||
finished = AL_TRUE;
|
//fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is eof for %s\n", soundSource[i].sample->decoder->filename);
|
||||||
soundSource[i].stream_should_be_playing = FALSE;
|
|
||||||
do_speech_advancetrack = AL_TRUE;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (soundSource[i].stream_looping)
|
//fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is %d for %s\n", soundSource[i].sample->decoder->error, soundSource[i].sample->decoder->filename);
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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",
|
fprintf (stderr, "StreamDecoderTaskFunc(): SoundDecoder_Decode error %d, file %s, source %d\n", soundSource[i].sample->decoder->error, soundSource[i].sample->decoder->filename, i);
|
||||||
Sound_GetError(), i);
|
|
||||||
soundSource[i].stream_should_be_playing = FALSE;
|
soundSource[i].stream_should_be_playing = FALSE;
|
||||||
break;
|
processed--;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decoded_bytes > 0)
|
if (decoded_bytes > 0)
|
||||||
{
|
{
|
||||||
format = DetermineALFormat (soundSource[i].sample->decoder);
|
alBufferData (buffer, soundSource[i].sample->decoder->format,
|
||||||
alBufferData (buffer, format, soundSource[i].sample->decoder->buffer,
|
soundSource[i].sample->decoder->buffer, decoded_bytes,
|
||||||
decoded_bytes, soundSource[i].sample->decoder->actual.rate);
|
soundSource[i].sample->decoder->frequency);
|
||||||
|
|
||||||
if ((error = alGetError()) != AL_NO_ERROR)
|
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;
|
finished = AL_TRUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -226,7 +213,8 @@ StreamDecoderTaskFunc (void *data)
|
|||||||
|
|
||||||
if ((error = alGetError()) != AL_NO_ERROR)
|
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;
|
finished = AL_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#ifndef STREAM_H
|
#ifndef STREAM_H
|
||||||
#define 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 StopStream (ALuint source);
|
||||||
void PauseStream (ALuint source);
|
void PauseStream (ALuint source);
|
||||||
void ResumeStream (ALuint source);
|
void ResumeStream (ALuint source);
|
||||||
|
|||||||
@@ -153,8 +153,9 @@ StopTrack ()
|
|||||||
{
|
{
|
||||||
if (track_clip[tct].sample->decoder)
|
if (track_clip[tct].sample->decoder)
|
||||||
{
|
{
|
||||||
Sound_FreeSample (track_clip[tct].sample->decoder);
|
SoundDecoder_Free (track_clip[tct].sample->decoder);
|
||||||
alDeleteBuffers (NUM_SOUNDBUFFERS, track_clip[tct].sample->buffer);
|
alDeleteBuffers (track_clip[tct].sample->num_buffers, track_clip[tct].sample->buffer);
|
||||||
|
HFree (track_clip[tct].sample->buffer);
|
||||||
}
|
}
|
||||||
HFree (track_clip[tct].sample);
|
HFree (track_clip[tct].sample);
|
||||||
track_clip[tct].sample = 0;
|
track_clip[tct].sample = 0;
|
||||||
@@ -199,21 +200,22 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText)
|
|||||||
fprintf (stderr, "SpliceTrack(): loading %s\n", TrackName);
|
fprintf (stderr, "SpliceTrack(): loading %s\n", TrackName);
|
||||||
|
|
||||||
track_clip[tct].sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
|
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)
|
if (track_clip[tct].sample->decoder)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "decoder %s rate %d channels %d\n",
|
fprintf (stderr, " decoder: %s, rate %d format %x\n",
|
||||||
track_clip[tct].sample->decoder->decoder->description,
|
track_clip[tct].sample->decoder->decoder_info,
|
||||||
track_clip[tct].sample->decoder->actual.rate,
|
track_clip[tct].sample->decoder->frequency,
|
||||||
track_clip[tct].sample->decoder->actual.channels);
|
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
|
else
|
||||||
{
|
{
|
||||||
fprintf (stderr, "SpliceTrack(): couldn't load %s: %s\n",
|
fprintf (stderr, "SpliceTrack(): couldn't load %s\n", TrackName);
|
||||||
TrackName, Sound_GetError());
|
|
||||||
HFree (track_clip[tct].sample);
|
HFree (track_clip[tct].sample);
|
||||||
track_clip[tct].sample = NULL;
|
track_clip[tct].sample = NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,17 +18,19 @@
|
|||||||
|
|
||||||
#ifdef SOUNDMODULE_SDL
|
#ifdef SOUNDMODULE_SDL
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#include <io.h>
|
|
||||||
#endif
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "libs/strings/strintrn.h"
|
#include "libs/strings/strintrn.h"
|
||||||
#include "libs/sound/sndintrn.h"
|
#include "libs/sound/sndintrn.h"
|
||||||
#include "libs/graphics/sdl/sdl_common.h"
|
#include "libs/graphics/sdl/sdl_common.h"
|
||||||
#include "libs/sound/sound_common.h"
|
#include "libs/sound/sound_common.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <io.h>
|
||||||
|
#include <SDL_mixer.h>
|
||||||
|
#else
|
||||||
#include <SDL/SDL_mixer.h>
|
#include <SDL/SDL_mixer.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
MEM_HANDLE
|
MEM_HANDLE
|
||||||
|
|||||||
@@ -19,10 +19,14 @@
|
|||||||
#ifdef SOUNDMODULE_SDL
|
#ifdef SOUNDMODULE_SDL
|
||||||
|
|
||||||
#include "libs/sound/sndintrn.h"
|
#include "libs/sound/sndintrn.h"
|
||||||
|
|
||||||
#include "libs/graphics/sdl/sdl_common.h"
|
#include "libs/graphics/sdl/sdl_common.h"
|
||||||
#include "libs/sound/sound_common.h"
|
#include "libs/sound/sound_common.h"
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <SDL_mixer.h>
|
||||||
|
#else
|
||||||
#include <SDL/SDL_mixer.h>
|
#include <SDL/SDL_mixer.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
static MUSIC_REF curMusicRef;
|
static MUSIC_REF curMusicRef;
|
||||||
|
|
||||||
|
|||||||
@@ -20,17 +20,19 @@
|
|||||||
|
|
||||||
#include "libs/graphics/sdl/sdl_common.h"
|
#include "libs/graphics/sdl/sdl_common.h"
|
||||||
#include "libs/sound/sound_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>
|
#include <SDL/SDL_mixer.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
int
|
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];
|
char SoundcardName[256];
|
||||||
int audio_rate,audio_channels;
|
int audio_rate, audio_channels, audio_bufsize;
|
||||||
Uint16 audio_format;
|
Uint16 audio_format;
|
||||||
SDL_version compile_version;
|
SDL_version compile_version;
|
||||||
|
|
||||||
@@ -42,20 +44,40 @@ TFB_InitSound (int driver, int flags, int frequency)
|
|||||||
}
|
}
|
||||||
fprintf (stderr, "SDL audio subsystem initialized.\n");
|
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");
|
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());
|
fprintf (stderr, "Unable to open audio: %s\n", Mix_GetError());
|
||||||
exit (-1);
|
exit (-1);
|
||||||
}
|
}
|
||||||
fprintf (stderr, "SDL_mixer initialized.\n");
|
fprintf (stderr, "SDL_mixer initialized.\n");
|
||||||
atexit (Mix_CloseAudio);
|
|
||||||
|
atexit (TFB_UninitSound);
|
||||||
|
|
||||||
SDL_AudioDriverName (SoundcardName, sizeof (SoundcardName));
|
SDL_AudioDriverName (SoundcardName, sizeof (SoundcardName));
|
||||||
Mix_QuerySpec (&audio_rate, &audio_format, &audio_channels);
|
Mix_QuerySpec (&audio_rate, &audio_format, &audio_channels);
|
||||||
fprintf (stderr, " opened %s at %d Hz %d bit %s, %d bytes audio buffer\n",
|
fprintf (stderr, " opened %s at %d Hz %d bit %s, %d bytes audio buffer\n",
|
||||||
SoundcardName, audio_rate, audio_format & 0xFF,
|
SoundcardName, audio_rate, audio_format & 0xFF,
|
||||||
audio_channels > 1 ? "stereo" : "mono", 2048);
|
audio_channels > 1 ? "stereo" : "mono", audio_bufsize);
|
||||||
MIX_VERSION (&compile_version);
|
MIX_VERSION (&compile_version);
|
||||||
fprintf (stderr, " compiled with SDL_mixer version: %d.%d.%d\n",
|
fprintf (stderr, " compiled with SDL_mixer version: %d.%d.%d\n",
|
||||||
compile_version.major,
|
compile_version.major,
|
||||||
@@ -69,6 +91,11 @@ TFB_InitSound (int driver, int flags, int frequency)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TFB_UninitSound (void)
|
||||||
|
{
|
||||||
|
Mix_CloseAudio ();
|
||||||
|
}
|
||||||
|
|
||||||
//Status: Unimplemented
|
//Status: Unimplemented
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -21,7 +21,12 @@
|
|||||||
#include "libs/graphics/sdl/sdl_common.h"
|
#include "libs/graphics/sdl/sdl_common.h"
|
||||||
#include "libs/sound/sound_common.h"
|
#include "libs/sound/sound_common.h"
|
||||||
#include "libs/sound/trackplayer.h"
|
#include "libs/sound/trackplayer.h"
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <SDL_mixer.h>
|
||||||
|
#else
|
||||||
#include <SDL/SDL_mixer.h>
|
#include <SDL/SDL_mixer.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define VOICE_CHANNEL 0
|
#define VOICE_CHANNEL 0
|
||||||
|
|||||||
@@ -26,9 +26,11 @@ enum
|
|||||||
};
|
};
|
||||||
|
|
||||||
// flags for TFB_InitSound
|
// 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);
|
void TFB_UninitSound (void);
|
||||||
|
|
||||||
extern int musicVolume;
|
extern int musicVolume;
|
||||||
|
|||||||
+35
-18
@@ -51,10 +51,12 @@ main (int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
int gfxdriver = TFB_GFXDRIVER_SDL_PURE;
|
int gfxdriver = TFB_GFXDRIVER_SDL_PURE;
|
||||||
int gfxflags = 0;
|
int gfxflags = 0;
|
||||||
|
int soundflags = TFB_SOUNDFLAGS_MQAUDIO;
|
||||||
int width = 640, height = 480, bpp = 16;
|
int width = 640, height = 480, bpp = 16;
|
||||||
int frequency = 44100;
|
int frequency = 44100;
|
||||||
int vol;
|
int vol;
|
||||||
char contentdir[1000];
|
char contentdir[1000];
|
||||||
|
char str[1000];
|
||||||
|
|
||||||
int option_index = 0, c;
|
int option_index = 0, c;
|
||||||
static struct option long_options[] =
|
static struct option long_options[] =
|
||||||
@@ -64,7 +66,6 @@ main (int argc, char *argv[])
|
|||||||
{"fullscreen", 0, NULL, 'f'},
|
{"fullscreen", 0, NULL, 'f'},
|
||||||
{"opengl", 0, NULL, 'o'},
|
{"opengl", 0, NULL, 'o'},
|
||||||
{"bilinear", 0, NULL, 'b'},
|
{"bilinear", 0, NULL, 'b'},
|
||||||
{"frequency", 1, NULL, 'q'},
|
|
||||||
{"fps", 0, NULL, 'p'},
|
{"fps", 0, NULL, 'p'},
|
||||||
{"tv", 0, NULL, 't'},
|
{"tv", 0, NULL, 't'},
|
||||||
{"contentdir", 1, NULL, 'c'},
|
{"contentdir", 1, NULL, 'c'},
|
||||||
@@ -74,6 +75,7 @@ main (int argc, char *argv[])
|
|||||||
{"speechvol", 1, NULL, 'T'},
|
{"speechvol", 1, NULL, 'T'},
|
||||||
{"3domusic", 0, NULL, 'e'},
|
{"3domusic", 0, NULL, 'e'},
|
||||||
{"pcmusic", 0, NULL, 'm'},
|
{"pcmusic", 0, NULL, 'm'},
|
||||||
|
{"audioquality", 1, NULL, 'q'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -83,7 +85,7 @@ main (int argc, char *argv[])
|
|||||||
strcpy (contentdir, "../../content");
|
strcpy (contentdir, "../../content");
|
||||||
#endif
|
#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) {
|
switch (c) {
|
||||||
case 'r':
|
case 'r':
|
||||||
@@ -101,9 +103,6 @@ main (int argc, char *argv[])
|
|||||||
case 'b':
|
case 'b':
|
||||||
gfxflags |= TFB_GFXFLAGS_BILINEAR_FILTERING;
|
gfxflags |= TFB_GFXFLAGS_BILINEAR_FILTERING;
|
||||||
break;
|
break;
|
||||||
case 'q':
|
|
||||||
sscanf(optarg, "%d", &frequency);
|
|
||||||
break;
|
|
||||||
case 'p':
|
case 'p':
|
||||||
gfxflags |= TFB_GFXFLAGS_SHOWFPS;
|
gfxflags |= TFB_GFXFLAGS_SHOWFPS;
|
||||||
break;
|
break;
|
||||||
@@ -143,26 +142,44 @@ main (int argc, char *argv[])
|
|||||||
case 'm':
|
case 'm':
|
||||||
optWhichMusic = MUSIC_PC;
|
optWhichMusic = MUSIC_PC;
|
||||||
break;
|
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:
|
default:
|
||||||
printf ("\nOption %s not found!\n", long_options[option_index].name);
|
printf ("\nOption %s not found!\n", long_options[option_index].name);
|
||||||
case '?':
|
case '?':
|
||||||
case 'h':
|
case 'h':
|
||||||
printf("\nThe Ur-Quan Masters\n");
|
printf("\nThe Ur-Quan Masters\n");
|
||||||
printf("Options:\n");
|
printf("Options:\n");
|
||||||
printf(" -r, --res=WIDTHxHEIGHT\n");
|
printf(" -r, --res=WIDTHxHEIGHT (default 640x480, others work only with --opengl)\n");
|
||||||
printf(" -d, --bpp=BITSPERPIXEL\n");
|
printf(" -d, --bpp=BITSPERPIXEL (default 16)\n");
|
||||||
printf(" -f, --fullscreen\n");
|
printf(" -f, --fullscreen (default off)\n");
|
||||||
printf(" -o, --opengl\n");
|
printf(" -o, --opengl (default off, usage recommended if TNT2 or better gfx card)\n");
|
||||||
printf(" -b, --bilinear\n");
|
printf(" -b, --bilinear (default off, only works with --opengl)\n");
|
||||||
printf(" -q, --frequency=FREQUENCY\n");
|
printf(" -p, --fps (default off)\n");
|
||||||
printf(" -p, --fps\n");
|
printf(" -t, --tv (default off, only works with --opengl\n");
|
||||||
printf(" -t, --tv\n");
|
|
||||||
printf(" -c, --contentdir=CONTENTDIR\n");
|
printf(" -c, --contentdir=CONTENTDIR\n");
|
||||||
printf(" -M, --musicvol=VOLUME (0-100)\n");
|
printf(" -M, --musicvol=VOLUME (0-100, default 100)\n");
|
||||||
printf(" -S, --sfxvol=VOLUME (0-100)\n");
|
printf(" -S, --sfxvol=VOLUME (0-100, default 100)\n");
|
||||||
printf(" -T, --speechvol=VOLUME (0-100)\n");
|
printf(" -T, --speechvol=VOLUME (0-100, default 100)\n");
|
||||||
printf(" -e, --3domusic\n");
|
printf(" -e, --3domusic (default)\n");
|
||||||
printf(" -m, --pcmusic\n");
|
printf(" -m, --pcmusic\n");
|
||||||
|
printf(" -q, --audioquality=QUALITY (high, medium or low, default medium)\n");
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -179,7 +196,7 @@ main (int argc, char *argv[])
|
|||||||
mem_init ();
|
mem_init ();
|
||||||
|
|
||||||
TFB_InitGraphics (gfxdriver, gfxflags, width, height, bpp);
|
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);
|
TFB_InitInput (TFB_INPUTDRIVER_SDL, 0);
|
||||||
|
|
||||||
AssignTask (Starcon2Main, 1024, "Starcon2Main");
|
AssignTask (Starcon2Main, 1024, "Starcon2Main");
|
||||||
|
|||||||
Reference in New Issue
Block a user