From 8a1681fb5a2822bc2779bcac2f4b8dec7f585381 Mon Sep 17 00:00:00 2001 From: terminx Date: Sat, 19 Oct 2019 23:48:08 +0000 Subject: [PATCH] More audiolib work git-svn-id: https://svn.eduke32.com/eduke32@8218 1a8010ca-5511-0410-912e-c29ae57300e0 # Conflicts: # source/audiolib/src/music.cpp # Conflicts: # GNUmakefile # platform/Windows/audiolib.vcxproj # platform/Windows/audiolib.vcxproj.filters # source/duke3d/src/menus.cpp --- source/audiolib/include/mpu401.h | 68 ---- source/audiolib/include/multivoc.h | 2 +- source/audiolib/include/sndcards.h | 1 - source/audiolib/src/_midi.h | 7 + source/audiolib/src/_multivc.h | 5 + source/audiolib/src/driver_adlib.cpp | 103 ++++++ source/audiolib/src/driver_adlib.h | 32 ++ source/audiolib/src/driver_winmm.cpp | 11 +- source/audiolib/src/drivers.cpp | 50 +-- source/audiolib/src/midi.cpp | 114 ++---- source/audiolib/src/midi.h | 30 +- source/audiolib/src/mpu401.cpp | 497 --------------------------- source/audiolib/src/multivoc.cpp | 29 +- source/audiolib/src/music.cpp | 158 +++++++++ source/duke3d/src/menus.cpp | 22 +- source/duke3d/src/sounds.cpp | 2 +- 16 files changed, 412 insertions(+), 719 deletions(-) delete mode 100644 source/audiolib/include/mpu401.h create mode 100644 source/audiolib/src/driver_adlib.cpp create mode 100644 source/audiolib/src/driver_adlib.h delete mode 100644 source/audiolib/src/mpu401.cpp create mode 100644 source/audiolib/src/music.cpp diff --git a/source/audiolib/include/mpu401.h b/source/audiolib/include/mpu401.h deleted file mode 100644 index 3ed250d93..000000000 --- a/source/audiolib/include/mpu401.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au) -*/ -#ifndef __MPU401_H -#define __MPU401_H - -#include "compat.h" - -#define MPU_DefaultAddress 0x330 - -enum MPU_ERRORS - { - MPU_Warning = -2, - MPU_Error = -1, - MPU_Ok = 0 - }; - -#define MPU_NotFound -1 -#define MPU_UARTFailed -2 - -#define MPU_ReadyToWrite 0x40 -#define MPU_ReadyToRead 0x80 -#define MPU_CmdEnterUART 0x3f -#define MPU_CmdReset 0xff -#define MPU_CmdAcknowledge 0xfe - -extern int _MPU_CurrentBuffer; -extern int _MPU_BuffersWaiting; - -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(int tempo); -void MPU_SetDivision(int division); -void MPU_SetVolume(int volume); -int MPU_GetVolume(void); - -void MPU_BeginPlayback( void ); -void MPU_Pause(void); -void MPU_Unpause(void); - -#endif diff --git a/source/audiolib/include/multivoc.h b/source/audiolib/include/multivoc.h index 20a8f7954..e43448480 100644 --- a/source/audiolib/include/multivoc.h +++ b/source/audiolib/include/multivoc.h @@ -124,7 +124,7 @@ void MV_SetReverseStereo(int setting); int MV_GetReverseStereo(void); int MV_Init(int soundcard, int MixRate, int Voices, int numchannels, void *initdata); int MV_Shutdown(void); -void MV_HookMusicRoutine(void (*callback)(char *buffer, int length)); +void MV_HookMusicRoutine(void (*callback)(void)); void MV_UnhookMusicRoutine(void); static inline void MV_SetPrintf(void (*function)(const char *, ...)) { if (function) MV_Printf = function; } diff --git a/source/audiolib/include/sndcards.h b/source/audiolib/include/sndcards.h index c4618cd92..42310d155 100644 --- a/source/audiolib/include/sndcards.h +++ b/source/audiolib/include/sndcards.h @@ -37,7 +37,6 @@ typedef enum ASS_SDL, ASS_DirectSound, ASS_WinMM, - ASS_MPU401, ASS_OPL3, ASS_NumSoundCards, ASS_AutoDetect = -2 diff --git a/source/audiolib/src/_midi.h b/source/audiolib/src/_midi.h index 5f66a197a..56a0f8793 100644 --- a/source/audiolib/src/_midi.h +++ b/source/audiolib/src/_midi.h @@ -48,6 +48,8 @@ namespace OPLMusic { #define MIDI_PAN 10 #define MIDI_DETUNE 94 #define MIDI_RHYTHM_CHANNEL 9 +#define MIDI_BANK_SELECT_MSB 0 +#define MIDI_BANK_SELECT_LSB 32 #define MIDI_RPN_MSB 100 #define MIDI_RPN_LSB 101 #define MIDI_DATAENTRY_MSB 6 @@ -67,8 +69,13 @@ namespace OPLMusic { #define MIDI_SYSEX_CONTINUE 0xF7 #define MIDI_META_EVENT 0xFF #define MIDI_END_OF_TRACK 0x2F +#define MIDI_HOLD1 0x40 +#define MIDI_SOSTENUTO 0x42 #define MIDI_TEMPO_CHANGE 0x51 #define MIDI_TIME_SIGNATURE 0x58 +#define MIDI_REVERB 0x5b +#define MIDI_CHORUS 0x5d +#define MIDI_ALL_SOUNDS_OFF 0x78 #define MIDI_RESET_ALL_CONTROLLERS 0x79 #define MIDI_ALL_NOTES_OFF 0x7b #define MIDI_MONO_MODE_ON 0x7E diff --git a/source/audiolib/src/_multivc.h b/source/audiolib/src/_multivc.h index e971cc3fb..c50edc85f 100644 --- a/source/audiolib/src/_multivc.h +++ b/source/audiolib/src/_multivc.h @@ -231,6 +231,11 @@ extern Pan MV_PanTable[ MV_NUMPANPOSITIONS ][ MV_MAXVOLUME + 1 ]; extern int MV_ErrorCode; extern int MV_Installed; extern int MV_MixRate; +extern char *MV_MusicBuffer; +extern int MV_BufferSize; + +extern int MV_MIDIRenderTempo; +extern int MV_MIDIRenderTimer; static FORCE_INLINE int MV_SetErrorCode(int status) { diff --git a/source/audiolib/src/driver_adlib.cpp b/source/audiolib/src/driver_adlib.cpp new file mode 100644 index 000000000..13268bc63 --- /dev/null +++ b/source/audiolib/src/driver_adlib.cpp @@ -0,0 +1,103 @@ +/** + * Adlib MIDI output + */ + +#include "driver_adlib.h" + +#include "al_midi.h" +#include "compat.h" +#include "midifuncs.h" +#include "midi.h" +#include "_multivc.h" + +enum { + AdlibErr_Warning = -2, + AdlibErr_Error = -1, + AdlibErr_Ok = 0, + AdlibErr_Uninitialised, +}; + +static int ErrorCode = AdlibErr_Ok; + +int AdlibDrv_GetError(void) +{ + return ErrorCode; +} + +const char *AdlibDrv_ErrorString( int ErrorNumber ) +{ + const char *ErrorString; + + switch( ErrorNumber ) + { + case AdlibErr_Warning : + case AdlibErr_Error : + ErrorString = AdlibDrv_ErrorString( ErrorCode ); + break; + + case AdlibErr_Ok : + ErrorString = "Adlib ok."; + break; + + case AdlibErr_Uninitialised: + ErrorString = "Adlib uninitialised."; + break; + + default: + ErrorString = "Unknown Adlib error."; + break; + } + + return ErrorString; +} + +int AdlibDrv_MIDI_Init(midifuncs *funcs) +{ + AdlibDrv_MIDI_Shutdown(); + Bmemset(funcs, 0, sizeof(midifuncs)); + + funcs->NoteOff = OPLMusic::AL_NoteOff; + funcs->NoteOn = OPLMusic::AL_NoteOn; + funcs->PolyAftertouch = NULL; + funcs->ControlChange = OPLMusic::AL_ControlChange; + funcs->ProgramChange = OPLMusic::AL_ProgramChange; + funcs->ChannelAftertouch = NULL; + funcs->PitchBend = OPLMusic::AL_SetPitchBend; + + return AdlibErr_Ok; +} + +void AdlibDrv_MIDI_Shutdown(void) +{ + AdlibDrv_MIDI_HaltPlayback(); +} + +int AdlibDrv_MIDI_StartPlayback(void (*service)(void)) +{ + AdlibDrv_MIDI_HaltPlayback(); + + OPLMusic::AL_Init(MV_MixRate); + MV_HookMusicRoutine(service); + + return MIDI_Ok; +} + +void AdlibDrv_MIDI_HaltPlayback(void) +{ + MV_UnhookMusicRoutine(); +} + +void AdlibDrv_MIDI_SetTempo(int tempo, int division) +{ + MV_MIDIRenderTempo = (tempo * division)/60; + MV_MIDIRenderTimer = 0; +} + +void AdlibDrv_MIDI_Lock(void) +{ +} + +void AdlibDrv_MIDI_Unlock(void) +{ +} + diff --git a/source/audiolib/src/driver_adlib.h b/source/audiolib/src/driver_adlib.h new file mode 100644 index 000000000..48ab496b2 --- /dev/null +++ b/source/audiolib/src/driver_adlib.h @@ -0,0 +1,32 @@ +/* + 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 AdlibDrv_GetError(void); +const char *AdlibDrv_ErrorString( int ErrorNumber ); + +int AdlibDrv_MIDI_Init(midifuncs *); +void AdlibDrv_MIDI_Shutdown(void); +int AdlibDrv_MIDI_StartPlayback(void (*service)(void)); +void AdlibDrv_MIDI_HaltPlayback(void); +void AdlibDrv_MIDI_SetTempo(int tempo, int division); +void AdlibDrv_MIDI_Lock(void); +void AdlibDrv_MIDI_Unlock(void); diff --git a/source/audiolib/src/driver_winmm.cpp b/source/audiolib/src/driver_winmm.cpp index ffae6229d..06e7394c1 100644 --- a/source/audiolib/src/driver_winmm.cpp +++ b/source/audiolib/src/driver_winmm.cpp @@ -65,7 +65,7 @@ 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 +#define MIDI_BUFFER_SPACE (12*128u) // 128 note-on events typedef struct MidiBuffer { struct MidiBuffer *next; @@ -79,7 +79,6 @@ 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 @@ -94,8 +93,6 @@ static MidiBuffer *currentMidiBuffer; #define MIDI_ALL_NOTES_OFF 0x7B - - int WinMMDrv_GetError(void) { return ErrorCode; @@ -357,7 +354,7 @@ static void midi_setup_event(int length, unsigned char ** data) */ static BOOL midi_get_buffer(int length, unsigned char ** data) { - int datalen; + unsigned int datalen; MidiBuffer * node; // determine the space to alloc. @@ -646,6 +643,8 @@ static DWORD midi_get_tick(void) static DWORD WINAPI midiDataThread(LPVOID lpParameter) { + UNREFERENCED_PARAMETER(lpParameter); + DWORD waitret; DWORD sequenceTime; DWORD sleepAmount = 100 / THREAD_QUEUE_INTERVAL; @@ -677,7 +676,7 @@ static DWORD WINAPI midiDataThread(LPVOID lpParameter) sequenceTime = midi_get_tick(); sleepAmount = 100 / THREAD_QUEUE_INTERVAL; - if ((int)(midiThreadTimer - sequenceTime) > midiThreadQueueTicks) { + if ((midiThreadTimer - sequenceTime) > midiThreadQueueTicks) { // we're running ahead, so sleep for half the usual // amount and try again sleepAmount /= 2; diff --git a/source/audiolib/src/drivers.cpp b/source/audiolib/src/drivers.cpp index 7b3ba3816..7c81bc34c 100644 --- a/source/audiolib/src/drivers.cpp +++ b/source/audiolib/src/drivers.cpp @@ -26,6 +26,7 @@ #include "drivers.h" #include "driver_nosound.h" +#include "driver_adlib.h" #ifdef RENDERTYPESDL # include "driver_sdl.h" @@ -141,50 +142,23 @@ static struct { #else UNSUPPORTED_COMPLETELY #endif - - // TODO: create the driver functions for these - // - // older MPU-401 code... - #ifdef _WIN32 - { - "MPU-401", - WinMMDrv_GetError, - WinMMDrv_ErrorString, - - UNSUPPORTED_PCM, - - WinMMDrv_MIDI_Init, - WinMMDrv_MIDI_Shutdown, - WinMMDrv_MIDI_StartPlayback, - WinMMDrv_MIDI_HaltPlayback, - WinMMDrv_MIDI_SetTempo, - WinMMDrv_MIDI_Lock, - WinMMDrv_MIDI_Unlock, - }, - #else - UNSUPPORTED_COMPLETELY - #endif - - #ifdef _WIN32 + // OPL3 emulation { - "OPL3", - WinMMDrv_GetError, - WinMMDrv_ErrorString, + "Nuked OPL3", + AdlibDrv_GetError, + AdlibDrv_ErrorString, UNSUPPORTED_PCM, - WinMMDrv_MIDI_Init, - WinMMDrv_MIDI_Shutdown, - WinMMDrv_MIDI_StartPlayback, - WinMMDrv_MIDI_HaltPlayback, - WinMMDrv_MIDI_SetTempo, - WinMMDrv_MIDI_Lock, - WinMMDrv_MIDI_Unlock, + AdlibDrv_MIDI_Init, + AdlibDrv_MIDI_Shutdown, + AdlibDrv_MIDI_StartPlayback, + AdlibDrv_MIDI_HaltPlayback, + AdlibDrv_MIDI_SetTempo, + AdlibDrv_MIDI_Lock, + AdlibDrv_MIDI_Unlock, }, - #else - UNSUPPORTED_COMPLETELY - #endif }; diff --git a/source/audiolib/src/midi.cpp b/source/audiolib/src/midi.cpp index bb34219e2..de995c22c 100644 --- a/source/audiolib/src/midi.cpp +++ b/source/audiolib/src/midi.cpp @@ -37,14 +37,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "midi.h" #include "_midi.h" +#include "_multivc.h" #include "al_midi.h" #include "compat.h" -#include "mpu401.h" #include "multivoc.h" #include "music.h" #include "pragmas.h" #include "sndcards.h" -#include "windows_inc.h" extern int MV_MixRate; extern int ASS_MIDISoundDriver; @@ -87,11 +86,10 @@ static midifuncs *_MIDI_Funcs; static int _MIDI_Reset; -int MIDI_Tempo = 120; +static int MIDI_Tempo = 120; -static int _MIDI_PlayRoutine = -1; -static int _MIDI_MixRate = 44100; -static int _MIDI_MixTimer; +int MV_MIDIRenderTempo = -1; +int MV_MIDIRenderTimer; static int _MIDI_ReadNumber(void *from, size_t size) { @@ -521,13 +519,18 @@ static int _MIDI_SendControlChange(int channel, int c1, int c2) int MIDI_AllNotesOff(void) { + SoundDriver_MIDI_Lock(); + for (bssize_t channel = 0; channel < NUM_MIDI_CHANNELS; channel++) { - _MIDI_SendControlChange(channel, 0x40, 0); + _MIDI_SendControlChange(channel, MIDI_HOLD1, 0); + _MIDI_SendControlChange(channel, MIDI_SOSTENUTO, 0); _MIDI_SendControlChange(channel, MIDI_ALL_NOTES_OFF, 0); - _MIDI_SendControlChange(channel, 0x78, 0); + _MIDI_SendControlChange(channel, MIDI_ALL_SOUNDS_OFF, 0); } + SoundDriver_MIDI_Unlock(); + return MIDI_Ok; } @@ -554,6 +557,8 @@ int MIDI_Reset(void) { MIDI_AllNotesOff(); + SoundDriver_MIDI_Lock(); + for (bssize_t channel = 0; channel < NUM_MIDI_CHANNELS; channel++) { _MIDI_SendControlChange(channel, MIDI_RESET_ALL_CONTROLLERS, 0); @@ -566,6 +571,8 @@ int MIDI_Reset(void) _MIDI_SendChannelVolumes(); + SoundDriver_MIDI_Unlock(); + _MIDI_Reset = TRUE; return MIDI_Ok; @@ -615,8 +622,6 @@ void MIDI_ContinueSong(void) return; _MIDI_SongActive = TRUE; - if (ASS_MIDISoundDriver == ASS_MPU401) - MPU_Unpause(); } void MIDI_PauseSong(void) @@ -626,8 +631,6 @@ void MIDI_PauseSong(void) _MIDI_SongActive = FALSE; MIDI_AllNotesOff(); - if (ASS_MIDISoundDriver == ASS_MPU401) - MPU_Pause(); } void MIDI_SetMidiFuncs(midifuncs *funcs) { _MIDI_Funcs = funcs; } @@ -637,15 +640,11 @@ void MIDI_StopSong(void) if (!_MIDI_SongLoaded) return; + SoundDriver_MIDI_HaltPlayback(); + _MIDI_SongActive = FALSE; _MIDI_SongLoaded = FALSE; - if (ASS_MIDISoundDriver == ASS_MPU401) - { - MPU_Reset(); - MPU_Init(ASS_MIDISoundDriver); - } - MIDI_Reset(); _MIDI_ResetTracks(); @@ -658,10 +657,6 @@ void MIDI_StopSong(void) _MIDI_TotalTicks = 0; _MIDI_TotalBeats = 0; _MIDI_TotalMeasures = 0; - - if (ASS_MIDISoundDriver == ASS_OPL3) - MV_UnhookMusicRoutine(); - } int MIDI_PlaySong(char *song, int loopflag) @@ -728,16 +723,6 @@ int MIDI_PlaySong(char *song, int loopflag) if (_MIDI_SongLoaded) MIDI_StopSong(); - 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; @@ -753,59 +738,34 @@ int MIDI_PlaySong(char *song, int loopflag) _MIDI_Reset = FALSE; - if (ASS_MIDISoundDriver == ASS_MPU401) + if (ASS_MIDISoundDriver == ASS_OPL3) { - MIDI_SetDivision(_MIDI_Division); - //MIDI_SetTempo( 120 ); + MV_MIDIRenderTempo = 100; + MV_MIDIRenderTimer = 0; } - else - { - _MIDI_PlayRoutine = 100; - _MIDI_MixTimer = 0; - //MIDI_SetDivision(_MIDI_Division); - MIDI_SetTempo( 120 ); - } + MIDI_SetTempo(120); + + if (SoundDriver_MIDI_StartPlayback(ASS_MIDISoundDriver == ASS_OPL3 ? MV_RenderMIDI : _MIDI_ServiceRoutine) != MIDI_Ok) + return MIDI_DriverError; _MIDI_SongLoaded = TRUE; _MIDI_SongActive = TRUE; - 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(int tempo) { - int tickspersecond; - MIDI_Tempo = tempo; - tickspersecond = ((tempo) * _MIDI_Division)/60; + SoundDriver_MIDI_SetTempo(tempo, _MIDI_Division); + int const tickspersecond = tempo * _MIDI_Division / 60; _MIDI_FPSecondsPerTick = tabledivide32_noinline(1 << TIME_PRECISION, tickspersecond); - if (ASS_MIDISoundDriver == ASS_MPU401) - { - MPU_SetTempo(tempo); - } - else if (ASS_MIDISoundDriver == ASS_OPL3) - { - _MIDI_PlayRoutine = tickspersecond; - _MIDI_MixTimer = 0; - } } void MIDI_SetDivision(int division) { - if (ASS_MIDISoundDriver == ASS_MPU401) - MPU_SetDivision(division); + UNREFERENCED_PARAMETER(division); } int MIDI_GetTempo(void) { return MIDI_Tempo; } @@ -816,9 +776,6 @@ static void _MIDI_InitEMIDI(void) switch (ASS_MIDISoundDriver) { - case ASS_MPU401: - type = EMIDI_GeneralMIDI; - break; case ASS_OPL3: type = EMIDI_Adlib; break; @@ -1026,21 +983,21 @@ static void _MIDI_InitEMIDI(void) _MIDI_ResetTracks(); } -void MIDI_MusicMix(char *buffer, int length) +void MV_RenderMIDI(void) { - int16_t * buffer16 = (int16_t *)buffer; - int const samples = length >> 2; + int16_t * buffer16 = (int16_t *)MV_MusicBuffer; + int const samples = MV_BufferSize >> 2; for (int i = 0; i < samples; i++) { Bit16s buf[2]; - while (_MIDI_MixTimer >= _MIDI_MixRate) + while (MV_MIDIRenderTimer >= MV_MixRate) { - if (_MIDI_PlayRoutine >= 0) + if (MV_MIDIRenderTempo >= 0) _MIDI_ServiceRoutine(); - _MIDI_MixTimer -= _MIDI_MixRate; + MV_MIDIRenderTimer -= MV_MixRate; } - if (_MIDI_PlayRoutine >= 0) _MIDI_MixTimer += _MIDI_PlayRoutine; + if (MV_MIDIRenderTempo >= 0) MV_MIDIRenderTimer += MV_MIDIRenderTempo; OPL3_GenerateResampled(&OPLMusic::chip, buf); *buffer16++ = clamp(buf[0]<<1, INT16_MIN, INT16_MAX); *buffer16++ = clamp(buf[1]<<1, INT16_MIN, INT16_MAX); @@ -1050,7 +1007,6 @@ void MIDI_MusicMix(char *buffer, int length) void MIDI_UpdateMusic(void) { - if (!_MIDI_SongLoaded || !_MIDI_SongActive) return; - while (_MPU_BuffersWaiting < 4) _MIDI_ServiceRoutine(); + } diff --git a/source/audiolib/src/midi.h b/source/audiolib/src/midi.h index f6bba09ef..584c4e6f2 100644 --- a/source/audiolib/src/midi.h +++ b/source/audiolib/src/midi.h @@ -54,20 +54,20 @@ enum MIDI_Errors #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); +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 MV_RenderMIDI(void); +void MIDI_UpdateMusic(void); +void MIDI_SetDivision(int division); #endif diff --git a/source/audiolib/src/mpu401.cpp b/source/audiolib/src/mpu401.cpp deleted file mode 100644 index 4c0e252a5..000000000 --- a/source/audiolib/src/mpu401.cpp +++ /dev/null @@ -1,497 +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. -*/ -//------------------------------------------------------------------------- - -/********************************************************************** - 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. -**********************************************************************/ - -// This object is shared by all Build games with MIDI playback! - -#include "mpu401.h" -#include "compat.h" -#include "pragmas.h" - -#define NEED_MMSYSTEM_H -#include "windows_inc.h" - -static HMIDISTRM hmido = (HMIDISTRM)-1; -static MIDIOUTCAPS midicaps; -static DWORD mididevice = -1; - -#define PAD(x) ((((x)+3)&(~3))) - -#define BUFFERLEN (32*4*4) -#define NUMBUFFERS 6 -static char eventbuf[NUMBUFFERS][BUFFERLEN]; -static int eventcnt[NUMBUFFERS]; -static MIDIHDR bufferheaders[NUMBUFFERS]; -int _MPU_CurrentBuffer = 0; -int _MPU_BuffersWaiting = 0; - -extern uint32_t _MIDI_GlobalPositionInTicks; -uint32_t _MPU_LastEvent=0; - -#define MIDI_NOTE_OFF 0x80 -#define MIDI_NOTE_ON 0x90 -#define MIDI_POLY_AFTER_TCH 0xA0 -#define MIDI_CONTROL_CHANGE 0xB0 -#define MIDI_PROGRAM_CHANGE 0xC0 -#define MIDI_AFTER_TOUCH 0xD0 -#define MIDI_PITCH_BEND 0xE0 -#define MIDI_META_EVENT 0xFF -#define MIDI_END_OF_TRACK 0x2F -#define MIDI_TEMPO_CHANGE 0x51 -#define MIDI_MONO_MODE_ON 0x7E -#define MIDI_ALL_NOTES_OFF 0x7B - - -/********************************************************************** - - Memory locked functions: - -**********************************************************************/ - - -void MPU_FinishBuffer(int buffer) -{ - if (!eventcnt[buffer]) return; - ZeroMemory(&bufferheaders[buffer], sizeof(MIDIHDR)); - bufferheaders[buffer].lpData = eventbuf[buffer]; - bufferheaders[buffer].dwBufferLength = - bufferheaders[buffer].dwBytesRecorded = eventcnt[buffer]; - midiOutPrepareHeader((HMIDIOUT)hmido, &bufferheaders[buffer], sizeof(MIDIHDR)); - midiStreamOut(hmido, &bufferheaders[buffer], sizeof(MIDIHDR)); -// printf("Sending %d bytes (buffer %d)\n",eventcnt[buffer],buffer); - _MPU_BuffersWaiting++; -} - -void MPU_BeginPlayback(void) -{ - _MPU_LastEvent = _MIDI_GlobalPositionInTicks; - if (hmido != (HMIDISTRM)-1) midiStreamRestart(hmido); -} - -void MPU_Pause(void) -{ - if (hmido != (HMIDISTRM)-1) midiStreamPause(hmido); -} - -void MPU_Unpause(void) -{ - if (hmido != (HMIDISTRM)-1) midiStreamRestart(hmido); -} - - -void CALLBACK MPU_MIDICallback(HMIDIOUT handle, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - int i; - - UNREFERENCED_PARAMETER(dwInstance); - UNREFERENCED_PARAMETER(dwParam2); - - switch (uMsg) - { - case MOM_DONE: - midiOutUnprepareHeader((HMIDIOUT)handle, (MIDIHDR *)dwParam1, sizeof(MIDIHDR)); - for (i=0; i BUFFERLEN) - { - // buffer over-full - nextbuffer = MPU_GetNextBuffer(); - if (nextbuffer < 0) - { -// printf("All buffers full!\n"); - return; - } - MPU_FinishBuffer(_MPU_CurrentBuffer); - _MPU_CurrentBuffer = nextbuffer; - } - - p = eventbuf[_MPU_CurrentBuffer] + eventcnt[_MPU_CurrentBuffer]; - ((int *)p)[0] = _MIDI_GlobalPositionInTicks - _MPU_LastEvent; - ((int *)p)[1] = 0; - ((int *)p)[2] = (MEVT_SHORTMSG << 24) | ((*((int *)data)) & masks[count-1]); - eventcnt[_MPU_CurrentBuffer] += 12; - } - else - { - padded = PAD(count); - if (eventcnt[_MPU_CurrentBuffer] + 12 + padded > BUFFERLEN) - { - // buffer over-full - nextbuffer = MPU_GetNextBuffer(); - if (nextbuffer < 0) - { -// printf("All buffers full!\n"); - return; - } - MPU_FinishBuffer(_MPU_CurrentBuffer); - _MPU_CurrentBuffer = nextbuffer; - } - - p = eventbuf[_MPU_CurrentBuffer] + eventcnt[_MPU_CurrentBuffer]; - ((int *)p)[0] = _MIDI_GlobalPositionInTicks - _MPU_LastEvent; - ((int *)p)[1] = 0; - ((int *)p)[2] = (MEVT_LONGMSG<<24) | (count & 0xffffffl); - p+=12; eventcnt[_MPU_CurrentBuffer] += 12; - for (; count>0; count--, padded--, eventcnt[_MPU_CurrentBuffer]++) - *(p++) = *(data++); - for (; padded>0; padded--, eventcnt[_MPU_CurrentBuffer]++) - *(p++) = 0; - } - _MPU_LastEvent = _MIDI_GlobalPositionInTicks; -} - - -/*--------------------------------------------------------------------- - Function: MPU_SendMidiImmediate - - Sends a MIDI message immediately to the the music device. ----------------------------------------------------------------------*/ -void MPU_SendMidiImmediate(char *data, int count) -{ - MIDIHDR mhdr; - static int masks[3] = { 0x00ffffffl, 0x0000ffffl, 0x000000ffl }; - - if (!count) return; - if (count<=3) midiOutShortMsg((HMIDIOUT)hmido, (*((int *)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. ----------------------------------------------------------------------*/ - -int MPU_Reset -( - void -) - -{ - midiStreamStop(hmido); - midiStreamClose(hmido); - hmido = (HMIDISTRM)-1; - - return MPU_Ok; -} - - -/*--------------------------------------------------------------------- - Function: MPU_Init - - Detects and initializes the MPU401 card. ----------------------------------------------------------------------*/ - -int MPU_Init -( - int addr -) - -{ - if (hmido != (HMIDISTRM)-1) - return MPU_Ok; - - int i; - - for (i=0; i>2; i++) { int sl = *source++; int sr = *source++; @@ -716,7 +716,7 @@ static int MV_StartPlayback(void) MV_MixPage = 1; - if (SoundDriver_PCM_BeginPlayback(MV_MixBuffer[0], MV_BufferSize, MV_NumberOfBuffers, MV_ServiceVoc) != MV_Ok) + if (SoundDriver_PCM_BeginPlayback(MV_MixBuffer[MV_NumberOfBuffers], MV_BufferSize, MV_NumberOfBuffers, MV_ServiceVoc) != MV_Ok) return MV_SetErrorCode(MV_DriverError); return MV_Ok; @@ -789,7 +789,7 @@ int MV_Init(int soundcard, int MixRate, int Voices, int numchannels, void *initd MV_SetErrorCode(MV_Ok); // MV_TotalMemory + 2: FIXME, see valgrind_errors.log - int const totalmem = Voices * sizeof(VoiceNode) + (MV_TOTALBUFFERSIZE << 1) + 2; + int const totalmem = Voices * sizeof(VoiceNode) + (MV_TOTALBUFFERSIZE<<1) + (MV_MIXBUFFERSIZE<<2); char *ptr = (char *) Xaligned_alloc(16, totalmem); @@ -845,6 +845,8 @@ int MV_Init(int soundcard, int MixRate, int Voices, int numchannels, void *initd ptr += MV_BufferSize; } + MV_MusicBuffer = ptr; + // Calculate pan table MV_CalcPanTable(); @@ -894,7 +896,7 @@ int MV_Shutdown(void) return MV_Ok; } -void MV_HookMusicRoutine(void(*callback)(char *buffer, int length)) +void MV_HookMusicRoutine(void(*callback)(void)) { MV_Lock(); MV_MusicCallback = callback; @@ -904,10 +906,13 @@ void MV_HookMusicRoutine(void(*callback)(char *buffer, int length)) void MV_UnhookMusicRoutine(void) { - MV_Lock(); - MV_MusicCallback = NULL; - MV_MixMusic = FALSE; - MV_Unlock(); + if (MV_MusicCallback) + { + MV_Lock(); + MV_MusicCallback = NULL; + MV_MixMusic = FALSE; + MV_Unlock(); + } } const char *loopStartTags[loopStartTagCount] = { "LOOP_START", "LOOPSTART", "LOOP" }; diff --git a/source/audiolib/src/music.cpp b/source/audiolib/src/music.cpp new file mode 100644 index 000000000..261d2ff81 --- /dev/null +++ b/source/audiolib/src/music.cpp @@ -0,0 +1,158 @@ +//------------------------------------------------------------------------- +/* +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. +*/ +//------------------------------------------------------------------------- + +// This object is shared by all Build games with MIDI playback! + +#include "music.h" + +#include "al_midi.h" +#include "compat.h" +#include "drivers.h" +#include "midi.h" +#include "multivoc.h" +#include "sndcards.h" + +int MUSIC_ErrorCode = MUSIC_Ok; + +static midifuncs MUSIC_MidiFunctions; + +#define MUSIC_SetErrorCode(status) MUSIC_ErrorCode = (status); + +const char *MUSIC_ErrorString(int ErrorNumber) +{ + const char *ErrorString; + + switch (ErrorNumber) + { + case MUSIC_Warning: + case MUSIC_Error: ErrorString = MUSIC_ErrorString(MUSIC_ErrorCode); break; + case MUSIC_Ok: ErrorString = "Music ok."; break; + case MUSIC_MidiError: ErrorString = "Error playing MIDI file."; break; + default: ErrorString = "Unknown Music error code."; break; + } + + return ErrorString; +} + + +int MUSIC_Init(int SoundCard) +{ + int detected = 0; + + if (SoundCard == ASS_AutoDetect) + { +redetect: + detected++; + +#if defined _WIN32 + SoundCard = ASS_WinMM; +#elif RENDERTYPESDL + SoundCard = ASS_SDL; +#else + SoundCard = ASS_NoSound; +#endif + } + + if (SoundCard < 0 || SoundCard >= ASS_NumSoundCards) + { +failed: + MV_Printf("failed!\n"); + MUSIC_ErrorCode = MUSIC_MidiError; + return MUSIC_Error; + } + + if (!SoundDriver_IsMIDISupported(SoundCard)) + { + MV_Printf("Couldn't init %s\n", SoundDriver_GetName(SoundCard)); + + if (detected < 2) + goto redetect; + + goto failed; + } + + ASS_MIDISoundDriver = SoundCard; + + int status = SoundDriver_MIDI_Init(&MUSIC_MidiFunctions); + + if (status != MUSIC_Ok) + { + if (detected < 2) + goto redetect; + + goto failed; + } + + MV_Printf("successfully initialized %s!\n", SoundDriver_GetName(SoundCard)); + + MIDI_SetMidiFuncs(&MUSIC_MidiFunctions); + + return MUSIC_Ok; +} + + +int MUSIC_Shutdown(void) +{ + MIDI_StopSong(); + + return MUSIC_Ok; +} + + +void MUSIC_SetVolume(int volume) { MIDI_SetVolume(min(max(0, volume), 255)); } + + +int MUSIC_GetVolume(void) { return MIDI_GetVolume(); } +void MUSIC_SetLoopFlag(int loopflag) { MIDI_SetLoopFlag(loopflag); } +void MUSIC_Continue(void) { MIDI_ContinueSong(); } +void MUSIC_Pause(void) { MIDI_PauseSong(); } + +int MUSIC_StopSong(void) +{ + MIDI_StopSong(); + MUSIC_SetErrorCode(MUSIC_Ok); + return MUSIC_Ok; +} + + +int MUSIC_PlaySong(char *song, int songsize, int loopflag, const char *fn /*= nullptr*/) +{ + UNREFERENCED_PARAMETER(songsize); + UNREFERENCED_PARAMETER(fn); + + MUSIC_SetErrorCode(MUSIC_Ok) + + if (MIDI_PlaySong(song, loopflag) != MIDI_Ok) + { + MUSIC_SetErrorCode(MUSIC_MidiError); + return MUSIC_Warning; + } + + return MUSIC_Ok; +} + + +void MUSIC_Update(void) +{ + MIDI_UpdateMusic(); +} diff --git a/source/duke3d/src/menus.cpp b/source/duke3d/src/menus.cpp index 6143011a0..665062de3 100644 --- a/source/duke3d/src/menus.cpp +++ b/source/duke3d/src/menus.cpp @@ -1131,7 +1131,7 @@ static MenuEntry_t ME_SAVE_NEW = MAKE_MENUENTRY( s_NewSaveGame, &MF_Minifont, &M static MenuEntry_t *ME_SAVE; static MenuEntry_t **MEL_SAVE; -static int32_t soundrate, soundvoices; +static int32_t soundrate, soundvoices, musicdevice; static MenuOption_t MEO_SOUND = MAKE_MENUOPTION( &MF_Redfont, &MEOS_OffOn, &snd_enabled.Value ); static MenuEntry_t ME_SOUND = MAKE_MENUENTRY( "Sound:", &MF_Redfont, &MEF_BigOptionsRt, &MEO_SOUND, Option ); @@ -1165,6 +1165,23 @@ static MenuRangeInt32_t MEO_SOUND_NUMVOICES = MAKE_MENURANGE( &soundvoices, &MF_ static MenuEntry_t ME_SOUND_NUMVOICES = MAKE_MENUENTRY( "Voices:", &MF_Redfont, &MEF_BigOptionsRt, &MEO_SOUND_NUMVOICES, RangeInt32 ); #endif +static char const *MEOSN_SOUND_MUSICDEVICE[] = { +#ifdef _WIN32 + "Windows", +#endif + "OPL3", +}; +static int32_t MEOSV_SOUND_MUSICDEVICE[] = { +#ifdef _WIN32 + ASS_WinMM, +#endif + ASS_OPL3, +}; + +static MenuOptionSet_t MEOS_SOUND_MUSICDEVICE = MAKE_MENUOPTIONSET( MEOSN_SOUND_MUSICDEVICE, MEOSV_SOUND_MUSICDEVICE, 0x2 ); +static MenuOption_t MEO_SOUND_MUSICDEVICE = MAKE_MENUOPTION( &MF_Redfont, &MEOS_SOUND_MUSICDEVICE, &musicdevice ); +static MenuEntry_t ME_SOUND_MUSICDEVICE = MAKE_MENUENTRY( "Music device:", &MF_Redfont, &MEF_BigOptionsRt, &MEO_SOUND_MUSICDEVICE, Option ); + static MenuEntry_t ME_SOUND_RESTART = MAKE_MENUENTRY( "Apply Changes", &MF_Redfont, &MEF_BigOptions_Apply, &MEO_NULL, Link ); #ifndef EDUKE32_SIMPLE_MENU @@ -1190,6 +1207,7 @@ static MenuEntry_t *MEL_ADVSOUND[] = { &ME_SOUND_NUMVOICES, &ME_Space2_Redfont, #endif + &ME_SOUND_MUSICDEVICE, &ME_SOUND_RESTART, }; @@ -3219,6 +3237,7 @@ static void Menu_EntryLinkActivate(MenuEntry_t *entry) { snd_mixrate = soundrate; snd_numvoices = soundvoices; + ud.config.MusicDevice = musicdevice; S_SoundShutdown(); S_MusicShutdown(); @@ -4241,6 +4260,7 @@ static void Menu_AboutToStartDisplaying(Menu_t * m) case MENU_ADVSOUND: soundrate = snd_mixrate; soundvoices = snd_numvoices; + musicdevice = ud.config.MusicDevice; break; default: diff --git a/source/duke3d/src/sounds.cpp b/source/duke3d/src/sounds.cpp index 63334c58d..79c508ccc 100644 --- a/source/duke3d/src/sounds.cpp +++ b/source/duke3d/src/sounds.cpp @@ -112,7 +112,7 @@ void S_SoundShutdown(void) void S_MusicStartup(void) { - initprintf("Initializing music...\n"); + initprintf("Initializing music... "); if (MUSIC_Init(ud.config.MusicDevice) == MUSIC_Ok || MUSIC_Init(0) == MUSIC_Ok || MUSIC_Init(1) == MUSIC_Ok) {