mirror of
https://github.com/DrBeef/Raze.git
synced 2024-11-15 17:01:51 +00:00
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
This commit is contained in:
parent
d6e52ed526
commit
a1f08f2465
13 changed files with 1437 additions and 385 deletions
|
@ -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
|
39
source/audiolib/include/midifuncs.h
Normal file
39
source/audiolib/include/midifuncs.h
Normal file
|
@ -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
|
|
@ -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);
|
||||
|
|
46
source/audiolib/include/sndcards.h
Normal file
46
source/audiolib/include/sndcards.h
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
837
source/audiolib/src/driver_winmm.cpp
Normal file
837
source/audiolib/src/driver_winmm.cpp
Normal file
|
@ -0,0 +1,837 @@
|
|||
/*
|
||||
Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
|
||||
|
||||
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 <mmsystem.h>
|
||||
|
||||
#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:
|
33
source/audiolib/src/driver_winmm.h
Normal file
33
source/audiolib/src/driver_winmm.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
|
||||
|
||||
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);
|
||||
|
118
source/audiolib/src/ll.h
Normal file
118
source/audiolib/src/ll.h
Normal file
|
@ -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
|
|
@ -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));
|
||||
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,6 +615,7 @@ void MIDI_ContinueSong(void)
|
|||
return;
|
||||
|
||||
_MIDI_SongActive = TRUE;
|
||||
if (ASS_MIDISoundDriver == ASS_MPU401)
|
||||
MPU_Unpause();
|
||||
}
|
||||
|
||||
|
@ -604,6 +626,7 @@ void MIDI_PauseSong(void)
|
|||
|
||||
_MIDI_SongActive = FALSE;
|
||||
MIDI_AllNotesOff();
|
||||
if (ASS_MIDISoundDriver == ASS_MPU401)
|
||||
MPU_Pause();
|
||||
}
|
||||
|
||||
|
@ -617,8 +640,11 @@ void MIDI_StopSong(void)
|
|||
_MIDI_SongActive = FALSE;
|
||||
_MIDI_SongLoaded = FALSE;
|
||||
|
||||
if (ASS_MIDISoundDriver == ASS_MPU401)
|
||||
{
|
||||
MPU_Reset();
|
||||
MPU_Init(MUSIC_SoundDevice);
|
||||
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();
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
|
73
source/audiolib/src/midi.h
Normal file
73
source/audiolib/src/midi.h
Normal file
|
@ -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
|
|
@ -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; i<NUMBUFFERS; i++)
|
||||
{
|
||||
if (eventcnt[i] == 0) return i;
|
||||
|
@ -154,11 +154,11 @@ int32_t MPU_GetNextBuffer(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
void MPU_SendMidi(char *data, int32_t count)
|
||||
void MPU_SendMidi(char *data, int count)
|
||||
{
|
||||
char *p;
|
||||
int32_t padded, nextbuffer;
|
||||
static int32_t masks[3] = { 0x000000ffl, 0x0000ffffl, 0x00ffffffl };
|
||||
int padded, nextbuffer;
|
||||
static int masks[3] = { 0x000000ffl, 0x0000ffffl, 0x00ffffffl };
|
||||
|
||||
if (count <= 0) return;
|
||||
if (count <= 3)
|
||||
|
@ -177,9 +177,9 @@ void MPU_SendMidi(char *data, int32_t count)
|
|||
}
|
||||
|
||||
p = eventbuf[_MPU_CurrentBuffer] + eventcnt[_MPU_CurrentBuffer];
|
||||
((int32_t *)p)[0] = _MIDI_GlobalPositionInTicks - _MPU_LastEvent;
|
||||
((int32_t *)p)[1] = 0;
|
||||
((int32_t *)p)[2] = (MEVT_SHORTMSG << 24) | ((*((int32_t *)data)) & masks[count-1]);
|
||||
((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
|
||||
|
@ -199,9 +199,9 @@ void MPU_SendMidi(char *data, int32_t count)
|
|||
}
|
||||
|
||||
p = eventbuf[_MPU_CurrentBuffer] + eventcnt[_MPU_CurrentBuffer];
|
||||
((int32_t *)p)[0] = _MIDI_GlobalPositionInTicks - _MPU_LastEvent;
|
||||
((int32_t *)p)[1] = 0;
|
||||
((int32_t *)p)[2] = (MEVT_LONGMSG<<24) | (count & 0xffffffl);
|
||||
((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++);
|
||||
|
@ -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; i<NUMBUFFERS; i++) eventcnt[i]=0;
|
||||
|
||||
|
@ -294,9 +294,9 @@ int32_t MPU_Init
|
|||
|
||||
void MPU_NoteOff
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t key,
|
||||
int32_t velocity
|
||||
int channel,
|
||||
int key,
|
||||
int velocity
|
||||
)
|
||||
|
||||
{
|
||||
|
@ -316,9 +316,9 @@ void MPU_NoteOff
|
|||
|
||||
void MPU_NoteOn
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t key,
|
||||
int32_t velocity
|
||||
int channel,
|
||||
int key,
|
||||
int velocity
|
||||
)
|
||||
|
||||
{
|
||||
|
@ -338,9 +338,9 @@ void MPU_NoteOn
|
|||
|
||||
void MPU_PolyAftertouch
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t key,
|
||||
int32_t pressure
|
||||
int channel,
|
||||
int key,
|
||||
int pressure
|
||||
)
|
||||
|
||||
{
|
||||
|
@ -360,9 +360,9 @@ void MPU_PolyAftertouch
|
|||
|
||||
void MPU_ControlChange
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t number,
|
||||
int32_t value
|
||||
int channel,
|
||||
int number,
|
||||
int value
|
||||
)
|
||||
|
||||
{
|
||||
|
@ -382,8 +382,8 @@ void MPU_ControlChange
|
|||
|
||||
void MPU_ProgramChange
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t program
|
||||
int channel,
|
||||
int program
|
||||
)
|
||||
|
||||
{
|
||||
|
@ -402,8 +402,8 @@ void MPU_ProgramChange
|
|||
|
||||
void MPU_ChannelAftertouch
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t pressure
|
||||
int channel,
|
||||
int pressure
|
||||
)
|
||||
|
||||
{
|
||||
|
@ -422,9 +422,9 @@ void MPU_ChannelAftertouch
|
|||
|
||||
void MPU_PitchBend
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t lsb,
|
||||
int32_t msb
|
||||
int channel,
|
||||
int lsb,
|
||||
int msb
|
||||
)
|
||||
|
||||
{
|
||||
|
@ -437,7 +437,7 @@ void MPU_PitchBend
|
|||
|
||||
|
||||
|
||||
void MPU_SetTempo(int32_t tempo)
|
||||
void MPU_SetTempo(int tempo)
|
||||
{
|
||||
MIDIPROPTEMPO prop;
|
||||
prop.cbStruct = sizeof(MIDIPROPTEMPO);
|
||||
|
@ -445,7 +445,7 @@ void MPU_SetTempo(int32_t tempo)
|
|||
midiStreamProperty(hmido, (LPBYTE)&prop, MIDIPROP_SET|MIDIPROP_TEMPO);
|
||||
}
|
||||
|
||||
void MPU_SetDivision(int32_t division)
|
||||
void MPU_SetDivision(int division)
|
||||
{
|
||||
MIDIPROPTIMEDIV prop;
|
||||
prop.cbStruct = sizeof(MIDIPROPTIMEDIV);
|
||||
|
@ -453,11 +453,11 @@ void MPU_SetDivision(int32_t division)
|
|||
midiStreamProperty(hmido, (LPBYTE)&prop, MIDIPROP_SET|MIDIPROP_TIMEDIV);
|
||||
}
|
||||
|
||||
void MPU_SetVolume(int32_t volume)
|
||||
void MPU_SetVolume(int volume)
|
||||
{
|
||||
/*
|
||||
HMIXER hmixer;
|
||||
int32_t mixerid;
|
||||
int mixerid;
|
||||
MIXERCONTROLDETAILS mxcd;
|
||||
MIXERCONTROLDETAILS_UNSIGNED mxcdu;
|
||||
MMRESULT mme;
|
||||
|
@ -488,7 +488,7 @@ void MPU_SetVolume(int32_t volume)
|
|||
UNREFERENCED_PARAMETER(volume);
|
||||
}
|
||||
|
||||
int32_t MPU_GetVolume(void)
|
||||
int MPU_GetVolume(void)
|
||||
{
|
||||
// if (mididevice < 0) return 0;
|
||||
|
||||
|
|
|
@ -1,109 +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.
|
||||
*/
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// This object is shared by all Build games with MIDI playback!
|
||||
|
||||
#include "compat.h"
|
||||
#include "music.h"
|
||||
#include "midi.h"
|
||||
#include "mpu401.h"
|
||||
|
||||
int32_t MUSIC_SoundDevice = -1;
|
||||
int32_t MUSIC_ErrorCode = MUSIC_Ok;
|
||||
char const *errorMessage;
|
||||
static midifuncs MUSIC_MidiFunctions;
|
||||
|
||||
int32_t MUSIC_InitMidi(int32_t card, midifuncs *Funcs, int32_t Address);
|
||||
|
||||
|
||||
int32_t MUSIC_Init(int32_t SoundCard, int32_t Address)
|
||||
{
|
||||
MUSIC_SoundDevice = SoundCard;
|
||||
|
||||
return MUSIC_InitMidi(SoundCard, &MUSIC_MidiFunctions, Address);
|
||||
}
|
||||
|
||||
|
||||
int32_t MUSIC_Shutdown(void)
|
||||
{
|
||||
MIDI_StopSong();
|
||||
|
||||
return MUSIC_Ok;
|
||||
}
|
||||
|
||||
|
||||
void MUSIC_SetVolume(int32_t volume)
|
||||
{
|
||||
if (MUSIC_SoundDevice != -1)
|
||||
MIDI_SetVolume(min(max(0, volume), 255));
|
||||
}
|
||||
|
||||
|
||||
int32_t MUSIC_GetVolume(void) { return MUSIC_SoundDevice == -1 ? 0 : MIDI_GetVolume(); }
|
||||
void MUSIC_SetLoopFlag(int32_t loopflag) { MIDI_SetLoopFlag(loopflag); }
|
||||
void MUSIC_Continue(void) { MIDI_ContinueSong(); }
|
||||
void MUSIC_Pause(void) { MIDI_PauseSong(); }
|
||||
|
||||
int32_t MUSIC_StopSong(void)
|
||||
{
|
||||
MIDI_StopSong();
|
||||
MUSIC_SetErrorCode(MUSIC_Ok);
|
||||
return MUSIC_Ok;
|
||||
}
|
||||
|
||||
|
||||
int32_t MUSIC_PlaySong(char *song, int32_t songsize, int32_t 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_FileError);
|
||||
return MUSIC_Error;
|
||||
}
|
||||
|
||||
return MUSIC_Ok;
|
||||
}
|
||||
|
||||
|
||||
int32_t MUSIC_InitMidi(int32_t card, midifuncs *Funcs, int32_t Address)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(card);
|
||||
UNREFERENCED_PARAMETER(Address);
|
||||
Funcs->NoteOff = MPU_NoteOff;
|
||||
Funcs->NoteOn = MPU_NoteOn;
|
||||
Funcs->PolyAftertouch = MPU_PolyAftertouch;
|
||||
Funcs->ControlChange = MPU_ControlChange;
|
||||
Funcs->ProgramChange = MPU_ProgramChange;
|
||||
Funcs->ChannelAftertouch = MPU_ChannelAftertouch;
|
||||
Funcs->PitchBend = MPU_PitchBend;
|
||||
|
||||
MIDI_SetMidiFuncs(Funcs);
|
||||
|
||||
return MIDI_Ok;
|
||||
}
|
||||
|
||||
void MUSIC_Update(void) { MIDI_UpdateMusic(); }
|
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in a new issue