diff --git a/polymer/eduke32/Makefile b/polymer/eduke32/Makefile
index d3f32ae5a..148f3fe44 100644
--- a/polymer/eduke32/Makefile
+++ b/polymer/eduke32/Makefile
@@ -10,8 +10,6 @@ PRETTY_OUTPUT = 1
# SDK locations - adjust to match your setup
DXROOT=../sdk/dx
-ALROOT = AL
-
# Engine options
SUPERBUILD = 1
POLYMOST = 1
@@ -124,7 +122,6 @@ GAMEOBJS=$(OBJ)/game.$o \
$(OBJ)/osdcmds.$o \
$(OBJ)/grpscan.$o \
$(OBJ)/sounds.$o \
- $(OBJ)/audiolib_musicstub.$o \
$(JMACTOBJ)
EDITOROBJS=$(OBJ)/astub.$o \
@@ -139,20 +136,19 @@ ifeq ($(PLATFORM),LINUX)
endif
ifeq ($(PLATFORM),DARWIN)
- ALROOT = Apple
ifeq (1,$(SDL_FRAMEWORK))
- OURCFLAGS += -fno-pic -I$(ALROOT)/include -I/Library/Frameworks/SDL.framework/Headers \
+ OURCFLAGS += -fno-pic -IApple/include -I/Library/Frameworks/SDL.framework/Headers \
-I-I/Library/Frameworks/SDL_mixer.framework/Headers
- LIBS += -read_only_relocs suppress -L$(ALROOT)/lib -lvorbisfile -lvorbis -logg -lm \
- -Wl,-framework,SDL -Wl,-framework,SDL_mixer $(ALROOT)/lib/libSDLmain.a \
+ LIBS += -read_only_relocs suppress -LApple/lib -lvorbisfile -lvorbis -logg -lm \
+ -Wl,-framework,SDL -Wl,-framework,SDL_mixer Apple/lib/libSDLmain.a \
-Wl,-framework,Cocoa -Wl,-framework,Carbon -Wl,-framework,OpenGL \
-Wl,-framework,CoreMidi -Wl,-framework,AudioUnit \
-Wl,-framework,AudioToolbox -Wl,-framework,IOKit -Wl,-framework,AGL \
-Wl,-framework,QuickTime -lm
else
- OURCFLAGS += -fno-pic -I$(ALROOT)/include -I$(SDLROOT)/include -I$(SDLROOT)/include/SDL
- LIBS += -read_only_relocs suppress -L$(ALROOT)/lib -lvorbisfile -lvorbis -logg -lm -lSDL_mixer \
+ OURCFLAGS += -fno-pic -I$(SDLROOT)/include -I$(SDLROOT)/include/SDL
+ LIBS += -read_only_relocs suppress -lvorbisfile -lvorbis -logg -lm -lSDL_mixer \
-Wl,-framework,Cocoa -Wl,-framework,Carbon -Wl,-framework,OpenGL \
-Wl,-framework,CoreMidi -Wl,-framework,AudioUnit \
-Wl,-framework,AudioToolbox -Wl,-framework,IOKit -Wl,-framework,AGL \
@@ -162,12 +158,14 @@ ifeq ($(PLATFORM),DARWIN)
endif
ifeq ($(PLATFORM),WINDOWS)
- OURCFLAGS += -fno-pic -DUNDERSCORES -I$(DXROOT)/include -I$(ALROOT)/include # -I$(ENETROOT)/include
+ OURCFLAGS += -fno-pic -DUNDERSCORES -I$(DXROOT)/include
NASMFLAGS+= -DUNDERSCORES -f win32
LIBS += -L$(JAUDIOLIBDIR)/third-party/mingw32/lib -lvorbisfile -lvorbis -logg -lwsock32 -lws2_32 -lwinmm -ldsound
- GAMEOBJS+= $(OBJ)/gameres.$o $(OBJ)/winbits.$o $(OBJ)/startwin.game.$o
+ GAMEOBJS+= $(OBJ)/gameres.$o $(OBJ)/winbits.$o $(OBJ)/startwin.game.$o $(OBJ)/music.$o $(OBJ)/midi.$o $(OBJ)/mpu401.$o
EDITOROBJS+= $(OBJ)/buildres.$o
JAUDIOLIB=libjfaudiolib_win32.a
+else
+ GAMEOBJS+= $(OBJ)/audiolib_musicstub.$o
endif
ifeq ($(RENDERTYPE),SDL)
diff --git a/polymer/eduke32/Makefile.deps b/polymer/eduke32/Makefile.deps
index 9bbd8554b..0a6a97105 100644
--- a/polymer/eduke32/Makefile.deps
+++ b/polymer/eduke32/Makefile.deps
@@ -61,7 +61,7 @@ $(OBJ)/dsoundout.$o: $(SRC)/jaudiolib/dsoundout.c $(SRC)/jaudiolib/dsoundout.h
$(OBJ)/openal.$o: $(SRC)/jaudiolib/openal.c $(SRC)/jaudiolib/openal.h
$(OBJ)/dsl.$o: $(SRC)/jaudiolib/dsl.c $(SRC)/jaudiolib/dsl.h $(EINC)/compat.h
-$(OBJ)/midi.$o: $(SRC)/jaudiolib/midi.c $(SRC)/jaudiolib/standard.h $(SRC)/jaudiolib/music.h $(SRC)/jaudiolib/_midi.h $(SRC)/jaudiolib/midi.h
-$(OBJ)/mpu401.$o: $(SRC)/jaudiolib/mpu401.c $(SRC)/jaudiolib/mpu401.h
-$(OBJ)/music.$o: $(SRC)/jaudiolib/music.c $(SRC)/jaudiolib/music.h $(SRC)/jaudiolib/midi.h $(SRC)/jaudiolib/mpu401.h
+$(OBJ)/midi.$o: $(SRC)/midi.c $(SRC)/_midi.h $(SRC)/midi.h $(JAUDIOLIBDIR)/include/music.h
+$(OBJ)/mpu401.$o: $(SRC)/mpu401.c $(SRC)/mpu401.h $(JAUDIOLIBDIR)/include/music.h
+$(OBJ)/music.$o: $(SRC)/music.c $(SRC)/midi.h $(SRC)/mpu401.h $(JAUDIOLIBDIR)/include/music.h
diff --git a/polymer/eduke32/eduke32.vcproj b/polymer/eduke32/eduke32.vcproj
index 28727292f..52a4bba5d 100644
--- a/polymer/eduke32/eduke32.vcproj
+++ b/polymer/eduke32/eduke32.vcproj
@@ -412,6 +412,18 @@
RelativePath=".\source\menus.c"
>
+
+
+
+
+
+
diff --git a/polymer/eduke32/source/_midi.h b/polymer/eduke32/source/_midi.h
new file mode 100644
index 000000000..f2c41ab04
--- /dev/null
+++ b/polymer/eduke32/source/_midi.h
@@ -0,0 +1,282 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+Modifications for JonoF's port by Jonathon Fowler (jonof@edgenetwk.com)
+
+*/
+/**********************************************************************
+ module: _MIDI.H
+
+ author: James R. Dose
+ date: May 25, 1994
+
+ Private header for MIDI.C. Midi song file playback routines.
+
+ (c) Copyright 1994 James R. Dose. All Rights Reserved.
+**********************************************************************/
+
+#ifndef ___MIDI_H
+#define ___MIDI_H
+#include "compat.h"
+
+#define RELATIVE_BEAT( measure, beat, tick ) \
+ ( ( tick ) + ( ( beat ) << 9 ) + ( ( measure ) << 16 ) )
+
+//Bobby Prince thinks this may be 100
+//#define GENMIDI_DefaultVolume 100
+#define GENMIDI_DefaultVolume 90
+
+#define MAX_FORMAT 1
+
+#define NUM_MIDI_CHANNELS 16
+
+#define TIME_PRECISION 16
+
+#define MIDI_HEADER_SIGNATURE 0x6468544d // "MThd"
+#define MIDI_TRACK_SIGNATURE 0x6b72544d // "MTrk"
+
+#define MIDI_VOLUME 7
+#define MIDI_PAN 10
+#define MIDI_DETUNE 94
+#define MIDI_RHYTHM_CHANNEL 9
+#define MIDI_RPN_MSB 100
+#define MIDI_RPN_LSB 101
+#define MIDI_DATAENTRY_MSB 6
+#define MIDI_DATAENTRY_LSB 38
+#define MIDI_PITCHBEND_MSB 0
+#define MIDI_PITCHBEND_LSB 0
+#define MIDI_RUNNING_STATUS 0x80
+#define MIDI_NOTE_OFF 0x8
+#define MIDI_NOTE_ON 0x9
+#define MIDI_POLY_AFTER_TCH 0xA
+#define MIDI_CONTROL_CHANGE 0xB
+#define MIDI_PROGRAM_CHANGE 0xC
+#define MIDI_AFTER_TOUCH 0xD
+#define MIDI_PITCH_BEND 0xE
+#define MIDI_SPECIAL 0xF
+#define MIDI_SYSEX 0xF0
+#define MIDI_SYSEX_CONTINUE 0xF7
+#define MIDI_META_EVENT 0xFF
+#define MIDI_END_OF_TRACK 0x2F
+#define MIDI_TEMPO_CHANGE 0x51
+#define MIDI_TIME_SIGNATURE 0x58
+#define MIDI_RESET_ALL_CONTROLLERS 0x79
+#define MIDI_ALL_NOTES_OFF 0x7b
+#define MIDI_MONO_MODE_ON 0x7E
+#define MIDI_SYSTEM_RESET 0xFF
+
+#define GET_NEXT_EVENT( track, data ) \
+ ( data ) = *( track )->pos; \
+ ( track )->pos += 1
+
+#define GET_MIDI_CHANNEL( event ) ( ( event ) & 0xf )
+#define GET_MIDI_COMMAND( event ) ( ( event ) >> 4 )
+
+#define EMIDI_INFINITE -1
+#define EMIDI_END_LOOP_VALUE 127
+#define EMIDI_ALL_CARDS 127
+#define EMIDI_INCLUDE_TRACK 110
+#define EMIDI_EXCLUDE_TRACK 111
+#define EMIDI_PROGRAM_CHANGE 112
+#define EMIDI_VOLUME_CHANGE 113
+#define EMIDI_CONTEXT_START 114
+#define EMIDI_CONTEXT_END 115
+#define EMIDI_LOOP_START 116
+#define EMIDI_LOOP_END 117
+#define EMIDI_SONG_LOOP_START 118
+#define EMIDI_SONG_LOOP_END 119
+
+#define EMIDI_GeneralMIDI 0
+
+#define EMIDI_AffectsCurrentCard( c, type ) \
+ ( ( ( c ) == EMIDI_ALL_CARDS ) || ( ( c ) == ( type ) ) )
+
+
+#define EMIDI_NUM_CONTEXTS 7
+typedef struct
+ {
+ char *pos;
+ char *loopstart;
+ int16_t loopcount;
+ int16_t RunningStatus;
+ unsigned time;
+ int32_t FPSecondsPerTick;
+ int16_t tick;
+ int16_t beat;
+ int16_t measure;
+ int16_t BeatsPerMeasure;
+ int16_t TicksPerBeat;
+ int16_t TimeBase;
+ int32_t delay;
+ int16_t active;
+ } songcontext;
+
+typedef struct
+ {
+ char *start;
+ char *pos;
+
+ int32_t delay;
+ int16_t active;
+ int16_t RunningStatus;
+
+ int16_t currentcontext;
+ songcontext context[ EMIDI_NUM_CONTEXTS ];
+
+ char EMIDI_IncludeTrack;
+ char EMIDI_ProgramChange;
+ char EMIDI_VolumeChange;
+ } track;
+
+static int32_t _MIDI_ReadNumber( void *from, size_t size );
+static int32_t _MIDI_ReadDelta( track *ptr );
+static void _MIDI_ResetTracks( void );
+static void _MIDI_AdvanceTick( void );
+static void _MIDI_MetaEvent( track *Track );
+static void _MIDI_SysEx( track *Track );
+static int32_t _MIDI_InterpretControllerInfo( track *Track, int32_t TimeSet,
+ int32_t channel, int32_t c1, int32_t c2 );
+static int32_t _MIDI_SendControlChange( int32_t channel, int32_t c1, int32_t c2 );
+static void _MIDI_SetChannelVolume( int32_t channel, int32_t volume );
+static void _MIDI_SendChannelVolumes( void );
+static int32_t _MIDI_ProcessNextTick( void );
+static void _MIDI_InitEMIDI( void );
+
+/*
+ if ( c1 == EMIDI_LOOP_START )
+ {
+ if ( c2 == 0 )
+ {
+ Track->context[ 0 ].loopcount = EMIDI_INFINITE;
+ }
+ else
+ {
+ Track->context[ 0 ].loopcount = c2;
+ }
+
+ Track->context[ 0 ].pos = Track->pos;
+ Track->context[ 0 ].loopstart = Track->pos;
+ Track->context[ 0 ].RunningStatus = Track->RunningStatus;
+ Track->context[ 0 ].time = _MIDI_Time;
+ Track->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick;
+ Track->context[ 0 ].tick = _MIDI_Tick;
+ Track->context[ 0 ].beat = _MIDI_Beat;
+ Track->context[ 0 ].measure = _MIDI_Measure;
+ Track->context[ 0 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure;
+ Track->context[ 0 ].TicksPerBeat = _MIDI_TicksPerBeat;
+ Track->context[ 0 ].TimeBase = _MIDI_TimeBase;
+ break;
+ }
+
+ if ( ( c1 == EMIDI_LOOP_END ) &&
+ ( c2 == EMIDI_END_LOOP_VALUE ) )
+ {
+ if ( ( Track->context[ 0 ].loopstart != NULL ) &&
+ ( Track->context[ 0 ].loopcount != 0 ) )
+ {
+ if ( Track->context[ 0 ].loopcount != EMIDI_INFINITE )
+ {
+ Track->context[ 0 ].loopcount--;
+ }
+
+ Track->pos = Track->context[ 0 ].loopstart;
+ Track->RunningStatus = Track->context[ 0 ].RunningStatus;
+
+ if ( !TimeSet )
+ {
+ _MIDI_Time = Track->context[ 0 ].time;
+ _MIDI_FPSecondsPerTick = Track->context[ 0 ].FPSecondsPerTick;
+ _MIDI_Tick = Track->context[ 0 ].tick;
+ _MIDI_Beat = Track->context[ 0 ].beat;
+ _MIDI_Measure = Track->context[ 0 ].measure;
+ _MIDI_BeatsPerMeasure = Track->context[ 0 ].BeatsPerMeasure;
+ _MIDI_TicksPerBeat = Track->context[ 0 ].TicksPerBeat;
+ _MIDI_TimeBase = Track->context[ 0 ].TimeBase;
+ TimeSet = TRUE;
+ }
+ }
+ break;
+ }
+
+ if ( c1 == MIDI_MONO_MODE_ON )
+ {
+ Track->pos++;
+ }
+
+ if ( ( c1 == MIDI_VOLUME ) && ( !Track->EMIDI_VolumeChange ) )
+ {
+ _MIDI_SetChannelVolume( channel, c2 );
+ break;
+ }
+ else if ( ( c1 == EMIDI_VOLUME_CHANGE ) &&
+ ( Track->EMIDI_VolumeChange ) )
+ {
+ _MIDI_SetChannelVolume( channel, c2 );
+ break;
+ }
+
+ if ( ( c1 == EMIDI_PROGRAM_CHANGE ) &&
+ ( Track->EMIDI_ProgramChange ) )
+ {
+ _MIDI_Funcs->ProgramChange( channel, MIDI_PatchMap[ c2 & 0x7f ] );
+ break;
+ }
+
+ if ( c1 == EMIDI_CONTEXT_START )
+ {
+ break;
+ }
+
+ if ( c1 == EMIDI_CONTEXT_END )
+ {
+ if ( ( Track->currentcontext != _MIDI_Context ) ||
+ ( Track->context[ _MIDI_Context ].pos == NULL )
+ {
+ break;
+ }
+
+ Track->currentcontext = _MIDI_Context;
+ Track->context[ 0 ].loopstart = Track->context[ _MIDI_Context ].loopstart;
+ Track->context[ 0 ].loopcount = Track->context[ _MIDI_Context ].loopcount;
+ Track->pos = Track->context[ _MIDI_Context ].pos;
+ Track->RunningStatus = Track->context[ _MIDI_Context ].RunningStatus;
+
+ if ( TimeSet )
+ {
+ break;
+ }
+
+ _MIDI_Time = Track->context[ _MIDI_Context ].time;
+ _MIDI_FPSecondsPerTick = Track->context[ _MIDI_Context ].FPSecondsPerTick;
+ _MIDI_Tick = Track->context[ _MIDI_Context ].tick;
+ _MIDI_Beat = Track->context[ _MIDI_Context ].beat;
+ _MIDI_Measure = Track->context[ _MIDI_Context ].measure;
+ _MIDI_BeatsPerMeasure = Track->context[ _MIDI_Context ].BeatsPerMeasure;
+ _MIDI_TicksPerBeat = Track->context[ _MIDI_Context ].TicksPerBeat;
+ _MIDI_TimeBase = Track->context[ _MIDI_Context ].TimeBase;
+ TimeSet = TRUE;
+ break;
+ }
+
+ if ( _MIDI_Funcs->ControlChange )
+ {
+ _MIDI_Funcs->ControlChange( channel, c1, c2 );
+ }
+ */
+
+#endif
diff --git a/polymer/eduke32/source/game.c b/polymer/eduke32/source/game.c
index c58114671..38b1177b0 100644
--- a/polymer/eduke32/source/game.c
+++ b/polymer/eduke32/source/game.c
@@ -579,6 +579,7 @@ void Net_GetPackets(void)
input_t *osyn, *nsyn;
sampletimer();
+ MUSIC_Update();
G_HandleSpecialKeys();
@@ -1072,6 +1073,7 @@ void faketimerhandler(void)
}
sampletimer();
+ MUSIC_Update();
if ((totalclock < ototalclock+TICSPERFRAME) || (ready2send == 0)) return;
ototalclock += TICSPERFRAME;
@@ -11525,6 +11527,8 @@ MAIN_LOOP_RESTART:
quitevent = 0;
}
+ MUSIC_Update();
+
// only allow binds to function if the player is actually in a game (not in a menu, typing, et cetera) or demo
bindsenabled = (g_player[myconnectindex].ps->gm == MODE_GAME || g_player[myconnectindex].ps->gm == MODE_DEMO);
@@ -13325,6 +13329,7 @@ FRAGBONUS:
Net_GetPackets();
handleevents();
+ MUSIC_Update();
if (g_player[myconnectindex].ps->gm&MODE_EOL)
{
diff --git a/polymer/eduke32/source/jaudiolib/include/music.h b/polymer/eduke32/source/jaudiolib/include/music.h
index 56942790d..e63af97f2 100644
--- a/polymer/eduke32/source/jaudiolib/include/music.h
+++ b/polymer/eduke32/source/jaudiolib/include/music.h
@@ -1,93 +1,92 @@
-/*
-Copyright (C) 1994-1995 Apogee Software, Ltd.
-
-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.
-
-*/
-/**********************************************************************
- module: MUSIC.H
-
- author: James R. Dose
- date: March 25, 1994
-
- Public header for MUSIC.C
-
- (c) Copyright 1994 James R. Dose. All Rights Reserved.
-**********************************************************************/
-
-#ifndef __MUSIC_H
-#define __MUSIC_H
-
-#include "inttypes.h"
-#include "sndcards.h"
-
-extern int32_t MUSIC_ErrorCode;
-
-enum MUSIC_ERRORS
- {
- MUSIC_Warning = -2,
- MUSIC_Error = -1,
- MUSIC_Ok = 0,
- MUSIC_ASSVersion,
- MUSIC_SoundCardError,
- MUSIC_MPU401Error,
- MUSIC_InvalidCard,
- MUSIC_MidiError,
- MUSIC_TaskManError,
- MUSIC_FMNotDetected,
- MUSIC_DPMI_Error
- };
-
-typedef struct
- {
- uint32_t tickposition;
- uint32_t milliseconds;
- uint32_t measure;
- uint32_t beat;
- uint32_t tick;
- } songposition;
-
-#define MUSIC_LoopSong ( 1 == 1 )
-#define MUSIC_PlayOnce ( !MUSIC_LoopSong )
-
-char *MUSIC_ErrorString( int32_t ErrorNumber );
-int32_t MUSIC_Init( int32_t SoundCard, int32_t Address );
-int32_t MUSIC_Shutdown( void );
-void MUSIC_SetMaxFMMidiChannel( int32_t channel );
-void MUSIC_SetVolume( int32_t volume );
-void MUSIC_SetMidiChannelVolume( int32_t channel, int32_t volume );
-void MUSIC_ResetMidiChannelVolumes( void );
-int32_t MUSIC_GetVolume( void );
-void MUSIC_SetLoopFlag( int32_t loopflag );
-int32_t MUSIC_SongPlaying( void );
-void MUSIC_Continue( void );
-void MUSIC_Pause( void );
-int32_t MUSIC_StopSong( void );
-int32_t MUSIC_PlaySong( uint8_t *song, int32_t loopflag );
-void MUSIC_SetContext( int32_t context );
-int32_t MUSIC_GetContext( void );
-void MUSIC_SetSongTick( uint32_t PositionInTicks );
-void MUSIC_SetSongTime( uint32_t milliseconds );
-void MUSIC_SetSongPosition( int32_t measure, int32_t beat, int32_t tick );
-void MUSIC_GetSongPosition( songposition *pos );
-void MUSIC_GetSongLength( songposition *pos );
-int32_t MUSIC_FadeVolume( int32_t tovolume, int32_t milliseconds );
-int32_t MUSIC_FadeActive( void );
-void MUSIC_StopFade( void );
-void MUSIC_RerouteMidiChannel( int32_t channel, int32_t ( *function )( int32_t event, int32_t c1, int32_t c2 ) );
-void MUSIC_RegisterTimbreBank( uint8_t *timbres );
-
-#endif
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+Modifications for JonoF's port by Jonathon Fowler (jonof@edgenetwk.com)
+*/
+/**********************************************************************
+ module: MUSIC.H
+
+ author: James R. Dose
+ date: March 25, 1994
+
+ Public header for MUSIC.C
+
+ (c) Copyright 1994 James R. Dose. All Rights Reserved.
+**********************************************************************/
+
+#ifndef __MUSIC_H
+#define __MUSIC_H
+
+#include "compat.h"
+
+extern int32_t MUSIC_ErrorCode;
+
+enum MUSIC_ERRORS
+ {
+ MUSIC_Warning = -2,
+ MUSIC_Error = -1,
+ MUSIC_Ok = 0,
+ MUSIC_ASSVersion,
+ MUSIC_SoundCardError,
+ MUSIC_MPU401Error,
+ MUSIC_InvalidCard,
+ MUSIC_MidiError,
+ MUSIC_TaskManError,
+ MUSIC_DPMI_Error
+ };
+
+typedef struct
+ {
+ uint32_t tickposition;
+ uint32_t milliseconds;
+ uint32_t measure;
+ uint32_t beat;
+ uint32_t tick;
+ } songposition;
+
+#define MUSIC_LoopSong ( 1 == 1 )
+#define MUSIC_PlayOnce ( !MUSIC_LoopSong )
+
+char *MUSIC_ErrorString( int32_t ErrorNumber );
+int32_t MUSIC_Init( int32_t SoundCard, int32_t Address );
+int32_t MUSIC_Shutdown( void );
+void MUSIC_SetVolume( int32_t volume );
+void MUSIC_SetMidiChannelVolume( int32_t channel, int32_t volume );
+void MUSIC_ResetMidiChannelVolumes( void );
+int32_t MUSIC_GetVolume( void );
+void MUSIC_SetLoopFlag( int32_t loopflag );
+int32_t MUSIC_SongPlaying( void );
+void MUSIC_Continue( void );
+void MUSIC_Pause( void );
+int32_t MUSIC_StopSong( void );
+int32_t MUSIC_PlaySong( char *song, int32_t loopflag );
+void MUSIC_SetContext( int32_t context );
+int32_t MUSIC_GetContext( void );
+void MUSIC_SetSongTick( uint32_t PositionInTicks );
+void MUSIC_SetSongTime( uint32_t milliseconds );
+void MUSIC_SetSongPosition( int32_t measure, int32_t beat, int32_t tick );
+void MUSIC_GetSongPosition( songposition *pos );
+void MUSIC_GetSongLength( songposition *pos );
+int32_t MUSIC_FadeVolume( int32_t tovolume, int32_t milliseconds );
+int32_t MUSIC_FadeActive( void );
+void MUSIC_StopFade( void );
+void MUSIC_RerouteMidiChannel( int32_t channel, int32_t ( *function )( int32_t event, int32_t c1, int32_t c2 ) );
+void MUSIC_RegisterTimbreBank( char *timbres );
+void MUSIC_Update(void);
+
+#endif
diff --git a/polymer/eduke32/source/jaudiolib/src/_multivc.h b/polymer/eduke32/source/jaudiolib/src/_multivc.h
index d05675f78..8bd4f001a 100644
--- a/polymer/eduke32/source/jaudiolib/src/_multivc.h
+++ b/polymer/eduke32/source/jaudiolib/src/_multivc.h
@@ -229,30 +229,13 @@ typedef char HARSH_CLIP_TABLE_8[ MV_NumVoices * 256 ];
#define MV_SetErrorCode( status ) \
MV_ErrorCode = ( status );
-static void MV_Mix( VoiceNode *voice, int32_t buffer );
void MV_PlayVoice( VoiceNode *voice );
-static void MV_StopVoice( VoiceNode *voice );
-static void MV_ServiceVoc( void );
-static playbackstatus MV_GetNextVOCBlock( VoiceNode *voice );
-static playbackstatus MV_GetNextDemandFeedBlock( VoiceNode *voice );
-static playbackstatus MV_GetNextRawBlock( VoiceNode *voice );
-static playbackstatus MV_GetNextWAVBlock( VoiceNode *voice );
-static playbackstatus MV_GetNextVorbisBlock( VoiceNode *voice );
-
-static void MV_ServiceRecord( void );
-static VoiceNode *MV_GetVoice( int32_t handle );
VoiceNode *MV_AllocVoice( int32_t priority );
-static int16_t *MV_GetVolumeTable( int32_t vol );
-
void MV_SetVoiceMixMode( VoiceNode *voice );
void MV_SetVoiceVolume ( VoiceNode *voice, int32_t vol, int32_t left, int32_t right );
-static void MV_SetVoicePitch( VoiceNode *voice, uint32_t rate, int32_t pitchoffset );
-static void MV_CalcVolume( int32_t MaxLevel );
-static void MV_CalcPanTable( void );
-
void MV_ReleaseVorbisVoice( VoiceNode * voice );
// implemented in mix.c
diff --git a/polymer/eduke32/source/jaudiolib/src/fx_man.c b/polymer/eduke32/source/jaudiolib/src/fx_man.c
index fe71f8be4..c228d72c0 100644
--- a/polymer/eduke32/source/jaudiolib/src/fx_man.c
+++ b/polymer/eduke32/source/jaudiolib/src/fx_man.c
@@ -30,6 +30,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include
#include
+#include
#include "sndcards.h"
#include "drivers.h"
#include "multivoc.h"
diff --git a/polymer/eduke32/source/jaudiolib/src/multivoc.c b/polymer/eduke32/source/jaudiolib/src/multivoc.c
index f2fad54f2..32b451918 100644
--- a/polymer/eduke32/source/jaudiolib/src/multivoc.c
+++ b/polymer/eduke32/source/jaudiolib/src/multivoc.c
@@ -49,6 +49,23 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define LITTLE32
#endif
+static void MV_Mix( VoiceNode *voice, int32_t buffer );
+static void MV_StopVoice( VoiceNode *voice );
+static void MV_ServiceVoc( void );
+
+static playbackstatus MV_GetNextVOCBlock( VoiceNode *voice );
+static playbackstatus MV_GetNextDemandFeedBlock( VoiceNode *voice );
+static playbackstatus MV_GetNextRawBlock( VoiceNode *voice );
+static playbackstatus MV_GetNextWAVBlock( VoiceNode *voice );
+
+static VoiceNode *MV_GetVoice( int32_t handle );
+
+static int16_t *MV_GetVolumeTable( int32_t vol );
+
+static void MV_SetVoicePitch( VoiceNode *voice, uint32_t rate, int32_t pitchoffset );
+static void MV_CalcVolume( int32_t MaxLevel );
+static void MV_CalcPanTable( void );
+
static inline uint16_t SWAP16(uint16_t s)
{
return (s >> 8) | (s << 8);
@@ -399,7 +416,6 @@ void MV_ServiceVoc
{
VoiceNode *voice;
VoiceNode *next;
- char *buffer;
//int32_t flags;
// Toggle which buffer we'll mix next
@@ -528,7 +544,7 @@ playbackstatus MV_GetNextVOCBlock
int32_t lastblocktype;
uint32_t blocklength;
uint32_t samplespeed;
- uint32_t tc;
+ uint32_t tc = 0;
int32_t packtype;
int32_t voicemode;
int32_t done;
@@ -898,6 +914,7 @@ playbackstatus MV_GetNextWAVBlock
Starts recording of the waiting buffer.
---------------------------------------------------------------------*/
+/*
static void MV_ServiceRecord
(
void
@@ -917,6 +934,7 @@ static void MV_ServiceRecord
MV_MixPage = 0;
}
}
+*/
/*---------------------------------------------------------------------
diff --git a/polymer/eduke32/source/jaudiolib/src/vorbis.c b/polymer/eduke32/source/jaudiolib/src/vorbis.c
index 1688e0e42..dc32a5fd3 100644
--- a/polymer/eduke32/source/jaudiolib/src/vorbis.c
+++ b/polymer/eduke32/source/jaudiolib/src/vorbis.c
@@ -109,7 +109,7 @@ static int32_t close_vorbis(void * datasource)
return 0;
}
-static int32_t tell_vorbis(void * datasource)
+static long tell_vorbis(void * datasource)
{
vorbis_data * vorb = (vorbis_data *) datasource;
diff --git a/polymer/eduke32/source/midi.c b/polymer/eduke32/source/midi.c
new file mode 100644
index 000000000..1333f924a
--- /dev/null
+++ b/polymer/eduke32/source/midi.c
@@ -0,0 +1,2069 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+Modifications for JonoF's port by Jonathon Fowler (jonof@edgenetwk.com)
+*/
+/**********************************************************************
+ module: MIDI.C
+
+ author: James R. Dose
+ date: May 25, 1994
+
+ Midi song file playback routines.
+
+ (c) Copyright 1994 James R. Dose. All Rights Reserved.
+**********************************************************************/
+
+#include
+#include
+#include "standard.h"
+#include "music.h"
+#include "_midi.h"
+#include "midi.h"
+#include "mpu401.h"
+#include "compat.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include
+
+extern int32_t MUSIC_SoundDevice;
+
+static const int32_t _MIDI_CommandLengths[ NUM_MIDI_CHANNELS ] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0
+};
+
+static int32_t(*_MIDI_RerouteFunctions[ NUM_MIDI_CHANNELS ])
+(
+ int32_t event,
+ int32_t c1,
+ int32_t c2
+) =
+{
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static track *_MIDI_TrackPtr = NULL;
+static int32_t _MIDI_TrackMemSize;
+static int32_t _MIDI_NumTracks;
+
+static int32_t _MIDI_SongActive = FALSE;
+static int32_t _MIDI_SongLoaded = FALSE;
+static int32_t _MIDI_Loop = FALSE;
+
+static int32_t _MIDI_Division;
+static int32_t _MIDI_Tick = 0;
+static int32_t _MIDI_Beat = 1;
+static int32_t _MIDI_Measure = 1;
+static unsigned _MIDI_Time;
+static int32_t _MIDI_BeatsPerMeasure;
+static int32_t _MIDI_TicksPerBeat;
+static int32_t _MIDI_TimeBase;
+static int32_t _MIDI_FPSecondsPerTick;
+static unsigned _MIDI_TotalTime;
+static int32_t _MIDI_TotalTicks;
+static int32_t _MIDI_TotalBeats;
+static int32_t _MIDI_TotalMeasures;
+
+uint32_t _MIDI_PositionInTicks;
+uint32_t _MIDI_GlobalPositionInTicks;
+
+static int32_t _MIDI_Context;
+
+static int32_t _MIDI_ActiveTracks;
+static int32_t _MIDI_TotalVolume = MIDI_MaxVolume;
+
+static int32_t _MIDI_ChannelVolume[ NUM_MIDI_CHANNELS ];
+static int32_t _MIDI_UserChannelVolume[ NUM_MIDI_CHANNELS ] =
+{
+ 256, 256, 256, 256, 256, 256, 256, 256,
+ 256, 256, 256, 256, 256, 256, 256, 256
+};
+
+static midifuncs *_MIDI_Funcs = NULL;
+
+static int32_t Reset = FALSE;
+
+int32_t MIDI_Tempo = 120;
+
+char MIDI_PatchMap[ 128 ];
+
+
+/**********************************************************************
+
+ Memory locked functions:
+
+**********************************************************************/
+
+
+/*---------------------------------------------------------------------
+ Function: _MIDI_ReadNumber
+
+ Reads a variable length number from a MIDI track.
+---------------------------------------------------------------------*/
+
+static int32_t _MIDI_ReadNumber
+(
+ void *from,
+ size_t size
+)
+
+{
+ char *FromPtr;
+ int32_t value;
+
+ if (size > 4)
+ {
+ size = 4;
+ }
+
+ FromPtr = (char *)from;
+
+ value = 0;
+ while (size--)
+ {
+ value <<= 8;
+ value += *FromPtr++;
+ }
+
+ return(value);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: _MIDI_ReadDelta
+
+ Reads a variable length encoded delta delay time from the MIDI data.
+---------------------------------------------------------------------*/
+
+static int32_t _MIDI_ReadDelta
+(
+ track *ptr
+)
+
+{
+ int32_t value;
+ char c;
+
+ GET_NEXT_EVENT(ptr, value);
+
+ if (value & 0x80)
+ {
+ value &= 0x7f;
+ do
+ {
+ GET_NEXT_EVENT(ptr, c);
+ value = (value << 7) + (c & 0x7f);
+ }
+ while (c & 0x80);
+ }
+
+ return(value);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: _MIDI_ResetTracks
+
+ Sets the track pointers to the beginning of the song.
+---------------------------------------------------------------------*/
+
+static void _MIDI_ResetTracks
+(
+ void
+)
+
+{
+ int32_t i;
+ track *ptr;
+
+ _MIDI_Tick = 0;
+ _MIDI_Beat = 1;
+ _MIDI_Measure = 1;
+ _MIDI_Time = 0;
+ _MIDI_BeatsPerMeasure = 4;
+ _MIDI_TicksPerBeat = _MIDI_Division;
+ _MIDI_TimeBase = 4;
+
+ _MIDI_PositionInTicks = 0;
+ //_MIDI_GlobalPositionInTicks = 0;
+ _MIDI_ActiveTracks = 0;
+ _MIDI_Context = 0;
+
+ ptr = _MIDI_TrackPtr;
+ for (i = 0; i < _MIDI_NumTracks; i++)
+ {
+ ptr->pos = ptr->start;
+ ptr->delay = _MIDI_ReadDelta(ptr);
+ ptr->active = ptr->EMIDI_IncludeTrack;
+ ptr->RunningStatus = 0;
+ ptr->currentcontext = 0;
+ ptr->context[ 0 ].loopstart = ptr->start;
+ ptr->context[ 0 ].loopcount = 0;
+
+ if (ptr->active)
+ {
+ _MIDI_ActiveTracks++;
+ }
+
+ ptr++;
+ }
+}
+
+
+/*---------------------------------------------------------------------
+ Function: _MIDI_AdvanceTick
+
+ Increment tick counters.
+---------------------------------------------------------------------*/
+
+static void _MIDI_AdvanceTick
+(
+ void
+)
+
+{
+ _MIDI_PositionInTicks++;
+ _MIDI_Time += _MIDI_FPSecondsPerTick;
+
+ _MIDI_Tick++;
+ while (_MIDI_Tick > _MIDI_TicksPerBeat)
+ {
+ _MIDI_Tick -= _MIDI_TicksPerBeat;
+ _MIDI_Beat++;
+ }
+ while (_MIDI_Beat > _MIDI_BeatsPerMeasure)
+ {
+ _MIDI_Beat -= _MIDI_BeatsPerMeasure;
+ _MIDI_Measure++;
+ }
+}
+
+
+/*---------------------------------------------------------------------
+ Function: _MIDI_SysEx
+
+ Interpret SysEx Event.
+---------------------------------------------------------------------*/
+
+static void _MIDI_SysEx
+(
+ track *Track
+)
+
+{
+ int32_t length;
+
+ length = _MIDI_ReadDelta(Track);
+ Track->pos += length;
+}
+
+
+/*---------------------------------------------------------------------
+ Function: _MIDI_MetaEvent
+
+ Interpret Meta Event.
+---------------------------------------------------------------------*/
+
+static void _MIDI_MetaEvent
+(
+ track *Track
+)
+
+{
+ int32_t command;
+ int32_t length;
+ int32_t denominator;
+ int32_t tempo;
+
+ GET_NEXT_EVENT(Track, command);
+ GET_NEXT_EVENT(Track, length);
+
+ switch (command)
+ {
+ case MIDI_END_OF_TRACK :
+ Track->active = FALSE;
+
+ _MIDI_ActiveTracks--;
+ break;
+
+ case MIDI_TEMPO_CHANGE :
+ tempo = 60000000L / _MIDI_ReadNumber(Track->pos, 3);
+ MIDI_SetTempo(tempo);
+ break;
+
+ case MIDI_TIME_SIGNATURE :
+ if ((_MIDI_Tick > 0) || (_MIDI_Beat > 1))
+ {
+ _MIDI_Measure++;
+ }
+
+ _MIDI_Tick = 0;
+ _MIDI_Beat = 1;
+
+ _MIDI_BeatsPerMeasure = (int32_t)*Track->pos;
+ denominator = (int32_t)*(Track->pos + 1);
+ _MIDI_TimeBase = 1;
+ while (denominator > 0)
+ {
+ _MIDI_TimeBase += _MIDI_TimeBase;
+ denominator--;
+ }
+ _MIDI_TicksPerBeat = (_MIDI_Division * 4) / _MIDI_TimeBase;
+ break;
+ }
+
+ Track->pos += length;
+}
+
+
+/*---------------------------------------------------------------------
+ Function: _MIDI_InterpretControllerInfo
+
+ Interprets the MIDI controller info.
+---------------------------------------------------------------------*/
+
+static int32_t _MIDI_InterpretControllerInfo
+(
+ track *Track,
+ int32_t TimeSet,
+ int32_t channel,
+ int32_t c1,
+ int32_t c2
+)
+
+{
+ track *trackptr;
+ int32_t tracknum;
+ int32_t loopcount;
+
+ switch (c1)
+ {
+ case MIDI_MONO_MODE_ON :
+ Track->pos++;
+ break;
+
+ case MIDI_VOLUME :
+ if (!Track->EMIDI_VolumeChange)
+ {
+ _MIDI_SetChannelVolume(channel, c2);
+ }
+ break;
+
+ case EMIDI_INCLUDE_TRACK :
+ case EMIDI_EXCLUDE_TRACK :
+ break;
+
+ case EMIDI_PROGRAM_CHANGE :
+ if (Track->EMIDI_ProgramChange)
+ {
+ _MIDI_Funcs->ProgramChange(channel, MIDI_PatchMap[ c2 & 0x7f ]);
+ }
+ break;
+
+ case EMIDI_VOLUME_CHANGE :
+ if (Track->EMIDI_VolumeChange)
+ {
+ _MIDI_SetChannelVolume(channel, c2);
+ }
+ break;
+
+ case EMIDI_CONTEXT_START :
+ break;
+
+ case EMIDI_CONTEXT_END :
+ if ((Track->currentcontext == _MIDI_Context) ||
+ (_MIDI_Context < 0) ||
+ (Track->context[ _MIDI_Context ].pos == NULL))
+ {
+ break;
+ }
+
+ Track->currentcontext = _MIDI_Context;
+ Track->context[ 0 ].loopstart = Track->context[ _MIDI_Context ].loopstart;
+ Track->context[ 0 ].loopcount = Track->context[ _MIDI_Context ].loopcount;
+ Track->pos = Track->context[ _MIDI_Context ].pos;
+ Track->RunningStatus = Track->context[ _MIDI_Context ].RunningStatus;
+
+ if (TimeSet)
+ {
+ break;
+ }
+
+ _MIDI_Time = Track->context[ _MIDI_Context ].time;
+ _MIDI_FPSecondsPerTick = Track->context[ _MIDI_Context ].FPSecondsPerTick;
+ _MIDI_Tick = Track->context[ _MIDI_Context ].tick;
+ _MIDI_Beat = Track->context[ _MIDI_Context ].beat;
+ _MIDI_Measure = Track->context[ _MIDI_Context ].measure;
+ _MIDI_BeatsPerMeasure = Track->context[ _MIDI_Context ].BeatsPerMeasure;
+ _MIDI_TicksPerBeat = Track->context[ _MIDI_Context ].TicksPerBeat;
+ _MIDI_TimeBase = Track->context[ _MIDI_Context ].TimeBase;
+ TimeSet = TRUE;
+ break;
+
+ case EMIDI_LOOP_START :
+ case EMIDI_SONG_LOOP_START :
+ if (c2 == 0)
+ {
+ loopcount = EMIDI_INFINITE;
+ }
+ else
+ {
+ loopcount = c2;
+ }
+
+ if (c1 == EMIDI_SONG_LOOP_START)
+ {
+ trackptr = _MIDI_TrackPtr;
+ tracknum = _MIDI_NumTracks;
+ }
+ else
+ {
+ trackptr = Track;
+ tracknum = 1;
+ }
+
+ while (tracknum > 0)
+ {
+ trackptr->context[ 0 ].loopcount = loopcount;
+ trackptr->context[ 0 ].pos = trackptr->pos;
+ trackptr->context[ 0 ].loopstart = trackptr->pos;
+ trackptr->context[ 0 ].RunningStatus = trackptr->RunningStatus;
+ trackptr->context[ 0 ].active = trackptr->active;
+ trackptr->context[ 0 ].delay = trackptr->delay;
+ trackptr->context[ 0 ].time = _MIDI_Time;
+ trackptr->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick;
+ trackptr->context[ 0 ].tick = _MIDI_Tick;
+ trackptr->context[ 0 ].beat = _MIDI_Beat;
+ trackptr->context[ 0 ].measure = _MIDI_Measure;
+ trackptr->context[ 0 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure;
+ trackptr->context[ 0 ].TicksPerBeat = _MIDI_TicksPerBeat;
+ trackptr->context[ 0 ].TimeBase = _MIDI_TimeBase;
+ trackptr++;
+ tracknum--;
+ }
+ break;
+
+ case EMIDI_LOOP_END :
+ case EMIDI_SONG_LOOP_END :
+ if ((c2 != EMIDI_END_LOOP_VALUE) ||
+ (Track->context[ 0 ].loopstart == NULL) ||
+ (Track->context[ 0 ].loopcount == 0))
+ {
+ break;
+ }
+
+ if (c1 == EMIDI_SONG_LOOP_END)
+ {
+ trackptr = _MIDI_TrackPtr;
+ tracknum = _MIDI_NumTracks;
+ _MIDI_ActiveTracks = 0;
+ }
+ else
+ {
+ trackptr = Track;
+ tracknum = 1;
+ _MIDI_ActiveTracks--;
+ }
+
+ while (tracknum > 0)
+ {
+ if (trackptr->context[ 0 ].loopcount != EMIDI_INFINITE)
+ {
+ trackptr->context[ 0 ].loopcount--;
+ }
+
+ trackptr->pos = trackptr->context[ 0 ].loopstart;
+ trackptr->RunningStatus = trackptr->context[ 0 ].RunningStatus;
+ trackptr->delay = trackptr->context[ 0 ].delay;
+ trackptr->active = trackptr->context[ 0 ].active;
+ if (trackptr->active)
+ {
+ _MIDI_ActiveTracks++;
+ }
+
+ if (!TimeSet)
+ {
+ _MIDI_Time = trackptr->context[ 0 ].time;
+ _MIDI_FPSecondsPerTick = trackptr->context[ 0 ].FPSecondsPerTick;
+ _MIDI_Tick = trackptr->context[ 0 ].tick;
+ _MIDI_Beat = trackptr->context[ 0 ].beat;
+ _MIDI_Measure = trackptr->context[ 0 ].measure;
+ _MIDI_BeatsPerMeasure = trackptr->context[ 0 ].BeatsPerMeasure;
+ _MIDI_TicksPerBeat = trackptr->context[ 0 ].TicksPerBeat;
+ _MIDI_TimeBase = trackptr->context[ 0 ].TimeBase;
+ TimeSet = TRUE;
+ }
+
+ trackptr++;
+ tracknum--;
+ }
+ break;
+
+ default :
+ if (_MIDI_Funcs->ControlChange)
+ {
+ _MIDI_Funcs->ControlChange(channel, c1, c2);
+ }
+ }
+
+ return TimeSet;
+}
+
+
+/*---------------------------------------------------------------------
+ Function: _MIDI_ServiceRoutine
+
+ Task that interperates the MIDI data.
+---------------------------------------------------------------------*/
+
+static int32_t _MIDI_ServiceRoutine(void)
+{
+ int32_t event;
+ int32_t channel;
+ int32_t command;
+ track *Track;
+ int32_t tracknum;
+ int32_t status;
+ int32_t c1 = 0;
+ int32_t c2 = 0;
+ int32_t TimeSet = FALSE;
+
+ if (_MIDI_SongActive)
+ {
+ Track = _MIDI_TrackPtr;
+ tracknum = 0;
+ while (tracknum < _MIDI_NumTracks)
+ {
+ while ((Track->active) && (Track->delay == 0))
+ {
+ GET_NEXT_EVENT(Track, event);
+
+ if (GET_MIDI_COMMAND(event) == MIDI_SPECIAL)
+ {
+ switch (event)
+ {
+ case MIDI_SYSEX :
+ case MIDI_SYSEX_CONTINUE :
+ _MIDI_SysEx(Track);
+ break;
+
+ case MIDI_META_EVENT :
+ _MIDI_MetaEvent(Track);
+ break;
+ }
+
+ if (Track->active)
+ {
+ Track->delay = _MIDI_ReadDelta(Track);
+ }
+ continue;
+ }
+
+ if (event & MIDI_RUNNING_STATUS)
+ {
+ Track->RunningStatus = event;
+ }
+ else
+ {
+ event = Track->RunningStatus;
+ Track->pos--;
+ }
+
+ channel = GET_MIDI_CHANNEL(event);
+ command = GET_MIDI_COMMAND(event);
+
+ if (_MIDI_CommandLengths[ command ] > 0)
+ {
+ GET_NEXT_EVENT(Track, c1);
+ if (_MIDI_CommandLengths[ command ] > 1)
+ {
+ GET_NEXT_EVENT(Track, c2);
+ }
+ }
+
+ if (_MIDI_RerouteFunctions[ channel ] != NULL)
+ {
+ status = _MIDI_RerouteFunctions[ channel ](event, c1, c2);
+
+ if (status == MIDI_DONT_PLAY)
+ {
+ Track->delay = _MIDI_ReadDelta(Track);
+ continue;
+ }
+ }
+
+ switch (command)
+ {
+ case MIDI_NOTE_OFF :
+ if (_MIDI_Funcs->NoteOff)
+ {
+ _MIDI_Funcs->NoteOff(channel, c1, c2);
+ }
+ break;
+
+ case MIDI_NOTE_ON :
+ if (_MIDI_Funcs->NoteOn)
+ {
+ _MIDI_Funcs->NoteOn(channel, c1, c2);
+ }
+ break;
+
+ case MIDI_POLY_AFTER_TCH :
+ if (_MIDI_Funcs->PolyAftertouch)
+ {
+ _MIDI_Funcs->PolyAftertouch(channel, c1, c2);
+ }
+ break;
+
+ case MIDI_CONTROL_CHANGE :
+ TimeSet = _MIDI_InterpretControllerInfo(Track, TimeSet, channel, c1, c2);
+ break;
+
+ case MIDI_PROGRAM_CHANGE :
+ if ((_MIDI_Funcs->ProgramChange) && (!Track->EMIDI_ProgramChange))
+ {
+ _MIDI_Funcs->ProgramChange(channel, MIDI_PatchMap[ c1 & 0x7f ]);
+ }
+ break;
+
+ case MIDI_AFTER_TOUCH :
+ if (_MIDI_Funcs->ChannelAftertouch)
+ {
+ _MIDI_Funcs->ChannelAftertouch(channel, c1);
+ }
+ break;
+
+ case MIDI_PITCH_BEND :
+ if (_MIDI_Funcs->PitchBend)
+ {
+ _MIDI_Funcs->PitchBend(channel, c1, c2);
+ }
+ break;
+
+ default :
+ break;
+ }
+
+ Track->delay = _MIDI_ReadDelta(Track);
+ }
+
+ Track->delay--;
+ Track++;
+ tracknum++;
+
+ if (_MIDI_ActiveTracks == 0)
+ {
+ _MIDI_ResetTracks();
+ if (_MIDI_Loop)
+ {
+ tracknum = 0;
+ Track = _MIDI_TrackPtr;
+ }
+ else
+ {
+ _MIDI_SongActive = FALSE;
+ break;
+ }
+ }
+ }
+
+ _MIDI_AdvanceTick();
+ _MIDI_GlobalPositionInTicks++;
+ }
+ return 0;
+}
+
+
+/*---------------------------------------------------------------------
+ Function: _MIDI_SendControlChange
+
+ Sends a control change to the proper device
+---------------------------------------------------------------------*/
+
+static int32_t _MIDI_SendControlChange
+(
+ int32_t channel,
+ int32_t c1,
+ int32_t c2
+)
+
+{
+ int32_t status;
+
+ if (_MIDI_RerouteFunctions[ channel ] != NULL)
+ {
+ status = _MIDI_RerouteFunctions[ channel ](0xB0 + channel,
+ c1, c2);
+ if (status == MIDI_DONT_PLAY)
+ {
+ return(MIDI_Ok);
+ }
+ }
+
+ if (_MIDI_Funcs == NULL)
+ {
+ return(MIDI_Error);
+ }
+
+ if (_MIDI_Funcs->ControlChange == NULL)
+ {
+ return(MIDI_Error);
+ }
+
+ _MIDI_Funcs->ControlChange(channel, c1, c2);
+
+ return(MIDI_Ok);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_RerouteMidiChannel
+
+ Sets callback function to reroute MIDI commands from specified
+ function.
+---------------------------------------------------------------------*/
+
+void MIDI_RerouteMidiChannel
+(
+ int32_t channel,
+ int32_t(*function)(int32_t event, int32_t c1, int32_t c2)
+)
+
+{
+ if ((channel >= 1) && (channel <= 16))
+ {
+ _MIDI_RerouteFunctions[ channel - 1 ] = function;
+ }
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_AllNotesOff
+
+ Sends all notes off commands on all midi channels.
+---------------------------------------------------------------------*/
+
+int32_t MIDI_AllNotesOff
+(
+ void
+)
+
+{
+ int32_t channel;
+
+ for (channel = 0; channel < NUM_MIDI_CHANNELS; channel++)
+ {
+ _MIDI_SendControlChange(channel, 0x40, 0);
+ _MIDI_SendControlChange(channel, MIDI_ALL_NOTES_OFF, 0);
+ _MIDI_SendControlChange(channel, 0x78, 0);
+ }
+
+ return(MIDI_Ok);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: _MIDI_SetChannelVolume
+
+ Sets the volume of the specified midi channel.
+---------------------------------------------------------------------*/
+
+static void _MIDI_SetChannelVolume
+(
+ int32_t channel,
+ int32_t volume
+)
+
+{
+ int32_t status;
+ int32_t remotevolume;
+
+ _MIDI_ChannelVolume[ channel ] = volume;
+
+ if (_MIDI_RerouteFunctions[ channel ] != NULL)
+ {
+ remotevolume = volume * _MIDI_TotalVolume;
+ remotevolume *= _MIDI_UserChannelVolume[ channel ];
+ remotevolume /= MIDI_MaxVolume;
+ remotevolume >>= 8;
+
+ status = _MIDI_RerouteFunctions[ channel ](0xB0 + channel,
+ MIDI_VOLUME, remotevolume);
+ if (status == MIDI_DONT_PLAY)
+ {
+ return;
+ }
+ }
+
+ if (_MIDI_Funcs == NULL)
+ {
+ return;
+ }
+
+ if (_MIDI_Funcs->ControlChange == NULL)
+ {
+ return;
+ }
+
+ // For user volume
+ volume *= _MIDI_UserChannelVolume[ channel ];
+
+ if (_MIDI_Funcs->SetVolume == NULL)
+ {
+ volume *= _MIDI_TotalVolume;
+ volume /= MIDI_MaxVolume;
+ }
+
+ // For user volume
+ volume >>= 8;
+
+ _MIDI_Funcs->ControlChange(channel, MIDI_VOLUME, volume);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_SetUserChannelVolume
+
+ Sets the volume of the specified midi channel.
+---------------------------------------------------------------------*/
+
+void MIDI_SetUserChannelVolume
+(
+ int32_t channel,
+ int32_t volume
+)
+
+{
+ // Convert channel from 1-16 to 0-15
+ channel--;
+
+ volume = max(0, volume);
+ volume = min(volume, 256);
+
+ if ((channel >= 0) && (channel < NUM_MIDI_CHANNELS))
+ {
+ _MIDI_UserChannelVolume[ channel ] = volume;
+ _MIDI_SetChannelVolume(channel, _MIDI_ChannelVolume[ channel ]);
+ }
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_ResetUserChannelVolume
+
+ Sets the volume of the specified midi channel.
+---------------------------------------------------------------------*/
+
+void MIDI_ResetUserChannelVolume
+(
+ void
+)
+
+{
+ int32_t channel;
+
+ for (channel = 0; channel < NUM_MIDI_CHANNELS; channel++)
+ {
+ _MIDI_UserChannelVolume[ channel ] = 256;
+ }
+
+ _MIDI_SendChannelVolumes();
+}
+
+
+/*---------------------------------------------------------------------
+ Function: _MIDI_SendChannelVolumes
+
+ Sets the volume on all the midi channels.
+---------------------------------------------------------------------*/
+
+static void _MIDI_SendChannelVolumes
+(
+ void
+)
+
+{
+ int32_t channel;
+
+ for (channel = 0; channel < NUM_MIDI_CHANNELS; channel++)
+ {
+ _MIDI_SetChannelVolume(channel, _MIDI_ChannelVolume[ channel ]);
+ }
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_Reset
+
+ Resets the MIDI device to General Midi defaults.
+---------------------------------------------------------------------*/
+
+int32_t MIDI_Reset
+(
+ void
+)
+
+{
+ int32_t channel;
+
+ MIDI_AllNotesOff();
+
+ for (channel = 0; channel < NUM_MIDI_CHANNELS; channel++)
+ {
+ _MIDI_SendControlChange(channel, MIDI_RESET_ALL_CONTROLLERS, 0);
+ _MIDI_SendControlChange(channel, MIDI_RPN_MSB, MIDI_PITCHBEND_MSB);
+ _MIDI_SendControlChange(channel, MIDI_RPN_LSB, MIDI_PITCHBEND_LSB);
+ _MIDI_SendControlChange(channel, MIDI_DATAENTRY_MSB, 2); /* Pitch Bend Sensitivity MSB */
+ _MIDI_SendControlChange(channel, MIDI_DATAENTRY_LSB, 0); /* Pitch Bend Sensitivity LSB */
+ _MIDI_ChannelVolume[ channel ] = GENMIDI_DefaultVolume;
+ }
+
+ _MIDI_SendChannelVolumes();
+
+ Reset = TRUE;
+
+ return(MIDI_Ok);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_SetVolume
+
+ Sets the total volume of the music.
+---------------------------------------------------------------------*/
+
+int32_t MIDI_SetVolume
+(
+ int32_t volume
+)
+
+{
+ int32_t i;
+
+ if (_MIDI_Funcs == NULL)
+ {
+ return(MIDI_NullMidiModule);
+ }
+
+ volume = min(MIDI_MaxVolume, volume);
+ volume = max(0, volume);
+
+ _MIDI_TotalVolume = volume;
+
+ if (_MIDI_Funcs->SetVolume)
+ {
+ _MIDI_Funcs->SetVolume(volume);
+
+ for (i = 0; i < NUM_MIDI_CHANNELS; i++)
+ {
+ if (_MIDI_RerouteFunctions[ i ] != NULL)
+ {
+ _MIDI_SetChannelVolume(i, _MIDI_ChannelVolume[ i ]);
+ }
+ }
+ }
+ else
+ {
+ _MIDI_SendChannelVolumes();
+ }
+
+ return(MIDI_Ok);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_GetVolume
+
+ Returns the total volume of the music.
+---------------------------------------------------------------------*/
+
+int32_t MIDI_GetVolume
+(
+ void
+)
+
+{
+ int32_t volume;
+
+ if (_MIDI_Funcs == NULL)
+ {
+ return(MIDI_NullMidiModule);
+ }
+
+ if (_MIDI_Funcs->GetVolume)
+ {
+ volume = _MIDI_Funcs->GetVolume();
+ }
+ else
+ {
+ volume = _MIDI_TotalVolume;
+ }
+
+ return(volume);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_SetContext
+
+ Sets the song context.
+---------------------------------------------------------------------*/
+
+void MIDI_SetContext
+(
+ int32_t context
+)
+
+{
+ if ((context > 0) && (context < EMIDI_NUM_CONTEXTS))
+ {
+ _MIDI_Context = context;
+ }
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_GetContext
+
+ Returns the current song context.
+---------------------------------------------------------------------*/
+
+int32_t MIDI_GetContext
+(
+ void
+)
+
+{
+ return _MIDI_Context;
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_SetLoopFlag
+
+ Sets whether the song should loop when finished or not.
+---------------------------------------------------------------------*/
+
+void MIDI_SetLoopFlag
+(
+ int32_t loopflag
+)
+
+{
+ _MIDI_Loop = loopflag;
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_ContinueSong
+
+ Continues playback of a paused song.
+---------------------------------------------------------------------*/
+
+void MIDI_ContinueSong
+(
+ void
+)
+
+{
+ if (_MIDI_SongLoaded)
+ {
+ _MIDI_SongActive = TRUE;
+ MPU_Unpause();
+ }
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_PauseSong
+
+ Pauses playback of the current song.
+---------------------------------------------------------------------*/
+
+void MIDI_PauseSong
+(
+ void
+)
+
+{
+ if (_MIDI_SongLoaded)
+ {
+ _MIDI_SongActive = FALSE;
+ MIDI_AllNotesOff();
+ MPU_Pause();
+ }
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_SongPlaying
+
+ Returns whether a song is playing or not.
+---------------------------------------------------------------------*/
+
+int32_t MIDI_SongPlaying
+(
+ void
+)
+
+{
+ return(_MIDI_SongActive);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_SetMidiFuncs
+
+ Selects the routines that send the MIDI data to the music device.
+---------------------------------------------------------------------*/
+
+void MIDI_SetMidiFuncs
+(
+ midifuncs *funcs
+)
+
+{
+ _MIDI_Funcs = funcs;
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_StopSong
+
+ Stops playback of the currently playing song.
+---------------------------------------------------------------------*/
+
+void MIDI_StopSong
+(
+ void
+)
+
+{
+ if (_MIDI_SongLoaded)
+ {
+ _MIDI_SongActive = FALSE;
+ _MIDI_SongLoaded = FALSE;
+
+ MIDI_Reset();
+ _MIDI_ResetTracks();
+
+ if (_MIDI_Funcs->ReleasePatches)
+ {
+ _MIDI_Funcs->ReleasePatches();
+ }
+
+ Bfree(_MIDI_TrackPtr);
+
+ _MIDI_TrackPtr = NULL;
+ _MIDI_NumTracks = 0;
+ _MIDI_TrackMemSize = 0;
+
+ _MIDI_TotalTime = 0;
+ _MIDI_TotalTicks = 0;
+ _MIDI_TotalBeats = 0;
+ _MIDI_TotalMeasures = 0;
+
+ MPU_Reset();
+ }
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_PlaySong
+
+ Begins playback of a MIDI song.
+---------------------------------------------------------------------*/
+
+int32_t MIDI_PlaySong
+(
+ char *song,
+ int32_t loopflag
+)
+
+{
+ int32_t numtracks;
+ int32_t format;
+ int32_t headersize;
+ int32_t tracklength;
+ track *CurrentTrack;
+ char *ptr;
+
+ if (_MIDI_SongLoaded)
+ {
+ MIDI_StopSong();
+ }
+
+ MPU_Init(MUSIC_SoundDevice);
+
+ _MIDI_Loop = loopflag;
+
+ if (_MIDI_Funcs == NULL)
+ {
+ return(MIDI_NullMidiModule);
+ }
+
+ if (*(uint32_t *)song != MIDI_HEADER_SIGNATURE)
+ {
+ return(MIDI_InvalidMidiFile);
+ }
+
+ song += 4;
+
+ headersize = _MIDI_ReadNumber(song, 4);
+ song += 4;
+ format = _MIDI_ReadNumber(song, 2);
+ _MIDI_NumTracks = _MIDI_ReadNumber(song + 2, 2);
+ _MIDI_Division = _MIDI_ReadNumber(song + 4, 2);
+ if (_MIDI_Division < 0)
+ {
+ // If a SMPTE time division is given, just set to 96 so no errors occur
+ _MIDI_Division = 96;
+ }
+
+ if (format > MAX_FORMAT)
+ {
+ return(MIDI_UnknownMidiFormat);
+ }
+
+ ptr = song + headersize;
+
+ if (_MIDI_NumTracks == 0)
+ {
+ return(MIDI_NoTracks);
+ }
+
+ _MIDI_TrackMemSize = _MIDI_NumTracks * sizeof(track);
+ _MIDI_TrackPtr = Bmalloc(_MIDI_TrackMemSize);
+ if (_MIDI_TrackPtr == NULL)
+ {
+ return(MIDI_NoMemory);
+ }
+
+ CurrentTrack = _MIDI_TrackPtr;
+ numtracks = _MIDI_NumTracks;
+ while (numtracks--)
+ {
+ if (*(uint32_t *)ptr != MIDI_TRACK_SIGNATURE)
+ {
+ Bfree(_MIDI_TrackPtr);
+
+ _MIDI_TrackPtr = NULL;
+ _MIDI_TrackMemSize = 0;
+
+ return(MIDI_InvalidTrack);
+ }
+
+ tracklength = _MIDI_ReadNumber(ptr + 4, 4);
+ ptr += 8;
+ CurrentTrack->start = ptr;
+ ptr += tracklength;
+ CurrentTrack++;
+ }
+
+ if (_MIDI_Funcs->GetVolume != NULL)
+ {
+ _MIDI_TotalVolume = _MIDI_Funcs->GetVolume();
+ }
+
+ _MIDI_InitEMIDI();
+
+ if (_MIDI_Funcs->LoadPatch)
+ {
+ MIDI_LoadTimbres();
+ }
+
+ _MIDI_ResetTracks();
+
+ if (!Reset)
+ {
+ MIDI_Reset();
+ }
+
+ Reset = FALSE;
+
+ MIDI_SetDivision(_MIDI_Division);
+ //MIDI_SetTempo( 120 );
+
+ _MIDI_SongLoaded = TRUE;
+ _MIDI_SongActive = TRUE;
+
+ while (_MPU_BuffersWaiting < 4) _MIDI_ServiceRoutine();
+ MPU_BeginPlayback();
+
+ return(MIDI_Ok);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_SetTempo
+
+ Sets the song tempo.
+---------------------------------------------------------------------*/
+
+void MIDI_SetTempo
+(
+ int32_t tempo
+)
+
+{
+ int32_t tickspersecond;
+
+ MIDI_Tempo = tempo;
+ tickspersecond = ((tempo) * _MIDI_Division) / 60;
+ _MIDI_FPSecondsPerTick = (1 << TIME_PRECISION) / tickspersecond;
+ MPU_SetTempo(tempo);
+}
+
+void MIDI_SetDivision(int32_t division)
+{
+ MPU_SetDivision(division);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_GetTempo
+
+ Returns the song tempo.
+---------------------------------------------------------------------*/
+
+int32_t MIDI_GetTempo
+(
+ void
+)
+
+{
+ return(MIDI_Tempo);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: _MIDI_ProcessNextTick
+
+ Sets the position of the song pointer.
+---------------------------------------------------------------------*/
+
+static int32_t _MIDI_ProcessNextTick
+(
+ void
+)
+
+{
+ int32_t event;
+ int32_t channel;
+ int32_t command;
+ track *Track;
+ int32_t tracknum;
+ int32_t status;
+ int32_t c1 = 0;
+ int32_t c2 = 0;
+ int32_t TimeSet = FALSE;
+
+ Track = _MIDI_TrackPtr;
+ tracknum = 0;
+ while ((tracknum < _MIDI_NumTracks) && (Track != NULL))
+ {
+ while ((Track->active) && (Track->delay == 0))
+ {
+ GET_NEXT_EVENT(Track, event);
+
+ if (GET_MIDI_COMMAND(event) == MIDI_SPECIAL)
+ {
+ switch (event)
+ {
+ case MIDI_SYSEX :
+ case MIDI_SYSEX_CONTINUE :
+ _MIDI_SysEx(Track);
+ break;
+
+ case MIDI_META_EVENT :
+ _MIDI_MetaEvent(Track);
+ break;
+ }
+
+ if (Track->active)
+ {
+ Track->delay = _MIDI_ReadDelta(Track);
+ }
+
+ continue;
+ }
+
+ if (event & MIDI_RUNNING_STATUS)
+ {
+ Track->RunningStatus = event;
+ }
+ else
+ {
+ event = Track->RunningStatus;
+ Track->pos--;
+ }
+
+ channel = GET_MIDI_CHANNEL(event);
+ command = GET_MIDI_COMMAND(event);
+
+ if (_MIDI_CommandLengths[ command ] > 0)
+ {
+ GET_NEXT_EVENT(Track, c1);
+ if (_MIDI_CommandLengths[ command ] > 1)
+ {
+ GET_NEXT_EVENT(Track, c2);
+ }
+ }
+
+ if (_MIDI_RerouteFunctions[ channel ] != NULL)
+ {
+ status = _MIDI_RerouteFunctions[ channel ](event, c1, c2);
+
+ if (status == MIDI_DONT_PLAY)
+ {
+ Track->delay = _MIDI_ReadDelta(Track);
+ continue;
+ }
+ }
+
+ switch (command)
+ {
+ case MIDI_NOTE_OFF :
+ break;
+
+ case MIDI_NOTE_ON :
+ break;
+
+ case MIDI_POLY_AFTER_TCH :
+ if (_MIDI_Funcs->PolyAftertouch)
+ {
+ _MIDI_Funcs->PolyAftertouch(channel, c1, c2);
+ }
+ break;
+
+ case MIDI_CONTROL_CHANGE :
+ TimeSet = _MIDI_InterpretControllerInfo(Track, TimeSet,
+ channel, c1, c2);
+ break;
+
+ case MIDI_PROGRAM_CHANGE :
+ if ((_MIDI_Funcs->ProgramChange) &&
+ (!Track->EMIDI_ProgramChange))
+ {
+ _MIDI_Funcs->ProgramChange(channel, c1);
+ }
+ break;
+
+ case MIDI_AFTER_TOUCH :
+ if (_MIDI_Funcs->ChannelAftertouch)
+ {
+ _MIDI_Funcs->ChannelAftertouch(channel, c1);
+ }
+ break;
+
+ case MIDI_PITCH_BEND :
+ if (_MIDI_Funcs->PitchBend)
+ {
+ _MIDI_Funcs->PitchBend(channel, c1, c2);
+ }
+ break;
+
+ default :
+ break;
+ }
+
+ Track->delay = _MIDI_ReadDelta(Track);
+ }
+
+ Track->delay--;
+ Track++;
+ tracknum++;
+
+ if (_MIDI_ActiveTracks == 0)
+ {
+ break;
+ }
+ }
+
+ _MIDI_AdvanceTick();
+
+ return(TimeSet);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_SetSongTick
+
+ Sets the position of the song pointer.
+---------------------------------------------------------------------*/
+
+void MIDI_SetSongTick
+(
+ uint32_t PositionInTicks
+)
+
+{
+ if (!_MIDI_SongLoaded)
+ {
+ return;
+ }
+
+ MIDI_PauseSong();
+
+ if (PositionInTicks < _MIDI_PositionInTicks)
+ {
+ _MIDI_ResetTracks();
+ MIDI_Reset();
+ }
+
+ while (_MIDI_PositionInTicks < PositionInTicks)
+ {
+ if (_MIDI_ProcessNextTick())
+ {
+ break;
+ }
+ if (_MIDI_ActiveTracks == 0)
+ {
+ _MIDI_ResetTracks();
+ if (!_MIDI_Loop)
+ {
+ return;
+ }
+ break;
+ }
+ }
+
+ MIDI_SetVolume(_MIDI_TotalVolume);
+ MIDI_ContinueSong();
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_SetSongTime
+
+ Sets the position of the song pointer.
+---------------------------------------------------------------------*/
+
+void MIDI_SetSongTime
+(
+ uint32_t milliseconds
+)
+
+{
+ uint32_t mil;
+ uint32_t sec;
+ uint32_t newtime;
+
+ if (!_MIDI_SongLoaded)
+ {
+ return;
+ }
+
+ MIDI_PauseSong();
+
+ mil = ((milliseconds % 1000) << TIME_PRECISION) / 1000;
+ sec = (milliseconds / 1000) << TIME_PRECISION;
+ newtime = sec + mil;
+
+ if (newtime < _MIDI_Time)
+ {
+ _MIDI_ResetTracks();
+ MIDI_Reset();
+ }
+
+ while (_MIDI_Time < newtime)
+ {
+ if (_MIDI_ProcessNextTick())
+ {
+ break;
+ }
+ if (_MIDI_ActiveTracks == 0)
+ {
+ _MIDI_ResetTracks();
+ if (!_MIDI_Loop)
+ {
+ return;
+ }
+ break;
+ }
+ }
+
+ MIDI_SetVolume(_MIDI_TotalVolume);
+ MIDI_ContinueSong();
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_SetSongPosition
+
+ Sets the position of the song pointer.
+---------------------------------------------------------------------*/
+
+void MIDI_SetSongPosition
+(
+ int32_t measure,
+ int32_t beat,
+ int32_t tick
+)
+
+{
+ uint32_t pos;
+
+ if (!_MIDI_SongLoaded)
+ {
+ return;
+ }
+
+ MIDI_PauseSong();
+
+ pos = RELATIVE_BEAT(measure, beat, tick);
+
+ if (pos < (uint32_t)RELATIVE_BEAT(_MIDI_Measure, _MIDI_Beat, _MIDI_Tick))
+ {
+ _MIDI_ResetTracks();
+ MIDI_Reset();
+ }
+
+ while ((uint32_t)RELATIVE_BEAT(_MIDI_Measure, _MIDI_Beat, _MIDI_Tick) < pos)
+ {
+ if (_MIDI_ProcessNextTick())
+ {
+ break;
+ }
+ if (_MIDI_ActiveTracks == 0)
+ {
+ _MIDI_ResetTracks();
+ if (!_MIDI_Loop)
+ {
+ return;
+ }
+ break;
+ }
+ }
+
+ MIDI_SetVolume(_MIDI_TotalVolume);
+ MIDI_ContinueSong();
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_GetSongPosition
+
+ Returns the position of the song pointer in Measures, beats, ticks.
+---------------------------------------------------------------------*/
+
+void MIDI_GetSongPosition
+(
+ songposition *pos
+)
+
+{
+ uint32_t mil;
+ uint32_t sec;
+
+ mil = (_MIDI_Time & ((1 << TIME_PRECISION) - 1)) * 1000;
+ sec = _MIDI_Time >> TIME_PRECISION;
+ pos->milliseconds = (mil >> TIME_PRECISION) + (sec * 1000);
+ pos->tickposition = _MIDI_PositionInTicks;
+ pos->measure = _MIDI_Measure;
+ pos->beat = _MIDI_Beat;
+ pos->tick = _MIDI_Tick;
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_GetSongLength
+
+ Returns the length of the song.
+---------------------------------------------------------------------*/
+
+void MIDI_GetSongLength
+(
+ songposition *pos
+)
+
+{
+ uint32_t mil;
+ uint32_t sec;
+
+ mil = (_MIDI_TotalTime & ((1 << TIME_PRECISION) - 1)) * 1000;
+ sec = _MIDI_TotalTime >> TIME_PRECISION;
+
+ pos->milliseconds = (mil >> TIME_PRECISION) + (sec * 1000);
+ pos->measure = _MIDI_TotalMeasures;
+ pos->beat = _MIDI_TotalBeats;
+ pos->tick = _MIDI_TotalTicks;
+ pos->tickposition = 0;
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_InitEMIDI
+
+ Sets up the EMIDI
+---------------------------------------------------------------------*/
+
+static void _MIDI_InitEMIDI
+(
+ void
+)
+
+{
+ int32_t event;
+ int32_t command;
+ int32_t channel;
+ int32_t length;
+ int32_t IncludeFound;
+ track *Track;
+ int32_t tracknum;
+ int32_t type;
+ int32_t c1;
+ int32_t c2;
+
+ type = EMIDI_GeneralMIDI;
+
+ _MIDI_ResetTracks();
+
+ _MIDI_TotalTime = 0;
+ _MIDI_TotalTicks = 0;
+ _MIDI_TotalBeats = 0;
+ _MIDI_TotalMeasures = 0;
+
+ Track = _MIDI_TrackPtr;
+ tracknum = 0;
+ while ((tracknum < _MIDI_NumTracks) && (Track != NULL))
+ {
+ _MIDI_Tick = 0;
+ _MIDI_Beat = 1;
+ _MIDI_Measure = 1;
+ _MIDI_Time = 0;
+ _MIDI_BeatsPerMeasure = 4;
+ _MIDI_TicksPerBeat = _MIDI_Division;
+ _MIDI_TimeBase = 4;
+
+ _MIDI_PositionInTicks = 0;
+ _MIDI_ActiveTracks = 0;
+ _MIDI_Context = -1;
+
+ Track->RunningStatus = 0;
+ Track->active = TRUE;
+
+ Track->EMIDI_ProgramChange = FALSE;
+ Track->EMIDI_VolumeChange = FALSE;
+ Track->EMIDI_IncludeTrack = TRUE;
+
+ memset(Track->context, 0, sizeof(Track->context));
+
+ while (Track->delay > 0)
+ {
+ _MIDI_AdvanceTick();
+ Track->delay--;
+ }
+
+ IncludeFound = FALSE;
+ while (Track->active)
+ {
+ GET_NEXT_EVENT(Track, event);
+
+ if (GET_MIDI_COMMAND(event) == MIDI_SPECIAL)
+ {
+ switch (event)
+ {
+ case MIDI_SYSEX :
+ case MIDI_SYSEX_CONTINUE :
+ _MIDI_SysEx(Track);
+ break;
+
+ case MIDI_META_EVENT :
+ _MIDI_MetaEvent(Track);
+ break;
+ }
+
+ if (Track->active)
+ {
+ Track->delay = _MIDI_ReadDelta(Track);
+ while (Track->delay > 0)
+ {
+ _MIDI_AdvanceTick();
+ Track->delay--;
+ }
+ }
+
+ continue;
+ }
+
+ if (event & MIDI_RUNNING_STATUS)
+ {
+ Track->RunningStatus = event;
+ }
+ else
+ {
+ event = Track->RunningStatus;
+ Track->pos--;
+ }
+
+ channel = GET_MIDI_CHANNEL(event);
+ command = GET_MIDI_COMMAND(event);
+ length = _MIDI_CommandLengths[ command ];
+
+ if (command == MIDI_CONTROL_CHANGE)
+ {
+ if (*Track->pos == MIDI_MONO_MODE_ON)
+ {
+ length++;
+ }
+ GET_NEXT_EVENT(Track, c1);
+ GET_NEXT_EVENT(Track, c2);
+ length -= 2;
+
+ switch (c1)
+ {
+ case EMIDI_LOOP_START :
+ case EMIDI_SONG_LOOP_START :
+ if (c2 == 0)
+ {
+ Track->context[ 0 ].loopcount = EMIDI_INFINITE;
+ }
+ else
+ {
+ Track->context[ 0 ].loopcount = c2;
+ }
+
+ Track->context[ 0 ].pos = Track->pos;
+ Track->context[ 0 ].loopstart = Track->pos;
+ Track->context[ 0 ].RunningStatus = Track->RunningStatus;
+ Track->context[ 0 ].time = _MIDI_Time;
+ Track->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick;
+ Track->context[ 0 ].tick = _MIDI_Tick;
+ Track->context[ 0 ].beat = _MIDI_Beat;
+ Track->context[ 0 ].measure = _MIDI_Measure;
+ Track->context[ 0 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure;
+ Track->context[ 0 ].TicksPerBeat = _MIDI_TicksPerBeat;
+ Track->context[ 0 ].TimeBase = _MIDI_TimeBase;
+ break;
+
+ case EMIDI_LOOP_END :
+ case EMIDI_SONG_LOOP_END :
+ if (c2 == EMIDI_END_LOOP_VALUE)
+ {
+ Track->context[ 0 ].loopstart = NULL;
+ Track->context[ 0 ].loopcount = 0;
+ }
+ break;
+
+ case EMIDI_INCLUDE_TRACK :
+ if (EMIDI_AffectsCurrentCard(c2, type))
+ {
+ //printf( "Include track %d on card %d\n", tracknum, c2 );
+ IncludeFound = TRUE;
+ Track->EMIDI_IncludeTrack = TRUE;
+ }
+ else if (!IncludeFound)
+ {
+ //printf( "Track excluded %d on card %d\n", tracknum, c2 );
+ IncludeFound = TRUE;
+ Track->EMIDI_IncludeTrack = FALSE;
+ }
+ break;
+
+ case EMIDI_EXCLUDE_TRACK :
+ if (EMIDI_AffectsCurrentCard(c2, type))
+ {
+ //printf( "Exclude track %d on card %d\n", tracknum, c2 );
+ Track->EMIDI_IncludeTrack = FALSE;
+ }
+ break;
+
+ case EMIDI_PROGRAM_CHANGE :
+ if (!Track->EMIDI_ProgramChange)
+ //printf( "Program change on track %d\n", tracknum );
+ Track->EMIDI_ProgramChange = TRUE;
+ break;
+
+ case EMIDI_VOLUME_CHANGE :
+ if (!Track->EMIDI_VolumeChange)
+ //printf( "Volume change on track %d\n", tracknum );
+ Track->EMIDI_VolumeChange = TRUE;
+ break;
+
+ case EMIDI_CONTEXT_START :
+ if ((c2 > 0) && (c2 < EMIDI_NUM_CONTEXTS))
+ {
+ Track->context[ c2 ].pos = Track->pos;
+ Track->context[ c2 ].loopstart = Track->context[ 0 ].loopstart;
+ Track->context[ c2 ].loopcount = Track->context[ 0 ].loopcount;
+ Track->context[ c2 ].RunningStatus = Track->RunningStatus;
+ Track->context[ c2 ].time = _MIDI_Time;
+ Track->context[ c2 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick;
+ Track->context[ c2 ].tick = _MIDI_Tick;
+ Track->context[ c2 ].beat = _MIDI_Beat;
+ Track->context[ c2 ].measure = _MIDI_Measure;
+ Track->context[ c2 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure;
+ Track->context[ c2 ].TicksPerBeat = _MIDI_TicksPerBeat;
+ Track->context[ c2 ].TimeBase = _MIDI_TimeBase;
+ }
+ break;
+
+ case EMIDI_CONTEXT_END :
+ break;
+ }
+ }
+
+ Track->pos += length;
+ Track->delay = _MIDI_ReadDelta(Track);
+
+ while (Track->delay > 0)
+ {
+ _MIDI_AdvanceTick();
+ Track->delay--;
+ }
+ }
+
+ _MIDI_TotalTime = max(_MIDI_TotalTime, _MIDI_Time);
+ if (RELATIVE_BEAT(_MIDI_Measure, _MIDI_Beat, _MIDI_Tick) >
+ RELATIVE_BEAT(_MIDI_TotalMeasures, _MIDI_TotalBeats,
+ _MIDI_TotalTicks))
+ {
+ _MIDI_TotalTicks = _MIDI_Tick;
+ _MIDI_TotalBeats = _MIDI_Beat;
+ _MIDI_TotalMeasures = _MIDI_Measure;
+ }
+
+ Track++;
+ tracknum++;
+ }
+
+ _MIDI_ResetTracks();
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MIDI_LoadTimbres
+
+ Preloads the timbres on cards that use patch-caching.
+---------------------------------------------------------------------*/
+
+void MIDI_LoadTimbres
+(
+ void
+)
+
+{
+ int32_t event;
+ int32_t command;
+ int32_t channel;
+ int32_t length;
+ int32_t Finished;
+ track *Track;
+ int32_t tracknum;
+
+ Track = _MIDI_TrackPtr;
+ tracknum = 0;
+ while ((tracknum < _MIDI_NumTracks) && (Track != NULL))
+ {
+ Finished = FALSE;
+ while (!Finished)
+ {
+ GET_NEXT_EVENT(Track, event);
+
+ if (GET_MIDI_COMMAND(event) == MIDI_SPECIAL)
+ {
+ switch (event)
+ {
+ case MIDI_SYSEX :
+ case MIDI_SYSEX_CONTINUE :
+ length = _MIDI_ReadDelta(Track);
+ Track->pos += length;
+ break;
+
+ case MIDI_META_EVENT :
+ GET_NEXT_EVENT(Track, command);
+ GET_NEXT_EVENT(Track, length);
+
+ if (command == MIDI_END_OF_TRACK)
+ {
+ Finished = TRUE;
+ }
+
+ Track->pos += length;
+ break;
+ }
+
+ if (!Finished)
+ {
+ _MIDI_ReadDelta(Track);
+ }
+
+ continue;
+ }
+
+ if (event & MIDI_RUNNING_STATUS)
+ {
+ Track->RunningStatus = event;
+ }
+ else
+ {
+ event = Track->RunningStatus;
+ Track->pos--;
+ }
+
+ channel = GET_MIDI_CHANNEL(event);
+ command = GET_MIDI_COMMAND(event);
+ length = _MIDI_CommandLengths[ command ];
+
+ if (command == MIDI_CONTROL_CHANGE)
+ {
+ if (*Track->pos == MIDI_MONO_MODE_ON)
+ {
+ length++;
+ }
+
+ if (*Track->pos == EMIDI_PROGRAM_CHANGE)
+ {
+ _MIDI_Funcs->LoadPatch(*(Track->pos + 1));
+ }
+ }
+
+ if (channel == MIDI_RHYTHM_CHANNEL)
+ {
+ if (command == MIDI_NOTE_ON)
+ {
+ _MIDI_Funcs->LoadPatch(128 + *Track->pos);
+ }
+ }
+ else
+ {
+ if (command == MIDI_PROGRAM_CHANGE)
+ {
+ _MIDI_Funcs->LoadPatch(*Track->pos);
+ }
+ }
+ Track->pos += length;
+ _MIDI_ReadDelta(Track);
+ }
+ Track++;
+ tracknum++;
+ }
+
+ _MIDI_ResetTracks();
+}
+
+
+void MIDI_UpdateMusic(void)
+{
+ if (!_MIDI_SongLoaded || !_MIDI_SongActive) return;
+ while (_MPU_BuffersWaiting < 4) _MIDI_ServiceRoutine();
+}
+
diff --git a/polymer/eduke32/source/midi.h b/polymer/eduke32/source/midi.h
new file mode 100644
index 000000000..e3eab853a
--- /dev/null
+++ b/polymer/eduke32/source/midi.h
@@ -0,0 +1,100 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+Modifications for JonoF's port by Jonathon Fowler (jonof@edgenetwk.com)
+*/
+/**********************************************************************
+ module: MIDI.H
+
+ author: James R. Dose
+ date: May 25, 1994
+
+ Public header for MIDI.C. Midi song file playback routines.
+
+ (c) Copyright 1994 James R. Dose. All Rights Reserved.
+**********************************************************************/
+
+#ifndef __MIDI_H
+#define __MIDI_H
+
+enum MIDI_Errors
+ {
+ MIDI_Warning = -2,
+ MIDI_Error = -1,
+ MIDI_Ok = 0,
+ MIDI_NullMidiModule,
+ MIDI_InvalidMidiFile,
+ MIDI_UnknownMidiFormat,
+ MIDI_NoTracks,
+ MIDI_InvalidTrack,
+ MIDI_NoMemory,
+ MIDI_DPMI_Error
+ };
+
+
+#define MIDI_PASS_THROUGH 1
+#define MIDI_DONT_PLAY 0
+
+#define MIDI_MaxVolume 255
+
+extern char MIDI_PatchMap[ 128 ];
+
+typedef struct
+ {
+ void ( *NoteOff )( int32_t channel, int32_t key, int32_t velocity );
+ void ( *NoteOn )( int32_t channel, int32_t key, int32_t velocity );
+ void ( *PolyAftertouch )( int32_t channel, int32_t key, int32_t pressure );
+ void ( *ControlChange )( int32_t channel, int32_t number, int32_t value );
+ void ( *ProgramChange )( int32_t channel, int32_t program );
+ void ( *ChannelAftertouch )( int32_t channel, int32_t pressure );
+ void ( *PitchBend )( int32_t channel, int32_t lsb, int32_t msb );
+ void ( *ReleasePatches )( void );
+ void ( *LoadPatch )( int32_t number );
+ void ( *SetVolume )( int32_t volume );
+ int32_t ( *GetVolume )( void );
+ void ( *FinishBuffer )( void );
+ } midifuncs;
+
+void MIDI_RerouteMidiChannel( int32_t channel, int32_t ( *function )( int32_t event, int32_t c1, int32_t c2 ) );
+int32_t MIDI_AllNotesOff( void );
+void MIDI_SetUserChannelVolume( int32_t channel, int32_t volume );
+void MIDI_ResetUserChannelVolume( void );
+int32_t MIDI_Reset( void );
+int32_t MIDI_SetVolume( int32_t volume );
+int32_t MIDI_GetVolume( void );
+void MIDI_SetMidiFuncs( midifuncs *funcs );
+void MIDI_SetContext( int32_t context );
+int32_t MIDI_GetContext( void );
+void MIDI_SetLoopFlag( int32_t loopflag );
+void MIDI_ContinueSong( void );
+void MIDI_PauseSong( void );
+int32_t MIDI_SongPlaying( void );
+void MIDI_StopSong( void );
+int32_t MIDI_PlaySong( char *song, int32_t loopflag );
+void MIDI_SetTempo( int32_t tempo );
+int32_t MIDI_GetTempo( void );
+void MIDI_SetSongTick( uint32_t PositionInTicks );
+void MIDI_SetSongTime( uint32_t milliseconds );
+void MIDI_SetSongPosition( int32_t measure, int32_t beat, int32_t tick );
+void MIDI_GetSongPosition( songposition *pos );
+void MIDI_GetSongLength( songposition *pos );
+void MIDI_LoadTimbres( void );
+void MIDI_UpdateMusic(void);
+void MIDI_SetDivision( int32_t division );
+
+#endif
diff --git a/polymer/eduke32/source/mpu401.c b/polymer/eduke32/source/mpu401.c
new file mode 100644
index 000000000..0fd040fc8
--- /dev/null
+++ b/polymer/eduke32/source/mpu401.c
@@ -0,0 +1,495 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+Modifications for JonoF's port by Jonathon Fowler (jonof@edgenetwk.com)
+*/
+/**********************************************************************
+ module: MPU401.C
+
+ author: James R. Dose
+ date: January 1, 1994
+
+ Low level routines to support sending of MIDI data to MPU401
+ compatible MIDI interfaces.
+
+ (c) Copyright 1994 James R. Dose. All Rights Reserved.
+**********************************************************************/
+
+#include "mpu401.h"
+#include "compat.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include
+#include
+
+static HMIDISTRM hmido = (HMIDISTRM)-1;
+static MIDIOUTCAPS midicaps;
+static DWORD mididevice = -1;
+
+typedef struct
+{
+ int32_t time;
+ int32_t stream;
+ int32_t event;
+}
+MIDIEVENTHEAD;
+#define PAD(x) ((((x)+3)&(~3)))
+
+#define BUFFERLEN (32*4*4)
+#define NUMBUFFERS 6
+static char eventbuf[NUMBUFFERS][BUFFERLEN];
+static int32_t eventcnt[NUMBUFFERS];
+static MIDIHDR bufferheaders[NUMBUFFERS];
+int32_t _MPU_CurrentBuffer = 0;
+int32_t _MPU_BuffersWaiting = 0;
+
+extern uint32_t _MIDI_GlobalPositionInTicks;
+uint32_t _MPU_LastEvent=0;
+
+#define MIDI_NOTE_OFF 0x80
+#define MIDI_NOTE_ON 0x90
+#define MIDI_POLY_AFTER_TCH 0xA0
+#define MIDI_CONTROL_CHANGE 0xB0
+#define MIDI_PROGRAM_CHANGE 0xC0
+#define MIDI_AFTER_TOUCH 0xD0
+#define MIDI_PITCH_BEND 0xE0
+#define MIDI_META_EVENT 0xFF
+#define MIDI_END_OF_TRACK 0x2F
+#define MIDI_TEMPO_CHANGE 0x51
+#define MIDI_MONO_MODE_ON 0x7E
+#define MIDI_ALL_NOTES_OFF 0x7B
+
+
+/**********************************************************************
+
+ Memory locked functions:
+
+**********************************************************************/
+
+
+void MPU_FinishBuffer(int32_t buffer)
+{
+ if (!eventcnt[buffer]) return;
+ ZeroMemory(&bufferheaders[buffer], sizeof(MIDIHDR));
+ bufferheaders[buffer].lpData = eventbuf[buffer];
+ bufferheaders[buffer].dwBufferLength =
+ bufferheaders[buffer].dwBytesRecorded = eventcnt[buffer];
+ midiOutPrepareHeader((HMIDIOUT)hmido, &bufferheaders[buffer], sizeof(MIDIHDR));
+ midiStreamOut(hmido, &bufferheaders[buffer], sizeof(MIDIHDR));
+// printf("Sending %d bytes (buffer %d)\n",eventcnt[buffer],buffer);
+ _MPU_BuffersWaiting++;
+}
+
+void MPU_BeginPlayback(void)
+{
+ _MPU_LastEvent = _MIDI_GlobalPositionInTicks;
+ if (hmido != (HMIDISTRM)-1) midiStreamRestart(hmido);
+}
+
+void MPU_Pause(void)
+{
+ if (hmido != (HMIDISTRM)-1) midiStreamPause(hmido);
+}
+
+void MPU_Unpause(void)
+{
+ if (hmido != (HMIDISTRM)-1) midiStreamRestart(hmido);
+}
+
+
+void CALLBACK MPU_MIDICallback(HMIDIOUT handle, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
+{
+ int32_t i;
+
+ UNREFERENCED_PARAMETER(dwInstance);
+ UNREFERENCED_PARAMETER(dwParam2);
+
+ switch (uMsg)
+ {
+ case MOM_DONE:
+ midiOutUnprepareHeader((HMIDIOUT)handle, (MIDIHDR*)dwParam1, sizeof(MIDIHDR));
+ for (i=0;i BUFFERLEN)
+ {
+ // buffer over-full
+ nextbuffer = MPU_GetNextBuffer();
+ if (nextbuffer < 0)
+ {
+// printf("All buffers full!\n");
+ return;
+ }
+ MPU_FinishBuffer(_MPU_CurrentBuffer);
+ _MPU_CurrentBuffer = nextbuffer;
+ }
+
+ p = eventbuf[_MPU_CurrentBuffer] + eventcnt[_MPU_CurrentBuffer];
+ ((int32_t*)p)[0] = _MIDI_GlobalPositionInTicks - _MPU_LastEvent;
+ ((int32_t*)p)[1] = 0;
+ ((int32_t*)p)[2] = (MEVT_SHORTMSG << 24) | ((*((int32_t*)data)) & masks[count-1]);
+ eventcnt[_MPU_CurrentBuffer] += 12;
+ }
+ else
+ {
+ padded = PAD(count);
+ if (eventcnt[_MPU_CurrentBuffer] + 12 + padded > BUFFERLEN)
+ {
+ // buffer over-full
+ nextbuffer = MPU_GetNextBuffer();
+ if (nextbuffer < 0)
+ {
+// printf("All buffers full!\n");
+ return;
+ }
+ MPU_FinishBuffer(_MPU_CurrentBuffer);
+ _MPU_CurrentBuffer = nextbuffer;
+ }
+
+ p = eventbuf[_MPU_CurrentBuffer] + eventcnt[_MPU_CurrentBuffer];
+ ((int32_t*)p)[0] = _MIDI_GlobalPositionInTicks - _MPU_LastEvent;
+ ((int32_t*)p)[1] = 0;
+ ((int32_t*)p)[2] = (MEVT_LONGMSG<<24) | (count & 0xffffffl);
+ p+=12; eventcnt[_MPU_CurrentBuffer] += 12;
+ for (; count>0; count--, padded--, eventcnt[_MPU_CurrentBuffer]++)
+ *(p++) = *(data++);
+ for (; padded>0; padded--, eventcnt[_MPU_CurrentBuffer]++)
+ *(p++) = 0;
+ }
+ _MPU_LastEvent = _MIDI_GlobalPositionInTicks;
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MPU_SendMidiImmediate
+
+ Sends a MIDI message immediately to the the music device.
+---------------------------------------------------------------------*/
+void MPU_SendMidiImmediate(char *data, int32_t count)
+{
+ MIDIHDR mhdr;
+ static int32_t masks[3] = { 0x00ffffffl, 0x0000ffffl, 0x000000ffl };
+
+ if (!count) return;
+ if (count<=3) midiOutShortMsg((HMIDIOUT)hmido, (*((int32_t*)data)) & masks[count-1]);
+ else
+ {
+ ZeroMemory(&mhdr, sizeof(mhdr));
+ mhdr.lpData = data;
+ mhdr.dwBufferLength = count;
+ midiOutPrepareHeader((HMIDIOUT)hmido, &mhdr, sizeof(MIDIHDR));
+ midiOutLongMsg((HMIDIOUT)hmido, &mhdr, sizeof(MIDIHDR));
+ while (!(mhdr.dwFlags & MHDR_DONE)) ;
+ midiOutUnprepareHeader((HMIDIOUT)hmido, &mhdr, sizeof(MIDIHDR));
+ }
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MPU_Reset
+
+ Resets the MPU401 card.
+---------------------------------------------------------------------*/
+
+int32_t MPU_Reset
+(
+ void
+)
+
+{
+ midiStreamStop(hmido);
+ midiStreamClose(hmido);
+
+ return(MPU_Ok);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MPU_Init
+
+ Detects and initializes the MPU401 card.
+---------------------------------------------------------------------*/
+
+int32_t MPU_Init
+(
+ int32_t addr
+)
+
+{
+ int32_t i;
+
+ for (i=0;i
+#include
+#include "music.h"
+#include "midi.h"
+#include "mpu401.h"
+#include "compat.h"
+#include "duke3d.h"
+
+#ifndef TRUE
+#define TRUE ( 1 == 1 )
+#define FALSE ( !TRUE )
+#endif
+
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef max
+# define max(a,b) ( ((a) > (b)) ? (a) : (b) )
+#endif
+
+int32_t MUSIC_SoundDevice = -1;
+int32_t MUSIC_ErrorCode = MUSIC_Ok;
+
+static midifuncs MUSIC_MidiFunctions;
+
+int32_t MUSIC_InitMidi(int32_t card, midifuncs *Funcs, int32_t Address);
+
+#define MUSIC_SetErrorCode( status ) \
+ MUSIC_ErrorCode = ( status );
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_ErrorString
+
+ Returns a pointer to the error message associated with an error
+ number. A -1 returns a pointer the current error.
+---------------------------------------------------------------------*/
+
+char *MUSIC_ErrorString
+(
+ int32_t ErrorNumber
+)
+
+{
+ char *ErrorString;
+
+ switch (ErrorNumber)
+ {
+ case MUSIC_Warning :
+ case MUSIC_Error :
+ ErrorString = MUSIC_ErrorString(MUSIC_ErrorCode);
+ break;
+
+ case MUSIC_Ok :
+ ErrorString = "Music ok.";
+ break;
+
+ case MUSIC_ASSVersion :
+ ErrorString = "Apogee Sound System Version WinMM "
+ "Programmed by Jim Dose, Ported by Jonathon Fowler\n"
+ "(c) Copyright 1996 James R. Dose. All Rights Reserved.\n";
+ break;
+
+ case MUSIC_SoundCardError :
+ case MUSIC_MPU401Error :
+ ErrorString = "Could not detect MPU-401.";
+ break;
+
+ case MUSIC_InvalidCard :
+ ErrorString = "Invalid Music device.";
+ break;
+
+ case MUSIC_MidiError :
+ ErrorString = "Error playing MIDI file.";
+ break;
+
+ case MUSIC_TaskManError :
+ ErrorString = "TaskMan error.";
+ break;
+
+ case MUSIC_DPMI_Error :
+ ErrorString = "DPMI Error in MUSIC.";
+ break;
+
+ default :
+ ErrorString = "Unknown Music error code.";
+ break;
+ }
+
+ return(ErrorString);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_Init
+
+ Selects which sound device to use.
+---------------------------------------------------------------------*/
+
+int32_t MUSIC_Init
+(
+ int32_t SoundCard,
+ int32_t Address
+)
+
+{
+ int32_t i;
+ int32_t status;
+
+ for (i = 0; i < 128; i++)
+ {
+ MIDI_PatchMap[ i ] = i;
+ }
+
+ MUSIC_SoundDevice = SoundCard;
+
+ status = MUSIC_InitMidi(SoundCard, &MUSIC_MidiFunctions, Address);
+
+ return(status);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_Shutdown
+
+ Terminates use of sound device.
+---------------------------------------------------------------------*/
+
+int32_t MUSIC_Shutdown
+(
+ void
+)
+
+{
+ int32_t status;
+
+ status = MUSIC_Ok;
+
+ MIDI_StopSong();
+
+ //MPU_Reset();
+
+ return(status);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_SetVolume
+
+ Sets the volume of music playback.
+---------------------------------------------------------------------*/
+
+void MUSIC_SetVolume
+(
+ int32_t volume
+)
+
+{
+ volume = max(0, volume);
+ volume = min(volume, 255);
+ if (MUSIC_SoundDevice != -1)
+ {
+ MIDI_SetVolume(volume);
+ }
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_SetMidiChannelVolume
+
+ Sets the volume of music playback on the specified MIDI channel.
+---------------------------------------------------------------------*/
+
+void MUSIC_SetMidiChannelVolume
+(
+ int32_t channel,
+ int32_t volume
+)
+
+{
+ MIDI_SetUserChannelVolume(channel, volume);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_ResetMidiChannelVolumes
+
+ Sets the volume of music playback on all MIDI channels to full volume.
+---------------------------------------------------------------------*/
+
+void MUSIC_ResetMidiChannelVolumes
+(
+ void
+)
+
+{
+ MIDI_ResetUserChannelVolume();
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_GetVolume
+
+ Returns the volume of music playback.
+---------------------------------------------------------------------*/
+
+int32_t MUSIC_GetVolume
+(
+ void
+)
+
+{
+ if (MUSIC_SoundDevice == -1)
+ {
+ return(0);
+ }
+ return(MIDI_GetVolume());
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_SetLoopFlag
+
+ Set whether the music will loop or end when it reaches the end of
+ the song.
+---------------------------------------------------------------------*/
+
+void MUSIC_SetLoopFlag
+(
+ int32_t loopflag
+)
+
+{
+ MIDI_SetLoopFlag(loopflag);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_SongPlaying
+
+ Returns whether there is a song playing.
+---------------------------------------------------------------------*/
+
+int32_t MUSIC_SongPlaying
+(
+ void
+)
+
+{
+ return(MIDI_SongPlaying());
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_Continue
+
+ Continues playback of a paused song.
+---------------------------------------------------------------------*/
+
+void MUSIC_Continue
+(
+ void
+)
+
+{
+ MIDI_ContinueSong();
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_Pause
+
+ Pauses playback of a song.
+---------------------------------------------------------------------*/
+
+void MUSIC_Pause
+(
+ void
+)
+
+{
+ MIDI_PauseSong();
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_StopSong
+
+ Stops playback of current song.
+---------------------------------------------------------------------*/
+
+int32_t MUSIC_StopSong
+(
+ void
+)
+
+{
+ MUSIC_StopFade();
+ MIDI_StopSong();
+ MUSIC_SetErrorCode(MUSIC_Ok);
+ return(MUSIC_Ok);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_PlaySong
+
+ Begins playback of MIDI song.
+---------------------------------------------------------------------*/
+
+int32_t MUSIC_PlaySong
+(
+ char *song,
+ int32_t loopflag
+)
+
+{
+ int32_t status;
+
+ {
+ MUSIC_StopSong();
+ status = MIDI_PlaySong(song, loopflag);
+ if (status != MIDI_Ok)
+ {
+ MUSIC_SetErrorCode(MUSIC_MidiError);
+ return(MUSIC_Warning);
+ }
+ }
+
+ return(MUSIC_Ok);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_SetContext
+
+ Sets the song context.
+---------------------------------------------------------------------*/
+
+void MUSIC_SetContext
+(
+ int32_t context
+)
+
+{
+ MIDI_SetContext(context);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_GetContext
+
+ Returns the current song context.
+---------------------------------------------------------------------*/
+
+int32_t MUSIC_GetContext
+(
+ void
+)
+
+{
+ return MIDI_GetContext();
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_SetSongTick
+
+ Sets the position of the song pointer.
+---------------------------------------------------------------------*/
+
+void MUSIC_SetSongTick
+(
+ uint32_t PositionInTicks
+)
+
+{
+ MIDI_SetSongTick(PositionInTicks);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_SetSongTime
+
+ Sets the position of the song pointer.
+---------------------------------------------------------------------*/
+
+void MUSIC_SetSongTime
+(
+ uint32_t milliseconds
+)
+
+{
+ MIDI_SetSongTime(milliseconds);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_SetSongPosition
+
+ Sets the position of the song pointer.
+---------------------------------------------------------------------*/
+
+void MUSIC_SetSongPosition
+(
+ int32_t measure,
+ int32_t beat,
+ int32_t tick
+)
+
+{
+ MIDI_SetSongPosition(measure, beat, tick);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_GetSongPosition
+
+ Returns the position of the song pointer.
+---------------------------------------------------------------------*/
+
+void MUSIC_GetSongPosition
+(
+ songposition *pos
+)
+
+{
+ MIDI_GetSongPosition(pos);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_GetSongLength
+
+ Returns the length of the song.
+---------------------------------------------------------------------*/
+
+void MUSIC_GetSongLength
+(
+ songposition *pos
+)
+
+{
+ MIDI_GetSongLength(pos);
+}
+
+
+int32_t MUSIC_InitMidi
+(
+ int32_t card,
+ midifuncs *Funcs,
+ int32_t Address
+)
+
+{
+ UNREFERENCED_PARAMETER(card);
+ UNREFERENCED_PARAMETER(Address);
+ Funcs->NoteOff = MPU_NoteOff;
+ Funcs->NoteOn = MPU_NoteOn;
+ Funcs->PolyAftertouch = MPU_PolyAftertouch;
+ Funcs->ControlChange = MPU_ControlChange;
+ Funcs->ProgramChange = MPU_ProgramChange;
+ Funcs->ChannelAftertouch = MPU_ChannelAftertouch;
+ Funcs->PitchBend = MPU_PitchBend;
+ Funcs->ReleasePatches = NULL;
+ Funcs->LoadPatch = NULL;
+ Funcs->SetVolume = NULL /*MPU_SetVolume*/;
+ Funcs->GetVolume = NULL /*MPU_GetVolume*/;
+
+ MIDI_SetMidiFuncs(Funcs);
+
+ return(MIDI_Ok);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_FadeVolume
+
+ Fades music volume from current level to another over a specified
+ period of time.
+---------------------------------------------------------------------*/
+
+int32_t MUSIC_FadeVolume
+(
+ int32_t tovolume,
+ int32_t milliseconds
+)
+
+{
+ UNREFERENCED_PARAMETER(milliseconds);
+ MIDI_SetVolume(tovolume);
+ return(MUSIC_Ok);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_FadeActive
+
+ Returns whether the fade routine is active.
+---------------------------------------------------------------------*/
+
+int32_t MUSIC_FadeActive
+(
+ void
+)
+
+{
+ return(0);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_StopFade
+
+ Stops fading the music.
+---------------------------------------------------------------------*/
+
+void MUSIC_StopFade
+(
+ void
+)
+
+{}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_RerouteMidiChannel
+
+ Sets callback function to reroute MIDI commands from specified
+ function.
+---------------------------------------------------------------------*/
+
+void MUSIC_RerouteMidiChannel
+(
+ int32_t channel,
+ int32_t(*function)(int32_t event, int32_t c1, int32_t c2)
+)
+
+{
+ MIDI_RerouteMidiChannel(channel, function);
+}
+
+
+/*---------------------------------------------------------------------
+ Function: MUSIC_RegisterTimbreBank
+
+ Halts playback of all sounds.
+---------------------------------------------------------------------*/
+
+void MUSIC_RegisterTimbreBank
+(
+ char *timbres
+)
+
+{
+ UNREFERENCED_PARAMETER(timbres);
+}
+
+
+void MUSIC_Update(void)
+{
+ MIDI_UpdateMusic();
+}
+
diff --git a/polymer/eduke32/source/sounds.c b/polymer/eduke32/source/sounds.c
index d32c3d8b1..a7be0e0d6 100644
--- a/polymer/eduke32/source/sounds.c
+++ b/polymer/eduke32/source/sounds.c
@@ -39,7 +39,7 @@ int32_t backflag,g_numEnvSoundsPlaying,g_maxSoundPos = 0;
#define MUSIC_ID -65536
static int32_t MusicIsWaveform = 0;
-static uint8_t * MusicPtr = 0;
+static char * MusicPtr = 0;
static int32_t MusicLen = 0;
static int32_t MusicVoice = -1;
static int32_t MusicPaused = 0;
@@ -156,9 +156,9 @@ void S_MusicStartup(void)
{
MUSIC_SetVolume(ud.config.MusicVolume);
}
- /*
+
initprintf("Couldn't find selected sound card, or, error w/ sound card itself.\n");
-
+/*
S_SoundShutdown();
uninittimer();
uninitengine();
@@ -343,11 +343,11 @@ int32_t S_PlayMusic(const char *fn, const int32_t sel)
S_StopMusic();
MusicLen = kfilelength(fp);
- MusicPtr = (uint8_t *) Bmalloc(MusicLen);
+ MusicPtr = (char *) Bmalloc(MusicLen);
kread(fp, MusicPtr, MusicLen);
kclose(fp);
- if (!memcmp(MusicPtr, "MThd", 4))
+ if (!Bmemcmp(MusicPtr, "MThd", 4))
{
MUSIC_PlaySong(MusicPtr, MUSIC_LoopSong);
MusicIsWaveform = 0;
@@ -369,10 +369,8 @@ void S_StopMusic(void)
FX_StopSound(MusicVoice);
MusicVoice = -1;
}
- else if (!MusicIsWaveform)
- {
- MUSIC_StopSong();
- }
+
+ MUSIC_StopSong();
if (MusicPtr)
{
diff --git a/polymer/eduke32/source/standard.h b/polymer/eduke32/source/standard.h
new file mode 100644
index 000000000..952648cb6
--- /dev/null
+++ b/polymer/eduke32/source/standard.h
@@ -0,0 +1,73 @@
+/*
+Copyright (C) 1994-1995 Apogee Software, Ltd.
+
+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.
+
+Modifications for JonoF's port by Jonathon Fowler (jonof@edgenetwk.com)
+*/
+/**********************************************************************
+ module: STANDARD.H
+
+ author: James R. Dose
+ date: May 25, 1994
+
+ Header containing standard definitions.
+
+ (c) Copyright 1994 James R. Dose. All Rights Reserved.
+**********************************************************************/
+
+#ifndef __STANDARD_H
+#define __STANDARD_H
+
+typedef int boolean;
+typedef int errorcode;
+
+#ifndef TRUE
+ #define TRUE ( 1 == 1 )
+ #define FALSE ( !TRUE )
+#endif
+
+enum STANDARD_ERRORS
+ {
+ Warning = -2,
+ FatalError = -1,
+ Success = 0
+ };
+
+#define BITSET( data, bit ) \
+ ( ( ( data ) & ( bit ) ) == ( bit ) )
+
+#define ARRAY_LENGTH( array ) \
+ ( sizeof( array ) / sizeof( ( array )[ 0 ] ) )
+
+#define WITHIN_BOUNDS( array, index ) \
+ ( ( 0 <= ( index ) ) && ( ( index ) < ARRAY_LENGTH( array ) ) )
+
+#define FOREVER for( ; ; )
+
+#ifdef NDEBUG
+ #define DEBUGGING 0
+#else
+ #define DEBUGGING 1
+#endif
+
+#define DEBUG_CODE \
+ if ( DEBUGGING == 0 ) \
+ { \
+ } \
+ else
+
+#endif