mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2025-01-09 09:40:46 +00:00
e815474cbe
returning from one function to another function when the function that was called was used as part of an expression. - Fixed: Using Thing_Hate with arg0 (hater) set to 0 from an open script could crash. - Fixed: Some items along ledges in Hexen's MAP32 (Orchard of Lamentations) appeared at the bottom of the ledge (and consequently inside it) instead of on top of it because the items were placed directly on the lines. AActor::LinkToWorldForMapThing() needs to use the original R_PointOnLineSide() code to handle situations like this. Previously, it just used the original code for straight horizontal/vertical lines and used the new code for diagonal lines. - Fixed: FWadCollection::MergeLumps() used in incorrect realloc. - Fixed: FPlayList::NextLine() did not properly handle blank lines in the playlist. - Changed: Decals now use lightweight thinkers instead of actors. (76 bytes versus 396, so you save 320k if you have 1024 decals present.) - Fixed: Wads added with pullin were loaded immediately after the IWAD. Exec files are now processed immediately before -file but after autoloading wads in D_DoomMain(). - Fixed: sdl/i_system.h unconditionally defined SHARE_DIR, preventing redefinition from the command line. - Fixed: The standard way to include SDL.h is <SDL.h>, not <SDL/SDL.h>. - Fixed: Returned FActiveInterpolation::HashKey()'s return type to size_t, avoiding a pointer truncation warning. SVN r30 (trunk)
685 lines
15 KiB
C++
685 lines
15 KiB
C++
#include "i_musicinterns.h"
|
|
#include "c_cvars.h"
|
|
#include "cmdlib.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>
|
|
|
|
int ChildQuit;
|
|
|
|
void ChildSigHandler (int signum)
|
|
{
|
|
ChildQuit = waitpid (-1, NULL, WNOHANG);
|
|
}
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
const char TimiditySong::EventName[] = "TiMidity Killer";
|
|
|
|
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)
|
|
|
|
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)
|
|
{
|
|
m_Status = STATE_Stopped;
|
|
m_Looping = looping;
|
|
|
|
if (LaunchTimidity ())
|
|
{
|
|
if (m_Stream != NULL)
|
|
{
|
|
if (m_Stream->Play (snd_musicvolume))
|
|
{
|
|
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, 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;
|
|
}
|
|
|
|
BYTE *buf = new BYTE[len];
|
|
fread (buf, 1, len, file);
|
|
|
|
// 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);
|
|
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);
|
|
|
|
if (pipeSize != 0)
|
|
{
|
|
#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 ()
|
|
{
|
|
if (CommandLine.Len() == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Tell Timidity whether it should loop or not
|
|
CommandLine[LoopPos] = m_Looping ? 'l' : ' ';
|
|
DPrintf ("cmd: \x1cG%s\n", CommandLine.GetChars());
|
|
|
|
#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 = "TiMidity (ZDoom Launched)";
|
|
startup.wShowWindow = SW_SHOWMINNOACTIVE;
|
|
|
|
if (CreateProcess (NULL, CommandLine.GetChars(), 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
|
|
return true;
|
|
}
|
|
|
|
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))
|
|
{
|
|
sprintf (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]);
|
|
|
|
printf ("exec %s\n", words.we_wordv[0]);
|
|
execvp (words.we_wordv[0], words.we_wordv);
|
|
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;
|
|
}
|
|
|
|
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;
|
|
|
|
got = read (song->WavePipe[0], (BYTE *)buff, len);
|
|
if (got < len)
|
|
{
|
|
memset ((BYTE *)buff+got, 0, len-got);
|
|
}
|
|
|
|
if (ChildQuit == song->ChildProcess)
|
|
{
|
|
ChildQuit = 0;
|
|
// printf ("child gone\n");
|
|
song->ChildProcess = -1;
|
|
return false;
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
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
|