From a1f08f24650030dbc558ed260e0849b1574cbc42 Mon Sep 17 00:00:00 2001 From: terminx Date: Sat, 19 Oct 2019 23:47:42 +0000 Subject: [PATCH] New files for audiolib This is in a separate commit just to make the changes to existing files easier to go through. git-svn-id: https://svn.eduke32.com/eduke32@8215 1a8010ca-5511-0410-912e-c29ae57300e0 # Conflicts: # source/audiolib/include/midi.h # source/audiolib/src/_midi.h # source/audiolib/src/al_midi.cpp # source/audiolib/src/midi.cpp # source/audiolib/src/music.cpp # source/audiolib/src/oplmidi.cpp # source/duke3d/src/midi.cpp # Conflicts: # source/audiolib/src/al_midi.cpp # source/audiolib/src/midi.cpp # source/audiolib/src/music.cpp --- source/audiolib/include/midi.h | 89 -- source/audiolib/include/midifuncs.h | 39 + source/audiolib/include/mpu401.h | 34 +- source/audiolib/include/sndcards.h | 46 + source/audiolib/src/_midi.h | 23 +- source/audiolib/src/driver_winmm.cpp | 837 ++++++++++++++++++ source/audiolib/src/driver_winmm.h | 33 + source/audiolib/src/ll.h | 118 +++ source/audiolib/src/midi.cpp | 292 ++++-- source/audiolib/src/midi.h | 73 ++ source/audiolib/src/mpu401.cpp | 94 +- source/audiolib/src/music.cpp | 109 --- .../src/music_external.cpp | 35 +- 13 files changed, 1437 insertions(+), 385 deletions(-) delete mode 100644 source/audiolib/include/midi.h create mode 100644 source/audiolib/include/midifuncs.h create mode 100644 source/audiolib/include/sndcards.h create mode 100644 source/audiolib/src/driver_winmm.cpp create mode 100644 source/audiolib/src/driver_winmm.h create mode 100644 source/audiolib/src/ll.h create mode 100644 source/audiolib/src/midi.h delete mode 100644 source/audiolib/src/music.cpp rename source/{duke3d => audiolib}/src/music_external.cpp (90%) diff --git a/source/audiolib/include/midi.h b/source/audiolib/include/midi.h deleted file mode 100644 index 86f1ecbdd..000000000 --- a/source/audiolib/include/midi.h +++ /dev/null @@ -1,89 +0,0 @@ -//------------------------------------------------------------------------- -/* -Copyright (C) 2010-2019 EDuke32 developers and contributors -Copyright (C) 2019 Nuke.YKT - -This file is part of NBlood. - -NBlood 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -//------------------------------------------------------------------------- - -#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 (*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_MusicMix( char *buffer, int length ); -void MIDI_UpdateMusic(void); -void MIDI_SetDivision( int32_t division ); - -#endif diff --git a/source/audiolib/include/midifuncs.h b/source/audiolib/include/midifuncs.h new file mode 100644 index 000000000..7b85a49b7 --- /dev/null +++ b/source/audiolib/include/midifuncs.h @@ -0,0 +1,39 @@ +/* +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. + +*/ +#ifndef __MIDIFUNCS_H +#define __MIDIFUNCS_H + +typedef struct + { + void ( *NoteOff )( int channel, int key, int velocity ); + void ( *NoteOn )( int channel, int key, int velocity ); + void ( *PolyAftertouch )( int channel, int key, int pressure ); + void ( *ControlChange )( int channel, int number, int value ); + void ( *ProgramChange )( int channel, int program ); + void ( *ChannelAftertouch )( int channel, int pressure ); + void ( *PitchBend )( int channel, int lsb, int msb ); + void ( *ReleasePatches )( void ); + void ( *LoadPatch )( int number ); + void ( *SetVolume )( int volume ); + int ( *GetVolume )( void ); + void ( *SysEx )( const unsigned char * data, int length ); + } midifuncs; + +#endif diff --git a/source/audiolib/include/mpu401.h b/source/audiolib/include/mpu401.h index 419ce59af..3ed250d93 100644 --- a/source/audiolib/include/mpu401.h +++ b/source/audiolib/include/mpu401.h @@ -41,25 +41,25 @@ enum MPU_ERRORS #define MPU_CmdReset 0xff #define MPU_CmdAcknowledge 0xfe -extern int32_t _MPU_CurrentBuffer; -extern int32_t _MPU_BuffersWaiting; +extern int _MPU_CurrentBuffer; +extern int _MPU_BuffersWaiting; -void MPU_SendMidi( char *data, int32_t count ); -void MPU_SendMidiImmediate( char *data, int32_t count ); -int32_t MPU_Reset( void ); -int32_t MPU_Init( int32_t addr ); -void MPU_NoteOff( int32_t channel, int32_t key, int32_t velocity ); -void MPU_NoteOn( int32_t channel, int32_t key, int32_t velocity ); -void MPU_PolyAftertouch( int32_t channel, int32_t key, int32_t pressure ); -void MPU_ControlChange( int32_t channel, int32_t number, int32_t value ); -void MPU_ProgramChange( int32_t channel, int32_t program ); -void MPU_ChannelAftertouch( int32_t channel, int32_t pressure ); -void MPU_PitchBend( int32_t channel, int32_t lsb, int32_t msb ); +void MPU_SendMidi( char *data, int count ); +void MPU_SendMidiImmediate( char *data, int count ); +int MPU_Reset( void ); +int MPU_Init( int addr ); +void MPU_NoteOff( int channel, int key, int velocity ); +void MPU_NoteOn( int channel, int key, int velocity ); +void MPU_PolyAftertouch( int channel, int key, int pressure ); +void MPU_ControlChange( int channel, int number, int value ); +void MPU_ProgramChange( int channel, int program ); +void MPU_ChannelAftertouch( int channel, int pressure ); +void MPU_PitchBend( int channel, int lsb, int msb ); -void MPU_SetTempo(int32_t tempo); -void MPU_SetDivision(int32_t division); -void MPU_SetVolume(int32_t volume); -int32_t MPU_GetVolume(void); +void MPU_SetTempo(int tempo); +void MPU_SetDivision(int division); +void MPU_SetVolume(int volume); +int MPU_GetVolume(void); void MPU_BeginPlayback( void ); void MPU_Pause(void); diff --git a/source/audiolib/include/sndcards.h b/source/audiolib/include/sndcards.h new file mode 100644 index 000000000..c4618cd92 --- /dev/null +++ b/source/audiolib/include/sndcards.h @@ -0,0 +1,46 @@ +/* +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: SNDCARDS.H + + author: James R. Dose + date: March 31, 1994 + + Contains enumerated type definitions for sound cards. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __SNDCARDS_H +#define __SNDCARDS_H + +typedef enum +{ + ASS_NoSound, + ASS_SDL, + ASS_DirectSound, + ASS_WinMM, + ASS_MPU401, + ASS_OPL3, + ASS_NumSoundCards, + ASS_AutoDetect = -2 +} soundcardnames; + +#endif diff --git a/source/audiolib/src/_midi.h b/source/audiolib/src/_midi.h index f522fafca..5f66a197a 100644 --- a/source/audiolib/src/_midi.h +++ b/source/audiolib/src/_midi.h @@ -25,6 +25,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define ___MIDI_H #include "compat.h" +#ifdef OPL_MIDI_HEADER +namespace OPLMusic { +#endif #define RELATIVE_BEAT( measure, beat, tick ) \ ( ( tick ) + ( ( beat ) << 9 ) + ( ( measure ) << 16 ) ) @@ -95,6 +98,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define EMIDI_GeneralMIDI 0 #define EMIDI_SoundBlaster 4 +#define EMIDI_Adlib 7 #define EMIDI_AffectsCurrentCard(c, type) (((c) == EMIDI_ALL_CARDS) || ((c) == (type))) #define EMIDI_NUM_CONTEXTS 7 @@ -106,14 +110,14 @@ typedef struct int16_t loopcount; int16_t RunningStatus; unsigned time; - int32_t FPSecondsPerTick; + int FPSecondsPerTick; int16_t tick; int16_t beat; int16_t measure; int16_t BeatsPerMeasure; int16_t TicksPerBeat; int16_t TimeBase; - int32_t delay; + int delay; int16_t active; } songcontext; @@ -122,7 +126,7 @@ typedef struct char *start; char *pos; - int32_t delay; + int delay; int16_t active; int16_t RunningStatus; @@ -134,16 +138,19 @@ typedef struct char EMIDI_VolumeChange; } track; -static int32_t _MIDI_ReadNumber(void *from, size_t size); -static int32_t _MIDI_ReadDelta(track *ptr); +static int _MIDI_ReadNumber(void *from, size_t size); +static int _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 int _MIDI_InterpretControllerInfo(track *Track, int TimeSet, int channel, int c1, int c2); +static int _MIDI_SendControlChange(int channel, int c1, int c2); +static void _MIDI_SetChannelVolume(int channel, int volume); static void _MIDI_SendChannelVolumes(void); static void _MIDI_InitEMIDI(void); +#ifdef OPL_MIDI_HEADER +} +#endif #endif diff --git a/source/audiolib/src/driver_winmm.cpp b/source/audiolib/src/driver_winmm.cpp new file mode 100644 index 000000000..ffae6229d --- /dev/null +++ b/source/audiolib/src/driver_winmm.cpp @@ -0,0 +1,837 @@ +/* + Copyright (C) 2009 Jonathon Fowler + + 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. + + */ + +/** + * WinMM MIDI output driver + */ + +#include "driver_winmm.h" + +#include "compat.h" +#include "ll.h" +#include "midifuncs.h" +#include "multivoc.h" + +#include + +#ifdef _MSC_VER +#define inline _inline +#endif + +enum +{ + WinMMErr_Warning = -2, + WinMMErr_Error = -1, + WinMMErr_Ok = 0, + WinMMErr_Uninitialised, + WinMMErr_NotifyWindow, + WinMMErr_MIDIStreamOpen, + WinMMErr_MIDIStreamRestart, + WinMMErr_MIDICreateEvent, + WinMMErr_MIDIPlayThread, + WinMMErr_MIDICreateMutex +}; + +static int ErrorCode = WinMMErr_Ok; + +static BOOL midiInstalled; +static HMIDISTRM midiStream; +static UINT midiDeviceID = MIDI_MAPPER; +static void (*midiThreadService)(void); +static unsigned int midiThreadTimer; +static unsigned int midiLastEventTime; +static unsigned int midiThreadQueueTimer; +static unsigned int midiThreadQueueTicks; +static HANDLE midiThread; +static HANDLE midiThreadQuitEvent; +static HANDLE midiMutex; +static BOOL midiStreamRunning; +static int midiLastDivision; +#define THREAD_QUEUE_INTERVAL 10 // 1/10 sec +#define MIDI_BUFFER_SPACE (12*128) // 128 note-on events + +typedef struct MidiBuffer { + struct MidiBuffer *next; + struct MidiBuffer *prev; + + BOOL prepared; + MIDIHDR hdr; +} MidiBuffer; + +static volatile MidiBuffer activeMidiBuffers; +static volatile MidiBuffer spareMidiBuffers; +static MidiBuffer *currentMidiBuffer; + + +#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 + + + + +int WinMMDrv_GetError(void) +{ + return ErrorCode; +} + +const char *WinMMDrv_ErrorString( int ErrorNumber ) +{ + const char *ErrorString; + + switch( ErrorNumber ) + { + case WinMMErr_Warning : + case WinMMErr_Error : + ErrorString = WinMMDrv_ErrorString( ErrorCode ); + break; + + case WinMMErr_Ok : + ErrorString = "WinMM ok."; + break; + + case WinMMErr_Uninitialised: + ErrorString = "WinMM uninitialised."; + break; + + case WinMMErr_MIDIStreamOpen: + ErrorString = "MIDI error: failed opening stream."; + break; + + case WinMMErr_MIDIStreamRestart: + ErrorString = "MIDI error: failed starting stream."; + break; + + case WinMMErr_MIDICreateEvent: + ErrorString = "MIDI error: failed creating play thread quit event."; + break; + + case WinMMErr_MIDIPlayThread: + ErrorString = "MIDI error: failed creating play thread."; + break; + + case WinMMErr_MIDICreateMutex: + ErrorString = "MIDI error: failed creating play mutex."; + break; + + default: + ErrorString = "Unknown WinMM error code."; + break; + } + + return ErrorString; + +} + + +// will append "err nnn (ssss)\n" to the end of the string it emits +static void midi_error(MMRESULT rv, const char * fmt, ...) +{ + va_list va; + const char * errtxt = "?"; + + switch (rv) { + case MMSYSERR_NOERROR: errtxt = "MMSYSERR_NOERROR"; break; + case MMSYSERR_BADDEVICEID: errtxt = "MMSYSERR_BADDEVICEID"; break; + case MMSYSERR_NOTENABLED: errtxt = "MMSYSERR_NOTENABLED"; break; + case MMSYSERR_ALLOCATED: errtxt = "MMSYSERR_ALLOCATED"; break; + case MMSYSERR_INVALHANDLE: errtxt = "MMSYSERR_INVALHANDLE"; break; + case MMSYSERR_NODRIVER: errtxt = "MMSYSERR_NODRIVER"; break; + case MMSYSERR_NOMEM: errtxt = "MMSYSERR_NOMEM"; break; + case MMSYSERR_NOTSUPPORTED: errtxt = "MMSYSERR_NOTSUPPORTED"; break; + case MMSYSERR_BADERRNUM: errtxt = "MMSYSERR_BADERRNUM"; break; + case MMSYSERR_INVALFLAG: errtxt = "MMSYSERR_INVALFLAG"; break; + case MMSYSERR_INVALPARAM: errtxt = "MMSYSERR_INVALPARAM"; break; + case MMSYSERR_HANDLEBUSY: errtxt = "MMSYSERR_HANDLEBUSY"; break; + case MMSYSERR_INVALIDALIAS: errtxt = "MMSYSERR_INVALIDALIAS"; break; + case MMSYSERR_BADDB: errtxt = "MMSYSERR_BADDB"; break; + case MMSYSERR_KEYNOTFOUND: errtxt = "MMSYSERR_KEYNOTFOUND"; break; + case MMSYSERR_READERROR: errtxt = "MMSYSERR_READERROR"; break; + case MMSYSERR_WRITEERROR: errtxt = "MMSYSERR_WRITEERROR"; break; + case MMSYSERR_DELETEERROR: errtxt = "MMSYSERR_DELETEERROR"; break; + case MMSYSERR_VALNOTFOUND: errtxt = "MMSYSERR_VALNOTFOUND"; break; + case MMSYSERR_NODRIVERCB: errtxt = "MMSYSERR_NODRIVERCB"; break; + default: break; + } + + va_start(va, fmt); + MV_Printf(fmt, va); + va_end(va); + + MV_Printf(" err %d (%s)\n", (int)rv, errtxt); +} + +static void midi_dispose_buffer(MidiBuffer * node, const char * caller) +{ + MMRESULT rv; + + if (node->prepared) { + rv = midiOutUnprepareHeader( (HMIDIOUT) midiStream, &node->hdr, sizeof(MIDIHDR) ); + if (rv != MMSYSERR_NOERROR) { + midi_error(rv, "WinMM %s/midi_dispose_buffer midiOutUnprepareHeader", caller); + } + node->prepared = FALSE; + } + + if (midiThread) { + // remove the node from the activeMidiBuffers list + LL_Remove( node, next, prev ); + + // when playing, we keep the buffers + LL_Add( (MidiBuffer*) &spareMidiBuffers, node, next, prev ); + //MV_Printf("WinMM %s/midi_dispose_buffer recycling buffer %p\n", caller, node); + } else { + // when not, we throw them away + free(node); + //MV_Printf("WinMM %s/midi_dispose_buffer freeing buffer %p\n", caller, node); + } +} + +static void midi_gc_buffers(void) +{ + MidiBuffer *node, *next; + + for ( node = activeMidiBuffers.next; node != &activeMidiBuffers; node = next ) { + next = node->next; + + if (node->hdr.dwFlags & MHDR_DONE) { + midi_dispose_buffer(node, "midi_gc_buffers"); + } + } +} + +static void midi_free_buffers(void) +{ + MidiBuffer *node, *next; + + //MV_Printf("waiting for active buffers to return\n"); + while (!LL_ListEmpty(&activeMidiBuffers, next, prev)) { + // wait for Windows to finish with all the buffers queued + midi_gc_buffers(); + //MV_Printf("waiting...\n"); + Sleep(10); + } + //MV_Printf("waiting over\n"); + + for ( node = spareMidiBuffers.next; node != &spareMidiBuffers; node = next ) { + next = node->next; + LL_Remove( node, next, prev ); + free(node); + //MV_Printf("WinMM midi_free_buffers freeing buffer %p\n", node); + } + + assert(currentMidiBuffer == 0); +} + +static void midi_flush_current_buffer(void) +{ + MMRESULT rv; + MIDIEVENT * evt; + BOOL needsPrepare = FALSE; + + if (!currentMidiBuffer) { + return; + } + + evt = (MIDIEVENT *) currentMidiBuffer->hdr.lpData; + + if (!midiThread) { + // immediate messages don't use a MIDIEVENT header so strip it off and + // make some adjustments + + currentMidiBuffer->hdr.dwBufferLength = currentMidiBuffer->hdr.dwBytesRecorded - 12; + currentMidiBuffer->hdr.dwBytesRecorded = 0; + currentMidiBuffer->hdr.lpData = (LPSTR) &evt->dwParms[0]; + + if (currentMidiBuffer->hdr.dwBufferLength > 0) { + needsPrepare = TRUE; + } + } else { + needsPrepare = TRUE; + } + + if (needsPrepare) { + // playing a file, or sending a sysex when not playing means + // we need to prepare the buffer + rv = midiOutPrepareHeader( (HMIDIOUT) midiStream, ¤tMidiBuffer->hdr, sizeof(MIDIHDR) ); + if (rv != MMSYSERR_NOERROR) { + midi_error(rv, "WinMM midi_flush_current_buffer midiOutPrepareHeader"); + return; + } + + currentMidiBuffer->prepared = TRUE; + } + + if (midiThread) { + // midi file playing, so send events to the stream + + LL_Add( (MidiBuffer*) &activeMidiBuffers, currentMidiBuffer, next, prev ); + + rv = midiStreamOut(midiStream, ¤tMidiBuffer->hdr, sizeof(MIDIHDR)); + if (rv != MMSYSERR_NOERROR) { + midi_error(rv, "WinMM midi_flush_current_buffer midiStreamOut"); + midi_dispose_buffer(currentMidiBuffer, "midi_flush_current_buffer"); + return; + } + + //MV_Printf("WinMM midi_flush_current_buffer queued buffer %p\n", currentMidiBuffer); + } else { + // midi file not playing, so send immediately + + if (currentMidiBuffer->hdr.dwBufferLength > 0) { + rv = midiOutLongMsg( (HMIDIOUT) midiStream, ¤tMidiBuffer->hdr, sizeof(MIDIHDR) ); + if (rv == MMSYSERR_NOERROR) { + // busy-wait for Windows to be done with it + while (!(currentMidiBuffer->hdr.dwFlags & MHDR_DONE)) ; + + //MV_Printf("WinMM midi_flush_current_buffer sent immediate long\n"); + } else { + midi_error(rv, "WinMM midi_flush_current_buffer midiOutLongMsg"); + } + } else { + rv = midiOutShortMsg( (HMIDIOUT) midiStream, evt->dwEvent ); + if (rv == MMSYSERR_NOERROR) { + //MV_Printf("WinMM midi_flush_current_buffer sent immediate short\n"); + } else { + midi_error(rv, "WinMM midi_flush_current_buffer midiOutShortMsg"); + } + } + + midi_dispose_buffer(currentMidiBuffer, "midi_flush_current_buffer"); + } + + currentMidiBuffer = 0; +} + +static void midi_setup_event(int length, unsigned char ** data) +{ + MIDIEVENT * evt; + + evt = (MIDIEVENT *) ((intptr_t) currentMidiBuffer->hdr.lpData + + currentMidiBuffer->hdr.dwBytesRecorded); + + evt->dwDeltaTime = midiThread ? (midiThreadTimer - midiLastEventTime) : 0; + evt->dwStreamID = 0; + + if (length <= 3) { + evt->dwEvent = (DWORD)MEVT_SHORTMSG << 24; + *data = (unsigned char *) &evt->dwEvent; + } else { + evt->dwEvent = ((DWORD)MEVT_LONGMSG << 24) | (length & 0x00ffffff); + *data = (unsigned char *) &evt->dwParms[0]; + } +} + +/* Gets space in the buffer presently being filled. + If insufficient space can be found in the buffer, + what is there is flushed to the stream and a new + buffer large enough is allocated. + + Returns a pointer to starting writing at in 'data'. + */ +static BOOL midi_get_buffer(int length, unsigned char ** data) +{ + int datalen; + MidiBuffer * node; + + // determine the space to alloc. + // the size of a MIDIEVENT is 3*sizeof(DWORD) = 12. + // short messages need only that amount of space. + // long messages need additional space equal to the length of + // the message, padded to 4 bytes + + if (length <= 3) { + datalen = 12; + } else { + datalen = 12 + length; + if ((datalen & 3) > 0) { + datalen += 4 - (datalen & 3); + } + } + + if (!midiThread) { + assert(currentMidiBuffer == 0); + } + + if (currentMidiBuffer && (currentMidiBuffer->hdr.dwBufferLength - + currentMidiBuffer->hdr.dwBytesRecorded) >= datalen) { + // there was enough space in the current buffer, so hand that back + midi_setup_event(length, data); + + currentMidiBuffer->hdr.dwBytesRecorded += datalen; + + return TRUE; + } + + if (currentMidiBuffer) { + // not enough space in the current buffer to accommodate the + // new data, so flush it to the stream + midi_flush_current_buffer(); + currentMidiBuffer = 0; + } + + // check if there's a spare buffer big enough to hold the message + if (midiThread) { + for ( node = spareMidiBuffers.next; node != &spareMidiBuffers; node = node->next ) { + if (node->hdr.dwBufferLength >= datalen) { + // yes! + LL_Remove( node, next, prev ); + + node->hdr.dwBytesRecorded = 0; + memset(node->hdr.lpData, 0, node->hdr.dwBufferLength); + + currentMidiBuffer = node; + + //MV_Printf("WinMM midi_get_buffer fetched buffer %p\n", node); + break; + } + } + } + + if (!currentMidiBuffer) { + // there were no spare buffers, or none were big enough, so + // allocate a new one + int size; + + if (midiThread) { + // playing a file, so allocate a buffer for more than + // one event + size = max(MIDI_BUFFER_SPACE, datalen); + } else { + // not playing a file, so allocate just a buffer for + // the event we'll be sending immediately + size = datalen; + } + + node = (MidiBuffer *) malloc( sizeof(MidiBuffer) + size ); + if (node == 0) { + return FALSE; + } + + memset(node, 0, sizeof(MidiBuffer) + datalen); + node->hdr.dwUser = (DWORD_PTR) node; + node->hdr.lpData = (LPSTR) ((intptr_t)node + sizeof(MidiBuffer)); + node->hdr.dwBufferLength = size; + node->hdr.dwBytesRecorded = 0; + + currentMidiBuffer = node; + + //MV_Printf("WinMM midi_get_buffer allocated buffer %p\n", node); + } + + midi_setup_event(length, data); + + currentMidiBuffer->hdr.dwBytesRecorded += datalen; + + return TRUE; +} + +static inline void midi_sequence_event(void) +{ + if (!midiThread) { + // a midi event being sent out of playback (streaming) mode + midi_flush_current_buffer(); + return; + } + + //MV_Printf("WinMM midi_sequence_event buffered\n"); + + // update the delta time counter + midiLastEventTime = midiThreadTimer; +} + +static void Func_NoteOff( int channel, int key, int velocity ) +{ + unsigned char * data; + + if (midi_get_buffer(3, &data)) { + data[0] = MIDI_NOTE_OFF | channel; + data[1] = key; + data[2] = velocity; + midi_sequence_event(); + } else MV_Printf("WinMM Func_NoteOff error\n"); +} + +static void Func_NoteOn( int channel, int key, int velocity ) +{ + unsigned char * data; + + if (midi_get_buffer(3, &data)) { + data[0] = MIDI_NOTE_ON | channel; + data[1] = key; + data[2] = velocity; + midi_sequence_event(); + } else MV_Printf("WinMM Func_NoteOn error\n"); +} + +static void Func_PolyAftertouch( int channel, int key, int pressure ) +{ + unsigned char * data; + + if (midi_get_buffer(3, &data)) { + data[0] = MIDI_POLY_AFTER_TCH | channel; + data[1] = key; + data[2] = pressure; + midi_sequence_event(); + } else MV_Printf("WinMM Func_PolyAftertouch error\n"); +} + +static void Func_ControlChange( int channel, int number, int value ) +{ + unsigned char * data; + + if (midi_get_buffer(3, &data)) { + data[0] = MIDI_CONTROL_CHANGE | channel; + data[1] = number; + data[2] = value; + midi_sequence_event(); + } else MV_Printf("WinMM Func_ControlChange error\n"); +} + +static void Func_ProgramChange( int channel, int program ) +{ + unsigned char * data; + + if (midi_get_buffer(2, &data)) { + data[0] = MIDI_PROGRAM_CHANGE | channel; + data[1] = program; + midi_sequence_event(); + } else MV_Printf("WinMM Func_ProgramChange error\n"); +} + +static void Func_ChannelAftertouch( int channel, int pressure ) +{ + unsigned char * data; + + if (midi_get_buffer(2, &data)) { + data[0] = MIDI_AFTER_TOUCH | channel; + data[1] = pressure; + midi_sequence_event(); + } else MV_Printf("WinMM Func_ChannelAftertouch error\n"); +} + +static void Func_PitchBend( int channel, int lsb, int msb ) +{ + unsigned char * data; + + if (midi_get_buffer(3, &data)) { + data[0] = MIDI_PITCH_BEND | channel; + data[1] = lsb; + data[2] = msb; + midi_sequence_event(); + } else MV_Printf("WinMM Func_PitchBend error\n"); +} + +static void Func_SysEx( const unsigned char * data, int length ) +{ + unsigned char * wdata; + + if (midi_get_buffer(length, &wdata)) { + memcpy(wdata, data, length); + midi_sequence_event(); + } else MV_Printf("WinMM Func_SysEx error\n"); +} + +int WinMMDrv_MIDI_Init(midifuncs * funcs) +{ + MMRESULT rv; + + if (midiInstalled) { + WinMMDrv_MIDI_Shutdown(); + } + + memset(funcs, 0, sizeof(midifuncs)); + + LL_Reset( (MidiBuffer*) &activeMidiBuffers, next, prev ); + LL_Reset( (MidiBuffer*) &spareMidiBuffers, next, prev ); + + midiMutex = CreateMutex(0, FALSE, 0); + if (!midiMutex) { + ErrorCode = WinMMErr_MIDICreateMutex; + return WinMMErr_Error; + } + + rv = midiStreamOpen(&midiStream, &midiDeviceID, 1, (DWORD_PTR) 0, (DWORD_PTR) 0, CALLBACK_NULL); + if (rv != MMSYSERR_NOERROR) { + CloseHandle(midiMutex); + midiMutex = 0; + + midi_error(rv, "WinMM MIDI_Init midiStreamOpen"); + ErrorCode = WinMMErr_MIDIStreamOpen; + return WinMMErr_Error; + } + + funcs->NoteOff = Func_NoteOff; + funcs->NoteOn = Func_NoteOn; + funcs->PolyAftertouch = Func_PolyAftertouch; + funcs->ControlChange = Func_ControlChange; + funcs->ProgramChange = Func_ProgramChange; + funcs->ChannelAftertouch = Func_ChannelAftertouch; + funcs->PitchBend = Func_PitchBend; + funcs->SysEx = Func_SysEx; + + midiInstalled = TRUE; + + return WinMMErr_Ok; +} + +void WinMMDrv_MIDI_Shutdown(void) +{ + MMRESULT rv; + + if (!midiInstalled) { + return; + } + + WinMMDrv_MIDI_HaltPlayback(); + + if (midiStream) { + rv = midiStreamClose(midiStream); + if (rv != MMSYSERR_NOERROR) { + midi_error(rv, "WinMM MIDI_Shutdown midiStreamClose"); + } + } + + if (midiMutex) { + CloseHandle(midiMutex); + } + + midiStream = 0; + midiMutex = 0; + + midiInstalled = FALSE; +} + +static DWORD midi_get_tick(void) +{ + MMRESULT rv; + MMTIME mmtime; + + mmtime.wType = TIME_TICKS; + + rv = midiStreamPosition(midiStream, &mmtime, sizeof(MMTIME)); + if (rv != MMSYSERR_NOERROR) { + midi_error(rv, "WinMM midi_get_tick midiStreamPosition"); + return 0; + } + + return mmtime.u.ticks; +} + +static DWORD WINAPI midiDataThread(LPVOID lpParameter) +{ + DWORD waitret; + DWORD sequenceTime; + DWORD sleepAmount = 100 / THREAD_QUEUE_INTERVAL; + + MV_Printf("WinMM midiDataThread: started\n"); + + midiThreadTimer = midi_get_tick(); + midiLastEventTime = midiThreadTimer; + midiThreadQueueTimer = midiThreadTimer + midiThreadQueueTicks; + + WinMMDrv_MIDI_Lock(); + midi_gc_buffers(); + while (midiThreadTimer < midiThreadQueueTimer) { + if (midiThreadService) { + midiThreadService(); + } + midiThreadTimer++; + } + midi_flush_current_buffer(); + WinMMDrv_MIDI_Unlock(); + + do { + waitret = WaitForSingleObject(midiThreadQuitEvent, sleepAmount); + if (waitret == WAIT_OBJECT_0) { + MV_Printf("WinMM midiDataThread: exiting\n"); + break; + } else if (waitret == WAIT_TIMEOUT) { + // queue a tick + sequenceTime = midi_get_tick(); + + sleepAmount = 100 / THREAD_QUEUE_INTERVAL; + if ((int)(midiThreadTimer - sequenceTime) > midiThreadQueueTicks) { + // we're running ahead, so sleep for half the usual + // amount and try again + sleepAmount /= 2; + continue; + } + + midiThreadQueueTimer = sequenceTime + midiThreadQueueTicks; + + WinMMDrv_MIDI_Lock(); + midi_gc_buffers(); + while (midiThreadTimer < midiThreadQueueTimer) { + if (midiThreadService) { + midiThreadService(); + } + midiThreadTimer++; + } + midi_flush_current_buffer(); + WinMMDrv_MIDI_Unlock(); + + } else { + MV_Printf("WinMM midiDataThread: wfmo err %d\n", (int) waitret); + } + } while (1); + + return 0; +} + +int WinMMDrv_MIDI_StartPlayback(void (*service)(void)) +{ + MMRESULT rv; + + WinMMDrv_MIDI_HaltPlayback(); + + midiThreadService = service; + + midiThreadQuitEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!midiThreadQuitEvent) { + ErrorCode = WinMMErr_MIDICreateEvent; + return WinMMErr_Error; + } + + if (!midiStreamRunning) { + rv = midiStreamRestart(midiStream); + if (rv != MMSYSERR_NOERROR) { + midi_error(rv, "MIDI_StartPlayback midiStreamRestart"); + WinMMDrv_MIDI_HaltPlayback(); + ErrorCode = WinMMErr_MIDIStreamRestart; + return WinMMErr_Error; + } + + midiStreamRunning = TRUE; + } + + midiThread = CreateThread(NULL, 0, midiDataThread, 0, 0, 0); + if (!midiThread) { + WinMMDrv_MIDI_HaltPlayback(); + ErrorCode = WinMMErr_MIDIPlayThread; + return WinMMErr_Error; + } + + return WinMMErr_Ok; +} + +void WinMMDrv_MIDI_HaltPlayback(void) +{ + MMRESULT rv; + + if (midiThread) { + SetEvent(midiThreadQuitEvent); + + WaitForSingleObject(midiThread, INFINITE); + MV_Printf("WinMM MIDI_HaltPlayback synched\n"); + + CloseHandle(midiThread); + } + + if (midiThreadQuitEvent) { + CloseHandle(midiThreadQuitEvent); + } + + if (midiStreamRunning) { + MV_Printf("stopping stream\n"); + rv = midiStreamStop(midiStream); + if (rv != MMSYSERR_NOERROR) { + midi_error(rv, "WinMM MIDI_HaltPlayback midiStreamStop"); + } + MV_Printf("stream stopped\n"); + + midiStreamRunning = FALSE; + } + + midi_free_buffers(); + + midiThread = 0; + midiThreadQuitEvent = 0; +} + +void WinMMDrv_MIDI_SetTempo(int tempo, int division) +{ + MMRESULT rv; + MIDIPROPTEMPO propTempo; + MIDIPROPTIMEDIV propTimediv; + BOOL running = midiStreamRunning; + + //MV_Printf("MIDI_SetTempo %d/%d\n", tempo, division); + + propTempo.cbStruct = sizeof(MIDIPROPTEMPO); + propTempo.dwTempo = 60000000l / tempo; + propTimediv.cbStruct = sizeof(MIDIPROPTIMEDIV); + propTimediv.dwTimeDiv = division; + + if (midiLastDivision != division) { + // changing the division means halting the stream + WinMMDrv_MIDI_HaltPlayback(); + + rv = midiStreamProperty(midiStream, (LPBYTE) &propTimediv, MIDIPROP_SET | MIDIPROP_TIMEDIV); + if (rv != MMSYSERR_NOERROR) { + midi_error(rv, "WinMM MIDI_SetTempo midiStreamProperty timediv"); + } + } + + rv = midiStreamProperty(midiStream, (LPBYTE) &propTempo, MIDIPROP_SET | MIDIPROP_TEMPO); + if (rv != MMSYSERR_NOERROR) { + midi_error(rv, "WinMM MIDI_SetTempo midiStreamProperty tempo"); + } + + if (midiLastDivision != division) { + if (running && WinMMDrv_MIDI_StartPlayback(midiThreadService) != WinMMErr_Ok) { + return; + } + + midiLastDivision = division; + } + + midiThreadQueueTicks = (int) ceil( ( ( (double) tempo * (double) division ) / 60.0 ) / + (double) THREAD_QUEUE_INTERVAL ); + if (midiThreadQueueTicks <= 0) { + midiThreadQueueTicks = 1; + } +} + +void WinMMDrv_MIDI_Lock(void) +{ + DWORD err; + + err = WaitForSingleObject(midiMutex, INFINITE); + if (err != WAIT_OBJECT_0) { + MV_Printf("WinMM midiMutex lock: wfso %d\n", (int) err); + } +} + +void WinMMDrv_MIDI_Unlock(void) +{ + ReleaseMutex(midiMutex); +} + +// vim:ts=4:sw=4:expandtab: diff --git a/source/audiolib/src/driver_winmm.h b/source/audiolib/src/driver_winmm.h new file mode 100644 index 000000000..51c71d2b6 --- /dev/null +++ b/source/audiolib/src/driver_winmm.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2009 Jonathon Fowler + + 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. + + */ + +#include "midifuncs.h" + +int WinMMDrv_GetError(void); +const char *WinMMDrv_ErrorString( int ErrorNumber ); + +int WinMMDrv_MIDI_Init(midifuncs *); +void WinMMDrv_MIDI_Shutdown(void); +int WinMMDrv_MIDI_StartPlayback(void (*service)(void)); +void WinMMDrv_MIDI_HaltPlayback(void); +void WinMMDrv_MIDI_SetTempo(int tempo, int division); +void WinMMDrv_MIDI_Lock(void); +void WinMMDrv_MIDI_Unlock(void); + diff --git a/source/audiolib/src/ll.h b/source/audiolib/src/ll.h new file mode 100644 index 000000000..a0a581ffe --- /dev/null +++ b/source/audiolib/src/ll.h @@ -0,0 +1,118 @@ +/* +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. + +*/ +#ifndef __linklist_h +#define __linklist_h +#ifdef __cplusplus +extern "C" { +#endif + + +#define NewNode(type) ((type*)SafeMalloc(sizeof(type))) + + +#define LL_CreateNewLinkedList(rootnode,type,next,prev) \ + { \ + (rootnode) = NewNode(type); \ + (rootnode)->prev = (rootnode); \ + (rootnode)->next = (rootnode); \ + } + + + +#define LL_AddNode(rootnode, newnode, next, prev) \ + { \ + (newnode)->next = (rootnode); \ + (newnode)->prev = (rootnode)->prev; \ + (rootnode)->prev->next = (newnode); \ + (rootnode)->prev = (newnode); \ + } + +#define LL_TransferList(oldroot,newroot,next,prev) \ + { \ + if ((oldroot)->prev != (oldroot)) \ + { \ + (oldroot)->prev->next = (newroot); \ + (oldroot)->next->prev = (newroot)->prev; \ + (newroot)->prev->next = (oldroot)->next; \ + (newroot)->prev = (oldroot)->prev; \ + (oldroot)->next = (oldroot); \ + (oldroot)->prev = (oldroot); \ + } \ + } + +#define LL_ReverseList(root,type,next,prev) \ + { \ + type *newend,*trav,*tprev; \ + \ + newend = (root)->next; \ + for(trav = (root)->prev; trav != newend; trav = tprev) \ + { \ + tprev = trav->prev; \ + LL_MoveNode(trav,newend,next,prev); \ + } \ + } + + +#define LL_RemoveNode(node,next,prev) \ + { \ + (node)->prev->next = (node)->next; \ + (node)->next->prev = (node)->prev; \ + (node)->next = (node); \ + (node)->prev = (node); \ + } + + +#define LL_SortedInsertion(rootnode,insertnode,next,prev,type,sortparm) \ + { \ + type *hoya; \ + \ + hoya = (rootnode)->next; \ + while((hoya != (rootnode)) && ((insertnode)->sortparm > hoya->sortparm)) \ + { \ + hoya = hoya->next; \ + } \ + LL_AddNode(hoya,(insertnode),next,prev); \ + } + +#define LL_MoveNode(node,newroot,next,prev) \ + { \ + LL_RemoveNode((node),next,prev); \ + LL_AddNode((newroot),(node),next,prev); \ + } + +#define LL_ListEmpty(list,next,prev) \ + ( \ + ((list)->next == (list)) && \ + ((list)->prev == (list)) \ + ) + +#define LL_Free(list) SafeFree(list) +#define LL_Reset(list,next,prev) (list)->next = (list)->prev = (list) +#define LL_New LL_CreateNewLinkedList +#define LL_Remove LL_RemoveNode +#define LL_Add LL_AddNode +#define LL_Empty LL_ListEmpty +#define LL_Move LL_MoveNode + + +#ifdef __cplusplus +}; +#endif +#endif diff --git a/source/audiolib/src/midi.cpp b/source/audiolib/src/midi.cpp index a4531928f..bb34219e2 100644 --- a/source/audiolib/src/midi.cpp +++ b/source/audiolib/src/midi.cpp @@ -34,74 +34,72 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // This object is shared by all Build games with MIDI playback! -#include "compat.h" -#include "music.h" -#include "_midi.h" #include "midi.h" -#include "mpu401.h" + +#include "_midi.h" +#include "al_midi.h" #include "compat.h" -#include "pragmas.h" - +#include "mpu401.h" #include "multivoc.h" - +#include "music.h" +#include "pragmas.h" +#include "sndcards.h" #include "windows_inc.h" -extern int32_t MUSIC_SoundDevice; +extern int MV_MixRate; +extern int ASS_MIDISoundDriver; -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 const int _MIDI_CommandLengths[NUM_MIDI_CHANNELS] = { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0 }; -static track *_MIDI_TrackPtr = NULL; -static int32_t _MIDI_TrackMemSize; -static int32_t _MIDI_NumTracks; +static track * _MIDI_TrackPtr; +static int _MIDI_TrackMemSize; +static int _MIDI_NumTracks; -static int32_t _MIDI_SongActive = FALSE; -static int32_t _MIDI_SongLoaded = FALSE; -static int32_t _MIDI_Loop = FALSE; +static int _MIDI_SongActive; +static int _MIDI_SongLoaded; +static int _MIDI_Loop; -static int32_t _MIDI_Division; -static int32_t _MIDI_Tick = 0; -static int32_t _MIDI_Beat = 1; -static int32_t _MIDI_Measure = 1; +static int _MIDI_Division; +static int _MIDI_Tick; +static int _MIDI_Beat = 1; +static int _MIDI_Measure = 1; static uint32_t _MIDI_Time; -static int32_t _MIDI_BeatsPerMeasure; -static int32_t _MIDI_TicksPerBeat; -static int32_t _MIDI_TimeBase; -static int32_t _MIDI_FPSecondsPerTick; +static int _MIDI_BeatsPerMeasure; +static int _MIDI_TicksPerBeat; +static int _MIDI_TimeBase; +static int _MIDI_FPSecondsPerTick; static uint32_t _MIDI_TotalTime; -static int32_t _MIDI_TotalTicks; -static int32_t _MIDI_TotalBeats; -static int32_t _MIDI_TotalMeasures; +static int _MIDI_TotalTicks; +static int _MIDI_TotalBeats; +static int _MIDI_TotalMeasures; uint32_t _MIDI_PositionInTicks; uint32_t _MIDI_GlobalPositionInTicks; -static int32_t _MIDI_Context; +static int _MIDI_Context; -static int32_t _MIDI_ActiveTracks; -static int32_t _MIDI_TotalVolume = MIDI_MaxVolume; +static int _MIDI_ActiveTracks; +static int _MIDI_TotalVolume = MIDI_MaxVolume; -static int32_t _MIDI_ChannelVolume[ NUM_MIDI_CHANNELS ]; +static int _MIDI_ChannelVolume[ NUM_MIDI_CHANNELS ]; -static midifuncs *_MIDI_Funcs = NULL; +static midifuncs *_MIDI_Funcs; -static int32_t Reset = FALSE; +static int _MIDI_Reset; -int32_t MIDI_Tempo = 120; +int MIDI_Tempo = 120; -static int32_t _MIDI_PlayRoutine = -1; -static int32_t _MIDI_MixRate = 44100; -static int32_t _MIDI_MixTimer = 0; +static int _MIDI_PlayRoutine = -1; +static int _MIDI_MixRate = 44100; +static int _MIDI_MixTimer; -static int32_t _MIDI_ReadNumber(void *from, size_t size) +static int _MIDI_ReadNumber(void *from, size_t size) { if (size > 4) size = 4; char *FromPtr = (char *)from; - int32_t value = 0; + int value = 0; while (size--) { @@ -112,9 +110,9 @@ static int32_t _MIDI_ReadNumber(void *from, size_t size) return value; } -static int32_t _MIDI_ReadDelta(track *ptr) +static int _MIDI_ReadDelta(track *ptr) { - int32_t value; + int value; GET_NEXT_EVENT(ptr, value); @@ -185,15 +183,15 @@ static void _MIDI_AdvanceTick(void) static void _MIDI_SysEx(track *Track) { - int32_t length = _MIDI_ReadDelta(Track); + int length = _MIDI_ReadDelta(Track); Track->pos += length; } static void _MIDI_MetaEvent(track *Track) { - int32_t command; - int32_t length; + int command; + int length; GET_NEXT_EVENT(Track, command); GET_NEXT_EVENT(Track, length); @@ -208,7 +206,7 @@ static void _MIDI_MetaEvent(track *Track) case MIDI_TEMPO_CHANGE: { - int32_t tempo = tabledivide32_noinline(60000000L, _MIDI_ReadNumber(Track->pos, 3)); + int tempo = tabledivide32_noinline(60000000L, _MIDI_ReadNumber(Track->pos, 3)); MIDI_SetTempo(tempo); break; } @@ -221,8 +219,8 @@ static void _MIDI_MetaEvent(track *Track) _MIDI_Tick = 0; _MIDI_Beat = 1; _MIDI_TimeBase = 1; - _MIDI_BeatsPerMeasure = (int32_t)*Track->pos; - int32_t denominator = (int32_t) * (Track->pos + 1); + _MIDI_BeatsPerMeasure = (int)*Track->pos; + int denominator = (int) * (Track->pos + 1); while (denominator > 0) { @@ -238,11 +236,11 @@ static void _MIDI_MetaEvent(track *Track) Track->pos += length; } -static int32_t _MIDI_InterpretControllerInfo(track *Track, int32_t TimeSet, int32_t channel, int32_t c1, int32_t c2) +static int _MIDI_InterpretControllerInfo(track *Track, int TimeSet, int channel, int c1, int c2) { track *trackptr; - int32_t tracknum; - int32_t loopcount; + int tracknum; + int loopcount; switch (c1) { @@ -401,16 +399,16 @@ static void _MIDI_ServiceRoutine(void) return; track *Track = _MIDI_TrackPtr; - int32_t tracknum = 0; - int32_t TimeSet = FALSE; - int32_t c1 = 0; - int32_t c2 = 0; + int tracknum = 0; + int TimeSet = FALSE; + int c1 = 0; + int c2 = 0; while (tracknum < _MIDI_NumTracks) { while ((Track->active) && (Track->delay == 0)) { - int32_t event; + int event; GET_NEXT_EVENT(Track, event); if (GET_MIDI_COMMAND(event) == MIDI_SPECIAL) @@ -511,7 +509,7 @@ static void _MIDI_ServiceRoutine(void) _MIDI_GlobalPositionInTicks++; } -static int32_t _MIDI_SendControlChange(int32_t channel, int32_t c1, int32_t c2) +static int _MIDI_SendControlChange(int channel, int c1, int c2) { if (_MIDI_Funcs == NULL || _MIDI_Funcs->ControlChange == NULL) return MIDI_Error; @@ -521,7 +519,7 @@ static int32_t _MIDI_SendControlChange(int32_t channel, int32_t c1, int32_t c2) return MIDI_Ok; } -int32_t MIDI_AllNotesOff(void) +int MIDI_AllNotesOff(void) { for (bssize_t channel = 0; channel < NUM_MIDI_CHANNELS; channel++) { @@ -533,7 +531,7 @@ int32_t MIDI_AllNotesOff(void) return MIDI_Ok; } -static void _MIDI_SetChannelVolume(int32_t channel, int32_t volume) +static void _MIDI_SetChannelVolume(int channel, int volume) { _MIDI_ChannelVolume[ channel ] = volume; @@ -552,7 +550,7 @@ static void _MIDI_SendChannelVolumes(void) _MIDI_SetChannelVolume(channel, _MIDI_ChannelVolume[channel]); } -int32_t MIDI_Reset(void) +int MIDI_Reset(void) { MIDI_AllNotesOff(); @@ -568,25 +566,48 @@ int32_t MIDI_Reset(void) _MIDI_SendChannelVolumes(); - Reset = TRUE; + _MIDI_Reset = TRUE; return MIDI_Ok; } -int32_t MIDI_SetVolume(int32_t volume) + +int MIDI_SetVolume(int volume) { if (_MIDI_Funcs == NULL) return MIDI_NullMidiModule; - _MIDI_TotalVolume = max(0, min(MIDI_MaxVolume, volume)); - _MIDI_SendChannelVolumes(); + volume = min(MIDI_MaxVolume, volume); + volume = max(0, volume); + + _MIDI_TotalVolume = volume; + + SoundDriver_MIDI_Lock(); + + if (_MIDI_Funcs->SetVolume) + _MIDI_Funcs->SetVolume(volume); + else + _MIDI_SendChannelVolumes(); + + SoundDriver_MIDI_Unlock(); return MIDI_Ok; } -int32_t MIDI_GetVolume(void) { return (_MIDI_Funcs == NULL) ? MIDI_NullMidiModule : _MIDI_TotalVolume; } -void MIDI_SetLoopFlag(int32_t loopflag) { _MIDI_Loop = loopflag; } +int MIDI_GetVolume(void) +{ + if (_MIDI_Funcs == NULL) + return MIDI_NullMidiModule; + + SoundDriver_MIDI_Lock(); + int volume = (_MIDI_Funcs->GetVolume) ? _MIDI_Funcs->GetVolume() : _MIDI_TotalVolume; + SoundDriver_MIDI_Unlock(); + + return volume; +} + +void MIDI_SetLoopFlag(int loopflag) { _MIDI_Loop = loopflag; } void MIDI_ContinueSong(void) { @@ -594,7 +615,8 @@ void MIDI_ContinueSong(void) return; _MIDI_SongActive = TRUE; - MPU_Unpause(); + if (ASS_MIDISoundDriver == ASS_MPU401) + MPU_Unpause(); } void MIDI_PauseSong(void) @@ -604,7 +626,8 @@ void MIDI_PauseSong(void) _MIDI_SongActive = FALSE; MIDI_AllNotesOff(); - MPU_Pause(); + if (ASS_MIDISoundDriver == ASS_MPU401) + MPU_Pause(); } void MIDI_SetMidiFuncs(midifuncs *funcs) { _MIDI_Funcs = funcs; } @@ -617,8 +640,11 @@ void MIDI_StopSong(void) _MIDI_SongActive = FALSE; _MIDI_SongLoaded = FALSE; - MPU_Reset(); - MPU_Init(MUSIC_SoundDevice); + if (ASS_MIDISoundDriver == ASS_MPU401) + { + MPU_Reset(); + MPU_Init(ASS_MIDISoundDriver); + } MIDI_Reset(); _MIDI_ResetTracks(); @@ -633,15 +659,17 @@ void MIDI_StopSong(void) _MIDI_TotalBeats = 0; _MIDI_TotalMeasures = 0; + if (ASS_MIDISoundDriver == ASS_OPL3) + MV_UnhookMusicRoutine(); + } -int32_t MIDI_PlaySong(char *song, int32_t loopflag) +int MIDI_PlaySong(char *song, int loopflag) { - extern int32_t MV_MixRate; - int32_t numtracks; - int32_t format; - int32_t headersize; - int32_t tracklength; + int numtracks; + int format; + int headersize; + int tracklength; track *CurrentTrack; char *ptr; @@ -655,8 +683,8 @@ int32_t MIDI_PlaySong(char *song, int32_t loopflag) headersize = _MIDI_ReadNumber(song, 4); song += 4; format = _MIDI_ReadNumber(song, 2); - int32_t My_MIDI_NumTracks = _MIDI_ReadNumber(song + 2, 2); - int32_t My_MIDI_Division = _MIDI_ReadNumber(song + 4, 2); + int My_MIDI_NumTracks = _MIDI_ReadNumber(song + 2, 2); + int My_MIDI_Division = _MIDI_ReadNumber(song + 4, 2); if (My_MIDI_Division < 0) { // If a SMPTE time division is given, just set to 96 so no errors occur @@ -671,7 +699,7 @@ int32_t MIDI_PlaySong(char *song, int32_t loopflag) if (My_MIDI_NumTracks == 0) return MIDI_NoTracks; - int32_t My_MIDI_TrackMemSize = My_MIDI_NumTracks * sizeof(track); + int My_MIDI_TrackMemSize = My_MIDI_NumTracks * sizeof(track); track * My_MIDI_TrackPtr = (track *)Xmalloc(My_MIDI_TrackMemSize); CurrentTrack = My_MIDI_TrackPtr; @@ -700,7 +728,16 @@ int32_t MIDI_PlaySong(char *song, int32_t loopflag) if (_MIDI_SongLoaded) MIDI_StopSong(); - MPU_Init(0/*MUSIC_SoundDevice*/); + switch (ASS_MIDISoundDriver) + { + case ASS_MPU401: + MPU_Init(0/*MUSIC_SoundDevice*/); + break; + case ASS_OPL3: + OPLMusic::AL_Init(MV_MixRate); + break; + } + _MIDI_Loop = loopflag; _MIDI_NumTracks = My_MIDI_NumTracks; @@ -711,42 +748,81 @@ int32_t MIDI_PlaySong(char *song, int32_t loopflag) _MIDI_InitEMIDI(); _MIDI_ResetTracks(); - if (!Reset) + if (!_MIDI_Reset) MIDI_Reset(); - Reset = FALSE; + _MIDI_Reset = FALSE; - MIDI_SetDivision(_MIDI_Division); + if (ASS_MIDISoundDriver == ASS_MPU401) + { + MIDI_SetDivision(_MIDI_Division); + //MIDI_SetTempo( 120 ); + } + else + { + _MIDI_PlayRoutine = 100; + _MIDI_MixTimer = 0; + + //MIDI_SetDivision(_MIDI_Division); + MIDI_SetTempo( 120 ); + } _MIDI_SongLoaded = TRUE; _MIDI_SongActive = TRUE; - while (_MPU_BuffersWaiting < 4) _MIDI_ServiceRoutine(); - MPU_BeginPlayback(); + if (ASS_MIDISoundDriver == ASS_MPU401) + { + while (_MPU_BuffersWaiting < 4) _MIDI_ServiceRoutine(); + MPU_BeginPlayback(); + } + else if (ASS_MIDISoundDriver == ASS_OPL3) + { + MV_HookMusicRoutine(MIDI_MusicMix); + _MIDI_MixRate = MV_MixRate; + } return MIDI_Ok; } -void MIDI_SetTempo(int32_t tempo) +void MIDI_SetTempo(int tempo) { - int32_t tickspersecond; + int tickspersecond; MIDI_Tempo = tempo; tickspersecond = ((tempo) * _MIDI_Division)/60; _MIDI_FPSecondsPerTick = tabledivide32_noinline(1 << TIME_PRECISION, tickspersecond); - MPU_SetTempo(tempo); + if (ASS_MIDISoundDriver == ASS_MPU401) + { + MPU_SetTempo(tempo); + } + else if (ASS_MIDISoundDriver == ASS_OPL3) + { + _MIDI_PlayRoutine = tickspersecond; + _MIDI_MixTimer = 0; + } } -void MIDI_SetDivision(int32_t division) +void MIDI_SetDivision(int division) { - MPU_SetDivision(division); + if (ASS_MIDISoundDriver == ASS_MPU401) + MPU_SetDivision(division); } -int32_t MIDI_GetTempo(void) { return MIDI_Tempo; } +int MIDI_GetTempo(void) { return MIDI_Tempo; } static void _MIDI_InitEMIDI(void) { - int32_t type = EMIDI_GeneralMIDI; + int type = EMIDI_GeneralMIDI; + + switch (ASS_MIDISoundDriver) + { + case ASS_MPU401: + type = EMIDI_GeneralMIDI; + break; + case ASS_OPL3: + type = EMIDI_Adlib; + break; + } _MIDI_ResetTracks(); @@ -756,7 +832,7 @@ static void _MIDI_InitEMIDI(void) _MIDI_TotalMeasures = 0; track *Track = _MIDI_TrackPtr; - int32_t tracknum = 0; + int tracknum = 0; while ((tracknum < _MIDI_NumTracks) && (Track != NULL)) { @@ -787,11 +863,11 @@ static void _MIDI_InitEMIDI(void) Track->delay--; } - int32_t IncludeFound = FALSE; + int IncludeFound = FALSE; while (Track->active) { - int32_t event; + int event; GET_NEXT_EVENT(Track, event); @@ -834,7 +910,7 @@ static void _MIDI_InitEMIDI(void) if (*Track->pos == MIDI_MONO_MODE_ON) length++; - int32_t c1, c2; + int c1, c2; GET_NEXT_EVENT(Track, c1); GET_NEXT_EVENT(Track, c2); length -= 2; @@ -950,6 +1026,28 @@ static void _MIDI_InitEMIDI(void) _MIDI_ResetTracks(); } +void MIDI_MusicMix(char *buffer, int length) +{ + int16_t * buffer16 = (int16_t *)buffer; + int const samples = length >> 2; + + for (int i = 0; i < samples; i++) + { + Bit16s buf[2]; + while (_MIDI_MixTimer >= _MIDI_MixRate) + { + if (_MIDI_PlayRoutine >= 0) + _MIDI_ServiceRoutine(); + _MIDI_MixTimer -= _MIDI_MixRate; + } + if (_MIDI_PlayRoutine >= 0) _MIDI_MixTimer += _MIDI_PlayRoutine; + OPL3_GenerateResampled(&OPLMusic::chip, buf); + *buffer16++ = clamp(buf[0]<<1, INT16_MIN, INT16_MAX); + *buffer16++ = clamp(buf[1]<<1, INT16_MIN, INT16_MAX); + } +} + + void MIDI_UpdateMusic(void) { if (!_MIDI_SongLoaded || !_MIDI_SongActive) return; diff --git a/source/audiolib/src/midi.h b/source/audiolib/src/midi.h new file mode 100644 index 000000000..f6bba09ef --- /dev/null +++ b/source/audiolib/src/midi.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. + +*/ +/********************************************************************** + 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 + +#include "compat.h" +#include "midifuncs.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_DriverError +}; + + +#define MIDI_PASS_THROUGH 1 +#define MIDI_DONT_PLAY 0 + +#define MIDI_MaxVolume 255 + +int MIDI_AllNotesOff(void); +int MIDI_Reset(void); +int MIDI_SetVolume(int volume); +int MIDI_GetVolume(void); +void MIDI_SetMidiFuncs(midifuncs *funcs); +void MIDI_SetLoopFlag(int loopflag); +void MIDI_ContinueSong(void); +void MIDI_PauseSong(void); +void MIDI_StopSong(void); +int MIDI_PlaySong(char *song, int loopflag); +void MIDI_SetTempo(int tempo); +int MIDI_GetTempo(void); +void MIDI_MusicMix(char *buffer, int length); +void MIDI_UpdateMusic(void); +void MIDI_SetDivision(int division); + +#endif diff --git a/source/audiolib/src/mpu401.cpp b/source/audiolib/src/mpu401.cpp index ffa022e77..4c0e252a5 100644 --- a/source/audiolib/src/mpu401.cpp +++ b/source/audiolib/src/mpu401.cpp @@ -51,10 +51,10 @@ static DWORD mididevice = -1; #define BUFFERLEN (32*4*4) #define NUMBUFFERS 6 static char eventbuf[NUMBUFFERS][BUFFERLEN]; -static int32_t eventcnt[NUMBUFFERS]; +static int eventcnt[NUMBUFFERS]; static MIDIHDR bufferheaders[NUMBUFFERS]; -int32_t _MPU_CurrentBuffer = 0; -int32_t _MPU_BuffersWaiting = 0; +int _MPU_CurrentBuffer = 0; +int _MPU_BuffersWaiting = 0; extern uint32_t _MIDI_GlobalPositionInTicks; uint32_t _MPU_LastEvent=0; @@ -80,7 +80,7 @@ uint32_t _MPU_LastEvent=0; **********************************************************************/ -void MPU_FinishBuffer(int32_t buffer) +void MPU_FinishBuffer(int buffer) { if (!eventcnt[buffer]) return; ZeroMemory(&bufferheaders[buffer], sizeof(MIDIHDR)); @@ -112,7 +112,7 @@ void MPU_Unpause(void) void CALLBACK MPU_MIDICallback(HMIDIOUT handle, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { - int32_t i; + int i; UNREFERENCED_PARAMETER(dwInstance); UNREFERENCED_PARAMETER(dwParam2); @@ -144,9 +144,9 @@ void CALLBACK MPU_MIDICallback(HMIDIOUT handle, UINT uMsg, DWORD_PTR dwInstance, Queues a MIDI message to the music device. ---------------------------------------------------------------------*/ -int32_t MPU_GetNextBuffer(void) +int MPU_GetNextBuffer(void) { - int32_t i; + int i; for (i=0; i0; count--, padded--, eventcnt[_MPU_CurrentBuffer]++) *(p++) = *(data++); @@ -217,13 +217,13 @@ void MPU_SendMidi(char *data, int32_t count) Sends a MIDI message immediately to the the music device. ---------------------------------------------------------------------*/ -void MPU_SendMidiImmediate(char *data, int32_t count) +void MPU_SendMidiImmediate(char *data, int count) { MIDIHDR mhdr; - static int32_t masks[3] = { 0x00ffffffl, 0x0000ffffl, 0x000000ffl }; + static int masks[3] = { 0x00ffffffl, 0x0000ffffl, 0x000000ffl }; if (!count) return; - if (count<=3) midiOutShortMsg((HMIDIOUT)hmido, (*((int32_t *)data)) & masks[count-1]); + if (count<=3) midiOutShortMsg((HMIDIOUT)hmido, (*((int *)data)) & masks[count-1]); else { ZeroMemory(&mhdr, sizeof(mhdr)); @@ -243,7 +243,7 @@ void MPU_SendMidiImmediate(char *data, int32_t count) Resets the MPU401 card. ---------------------------------------------------------------------*/ -int32_t MPU_Reset +int MPU_Reset ( void ) @@ -263,16 +263,16 @@ int32_t MPU_Reset Detects and initializes the MPU401 card. ---------------------------------------------------------------------*/ -int32_t MPU_Init +int MPU_Init ( - int32_t addr + int addr ) { if (hmido != (HMIDISTRM)-1) return MPU_Ok; - int32_t i; + int i; for (i=0; iNoteOff = 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; - - MIDI_SetMidiFuncs(Funcs); - - return MIDI_Ok; -} - -void MUSIC_Update(void) { MIDI_UpdateMusic(); } diff --git a/source/duke3d/src/music_external.cpp b/source/audiolib/src/music_external.cpp similarity index 90% rename from source/duke3d/src/music_external.cpp rename to source/audiolib/src/music_external.cpp index d82ca5ec9..456c56e3f 100644 --- a/source/duke3d/src/music_external.cpp +++ b/source/audiolib/src/music_external.cpp @@ -22,9 +22,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // This object is shared by all Build games with MIDI playback! -#include "cache1d.h" #include "compat.h" -#include "duke3d.h" +#include "multivoc.h" #include "music.h" #include "vfs.h" #include "winbits.h" @@ -42,9 +41,9 @@ typedef HANDLE proc_t; #endif static char ** g_musicPlayerArgv; -static int32_t g_musicPlayerEnabled; +static int g_musicPlayerEnabled; static proc_t g_musicPlayerHandle = INVALID_HANDLE_VALUE; -static int32_t g_musicPlayerReady; +static int g_musicPlayerReady; static int8_t g_musicPlayerRestart; static char * g_musicPlayerCommandLine; @@ -53,7 +52,7 @@ static int g_musicFileNameArgvPos; char const *errorMessage; -int32_t MUSIC_Init(int32_t SoundCard, int32_t Address) +int MUSIC_Init(int SoundCard) { // Use an external music player g_musicPlayerCommandLine = getenv("EDUKE32_MUSIC_CMD"); @@ -75,10 +74,10 @@ int32_t MUSIC_Init(int32_t SoundCard, int32_t Address) return MUSIC_Error; } - initprintf("Using external music player: \"%s\"\n", g_musicPlayerCommandLine); + MV_Printf("Using external music player: \"%s\"\n", g_musicPlayerCommandLine); #ifndef _WIN32 - int32_t ws=1, numargs=0, pagesize=Bgetpagesize(); + int ws=1, numargs=0, pagesize=Bgetpagesize(); char *c, *cmd; size_t sz; @@ -144,7 +143,7 @@ int32_t MUSIC_Init(int32_t SoundCard, int32_t Address) } -int32_t MUSIC_Shutdown(void) +int MUSIC_Shutdown(void) { MUSIC_StopSong(); g_musicPlayerReady = 0; @@ -153,14 +152,14 @@ int32_t MUSIC_Shutdown(void) } // MUSIC_Shutdown -void MUSIC_SetMaxFMMidiChannel(int32_t channel) +void MUSIC_SetMaxFMMidiChannel(int channel) { UNREFERENCED_PARAMETER(channel); } // MUSIC_SetMaxFMMidiChannel int MUSIC_Volume; -void MUSIC_SetVolume(int32_t volume) +void MUSIC_SetVolume(int volume) { volume = max(0, volume); volume = min(volume, 255); @@ -169,13 +168,13 @@ void MUSIC_SetVolume(int32_t volume) } // MUSIC_SetVolume -int32_t MUSIC_GetVolume(void) +int MUSIC_GetVolume(void) { return MUSIC_Volume; } // MUSIC_GetVolume -void MUSIC_SetLoopFlag(int32_t loopflag) +void MUSIC_SetLoopFlag(int loopflag) { UNREFERENCED_PARAMETER(loopflag); } // MUSIC_SetLoopFlag @@ -190,7 +189,7 @@ void MUSIC_Pause(void) { } // MUSIC_Pause -int32_t MUSIC_StopSong(void) +int MUSIC_StopSong(void) { if (!g_musicPlayerEnabled) return MUSIC_Ok; @@ -232,7 +231,7 @@ int32_t MUSIC_StopSong(void) return MUSIC_Ok; } // MUSIC_StopSong -static int32_t MUSIC_PlayExternal() +static int MUSIC_PlayExternal() { #ifdef _WIN32 STARTUPINFO si; @@ -244,7 +243,7 @@ static int32_t MUSIC_PlayExternal() if (!CreateProcess(NULL,g_musicPlayerCommandLine,NULL,NULL,0,0,NULL,NULL,&si,&pi)) { - initprintf("%s: CreateProcess: %s\n", __func__, windowsGetErrorMessage(GetLastError())); + MV_Printf("%s: CreateProcess: %s\n", __func__, windowsGetErrorMessage(GetLastError())); return MUSIC_Error; } else @@ -293,7 +292,7 @@ static void sigchld_handler(int signo) } #endif -int32_t MUSIC_PlaySong(char *song, int32_t songsize, int32_t loopflag, const char *fn /*= nullptr*/) +int MUSIC_PlaySong(char *song, int songsize, int loopflag, const char *fn /*= nullptr*/) { if (!g_musicPlayerEnabled) { @@ -302,7 +301,7 @@ int32_t MUSIC_PlaySong(char *song, int32_t songsize, int32_t loopflag, const cha } #ifndef _WIN32 - static int32_t sigchld_handler_set; + static int sigchld_handler_set; if (!sigchld_handler_set) { @@ -336,7 +335,7 @@ int32_t MUSIC_PlaySong(char *song, int32_t songsize, int32_t loopflag, const cha } else { - initprintf("%s: fopen: %s\n", __func__, strerror(errno)); + MV_Printf("%s: fopen: %s\n", __func__, strerror(errno)); return MUSIC_Error; }