- Reimplemented snd_midiprecache, now for MIDI as well as MUS, and

defaulting to false.


SVN r895 (trunk)
This commit is contained in:
Randy Heit 2008-04-09 03:55:04 +00:00
parent 894b663877
commit 68e4b3d946
11 changed files with 304 additions and 11 deletions

View file

@ -1,3 +1,7 @@
April 8, 2008
- Reimplemented snd_midiprecache, now for MIDI as well as MUS, and
defaulting to false.
April 8, 2008 (Changes by Graf Zahl)
- Eliminated all use of global variables used as output for P_CheckPosition
and P_TryMove. Moved BlockingLine and BlockingMobj into AActor because

View file

@ -70,6 +70,8 @@ EXTERN_CVAR (Bool, snd_pitched)
EXTERN_CVAR (Color, am_wallcolor)
EXTERN_CVAR (Color, am_fdwallcolor)
EXTERN_CVAR (Color, am_cdwallcolor)
EXTERN_CVAR (Float, spc_amp)
EXTERN_CVAR (Bool, snd_midiprecache)
FString WeaponSection;
@ -297,14 +299,15 @@ void FGameConfigFile::DoGlobalSetup ()
}
if (last < 206)
{ // spc_amp is now a float, not an int.
FBaseCVar *amp = FindCVar ("spc_amp", NULL);
if (amp != NULL)
if (spc_amp > 16)
{
UCVarValue val = amp->GetGenericRep(CVAR_Float);
val.Float /= 16.f;
amp->SetGenericRep(val, CVAR_Float);
spc_amp = spc_amp / 16.f;
}
}
if (last < 207)
{ // Now that snd_midiprecache works again, you probably don't want it on.
snd_midiprecache = false;
}
}
}
}

View file

@ -71,6 +71,7 @@ typedef struct
WORD NumSecondaryChans;
WORD NumInstruments;
WORD Pad;
// WORD UsedInstruments[NumInstruments];
} MUSHeader;
bool ProduceMIDI (const BYTE *musBuf, TArray<BYTE> &outFile);

View file

@ -112,6 +112,7 @@ public:
virtual bool FakeVolume() = 0;
virtual bool Pause(bool paused) = 0;
virtual bool NeedThreadedCallback() = 0;
virtual void PrecacheInstruments(const BYTE *instruments, int count);
};
// WinMM implementation of a MIDI output device -----------------------------
@ -137,6 +138,7 @@ public:
bool FakeVolume();
bool NeedThreadedCallback();
bool Pause(bool paused);
void PrecacheInstruments(const BYTE *instruments, int count);
protected:
static void CALLBACK CallbackFunc(HMIDIOUT, UINT, DWORD_PTR, DWORD, DWORD);
@ -236,6 +238,7 @@ protected:
virtual void DoInitialSetup() = 0;
virtual void DoRestart() = 0;
virtual bool CheckDone() = 0;
virtual void Precache() = 0;
virtual DWORD *MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time) = 0;
enum
@ -294,6 +297,7 @@ protected:
void DoInitialSetup();
void DoRestart();
bool CheckDone();
void Precache();
DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time);
MUSHeader *MusHeader;
@ -319,6 +323,7 @@ protected:
void DoInitialSetup();
void DoRestart();
bool CheckDone();
void Precache();
DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time);
void AdvanceTracks(DWORD time);

View file

