diff --git a/polymer/eduke32/source/_midi.h b/polymer/eduke32/source/_midi.h index d7ead6b36..164d1be21 100644 --- a/polymer/eduke32/source/_midi.h +++ b/polymer/eduke32/source/_midi.h @@ -1,12 +1,10 @@ -//------------------------------------------------------------------------- /* -Copyright (C) 2016 EDuke32 developers and contributors +Copyright (C) 1994-1995 Apogee Software, Ltd. -This file is part of EDuke32. - -EDuke32 is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. +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 @@ -17,14 +15,27 @@ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au) + */ -//------------------------------------------------------------------------- +/********************************************************************** + 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)) +#define RELATIVE_BEAT( measure, beat, tick ) \ + ( ( tick ) + ( ( beat ) << 9 ) + ( ( measure ) << 16 ) ) //Bobby Prince thinks this may be 100 //#define GENMIDI_DefaultVolume 100 @@ -69,12 +80,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #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_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 GET_MIDI_CHANNEL( event ) ( ( event ) & 0xf ) +#define GET_MIDI_COMMAND( event ) ( ( event ) >> 4 ) #define EMIDI_INFINITE -1 #define EMIDI_END_LOOP_VALUE 127 @@ -92,54 +103,180 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define EMIDI_GeneralMIDI 0 -#define EMIDI_AffectsCurrentCard(c, type) (((c) == EMIDI_ALL_CARDS) || ((c) == (type))) +#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; + { + 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; + { + char *start; + char *pos; - int32_t delay; - int16_t active; - int16_t RunningStatus; + int32_t delay; + int16_t active; + int16_t RunningStatus; - int16_t currentcontext; - songcontext context[EMIDI_NUM_CONTEXTS]; + int16_t currentcontext; + songcontext context[ EMIDI_NUM_CONTEXTS ]; - char EMIDI_IncludeTrack; - char EMIDI_ProgramChange; - char EMIDI_VolumeChange; -} track; + 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_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 void _MIDI_InitEMIDI( void ); +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/jaudiolib/include/music.h b/polymer/eduke32/source/jaudiolib/include/music.h index 219b7ee54..8671185c1 100644 --- a/polymer/eduke32/source/jaudiolib/include/music.h +++ b/polymer/eduke32/source/jaudiolib/include/music.h @@ -1,12 +1,10 @@ -//------------------------------------------------------------------------- /* -Copyright (C) 2016 EDuke32 developers and contributors +Copyright (C) 1994-1995 Apogee Software, Ltd. -This file is part of EDuke32. - -EDuke32 is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. +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 @@ -17,8 +15,19 @@ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au) */ -//------------------------------------------------------------------------- +/********************************************************************** + 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 @@ -28,24 +37,56 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. extern int32_t MUSIC_ErrorCode; enum MUSIC_ERRORS -{ - MUSIC_Warning = -2, - MUSIC_Error = -1, - MUSIC_Ok = 0, - MUSIC_MidiError, -}; + { + 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 ) -const char *MUSIC_ErrorString(int32_t ErrorNumber); -int32_t MUSIC_Init(int32_t SoundCard); -int32_t MUSIC_Shutdown(void); -void MUSIC_SetVolume(int32_t volume); -void MUSIC_Continue(void); -void MUSIC_Pause(void); -int32_t MUSIC_StopSong(void); -int32_t MUSIC_PlaySong(char *song, int32_t loopflag); -void MUSIC_Update(void); +const 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, int32_t, int32_t ) ); +void MUSIC_RegisterTimbreBank( char *timbres ); +void MUSIC_Update(void); #endif diff --git a/polymer/eduke32/source/midi.c b/polymer/eduke32/source/midi.c index afaaea966..06a5f00fa 100644 --- a/polymer/eduke32/source/midi.c +++ b/polymer/eduke32/source/midi.c @@ -1,6 +1,6 @@ //------------------------------------------------------------------------- /* -Copyright (C) 2016 EDuke32 developers and contributors +Copyright (C) 2010 EDuke32 developers and contributors This file is part of EDuke32. @@ -20,6 +20,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //------------------------------------------------------------------------- +/********************************************************************** + 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" @@ -40,6 +51,8 @@ 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, int32_t, int32_t); + static track *_MIDI_TrackPtr = NULL; static int32_t _MIDI_TrackMemSize; static int32_t _MIDI_NumTracks; @@ -71,6 +84,11 @@ 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; @@ -94,22 +112,31 @@ char MIDI_PatchMap[ 128 ]; Reads a variable length number from a MIDI track. ---------------------------------------------------------------------*/ -static int32_t _MIDI_ReadNumber(void *from, size_t size) +static int32_t _MIDI_ReadNumber +( + void *from, + size_t size +) + { + char *FromPtr; + int32_t value; + if (size > 4) + { size = 4; + } - char *FromPtr = (char *)from; + FromPtr = (char *)from; - int32_t value = 0; - - do + value = 0; + while (size--) { value <<= 8; value += *FromPtr++; - } while (size--); + } - return value; + return(value); } @@ -119,17 +146,20 @@ static int32_t _MIDI_ReadNumber(void *from, size_t size) Reads a variable length encoded delta delay time from the MIDI data. ---------------------------------------------------------------------*/ -static int32_t _MIDI_ReadDelta(track *ptr) +static int32_t _MIDI_ReadDelta +( + track *ptr +) + { int32_t value; + char c; GET_NEXT_EVENT(ptr, value); if (value & 0x80) { value &= 0x7f; - - char c; do { GET_NEXT_EVENT(ptr, c); @@ -138,7 +168,7 @@ static int32_t _MIDI_ReadDelta(track *ptr) while (c & 0x80); } - return value; + return(value); } @@ -148,8 +178,15 @@ static int32_t _MIDI_ReadDelta(track *ptr) Sets the track pointers to the beginning of the song. ---------------------------------------------------------------------*/ -static void _MIDI_ResetTracks(void) +static void _MIDI_ResetTracks +( + void +) + { + int32_t i; + track *ptr; + _MIDI_Tick = 0; _MIDI_Beat = 1; _MIDI_Measure = 1; @@ -163,9 +200,8 @@ static void _MIDI_ResetTracks(void) _MIDI_ActiveTracks = 0; _MIDI_Context = 0; - track *ptr = _MIDI_TrackPtr; - - for (int i = 0; i < _MIDI_NumTracks; i++) + ptr = _MIDI_TrackPtr; + for (i = 0; i < _MIDI_NumTracks; i++) { ptr->pos = ptr->start; ptr->delay = _MIDI_ReadDelta(ptr); @@ -176,7 +212,9 @@ static void _MIDI_ResetTracks(void) ptr->context[ 0 ].loopcount = 0; if (ptr->active) + { _MIDI_ActiveTracks++; + } ptr++; } @@ -189,17 +227,21 @@ static void _MIDI_ResetTracks(void) Increment tick counters. ---------------------------------------------------------------------*/ -static void _MIDI_AdvanceTick(void) +static void _MIDI_AdvanceTick +( + void +) + { _MIDI_PositionInTicks++; _MIDI_Time += _MIDI_FPSecondsPerTick; - while (++_MIDI_Tick > _MIDI_TicksPerBeat) + _MIDI_Tick++; + while (_MIDI_Tick > _MIDI_TicksPerBeat) { _MIDI_Tick -= _MIDI_TicksPerBeat; _MIDI_Beat++; } - while (_MIDI_Beat > _MIDI_BeatsPerMeasure) { _MIDI_Beat -= _MIDI_BeatsPerMeasure; @@ -214,9 +256,15 @@ static void _MIDI_AdvanceTick(void) Interpret SysEx Event. ---------------------------------------------------------------------*/ -static void _MIDI_SysEx(track *Track) +static void _MIDI_SysEx +( + track *Track +) + { - int32_t const length = _MIDI_ReadDelta(Track); + int32_t length; + + length = _MIDI_ReadDelta(Track); Track->pos += length; } @@ -227,10 +275,16 @@ static void _MIDI_SysEx(track *Track) Interpret Meta Event. ---------------------------------------------------------------------*/ -static void _MIDI_MetaEvent(track *Track) +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); @@ -244,22 +298,22 @@ static void _MIDI_MetaEvent(track *Track) break; case MIDI_TEMPO_CHANGE : - MIDI_SetTempo( - tabledivide32_noinline(60000000L, _MIDI_ReadNumber(Track->pos, 3))); + tempo = tabledivide32_noinline(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; - int32_t denominator = (int32_t) *(Track->pos + 1); + _MIDI_BeatsPerMeasure = (int32_t)*Track->pos; + denominator = (int32_t)*(Track->pos + 1); _MIDI_TimeBase = 1; - while (denominator > 0) { _MIDI_TimeBase += _MIDI_TimeBase; @@ -268,7 +322,6 @@ static void _MIDI_MetaEvent(track *Track) _MIDI_TicksPerBeat = tabledivide32_noinline(_MIDI_Division * 4, _MIDI_TimeBase); break; } - } Track->pos += length; } @@ -280,7 +333,15 @@ static void _MIDI_MetaEvent(track *Track) Interprets the MIDI controller info. ---------------------------------------------------------------------*/ -static int32_t _MIDI_InterpretControllerInfo(track *Track, int32_t TimeSet, int32_t channel, int32_t c1, int32_t c2) +static int32_t _MIDI_InterpretControllerInfo +( + track *Track, + int32_t TimeSet, + int32_t channel, + int32_t c1, + int32_t c2 +) + { track *trackptr; int32_t tracknum; @@ -294,7 +355,9 @@ static int32_t _MIDI_InterpretControllerInfo(track *Track, int32_t TimeSet, int3 case MIDI_VOLUME : if (!Track->EMIDI_VolumeChange) + { _MIDI_SetChannelVolume(channel, c2); + } break; case EMIDI_INCLUDE_TRACK : @@ -303,21 +366,28 @@ static int32_t _MIDI_InterpretControllerInfo(track *Track, int32_t TimeSet, int3 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)) + 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; @@ -326,7 +396,9 @@ static int32_t _MIDI_InterpretControllerInfo(track *Track, int32_t TimeSet, int3 Track->RunningStatus = Track->context[ _MIDI_Context ].RunningStatus; if (TimeSet) + { break; + } _MIDI_Time = Track->context[ _MIDI_Context ].time; _MIDI_FPSecondsPerTick = Track->context[ _MIDI_Context ].FPSecondsPerTick; @@ -341,7 +413,14 @@ static int32_t _MIDI_InterpretControllerInfo(track *Track, int32_t TimeSet, int3 case EMIDI_LOOP_START : case EMIDI_SONG_LOOP_START : - loopcount = c2 ? c2 : EMIDI_INFINITE; + if (c2 == 0) + { + loopcount = EMIDI_INFINITE; + } + else + { + loopcount = c2; + } if (c1 == EMIDI_SONG_LOOP_START) { @@ -377,8 +456,12 @@ static int32_t _MIDI_InterpretControllerInfo(track *Track, int32_t TimeSet, int3 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)) + if ((c2 != EMIDI_END_LOOP_VALUE) || + (Track->context[ 0 ].loopstart == NULL) || + (Track->context[ 0 ].loopcount == 0)) + { break; + } if (c1 == EMIDI_SONG_LOOP_END) { @@ -396,15 +479,18 @@ static int32_t _MIDI_InterpretControllerInfo(track *Track, int32_t TimeSet, int3 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) { @@ -426,7 +512,9 @@ static int32_t _MIDI_InterpretControllerInfo(track *Track, int32_t TimeSet, int3 default : if (_MIDI_Funcs->ControlChange) + { _MIDI_Funcs->ControlChange(channel, c1, c2); + } } return TimeSet; @@ -441,18 +529,24 @@ static int32_t _MIDI_InterpretControllerInfo(track *Track, int32_t TimeSet, int3 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) { - int32_t TimeSet = FALSE; - track *Track = _MIDI_TrackPtr; - int32_t tracknum = 0; - + Track = _MIDI_TrackPtr; + tracknum = 0; while (tracknum < _MIDI_NumTracks) { while ((Track->active) && (Track->delay == 0)) { - int32_t event; - GET_NEXT_EVENT(Track, event); if (GET_MIDI_COMMAND(event) == MIDI_SPECIAL) @@ -470,8 +564,9 @@ static int32_t _MIDI_ServiceRoutine(void) } if (Track->active) + { Track->delay = _MIDI_ReadDelta(Track); - + } continue; } @@ -485,35 +580,50 @@ static int32_t _MIDI_ServiceRoutine(void) Track->pos--; } - int32_t channel = GET_MIDI_CHANNEL(event); - int32_t command = GET_MIDI_COMMAND(event); - - int32_t c1 = 0; - int32_t c2 = 0; + 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 : @@ -522,17 +632,23 @@ static int32_t _MIDI_ServiceRoutine(void) 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 : @@ -568,49 +684,242 @@ static int32_t _MIDI_ServiceRoutine(void) return 0; } -static int32_t _MIDI_SendControlChange(int32_t channel, int32_t c1, int32_t c2) + +/*--------------------------------------------------------------------- + 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 +) + { - if (_MIDI_Funcs == NULL || _MIDI_Funcs->ControlChange == NULL) - return MIDI_Error; + 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; + return(MIDI_Ok); } -int32_t MIDI_AllNotesOff(void) + +/*--------------------------------------------------------------------- + Function: MIDI_RerouteMidiChannel + + Sets callback function to reroute MIDI commands from specified + function. +---------------------------------------------------------------------*/ + +void MIDI_RerouteMidiChannel +( + int32_t channel, + int32_t(*function)(int32_t, int32_t, int32_t) +) + { - for (int32_t channel = 0; channel < NUM_MIDI_CHANNELS; channel++) + 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; + return(MIDI_Ok); } -static void _MIDI_SetChannelVolume(int32_t channel, int32_t volume) + +/*--------------------------------------------------------------------- + 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_Funcs == NULL || _MIDI_Funcs->ControlChange == NULL) + if (_MIDI_RerouteFunctions[ channel ] != NULL) + { + remotevolume = volume * _MIDI_TotalVolume; + remotevolume *= _MIDI_UserChannelVolume[ channel ]; + remotevolume = tabledivide32_noinline(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 = tabledivide32_noinline(volume, MIDI_MaxVolume); + } + + // For user volume + volume >>= 8; _MIDI_Funcs->ControlChange(channel, MIDI_VOLUME, volume); } -static void _MIDI_SendChannelVolumes(void) + +/*--------------------------------------------------------------------- + Function: MIDI_SetUserChannelVolume + + Sets the volume of the specified midi channel. +---------------------------------------------------------------------*/ + +void MIDI_SetUserChannelVolume +( + int32_t channel, + int32_t volume +) + { - for (int32_t channel = 0; channel < NUM_MIDI_CHANNELS; channel++) + // 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 ]); + } } -int32_t MIDI_Reset(void) + +/*--------------------------------------------------------------------- + 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 (int32_t channel = 0; channel < NUM_MIDI_CHANNELS; channel++) + 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); @@ -624,7 +933,7 @@ int32_t MIDI_Reset(void) Reset = TRUE; - return MIDI_Ok; + return(MIDI_Ok); } @@ -634,21 +943,139 @@ int32_t MIDI_Reset(void) Sets the total volume of the music. ---------------------------------------------------------------------*/ -int32_t MIDI_SetVolume(int32_t volume) -{ - if (_MIDI_Funcs == NULL) - return MIDI_NullMidiModule; +int32_t MIDI_SetVolume +( + int32_t volume +) - volume = clamp(volume, 0, MIDI_MaxVolume); +{ + int32_t i; + + if (_MIDI_Funcs == NULL) + { + return(MIDI_NullMidiModule); + } + + volume = min(MIDI_MaxVolume, volume); + volume = max(0, volume); _MIDI_TotalVolume = volume; - _MIDI_SendChannelVolumes(); + if (_MIDI_Funcs->SetVolume) + { + _MIDI_Funcs->SetVolume(volume); - return MIDI_Ok; + 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); } -void MIDI_ContinueSong(void) + +/*--------------------------------------------------------------------- + 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) { @@ -657,7 +1084,18 @@ void MIDI_ContinueSong(void) } } -void MIDI_PauseSong(void) + +/*--------------------------------------------------------------------- + Function: MIDI_PauseSong + + Pauses playback of the current song. +---------------------------------------------------------------------*/ + +void MIDI_PauseSong +( + void +) + { if (_MIDI_SongLoaded) { @@ -667,15 +1105,50 @@ void MIDI_PauseSong(void) } } + +/*--------------------------------------------------------------------- + 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; } +void MIDI_SetMidiFuncs +( + midifuncs *funcs +) + +{ + _MIDI_Funcs = funcs; +} + + +/*--------------------------------------------------------------------- + Function: MIDI_StopSong + + Stops playback of the currently playing song. +---------------------------------------------------------------------*/ + +void MIDI_StopSong +( + void +) -void MIDI_StopSong(void) { if (_MIDI_SongLoaded) { @@ -685,6 +1158,11 @@ void MIDI_StopSong(void) MIDI_Reset(); _MIDI_ResetTracks(); + if (_MIDI_Funcs->ReleasePatches) + { + _MIDI_Funcs->ReleasePatches(); + } + DO_FREE_AND_NULL(_MIDI_TrackPtr); _MIDI_NumTracks = 0; @@ -699,89 +1177,145 @@ void MIDI_StopSong(void) } } -int32_t MIDI_PlaySong(char *song, int32_t loopflag) + +/*--------------------------------------------------------------------- + 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; + { + return(MIDI_NullMidiModule); + } if (B_UNBUF32(song) != MIDI_HEADER_SIGNATURE) - return MIDI_InvalidMidiFile; + { + return(MIDI_InvalidMidiFile); + } - song += sizeof(int32_t); + song += 4; - int headersize = _MIDI_ReadNumber(song, sizeof(int32_t)); - song += sizeof(int32_t); - int format = _MIDI_ReadNumber(song, sizeof(int16_t)); - _MIDI_NumTracks = _MIDI_ReadNumber(song + sizeof(int16_t), sizeof(int16_t)); - _MIDI_Division = _MIDI_ReadNumber(song + sizeof(int16_t) + sizeof(int16_t), sizeof(int16_t)); - - // If a SMPTE time division is given, just set to 96 so no errors occur + 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; + { + return(MIDI_UnknownMidiFormat); + } - char *ptr = song + headersize; + ptr = song + headersize; if (_MIDI_NumTracks == 0) - return MIDI_NoTracks; + { + return(MIDI_NoTracks); + } _MIDI_TrackMemSize = _MIDI_NumTracks * sizeof(track); _MIDI_TrackPtr = (track *)Xmalloc(_MIDI_TrackMemSize); - track *CurrentTrack = _MIDI_TrackPtr; - int numtracks = _MIDI_NumTracks-1; - - do + CurrentTrack = _MIDI_TrackPtr; + numtracks = _MIDI_NumTracks; + while (numtracks--) { if (B_UNBUF32(ptr) != MIDI_TRACK_SIGNATURE) { DO_FREE_AND_NULL(_MIDI_TrackPtr); + _MIDI_TrackMemSize = 0; - return MIDI_InvalidTrack; + return(MIDI_InvalidTrack); } - int tracklength = _MIDI_ReadNumber(ptr + sizeof(int32_t), sizeof(int32_t)); - ptr += sizeof(int32_t) + sizeof(int32_t); + tracklength = _MIDI_ReadNumber(ptr + 4, 4); + ptr += 8; CurrentTrack->start = ptr; ptr += tracklength; CurrentTrack++; } - while (numtracks--); + + 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; + return(MIDI_Ok); } -void MIDI_SetTempo(int32_t tempo) + +/*--------------------------------------------------------------------- + Function: MIDI_SetTempo + + Sets the song tempo. +---------------------------------------------------------------------*/ + +void MIDI_SetTempo +( + int32_t tempo +) + { + int32_t tickspersecond; + MIDI_Tempo = tempo; - _MIDI_FPSecondsPerTick = tabledivide32_noinline(1 << TIME_PRECISION, ((tempo * _MIDI_Division) / 60)); + tickspersecond = ((tempo) * _MIDI_Division)/60; + _MIDI_FPSecondsPerTick = tabledivide32_noinline(1 << TIME_PRECISION, tickspersecond); MPU_SetTempo(tempo); } @@ -790,9 +1324,403 @@ void MIDI_SetDivision(int32_t division) MPU_SetDivision(division); } -static void _MIDI_InitEMIDI(void) + +/*--------------------------------------------------------------------- + Function: MIDI_GetTempo + + Returns the song tempo. +---------------------------------------------------------------------*/ + +int32_t MIDI_GetTempo +( + void +) + { - int32_t const type = EMIDI_GeneralMIDI; + 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 = tabledivide32_noinline((milliseconds % 1000) << TIME_PRECISION, 1000); + sec = tabledivide32_noinline(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(); @@ -801,8 +1729,8 @@ static void _MIDI_InitEMIDI(void) _MIDI_TotalBeats = 0; _MIDI_TotalMeasures = 0; - track *Track = _MIDI_TrackPtr; - int32_t tracknum = 0; + Track = _MIDI_TrackPtr; + tracknum = 0; while ((tracknum < _MIDI_NumTracks) && (Track != NULL)) { _MIDI_Tick = 0; @@ -832,11 +1760,9 @@ static void _MIDI_InitEMIDI(void) Track->delay--; } - int IncludeFound = FALSE; + IncludeFound = FALSE; while (Track->active) { - int32_t event; - GET_NEXT_EVENT(Track, event); if (GET_MIDI_COMMAND(event) == MIDI_SPECIAL) @@ -867,33 +1793,42 @@ static void _MIDI_InitEMIDI(void) } if (event & MIDI_RUNNING_STATUS) + { Track->RunningStatus = event; + } else { event = Track->RunningStatus; Track->pos--; } - int32_t const command = GET_MIDI_COMMAND(event); - int32_t length = _MIDI_CommandLengths[ command ]; +// 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++; - - int32_t c1, c2; - + } GET_NEXT_EVENT(Track, c1); GET_NEXT_EVENT(Track, c2); - length -= 2; switch (c1) { case EMIDI_LOOP_START : case EMIDI_SONG_LOOP_START : - Track->context[ 0 ].loopcount = c2 ? c2 : EMIDI_INFINITE; + 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; @@ -985,9 +1920,9 @@ static void _MIDI_InitEMIDI(void) } _MIDI_TotalTime = max(_MIDI_TotalTime, _MIDI_Time); - if (RELATIVE_BEAT(_MIDI_Measure, _MIDI_Beat, _MIDI_Tick) > - RELATIVE_BEAT(_MIDI_TotalMeasures, _MIDI_TotalBeats, _MIDI_TotalTicks)) + RELATIVE_BEAT(_MIDI_TotalMeasures, _MIDI_TotalBeats, + _MIDI_TotalTicks)) { _MIDI_TotalTicks = _MIDI_Tick; _MIDI_TotalBeats = _MIDI_Beat; @@ -1002,6 +1937,118 @@ static void _MIDI_InitEMIDI(void) } +/*--------------------------------------------------------------------- + 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; diff --git a/polymer/eduke32/source/midi.h b/polymer/eduke32/source/midi.h index 0f7a83430..68002098b 100644 --- a/polymer/eduke32/source/midi.h +++ b/polymer/eduke32/source/midi.h @@ -1,12 +1,10 @@ -//------------------------------------------------------------------------- /* -Copyright (C) 2016 EDuke32 developers and contributors +Copyright (C) 1994-1995 Apogee Software, Ltd. -This file is part of EDuke32. - -EDuke32 is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. +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 @@ -17,22 +15,36 @@ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au) */ -//------------------------------------------------------------------------- +/********************************************************************** + 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_Error = -1, - MIDI_Ok = 0, - MIDI_NullMidiModule, - MIDI_InvalidMidiFile, - MIDI_UnknownMidiFormat, - MIDI_NoTracks, - MIDI_InvalidTrack, -}; + { + 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 @@ -43,26 +55,46 @@ enum MIDI_Errors extern char MIDI_PatchMap[ 128 ]; typedef struct -{ - void(*NoteOff)(char channel, char key, char velocity); - void(*NoteOn)(char channel, char key, char velocity); - void(*PolyAftertouch)(char channel, char key, char pressure); - void(*ControlChange)(char channel, char number, char value); - void(*ProgramChange)(char channel, char program); - void(*ChannelAftertouch)(char channel, char pressure); - void(*PitchBend)(char channel, char lsb, char msb); -} midifuncs; + { + 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; -int32_t MIDI_AllNotesOff(void); -int32_t MIDI_Reset(void); -int32_t MIDI_SetVolume(int32_t volume); -void MIDI_SetMidiFuncs(midifuncs *funcs); -void MIDI_ContinueSong(void); -void MIDI_PauseSong(void); -void MIDI_StopSong(void); -int32_t MIDI_PlaySong(char *song, int32_t loopflag); -void MIDI_SetTempo(int32_t tempo); -void MIDI_UpdateMusic(void); -void MIDI_SetDivision(int32_t division); +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 index e3584a204..d62e1978f 100644 --- a/polymer/eduke32/source/mpu401.c +++ b/polymer/eduke32/source/mpu401.c @@ -1,6 +1,6 @@ //------------------------------------------------------------------------- /* -Copyright (C) 2016 EDuke32 developers and contributors +Copyright (C) 2010 EDuke32 developers and contributors This file is part of EDuke32. @@ -20,6 +20,18 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //------------------------------------------------------------------------- +/********************************************************************** + 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" #include "pragmas.h" @@ -32,6 +44,13 @@ 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) @@ -39,11 +58,11 @@ static DWORD mididevice = -1; static char eventbuf[NUMBUFFERS][BUFFERLEN]; static int32_t eventcnt[NUMBUFFERS]; static MIDIHDR bufferheaders[NUMBUFFERS]; -static int32_t _MPU_CurrentBuffer = 0; +int32_t _MPU_CurrentBuffer = 0; int32_t _MPU_BuffersWaiting = 0; extern uint32_t _MIDI_GlobalPositionInTicks; -static uint32_t _MPU_LastEvent=0; +uint32_t _MPU_LastEvent=0; #define MIDI_NOTE_OFF 0x80 #define MIDI_NOTE_ON 0x90 @@ -58,6 +77,14 @@ static uint32_t _MPU_LastEvent=0; #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; @@ -90,6 +117,8 @@ void MPU_Unpause(void) void CALLBACK MPU_MIDICallback(HMIDIOUT handle, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { + int32_t i; + UNREFERENCED_PARAMETER(dwInstance); UNREFERENCED_PARAMETER(dwParam2); @@ -97,7 +126,7 @@ void CALLBACK MPU_MIDICallback(HMIDIOUT handle, UINT uMsg, DWORD_PTR dwInstance, { case MOM_DONE: midiOutUnprepareHeader((HMIDIOUT)handle, (MIDIHDR *)dwParam1, sizeof(MIDIHDR)); - for (int i=0; i BUFFERLEN) { // buffer over-full - int32_t nextbuffer = MPU_GetNextBuffer(); + nextbuffer = MPU_GetNextBuffer(); if (nextbuffer < 0) { // printf("All buffers full!\n"); @@ -143,7 +181,7 @@ void MPU_SendMidi(char *data, int32_t count) _MPU_CurrentBuffer = nextbuffer; } - char *p = eventbuf[_MPU_CurrentBuffer] + eventcnt[_MPU_CurrentBuffer]; + 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]); @@ -151,11 +189,11 @@ void MPU_SendMidi(char *data, int32_t count) } else { - int32_t padded = PAD(count); + padded = PAD(count); if (eventcnt[_MPU_CurrentBuffer] + 12 + padded > BUFFERLEN) { // buffer over-full - int32_t nextbuffer = MPU_GetNextBuffer(); + nextbuffer = MPU_GetNextBuffer(); if (nextbuffer < 0) { // printf("All buffers full!\n"); @@ -165,7 +203,7 @@ void MPU_SendMidi(char *data, int32_t count) _MPU_CurrentBuffer = nextbuffer; } - char *p = eventbuf[_MPU_CurrentBuffer] + eventcnt[_MPU_CurrentBuffer]; + 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); @@ -178,69 +216,228 @@ void MPU_SendMidi(char *data, int32_t count) _MPU_LastEvent = _MIDI_GlobalPositionInTicks; } -int32_t MPU_Reset(void) + +/*--------------------------------------------------------------------- + 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; + return(MPU_Ok); } -int32_t MPU_Init(int32_t addr) + +/*--------------------------------------------------------------------- + Function: MPU_Init + + Detects and initializes the MPU401 card. +---------------------------------------------------------------------*/ + +int32_t MPU_Init +( + int32_t addr +) + { - for (int i=0; i #include #include "music.h" @@ -27,16 +38,41 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mpu401.h" #include "compat.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(midifuncs *Funcs); +int32_t MUSIC_InitMidi(int32_t card, midifuncs *Funcs, int32_t Address); -#define MUSIC_SetErrorCode(status) MUSIC_ErrorCode = (status); +#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. +---------------------------------------------------------------------*/ + +const char *MUSIC_ErrorString +( + int32_t ErrorNumber +) -const char *MUSIC_ErrorString(int32_t ErrorNumber) { const char *ErrorString; @@ -51,10 +87,33 @@ const char *MUSIC_ErrorString(int32_t ErrorNumber) 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; @@ -63,57 +122,371 @@ const char *MUSIC_ErrorString(int32_t ErrorNumber) return(ErrorString); } -int32_t MUSIC_Init(int32_t SoundCard) + +/*--------------------------------------------------------------------- + Function: MUSIC_Init + + Selects which sound device to use. +---------------------------------------------------------------------*/ + +int32_t MUSIC_Init +( + int32_t SoundCard, + int32_t Address +) + { - for (int i = 0; i < 128; i++) + int32_t i; + int32_t status; + + for (i = 0; i < 128; i++) + { MIDI_PatchMap[ i ] = i; + } MUSIC_SoundDevice = SoundCard; - return MUSIC_InitMidi(&MUSIC_MidiFunctions); + status = MUSIC_InitMidi(SoundCard, &MUSIC_MidiFunctions, Address); + + return(status); } -int32_t MUSIC_Shutdown(void) + +/*--------------------------------------------------------------------- + Function: MUSIC_Shutdown + + Terminates use of sound device. +---------------------------------------------------------------------*/ + +int32_t MUSIC_Shutdown +( + void +) + { + int32_t status; + + status = MUSIC_Ok; + MIDI_StopSong(); - return MUSIC_Ok; + //MPU_Reset(); + + return(status); } -void MUSIC_SetVolume(int32_t volume) -{ - volume = clamp(volume, 0, 255); +/*--------------------------------------------------------------------- + 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); + } } -void MUSIC_Continue(void) { MIDI_ContinueSong(); } -void MUSIC_Pause(void) { MIDI_PauseSong(); } +/*--------------------------------------------------------------------- + Function: MUSIC_SetMidiChannelVolume + + Sets the volume of music playback on the specified MIDI channel. +---------------------------------------------------------------------*/ + +void MUSIC_SetMidiChannelVolume +( + int32_t channel, + int32_t volume +) -int32_t MUSIC_StopSong(void) { + 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; + return(MUSIC_Ok); } -int32_t MUSIC_PlaySong(char *song, int32_t loopflag) -{ - MUSIC_StopSong(); - if (MIDI_PlaySong(song, loopflag) != MIDI_Ok) +/*--------------------------------------------------------------------- + Function: MUSIC_PlaySong + + Begins playback of MIDI song. +---------------------------------------------------------------------*/ + +int32_t MUSIC_PlaySong +( + char *song, + int32_t loopflag +) + +{ + int32_t status; + { - MUSIC_SetErrorCode(MUSIC_MidiError); - return MUSIC_Warning; + MUSIC_StopSong(); + status = MIDI_PlaySong(song, loopflag); + if (status != MIDI_Ok) + { + MUSIC_SetErrorCode(MUSIC_MidiError); + return(MUSIC_Warning); + } } - return MUSIC_Ok; + return(MUSIC_Ok); } -int32_t MUSIC_InitMidi(midifuncs *Funcs) + +/*--------------------------------------------------------------------- + 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; @@ -121,12 +494,101 @@ int32_t MUSIC_InitMidi(midifuncs *Funcs) 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; + 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, int32_t, int32_t) +) + +{ + 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/sdlmusic.c b/polymer/eduke32/source/sdlmusic.c index a9431be58..faa66fc30 100644 --- a/polymer/eduke32/source/sdlmusic.c +++ b/polymer/eduke32/source/sdlmusic.c @@ -64,10 +64,12 @@ static int32_t external_midi = 0; int32_t MUSIC_ErrorCode = MUSIC_Ok; +static char warningMessage[80]; static char errorMessage[80]; static int32_t music_initialized = 0; static int32_t music_context = 0; +static int32_t music_loopflag = MUSIC_PlayOnce; static Mix_Music *music_musicchunk = NULL; static void setErrorMessage(const char *msg) @@ -81,45 +83,70 @@ const char *MUSIC_ErrorString(int32_t ErrorNumber) { switch (ErrorNumber) { + case MUSIC_Warning: + return(warningMessage); + case MUSIC_Error: - return errorMessage; + return(errorMessage); case MUSIC_Ok: - return "OK; no error."; + return("OK; no error."); + + case MUSIC_ASSVersion: + return("Incorrect sound library version."); + + case MUSIC_SoundCardError: + return("General sound card error."); + + case MUSIC_InvalidCard: + return("Invalid sound card."); case MUSIC_MidiError: - return "MIDI error."; + return("MIDI error."); + + case MUSIC_MPU401Error: + return("MPU401 error."); + + case MUSIC_TaskManError: + return("Task Manager error."); + + //case MUSIC_FMNotDetected: + // return("FM not detected error."); + + case MUSIC_DPMI_Error: + return("DPMI error."); default: - return "Unknown error."; + return("Unknown error."); } // switch - return NULL; + return(NULL); } // MUSIC_ErrorString -int32_t MUSIC_Init(int32_t SoundCard) +int32_t MUSIC_Init(int32_t SoundCard, int32_t Address) { #ifdef __ANDROID__ music_initialized = 1; - return MUSIC_Ok; + return(MUSIC_Ok); #endif // Use an external MIDI player if the user has specified to do so char *command = getenv("EDUKE32_MUSIC_CMD"); const SDL_version *linked = Mix_Linked_Version(); UNREFERENCED_PARAMETER(SoundCard); + UNREFERENCED_PARAMETER(Address); if (music_initialized) { setErrorMessage("Music system is already initialized."); - return MUSIC_Error; + return(MUSIC_Error); } // if if (SDL_VERSIONNUM(linked->major,linked->minor,linked->patch) < MIX_REQUIREDVERSION) { // reject running with SDL_Mixer versions older than what is stated in sdl_inc.h initprintf("You need at least v%d.%d.%d of SDL_mixer for music\n",SDL_MIXER_MIN_X,SDL_MIXER_MIN_Y,SDL_MIXER_MIN_Z); - return MUSIC_Error; + return(MUSIC_Error); } external_midi = (command != NULL && command[0] != 0); @@ -205,35 +232,38 @@ int32_t MUSIC_Init(int32_t SoundCard) # endif #endif music_initialized = 1; - return MUSIC_Ok; + return(MUSIC_Ok); fallback: initprintf("Error setting music command, falling back to timidity.\n"); } - static const char *s[] = { "/etc/timidity.cfg", "/etc/timidity/timidity.cfg", "/etc/timidity/freepats.cfg" }; - FILE *fp; - - for (int i = ARRAY_SIZE(s)-1; i>=0; i--) { - fp = Bfopen(s[i], "r"); - if (fp == NULL) + static const char *s[] = { "/etc/timidity.cfg", "/etc/timidity/timidity.cfg", "/etc/timidity/freepats.cfg" }; + FILE *fp; + int32_t i; + + for (i = ARRAY_SIZE(s)-1; i>=0; i--) { - if (i == 0) + fp = Bfopen(s[i], "r"); + if (fp == NULL) { - initprintf("Error: couldn't open any of the following files:\n"); - for (i = ARRAY_SIZE(s)-1; i>=0; i--) - initprintf("%s\n",s[i]); - return MUSIC_Error; + if (i == 0) + { + initprintf("Error: couldn't open any of the following files:\n"); + for (i = ARRAY_SIZE(s)-1; i>=0; i--) + initprintf("%s\n",s[i]); + return(MUSIC_Error); + } + continue; } - continue; + else break; } - else break; + Bfclose(fp); } - Bfclose(fp); music_initialized = 1; - return MUSIC_Ok; + return(MUSIC_Ok); } // MUSIC_Init @@ -248,11 +278,18 @@ int32_t MUSIC_Shutdown(void) MUSIC_StopSong(); music_context = 0; music_initialized = 0; + music_loopflag = MUSIC_PlayOnce; - return MUSIC_Ok; + return(MUSIC_Ok); } // MUSIC_Shutdown +void MUSIC_SetMaxFMMidiChannel(int32_t channel) +{ + UNREFERENCED_PARAMETER(channel); +} // MUSIC_SetMaxFMMidiChannel + + void MUSIC_SetVolume(int32_t volume) { volume = max(0, volume); @@ -262,6 +299,36 @@ void MUSIC_SetVolume(int32_t volume) } // MUSIC_SetVolume +void MUSIC_SetMidiChannelVolume(int32_t channel, int32_t volume) +{ + UNREFERENCED_PARAMETER(channel); + UNREFERENCED_PARAMETER(volume); +} // MUSIC_SetMidiChannelVolume + + +void MUSIC_ResetMidiChannelVolumes(void) +{ +} // MUSIC_ResetMidiChannelVolumes + + +int32_t MUSIC_GetVolume(void) +{ + return(Mix_VolumeMusic(-1) << 1); // convert 0-128 to 0-255. +} // MUSIC_GetVolume + + +void MUSIC_SetLoopFlag(int32_t loopflag) +{ + music_loopflag = loopflag; +} // MUSIC_SetLoopFlag + + +int32_t MUSIC_SongPlaying(void) +{ + return((Mix_PlayingMusic()) ? TRUE : FALSE); +} // MUSIC_SongPlaying + + void MUSIC_Continue(void) { if (Mix_PausedMusic()) @@ -311,7 +378,7 @@ int32_t MUSIC_StopSong(void) external_midi_pid = -1; } - return MUSIC_Ok; + return(MUSIC_Ok); } #endif @@ -319,7 +386,7 @@ int32_t MUSIC_StopSong(void) if (!Mix_QuerySpec(NULL, NULL, NULL)) { setErrorMessage("Need FX system initialized, too. Sorry."); - return MUSIC_Error; + return(MUSIC_Error); } // if if ((Mix_PlayingMusic()) || (Mix_PausedMusic())) @@ -330,7 +397,7 @@ int32_t MUSIC_StopSong(void) music_musicchunk = NULL; - return MUSIC_Ok; + return(MUSIC_Ok); } // MUSIC_StopSong #if defined FORK_EXEC_MIDI @@ -437,5 +504,82 @@ int32_t MUSIC_PlaySong(char *song, int32_t loopflag) return MUSIC_Ok; } + +void MUSIC_SetContext(int32_t context) +{ + music_context = context; +} // MUSIC_SetContext + + +int32_t MUSIC_GetContext(void) +{ + return(music_context); +} // MUSIC_GetContext + + +void MUSIC_SetSongTick(uint32_t PositionInTicks) +{ + UNREFERENCED_PARAMETER(PositionInTicks); +} // MUSIC_SetSongTick + + +void MUSIC_SetSongTime(uint32_t milliseconds) +{ + UNREFERENCED_PARAMETER(milliseconds); +}// MUSIC_SetSongTime + + +void MUSIC_SetSongPosition(int32_t measure, int32_t beat, int32_t tick) +{ + UNREFERENCED_PARAMETER(measure); + UNREFERENCED_PARAMETER(beat); + UNREFERENCED_PARAMETER(tick); +} // MUSIC_SetSongPosition + + +void MUSIC_GetSongPosition(songposition *pos) +{ + UNREFERENCED_PARAMETER(pos); +} // MUSIC_GetSongPosition + + +void MUSIC_GetSongLength(songposition *pos) +{ + UNREFERENCED_PARAMETER(pos); +} // MUSIC_GetSongLength + + +int32_t MUSIC_FadeVolume(int32_t tovolume, int32_t milliseconds) +{ + UNREFERENCED_PARAMETER(tovolume); + Mix_FadeOutMusic(milliseconds); + return(MUSIC_Ok); +} // MUSIC_FadeVolume + + +int32_t MUSIC_FadeActive(void) +{ + return((Mix_FadingMusic() == MIX_FADING_OUT) ? TRUE : FALSE); +} // MUSIC_FadeActive + + +void MUSIC_StopFade(void) +{ +} // MUSIC_StopFade + + +void MUSIC_RerouteMidiChannel(int32_t channel, int32_t (*function)(int32_t, int32_t, int32_t)) +{ + UNREFERENCED_PARAMETER(channel); + UNREFERENCED_PARAMETER(function); +} // MUSIC_RerouteMidiChannel + + +void MUSIC_RegisterTimbreBank(char *timbres) +{ + UNREFERENCED_PARAMETER(timbres); +} // MUSIC_RegisterTimbreBank + + void MUSIC_Update(void) {} diff --git a/polymer/eduke32/source/sounds.c b/polymer/eduke32/source/sounds.c index 7ebc5f7b5..45b27c6de 100644 --- a/polymer/eduke32/source/sounds.c +++ b/polymer/eduke32/source/sounds.c @@ -101,7 +101,7 @@ void S_MusicStartup(void) { initprintf("Initializing music...\n"); - if (MUSIC_Init(0) == MUSIC_Ok || MUSIC_Init(1) == MUSIC_Ok) + if (MUSIC_Init(0, 0) == MUSIC_Ok || MUSIC_Init(1, 0) == MUSIC_Ok) { MUSIC_SetVolume(MASTER_VOLUME(ud.config.MusicVolume)); return;