2006-02-24 04:48:15 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include "i_musicinterns.h"
|
|
|
|
#include "templates.h"
|
|
|
|
#include "doomdef.h"
|
|
|
|
#include "m_swap.h"
|
|
|
|
|
|
|
|
extern DWORD midivolume;
|
|
|
|
extern UINT mididevice;
|
2008-03-04 06:36:23 +00:00
|
|
|
extern HANDLE MusicEvent;
|
|
|
|
|
|
|
|
#define MAX_TIME (10)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
EXTERN_CVAR (Float, snd_midivolume)
|
|
|
|
|
|
|
|
static const BYTE CtrlTranslate[15] =
|
|
|
|
{
|
|
|
|
0, // program change
|
|
|
|
0, // bank select
|
|
|
|
1, // modulation pot
|
|
|
|
7, // volume
|
|
|
|
10, // pan pot
|
|
|
|
11, // expression pot
|
|
|
|
91, // reverb depth
|
|
|
|
93, // chorus depth
|
|
|
|
64, // sustain pedal
|
|
|
|
67, // soft pedal
|
|
|
|
120, // all sounds off
|
|
|
|
123, // all notes off
|
|
|
|
126, // mono
|
|
|
|
127, // poly
|
|
|
|
121, // reset all controllers
|
|
|
|
};
|
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
MUSSong2::MUSSong2 (FILE *file, char *musiccache, int len)
|
|
|
|
: MidiOut(0), MusHeader(0), MusBuffer(0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
MusHeader = (MUSHeader *)new BYTE[len];
|
2006-04-14 12:58:52 +00:00
|
|
|
|
|
|
|
if (file != NULL)
|
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
if (fread(MusHeader, 1, len, file) != (size_t)len)
|
|
|
|
{
|
2006-04-14 12:58:52 +00:00
|
|
|
return;
|
2008-03-04 06:36:23 +00:00
|
|
|
}
|
2006-04-14 12:58:52 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memcpy(MusHeader, musiccache, len);
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
// Do some validation of the MUS file
|
|
|
|
if (MusHeader->Magic != MAKE_ID('M','U','S','\x1a'))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2008-03-04 06:36:23 +00:00
|
|
|
|
|
|
|
if (LittleShort(MusHeader->NumChans) > 15)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2008-03-04 06:36:23 +00:00
|
|
|
|
|
|
|
FullVolEvent.dwDeltaTime = 0;
|
|
|
|
FullVolEvent.dwStreamID = 0;
|
|
|
|
FullVolEvent.dwEvent = MEVT_LONGMSG | 8;
|
|
|
|
FullVolEvent.SysEx[0] = 0xf0;
|
|
|
|
FullVolEvent.SysEx[1] = 0x7f;
|
|
|
|
FullVolEvent.SysEx[2] = 0x7f;
|
|
|
|
FullVolEvent.SysEx[3] = 0x04;
|
|
|
|
FullVolEvent.SysEx[4] = 0x01;
|
|
|
|
FullVolEvent.SysEx[5] = 0x7f;
|
|
|
|
FullVolEvent.SysEx[6] = 0x7f;
|
|
|
|
FullVolEvent.SysEx[7] = 0xf7;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
MusBuffer = (BYTE *)MusHeader + LittleShort(MusHeader->SongStart);
|
|
|
|
MaxMusP = MIN<int> (LittleShort(MusHeader->SongLen), len - LittleShort(MusHeader->SongStart));
|
|
|
|
MusP = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
MUSSong2::~MUSSong2 ()
|
|
|
|
{
|
|
|
|
Stop ();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MUSSong2::IsMIDI () const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MUSSong2::IsValid () const
|
|
|
|
{
|
|
|
|
return MusBuffer != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MUSSong2::Play (bool looping)
|
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
UINT dev_id;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
m_Status = STATE_Stopped;
|
|
|
|
m_Looping = looping;
|
2008-03-04 06:36:23 +00:00
|
|
|
EndQueued = false;
|
|
|
|
VolumeChanged = false;
|
|
|
|
Restarting = false;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
dev_id = MAX(mididevice, 0u);
|
|
|
|
if (MMSYSERR_NOERROR != midiStreamOpen(&MidiOut, &dev_id, 1, (DWORD_PTR)Callback, (DWORD_PTR)this, CALLBACK_FUNCTION))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
Printf(PRINT_BOLD, "Could not open MIDI out device\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set time division and tempo.
|
|
|
|
MIDIPROPTIMEDIV timediv = { sizeof(MIDIPROPTIMEDIV), 140 };
|
|
|
|
MIDIPROPTEMPO tempo = { sizeof(MIDIPROPTEMPO), 1000000 };
|
|
|
|
|
|
|
|
if (MMSYSERR_NOERROR != midiStreamProperty(MidiOut, (LPBYTE)&timediv, MIDIPROP_SET | MIDIPROP_TIMEDIV) ||
|
|
|
|
MMSYSERR_NOERROR != midiStreamProperty(MidiOut, (LPBYTE)&tempo, MIDIPROP_SET | MIDIPROP_TEMPO))
|
|
|
|
{
|
|
|
|
Printf(PRINT_BOLD, "Setting MIDI stream speed failed\n");
|
|
|
|
midiStreamClose(MidiOut);
|
|
|
|
MidiOut = NULL;
|
2006-02-24 04:48:15 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try two different methods for setting the stream to full volume.
|
|
|
|
// Unfortunately, this isn't as reliable as it once was, which is a pity.
|
|
|
|
// The real volume selection is done by setting the volume controller for
|
|
|
|
// each channel. Because every General MIDI-compliant device must support
|
|
|
|
// this controller, it is the most reliable means of setting the volume.
|
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
VolumeWorks = (MMSYSERR_NOERROR == midiOutGetVolume((HMIDIOUT)MidiOut, &SavedVolume));
|
2006-02-24 04:48:15 +00:00
|
|
|
if (VolumeWorks)
|
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
VolumeWorks &= (MMSYSERR_NOERROR == midiOutSetVolume((HMIDIOUT)MidiOut, 0xffffffff));
|
|
|
|
}
|
|
|
|
if (!VolumeWorks)
|
|
|
|
{ // Send the standard SysEx message for full master volume
|
|
|
|
memset(&Buffer[0], 0, sizeof(Buffer[0]));
|
|
|
|
Buffer[0].lpData = (LPSTR)&FullVolEvent;
|
|
|
|
Buffer[0].dwBufferLength = sizeof(FullVolEvent);
|
|
|
|
Buffer[0].dwBytesRecorded = sizeof(FullVolEvent);
|
|
|
|
|
|
|
|
if (MMSYSERR_NOERROR == midiOutPrepareHeader((HMIDIOUT)MidiOut, &Buffer[0], sizeof(Buffer[0])))
|
|
|
|
{
|
|
|
|
midiStreamOut(MidiOut, &Buffer[0], sizeof(Buffer[0]));
|
|
|
|
}
|
|
|
|
BufferNum = 1;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
BufferNum = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
snd_midivolume.Callback(); // set volume to current music's properties
|
|
|
|
for (int i = 0; i < 16; ++i)
|
|
|
|
{
|
|
|
|
LastVelocity[i] = 64;
|
|
|
|
ChannelVolumes[i] = 127;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
// Fill the initial buffers for the song.
|
|
|
|
do
|
|
|
|
{
|
|
|
|
int res = FillBuffer(BufferNum, MAX_EVENTS, MAX_TIME);
|
|
|
|
if (res == SONG_MORE)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
if (MMSYSERR_NOERROR != midiStreamOut(MidiOut, &Buffer[BufferNum], sizeof(Buffer[0])))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
Stop();
|
|
|
|
return;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-03-04 06:36:23 +00:00
|
|
|
BufferNum ^= 1;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-03-04 06:36:23 +00:00
|
|
|
else if (res == SONG_DONE)
|
|
|
|
{
|
|
|
|
if (looping)
|
|
|
|
{
|
|
|
|
MusP = 0;
|
|
|
|
if (SONG_MORE == FillBuffer(BufferNum, MAX_EVENTS, MAX_TIME))
|
|
|
|
{
|
|
|
|
if (MMSYSERR_NOERROR != midiStreamOut(MidiOut, &Buffer[BufferNum], sizeof(MIDIHDR)))
|
|
|
|
{
|
|
|
|
Stop();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
BufferNum ^= 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Stop();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
EndQueued = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
Stop();
|
|
|
|
return;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
2008-03-04 06:36:23 +00:00
|
|
|
while (BufferNum != 0);
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
if (MMSYSERR_NOERROR != midiStreamRestart(MidiOut))
|
|
|
|
{
|
|
|
|
Stop();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_Status = STATE_Playing;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MUSSong2::Pause ()
|
|
|
|
{
|
|
|
|
if (m_Status == STATE_Playing)
|
|
|
|
{
|
|
|
|
m_Status = STATE_Paused;
|
2008-03-04 06:36:23 +00:00
|
|
|
OutputVolume(0);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MUSSong2::Resume ()
|
|
|
|
{
|
|
|
|
if (m_Status == STATE_Paused)
|
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
OutputVolume(midivolume & 0xffff);
|
2006-02-24 04:48:15 +00:00
|
|
|
m_Status = STATE_Playing;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MUSSong2::Stop ()
|
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
EndQueued = 2;
|
2006-02-24 04:48:15 +00:00
|
|
|
if (MidiOut)
|
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
midiStreamStop(MidiOut);
|
|
|
|
midiOutReset((HMIDIOUT)MidiOut);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (VolumeWorks)
|
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
midiOutSetVolume((HMIDIOUT)MidiOut, SavedVolume);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-03-04 06:36:23 +00:00
|
|
|
midiOutUnprepareHeader((HMIDIOUT)MidiOut, &Buffer[0], sizeof(MIDIHDR));
|
|
|
|
midiOutUnprepareHeader((HMIDIOUT)MidiOut, &Buffer[1], sizeof(MIDIHDR));
|
|
|
|
midiStreamClose(MidiOut);
|
2006-02-24 04:48:15 +00:00
|
|
|
MidiOut = NULL;
|
|
|
|
}
|
2008-03-04 06:36:23 +00:00
|
|
|
m_Status = STATE_Stopped;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool MUSSong2::IsPlaying ()
|
|
|
|
{
|
|
|
|
return m_Status != STATE_Stopped;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MUSSong2::SetVolume (float volume)
|
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
OutputVolume(midivolume & 0xffff);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
void MUSSong2::OutputVolume (DWORD volume)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
NewVolume = volume;
|
|
|
|
VolumeChanged = true;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
void CALLBACK MUSSong2::Callback(HMIDIOUT hOut, UINT uMsg, DWORD_PTR dwInstance, DWORD dwParam1, DWORD dwParam2)
|
|
|
|
{
|
|
|
|
MUSSong2 *self = (MUSSong2 *)dwInstance;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
if (self->EndQueued > 1)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
return;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-03-04 06:36:23 +00:00
|
|
|
if (uMsg == MOM_DONE)
|
|
|
|
{
|
|
|
|
SetEvent(MusicEvent);
|
|
|
|
}
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
void MUSSong2::ServiceEvent()
|
|
|
|
{
|
|
|
|
if (EndQueued == 1)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
Stop();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (MMSYSERR_NOERROR != midiOutUnprepareHeader((HMIDIOUT)MidiOut, &Buffer[BufferNum], sizeof(MIDIHDR)))
|
|
|
|
{
|
|
|
|
Printf ("Failed unpreparing MIDI header.\n");
|
|
|
|
Stop();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
fill:
|
|
|
|
switch (FillBuffer(BufferNum, MAX_EVENTS, MAX_TIME))
|
|
|
|
{
|
|
|
|
case SONG_MORE:
|
|
|
|
if (MMSYSERR_NOERROR != midiStreamOut(MidiOut, &Buffer[BufferNum], sizeof(MIDIHDR)))
|
|
|
|
{
|
|
|
|
Printf ("Failed streaming MIDI buffer.\n");
|
|
|
|
Stop();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BufferNum ^= 1;
|
|
|
|
}
|
|
|
|
break;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
case SONG_DONE:
|
|
|
|
if (m_Looping)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
MusP = 0;
|
|
|
|
Restarting = true;
|
|
|
|
goto fill;
|
|
|
|
}
|
|
|
|
EndQueued = 1;
|
|
|
|
break;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
default:
|
|
|
|
Stop();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
// Returns SONG_MORE if the buffer was prepared with data.
|
|
|
|
// Returns SONG_DONE if the song's end was reached. The buffer will never have data in this case.
|
|
|
|
// Returns SONG_ERROR if there was a problem preparing the buffer.
|
|
|
|
int MUSSong2::FillBuffer(int buffer_num, int max_events, DWORD max_time)
|
|
|
|
{
|
|
|
|
if (MusP >= MaxMusP)
|
|
|
|
{
|
|
|
|
return SONG_DONE;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
int i = 0;
|
|
|
|
SHORTMIDIEVENT *events = Events[buffer_num];
|
|
|
|
DWORD tot_time = 0;
|
|
|
|
DWORD time = 0;
|
|
|
|
|
|
|
|
// If the volume has changed, stick those events at the start of this buffer.
|
|
|
|
if (VolumeChanged)
|
|
|
|
{
|
|
|
|
VolumeChanged = false;
|
|
|
|
for (; i < 16; ++i)
|
|
|
|
{
|
|
|
|
BYTE courseVol = (BYTE)(((ChannelVolumes[i]+1) * NewVolume) >> 16);
|
|
|
|
events[i].dwDeltaTime = 0;
|
|
|
|
events[i].dwStreamID = 0;
|
|
|
|
events[i].dwEvent = MEVT_SHORTMSG | MIDI_CTRLCHANGE | i | (7<<8) | (courseVol<<16);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
// If the song is starting over, stop all notes in case any were left hanging.
|
|
|
|
if (Restarting)
|
|
|
|
{
|
|
|
|
Restarting = false;
|
|
|
|
for (int j = 0; j < 16; ++i, ++j)
|
|
|
|
{
|
|
|
|
events[i].dwDeltaTime = 0;
|
|
|
|
events[i].dwStreamID = 0;
|
|
|
|
events[i].dwEvent = MEVT_SHORTMSG | MIDI_NOTEOFF | i | (60 << 8) | (64<<16);
|
|
|
|
}
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
// Play nothing while paused.
|
|
|
|
if (m_Status == STATE_Paused)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
time = max_time;
|
|
|
|
goto end;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
// The final event is for a NOP to hold the delay from the last event.
|
|
|
|
max_events--;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
for (; i < max_events && tot_time <= max_time; ++i)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
BYTE mid1, mid2;
|
|
|
|
BYTE channel;
|
|
|
|
BYTE t = 0, status;
|
2008-03-04 06:36:23 +00:00
|
|
|
BYTE event = MusBuffer[MusP++];
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
if ((event & 0x70) != MUS_SCOREEND)
|
|
|
|
{
|
|
|
|
t = MusBuffer[MusP++];
|
|
|
|
}
|
|
|
|
channel = event & 15;
|
|
|
|
|
|
|
|
// Map MUS channels to MIDI channels
|
|
|
|
if (channel == 15)
|
|
|
|
{
|
|
|
|
channel = 9;
|
|
|
|
}
|
|
|
|
else if (channel >= 9)
|
|
|
|
{
|
|
|
|
channel = channel + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = channel;
|
|
|
|
|
|
|
|
switch (event & 0x70)
|
|
|
|
{
|
|
|
|
case MUS_NOTEOFF:
|
|
|
|
status |= MIDI_NOTEOFF;
|
|
|
|
mid1 = t;
|
|
|
|
mid2 = 64;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MUS_NOTEON:
|
|
|
|
status |= MIDI_NOTEON;
|
|
|
|
mid1 = t & 127;
|
|
|
|
if (t & 128)
|
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
LastVelocity[channel] = MusBuffer[MusP++];
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
mid2 = LastVelocity[channel];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MUS_PITCHBEND:
|
|
|
|
status |= MIDI_PITCHBEND;
|
|
|
|
mid1 = (t & 1) << 6;
|
|
|
|
mid2 = (t >> 1) & 127;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MUS_SYSEVENT:
|
|
|
|
status |= MIDI_CTRLCHANGE;
|
|
|
|
mid1 = CtrlTranslate[t];
|
|
|
|
mid2 = t == 12 ? LittleShort(MusHeader->NumChans) : 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MUS_CTRLCHANGE:
|
|
|
|
if (t == 0)
|
|
|
|
{ // program change
|
|
|
|
status |= MIDI_PRGMCHANGE;
|
|
|
|
mid1 = MusBuffer[MusP++];
|
|
|
|
mid2 = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
status |= MIDI_CTRLCHANGE;
|
|
|
|
mid1 = CtrlTranslate[t];
|
|
|
|
mid2 = MusBuffer[MusP++];
|
|
|
|
|
|
|
|
// Some devices don't support master volume
|
|
|
|
// (e.g. the Audigy's software MIDI synth--but not its two hardware ones),
|
|
|
|
// so assume none of them do and scale channel volumes manually.
|
|
|
|
if (mid1 == 7)
|
|
|
|
{
|
|
|
|
ChannelVolumes[channel] = mid2;
|
|
|
|
mid2 = (BYTE)(((mid2 + 1) * (midivolume & 0xffff)) >> 16);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MUS_SCOREEND:
|
|
|
|
default:
|
2008-03-04 06:36:23 +00:00
|
|
|
MusP = MaxMusP;
|
|
|
|
goto end;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
2008-03-04 06:36:23 +00:00
|
|
|
events[i].dwDeltaTime = time;
|
|
|
|
events[i].dwStreamID = 0;
|
|
|
|
events[i].dwEvent = MEVT_SHORTMSG | status | (mid1 << 8) | (mid2 << 16);
|
|
|
|
|
|
|
|
time = 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
if (event & 128)
|
|
|
|
{
|
2008-03-04 06:36:23 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
t = MusBuffer[MusP++];
|
|
|
|
time = (time << 7) | (t & 127);
|
|
|
|
}
|
|
|
|
while (t & 128);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-03-04 06:36:23 +00:00
|
|
|
tot_time += time;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-03-04 06:36:23 +00:00
|
|
|
end:
|
|
|
|
if (time != 0)
|
|
|
|
{
|
|
|
|
events[i].dwDeltaTime = time;
|
|
|
|
events[i].dwStreamID = 0;
|
|
|
|
events[i].dwEvent = MEVT_NOP;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
memset(&Buffer[buffer_num], 0, sizeof(MIDIHDR));
|
|
|
|
Buffer[buffer_num].lpData = (LPSTR)events;
|
|
|
|
Buffer[buffer_num].dwBufferLength = sizeof(events[0]) * i;
|
|
|
|
Buffer[buffer_num].dwBytesRecorded = sizeof(events[0]) * i;
|
|
|
|
if (MMSYSERR_NOERROR != midiOutPrepareHeader((HMIDIOUT)MidiOut, &Buffer[buffer_num], sizeof(MIDIHDR)))
|
|
|
|
{
|
|
|
|
Printf ("Preparing MIDI header failed.\n");
|
|
|
|
return SONG_ERROR;
|
|
|
|
}
|
|
|
|
return SONG_MORE;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
#endif
|