This commit is contained in:
Christoph Oelckers 2015-12-28 22:52:48 +01:00
commit b27116cbbd
25 changed files with 6477 additions and 8 deletions

View file

@ -188,6 +188,7 @@ else( WIN32 )
if( GTK2_FOUND )
set( ZDOOM_LIBS ${ZDOOM_LIBS} ${GTK2_LIBRARIES} )
include_directories( ${GTK2_INCLUDE_DIRS} )
link_directories( ${GTK2_LIBRARY_DIRS} )
else( GTK2_FOUND )
set( NO_GTK ON )
endif( GTK2_FOUND )
@ -1174,6 +1175,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
sound/music_midistream.cpp
sound/music_midi_base.cpp
sound/music_midi_timidity.cpp
sound/music_midi_wildmidi.cpp
sound/music_mus_opl.cpp
sound/music_stream.cpp
sound/music_fluidsynth_mididevice.cpp
@ -1222,6 +1224,12 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
timidity/playmidi.cpp
timidity/resample.cpp
timidity/timidity.cpp
wildmidi/file_io.cpp
wildmidi/gus_pat.cpp
wildmidi/lock.cpp
wildmidi/reverb.cpp
wildmidi/wildmidi_lib.cpp
wildmidi/wm_error.cpp
xlat/parse_xlat.cpp
fragglescript/t_fspic.cpp
fragglescript/t_func.cpp
@ -1359,6 +1367,8 @@ source_group("Audio Files\\OPL Synth" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURC
source_group("Audio Files\\OPL Synth\\DOSBox" FILES oplsynth/dosbox/opl.cpp oplsynth/dosbox/opl.h)
source_group("Audio Files\\Timidity\\Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/timidity/.+\\.h$")
source_group("Audio Files\\Timidity\\Source" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/timidity/.+\\.cpp$")
source_group("Audio Files\\WildMidi\\Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/wildmidi/.+\\.h$")
source_group("Audio Files\\WildMidi\\Source" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/wildmidi/.+\\.cpp$")
source_group("Decorate++" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/thingdef/.+")
source_group("FraggleScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/fragglescript/.+")
source_group("Games\\Doom Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_doom/.+")

View file

@ -1347,9 +1347,10 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply
int rootnode = npc->ConversationRoot;
if (reply->NextNode < 0)
{
npc->Conversation = StrifeDialogues[rootnode - reply->NextNode - 1];
if (gameaction != ga_slideshow)
unsigned next = (unsigned)(rootnode - reply->NextNode - 1);
if (gameaction != ga_slideshow && next < StrifeDialogues.Size())
{
npc->Conversation = StrifeDialogues[next];
P_StartConversation (npc, player->mo, player->ConversationFaceTalker, false);
return;
}

View file

@ -566,6 +566,10 @@ void APlayerPawn::Serialize (FArchive &arc)
{
arc << AirCapacity;
}
if (SaveVersion >= 4526)
{
arc << ViewHeight;
}
}
//===========================================================================

View file

@ -1372,6 +1372,7 @@ static void S_AddSNDINFO (int lump)
else if (sc.Compare("default")) MidiDevices[nm] = MDEV_DEFAULT;
else if (sc.Compare("fluidsynth")) MidiDevices[nm] = MDEV_FLUIDSYNTH;
else if (sc.Compare("gus")) MidiDevices[nm] = MDEV_GUS;
else if (sc.Compare("wildmidi")) MidiDevices[nm] = MDEV_WILDMIDI;
else sc.ScriptError("Unknown MIDI device %s\n", sc.String);
}
break;

View file

@ -394,6 +394,7 @@ enum EMidiDevice
MDEV_TIMIDITY = 3,
MDEV_FLUIDSYNTH = 4,
MDEV_GUS = 5,
MDEV_WILDMIDI = 6,
};
typedef TMap<FName, FName> MusicAliasMap;

View file

@ -189,6 +189,7 @@ void I_ShutdownMusic(void)
assert (currSong == NULL);
}
Timidity::FreeAll();
WildMidi_Shutdown();
#ifdef _WIN32
I_ShutdownMusicWin32();
#endif // _WIN32

View file

@ -24,6 +24,7 @@
#include "i_music.h"
#include "s_sound.h"
#include "files.h"
#include "wildmidi/wildmidi_lib.h"
void I_InitMusicWin32 ();
void I_ShutdownMusicWin32 ();
@ -218,6 +219,24 @@ protected:
#endif
};
class WildMidiMIDIDevice : public PseudoMIDIDevice
{
public:
WildMidiMIDIDevice();
~WildMidiMIDIDevice();
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
bool Preprocess(MIDIStreamer *song, bool looping);
bool IsOpen() const;
protected:
midi *mMidi;
bool mLoop;
static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata);
};
// Base class for software synthesizer MIDI output devices ------------------

View file

