mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-10 23:01:50 +00:00
- Did some restructuring of the OPL code in preparation for turning it
into a general MIDI player. - Fixed: Passing false for a stream callback did not stop the stream. - Removed opl_frequency, since the only time the emulation sounds good is when it plays at the exact frequency of a real chip. - Music no longer plays at all when snd_musicvolume is 0. - Bumped up snd_sfxvolume and snd_musicvolume default values. SVN r862 (trunk)
This commit is contained in:
parent
776d89428d
commit
938ae1767b
11 changed files with 243 additions and 163 deletions
|
@ -1,4 +1,11 @@
|
||||||
March 27, 2008
|
March 27, 2008
|
||||||
|
- Did some restructuring of the OPL code in preparation for turning it
|
||||||
|
into a general MIDI player.
|
||||||
|
- Fixed: Passing false for a stream callback did not stop the stream.
|
||||||
|
- Removed opl_frequency, since the only time the emulation sounds good is
|
||||||
|
when it plays at the exact frequency of a real chip.
|
||||||
|
- Music no longer plays at all when snd_musicvolume is 0.
|
||||||
|
- Bumped up snd_sfxvolume and snd_musicvolume default values.
|
||||||
- Changed D3DFB to explicitly request double buffering instead of assuming
|
- Changed D3DFB to explicitly request double buffering instead of assuming
|
||||||
that the drivers will treat a BackBufferCount of 0 as a request for
|
that the drivers will treat a BackBufferCount of 0 as a request for
|
||||||
double buffering.
|
double buffering.
|
||||||
|
|
|
@ -1270,26 +1270,13 @@ static menu_t SoundMenu =
|
||||||
*=======================================*/
|
*=======================================*/
|
||||||
|
|
||||||
EXTERN_CVAR (Bool, opl_enable)
|
EXTERN_CVAR (Bool, opl_enable)
|
||||||
EXTERN_CVAR (Int, opl_frequency)
|
|
||||||
EXTERN_CVAR (Bool, opl_onechip)
|
EXTERN_CVAR (Bool, opl_onechip)
|
||||||
|
|
||||||
static value_t OPLSampleRates[] =
|
|
||||||
{
|
|
||||||
{ 4000.f, "4000 Hz" },
|
|
||||||
{ 6215.f, "6215 Hz" },
|
|
||||||
{ 12429.f, "12429 Hz" },
|
|
||||||
{ 24858.f, "24858 Hz" },
|
|
||||||
{ 49716.f, "49716 Hz" },
|
|
||||||
};
|
|
||||||
|
|
||||||
static menuitem_t AdvSoundItems[] =
|
static menuitem_t AdvSoundItems[] =
|
||||||
{
|
{
|
||||||
{ whitetext,"OPL Synthesis", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
|
{ whitetext,"OPL Synthesis", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
|
||||||
{ discrete, "Use FM Synth for MUS music",{&opl_enable}, {2.0}, {0.0}, {0.0}, {OnOff} },
|
{ discrete, "Use FM Synth for MUS music",{&opl_enable}, {2.0}, {0.0}, {0.0}, {OnOff} },
|
||||||
{ discrete, "Only emulate one OPL chip", {&opl_onechip}, {2.0}, {0.0}, {0.0}, {OnOff} },
|
{ discrete, "Only emulate one OPL chip", {&opl_onechip}, {2.0}, {0.0}, {0.0}, {OnOff} },
|
||||||
{ discrete, "OPL synth sample rate", {&opl_frequency}, {5.0}, {0.0}, {0.0}, {OPLSampleRates} },
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static menu_t AdvSoundMenu =
|
static menu_t AdvSoundMenu =
|
||||||
|
|
|
@ -15,21 +15,21 @@
|
||||||
#include "v_text.h"
|
#include "v_text.h"
|
||||||
#include "c_dispatch.h"
|
#include "c_dispatch.h"
|
||||||
|
|
||||||
#define IMF_RATE 700
|
#define IMF_RATE 700.0
|
||||||
|
|
||||||
EXTERN_CVAR (Bool, opl_onechip)
|
EXTERN_CVAR (Bool, opl_onechip)
|
||||||
|
|
||||||
static OPLmusicBlock *BlockForStats;
|
static OPLmusicBlock *BlockForStats;
|
||||||
|
|
||||||
OPLmusicBlock::OPLmusicBlock (FILE *file, char * musiccache, int len, int rate, int maxSamples)
|
OPLmusicBlock::OPLmusicBlock()
|
||||||
: SampleRate (rate), NextTickIn (0), Looping (false), ScoreLen (len)
|
|
||||||
{
|
{
|
||||||
scoredata = NULL;
|
scoredata = NULL;
|
||||||
SampleBuff = NULL;
|
SampleBuff = NULL;
|
||||||
SampleBuffSize = 0;
|
SampleBuffSize = 0;
|
||||||
|
NextTickIn = 0;
|
||||||
TwoChips = !opl_onechip;
|
TwoChips = !opl_onechip;
|
||||||
io = new OPLio;
|
Looping = false;
|
||||||
|
io = NULL;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
InitializeCriticalSection (&ChipAccess);
|
InitializeCriticalSection (&ChipAccess);
|
||||||
#else
|
#else
|
||||||
|
@ -39,96 +39,12 @@ OPLmusicBlock::OPLmusicBlock (FILE *file, char * musiccache, int len, int rate,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
io = new OPLio;
|
||||||
scoredata = new BYTE[len];
|
|
||||||
|
|
||||||
if (file)
|
|
||||||
{
|
|
||||||
if (fread (scoredata, 1, len, file) != (size_t)len)
|
|
||||||
{
|
|
||||||
delete[] scoredata;
|
|
||||||
scoredata = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(scoredata, &musiccache[0], len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (io->OPLinit (TwoChips + 1, rate))
|
|
||||||
{
|
|
||||||
delete[] scoredata;
|
|
||||||
scoredata = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for MUS format
|
|
||||||
if (*(DWORD *)scoredata == MAKE_ID('M','U','S',0x1a))
|
|
||||||
{
|
|
||||||
FWadLump data = Wads.OpenLumpName ("GENMIDI");
|
|
||||||
if (0 != OPLloadBank (data))
|
|
||||||
{
|
|
||||||
delete[] scoredata;
|
|
||||||
scoredata = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
BlockForStats = this;
|
|
||||||
SamplesPerTick = ((rate/14)+5)/10; // round to nearest, not lowest
|
|
||||||
RawPlayer = NotRaw;
|
|
||||||
}
|
|
||||||
// Check for RDosPlay raw OPL format
|
|
||||||
else if (((DWORD *)scoredata)[0] == MAKE_ID('R','A','W','A') &&
|
|
||||||
((DWORD *)scoredata)[1] == MAKE_ID('D','A','T','A'))
|
|
||||||
{
|
|
||||||
RawPlayer = RDosPlay;
|
|
||||||
if (*(WORD *)(scoredata + 8) == 0)
|
|
||||||
{ // A clock speed of 0 is bad
|
|
||||||
*(WORD *)(scoredata + 8) = 0xFFFF;
|
|
||||||
}
|
|
||||||
SamplesPerTick = Scale (rate, LittleShort(*(WORD *)(scoredata + 8)), 1193180);
|
|
||||||
}
|
|
||||||
// Check for modified IMF format (includes a header)
|
|
||||||
else if (((DWORD *)scoredata)[0] == MAKE_ID('A','D','L','I') &&
|
|
||||||
scoredata[4] == 'B' && scoredata[5] == 1)
|
|
||||||
{
|
|
||||||
int songlen;
|
|
||||||
BYTE *max = scoredata + ScoreLen;
|
|
||||||
RawPlayer = IMF;
|
|
||||||
SamplesPerTick = rate / IMF_RATE;
|
|
||||||
|
|
||||||
score = scoredata + 6;
|
|
||||||
// Skip track and game name
|
|
||||||
for (int i = 2; i != 0; --i)
|
|
||||||
{
|
|
||||||
while (score < max && *score++ != '\0') {}
|
|
||||||
}
|
|
||||||
if (score < max) score++; // Skip unknown byte
|
|
||||||
if (score + 8 > max)
|
|
||||||
{ // Not enough room left for song data
|
|
||||||
delete[] scoredata;
|
|
||||||
scoredata = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
songlen = LittleLong(*(DWORD *)score);
|
|
||||||
if (songlen != 0 && (songlen +=4) < ScoreLen - (score - scoredata))
|
|
||||||
{
|
|
||||||
ScoreLen = songlen + int(score - scoredata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Restart ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OPLmusicBlock::~OPLmusicBlock()
|
OPLmusicBlock::~OPLmusicBlock()
|
||||||
{
|
{
|
||||||
BlockForStats = NULL;
|
BlockForStats = NULL;
|
||||||
if (scoredata != NULL)
|
|
||||||
{
|
|
||||||
io->OPLdeinit ();
|
|
||||||
delete[] scoredata;
|
|
||||||
scoredata = NULL;
|
|
||||||
}
|
|
||||||
if (SampleBuff != NULL)
|
if (SampleBuff != NULL)
|
||||||
{
|
{
|
||||||
delete[] SampleBuff;
|
delete[] SampleBuff;
|
||||||
|
@ -156,7 +72,7 @@ void OPLmusicBlock::ResetChips ()
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
io->OPLdeinit ();
|
io->OPLdeinit ();
|
||||||
io->OPLinit (TwoChips + 1, SampleRate);
|
io->OPLinit (TwoChips + 1, uint(OPL_SAMPLE_RATE));
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
LeaveCriticalSection (&ChipAccess);
|
LeaveCriticalSection (&ChipAccess);
|
||||||
#else
|
#else
|
||||||
|
@ -164,22 +80,125 @@ void OPLmusicBlock::ResetChips ()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OPLmusicBlock::IsValid () const
|
|
||||||
{
|
|
||||||
return scoredata != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OPLmusicBlock::SetLooping (bool loop)
|
|
||||||
{
|
|
||||||
Looping = loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OPLmusicBlock::Restart()
|
void OPLmusicBlock::Restart()
|
||||||
{
|
{
|
||||||
OPLstopMusic ();
|
OPLstopMusic ();
|
||||||
OPLplayMusic ();
|
OPLplayMusic ();
|
||||||
MLtime = 0;
|
MLtime = 0;
|
||||||
playingcount = 0;
|
playingcount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPLmusicFile::OPLmusicFile (FILE *file, char * musiccache, int len, int maxSamples)
|
||||||
|
: ScoreLen (len)
|
||||||
|
{
|
||||||
|
if (io == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scoredata = new BYTE[len];
|
||||||
|
|
||||||
|
if (file)
|
||||||
|
{
|
||||||
|
if (fread (scoredata, 1, len, file) != (size_t)len)
|
||||||
|
{
|
||||||
|
delete[] scoredata;
|
||||||
|
scoredata = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(scoredata, &musiccache[0], len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (io->OPLinit (TwoChips + 1, uint(OPL_SAMPLE_RATE)))
|
||||||
|
{
|
||||||
|
delete[] scoredata;
|
||||||
|
scoredata = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for MUS format
|
||||||
|
if (*(DWORD *)scoredata == MAKE_ID('M','U','S',0x1a))
|
||||||
|
{
|
||||||
|
FWadLump data = Wads.OpenLumpName ("GENMIDI");
|
||||||
|
if (0 != OPLloadBank (data))
|
||||||
|
{
|
||||||
|
delete[] scoredata;
|
||||||
|
scoredata = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BlockForStats = this;
|
||||||
|
SamplesPerTick = OPL_SAMPLE_RATE / 140.0;
|
||||||
|
RawPlayer = NotRaw;
|
||||||
|
}
|
||||||
|
// Check for RDosPlay raw OPL format
|
||||||
|
else if (((DWORD *)scoredata)[0] == MAKE_ID('R','A','W','A') &&
|
||||||
|
((DWORD *)scoredata)[1] == MAKE_ID('D','A','T','A'))
|
||||||
|
{
|
||||||
|
RawPlayer = RDosPlay;
|
||||||
|
if (*(WORD *)(scoredata + 8) == 0)
|
||||||
|
{ // A clock speed of 0 is bad
|
||||||
|
*(WORD *)(scoredata + 8) = 0xFFFF;
|
||||||
|
}
|
||||||
|
SamplesPerTick = OPL_SAMPLE_RATE * LittleShort(*(WORD *)(scoredata + 8)) / 1193180.0;
|
||||||
|
}
|
||||||
|
// Check for modified IMF format (includes a header)
|
||||||
|
else if (((DWORD *)scoredata)[0] == MAKE_ID('A','D','L','I') &&
|
||||||
|
scoredata[4] == 'B' && scoredata[5] == 1)
|
||||||
|
{
|
||||||
|
int songlen;
|
||||||
|
BYTE *max = scoredata + ScoreLen;
|
||||||
|
RawPlayer = IMF;
|
||||||
|
SamplesPerTick = OPL_SAMPLE_RATE / IMF_RATE;
|
||||||
|
|
||||||
|
score = scoredata + 6;
|
||||||
|
// Skip track and game name
|
||||||
|
for (int i = 2; i != 0; --i)
|
||||||
|
{
|
||||||
|
while (score < max && *score++ != '\0') {}
|
||||||
|
}
|
||||||
|
if (score < max) score++; // Skip unknown byte
|
||||||
|
if (score + 8 > max)
|
||||||
|
{ // Not enough room left for song data
|
||||||
|
delete[] scoredata;
|
||||||
|
scoredata = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
songlen = LittleLong(*(DWORD *)score);
|
||||||
|
if (songlen != 0 && (songlen +=4) < ScoreLen - (score - scoredata))
|
||||||
|
{
|
||||||
|
ScoreLen = songlen + int(score - scoredata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Restart ();
|
||||||
|
}
|
||||||
|
|
||||||
|
OPLmusicFile::~OPLmusicFile ()
|
||||||
|
{
|
||||||
|
if (scoredata != NULL)
|
||||||
|
{
|
||||||
|
io->OPLdeinit ();
|
||||||
|
delete[] scoredata;
|
||||||
|
scoredata = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OPLmusicFile::IsValid () const
|
||||||
|
{
|
||||||
|
return scoredata != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OPLmusicFile::SetLooping (bool loop)
|
||||||
|
{
|
||||||
|
Looping = loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OPLmusicFile::Restart ()
|
||||||
|
{
|
||||||
|
OPLmusicBlock::Restart();
|
||||||
if (RawPlayer == NotRaw)
|
if (RawPlayer == NotRaw)
|
||||||
{
|
{
|
||||||
score = scoredata + ((MUSheader *)scoredata)->scoreStart;
|
score = scoredata + ((MUSheader *)scoredata)->scoreStart;
|
||||||
|
@ -187,7 +206,7 @@ void OPLmusicBlock::Restart ()
|
||||||
else if (RawPlayer == RDosPlay)
|
else if (RawPlayer == RDosPlay)
|
||||||
{
|
{
|
||||||
score = scoredata + 10;
|
score = scoredata + 10;
|
||||||
SamplesPerTick = Scale (SampleRate, LittleShort(*(WORD *)(scoredata + 8)), 1193180);
|
SamplesPerTick = OPL_SAMPLE_RATE * LittleShort(*(WORD *)(scoredata + 8)) / 1193180.0;
|
||||||
}
|
}
|
||||||
else if (RawPlayer == IMF)
|
else if (RawPlayer == IMF)
|
||||||
{
|
{
|
||||||
|
@ -234,7 +253,7 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes)
|
||||||
#endif
|
#endif
|
||||||
while (numsamples > 0)
|
while (numsamples > 0)
|
||||||
{
|
{
|
||||||
int samplesleft = MIN (numsamples, NextTickIn);
|
int samplesleft = MIN (numsamples, int(NextTickIn));
|
||||||
|
|
||||||
if (samplesleft > 0)
|
if (samplesleft > 0)
|
||||||
{
|
{
|
||||||
|
@ -249,7 +268,7 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes)
|
||||||
samples1 += samplesleft;
|
samples1 += samplesleft;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NextTickIn == 0)
|
if (NextTickIn < 1)
|
||||||
{
|
{
|
||||||
int next = PlayTick ();
|
int next = PlayTick ();
|
||||||
if (next == 0)
|
if (next == 0)
|
||||||
|
@ -277,7 +296,7 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
prevEnded = false;
|
prevEnded = false;
|
||||||
NextTickIn = SamplesPerTick * next;
|
NextTickIn += SamplesPerTick * next;
|
||||||
assert (NextTickIn >= 0);
|
assert (NextTickIn >= 0);
|
||||||
MLtime += next;
|
MLtime += next;
|
||||||
}
|
}
|
||||||
|
@ -371,7 +390,7 @@ done:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int OPLmusicBlock::PlayTick ()
|
int OPLmusicFile::PlayTick ()
|
||||||
{
|
{
|
||||||
BYTE reg, data;
|
BYTE reg, data;
|
||||||
|
|
||||||
|
@ -397,7 +416,7 @@ int OPLmusicBlock::PlayTick ()
|
||||||
case 2: // Speed change or OPL3 switch
|
case 2: // Speed change or OPL3 switch
|
||||||
if (data == 0)
|
if (data == 0)
|
||||||
{
|
{
|
||||||
SamplesPerTick = Scale (SampleRate, LittleShort(*(WORD *)(score)), 1193180);
|
SamplesPerTick = OPL_SAMPLE_RATE * LittleShort(*(WORD *)(score)) / 1193180.0;
|
||||||
score += 2;
|
score += 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -9,27 +9,26 @@
|
||||||
#include "muslib.h"
|
#include "muslib.h"
|
||||||
#include "files.h"
|
#include "files.h"
|
||||||
|
|
||||||
|
#define OPL_SAMPLE_RATE 49716.0
|
||||||
|
|
||||||
class OPLmusicBlock : public musicBlock
|
class OPLmusicBlock : public musicBlock
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OPLmusicBlock (FILE *file, char * musiccache, int len, int rate, int maxSamples);
|
OPLmusicBlock();
|
||||||
~OPLmusicBlock();
|
~OPLmusicBlock();
|
||||||
bool IsValid () const;
|
|
||||||
|
|
||||||
bool ServiceStream(void *buff, int numbytes);
|
bool ServiceStream(void *buff, int numbytes);
|
||||||
void Restart ();
|
|
||||||
void SetLooping (bool loop);
|
|
||||||
void ResetChips();
|
void ResetChips();
|
||||||
int PlayTick ();
|
|
||||||
|
virtual void Restart();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int SampleRate;
|
virtual int PlayTick() = 0;
|
||||||
int NextTickIn;
|
|
||||||
int SamplesPerTick;
|
double NextTickIn;
|
||||||
|
double SamplesPerTick;
|
||||||
bool TwoChips;
|
bool TwoChips;
|
||||||
bool Looping;
|
bool Looping;
|
||||||
enum { NotRaw, RDosPlay, IMF } RawPlayer;
|
|
||||||
int ScoreLen;
|
|
||||||
|
|
||||||
int *SampleBuff;
|
int *SampleBuff;
|
||||||
int SampleBuffSize;
|
int SampleBuffSize;
|
||||||
|
@ -40,3 +39,20 @@ protected:
|
||||||
SDL_mutex *ChipAccess;
|
SDL_mutex *ChipAccess;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class OPLmusicFile : public OPLmusicBlock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OPLmusicFile(FILE *file, char *musiccache, int len, int maxSamples);
|
||||||
|
~OPLmusicFile();
|
||||||
|
|
||||||
|
bool IsValid() const;
|
||||||
|
void SetLooping(bool loop);
|
||||||
|
void Restart();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int PlayTick();
|
||||||
|
|
||||||
|
enum { NotRaw, RDosPlay, IMF } RawPlayer;
|
||||||
|
int ScoreLen;
|
||||||
|
};
|
||||||
|
|
|
@ -1359,6 +1359,16 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
|
||||||
// shutdown old music
|
// shutdown old music
|
||||||
S_StopMusic (true);
|
S_StopMusic (true);
|
||||||
|
|
||||||
|
// Just record it if volume is 0
|
||||||
|
if (snd_musicvolume <= 0)
|
||||||
|
{
|
||||||
|
mus_playing.loop = looping;
|
||||||
|
mus_playing.name = "";
|
||||||
|
mus_playing.baseorder = 0;
|
||||||
|
LastSong = musicname;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// load & register it
|
// load & register it
|
||||||
if (offset != -1)
|
if (offset != -1)
|
||||||
{
|
{
|
||||||
|
@ -1373,10 +1383,11 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
|
||||||
}
|
}
|
||||||
|
|
||||||
mus_playing.loop = looping;
|
mus_playing.loop = looping;
|
||||||
|
mus_playing.name = musicname;
|
||||||
|
LastSong = "";
|
||||||
|
|
||||||
if (mus_playing.handle != 0)
|
if (mus_playing.handle != 0)
|
||||||
{ // play it
|
{ // play it
|
||||||
mus_playing.name = musicname;
|
|
||||||
I_PlaySong (mus_playing.handle, looping, S_GetMusicVolume (musicname));
|
I_PlaySong (mus_playing.handle, looping, S_GetMusicVolume (musicname));
|
||||||
mus_playing.baseorder =
|
mus_playing.baseorder =
|
||||||
(I_SetSongPosition (mus_playing.handle, order) ? order : 0);
|
(I_SetSongPosition (mus_playing.handle, order) ? order : 0);
|
||||||
|
@ -1396,8 +1407,9 @@ void S_RestartMusic ()
|
||||||
{
|
{
|
||||||
if (!LastSong.IsEmpty())
|
if (!LastSong.IsEmpty())
|
||||||
{
|
{
|
||||||
S_ChangeMusic (LastSong, mus_playing.baseorder, mus_playing.loop, true);
|
FString song = LastSong;
|
||||||
LastSong = "";
|
LastSong = "";
|
||||||
|
S_ChangeMusic (song, mus_playing.baseorder, mus_playing.loop, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -427,7 +427,9 @@ public:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return FMOD_ERR_FILE_EOF;
|
self->Channel->stop();
|
||||||
|
// Contrary to the docs, this return value is completely ignored.
|
||||||
|
return FMOD_ERR_INVALID_PARAM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,25 +90,36 @@ float saved_relative_volume = 1.0f; // this could be used to implement an ACS Fa
|
||||||
// Maximum volume of MOD/stream music.
|
// Maximum volume of MOD/stream music.
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
CUSTOM_CVAR (Float, snd_musicvolume, 0.3f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CUSTOM_CVAR (Float, snd_musicvolume, 0.5f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
{
|
{
|
||||||
if (self < 0.f)
|
if (self < 0.f)
|
||||||
self = 0.f;
|
self = 0.f;
|
||||||
else if (self > 1.f)
|
else if (self > 1.f)
|
||||||
self = 1.f;
|
self = 1.f;
|
||||||
else if (GSnd != NULL)
|
else
|
||||||
|
{
|
||||||
|
if (GSnd != NULL)
|
||||||
{
|
{
|
||||||
// Set general music volume.
|
// Set general music volume.
|
||||||
GSnd->SetMusicVolume(clamp<float>(self * relative_volume, 0, 1));
|
GSnd->SetMusicVolume(clamp<float>(self * relative_volume, 0, 1));
|
||||||
|
}
|
||||||
// For music not implemented through the digital sound system,
|
// For music not implemented through the digital sound system,
|
||||||
// let them know about the changed.
|
// let them know about the change.
|
||||||
if (currSong != NULL)
|
if (currSong != NULL)
|
||||||
{
|
{
|
||||||
currSong->MusicVolumeChanged();
|
currSong->MusicVolumeChanged();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{ // If the music was stopped because volume was 0, start it now.
|
||||||
|
S_RestartMusic();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MusInfo::MusInfo()
|
||||||
|
: m_Status(STATE_Stopped), m_Looping(false), m_NotStartedYet(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
MusInfo::~MusInfo ()
|
MusInfo::~MusInfo ()
|
||||||
{
|
{
|
||||||
|
@ -187,6 +198,7 @@ void I_PlaySong (void *handle, int _looping, float rel_vol)
|
||||||
saved_relative_volume = relative_volume = rel_vol;
|
saved_relative_volume = relative_volume = rel_vol;
|
||||||
info->Stop ();
|
info->Stop ();
|
||||||
info->Play (_looping ? true : false);
|
info->Play (_looping ? true : false);
|
||||||
|
info->m_NotStartedYet = false;
|
||||||
|
|
||||||
if (info->m_Status == MusInfo::STATE_Playing)
|
if (info->m_Status == MusInfo::STATE_Playing)
|
||||||
currSong = info;
|
currSong = info;
|
||||||
|
|
|
@ -31,7 +31,7 @@ extern float relative_volume;
|
||||||
class MusInfo
|
class MusInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MusInfo () : m_Status(STATE_Stopped) {}
|
MusInfo ();
|
||||||
virtual ~MusInfo ();
|
virtual ~MusInfo ();
|
||||||
virtual void MusicVolumeChanged(); // snd_musicvolume changed
|
virtual void MusicVolumeChanged(); // snd_musicvolume changed
|
||||||
virtual void TimidityVolumeChanged(); // timidity_mastervolume changed
|
virtual void TimidityVolumeChanged(); // timidity_mastervolume changed
|
||||||
|
@ -53,12 +53,23 @@ public:
|
||||||
STATE_Paused
|
STATE_Paused
|
||||||
} m_Status;
|
} m_Status;
|
||||||
bool m_Looping;
|
bool m_Looping;
|
||||||
|
bool m_NotStartedYet; // Song has been created but not yet played
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
// A device that provides a WinMM-like MIDI streaming interface -------------
|
// A device that provides a WinMM-like MIDI streaming interface -------------
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
struct MIDIHDR
|
||||||
|
{
|
||||||
|
BYTE *lpData;
|
||||||
|
DWORD dwBufferLength;
|
||||||
|
DWORD dwBytesRecorded;
|
||||||
|
MIDIHDR *Next;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
class MIDIDevice
|
class MIDIDevice
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -109,8 +120,31 @@ protected:
|
||||||
void *CallbackData;
|
void *CallbackData;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Base class for streaming MUS and MIDI files ------------------------------
|
// OPL implementation of a MIDI output device -------------------------------
|
||||||
|
|
||||||
|
class OPLMIDIDevice : public MIDIDevice, OPLmusicBlock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OPLMIDIDevice();
|
||||||
|
~OPLMIDIDevice();
|
||||||
|
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
|
||||||
|
void Close();
|
||||||
|
bool IsOpen() const;
|
||||||
|
int GetTechnology() const;
|
||||||
|
int SetTempo(int tempo);
|
||||||
|
int SetTimeDiv(int timediv);
|
||||||
|
int StreamOut(MIDIHDR *data);
|
||||||
|
int Resume();
|
||||||
|
void Stop();
|
||||||
|
int PrepareHeader(MIDIHDR *data);
|
||||||
|
int UnprepareHeader(MIDIHDR *data);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void (*Callback)(unsigned int, void *, DWORD, DWORD);
|
||||||
|
void *CallbackData;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base class for streaming MUS and MIDI files ------------------------------
|
||||||
|
|
||||||
class MIDIStreamer : public MusInfo
|
class MIDIStreamer : public MusInfo
|
||||||
{
|
{
|
||||||
|
@ -305,7 +339,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
static bool FillStream (SoundStream *stream, void *buff, int len, void *userdata);
|
static bool FillStream (SoundStream *stream, void *buff, int len, void *userdata);
|
||||||
|
|
||||||
OPLmusicBlock *Music;
|
OPLmusicFile *Music;
|
||||||
};
|
};
|
||||||
|
|
||||||
// CD track/disk played through the multimedia system -----------------------
|
// CD track/disk played through the multimedia system -----------------------
|
||||||
|
|
|
@ -95,7 +95,7 @@ SoundRenderer *GSnd;
|
||||||
// Maximum volume of a sound effect.
|
// Maximum volume of a sound effect.
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
CUSTOM_CVAR (Float, snd_sfxvolume, 0.5f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
|
CUSTOM_CVAR (Float, snd_sfxvolume, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
|
||||||
{
|
{
|
||||||
if (self < 0.f)
|
if (self < 0.f)
|
||||||
self = 0.f;
|
self = 0.f;
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
|
|
||||||
// MACROS ------------------------------------------------------------------
|
// MACROS ------------------------------------------------------------------
|
||||||
|
|
||||||
#define MAX_TIME (1000000/20) // Send out 1/20 of a sec of events at a time.
|
#define MAX_TIME (1000000/10) // Send out 1/10 of a sec of events at a time.
|
||||||
|
|
||||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,5 @@
|
||||||
#include "i_musicinterns.h"
|
#include "i_musicinterns.h"
|
||||||
|
|
||||||
CUSTOM_CVAR (Int, opl_frequency, 49716, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|
||||||
{ // Clamp frequency to FMOD's limits
|
|
||||||
if (self < 4000)
|
|
||||||
self = 4000;
|
|
||||||
else if (self > 49716) // No need to go higher than this
|
|
||||||
self = 49716;
|
|
||||||
}
|
|
||||||
|
|
||||||
CVAR (Bool, opl_enable, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CVAR (Bool, opl_enable, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
|
|
||||||
static bool OPL_Active;
|
static bool OPL_Active;
|
||||||
|
@ -23,13 +15,12 @@ CUSTOM_CVAR (Bool, opl_onechip, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
|
|
||||||
OPLMUSSong::OPLMUSSong (FILE *file, char *musiccache, int len)
|
OPLMUSSong::OPLMUSSong (FILE *file, char *musiccache, int len)
|
||||||
{
|
{
|
||||||
int rate = *opl_frequency;
|
int samples = int(OPL_SAMPLE_RATE / 14);
|
||||||
int samples = rate/14;
|
|
||||||
|
|
||||||
Music = new OPLmusicBlock (file, musiccache, len, rate, samples);
|
Music = new OPLmusicFile (file, musiccache, len, samples);
|
||||||
|
|
||||||
m_Stream = GSnd->CreateStream (FillStream, samples*2,
|
m_Stream = GSnd->CreateStream (FillStream, samples*2,
|
||||||
SoundStream::Mono, rate, this);
|
SoundStream::Mono, int(OPL_SAMPLE_RATE), this);
|
||||||
if (m_Stream == NULL)
|
if (m_Stream == NULL)
|
||||||
{
|
{
|
||||||
Printf (PRINT_BOLD, "Could not create music stream.\n");
|
Printf (PRINT_BOLD, "Could not create music stream.\n");
|
||||||
|
|
Loading…
Reference in a new issue