@ -12,8 +12,6 @@ static bool nummididevicesset;
#ifdef _WIN32
UINT mididevice;
CVAR (Bool, snd_midiprecache, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CUSTOM_CVAR (Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
UINT oldmididev = mididevice;
@ -155,8 +153,9 @@ CCMD (snd_listmididevices)
MIDIOUTCAPS caps;
MMRESULT res;
PrintMidiDevice (-2, "TiMidity++", 0, 0);
PrintMidiDevice (-1, "FMOD", 0, 0);
PrintMidiDevice (-3, "Emulated OPL FM Synth", MOD_FMSYNTH, 0);
PrintMidiDevice (-2, "TiMidity++", 0, MOD_WAVETABLE | MOD_SWSYNTH);
PrintMidiDevice (-1, "FMOD", 0, MOD_WAVETABLE | MOD_SWSYNTH);
if (nummididevices != 0)
{
for (id = 0; id < nummididevices; ++id)
@ -206,6 +205,7 @@ void I_BuildMIDIMenuList (struct value_t **outValues, float *numValues)
CCMD (snd_listmididevices)
{
Printf("%s-3. Emulated OPL FM Synth\n", -3 == snd_mididevice ? TEXTCOLOR_BOLD : "");
Printf("%s-2. TiMidity++\n", -2 == snd_mididevice ? TEXTCOLOR_BOLD : "");
Printf("%s-1. FMOD\n", -1 == snd_mididevice ? TEXTCOLOR_BOLD : "");
}

View file

@ -754,6 +754,96 @@ void MIDISong2::SetTempo(int new_tempo)
}
}
//==========================================================================
//
// MIDISong2 :: Precache
//
// Scans each track for program change events on normal channels and note on
// events on channel 10. Does not care about bank selects, since they're
// unlikely to appear in a song aimed at Doom.
//
//==========================================================================
void MIDISong2::Precache()
{
int i, j;
// This array keeps track of instruments that are used. The first 128
// entries are for melodic instruments. The second 128 are for
// percussion.
BYTE found_instruments[256] = { 0, };
DoRestart();
for (i = 0; i < NumTracks; ++i)
{
TrackInfo *track = &Tracks[i];
BYTE running_status = 0;
BYTE ev, data1, data2, command, channel;
int len;
while (track->TrackP < track->MaxTrackP)
{
ev = track->TrackBegin[track->TrackP++];
command = ev & 0xF0;
if (command == MIDI_SYSEX || command == MIDI_SYSEXEND)
{
len = track->ReadVarLen();
track->TrackP += len;
}
else if (command == MIDI_META)
{
track->TrackP++;
len = track->ReadVarLen();
track->TrackP += len;
}
else if ((command & 0xF0) == 0xF0)
{
track->TrackP += CommonLengths[ev & 0xF];
}
else
{
if ((ev & 0x80) == 0)
{ // Use running status.
data1 = ev;
ev = running_status;
}
else
{ // Store new running status.
running_status = ev;
data1 = track->TrackBegin[track->TrackP++];
}
command = ev & 0x70;
channel = ev & 0x0F;
if (EventLengths[command >> 4] == 2)
{
data2 = track->TrackBegin[track->TrackP++];
}
if (channel != 9 && command == (MIDI_PRGMCHANGE & 0x70))
{
found_instruments[data1 & 127] = 1;
}
else if (channel == 9 && command == (MIDI_NOTEON & 0x70) && data2 != 0)
{
found_instruments[data1 | 128] = 1;
}
track->ReadVarLen(); // Skip delay.
}
}
}
DoRestart();
// Now pack everything into a contiguous region for the PrecacheInstruments call().
for (i = j = 0; i < 256; ++i)
{
if (found_instruments[i])
{
found_instruments[j++] = i;
}
}
MIDI->PrecacheInstruments(found_instruments, j);
}
//==========================================================================
//
// MIDISong2 :: GetOPLDumper

View file

@ -221,6 +221,7 @@ void MIDIStreamer::Play(bool looping)
}
CheckCaps();
Precache();
// Set time division and tempo.
if (0 != MIDI->SetTimeDiv(Division) ||
@ -301,7 +302,8 @@ void MIDIStreamer::Play(bool looping)
// MIDIStreamer :: Pause
//
// "Pauses" the song by setting it to zero volume and filling subsequent
// buffers with NOPs until the song is unpaused.
// buffers with NOPs until the song is unpaused. A MIDI device that
// supports real pauses will return true from its Pause() method.
//
//==========================================================================
@ -711,3 +713,22 @@ MIDIDevice::MIDIDevice()
MIDIDevice::~MIDIDevice()
{
}
//==========================================================================
//
// MIDIDevice :: PrecacheInstruments
//
// The MIDIStreamer calls this method between device open and the first
// buffered stream with a list of instruments known to be used by the song.
// If the device can benefit from preloading the instruments, it can do so
// now.
//
// For each entry, bit 7 set indicates that the instrument is percussion and
// the lower 7 bits contain the note number to use on MIDI channel 10,
// otherwise it is melodic and the lower 7 bits are the program number.
//
//==========================================================================
void MIDIDevice::PrecacheInstruments(const BYTE *instruments, int count)
{
}

View file

@ -179,6 +179,34 @@ bool MUSSong2::CheckDone()
return MusP >= MaxMusP;
}
//==========================================================================
//
// MUSSong2 :: Precache
//
// MUS songs contain information in their header for exactly this purpose.
//
//==========================================================================
void MUSSong2::Precache()
{
BYTE *work = (BYTE *)alloca(MusHeader->NumInstruments);
const WORD *used = (WORD *)MusHeader + sizeof(MUSHeader) / 2;
int i, j;
for (i = j = 0; i < MusHeader->NumInstruments; ++i)
{
if (used[i] < 128)
{
work[j++] = used[i];
}
else if (used[i] >= 135 && used[i] <= 181)
{ // Percussions are 100-based, not 128-based, eh?
work[j++] = (used[i] - 100) | 0x80;
}
}
MIDI->PrecacheInstruments(&work[0], j);
}
//==========================================================================
//
// MUSSong2 :: MakeEvents