@ -11,9 +11,9 @@ static DWORD nummididevices;
static bool nummididevicesset;
#ifdef HAVE_FLUIDSYNTH
#define NUM_DEF_DEVICES 5
#define NUM_DEF_DEVICES 6
#else
#define NUM_DEF_DEVICES 4
#define NUM_DEF_DEVICES 5
#endif
static void AddDefaultMidiDevices(FOptionValues *opt)
@ -33,8 +33,10 @@ static void AddDefaultMidiDevices(FOptionValues *opt)
pair[p+1].Value = -3.0;
pair[p+2].Text = "TiMidity++";
pair[p+2].Value = -2.0;
pair[p+3].Text = "Sound System";
pair[p+3].Value = -1.0;
pair[p+3].Text = "WildMidi";
pair[p+3].Value = -6.0;
pair[p+4].Text = "Sound System";
pair[p+4].Value = -1.0;
}
@ -70,7 +72,7 @@ CUSTOM_CVAR (Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
if (!nummididevicesset)
return;
if ((self >= (signed)nummididevices) || (self < -5))
if ((self >= (signed)nummididevices) || (self < -6))
{
Printf ("ID out of range. Using default device.\n");
self = 0;
@ -211,6 +213,7 @@ void I_BuildMIDIMenuList (FOptionValues *opt)
CCMD (snd_listmididevices)
{
Printf("%s-6. WildMidi\n", -6 == snd_mididevice ? TEXTCOLOR_BOLD : "");
#ifdef HAVE_FLUIDSYNTH
Printf("%s-5. FluidSynth\n", -5 == snd_mididevice ? TEXTCOLOR_BOLD : "");
#endif

View file

@ -0,0 +1,163 @@
#include "i_musicinterns.h"
#include "c_cvars.h"
#include "cmdlib.h"
#include "templates.h"
#include "version.h"
CVAR(String, wildmidi_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
static FString currentConfig;
// added because Timidity's output is rather loud.
CUSTOM_CVAR (Float, wildmidi_mastervolume, 1.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
if (self < 0.f)
self = 0.f;
else if (self > 1.f)
self = 1.f;
}
CUSTOM_CVAR (Int, wildmidi_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{ // Clamp frequency to Timidity's limits
if (self < 11000)
self = 11000;
else if (self > 65000)
self = 65000;
}
//==========================================================================
//
// WildMidiMIDIDevice Constructor
//
//==========================================================================
WildMidiMIDIDevice::WildMidiMIDIDevice()
{
mMidi = NULL;
mLoop = false;
}
//==========================================================================
//
// WildMidiMIDIDevice Destructor
//
//==========================================================================
WildMidiMIDIDevice::~WildMidiMIDIDevice ()
{
if (mMidi != NULL) WildMidi_Close(mMidi);
// do not shut down the device so that it can be reused for the next song being played.
}
//==========================================================================
//
// WildMidiMIDIDevice :: Preprocess
//
//==========================================================================
bool WildMidiMIDIDevice::Preprocess(MIDIStreamer *song, bool looping)
{
TArray<BYTE> midi;
// Write MIDI song to temporary file
song->CreateSMF(midi, looping ? 0 : 1);
mMidi = WildMidi_OpenBuffer(&midi[0], midi.Size());
if (mMidi == NULL)
{
Printf(PRINT_BOLD, "Could not open temp music file\n");
}
mLoop = looping;
return false;
}
//==========================================================================
//
// WildMidiMIDIDevice :: Open
//
//==========================================================================
int WildMidiMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata)
{
if (currentConfig.CompareNoCase(wildmidi_config) != 0)
{
if (currentConfig.IsNotEmpty()) WildMidi_Shutdown();
currentConfig = "";
if (!WildMidi_Init(wildmidi_config, wildmidi_frequency, WM_MO_ENHANCED_RESAMPLING))
{
currentConfig = wildmidi_config;
}
else
{
return 1;
}
}
Stream = GSnd->CreateStream(FillStream, 32 * 1024, 0, wildmidi_frequency, this);
if (Stream == NULL)
{
Printf(PRINT_BOLD, "Could not create music stream.\n");
return 1;
}
return 0;
}
//==========================================================================
//
// WildMidiMIDIDevice :: FillStream
//
//==========================================================================
bool WildMidiMIDIDevice::FillStream(SoundStream *stream, void *buff, int len, void *userdata)
{
char *buffer = (char*)buff;
WildMidiMIDIDevice *song = (WildMidiMIDIDevice *)userdata;
if (song->mMidi != NULL)
{
while (len > 0)
{
int written = WildMidi_GetOutput(song->mMidi, buffer, len);
if (written < 0)
{
// error
memset(buffer, 0, len);
return false;
}
buffer += written;
len -= written;
if (len > 0)
{
if (!song->mLoop)
{
memset(buffer, 0, len);
return written > 0;
}
else
{
// loop the sound (i.e. go back to start.)
unsigned long spos = 0;
WildMidi_FastSeek(song->mMidi, &spos);
}
}
}
}
return true;
}
//==========================================================================
//
// WildMidiMIDIDevice :: IsOpen
//
//==========================================================================
bool WildMidiMIDIDevice::IsOpen() const
{
return mMidi != NULL;
}

View file

@ -240,6 +240,7 @@ EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device)
#ifdef HAVE_FLUIDSYNTH
case -5: return MDEV_FLUIDSYNTH;
#endif
case -6: return MDEV_WILDMIDI;
default:
#ifdef _WIN32
return MDEV_MMAPI;
@ -292,6 +293,9 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const
case MDEV_TIMIDITY:
return new TimidityPPMIDIDevice;
case MDEV_WILDMIDI:
return new WildMidiMIDIDevice;
default:
return NULL;
}

View file

@ -76,7 +76,7 @@ const char *GetVersionString();
// Use 4500 as the base git save version, since it's higher than the
// SVN revision ever got.
#define SAVEVER 4525
#define SAVEVER 4526
#define SAVEVERSTRINGIFY2(x) #x
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)

94
src/wildmidi/common.h Normal file
View file

@ -0,0 +1,94 @@
/*
common.h
Midi Wavetable Processing library
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef __COMMON_H
#define __COMMON_H
#define SAMPLE_16BIT 0x01
#define SAMPLE_UNSIGNED 0x02
#define SAMPLE_LOOP 0x04
#define SAMPLE_PINGPONG 0x08
#define SAMPLE_REVERSE 0x10
#define SAMPLE_SUSTAIN 0x20
#define SAMPLE_ENVELOPE 0x40
#define SAMPLE_CLAMPED 0x80
#ifdef DEBUG_SAMPLES
#define SAMPLE_CONVERT_DEBUG(dx) printf("\r%s\n",dx)
#else
#define SAMPLE_CONVERT_DEBUG(dx)
#endif
extern unsigned short int _WM_SampleRate;
struct _sample {
unsigned long int data_length;
unsigned long int loop_start;
unsigned long int loop_end;
unsigned long int loop_size;
unsigned char loop_fraction;
unsigned short int rate;
unsigned long int freq_low;
unsigned long int freq_high;
unsigned long int freq_root;
unsigned char modes;
signed long int env_rate[7];
signed long int env_target[7];
unsigned long int inc_div;
signed short *data;
struct _sample *next;
};
struct _env {
float time;
float level;
unsigned char set;
};
struct _patch {
unsigned short patchid;
unsigned char loaded;
char *filename;
signed short int amp;
unsigned char keep;
unsigned char remove;
struct _env env[6];
unsigned char note;
unsigned long int inuse_count;
struct _sample *first_sample;
struct _patch *next;
};
/* Set our global defines here */
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#ifndef M_LN2
#define M_LN2 0.69314718055994530942
#endif
#endif /* __COMMON_H */

71
src/wildmidi/file_io.cpp Normal file
View file

@ -0,0 +1,71 @@
/*
** file_io.cpp
** ZDoom compatible file IO interface for WildMIDI
** (This file was completely redone to remove the low level IO code references)
**
**---------------------------------------------------------------------------
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "../files.h"
#include "wm_error.h"
#include "file_io.h"
unsigned char *_WM_BufferFile(const char *filename, unsigned long int *size)
{
FileReader file;
if (!file.Open(filename))
{
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno);
return NULL;
}
long fsize = file.GetLength();
if (fsize > WM_MAXFILESIZE)
{
/* don't bother loading suspiciously long files */
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LONGFIL, filename, 0);
return NULL;
}
unsigned char *data = (unsigned char*)malloc(fsize+1);
if (data == NULL)
{
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno);
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno);
return NULL;
}
file.Read(data, fsize);
data[fsize] = 0;
*size = fsize;
return data;
}

33
src/wildmidi/file_io.h Normal file
View file

@ -0,0 +1,33 @@
/*
file_io.c
file handling
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef __FILE_IO_H
#define __FILE_IO_H
#define WM_MAXFILESIZE 0x1fffffff
extern unsigned char *_WM_BufferFile (const char *filename, unsigned long int *size);
#endif /* __FILE_IO_H */

900
src/wildmidi/gus_pat.cpp Normal file
View file

