2006-02-24 04:48:15 +00:00
|
|
|
#include "i_musicinterns.h"
|
|
|
|
#include "c_cvars.h"
|
|
|
|
#include "cmdlib.h"
|
2008-01-27 16:56:25 +00:00
|
|
|
#include "templates.h"
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
#if !defined(_WIN32) && 0
|
|
|
|
// Under Linux, buffer output from Timidity to try to avoid "bubbles"
|
|
|
|
// in the sound output.
|
|
|
|
class FPipeBuffer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
FPipeBuffer::FPipeBuffer (int fragSize, int nFrags, int pipe);
|
|
|
|
~FPipeBuffer ();
|
|
|
|
|
|
|
|
int ReadFrag (BYTE *Buf);
|
|
|
|
|
|
|
|
private:
|
|
|
|
int PipeHandle;
|
|
|
|
int FragSize;
|
|
|
|
int BuffSize;
|
|
|
|
int WritePos, ReadPos;
|
|
|
|
BYTE *Buffer;
|
|
|
|
bool GotFull;
|
|
|
|
SDL_mutex *BufferMutex;
|
|
|
|
SDL_thread *Reader;
|
|
|
|
|
|
|
|
static int ThreadProc (void *data);
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <wordexp.h>
|
|
|
|
|
|
|
|
int ChildQuit;
|
|
|
|
|
|
|
|
void ChildSigHandler (int signum)
|
|
|
|
{
|
|
|
|
ChildQuit = waitpid (-1, NULL, WNOHANG);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
const char TimiditySong::EventName[] = "TiMidity Killer";
|
2007-03-29 01:03:50 +00:00
|
|
|
static char TimidityTitle[] = "TiMidity (ZDoom Launched)";
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
CVAR (String, timidity_exe, "timidity.exe", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|
|
|
#else
|
|
|
|
CVAR (String, timidity_exe, "timidity", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|
|
|
#endif
|
|
|
|
CVAR (String, timidity_extargs, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // extra args to pass to Timidity
|
|
|
|
CVAR (String, timidity_chorus, "0", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|
|
|
CVAR (String, timidity_reverb, "0", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|
|
|
CVAR (Bool, timidity_stereo, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|
|
|
CVAR (Bool, timidity_8bit, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|
|
|
CVAR (Bool, timidity_byteswap, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
2008-01-27 16:56:25 +00:00
|
|
|
// added because Timidity's output is rather loud.
|
|
|
|
CUSTOM_CVAR (Float, timidity_mastervolume, 1.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|
|
|
{
|
|
|
|
if (self < 0.f)
|
|
|
|
self = 0.f;
|
|
|
|
else if (self > 4.f)
|
|
|
|
self = 4.f;
|
2008-03-09 16:30:36 +00:00
|
|
|
if (currSong != NULL)
|
VERY IMPORTANT NOTE FOR ANYBODY BUILDING FROM THE TRUNK: This commit adds support
for FMOD Ex while at the same time removing support for FMOD 3. Be sure to update
your SDKs. GCC users, be sure to do a "make cleandep && make clean" before
building, or you will likely get inexplicable errors.
- Fixed: If you wanted to make cleandep with MinGW, you had to specifically
specify Makefile.mingw as the makefile to use.
- Added a normalizer to the OPL synth. It helped bring up the volume a little,
but not nearly as much as I would have liked.
- Removed MIDI Mapper references. It doesn't work with the stream API, and
it doesn't really exist on NT kernels, either.
- Reworked music volume: Except for MIDI, all music volume is controlled
through GSnd and not at the individual song level.
- Removed the mididevice global variable.
- Removed snd_midivolume. Now that all music uses a linear volume scale,
there's no need for two separate music volume controls.
- Increased snd_samplerate default up to 48000.
- Added snd_format, defaulting to "PCM-16".
- Added snd_speakermode, defaulting to "Auto".
- Replaced snd_fpu with snd_resampler, defaulting to "Linear".
- Bumped the snd_channels default up from a pitiful 12 to 32.
- Changed snd_3d default to true. The new cvar snd_hw3d determines if
hardware 3D support is used and default to false.
- Removed the libFLAC source, since FMOD Ex has native FLAC support.
- Removed the altsound code, since it was terribly gimped in comparison to
the FMOD code. It's original purpose was to have been as a springboard for
writing a non-FMOD sound system for Unix-y systems, but that never
happened.
- Finished preliminary FMOD Ex support.
SVN r789 (trunk)
2008-03-09 03:13:49 +00:00
|
|
|
currSong->TimidityVolumeChanged();
|
2008-01-27 16:56:25 +00:00
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
CUSTOM_CVAR (Int, timidity_pipe, 60, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|
|
|
{ // pipe size in ms
|
|
|
|
if (timidity_pipe < 0)
|
|
|
|
{ // a negative size makes no sense
|
|
|
|
timidity_pipe = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CUSTOM_CVAR (Int, timidity_frequency, 22050, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|
|
|
{ // Clamp frequency to Timidity's limits
|
|
|
|
if (self < 4000)
|
|
|
|
self = 4000;
|
|
|
|
else if (self > 65000)
|
|
|
|
self = 65000;
|
|
|
|
}
|
|
|
|
|
2008-08-03 03:54:48 +00:00
|
|
|
void TimiditySong::Play (bool looping, int subsong)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
m_Status = STATE_Stopped;
|
|
|
|
m_Looping = looping;
|
|
|
|
|
|
|
|
if (LaunchTimidity ())
|
|
|
|
{
|
|
|
|
if (m_Stream != NULL)
|
|
|
|
{
|
2008-04-13 03:23:33 +00:00
|
|
|
if (m_Stream->Play (true, timidity_mastervolume))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
m_Status = STATE_Playing;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // Assume success if not mixing with FMOD
|
|
|
|
m_Status = STATE_Playing;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TimiditySong::Stop ()
|
|
|
|
{
|
|
|
|
if (m_Status != STATE_Stopped)
|
|
|
|
{
|
|
|
|
if (m_Stream != NULL)
|
|
|
|
{
|
|
|
|
m_Stream->Stop ();
|
|
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
|
|
if (ChildProcess != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
SetEvent (KillerEvent);
|
|
|
|
if (WaitForSingleObject (ChildProcess, 500) != WAIT_OBJECT_0)
|
|
|
|
{
|
|
|
|
TerminateProcess (ChildProcess, 666);
|
|
|
|
}
|
|
|
|
CloseHandle (ChildProcess);
|
|
|
|
ChildProcess = INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (ChildProcess != -1)
|
|
|
|
{
|
|
|
|
if (kill (ChildProcess, SIGTERM) != 0)
|
|
|
|
{
|
|
|
|
kill (ChildProcess, SIGKILL);
|
|
|
|
}
|
|
|
|
waitpid (ChildProcess, NULL, 0);
|
|
|
|
ChildProcess = -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
m_Status = STATE_Stopped;
|
|
|
|
}
|
|
|
|
|
|
|
|
TimiditySong::~TimiditySong ()
|
|
|
|
{
|
|
|
|
Stop ();
|
|
|
|
#if _WIN32
|
|
|
|
if (WriteWavePipe != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
CloseHandle (WriteWavePipe);
|
|
|
|
WriteWavePipe = INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
if (ReadWavePipe != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
CloseHandle (ReadWavePipe);
|
|
|
|
ReadWavePipe = INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
if (KillerEvent != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
CloseHandle (KillerEvent);
|
|
|
|
KillerEvent = INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (WavePipe[1] != -1)
|
|
|
|
{
|
|
|
|
close (WavePipe[1]);
|
|
|
|
WavePipe[1] = -1;
|
|
|
|
}
|
|
|
|
if (WavePipe[0] != -1)
|
|
|
|
{
|
|
|
|
close (WavePipe[0]);
|
|
|
|
WavePipe[0] = -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2006-04-14 12:58:52 +00:00
|
|
|
TimiditySong::TimiditySong (FILE *file, char * musiccache, int len)
|
2006-02-24 04:48:15 +00:00
|
|
|
: DiskName ("zmid"),
|
|
|
|
#ifdef _WIN32
|
|
|
|
ReadWavePipe (INVALID_HANDLE_VALUE), WriteWavePipe (INVALID_HANDLE_VALUE),
|
|
|
|
KillerEvent (INVALID_HANDLE_VALUE),
|
|
|
|
ChildProcess (INVALID_HANDLE_VALUE),
|
2006-04-09 19:34:35 +00:00
|
|
|
Validated (false)
|
2006-02-24 04:48:15 +00:00
|
|
|
#else
|
2006-04-09 19:34:35 +00:00
|
|
|
ChildProcess (-1)
|
2006-02-24 04:48:15 +00:00
|
|
|
#endif
|
|
|
|
{
|
|
|
|
bool success;
|
|
|
|
FILE *f;
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
WavePipe[0] = WavePipe[1] = -1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (DiskName == NULL)
|
|
|
|
{
|
|
|
|
Printf (PRINT_BOLD, "Could not create temp music file\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
f = fopen (DiskName, "wb");
|
|
|
|
if (f == NULL)
|
|
|
|
{
|
|
|
|
Printf (PRINT_BOLD, "Could not open temp music file\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-04-14 12:58:52 +00:00
|
|
|
BYTE *buf;
|
|
|
|
|
|
|
|
if (file!=NULL)
|
|
|
|
{
|
|
|
|
buf = new BYTE[len];
|
|
|
|
fread (buf, 1, len, file);
|
|
|
|
}
|
|
|
|
else buf = (BYTE*)musiccache;
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
// The file type has already been checked before this class instance was
|
|
|
|
// created, so we only need to check one character to determine if this
|
|
|
|
// is a MUS or MIDI file and write it to disk as appropriate.
|
|
|
|
if (buf[1] == 'T')
|
|
|
|
{
|
|
|
|
success = (fwrite (buf, 1, len, f) == (size_t)len);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
success = ProduceMIDI (buf, f);
|
|
|
|
}
|
2007-09-12 00:20:11 +00:00
|
|
|
fclose (f);
|
2006-04-14 12:58:52 +00:00
|
|
|
if (file!=NULL)
|
|
|
|
{
|
|
|
|
delete[] buf;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
if (success)
|
|
|
|
{
|
|
|
|
PrepTimidity ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Printf (PRINT_BOLD, "Could not write temp music file\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TimiditySong::PrepTimidity ()
|
|
|
|
{
|
|
|
|
int pipeSize;
|
2008-03-28 00:38:17 +00:00
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
static SECURITY_ATTRIBUTES inheritable = { sizeof(inheritable), NULL, TRUE };
|
|
|
|
|
|
|
|
if (!Validated && !ValidateTimidity ())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Validated = true;
|
|
|
|
KillerEvent = CreateEvent (NULL, FALSE, FALSE, EventName);
|
|
|
|
if (KillerEvent == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
Printf (PRINT_BOLD, "Could not create TiMidity++ kill event.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif // WIN32
|
|
|
|
|
2006-04-09 19:34:35 +00:00
|
|
|
CommandLine.Format ("%s %s -EFchorus=%s -EFreverb=%s -s%d ",
|
2006-02-24 04:48:15 +00:00
|
|
|
*timidity_exe, *timidity_extargs,
|
|
|
|
*timidity_chorus, *timidity_reverb, *timidity_frequency);
|
|
|
|
|
|
|
|
pipeSize = (timidity_pipe * timidity_frequency / 1000)
|
|
|
|
<< (timidity_stereo + !timidity_8bit);
|
2008-03-28 00:38:17 +00:00
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
// Round pipe size up to nearest power of 2 to try and avoid partial
|
|
|
|
// buffer reads in FillStream() under NT. This does not seem to be an
|
|
|
|
// issue under 9x.
|
|
|
|
int bitmask = pipeSize & -pipeSize;
|
|
|
|
|
|
|
|
while (bitmask < pipeSize)
|
|
|
|
bitmask <<= 1;
|
|
|
|
pipeSize = bitmask;
|
|
|
|
|
|
|
|
if (!CreatePipe (&ReadWavePipe, &WriteWavePipe, &inheritable, pipeSize))
|
|
|
|
#else // WIN32
|
|
|
|
if (pipe (WavePipe) == -1)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
Printf (PRINT_BOLD, "Could not create a data pipe for TiMidity++.\n");
|
|
|
|
pipeSize = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_Stream = GSnd->CreateStream (FillStream, pipeSize,
|
|
|
|
(timidity_stereo ? 0 : SoundStream::Mono) |
|
|
|
|
(timidity_8bit ? SoundStream::Bits8 : 0),
|
|
|
|
timidity_frequency, this);
|
|
|
|
if (m_Stream == NULL)
|
|
|
|
{
|
|
|
|
Printf (PRINT_BOLD, "Could not create music stream.\n");
|
|
|
|
pipeSize = 0;
|
|
|
|
#ifdef _WIN32
|
|
|
|
CloseHandle (WriteWavePipe);
|
|
|
|
CloseHandle (ReadWavePipe);
|
|
|
|
ReadWavePipe = WriteWavePipe = INVALID_HANDLE_VALUE;
|
|
|
|
#else
|
|
|
|
close (WavePipe[1]);
|
|
|
|
close (WavePipe[0]);
|
|
|
|
WavePipe[0] = WavePipe[1] = -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pipeSize == 0)
|
|
|
|
{
|
|
|
|
Printf (PRINT_BOLD, "If your soundcard cannot play more than one\n"
|
|
|
|
"wave at a time, you will hear no music.\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-04-09 19:34:35 +00:00
|
|
|
CommandLine += "-o - -Ors";
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pipeSize == 0)
|
|
|
|
{
|
2006-04-09 19:34:35 +00:00
|
|
|
CommandLine += "-Od";
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
2006-04-09 19:34:35 +00:00
|
|
|
CommandLine += timidity_stereo ? 'S' : 'M';
|
|
|
|
CommandLine += timidity_8bit ? '8' : '1';
|
2006-02-24 04:48:15 +00:00
|
|
|
if (timidity_byteswap)
|
|
|
|
{
|
2006-04-09 19:34:35 +00:00
|
|
|
CommandLine += 'x';
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
2006-04-09 19:34:35 +00:00
|
|
|
LoopPos = CommandLine.Len() + 4;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-04-09 19:34:35 +00:00
|
|
|
CommandLine += " -idl ";
|
|
|
|
CommandLine += DiskName.GetName();
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
// Check that this TiMidity++ knows about the TiMidity Killer event.
|
|
|
|
// If not, then we can't use it, because Win32 provides no other way
|
|
|
|
// to conveniently signal it to quit. The check is done by simply
|
|
|
|
// searching for the event's name somewhere in the executable.
|
|
|
|
bool TimiditySong::ValidateTimidity ()
|
|
|
|
{
|
|
|
|
char foundPath[MAX_PATH];
|
|
|
|
char *filePart;
|
|
|
|
DWORD pathLen;
|
|
|
|
DWORD fileLen;
|
|
|
|
HANDLE diskFile;
|
|
|
|
HANDLE mapping;
|
|
|
|
const BYTE *exeBase;
|
|
|
|
const BYTE *exeEnd;
|
|
|
|
const BYTE *exe;
|
|
|
|
bool good;
|
|
|
|
|
|
|
|
pathLen = SearchPath (NULL, timidity_exe, NULL, MAX_PATH, foundPath, &filePart);
|
|
|
|
if (pathLen == 0)
|
|
|
|
{
|
|
|
|
Printf (PRINT_BOLD, "Please set the timidity_exe cvar to the location of TiMidity++\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (pathLen > MAX_PATH)
|
|
|
|
{
|
|
|
|
Printf (PRINT_BOLD, "The path to TiMidity++ is too long\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
diskFile = CreateFile (foundPath, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
|
|
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
|
|
|
if (diskFile == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
Printf (PRINT_BOLD, "Could not access %s\n", foundPath);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
fileLen = GetFileSize (diskFile, NULL);
|
|
|
|
mapping = CreateFileMapping (diskFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
|
|
if (mapping == NULL)
|
|
|
|
{
|
|
|
|
Printf (PRINT_BOLD, "Could not create mapping for %s\n", foundPath);
|
|
|
|
CloseHandle (diskFile);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
exeBase = (const BYTE *)MapViewOfFile (mapping, FILE_MAP_READ, 0, 0, 0);
|
|
|
|
if (exeBase == NULL)
|
|
|
|
{
|
|
|
|
Printf (PRINT_BOLD, "Could not map %s\n", foundPath);
|
|
|
|
CloseHandle (mapping);
|
|
|
|
CloseHandle (diskFile);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
good = false;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
for (exe = exeBase, exeEnd = exeBase+fileLen; exe < exeEnd; )
|
|
|
|
{
|
|
|
|
const char *tSpot = (const char *)memchr (exe, 'T', exeEnd - exe);
|
|
|
|
if (tSpot == NULL)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (memcmp (tSpot+1, EventName+1, sizeof(EventName)-1) == 0)
|
|
|
|
{
|
|
|
|
good = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
exe = (const BYTE *)tSpot + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
Printf (PRINT_BOLD, "Error reading %s\n", foundPath);
|
|
|
|
}
|
|
|
|
if (!good)
|
|
|
|
{
|
|
|
|
Printf (PRINT_BOLD, "ZDoom requires a special version of TiMidity++\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
UnmapViewOfFile ((LPVOID)exeBase);
|
|
|
|
CloseHandle (mapping);
|
|
|
|
CloseHandle (diskFile);
|
|
|
|
|
|
|
|
return good;
|
|
|
|
}
|
|
|
|
#endif // _WIN32
|
|
|
|
|
|
|
|
bool TimiditySong::LaunchTimidity ()
|
|
|
|
{
|
2006-05-16 02:50:18 +00:00
|
|
|
if (CommandLine.IsEmpty())
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tell Timidity whether it should loop or not
|
2006-05-16 02:50:18 +00:00
|
|
|
char *cmdline = CommandLine.LockBuffer();
|
|
|
|
cmdline[LoopPos] = m_Looping ? 'l' : ' ';
|
|
|
|
DPrintf ("cmd: \x1cG%s\n", cmdline);
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
STARTUPINFO startup = { sizeof(startup), };
|
|
|
|
PROCESS_INFORMATION procInfo;
|
|
|
|
|
|
|
|
startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
|
|
|
|
|
|
|
|
startup.hStdInput = INVALID_HANDLE_VALUE;
|
|
|
|
startup.hStdOutput = WriteWavePipe != INVALID_HANDLE_VALUE ?
|
|
|
|
WriteWavePipe : GetStdHandle (STD_OUTPUT_HANDLE);
|
|
|
|
startup.hStdError = GetStdHandle (STD_ERROR_HANDLE);
|
|
|
|
|
2007-03-29 01:03:50 +00:00
|
|
|
startup.lpTitle = TimidityTitle;
|
2006-02-24 04:48:15 +00:00
|
|
|
startup.wShowWindow = SW_SHOWMINNOACTIVE;
|
|
|
|
|
2006-05-16 02:50:18 +00:00
|
|
|
if (CreateProcess (NULL, cmdline, NULL, NULL, TRUE,
|
2006-02-24 04:48:15 +00:00
|
|
|
/*HIGH_PRIORITY_CLASS|*/DETACHED_PROCESS, NULL, NULL, &startup, &procInfo))
|
|
|
|
{
|
|
|
|
ChildProcess = procInfo.hProcess;
|
|
|
|
//SetThreadPriority (procInfo.hThread, THREAD_PRIORITY_HIGHEST);
|
|
|
|
CloseHandle (procInfo.hThread); // Don't care about the created thread
|
2006-05-16 02:50:18 +00:00
|
|
|
CommandLine.UnlockBuffer();
|
2006-02-24 04:48:15 +00:00
|
|
|
return true;
|
|
|
|
}
|
2006-05-16 02:50:18 +00:00
|
|
|
CommandLine.UnlockBuffer();
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
char hres[9];
|
|
|
|
LPTSTR msgBuf;
|
|
|
|
HRESULT err = GetLastError ();
|
|
|
|
|
|
|
|
if (!FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
NULL, err, 0, (LPTSTR)&msgBuf, 0, NULL))
|
|
|
|
{
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
mysnprintf (hres, countof(hres), "%08lx", err);
|
2006-02-24 04:48:15 +00:00
|
|
|
msgBuf = hres;
|
|
|
|
}
|
|
|
|
|
|
|
|
Printf (PRINT_BOLD, "Could not run timidity with the command line:\n%s\n"
|
2006-04-09 19:34:35 +00:00
|
|
|
"Reason: %s\n", CommandLine.GetChars(), msgBuf);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (msgBuf != hres)
|
|
|
|
{
|
|
|
|
LocalFree (msgBuf);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
#else
|
|
|
|
if (WavePipe[0] != -1 && WavePipe[1] == -1 && m_Stream != NULL)
|
|
|
|
{
|
|
|
|
// Timidity was previously launched, so the write end of the pipe
|
|
|
|
// is closed, and the read end is still open. Close the pipe
|
|
|
|
// completely and reopen it.
|
|
|
|
|
|
|
|
close (WavePipe[0]);
|
|
|
|
WavePipe[0] = -1;
|
|
|
|
delete m_Stream;
|
|
|
|
m_Stream = NULL;
|
|
|
|
PrepTimidity ();
|
|
|
|
}
|
|
|
|
|
|
|
|
int forkres;
|
|
|
|
wordexp_t words;
|
|
|
|
|
2006-04-09 19:34:35 +00:00
|
|
|
switch (wordexp (CommandLine.GetChars(), &words, 0))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
case 0: // all good
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WRDE_NOSPACE:
|
|
|
|
wordfree (&words);
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
forkres = fork ();
|
|
|
|
|
|
|
|
if (forkres == 0)
|
|
|
|
{
|
|
|
|
close (WavePipe[0]);
|
|
|
|
dup2 (WavePipe[1], STDOUT_FILENO);
|
|
|
|
freopen ("/dev/null", "r", stdin);
|
2008-03-27 04:25:52 +00:00
|
|
|
// freopen ("/dev/null", "w", stderr);
|
2006-02-24 04:48:15 +00:00
|
|
|
close (WavePipe[1]);
|
2006-04-12 01:50:09 +00:00
|
|
|
|
2008-03-28 00:38:17 +00:00
|
|
|
execvp (words.we_wordv[0], words.we_wordv);
|
2008-03-27 04:25:52 +00:00
|
|
|
fprintf(stderr,"execvp failed\n");
|
2006-02-24 04:48:15 +00:00
|
|
|
exit (0); // if execvp succeeds, we never get here
|
|
|
|
}
|
|
|
|
else if (forkres < 0)
|
|
|
|
{
|
|
|
|
Printf (PRINT_BOLD, "Could not fork when trying to start timidity\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// printf ("child is %d\n", forkres);
|
|
|
|
ChildProcess = forkres;
|
|
|
|
close (WavePipe[1]);
|
2008-03-28 00:38:17 +00:00
|
|
|
WavePipe[1] = -1;
|
|
|
|
/* usleep(1000000);
|
|
|
|
if (waitpid(ChildProcess, NULL, WNOHANG) == ChildProcess)
|
|
|
|
{
|
|
|
|
fprintf(stderr,"Launching timidity failed\n");
|
2008-03-27 04:25:52 +00:00
|
|
|
}*/
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
wordfree (&words);
|
|
|
|
return ChildProcess != -1;
|
|
|
|
#endif // _WIN32
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TimiditySong::FillStream (SoundStream *stream, void *buff, int len, void *userdata)
|
|
|
|
{
|
|
|
|
TimiditySong *song = (TimiditySong *)userdata;
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
DWORD avail, got, didget;
|
|
|
|
|
|
|
|
if (!PeekNamedPipe (song->ReadWavePipe, NULL, 0, NULL, &avail, NULL) || avail == 0)
|
|
|
|
{ // If nothing is available from the pipe, play silence.
|
|
|
|
memset (buff, 0, len);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
didget = 0;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
ReadFile (song->ReadWavePipe, (BYTE *)buff+didget, len-didget, &got, NULL);
|
|
|
|
didget += got;
|
|
|
|
if (didget >= (DWORD)len)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Give TiMidity a chance to output something more to the pipe
|
|
|
|
Sleep (10);
|
|
|
|
if (!PeekNamedPipe (song->ReadWavePipe, NULL, 0, NULL, &avail, NULL) || avail == 0)
|
|
|
|
{
|
|
|
|
memset ((BYTE *)buff+didget, 0, len-didget);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2008-03-28 00:38:17 +00:00
|
|
|
ssize_t got;
|
|
|
|
fd_set rfds;
|
|
|
|
struct timeval tv;
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
if (ChildQuit == song->ChildProcess)
|
|
|
|
{
|
|
|
|
ChildQuit = 0;
|
2008-03-27 04:25:52 +00:00
|
|
|
fprintf (stderr, "child gone\n");
|
2006-02-24 04:48:15 +00:00
|
|
|
song->ChildProcess = -1;
|
|
|
|
return false;
|
|
|
|
}
|
2008-03-28 00:38:17 +00:00
|
|
|
|
|
|
|
FD_ZERO(&rfds);
|
|
|
|
FD_SET(song->WavePipe[0], &rfds);
|
|
|
|
tv.tv_sec = 0;
|
|
|
|
tv.tv_usec = 50;
|
|
|
|
// fprintf(stderr,"select\n");
|
|
|
|
if (select(1, &rfds, NULL, NULL, &tv) <= 0 && 0)
|
|
|
|
{ // Nothing available, so play silence.
|
|
|
|
// fprintf(stderr,"nothing\n");
|
|
|
|
// memset(buff, 0, len);
|
|
|
|
return true;
|
|
|
|
}
|
2008-03-27 04:25:52 +00:00
|
|
|
// fprintf(stderr,"something\n");
|
|
|
|
|
|
|
|
got = read (song->WavePipe[0], (BYTE *)buff, len);
|
|
|
|
if (got < len)
|
|
|
|
{
|
|
|
|
memset ((BYTE *)buff+got, 0, len-got);
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
#endif
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
VERY IMPORTANT NOTE FOR ANYBODY BUILDING FROM THE TRUNK: This commit adds support
for FMOD Ex while at the same time removing support for FMOD 3. Be sure to update
your SDKs. GCC users, be sure to do a "make cleandep && make clean" before
building, or you will likely get inexplicable errors.
- Fixed: If you wanted to make cleandep with MinGW, you had to specifically
specify Makefile.mingw as the makefile to use.
- Added a normalizer to the OPL synth. It helped bring up the volume a little,
but not nearly as much as I would have liked.
- Removed MIDI Mapper references. It doesn't work with the stream API, and
it doesn't really exist on NT kernels, either.
- Reworked music volume: Except for MIDI, all music volume is controlled
through GSnd and not at the individual song level.
- Removed the mididevice global variable.
- Removed snd_midivolume. Now that all music uses a linear volume scale,
there's no need for two separate music volume controls.
- Increased snd_samplerate default up to 48000.
- Added snd_format, defaulting to "PCM-16".
- Added snd_speakermode, defaulting to "Auto".
- Replaced snd_fpu with snd_resampler, defaulting to "Linear".
- Bumped the snd_channels default up from a pitiful 12 to 32.
- Changed snd_3d default to true. The new cvar snd_hw3d determines if
hardware 3D support is used and default to false.
- Removed the libFLAC source, since FMOD Ex has native FLAC support.
- Removed the altsound code, since it was terribly gimped in comparison to
the FMOD code. It's original purpose was to have been as a springboard for
writing a non-FMOD sound system for Unix-y systems, but that never
happened.
- Finished preliminary FMOD Ex support.
SVN r789 (trunk)
2008-03-09 03:13:49 +00:00
|
|
|
void TimiditySong::TimidityVolumeChanged()
|
2008-01-27 16:56:25 +00:00
|
|
|
{
|
VERY IMPORTANT NOTE FOR ANYBODY BUILDING FROM THE TRUNK: This commit adds support
for FMOD Ex while at the same time removing support for FMOD 3. Be sure to update
your SDKs. GCC users, be sure to do a "make cleandep && make clean" before
building, or you will likely get inexplicable errors.
- Fixed: If you wanted to make cleandep with MinGW, you had to specifically
specify Makefile.mingw as the makefile to use.
- Added a normalizer to the OPL synth. It helped bring up the volume a little,
but not nearly as much as I would have liked.
- Removed MIDI Mapper references. It doesn't work with the stream API, and
it doesn't really exist on NT kernels, either.
- Reworked music volume: Except for MIDI, all music volume is controlled
through GSnd and not at the individual song level.
- Removed the mididevice global variable.
- Removed snd_midivolume. Now that all music uses a linear volume scale,
there's no need for two separate music volume controls.
- Increased snd_samplerate default up to 48000.
- Added snd_format, defaulting to "PCM-16".
- Added snd_speakermode, defaulting to "Auto".
- Replaced snd_fpu with snd_resampler, defaulting to "Linear".
- Bumped the snd_channels default up from a pitiful 12 to 32.
- Changed snd_3d default to true. The new cvar snd_hw3d determines if
hardware 3D support is used and default to false.
- Removed the libFLAC source, since FMOD Ex has native FLAC support.
- Removed the altsound code, since it was terribly gimped in comparison to
the FMOD code. It's original purpose was to have been as a springboard for
writing a non-FMOD sound system for Unix-y systems, but that never
happened.
- Finished preliminary FMOD Ex support.
SVN r789 (trunk)
2008-03-09 03:13:49 +00:00
|
|
|
if (m_Stream != NULL)
|
|
|
|
{
|
|
|
|
m_Stream->SetVolume(timidity_mastervolume);
|
|
|
|
}
|
2008-01-27 16:56:25 +00:00
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
bool TimiditySong::IsPlaying ()
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
if (ChildProcess != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
if (WaitForSingleObject (ChildProcess, 0) != WAIT_TIMEOUT)
|
|
|
|
{ // Timidity has quit
|
|
|
|
CloseHandle (ChildProcess);
|
|
|
|
ChildProcess = INVALID_HANDLE_VALUE;
|
|
|
|
#else
|
|
|
|
if (ChildProcess != -1)
|
|
|
|
{
|
|
|
|
if (waitpid (ChildProcess, NULL, WNOHANG) == ChildProcess)
|
|
|
|
{
|
|
|
|
ChildProcess = -1;
|
|
|
|
#endif
|
|
|
|
if (m_Looping)
|
|
|
|
{
|
|
|
|
if (!LaunchTimidity ())
|
|
|
|
{
|
|
|
|
Stop ();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !defined(_WIN32) && 0
|
|
|
|
FPipeBuffer::FPipeBuffer (int fragSize, int nFrags, int pipe)
|
|
|
|
: PipeHandle (pipe),
|
|
|
|
FragSize (fragSize),
|
|
|
|
BuffSize (fragSize * nFrags),
|
|
|
|
WritePos (0), ReadPos (0), GotFull (false),
|
|
|
|
Reader (0), PleaseExit (0)
|
|
|
|
{
|
|
|
|
Buffer = new BYTE[BuffSize];
|
|
|
|
if (Buffer != NULL)
|
|
|
|
{
|
|
|
|
BufferMutex = SDL_CreateMutex ();
|
|
|
|
if (BufferMutex == NULL)
|
|
|
|
{
|
|
|
|
Reader = SDL_CreateThread (ThreadProc, (void *)this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FPipeBuffer::~FPipeBuffer ()
|
|
|
|
{
|
|
|
|
if (Reader != NULL)
|
|
|
|
{ // I like the Win32 IPC facilities better than SDL's
|
|
|
|
// Fortunately, this is a simple thread, so I can cheat
|
|
|
|
// like this.
|
|
|
|
SDL_KillThread (ThreadProc);
|
|
|
|
}
|
|
|
|
if (BufferMutex != NULL)
|
|
|
|
{
|
|
|
|
SDL_DestroyMutex (BufferMutex);
|
|
|
|
}
|
|
|
|
if (Buffer != NULL)
|
|
|
|
{
|
|
|
|
delete[] Buffer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int FPipeBuffer::ReadFrag (BYTE *buf)
|
|
|
|
{
|
|
|
|
int startavvail;
|
|
|
|
int avail;
|
|
|
|
int pos;
|
|
|
|
int opos;
|
|
|
|
|
|
|
|
if (SDL_mutexP (BufferMutex) == -1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (WritePos > ReadPos)
|
|
|
|
{
|
|
|
|
avail = WritePos - ReadPos;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
avail = BuffSize - ReadPos + WritePos;
|
|
|
|
}
|
|
|
|
if (avail > FragSize)
|
|
|
|
avail = FragSize;
|
|
|
|
|
|
|
|
startavail = avali;
|
|
|
|
pos = ReadPos;
|
|
|
|
opos = 0;
|
|
|
|
|
|
|
|
while (avail != 0)
|
|
|
|
{
|
|
|
|
int thistime;
|
|
|
|
|
|
|
|
thistime = (pos + avail > BuffSize) ? BuffSize - pos : avail;
|
|
|
|
memcpy (buf + opos, Buffer + pos, thistime);
|
|
|
|
if (thistime != avail)
|
|
|
|
{
|
|
|
|
pos = 0;
|
|
|
|
avail -= thistime;
|
|
|
|
}
|
|
|
|
opos += thistime;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReadPos = pos;
|
|
|
|
|
|
|
|
SDL_mutexV (BufferMutex);
|
|
|
|
|
|
|
|
return startavail;
|
|
|
|
}
|
|
|
|
#endif // !_WIN32
|