View file

@ -55,6 +55,8 @@
// PUBLIC DATA DEFINITIONS -------------------------------------------------
CVAR (Bool, snd_midiprecache, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
// CODE --------------------------------------------------------------------
//==========================================================================
@ -203,6 +205,61 @@ void WinMIDIDevice::Stop()
}
}
//==========================================================================
//
// WinMIDIDevice :: PrecacheInstruments
//
// For each entry, bit 7 set indicates that the instrument is percussion and
// the lower 7 bits contain the note number to use on MIDI channel 10,
// otherwise it is melodic and the lower 7 bits are the program number.
//
// My old GUS PnP needed the instruments to be preloaded, or it would miss
// some notes the first time through the song. I doubt any modern
// hardware has this problem, but since I'd already written the code for
// ZDoom 1.22 and below, I'm resurrecting it now for completeness, since I'm
// using preloading for the internal Timidity.
//
//==========================================================================
void WinMIDIDevice::PrecacheInstruments(const BYTE *instruments, int count)
{
// Setting snd_midiprecache to false disables this precaching, since it
// does involve sleeping for more than a miniscule amount of time.
if (!snd_midiprecache)
{
return;
}
for (int i = 0, chan = 0; i < count; ++i)
{
if (instruments[i] & 0x80)
{ // Percussion
midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_NOTEON | 9 | ((instruments[i] & 0x7f) << 8) | (1 << 16));
}
else
{ // Melodic
midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_PRGMCHANGE | chan | (instruments[i] << 8));
midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_NOTEON | chan | (60 << 8) | (1 << 16));
if (++chan == 9)
{ // Skip the percussion channel
chan = 10;
}
}
// Once we've got an instrument playing on each melodic channel, sleep to give
// the driver time to load the instruments. Also do this for the final batch
// of instruments.
if (chan == 16 || i == count - 1)
{
Sleep(250);
for (chan = 15; chan-- != 0; )
{
// Turn all notes off
midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_CTRLCHANGE | chan | (123 << 8));
}
// And now chan is back at 0, ready to start the cycle over.
}
}
}
//==========================================================================
//
// WinMIDIDevice :: Pause

View file

@ -59,7 +59,7 @@
// Version stored in the ini's [LastRun] section.
// Bump it if you made some configuration change that you want to
// be able to migrate in FGameConfigFile::DoGlobalSetup().
#define LASTRUNVERSION "206"
#define LASTRUNVERSION "207"
// Protocol version used in demos.
// Bump it if you change existing DEM_ commands or add new ones.

View file

@ -2920,6 +2920,90 @@
>
</File>
</Filter>
<Filter
Name="Timidity"
>
<File
RelativePath=".\src\timidity\common.cpp"
>
</File>
<File
RelativePath=".\src\timidity\dls1.h"
>
</File>
<File
RelativePath=".\src\timidity\dls2.h"
>
</File>
<File
RelativePath=".\src\timidity\instrum.cpp"
>
</File>
<File
RelativePath=".\src\timidity\instrum_dls.cpp"
>
</File>
<File
RelativePath=".\src\timidity\mix.cpp"
>
</File>
<File
RelativePath=".\src\timidity\playmidi.cpp"
>
</File>
<File
RelativePath=".\src\timidity\resample.cpp"
>
</File>
<File
RelativePath=".\src\timidity\tables.cpp"
>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\src\timidity\timidity.cpp"
>
</File>
<File
RelativePath=".\src\timidity\timidity.h"
>
</File>
</Filter>
</Filter>
<Filter
Name="SDL Files"