@ -0,0 +1,900 @@
/*
gus_pat.c
Midi Wavetable Processing library
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
//#include "config.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gus_pat.h"
#include "common.h"
#include "wm_error.h"
#include "file_io.h"
#ifdef DEBUG_GUSPAT
#define GUSPAT_FILENAME_DEBUG(dx) fprintf(stderr,"\r%s\n",dx)
#define GUSPAT_INT_DEBUG(dx,dy) fprintf(stderr,"\r%s: %i\n",dx,dy)
#define GUSPAT_FLOAT_DEBUG(dx,dy) fprintf(stderr,"\r%s: %f\n",dx,dy)
#define GUSPAT_START_DEBUG() fprintf(stderr,"\r")
#define GUSPAT_MODE_DEBUG(dx,dy,dz) if (dx & dy) fprintf(stderr,"%s",dz)
#define GUSPAT_END_DEBUG() fprintf(stderr,"\n")
#else
#define GUSPAT_FILENAME_DEBUG(dx)
#define GUSPAT_INT_DEBUG(dx,dy)
#define GUSPAT_FLOAT_DEBUG(dx,dy)
#define GUSPAT_START_DEBUG()
#define GUSPAT_MODE_DEBUG(dx,dy,dz)
#define GUSPAT_END_DEBUG()
#endif
/*
* sample data conversion functions
* convert data to signed shorts
*/
/* 8bit signed */
static int convert_8s(unsigned char *data, struct _sample *gus_sample) {
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->data_length;
signed short int *write_data = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc((gus_sample->data_length + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data++ = (*read_data++) << 8;
} while (read_data != read_end);
return 0;
}
_WM_ERROR_NEW("(%s:%i) ERROR: calloc failed (%s)", __FUNCTION__, __LINE__,
strerror(errno));
return -1;
}
/* 8bit signed ping pong */
static int convert_8sp(unsigned char *data, struct _sample *gus_sample) {
unsigned long int loop_length = gus_sample->loop_end
- gus_sample->loop_start;
unsigned long int dloop_length = loop_length * 2;
unsigned long int new_length = gus_sample->data_length + dloop_length;
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->loop_start;
signed short int *write_data = NULL;
signed short int *write_data_a = NULL;
signed short int *write_data_b = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data++ = (*read_data++) << 8;
} while (read_data != read_end);
*write_data = (*read_data++ << 8);
write_data_a = write_data + dloop_length;
*write_data_a-- = *write_data;
write_data++;
write_data_b = write_data + dloop_length;
read_end = data + gus_sample->loop_end;
do {
*write_data = (*read_data++) << 8;
*write_data_a-- = *write_data;
*write_data_b++ = *write_data;
write_data++;
} while (read_data != read_end);
*write_data = (*read_data++ << 8);
*write_data_b++ = *write_data;
read_end = data + gus_sample->data_length;
if (read_data != read_end) {
do {
*write_data_b++ = (*read_data++) << 8;
} while (read_data != read_end);
}
gus_sample->loop_start += loop_length;
gus_sample->loop_end += dloop_length;
gus_sample->data_length = new_length;
gus_sample->modes ^= SAMPLE_PINGPONG;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 8bit signed reverse */
static int convert_8sr(unsigned char *data, struct _sample *gus_sample) {
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->data_length;
signed short int *write_data = NULL;
unsigned long int tmp_loop = 0;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc((gus_sample->data_length + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data + gus_sample->data_length - 1;
do {
*write_data-- = (*read_data++) << 8;
} while (read_data != read_end);
tmp_loop = gus_sample->loop_end;
gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start;
gus_sample->loop_start = gus_sample->data_length - tmp_loop;
gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4)
| ((gus_sample->loop_fraction & 0xf0) >> 4);
gus_sample->modes ^= SAMPLE_REVERSE;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 8bit signed reverse ping pong */
static int convert_8srp(unsigned char *data, struct _sample *gus_sample) {
unsigned long int loop_length = gus_sample->loop_end
- gus_sample->loop_start;
unsigned long int dloop_length = loop_length * 2;
unsigned long int new_length = gus_sample->data_length + dloop_length;
unsigned char *read_data = data + gus_sample->data_length - 1;
unsigned char *read_end = data + gus_sample->loop_end;
signed short int *write_data = NULL;
signed short int *write_data_a = NULL;
signed short int *write_data_b = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data++ = (*read_data--) << 8;
} while (read_data != read_end);
*write_data = (*read_data-- << 8);
write_data_a = write_data + dloop_length;
*write_data_a-- = *write_data;
write_data++;
write_data_b = write_data + dloop_length;
read_end = data + gus_sample->loop_start;
do {
*write_data = (*read_data--) << 8;
*write_data_a-- = *write_data;
*write_data_b++ = *write_data;
write_data++;
} while (read_data != read_end);
*write_data = (*read_data-- << 8);
*write_data_b++ = *write_data;
read_end = data - 1;
do {
*write_data_b++ = (*read_data--) << 8;
write_data_b++;
} while (read_data != read_end);
gus_sample->loop_start += loop_length;
gus_sample->loop_end += dloop_length;
gus_sample->data_length = new_length;
gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 8bit unsigned */
static int convert_8u(unsigned char *data, struct _sample *gus_sample) {
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->data_length;
signed short int *write_data = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc((gus_sample->data_length + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data++ = ((*read_data++) ^ 0x80) << 8;
} while (read_data != read_end);
gus_sample->modes ^= SAMPLE_UNSIGNED;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 8bit unsigned ping pong */
static int convert_8up(unsigned char *data, struct _sample *gus_sample) {
unsigned long int loop_length = gus_sample->loop_end
- gus_sample->loop_start;
unsigned long int dloop_length = loop_length * 2;
unsigned long int new_length = gus_sample->data_length + dloop_length;
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->loop_start;
signed short int *write_data = NULL;
signed short int *write_data_a = NULL;
signed short int *write_data_b = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data++ = ((*read_data++) ^ 0x80) << 8;
} while (read_data != read_end);
*write_data = ((*read_data++) ^ 0x80) << 8;
write_data_a = write_data + dloop_length;
*write_data_a-- = *write_data;
write_data++;
write_data_b = write_data + dloop_length;
read_end = data + gus_sample->loop_end;
do {
*write_data = ((*read_data++) ^ 0x80) << 8;
*write_data_a-- = *write_data;
*write_data_b++ = *write_data;
write_data++;
} while (read_data != read_end);
*write_data = ((*read_data++) ^ 0x80) << 8;
*write_data_b++ = *write_data;
read_end = data + gus_sample->data_length;
if (read_data != read_end) {
do {
*write_data_b++ = ((*read_data++) ^ 0x80) << 8;
} while (read_data != read_end);
}
gus_sample->loop_start += loop_length;
gus_sample->loop_end += dloop_length;
gus_sample->data_length = new_length;
gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_UNSIGNED;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 8bit unsigned reverse */
static int convert_8ur(unsigned char *data, struct _sample *gus_sample) {
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->data_length;
signed short int *write_data = NULL;
unsigned long int tmp_loop = 0;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc((gus_sample->data_length + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data + gus_sample->data_length - 1;
do {
*write_data-- = ((*read_data++) ^ 0x80) << 8;
} while (read_data != read_end);
tmp_loop = gus_sample->loop_end;
gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start;
gus_sample->loop_start = gus_sample->data_length - tmp_loop;
gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4)
| ((gus_sample->loop_fraction & 0xf0) >> 4);
gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 8bit unsigned reverse ping pong */
static int convert_8urp(unsigned char *data, struct _sample *gus_sample) {
unsigned long int loop_length = gus_sample->loop_end
- gus_sample->loop_start;
unsigned long int dloop_length = loop_length * 2;
unsigned long int new_length = gus_sample->data_length + dloop_length;
unsigned char *read_data = data + gus_sample->data_length - 1;
unsigned char *read_end = data + gus_sample->loop_end;
signed short int *write_data = NULL;
signed short int *write_data_a = NULL;
signed short int *write_data_b = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data++ = ((*read_data--) ^ 0x80) << 8;
} while (read_data != read_end);
*write_data = ((*read_data--) ^ 0x80) << 8;
write_data_a = write_data + dloop_length;
*write_data_a-- = *write_data;
write_data++;
write_data_b = write_data + dloop_length;
read_end = data + gus_sample->loop_start;
do {
*write_data = ((*read_data--) ^ 0x80) << 8;
*write_data_a-- = *write_data;
*write_data_b++ = *write_data;
write_data++;
} while (read_data != read_end);
*write_data = ((*read_data--) ^ 0x80) << 8;
*write_data_b++ = *write_data;
read_end = data - 1;
do {
*write_data_b++ = ((*read_data--) ^ 0x80) << 8;
} while (read_data != read_end);
gus_sample->loop_start += loop_length;
gus_sample->loop_end += dloop_length;
gus_sample->data_length = new_length;
gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 16bit signed */
static int convert_16s(unsigned char *data, struct _sample *gus_sample) {
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->data_length;
signed short int *write_data = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data = *read_data++;
*write_data++ |= (*read_data++) << 8;
} while (read_data < read_end);
gus_sample->loop_start >>= 1;
gus_sample->loop_end >>= 1;
gus_sample->data_length >>= 1;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 16bit signed ping pong */
static int convert_16sp(unsigned char *data, struct _sample *gus_sample) {
unsigned long int loop_length = gus_sample->loop_end
- gus_sample->loop_start;
unsigned long int dloop_length = loop_length * 2;
unsigned long int new_length = gus_sample->data_length + dloop_length;
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->loop_start;
signed short int *write_data = NULL;
signed short int *write_data_a = NULL;
signed short int *write_data_b = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc(((new_length >> 1) + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data = (*read_data++);
*write_data++ |= (*read_data++) << 8;
} while (read_data < read_end);
*write_data = (*read_data++);
*write_data |= (*read_data++) << 8;
write_data_a = write_data + (dloop_length >> 1);
*write_data_a-- = *write_data;
write_data++;
write_data_b = write_data + (dloop_length >> 1);
read_end = data + gus_sample->loop_end;
do {
*write_data = (*read_data++);
*write_data |= (*read_data++) << 8;
*write_data_a-- = *write_data;
*write_data_b++ = *write_data;
write_data++;
} while (read_data < read_end);
*write_data = *(read_data++);
*write_data |= (*read_data++) << 8;
*write_data_b++ = *write_data;
read_end = data + gus_sample->data_length;
if (read_data != read_end) {
do {
*write_data_b = *(read_data++);
*write_data_b++ |= (*read_data++) << 8;
} while (read_data < read_end);
}
gus_sample->loop_start += loop_length;
gus_sample->loop_end += dloop_length;
gus_sample->data_length = new_length;
gus_sample->modes ^= SAMPLE_PINGPONG;
gus_sample->loop_start >>= 1;
gus_sample->loop_end >>= 1;
gus_sample->data_length >>= 1;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 16bit signed reverse */
static int convert_16sr(unsigned char *data, struct _sample *gus_sample) {
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->data_length;
signed short int *write_data = NULL;
unsigned long int tmp_loop = 0;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1;
do {
*write_data = *read_data++;
*write_data-- |= (*read_data++) << 8;
} while (read_data < read_end);
tmp_loop = gus_sample->loop_end;
gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start;
gus_sample->loop_start = gus_sample->data_length - tmp_loop;
gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4)
| ((gus_sample->loop_fraction & 0xf0) >> 4);
gus_sample->loop_start >>= 1;
gus_sample->loop_end >>= 1;
gus_sample->data_length >>= 1;
gus_sample->modes ^= SAMPLE_REVERSE;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 16bit signed reverse ping pong */
static int convert_16srp(unsigned char *data, struct _sample *gus_sample) {
unsigned long int loop_length = gus_sample->loop_end
- gus_sample->loop_start;
unsigned long int dloop_length = loop_length * 2;
unsigned long int new_length = gus_sample->data_length + dloop_length;
unsigned char *read_data = data + gus_sample->data_length - 1;
unsigned char *read_end = data + gus_sample->loop_end;
signed short int *write_data = NULL;
signed short int *write_data_a = NULL;
signed short int *write_data_b = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc(((new_length >> 1) + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data = (*read_data--) << 8;
*write_data++ |= *read_data--;
} while (read_data < read_end);
*write_data = (*read_data-- << 8);
*write_data |= *read_data--;
write_data_a = write_data + (dloop_length >> 1);
*write_data_a-- = *write_data;
write_data++;
write_data_b = write_data + (dloop_length >> 1);
read_end = data + gus_sample->loop_start;
do {
*write_data = (*read_data--) << 8;
*write_data |= *read_data--;
*write_data_a-- = *write_data;
*write_data_b++ = *write_data;
write_data++;
} while (read_data < read_end);
*write_data = ((*read_data--) << 8);
*write_data |= *read_data--;
*write_data_b++ = *write_data;
read_end = data - 1;
do {
*write_data_b = (*read_data--) << 8;
*write_data_b++ |= *read_data--;
} while (read_data < read_end);
gus_sample->loop_start += loop_length;
gus_sample->loop_end += dloop_length;
gus_sample->data_length = new_length;
gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 16bit unsigned */
static int convert_16u(unsigned char *data, struct _sample *gus_sample) {
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->data_length;
signed short int *write_data = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data = *read_data++;
*write_data++ |= ((*read_data++) ^ 0x80) << 8;
} while (read_data < read_end);
gus_sample->loop_start >>= 1;
gus_sample->loop_end >>= 1;
gus_sample->data_length >>= 1;
gus_sample->modes ^= SAMPLE_UNSIGNED;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 16bit unsigned ping pong */
static int convert_16up(unsigned char *data, struct _sample *gus_sample) {
unsigned long int loop_length = gus_sample->loop_end
- gus_sample->loop_start;
unsigned long int dloop_length = loop_length * 2;
unsigned long int new_length = gus_sample->data_length + dloop_length;
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->loop_start;
signed short int *write_data = NULL;
signed short int *write_data_a = NULL;
signed short int *write_data_b = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc(((new_length >> 1) + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data = (*read_data++);
*write_data++ |= ((*read_data++) ^ 0x80) << 8;
} while (read_data < read_end);
*write_data = (*read_data++);
*write_data |= ((*read_data++) ^ 0x80) << 8;
write_data_a = write_data + (dloop_length >> 1);
*write_data_a-- = *write_data;
write_data++;
write_data_b = write_data + (dloop_length >> 1);
read_end = data + gus_sample->loop_end;
do {
*write_data = (*read_data++);
*write_data |= ((*read_data++) ^ 0x80) << 8;
*write_data_a-- = *write_data;
*write_data_b++ = *write_data;
write_data++;
} while (read_data < read_end);
*write_data = (*read_data++);
*write_data |= ((*read_data++) ^ 0x80) << 8;
*write_data_b++ = *write_data;
read_end = data + gus_sample->data_length;
if (read_data != read_end) {
do {
*write_data_b = (*read_data++);
*write_data_b++ |= ((*read_data++) ^ 0x80) << 8;
} while (read_data < read_end);
}
gus_sample->loop_start += loop_length;
gus_sample->loop_end += dloop_length;
gus_sample->data_length = new_length;
gus_sample->modes ^= SAMPLE_PINGPONG;
gus_sample->loop_start >>= 1;
gus_sample->loop_end >>= 1;
gus_sample->data_length >>= 1;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 16bit unsigned reverse */
static int convert_16ur(unsigned char *data, struct _sample *gus_sample) {
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->data_length;
signed short int *write_data = NULL;
unsigned long int tmp_loop = 0;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1;
do {
*write_data = *read_data++;
*write_data-- |= ((*read_data++) ^ 0x80) << 8;
} while (read_data < read_end);
tmp_loop = gus_sample->loop_end;
gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start;
gus_sample->loop_start = gus_sample->data_length - tmp_loop;
gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4)
| ((gus_sample->loop_fraction & 0xf0) >> 4);
gus_sample->loop_start >>= 1;
gus_sample->loop_end >>= 1;
gus_sample->data_length >>= 1;
gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 16bit unsigned reverse ping pong */
static int convert_16urp(unsigned char *data, struct _sample *gus_sample) {
unsigned long int loop_length = gus_sample->loop_end
- gus_sample->loop_start;
unsigned long int dloop_length = loop_length * 2;
unsigned long int new_length = gus_sample->data_length + dloop_length;
unsigned char *read_data = data + gus_sample->data_length - 1;
unsigned char *read_end = data + gus_sample->loop_end;
signed short int *write_data = NULL;
signed short int *write_data_a = NULL;
signed short int *write_data_b = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc(((new_length >> 1) + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data = ((*read_data--) ^ 0x80) << 8;
*write_data++ |= *read_data--;
} while (read_data < read_end);
*write_data = ((*read_data--) ^ 0x80) << 8;
*write_data |= *read_data--;
write_data_a = write_data + (dloop_length >> 1);
*write_data_a-- = *write_data;
write_data++;
write_data_b = write_data + (dloop_length >> 1);
read_end = data + gus_sample->loop_start;
do {
*write_data = ((*read_data--) ^ 0x80) << 8;
*write_data |= *read_data--;
*write_data_a-- = *write_data;
*write_data_b++ = *write_data;
write_data++;
} while (read_data < read_end);
*write_data = ((*read_data--) ^ 0x80) << 8;
*write_data |= *read_data--;
*write_data_b++ = *write_data;
read_end = data - 1;
do {
*write_data_b = ((*read_data--) ^ 0x80) << 8;
*write_data_b++ |= *read_data--;
} while (read_data < read_end);
gus_sample->loop_start += loop_length;
gus_sample->loop_end += dloop_length;
gus_sample->data_length = new_length;
gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* sample loading */
struct _sample * _WM_load_gus_pat(const char *filename, int fix_release) {
unsigned char *gus_patch;
unsigned long int gus_size;
unsigned long int gus_ptr;
unsigned char no_of_samples;
struct _sample *gus_sample = NULL;
struct _sample *first_gus_sample = NULL;
unsigned long int i = 0;
int (*do_convert[])(unsigned char *data, struct _sample *gus_sample) = {
convert_8s,
convert_16s,
convert_8u,
convert_16u,
convert_8sp,
convert_16sp,
convert_8up,
convert_16up,
convert_8sr,
convert_16sr,
convert_8ur,
convert_16ur,
convert_8srp,
convert_16srp,
convert_8urp,
convert_16urp
};
unsigned long int tmp_loop;
SAMPLE_CONVERT_DEBUG(__FUNCTION__); SAMPLE_CONVERT_DEBUG(filename);
if ((gus_patch = _WM_BufferFile(filename, &gus_size)) == NULL) {
return NULL;
}
if (gus_size < 239) {
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0);
free(gus_patch);
return NULL;
}
if (memcmp(gus_patch, "GF1PATCH110\0ID#000002", 22)
&& memcmp(gus_patch, "GF1PATCH100\0ID#000002", 22)) {
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)",
0);
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0);
free(gus_patch);
return NULL;
}
if (gus_patch[82] > 1) {
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)",
0);
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0);
free(gus_patch);
return NULL;
}
if (gus_patch[151] > 1) {
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)",
0);
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0);
free(gus_patch);
return NULL;
}
GUSPAT_FILENAME_DEBUG(filename); GUSPAT_INT_DEBUG("voices",gus_patch[83]);
no_of_samples = gus_patch[198];
gus_ptr = 239;
while (no_of_samples) {
unsigned long int tmp_cnt;
if (first_gus_sample == NULL) {
first_gus_sample = (struct _sample*)malloc(sizeof(struct _sample));
gus_sample = first_gus_sample;
} else {
gus_sample->next = (struct _sample*)malloc(sizeof(struct _sample));
gus_sample = gus_sample->next;
}
if (gus_sample == NULL) {
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0);
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0);
free(gus_patch);
return NULL;
}
gus_sample->next = NULL;
gus_sample->loop_fraction = gus_patch[gus_ptr + 7];
gus_sample->data_length = (gus_patch[gus_ptr + 11] << 24)
| (gus_patch[gus_ptr + 10] << 16)
| (gus_patch[gus_ptr + 9] << 8) | gus_patch[gus_ptr + 8];
gus_sample->loop_start = (gus_patch[gus_ptr + 15] << 24)
| (gus_patch[gus_ptr + 14] << 16)
| (gus_patch[gus_ptr + 13] << 8) | gus_patch[gus_ptr + 12];
gus_sample->loop_end = (gus_patch[gus_ptr + 19] << 24)
| (gus_patch[gus_ptr + 18] << 16)
| (gus_patch[gus_ptr + 17] << 8) | gus_patch[gus_ptr + 16];
gus_sample->rate = (gus_patch[gus_ptr + 21] << 8)
| gus_patch[gus_ptr + 20];
gus_sample->freq_low = ((gus_patch[gus_ptr + 25] << 24)
| (gus_patch[gus_ptr + 24] << 16)
| (gus_patch[gus_ptr + 23] << 8) | gus_patch[gus_ptr + 22]);
gus_sample->freq_high = ((gus_patch[gus_ptr + 29] << 24)
| (gus_patch[gus_ptr + 28] << 16)
| (gus_patch[gus_ptr + 27] << 8) | gus_patch[gus_ptr + 26]);
gus_sample->freq_root = ((gus_patch[gus_ptr + 33] << 24)
| (gus_patch[gus_ptr + 32] << 16)
| (gus_patch[gus_ptr + 31] << 8) | gus_patch[gus_ptr + 30]);
/* This is done this way instead of ((freq * 1024) / rate) to avoid 32bit overflow. */
/* Result is 0.001% inacurate */
gus_sample->inc_div = ((gus_sample->freq_root * 512) / gus_sample->rate) * 2;
#if 0
/* We dont use this info at this time, kept in here for info */
printf("\rTremolo Sweep: %i, Rate: %i, Depth %i\n",
gus_patch[gus_ptr+49], gus_patch[gus_ptr+50], gus_patch[gus_ptr+51]);
printf("\rVibrato Sweep: %i, Rate: %i, Depth %i\n",
gus_patch[gus_ptr+52], gus_patch[gus_ptr+53], gus_patch[gus_ptr+54]);
#endif
gus_sample->modes = gus_patch[gus_ptr + 55];
GUSPAT_START_DEBUG(); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_16BIT, "16bit "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_UNSIGNED, "Unsigned "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_LOOP, "Loop "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_PINGPONG, "PingPong "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_REVERSE, "Reverse "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_SUSTAIN, "Sustain "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_ENVELOPE, "Envelope "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_CLAMPED, "Clamped "); GUSPAT_END_DEBUG();
if (gus_sample->loop_start > gus_sample->loop_end) {
tmp_loop = gus_sample->loop_end;
gus_sample->loop_end = gus_sample->loop_start;
gus_sample->loop_start = tmp_loop;
gus_sample->loop_fraction =
((gus_sample->loop_fraction & 0x0f) << 4)
| ((gus_sample->loop_fraction & 0xf0) >> 4);
}
/*
FIXME: Experimental Hacky Fix
*/
if (fix_release) {
if (env_time_table[gus_patch[gus_ptr + 40]]
< env_time_table[gus_patch[gus_ptr + 41]]) {
unsigned char tmp_hack_rate = gus_patch[gus_ptr + 41];
gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 40];
gus_patch[gus_ptr + 40] = tmp_hack_rate;
}
}
for (i = 0; i < 6; i++) {
if (gus_sample->modes & SAMPLE_ENVELOPE) {
unsigned char env_rate = gus_patch[gus_ptr + 37 + i];
gus_sample->env_target[i] = 16448 * gus_patch[gus_ptr + 43 + i];
GUSPAT_INT_DEBUG("Envelope Level",gus_patch[gus_ptr+43+i]); GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[env_rate]);
gus_sample->env_rate[i] = (signed long int) (4194303.0
/ ((float) _WM_SampleRate * env_time_table[env_rate]));
GUSPAT_INT_DEBUG("Envelope Rate",gus_sample->env_rate[i]); GUSPAT_INT_DEBUG("GUSPAT Rate",env_rate);
if (gus_sample->env_rate[i] == 0) {
_WM_ERROR_NEW("%s: Warning: found invalid envelope(%lu) rate setting in %s. Using %f instead.",
__FUNCTION__, i, filename, env_time_table[63]);
gus_sample->env_rate[i] = (signed long int) (4194303.0
/ ((float) _WM_SampleRate * env_time_table[63]));
GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[63]);
}
} else {
gus_sample->env_target[i] = 4194303;
gus_sample->env_rate[i] = (signed long int) (4194303.0
/ ((float) _WM_SampleRate * env_time_table[63]));
GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[63]);
}
}
gus_sample->env_target[6] = 0;
gus_sample->env_rate[6] = (signed long int) (4194303.0
/ ((float) _WM_SampleRate * env_time_table[63]));
gus_ptr += 96;
tmp_cnt = gus_sample->data_length;
if (do_convert[(((gus_sample->modes & 0x18) >> 1)
| (gus_sample->modes & 0x03))](&gus_patch[gus_ptr], gus_sample)
== -1) {
free(gus_patch);
return NULL;
}
gus_ptr += tmp_cnt;
gus_sample->loop_start = (gus_sample->loop_start << 10)
| (((gus_sample->loop_fraction & 0x0f) << 10) / 16);
gus_sample->loop_end = (gus_sample->loop_end << 10)
| (((gus_sample->loop_fraction & 0xf0) << 6) / 16);
gus_sample->loop_size = gus_sample->loop_end - gus_sample->loop_start;
gus_sample->data_length = gus_sample->data_length << 10;
no_of_samples--;
}
free(gus_patch);
return first_gus_sample;
}

