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:
terminx 2019-10-19 23:47:42 +00:00 committed by Christoph Oelckers
parent d6e52ed526
commit a1f08f2465
13 changed files with 1437 additions and 385 deletions

View file

@ -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

View 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

View file

@ -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);

View 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

View file

@ -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

View 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, &currentMidiBuffer->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, &currentMidiBuffer->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, &currentMidiBuffer->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:

View 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
View 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

View file

@ -34,74 +34,72 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
// This object is shared by all Build games with MIDI playback!
#include "compat.h"
#include "music.h"
#include "_midi.h"
#include "midi.h"
#include "mpu401.h"
#include "_midi.h"
#include "al_midi.h"
#include "compat.h"
#include "pragmas.h"
#include "mpu401.h"
#include "multivoc.h"
#include "music.h"
#include "pragmas.h"
#include "sndcards.h"
#include "windows_inc.h"
extern int32_t MUSIC_SoundDevice;
extern int MV_MixRate;
extern int ASS_MIDISoundDriver;
static const int32_t _MIDI_CommandLengths[ NUM_MIDI_CHANNELS ] =
{
0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0
};
static const int _MIDI_CommandLengths[NUM_MIDI_CHANNELS] = { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0 };
static track *_MIDI_TrackPtr = NULL;
static int32_t _MIDI_TrackMemSize;
static int32_t _MIDI_NumTracks;
static track * _MIDI_TrackPtr;
static int _MIDI_TrackMemSize;
static int _MIDI_NumTracks;
static int32_t _MIDI_SongActive = FALSE;
static int32_t _MIDI_SongLoaded = FALSE;
static int32_t _MIDI_Loop = FALSE;
static int _MIDI_SongActive;
static int _MIDI_SongLoaded;
static int _MIDI_Loop;
static int32_t _MIDI_Division;
static int32_t _MIDI_Tick = 0;
static int32_t _MIDI_Beat = 1;
static int32_t _MIDI_Measure = 1;
static int _MIDI_Division;
static int _MIDI_Tick;
static int _MIDI_Beat = 1;
static int _MIDI_Measure = 1;
static uint32_t _MIDI_Time;
static int32_t _MIDI_BeatsPerMeasure;
static int32_t _MIDI_TicksPerBeat;
static int32_t _MIDI_TimeBase;
static int32_t _MIDI_FPSecondsPerTick;
static int _MIDI_BeatsPerMeasure;
static int _MIDI_TicksPerBeat;
static int _MIDI_TimeBase;
static int _MIDI_FPSecondsPerTick;
static uint32_t _MIDI_TotalTime;
static int32_t _MIDI_TotalTicks;
static int32_t _MIDI_TotalBeats;
static int32_t _MIDI_TotalMeasures;
static int _MIDI_TotalTicks;
static int _MIDI_TotalBeats;
static int _MIDI_TotalMeasures;
uint32_t _MIDI_PositionInTicks;
uint32_t _MIDI_GlobalPositionInTicks;
static int32_t _MIDI_Context;
static int _MIDI_Context;
static int32_t _MIDI_ActiveTracks;
static int32_t _MIDI_TotalVolume = MIDI_MaxVolume;
static int _MIDI_ActiveTracks;
static int _MIDI_TotalVolume = MIDI_MaxVolume;
static int32_t _MIDI_ChannelVolume[ NUM_MIDI_CHANNELS ];
static int _MIDI_ChannelVolume[ NUM_MIDI_CHANNELS ];
static midifuncs *_MIDI_Funcs = NULL;
static midifuncs *_MIDI_Funcs;
static int32_t Reset = FALSE;
static int _MIDI_Reset;
int32_t MIDI_Tempo = 120;
int MIDI_Tempo = 120;
static int32_t _MIDI_PlayRoutine = -1;
static int32_t _MIDI_MixRate = 44100;
static int32_t _MIDI_MixTimer = 0;
static int _MIDI_PlayRoutine = -1;
static int _MIDI_MixRate = 44100;
static int _MIDI_MixTimer;
static int32_t _MIDI_ReadNumber(void *from, size_t size)
static int _MIDI_ReadNumber(void *from, size_t size)
{
if (size > 4)
size = 4;
char *FromPtr = (char *)from;
int32_t value = 0;
int value = 0;
while (size--)
{
@ -112,9 +110,9 @@ static int32_t _MIDI_ReadNumber(void *from, size_t size)
return value;
}
static int32_t _MIDI_ReadDelta(track *ptr)
static int _MIDI_ReadDelta(track *ptr)
{
int32_t value;
int value;
GET_NEXT_EVENT(ptr, value);
@ -185,15 +183,15 @@ static void _MIDI_AdvanceTick(void)
static void _MIDI_SysEx(track *Track)
{
int32_t length = _MIDI_ReadDelta(Track);
int length = _MIDI_ReadDelta(Track);
Track->pos += length;
}
static void _MIDI_MetaEvent(track *Track)
{
int32_t command;
int32_t length;
int command;
int length;
GET_NEXT_EVENT(Track, command);
GET_NEXT_EVENT(Track, length);
@ -208,7 +206,7 @@ static void _MIDI_MetaEvent(track *Track)
case MIDI_TEMPO_CHANGE:
{
int32_t tempo = tabledivide32_noinline(60000000L, _MIDI_ReadNumber(Track->pos, 3));
int tempo = tabledivide32_noinline(60000000L, _MIDI_ReadNumber(Track->pos, 3));
MIDI_SetTempo(tempo);
break;
}
@ -221,8 +219,8 @@ static void _MIDI_MetaEvent(track *Track)
_MIDI_Tick = 0;
_MIDI_Beat = 1;
_MIDI_TimeBase = 1;
_MIDI_BeatsPerMeasure = (int32_t)*Track->pos;
int32_t denominator = (int32_t) * (Track->pos + 1);
_MIDI_BeatsPerMeasure = (int)*Track->pos;
int denominator = (int) * (Track->pos + 1);
while (denominator > 0)
{
@ -238,11 +236,11 @@ static void _MIDI_MetaEvent(track *Track)
Track->pos += length;
}
static int32_t _MIDI_InterpretControllerInfo(track *Track, int32_t TimeSet, int32_t channel, int32_t c1, int32_t c2)
static int _MIDI_InterpretControllerInfo(track *Track, int TimeSet, int channel, int c1, int c2)
{
track *trackptr;
int32_t tracknum;
int32_t loopcount;
int tracknum;
int loopcount;
switch (c1)
{
@ -401,16 +399,16 @@ static void _MIDI_ServiceRoutine(void)
return;
track *Track = _MIDI_TrackPtr;
int32_t tracknum = 0;
int32_t TimeSet = FALSE;
int32_t c1 = 0;
int32_t c2 = 0;
int tracknum = 0;
int TimeSet = FALSE;
int c1 = 0;
int c2 = 0;
while (tracknum < _MIDI_NumTracks)
{
while ((Track->active) && (Track->delay == 0))
{
int32_t event;
int event;
GET_NEXT_EVENT(Track, event);
if (GET_MIDI_COMMAND(event) == MIDI_SPECIAL)
@ -511,7 +509,7 @@ static void _MIDI_ServiceRoutine(void)
_MIDI_GlobalPositionInTicks++;
}
static int32_t _MIDI_SendControlChange(int32_t channel, int32_t c1, int32_t c2)
static int _MIDI_SendControlChange(int channel, int c1, int c2)
{
if (_MIDI_Funcs == NULL || _MIDI_Funcs->ControlChange == NULL)
return MIDI_Error;
@ -521,7 +519,7 @@ static int32_t _MIDI_SendControlChange(int32_t channel, int32_t c1, int32_t c2)
return MIDI_Ok;
}
int32_t MIDI_AllNotesOff(void)
int MIDI_AllNotesOff(void)
{
for (bssize_t channel = 0; channel < NUM_MIDI_CHANNELS; channel++)
{
@ -533,7 +531,7 @@ int32_t MIDI_AllNotesOff(void)
return MIDI_Ok;
}
static void _MIDI_SetChannelVolume(int32_t channel, int32_t volume)
static void _MIDI_SetChannelVolume(int channel, int volume)
{
_MIDI_ChannelVolume[ channel ] = volume;
@ -552,7 +550,7 @@ static void _MIDI_SendChannelVolumes(void)
_MIDI_SetChannelVolume(channel, _MIDI_ChannelVolume[channel]);
}
int32_t MIDI_Reset(void)
int MIDI_Reset(void)
{
MIDI_AllNotesOff();
@ -568,25 +566,48 @@ int32_t MIDI_Reset(void)
_MIDI_SendChannelVolumes();
Reset = TRUE;
_MIDI_Reset = TRUE;
return MIDI_Ok;
}
int32_t MIDI_SetVolume(int32_t volume)
int MIDI_SetVolume(int volume)
{
if (_MIDI_Funcs == NULL)
return MIDI_NullMidiModule;
_MIDI_TotalVolume = max(0, min(MIDI_MaxVolume, volume));
_MIDI_SendChannelVolumes();
volume = min(MIDI_MaxVolume, volume);
volume = max(0, volume);
_MIDI_TotalVolume = volume;
SoundDriver_MIDI_Lock();
if (_MIDI_Funcs->SetVolume)
_MIDI_Funcs->SetVolume(volume);
else
_MIDI_SendChannelVolumes();
SoundDriver_MIDI_Unlock();
return MIDI_Ok;
}
int32_t MIDI_GetVolume(void) { return (_MIDI_Funcs == NULL) ? MIDI_NullMidiModule : _MIDI_TotalVolume; }
void MIDI_SetLoopFlag(int32_t loopflag) { _MIDI_Loop = loopflag; }
int MIDI_GetVolume(void)
{
if (_MIDI_Funcs == NULL)
return MIDI_NullMidiModule;
SoundDriver_MIDI_Lock();
int volume = (_MIDI_Funcs->GetVolume) ? _MIDI_Funcs->GetVolume() : _MIDI_TotalVolume;
SoundDriver_MIDI_Unlock();
return volume;
}
void MIDI_SetLoopFlag(int loopflag) { _MIDI_Loop = loopflag; }
void MIDI_ContinueSong(void)
{
@ -594,7 +615,8 @@ void MIDI_ContinueSong(void)
return;
_MIDI_SongActive = TRUE;
MPU_Unpause();
if (ASS_MIDISoundDriver == ASS_MPU401)
MPU_Unpause();
}
void MIDI_PauseSong(void)
@ -604,7 +626,8 @@ void MIDI_PauseSong(void)
_MIDI_SongActive = FALSE;
MIDI_AllNotesOff();
MPU_Pause();
if (ASS_MIDISoundDriver == ASS_MPU401)
MPU_Pause();
}
void MIDI_SetMidiFuncs(midifuncs *funcs) { _MIDI_Funcs = funcs; }
@ -617,8 +640,11 @@ void MIDI_StopSong(void)
_MIDI_SongActive = FALSE;
_MIDI_SongLoaded = FALSE;
MPU_Reset();
MPU_Init(MUSIC_SoundDevice);
if (ASS_MIDISoundDriver == ASS_MPU401)
{
MPU_Reset();
MPU_Init(ASS_MIDISoundDriver);
}
MIDI_Reset();
_MIDI_ResetTracks();
@ -633,15 +659,17 @@ void MIDI_StopSong(void)
_MIDI_TotalBeats = 0;
_MIDI_TotalMeasures = 0;
if (ASS_MIDISoundDriver == ASS_OPL3)
MV_UnhookMusicRoutine();
}
int32_t MIDI_PlaySong(char *song, int32_t loopflag)
int MIDI_PlaySong(char *song, int loopflag)
{
extern int32_t MV_MixRate;
int32_t numtracks;
int32_t format;
int32_t headersize;
int32_t tracklength;
int numtracks;
int format;
int headersize;
int tracklength;
track *CurrentTrack;
char *ptr;
@ -655,8 +683,8 @@ int32_t MIDI_PlaySong(char *song, int32_t loopflag)
headersize = _MIDI_ReadNumber(song, 4);
song += 4;
format = _MIDI_ReadNumber(song, 2);
int32_t My_MIDI_NumTracks = _MIDI_ReadNumber(song + 2, 2);
int32_t My_MIDI_Division = _MIDI_ReadNumber(song + 4, 2);
int My_MIDI_NumTracks = _MIDI_ReadNumber(song + 2, 2);
int My_MIDI_Division = _MIDI_ReadNumber(song + 4, 2);
if (My_MIDI_Division < 0)
{
// If a SMPTE time division is given, just set to 96 so no errors occur
@ -671,7 +699,7 @@ int32_t MIDI_PlaySong(char *song, int32_t loopflag)
if (My_MIDI_NumTracks == 0)
return MIDI_NoTracks;
int32_t My_MIDI_TrackMemSize = My_MIDI_NumTracks * sizeof(track);
int My_MIDI_TrackMemSize = My_MIDI_NumTracks * sizeof(track);
track * My_MIDI_TrackPtr = (track *)Xmalloc(My_MIDI_TrackMemSize);
CurrentTrack = My_MIDI_TrackPtr;
@ -700,7 +728,16 @@ int32_t MIDI_PlaySong(char *song, int32_t loopflag)
if (_MIDI_SongLoaded)
MIDI_StopSong();
MPU_Init(0/*MUSIC_SoundDevice*/);
switch (ASS_MIDISoundDriver)
{
case ASS_MPU401:
MPU_Init(0/*MUSIC_SoundDevice*/);
break;
case ASS_OPL3:
OPLMusic::AL_Init(MV_MixRate);
break;
}
_MIDI_Loop = loopflag;
_MIDI_NumTracks = My_MIDI_NumTracks;
@ -711,42 +748,81 @@ int32_t MIDI_PlaySong(char *song, int32_t loopflag)
_MIDI_InitEMIDI();
_MIDI_ResetTracks();
if (!Reset)
if (!_MIDI_Reset)
MIDI_Reset();
Reset = FALSE;
_MIDI_Reset = FALSE;
MIDI_SetDivision(_MIDI_Division);
if (ASS_MIDISoundDriver == ASS_MPU401)
{
MIDI_SetDivision(_MIDI_Division);
//MIDI_SetTempo( 120 );
}
else
{
_MIDI_PlayRoutine = 100;
_MIDI_MixTimer = 0;
//MIDI_SetDivision(_MIDI_Division);
MIDI_SetTempo( 120 );
}
_MIDI_SongLoaded = TRUE;
_MIDI_SongActive = TRUE;
while (_MPU_BuffersWaiting < 4) _MIDI_ServiceRoutine();
MPU_BeginPlayback();
if (ASS_MIDISoundDriver == ASS_MPU401)
{
while (_MPU_BuffersWaiting < 4) _MIDI_ServiceRoutine();
MPU_BeginPlayback();
}
else if (ASS_MIDISoundDriver == ASS_OPL3)
{
MV_HookMusicRoutine(MIDI_MusicMix);
_MIDI_MixRate = MV_MixRate;
}
return MIDI_Ok;
}
void MIDI_SetTempo(int32_t tempo)
void MIDI_SetTempo(int tempo)
{
int32_t tickspersecond;
int tickspersecond;
MIDI_Tempo = tempo;
tickspersecond = ((tempo) * _MIDI_Division)/60;
_MIDI_FPSecondsPerTick = tabledivide32_noinline(1 << TIME_PRECISION, tickspersecond);
MPU_SetTempo(tempo);
if (ASS_MIDISoundDriver == ASS_MPU401)
{
MPU_SetTempo(tempo);
}
else if (ASS_MIDISoundDriver == ASS_OPL3)
{
_MIDI_PlayRoutine = tickspersecond;
_MIDI_MixTimer = 0;
}
}
void MIDI_SetDivision(int32_t division)
void MIDI_SetDivision(int division)
{
MPU_SetDivision(division);
if (ASS_MIDISoundDriver == ASS_MPU401)
MPU_SetDivision(division);
}
int32_t MIDI_GetTempo(void) { return MIDI_Tempo; }
int MIDI_GetTempo(void) { return MIDI_Tempo; }
static void _MIDI_InitEMIDI(void)
{
int32_t type = EMIDI_GeneralMIDI;
int type = EMIDI_GeneralMIDI;
switch (ASS_MIDISoundDriver)
{
case ASS_MPU401:
type = EMIDI_GeneralMIDI;
break;
case ASS_OPL3:
type = EMIDI_Adlib;
break;
}
_MIDI_ResetTracks();
@ -756,7 +832,7 @@ static void _MIDI_InitEMIDI(void)
_MIDI_TotalMeasures = 0;
track *Track = _MIDI_TrackPtr;
int32_t tracknum = 0;
int tracknum = 0;
while ((tracknum < _MIDI_NumTracks) && (Track != NULL))
{
@ -787,11 +863,11 @@ static void _MIDI_InitEMIDI(void)
Track->delay--;
}
int32_t IncludeFound = FALSE;
int IncludeFound = FALSE;
while (Track->active)
{
int32_t event;
int event;
GET_NEXT_EVENT(Track, event);
@ -834,7 +910,7 @@ static void _MIDI_InitEMIDI(void)
if (*Track->pos == MIDI_MONO_MODE_ON)
length++;
int32_t c1, c2;
int c1, c2;
GET_NEXT_EVENT(Track, c1);
GET_NEXT_EVENT(Track, c2);
length -= 2;
@ -950,6 +1026,28 @@ static void _MIDI_InitEMIDI(void)
_MIDI_ResetTracks();
}
void MIDI_MusicMix(char *buffer, int length)
{
int16_t * buffer16 = (int16_t *)buffer;
int const samples = length >> 2;
for (int i = 0; i < samples; i++)
{
Bit16s buf[2];
while (_MIDI_MixTimer >= _MIDI_MixRate)
{
if (_MIDI_PlayRoutine >= 0)
_MIDI_ServiceRoutine();
_MIDI_MixTimer -= _MIDI_MixRate;
}
if (_MIDI_PlayRoutine >= 0) _MIDI_MixTimer += _MIDI_PlayRoutine;
OPL3_GenerateResampled(&OPLMusic::chip, buf);
*buffer16++ = clamp(buf[0]<<1, INT16_MIN, INT16_MAX);
*buffer16++ = clamp(buf[1]<<1, INT16_MIN, INT16_MAX);
}
}
void MIDI_UpdateMusic(void)
{
if (!_MIDI_SongLoaded || !_MIDI_SongActive) return;

View 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

View file

@ -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;

View file

@ -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(); }

View file

@ -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;
}