From 505d3475ceae5575a39eb2ad6f278f94ba6d4934 Mon Sep 17 00:00:00 2001 From: terminx Date: Mon, 27 Jul 2009 10:46:42 +0000 Subject: [PATCH] Hack MIDI back in for win32 MSVC still broken git-svn-id: https://svn.eduke32.com/eduke32@1472 1a8010ca-5511-0410-912e-c29ae57300e0 --- polymer/eduke32/Makefile | 20 +- polymer/eduke32/Makefile.deps | 6 +- polymer/eduke32/eduke32.vcproj | 12 + polymer/eduke32/source/_midi.h | 282 +++ polymer/eduke32/source/game.c | 5 + .../eduke32/source/jaudiolib/include/music.h | 185 +- .../eduke32/source/jaudiolib/src/_multivc.h | 17 - polymer/eduke32/source/jaudiolib/src/fx_man.c | 1 + .../eduke32/source/jaudiolib/src/multivoc.c | 22 +- polymer/eduke32/source/jaudiolib/src/vorbis.c | 2 +- polymer/eduke32/source/midi.c | 2069 +++++++++++++++++ polymer/eduke32/source/midi.h | 100 + polymer/eduke32/source/mpu401.c | 495 ++++ polymer/eduke32/source/mpu401.h | 68 + polymer/eduke32/source/music.c | 595 +++++ polymer/eduke32/source/sounds.c | 16 +- polymer/eduke32/source/standard.h | 73 + 17 files changed, 3832 insertions(+), 136 deletions(-) create mode 100644 polymer/eduke32/source/_midi.h create mode 100644 polymer/eduke32/source/midi.c create mode 100644 polymer/eduke32/source/midi.h create mode 100644 polymer/eduke32/source/mpu401.c create mode 100644 polymer/eduke32/source/mpu401.h create mode 100644 polymer/eduke32/source/music.c create mode 100644 polymer/eduke32/source/standard.h 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