77
src/wildmidi/gus_pat.h Normal file
View file

@ -0,0 +1,77 @@
/*
gus_pat.h
Midi Wavetable Processing library
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef __GUS_PAT_H
#define __GUS_PAT_H
/* Guspat Envelope Rate Timings */
static float env_time_table[] = {
/* Row 1 = (4095.0 / (x * ( 1.0 / (1.6 * 14.0) ))) / 1000000.0 */
0.0f, 0.091728000f, 0.045864000f, 0.030576000f, 0.022932000f, 0.018345600f, 0.015288000f, 0.013104000f,
0.011466000f, 0.010192000f, 0.009172800f, 0.008338909f, 0.007644000f, 0.007056000f, 0.006552000f, 0.006115200f,
0.005733000f, 0.005395765f, 0.005096000f, 0.004827789f, 0.004586400f, 0.004368000f, 0.004169455f, 0.003988174f,
0.003822000f, 0.003669120f, 0.003528000f, 0.003397333f, 0.003276000f, 0.003163034f, 0.003057600f, 0.002958968f,
0.002866500f, 0.002779636f, 0.002697882f, 0.002620800f, 0.002548000f, 0.002479135f, 0.002413895f, 0.002352000f,
0.002293200f, 0.002237268f, 0.002184000f, 0.002133209f, 0.002084727f, 0.002038400f, 0.001994087f, 0.001951660f,
0.001911000f, 0.001872000f, 0.001834560f, 0.001798588f, 0.001764000f, 0.001730717f, 0.001698667f, 0.001667782f,
0.001638000f, 0.001609263f, 0.001581517f, 0.001554712f, 0.001528800f, 0.001503738f, 0.001479484f, 0.001456000f,
/* Row 2 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 8.0 ))) / 1000000.0 */
0.0f, 0.733824000f, 0.366912000f, 0.244608000f, 0.183456000f, 0.146764800f, 0.122304000f, 0.104832000f,
0.091728000f, 0.081536000f, 0.073382400f, 0.066711273f, 0.061152000f, 0.056448000f, 0.052416000f, 0.048921600f,
0.045864000f, 0.043166118f, 0.040768000f, 0.038622316f, 0.036691200f, 0.034944000f, 0.033355636f, 0.031905391f,
0.030576000f, 0.029352960f, 0.028224000f, 0.027178667f, 0.026208000f, 0.025304276f, 0.024460800f, 0.023671742f,
0.022932000f, 0.022237091f, 0.021583059f, 0.020966400f, 0.020384000f, 0.019833081f, 0.019311158f, 0.018816000f,
0.018345600f, 0.017898146f, 0.017472000f, 0.017065674f, 0.016677818f, 0.016307200f, 0.015952696f, 0.015613277f,
0.015288000f, 0.014976000f, 0.014676480f, 0.014388706f, 0.014112000f, 0.013845736f, 0.013589333f, 0.013342255f,
0.013104000f, 0.012874105f, 0.012652138f, 0.012437695f, 0.012230400f, 0.012029902f, 0.011835871f, 0.011648000f,
/* Row 3 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 64.0 ))) / 1000000.0 */
0.0f, 5.870592000f, 2.935296000f, 1.956864000f, 1.467648000f, 1.174118400f, 0.978432000f, 0.838656000f,
0.733824000f, 0.652288000f, 0.587059200f, 0.533690182f, 0.489216000f, 0.451584000f, 0.419328000f, 0.391372800f,
0.366912000f, 0.345328941f, 0.326144000f, 0.308978526f, 0.293529600f, 0.279552000f, 0.266845091f, 0.255243130f,
0.244608000f, 0.234823680f, 0.225792000f, 0.217429333f, 0.209664000f, 0.202434207f, 0.195686400f, 0.189373935f,
0.183456000f, 0.177896727f, 0.172664471f, 0.167731200f, 0.163072000f, 0.158664649f, 0.154489263f, 0.150528000f,
0.146764800f, 0.143185171f, 0.139776000f, 0.136525395f, 0.133422545f, 0.130457600f, 0.127621565f, 0.124906213f,
0.122304000f, 0.119808000f, 0.117411840f, 0.115109647f, 0.112896000f, 0.110765887f, 0.108714667f, 0.106738036f,
0.104832000f, 0.102992842f, 0.101217103f, 0.099501559f, 0.097843200f, 0.096239213f, 0.094686968f, 0.093184000f,
/* Row 4 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 512.0))) / 1000000.0 */
0.0f, 46.964736000f,23.482368000f,15.654912000f,11.741184000f, 9.392947200f, 7.827456000f, 6.709248000f,
5.870592000f, 5.218304000f, 4.696473600f, 4.269521455f, 3.913728000f, 3.612672000f, 3.354624000f, 3.130982400f,
2.935296000f, 2.762631529f, 2.609152000f, 2.471828211f, 2.348236800f, 2.236416000f, 2.134760727f, 2.041945043f,
1.956864000f, 1.878589440f, 1.806336000f, 1.739434667f, 1.677312000f, 1.619473655f, 1.565491200f, 1.514991484f,
1.467648000f, 1.423173818f, 1.381315765f, 1.341849600f, 1.304576000f, 1.269317189f, 1.235914105f, 1.204224000f,
1.174118400f, 1.145481366f, 1.118208000f, 1.092203163f, 1.067380364f, 1.043660800f, 1.020972522f, 0.999249702f,
0.978432000f, 0.958464000f, 0.939294720f, 0.920877176f, 0.903168000f, 0.886127094f, 0.869717333f, 0.853904291f,
0.838656000f, 0.823942737f, 0.809736828f, 0.796012475f, 0.782745600f, 0.769913705f, 0.757495742f, 0.745472000f
};
extern struct _sample * _WM_load_gus_pat (const char *filename, int _fix_release);
#endif /* __GUS_PAT_H */

