mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-01-18 15:42:34 +00:00
- Reimplemented snd_midiprecache, now for MIDI as well as MUS, and
defaulting to false. SVN r895 (trunk)
This commit is contained in:
parent
894b663877
commit
68e4b3d946
11 changed files with 304 additions and 11 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ typedef struct
|
|||
WORD NumSecondaryChans;
|
||||
WORD NumInstruments;
|
||||
WORD Pad;
|
||||
// WORD UsedInstruments[NumInstruments];
|
||||
} MUSHeader;
|
||||
|
||||
bool ProduceMIDI (const BYTE *musBuf, TArray<BYTE> &outFile);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 : "");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
84
zdoom.vcproj
84
zdoom.vcproj
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue