qzdoom/src/sound/music_midi_timidity.cpp

744 lines
16 KiB
C++
Raw Normal View History

#include "i_musicinterns.h"
#include "c_cvars.h"
#include "cmdlib.h"
#include "templates.h"
#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>
#include <signal.h>
int ChildQuit;
void ChildSigHandler (int signum)
{
ChildQuit = waitpid (-1, NULL, WNOHANG);
}
#endif
#ifdef _WIN32
const char TimiditySong::EventName[] = "TiMidity Killer";
static char TimidityTitle[] = "TiMidity (ZDoom Launched)";
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)
// 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;
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();
}
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;
}
void TimiditySong::Play (bool looping, int subsong)
{
m_Status = STATE_Stopped;
m_Looping = looping;
if (LaunchTimidity ())
{
if (m_Stream != NULL)
{
if (m_Stream->Play (true, timidity_mastervolume))
{
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
}
TimiditySong::TimiditySong (FILE *file, BYTE *musiccache, int len)
: DiskName ("zmid"),
#ifdef _WIN32
ReadWavePipe (INVALID_HANDLE_VALUE), WriteWavePipe (INVALID_HANDLE_VALUE),
KillerEvent (INVALID_HANDLE_VALUE),
ChildProcess (INVALID_HANDLE_VALUE),
Validated (false)
#else
ChildProcess (-1)
#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 = musiccache;
}
2006-04-14 12:58:52 +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);
}
fclose (f);
if (file != NULL)
2006-04-14 12:58:52 +00:00
{
delete[] buf;
}
if (success)
{
PrepTimidity ();
}
else
{
Printf (PRINT_BOLD, "Could not write temp music file\n");
}
}
void TimiditySong::PrepTimidity ()
{
int pipeSize;
#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
CommandLine.Format ("%s %s -EFchorus=%s -EFreverb=%s -s%d ",
*timidity_exe, *timidity_extargs,
*timidity_chorus, *timidity_reverb, *timidity_frequency);
pipeSize = (timidity_pipe * timidity_frequency / 1000)
<< (timidity_stereo + !timidity_8bit);
{
#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
{
CommandLine += "-o - -Ors";
}
}
if (pipeSize == 0)
{
CommandLine += "-Od";
}
CommandLine += timidity_stereo ? 'S' : 'M';
CommandLine += timidity_8bit ? '8' : '1';
if (timidity_byteswap)
{
CommandLine += 'x';
}
LoopPos = CommandLine.Len() + 4;
CommandLine += " -idl ";
CommandLine += DiskName.GetName();
}
#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())
{
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);
#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);
startup.lpTitle = TimidityTitle;
startup.wShowWindow = SW_SHOWMINNOACTIVE;
2006-05-16 02:50:18 +00:00
if (CreateProcess (NULL, cmdline, NULL, NULL, TRUE,
/*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();
return true;
}
2006-05-16 02:50:18 +00:00
CommandLine.UnlockBuffer();
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);
msgBuf = hres;
}
Printf (PRINT_BOLD, "Could not run timidity with the command line:\n%s\n"
"Reason: %s\n", CommandLine.GetChars(), msgBuf);
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;
switch (wordexp (CommandLine.GetChars(), &words, 0))
{
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);
// freopen ("/dev/null", "w", stderr);
close (WavePipe[1]);
2006-04-12 01:50:09 +00:00
execvp (words.we_wordv[0], words.we_wordv);
fprintf(stderr,"execvp failed\n");
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]);
WavePipe[1] = -1;
/* usleep(1000000);
if (waitpid(ChildProcess, NULL, WNOHANG) == ChildProcess)
{
fprintf(stderr,"Launching timidity failed\n");
}*/
}
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
ssize_t got;
fd_set rfds;
struct timeval tv;
if (ChildQuit == song->ChildProcess)
{
ChildQuit = 0;
fprintf (stderr, "child gone\n");
song->ChildProcess = -1;
return false;
}
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;
}
// fprintf(stderr,"something\n");
got = read (song->WavePipe[0], (BYTE *)buff, len);
if (got < len)
{
memset ((BYTE *)buff+got, 0, len-got);
}
#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()
{
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);
}
}
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