87
src/wildmidi/lock.cpp Normal file
View file

@ -0,0 +1,87 @@
/*
lock.c - data locking code for lib
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
//#include "config.h"
#ifndef __DJGPP__
#ifdef _WIN32
#include <windows.h>
#else
#define _GNU_SOURCE
#include <unistd.h>
#endif
#include "lock.h"
#include "common.h"
/*
_WM_Lock(wmlock)
wmlock = a pointer to a value
returns nothing
Attempts to set a lock on the MDI tree so that
only 1 library command may access it at any time.
If lock fails the process retries until successful.
*/
void _WM_Lock(int * wmlock) {
LOCK_START:
/* Check if lock is clear, if so set it */
if (*wmlock == 0) {
(*wmlock)++;
/* Now that the lock is set, make sure we
* don't have a race condition. If so,
* decrement the lock by one and retry. */
if (*wmlock == 1) {
return; /* Lock cleanly set */
}
(*wmlock)--;
}
#ifdef _WIN32
Sleep(10);
#else
usleep(500);
#endif
goto LOCK_START;
}
/*
_WM_Unlock(wmlock)
wmlock = a pointer to a value
returns nothing
Removes a lock previously placed on the MDI tree.
*/
void _WM_Unlock(int *wmlock) {
/* We don't want a -1 lock, so just to make sure */
if ((*wmlock) != 0) {
(*wmlock)--;
}
}
#endif /* __DJGPP__ */

36
src/wildmidi/lock.h Normal file
View file

@ -0,0 +1,36 @@
/*
lock.h - data locking code for lib
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef __LOCK_H
#define __LOCK_H
extern void _WM_Lock (int * wmlock);
extern void _WM_Unlock (int *wmlock);
#ifdef __DJGPP__
#define _WM_Lock(p) do {} while (0)
#define _WM_Unlock(p) do {} while (0)
#endif
#endif /* __LOCK_H */

398
src/wildmidi/reverb.cpp Normal file
View file

@ -0,0 +1,398 @@
/*
reverb.c
Midi Wavetable Processing library
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
//#include "config.h"
#include <math.h>
#include <stdlib.h>
#include "common.h"
#include "reverb.h"
/*
reverb function
*/
void _WM_reset_reverb(struct _rvb *rvb) {
int i, j, k;
for (i = 0; i < rvb->l_buf_size; i++) {
rvb->l_buf[i] = 0;
}
for (i = 0; i < rvb->r_buf_size; i++) {
rvb->r_buf[i] = 0;
}
for (k = 0; k < 8; k++) {
for (i = 0; i < 6; i++) {
for (j = 0; j < 2; j++) {
rvb->l_buf_flt_in[k][i][j] = 0;
rvb->l_buf_flt_out[k][i][j] = 0;
rvb->r_buf_flt_in[k][i][j] = 0;
rvb->r_buf_flt_out[k][i][j] = 0;
}
}
}
}
/*
_WM_init_reverb
=========================
Engine Description
8 reflective points around the room
2 speaker positions
1 listener position
Sounds come from the speakers to all points and to the listener.
Sound comes from the reflective points to the listener.
These sounds are combined, put through a filter that mimics surface absorbtion.
The combined sounds are also sent to the reflective points on the opposite side.
*/
struct _rvb *
_WM_init_reverb(int rate, float room_x, float room_y, float listen_x,
float listen_y) {
/* filters set at 125Hz, 250Hz, 500Hz, 1000Hz, 2000Hz, 4000Hz */
double Freq[] = {125.0, 250.0, 500.0, 1000.0, 2000.0, 4000.0};
/* numbers calculated from
* 101.325 kPa, 20 deg C, 50% relative humidity */
double dbAirAbs[] = {-0.00044, -0.00131, -0.002728, -0.004665, -0.009887, -0.029665};
/* modify these to adjust the absorption qualities of the surface.
* Remember that lower frequencies are less effected by surfaces
* Note: I am currently playing with the values and finding the ideal surfaces
* for nice default reverb.
*/
double dbAttn[8][6] = {
{-1.839, -6.205, -8.891, -12.059, -15.935, -20.942},
{-0.131, -6.205, -12.059, -20.933, -20.933, -15.944},
{-0.131, -6.205, -12.059, -20.933, -20.933, -15.944},
{-1.839, -6.205, -8.891, -12.059, -15.935, -20.942},
{-1.839, -6.205, -8.891, -12.059, -15.935, -20.942},
{-0.131, -6.205, -12.059, -20.933, -20.933, -15.944},
{-0.131, -6.205, -12.059, -20.933, -20.933, -15.944},
{-1.839, -6.205, -8.891, -12.059, -15.935, -20.942}
};
/*
double dbAttn[6] = {
// concrete covered in carpet
// -0.175, -0.537, -1.412, -4.437, -7.959, -7.959
// pleated drapes
-0.630, -3.223, -5.849, -12.041, -10.458, -7.959
};
*/
/* distance */
double SPL_DST[8] = {0.0};
double SPR_DST[8] = {0.0};
double RFN_DST[8] = {0.0};
double MAXL_DST = 0.0;
double MAXR_DST = 0.0;
double SPL_LSN_XOFS = 0.0;
double SPL_LSN_YOFS = 0.0;
double SPL_LSN_DST = 0.0;
double SPR_LSN_XOFS = 0.0;
double SPR_LSN_YOFS = 0.0;
double SPR_LSN_DST = 0.0;
struct _rvb *rtn_rvb = (struct _rvb*)malloc(sizeof(struct _rvb));
int j = 0;
int i = 0;
struct _coord {
double x;
double y;
};
#if 0
struct _coord SPL = {2.5, 5.0}; /* Left Speaker Position */
struct _coord SPR = {7.5, 5.0}; /* Right Speaker Position */
/* position of the reflective points */
struct _coord RFN[] = {
{ 5.0, 0.0},
{ 0.0, 6.66666},
{ 0.0, 13.3333},
{ 5.0, 20.0},
{ 10.0, 20.0},
{ 15.0, 13.3333},
{ 15.0, 6.66666},
{ 10.0, 0.0}
};
#else
struct _coord SPL; /* Left Speaker Position */
struct _coord SPR; /* Right Speaker Position */
/* position of the reflective points */
struct _coord RFN[8];
SPL.x = room_x / 4.0;
SPR.x = room_x / 4.0 * 3.0;
SPL.y = room_y / 10.0;
SPR.y = room_y / 10.0;
RFN[0].x = room_x / 3.0;
RFN[0].y = 0.0;
RFN[1].x = 0.0;
RFN[1].y = room_y / 3.0;
RFN[2].x = 0.0;
RFN[2].y = room_y / 3.0 * 2.0;
RFN[3].x = room_x / 3.0;
RFN[3].y = room_y;
RFN[4].x = room_x / 3.0 * 2.0;
RFN[4].y = room_y;
RFN[5].x = room_x;
RFN[5].y = room_y / 3.0 * 2.0;
RFN[6].x = room_x;
RFN[6].y = room_y / 3.0;
RFN[7].x = room_x / 3.0 * 2.0;
RFN[7].y = 0.0;
#endif
SPL_LSN_XOFS = SPL.x - listen_x;
SPL_LSN_YOFS = SPL.y - listen_y;
SPL_LSN_DST = sqrt((SPL_LSN_XOFS * SPL_LSN_XOFS) + (SPL_LSN_YOFS * SPL_LSN_YOFS));
if (SPL_LSN_DST > MAXL_DST)
MAXL_DST = SPL_LSN_DST;
SPR_LSN_XOFS = SPR.x - listen_x;
SPR_LSN_YOFS = SPR.y - listen_y;
SPR_LSN_DST = sqrt((SPR_LSN_XOFS * SPR_LSN_XOFS) + (SPR_LSN_YOFS * SPR_LSN_YOFS));
if (SPR_LSN_DST > MAXR_DST)
MAXR_DST = SPR_LSN_DST;
if (rtn_rvb == NULL) {
return NULL;
}
for (j = 0; j < 8; j++) {
double SPL_RFL_XOFS = 0;
double SPL_RFL_YOFS = 0;
double SPR_RFL_XOFS = 0;
double SPR_RFL_YOFS = 0;
double RFN_XOFS = listen_x - RFN[j].x;
double RFN_YOFS = listen_y - RFN[j].y;
RFN_DST[j] = sqrt((RFN_XOFS * RFN_XOFS) + (RFN_YOFS * RFN_YOFS));
SPL_RFL_XOFS = SPL.x - RFN[i].x;
SPL_RFL_YOFS = SPL.y - RFN[i].y;
SPR_RFL_XOFS = SPR.x - RFN[i].x;
SPR_RFL_YOFS = SPR.y - RFN[i].y;
SPL_DST[i] = sqrt(
(SPL_RFL_XOFS * SPL_RFL_XOFS) + (SPL_RFL_YOFS * SPL_RFL_YOFS));
SPR_DST[i] = sqrt(
(SPR_RFL_XOFS * SPR_RFL_XOFS) + (SPR_RFL_YOFS * SPR_RFL_YOFS));
/*
add the 2 distances together and remove the speaker to listener distance
so we dont have to delay the initial output
*/
SPL_DST[i] += RFN_DST[i];
/* so i dont have to delay speaker output */
SPL_DST[i] -= SPL_LSN_DST;
if (i < 4) {
if (SPL_DST[i] > MAXL_DST)
MAXL_DST = SPL_DST[i];
} else {
if (SPL_DST[i] > MAXR_DST)
MAXR_DST = SPL_DST[i];
}
SPR_DST[i] += RFN_DST[i];
/* so i dont have to delay speaker output */
SPR_DST[i] -= SPR_LSN_DST;
if (i < 4) {
if (SPR_DST[i] > MAXL_DST)
MAXL_DST = SPR_DST[i];
} else {
if (SPR_DST[i] > MAXR_DST)
MAXR_DST = SPR_DST[i];
}
RFN_DST[j] *= 2.0;
if (j < 4) {
if (RFN_DST[j] > MAXL_DST)
MAXL_DST = RFN_DST[j];
} else {
if (RFN_DST[j] > MAXR_DST)
MAXR_DST = RFN_DST[j];
}
for (i = 0; i < 6; i++) {
double srate = (double) rate;
double bandwidth = 2.0;
double omega = 2.0 * M_PI * Freq[i] / srate;
double sn = sin(omega);
double cs = cos(omega);
double alpha = sn * sinh(M_LN2 / 2 * bandwidth * omega / sn);
double A = pow(10.0, ((/*dbAttn[i]*/dbAttn[j][i] +
(dbAirAbs[i] * RFN_DST[j])) / 40.0) );
/*
Peaking band EQ filter
*/
double b0 = 1 + (alpha * A);
double b1 = -2 * cs;
double b2 = 1 - (alpha * A);
double a0 = 1 + (alpha / A);
double a1 = -2 * cs;
double a2 = 1 - (alpha / A);
rtn_rvb->coeff[j][i][0] = (signed long int) ((b0 / a0) * 1024.0);
rtn_rvb->coeff[j][i][1] = (signed long int) ((b1 / a0) * 1024.0);
rtn_rvb->coeff[j][i][2] = (signed long int) ((b2 / a0) * 1024.0);
rtn_rvb->coeff[j][i][3] = (signed long int) ((a1 / a0) * 1024.0);
rtn_rvb->coeff[j][i][4] = (signed long int) ((a2 / a0) * 1024.0);
}
}
/* init the reverb buffers */
rtn_rvb->l_buf_size = (int) ((float) rate * (MAXL_DST / 340.29));
rtn_rvb->l_buf = (long*)malloc(
sizeof(signed long int) * (rtn_rvb->l_buf_size + 1));
rtn_rvb->l_out = 0;
rtn_rvb->r_buf_size = (int) ((float) rate * (MAXR_DST / 340.29));
rtn_rvb->r_buf = (long*)malloc(
sizeof(signed long int) * (rtn_rvb->r_buf_size + 1));
rtn_rvb->r_out = 0;
for (i = 0; i < 4; i++) {
rtn_rvb->l_sp_in[i] = (int) ((float) rate * (SPL_DST[i] / 340.29));
rtn_rvb->l_sp_in[i + 4] = (int) ((float) rate
* (SPL_DST[i + 4] / 340.29));
rtn_rvb->r_sp_in[i] = (int) ((float) rate * (SPR_DST[i] / 340.29));
rtn_rvb->r_sp_in[i + 4] = (int) ((float) rate
* (SPR_DST[i + 4] / 340.29));
rtn_rvb->l_in[i] = (int) ((float) rate * (RFN_DST[i] / 340.29));
rtn_rvb->r_in[i] = (int) ((float) rate * (RFN_DST[i + 4] / 340.29));
}
rtn_rvb->gain = 4;
_WM_reset_reverb(rtn_rvb);
return rtn_rvb;
}
/* _WM_free_reverb - free up memory used for reverb */
void _WM_free_reverb(struct _rvb *rvb) {
if (!rvb) return;
free(rvb->l_buf);
free(rvb->r_buf);
free(rvb);
}
void _WM_do_reverb(struct _rvb *rvb, signed long int *buffer, int size) {
int i, j, k;
signed long int l_buf_flt = 0;
signed long int r_buf_flt = 0;
signed long int l_rfl = 0;
signed long int r_rfl = 0;
int vol_div = 64;
for (i = 0; i < size; i += 2) {
signed long int tmp_l_val = 0;
signed long int tmp_r_val = 0;
/*
add the initial reflections
from each speaker, 4 to go the left, 4 go to the right buffers
*/
tmp_l_val = buffer[i] / vol_div;
tmp_r_val = buffer[i + 1] / vol_div;
for (j = 0; j < 4; j++) {
rvb->l_buf[rvb->l_sp_in[j]] += tmp_l_val;
rvb->l_sp_in[j] = (rvb->l_sp_in[j] + 1) % rvb->l_buf_size;
rvb->l_buf[rvb->r_sp_in[j]] += tmp_r_val;
rvb->r_sp_in[j] = (rvb->r_sp_in[j] + 1) % rvb->l_buf_size;
rvb->r_buf[rvb->l_sp_in[j + 4]] += tmp_l_val;
rvb->l_sp_in[j + 4] = (rvb->l_sp_in[j + 4] + 1) % rvb->r_buf_size;
rvb->r_buf[rvb->r_sp_in[j + 4]] += tmp_r_val;
rvb->r_sp_in[j + 4] = (rvb->r_sp_in[j + 4] + 1) % rvb->r_buf_size;
}
/*
filter the reverb output and add to buffer
*/
l_rfl = rvb->l_buf[rvb->l_out];
rvb->l_buf[rvb->l_out] = 0;
rvb->l_out = (rvb->l_out + 1) % rvb->l_buf_size;
r_rfl = rvb->r_buf[rvb->r_out];
rvb->r_buf[rvb->r_out] = 0;
rvb->r_out = (rvb->r_out + 1) % rvb->r_buf_size;
for (k = 0; k < 8; k++) {
for (j = 0; j < 6; j++) {
l_buf_flt = ((l_rfl * rvb->coeff[k][j][0])
+ (rvb->l_buf_flt_in[k][j][0] * rvb->coeff[k][j][1])
+ (rvb->l_buf_flt_in[k][j][1] * rvb->coeff[k][j][2])
- (rvb->l_buf_flt_out[k][j][0] * rvb->coeff[k][j][3])
- (rvb->l_buf_flt_out[k][j][1] * rvb->coeff[k][j][4]))
/ 1024;
rvb->l_buf_flt_in[k][j][1] = rvb->l_buf_flt_in[k][j][0];
rvb->l_buf_flt_in[k][j][0] = l_rfl;
rvb->l_buf_flt_out[k][j][1] = rvb->l_buf_flt_out[k][j][0];
rvb->l_buf_flt_out[k][j][0] = l_buf_flt;
buffer[i] += l_buf_flt / 8;
r_buf_flt = ((r_rfl * rvb->coeff[k][j][0])
+ (rvb->r_buf_flt_in[k][j][0] * rvb->coeff[k][j][1])
+ (rvb->r_buf_flt_in[k][j][1] * rvb->coeff[k][j][2])
- (rvb->r_buf_flt_out[k][j][0] * rvb->coeff[k][j][3])
- (rvb->r_buf_flt_out[k][j][1] * rvb->coeff[k][j][4]))
/ 1024;
rvb->r_buf_flt_in[k][j][1] = rvb->r_buf_flt_in[k][j][0];
rvb->r_buf_flt_in[k][j][0] = r_rfl;
rvb->r_buf_flt_out[k][j][1] = rvb->r_buf_flt_out[k][j][0];
rvb->r_buf_flt_out[k][j][0] = r_buf_flt;
buffer[i + 1] += r_buf_flt / 8;
}
}
/*
add filtered result back into the buffers but on the opposite side
*/
tmp_l_val = buffer[i + 1] / vol_div;
tmp_r_val = buffer[i] / vol_div;
for (j = 0; j < 4; j++) {
rvb->l_buf[rvb->l_in[j]] += tmp_l_val;
rvb->l_in[j] = (rvb->l_in[j] + 1) % rvb->l_buf_size;
rvb->r_buf[rvb->r_in[j]] += tmp_r_val;
rvb->r_in[j] = (rvb->r_in[j] + 1) % rvb->r_buf_size;
}
}
}

57
src/wildmidi/reverb.h Normal file
View file

@ -0,0 +1,57 @@
/*
reverb.h
Midi Wavetable Processing library
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef __REVERB_H
#define __REVERB_H
struct _rvb {
/* filter data */
signed long int l_buf_flt_in[8][6][2];
signed long int l_buf_flt_out[8][6][2];
signed long int r_buf_flt_in[8][6][2];
signed long int r_buf_flt_out[8][6][2];
signed long int coeff[8][6][5];
/* buffer data */
signed long int *l_buf;
signed long int *r_buf;
int l_buf_size;
int r_buf_size;
int l_out;
int r_out;
int l_sp_in[8];
int r_sp_in[8];
int l_in[4];
int r_in[4];
int gain;
unsigned long int max_reverb_time;
};
extern void _WM_reset_reverb (struct _rvb *rvb);
extern struct _rvb *_WM_init_reverb(int rate, float room_x, float room_y, float listen_x, float listen_y);
extern void _WM_free_reverb (struct _rvb *rvb);
extern void _WM_do_reverb (struct _rvb *rvb, signed long int *buffer, int size);
#endif /* __REVERB_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,75 @@
/*
wildmidi_lib.h
Midi Wavetable Processing library
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef WILDMIDI_LIB_H
#define WILDMIDI_LIB_H
#define WM_MO_LOG_VOLUME 0x0001
#define WM_MO_ENHANCED_RESAMPLING 0x0002
#define WM_MO_REVERB 0x0004
#define WM_MO_WHOLETEMPO 0x8000
#define WM_MO_ROUNDTEMPO 0x2000
#define WM_GS_VERSION 0x0001
#define WM_SYMBOL // we do not need this in ZDoom
/*
#if defined(__cplusplus)
extern "C" {
#endif
*/
struct _WM_Info {
char *copyright;
unsigned long int current_sample;
unsigned long int approx_total_samples;
unsigned short int mixer_options;
unsigned long int total_midi_time;
};
typedef void midi;
WM_SYMBOL const char * WildMidi_GetString (unsigned short int info);
WM_SYMBOL int WildMidi_Init (const char * config_file, unsigned short int rate, unsigned short int options);
WM_SYMBOL int WildMidi_MasterVolume (unsigned char master_volume);
WM_SYMBOL midi * WildMidi_Open (const char *midifile);
WM_SYMBOL midi * WildMidi_OpenBuffer (unsigned char *midibuffer, unsigned long int size);
WM_SYMBOL int WildMidi_GetOutput (midi * handle, char * buffer, unsigned long int size);
WM_SYMBOL int WildMidi_SetOption (midi * handle, unsigned short int options, unsigned short int setting);
WM_SYMBOL struct _WM_Info * WildMidi_GetInfo (midi * handle);
WM_SYMBOL int WildMidi_FastSeek (midi * handle, unsigned long int *sample_pos);
WM_SYMBOL int WildMidi_Close (midi * handle);
WM_SYMBOL int WildMidi_Shutdown (void);
/*
#if defined(__cplusplus)
}
#endif
*/
#endif /* WILDMIDI_LIB_H */

86
src/wildmidi/wm_error.cpp Normal file
View file

@ -0,0 +1,86 @@
/*
wm_error.c
error reporting
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
//#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "wm_error.h"
#include "doomtype.h"
#include "v_text.h"
void _WM_ERROR_NEW(const char * wmfmt, ...) {
va_list args;
fprintf(stderr, "\r");
va_start(args, wmfmt);
vfprintf(stderr, wmfmt, args);
va_end(args);
fprintf(stderr, "\n");
}
void _WM_ERROR(const char * func, unsigned int lne, int wmerno,
const char * wmfor, int error) {
static const char *errors[WM_ERR_MAX+1] = {
"No error",
"Unable to obtain memory",
"Unable to stat",
"Unable to load",
"Unable to open",
"Unable to read",
"Invalid or Unsuported file format",
"File corrupt",
"Library not Initialized",
"Invalid argument",
"Library Already Initialized",
"Not a midi file",
"Refusing to load unusually long file",
"Invalid error code"
};
if (wmerno < 0 || wmerno > WM_ERR_MAX)
wmerno = WM_ERR_MAX;
if (wmfor != NULL) {
if (error != 0) {
Printf(TEXTCOLOR_RED "\rlibWildMidi(%s:%u): ERROR %s %s (%s)\n", func,
lne, errors[wmerno], wmfor, strerror(error));
} else {
Printf(TEXTCOLOR_RED "\rlibWildMidi(%s:%u): ERROR %s %s\n", func, lne,
errors[wmerno], wmfor);
}
} else {
if (error != 0) {
Printf(TEXTCOLOR_RED "\rlibWildMidi(%s:%u): ERROR %s (%s)\n", func, lne,
errors[wmerno], strerror(error));
} else {
Printf(TEXTCOLOR_RED "\rlibWildMidi(%s:%u): ERROR %s\n", func, lne,
errors[wmerno]);
}
}
}

56
src/wildmidi/wm_error.h Normal file
View file

@ -0,0 +1,56 @@
/*
wm_error.h
error reporting
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef __WM_ERROR_H
#define __WM_ERROR_H
enum {
WM_ERR_NONE = 0,
WM_ERR_MEM,
WM_ERR_STAT,
WM_ERR_LOAD,
WM_ERR_OPEN,
WM_ERR_READ,
WM_ERR_INVALID,
WM_ERR_CORUPT,
WM_ERR_NOT_INIT,
WM_ERR_INVALID_ARG,
WM_ERR_ALR_INIT,
WM_ERR_NOT_MIDI,
WM_ERR_LONGFIL,
WM_ERR_MAX
};
extern void _WM_ERROR_NEW(const char * wmfmt, ...)
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
;
extern void _WM_ERROR(const char * func, unsigned int lne, int wmerno,
const char * wmfor, int error);
#endif /* __WM_ERROR_H */

View file

@ -106,6 +106,7 @@
MapExports="true"
SubSystem="2"
StackReserveSize="0"
LargeAddressAware="2"
TerminalServerAware="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
@ -223,6 +224,7 @@
MapExports="true"
SubSystem="2"
StackReserveSize="0"
LargeAddressAware="2"
TerminalServerAware="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
@ -332,6 +334,7 @@
ProgramDatabaseFile=".\Debug/zdoomd.pdb"
SubSystem="2"
StackReserveSize="0"
LargeAddressAware="2"
TerminalServerAware="2"
SetChecksum="false"
TargetMachine="0"
@ -440,6 +443,7 @@
ProgramDatabaseFile=".\Debug/zdoomd.pdb"
SubSystem="2"
StackReserveSize="0"
LargeAddressAware="2"
TerminalServerAware="2"
SetChecksum="false"
TargetMachine="17"