mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-26 22:11:43 +00:00
- skeleton of new player class for Timidity++ - not tested yet.
This commit is contained in:
parent
803369fb8d
commit
d72b87f469
4 changed files with 131 additions and 920 deletions
|
@ -45,93 +45,31 @@
|
|||
#include "tmpfileplus.h"
|
||||
#include "m_misc.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#ifndef __OpenBSD__
|
||||
#include <wordexp.h>
|
||||
#endif
|
||||
#include <glob.h>
|
||||
#include <signal.h>
|
||||
|
||||
int ChildQuit;
|
||||
|
||||
void ChildSigHandler (int signum)
|
||||
{
|
||||
ChildQuit = waitpid (-1, NULL, WNOHANG);
|
||||
}
|
||||
#endif
|
||||
|
||||
class TimidityPPMIDIDevice : public PseudoMIDIDevice
|
||||
class TimidityPPMIDIDevice : public SoftSynthMIDIDevice
|
||||
{
|
||||
TArray<uint8_t> midi;
|
||||
FString CurrentConfig;
|
||||
public:
|
||||
TimidityPPMIDIDevice(const char *args);
|
||||
~TimidityPPMIDIDevice();
|
||||
|
||||
int Open(MidiCallback, void *userdata);
|
||||
bool Preprocess(MIDIStreamer *song, bool looping);
|
||||
bool IsOpen() const;
|
||||
int Resume();
|
||||
|
||||
void Stop();
|
||||
bool IsOpen();
|
||||
void TimidityVolumeChanged();
|
||||
void PrecacheInstruments(const uint16_t *instruments, int count);
|
||||
//FString GetStats();
|
||||
int GetDeviceType() const override { return MDEV_TIMIDITY; }
|
||||
bool Preprocess(MIDIStreamer *song, bool looping);
|
||||
void TimidityVolumeChanged();
|
||||
|
||||
protected:
|
||||
bool LaunchTimidity();
|
||||
//TimidityPlus::Player *Renderer;
|
||||
|
||||
FString DiskName;
|
||||
#ifdef _WIN32
|
||||
HANDLE ReadWavePipe;
|
||||
HANDLE WriteWavePipe;
|
||||
HANDLE ChildProcess;
|
||||
FString CommandLine;
|
||||
bool Validated;
|
||||
bool ValidateTimidity();
|
||||
#else // _WIN32
|
||||
int WavePipe[2];
|
||||
pid_t ChildProcess;
|
||||
#endif
|
||||
FString ExeName;
|
||||
bool Looping;
|
||||
|
||||
static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata);
|
||||
#ifdef _WIN32
|
||||
static const char EventName[];
|
||||
#endif
|
||||
void HandleEvent(int status, int parm1, int parm2);
|
||||
void HandleLongEvent(const uint8_t *data, int len);
|
||||
void ComputeOutput(float *buffer, int len);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
|
||||
BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode);
|
||||
|
||||
static char TimidityTitle[] = "TiMidity (" GAMENAME " Launched)";
|
||||
const char TimidityPPMIDIDevice::EventName[] = "TiMidity Killer";
|
||||
|
||||
CUSTOM_CVAR (String, timidity_exe, "timidity.exe", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
#else
|
||||
CUSTOM_CVAR(String, timidity_exe, "timidity", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
#endif
|
||||
{
|
||||
if (currSong != nullptr && currSong->GetDeviceType() == MDEV_TIMIDITY)
|
||||
{
|
||||
MIDIDeviceChanged(-1, true);
|
||||
}
|
||||
}
|
||||
|
||||
CVAR (String, timidity_extargs, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // extra args to pass to Timidity
|
||||
CVAR (String, timidity_config, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
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)
|
||||
// Config file to use
|
||||
CVAR(String, timidity_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
// added because Timidity's output is rather loud.
|
||||
CUSTOM_CVAR (Float, timidity_mastervolume, 1.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
@ -144,13 +82,6 @@ CUSTOM_CVAR (Float, timidity_mastervolume, 1.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|||
currSong->TimidityVolumeChanged();
|
||||
}
|
||||
|
||||
CUSTOM_CVAR (Int, timidity_pipe, 90, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{ // pipe size in ms
|
||||
if (self < 20)
|
||||
{ // Don't allow pipes less than 20ms
|
||||
self = 20;
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR (Int, timidity_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{ // Clamp frequency to Timidity's limits
|
||||
|
@ -166,34 +97,19 @@ CUSTOM_CVAR (Int, timidity_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) :
|
||||
#ifdef _WIN32
|
||||
ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE),
|
||||
ChildProcess(INVALID_HANDLE_VALUE),
|
||||
Validated(false),
|
||||
#else
|
||||
ChildProcess(-1),
|
||||
#endif
|
||||
Looping(false)
|
||||
TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
WavePipe[0] = WavePipe[1] = -1;
|
||||
#endif
|
||||
if (args == NULL || *args == 0) args = timidity_config;
|
||||
|
||||
if (args == NULL || *args == 0) args = timidity_exe;
|
||||
ExeName = args;
|
||||
|
||||
#ifdef _WIN32
|
||||
CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ",
|
||||
args, *timidity_extargs,
|
||||
*timidity_chorus, *timidity_reverb, *timidity_frequency);
|
||||
if (**timidity_config != '\0')
|
||||
if (CurrentConfig.CompareNoCase(args) != 0)
|
||||
{
|
||||
CommandLine += "-c \"";
|
||||
CommandLine += timidity_config;
|
||||
CommandLine += "\" ";
|
||||
// reload instruments
|
||||
// if (!reload_inst()) CurrentConfig = "";
|
||||
}
|
||||
if (CurrentConfig.IsNotEmpty())
|
||||
{
|
||||
//Renderer = new TimidityPlus::Player(timidity_frequency, args);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -204,34 +120,14 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) :
|
|||
|
||||
TimidityPPMIDIDevice::~TimidityPPMIDIDevice ()
|
||||
{
|
||||
if (DiskName.IsNotEmpty())
|
||||
Close();
|
||||
/*
|
||||
if (Renderer != nullptr)
|
||||
{
|
||||
remove(DiskName);
|
||||
delete Renderer;
|
||||
}
|
||||
*/
|
||||
|
||||
#if _WIN32
|
||||
if (WriteWavePipe != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle (WriteWavePipe);
|
||||
WriteWavePipe = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (ReadWavePipe != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle (ReadWavePipe);
|
||||
ReadWavePipe = 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
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -242,47 +138,9 @@ TimidityPPMIDIDevice::~TimidityPPMIDIDevice ()
|
|||
|
||||
bool TimidityPPMIDIDevice::Preprocess(MIDIStreamer *song, bool looping)
|
||||
{
|
||||
TArray<uint8_t> midi;
|
||||
bool success;
|
||||
FILE *f;
|
||||
|
||||
if (ExeName.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Looping = looping;
|
||||
|
||||
// Write MIDI song to temporary file
|
||||
song->CreateSMF(midi, looping ? 0 : 1);
|
||||
|
||||
FString path = M_GetAppDataPath(false);
|
||||
path += "/tmp";
|
||||
CreatePath(path);
|
||||
f = tmpfileplus(path, "zmid", &DiskName, 1);
|
||||
if (f == NULL)
|
||||
{
|
||||
Printf(PRINT_BOLD, "Could not open temp music file\n");
|
||||
return false;
|
||||
}
|
||||
success = (fwrite(&midi[0], 1, midi.Size(), f) == (size_t)midi.Size());
|
||||
fclose (f);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
Printf(PRINT_BOLD, "Could not write temp music file\n");
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
CommandLine.AppendFormat("-o - -Ors%c%c%c -id%c %s",
|
||||
timidity_stereo ? 'S' : 'M',
|
||||
timidity_8bit ? '8' : '1',
|
||||
timidity_byteswap ? 'x' : ' ',
|
||||
looping ? 'l' : ' ',
|
||||
DiskName);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
return midi.Size() > 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -290,414 +148,79 @@ bool TimidityPPMIDIDevice::Preprocess(MIDIStreamer *song, bool looping)
|
|||
// TimidityPPMIDIDevice :: Open
|
||||
//
|
||||
//==========================================================================
|
||||
namespace TimidityPlus
|
||||
{
|
||||
int load_midi_file(FileReader *fr);
|
||||
void run_midi(int samples);
|
||||
void timidity_close();
|
||||
}
|
||||
|
||||
int TimidityPPMIDIDevice::Open(MidiCallback callback, void *userdata)
|
||||
{
|
||||
int pipeSize;
|
||||
|
||||
#ifdef _WIN32
|
||||
static SECURITY_ATTRIBUTES inheritable = { sizeof(inheritable), NULL, true };
|
||||
|
||||
if (!Validated && !ValidateTimidity ())
|
||||
int ret = OpenStream(2, 0, callback, userdata);
|
||||
if (ret == 0)
|
||||
{
|
||||
return 101;
|
||||
//Renderer->Reset();
|
||||
MemoryReader fr((char*)&midi[0], midi.Size());
|
||||
return !TimidityPlus::load_midi_file(&fr);
|
||||
}
|
||||
|
||||
Validated = true;
|
||||
#endif // WIN32
|
||||
|
||||
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");
|
||||
return 1;
|
||||
}
|
||||
|
||||
Stream = GSnd->CreateStream(FillStream, pipeSize,
|
||||
(timidity_stereo ? 0 : SoundStream::Mono) |
|
||||
(timidity_8bit ? SoundStream::Bits8 : 0),
|
||||
timidity_frequency, this);
|
||||
if (Stream == NULL)
|
||||
{
|
||||
Printf(PRINT_BOLD, "Could not create music stream.\n");
|
||||
#ifdef _WIN32
|
||||
CloseHandle(WriteWavePipe);
|
||||
CloseHandle(ReadWavePipe);
|
||||
ReadWavePipe = WriteWavePipe = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
close(WavePipe[1]);
|
||||
close(WavePipe[0]);
|
||||
WavePipe[0] = WavePipe[1] = -1;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// TimidityPPMIDIDevice :: ValidateTimidity
|
||||
// TimidityPPMIDIDevice :: PrecacheInstruments
|
||||
//
|
||||
// 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.
|
||||
// Each entry is packed as follows:
|
||||
// Bits 0- 6: Instrument number
|
||||
// Bits 7-13: Bank number
|
||||
// Bit 14: Select drum set if 1, tone bank if 0
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
#ifdef _WIN32
|
||||
bool TimidityPPMIDIDevice::ValidateTimidity()
|
||||
void TimidityPPMIDIDevice::PrecacheInstruments(const uint16_t *instruments, int count)
|
||||
{
|
||||
char foundPath[MAX_PATH];
|
||||
char *filePart;
|
||||
DWORD pathLen;
|
||||
DWORD fileLen;
|
||||
HANDLE diskFile;
|
||||
HANDLE mapping;
|
||||
const uint8_t *exeBase;
|
||||
const uint8_t *exeEnd;
|
||||
const uint8_t *exe;
|
||||
bool good;
|
||||
|
||||
pathLen = SearchPath (NULL, timidity_exe, NULL, MAX_PATH, foundPath, &filePart);
|
||||
if (pathLen == 0)
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
Printf(PRINT_BOLD, "Please set the timidity_exe cvar to the location of TiMidity++\n");
|
||||
return false;
|
||||
//Renderer->MarkInstrument((instruments[i] >> 7) & 127, instruments[i] >> 14, instruments[i] & 127);
|
||||
}
|
||||
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 uint8_t *)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 uint8_t *)tSpot + 1;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Printf(PRINT_BOLD, "Error reading %s\n", foundPath);
|
||||
}
|
||||
if (!good)
|
||||
{
|
||||
Printf(PRINT_BOLD, GAMENAME " requires a special version of TiMidity++\n");
|
||||
}
|
||||
|
||||
UnmapViewOfFile((LPVOID)exeBase);
|
||||
CloseHandle(mapping);
|
||||
CloseHandle(diskFile);
|
||||
|
||||
return good;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// TimidityPPMIDIDevice :: LaunchTimidity
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool TimidityPPMIDIDevice::LaunchTimidity ()
|
||||
{
|
||||
if (ExeName.IsEmpty() || DiskName.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
DPrintf (DMSG_NOTIFY, "cmd: \x1cG%s\n", CommandLine.GetChars());
|
||||
|
||||
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;
|
||||
|
||||
if (CreateProcess(NULL, CommandLine.LockBuffer(), NULL, NULL, true,
|
||||
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
|
||||
CommandLine.UnlockBuffer();
|
||||
return true;
|
||||
}
|
||||
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))
|
||||
{
|
||||
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 && 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 Stream;
|
||||
Stream = NULL;
|
||||
Open (NULL, NULL);
|
||||
}
|
||||
|
||||
int forkres;
|
||||
#ifndef __OpenBSD__
|
||||
wordexp_t words;
|
||||
#endif
|
||||
glob_t glb;
|
||||
|
||||
// Get timidity executable path
|
||||
const char *exename = "timidity"; // Fallback default
|
||||
glob(ExeName.GetChars(), 0, NULL, &glb);
|
||||
if(glb.gl_pathc != 0)
|
||||
exename = glb.gl_pathv[0];
|
||||
#ifndef __OpenBSD__
|
||||
// Get user-defined extra args
|
||||
wordexp(timidity_extargs, &words, WRDE_NOCMD);
|
||||
#endif
|
||||
|
||||
std::string chorusarg = std::string("-EFchorus=") + *timidity_chorus;
|
||||
std::string reverbarg = std::string("-EFreverb=") + *timidity_reverb;
|
||||
std::string sratearg = std::string("-s") + std::to_string(*timidity_frequency);
|
||||
std::string outfilearg = "-o"; // An extra "-" is added later
|
||||
std::string outmodearg = "-Or";
|
||||
outmodearg += timidity_8bit ? "u8" : "s1";
|
||||
outmodearg += timidity_stereo ? "S" : "M";
|
||||
if(timidity_byteswap) outmodearg += "x";
|
||||
std::string ifacearg = "-id";
|
||||
if(Looping) ifacearg += "l";
|
||||
|
||||
std::vector<const char*> arglist;
|
||||
arglist.push_back(exename);
|
||||
#ifndef __OpenBSD__
|
||||
for(size_t i = 0;i < words.we_wordc;i++)
|
||||
arglist.push_back(words.we_wordv[i]);
|
||||
#endif
|
||||
if(**timidity_config != '\0')
|
||||
{
|
||||
arglist.push_back("-c");
|
||||
arglist.push_back(timidity_config);
|
||||
}
|
||||
arglist.push_back(chorusarg.c_str());
|
||||
arglist.push_back(reverbarg.c_str());
|
||||
arglist.push_back(sratearg.c_str());
|
||||
arglist.push_back(outfilearg.c_str());
|
||||
arglist.push_back("-");
|
||||
arglist.push_back(outmodearg.c_str());
|
||||
arglist.push_back(ifacearg.c_str());
|
||||
arglist.push_back(DiskName.GetChars());
|
||||
|
||||
DPrintf(DMSG_NOTIFY, "Timidity EXE: \x1cG%s\n", exename);
|
||||
int i = 1;
|
||||
std::for_each(arglist.begin()+1, arglist.end(),
|
||||
[&i](const char *arg)
|
||||
{ DPrintf(DMSG_NOTIFY, "arg %d: \x1cG%s\n", i++, arg); }
|
||||
);
|
||||
arglist.push_back(nullptr);
|
||||
|
||||
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]);
|
||||
|
||||
execvp (exename, const_cast<char*const*>(arglist.data()));
|
||||
fprintf(stderr,"execvp failed: %s\n", strerror(errno));
|
||||
_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");
|
||||
}*/
|
||||
}
|
||||
|
||||
#ifndef __OpenBSD__
|
||||
wordfree(&words);
|
||||
#endif
|
||||
globfree (&glb);
|
||||
return ChildProcess != -1;
|
||||
#endif // _WIN32
|
||||
//Renderer->load_missing_instruments();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// TimidityPPMIDIDevice :: FillStream
|
||||
// TimidityPPMIDIDevice :: HandleEvent
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool TimidityPPMIDIDevice::FillStream(SoundStream *stream, void *buff, int len, void *userdata)
|
||||
void TimidityPPMIDIDevice::HandleEvent(int status, int parm1, int parm2)
|
||||
{
|
||||
TimidityPPMIDIDevice *song = (TimidityPPMIDIDevice *)userdata;
|
||||
//Renderer->HandleEvent(status, parm1, parm2);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD avail, got, didget;
|
||||
//==========================================================================
|
||||
//
|
||||
// TimidityPPMIDIDevice :: HandleLongEvent
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
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, (uint8_t *)buff+didget, len-didget, &got, NULL);
|
||||
didget += got;
|
||||
if (didget >= (DWORD)len)
|
||||
break;
|
||||
void TimidityPPMIDIDevice::HandleLongEvent(const uint8_t *data, int len)
|
||||
{
|
||||
//Renderer->HandleLongMessage(data, len);
|
||||
}
|
||||
|
||||
// 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 ((uint8_t *)buff+didget, 0, len-didget);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
fd_set rfds;
|
||||
struct timeval tv;
|
||||
//==========================================================================
|
||||
//
|
||||
// TimidityPPMIDIDevice :: ComputeOutput
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
if (ChildQuit == song->ChildProcess)
|
||||
{
|
||||
ChildQuit = 0;
|
||||
fprintf(stderr, "child gone\n");
|
||||
song->ChildProcess = -1;
|
||||
return false;
|
||||
}
|
||||
void TimidityPPMIDIDevice::ComputeOutput(float *buffer, int len)
|
||||
{
|
||||
TimidityPlus::run_midi(len / 8); // bytes to samples
|
||||
memset(buffer, len, 0); // to do
|
||||
|
||||
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");
|
||||
|
||||
ssize_t got = 0;
|
||||
do {
|
||||
ssize_t r = read(song->WavePipe[0], (uint8_t*)buff+got, len-got);
|
||||
if(r < 0)
|
||||
{
|
||||
if(errno == EWOULDBLOCK || errno == EAGAIN)
|
||||
{
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(song->WavePipe[0], &rfds);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 50;
|
||||
select(1, &rfds, NULL, NULL, &tv);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
got += r;
|
||||
} while(got < len);
|
||||
if(got < len)
|
||||
memset((uint8_t*)buff+got, 0, len-got);
|
||||
#endif
|
||||
return true;
|
||||
//Renderer->ComputeOutput(buffer, len);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -714,162 +237,6 @@ void TimidityPPMIDIDevice::TimidityVolumeChanged()
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// TimidityPPMIDIDevice :: IsOpen
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool TimidityPPMIDIDevice::IsOpen() const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (ChildProcess != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (WaitForSingleObject(ChildProcess, 0) != WAIT_TIMEOUT)
|
||||
{ // Timidity++ has quit
|
||||
CloseHandle(ChildProcess);
|
||||
const_cast<TimidityPPMIDIDevice *>(this)->ChildProcess = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
if (ChildProcess != -1)
|
||||
{
|
||||
if (waitpid (ChildProcess, NULL, WNOHANG) == ChildProcess)
|
||||
{
|
||||
const_cast<TimidityPPMIDIDevice *>(this)->ChildProcess = -1;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// TimidityPPMIDIDevice :: Resume
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int TimidityPPMIDIDevice::Resume()
|
||||
{
|
||||
if (!Started)
|
||||
{
|
||||
if (LaunchTimidity())
|
||||
{
|
||||
if (Stream != NULL && Stream->Play(true, timidity_mastervolume))
|
||||
{
|
||||
Started = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// TimidityPPMIDIDevice :: Stop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void TimidityPPMIDIDevice::Stop ()
|
||||
{
|
||||
if (Started)
|
||||
{
|
||||
if (Stream != NULL)
|
||||
{
|
||||
Stream->Stop();
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (ChildProcess != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (!SafeTerminateProcess(ChildProcess, 666) && GetLastError() != ERROR_PROCESS_ABORTED)
|
||||
{
|
||||
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
|
||||
}
|
||||
Started = false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
Safely terminate a process by creating a remote thread
|
||||
in the process that calls ExitProcess
|
||||
|
||||
Source is a Dr Dobbs article circa 1999.
|
||||
*/
|
||||
typedef HANDLE (WINAPI *CreateRemoteThreadProto)(HANDLE,LPSECURITY_ATTRIBUTES,SIZE_T,LPTHREAD_START_ROUTINE,LPVOID,DWORD,LPDWORD);
|
||||
|
||||
BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode)
|
||||
{
|
||||
DWORD dwTID, dwCode;
|
||||
HRESULT dwErr = 0;
|
||||
HANDLE hRT = NULL;
|
||||
HINSTANCE hKernel = GetModuleHandle("Kernel32");
|
||||
BOOL bSuccess = FALSE;
|
||||
|
||||
// Detect the special case where the process is already dead...
|
||||
if ( GetExitCodeProcess(hProcess, &dwCode) && (dwCode == STILL_ACTIVE) )
|
||||
{
|
||||
FARPROC pfnExitProc;
|
||||
CreateRemoteThreadProto pfCreateRemoteThread;
|
||||
|
||||
pfnExitProc = GetProcAddress(hKernel, "ExitProcess");
|
||||
|
||||
// CreateRemoteThread does not exist on 9x systems.
|
||||
pfCreateRemoteThread = (CreateRemoteThreadProto)GetProcAddress(hKernel, "CreateRemoteThread");
|
||||
|
||||
if (pfCreateRemoteThread == NULL)
|
||||
{
|
||||
dwErr = ERROR_INVALID_FUNCTION;
|
||||
}
|
||||
else
|
||||
{
|
||||
hRT = pfCreateRemoteThread(hProcess,
|
||||
NULL,
|
||||
0,
|
||||
(LPTHREAD_START_ROUTINE)pfnExitProc,
|
||||
(PVOID)(UINT_PTR)uExitCode, 0, &dwTID);
|
||||
|
||||
if ( hRT == NULL )
|
||||
dwErr = GetLastError();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dwErr = ERROR_PROCESS_ABORTED;
|
||||
}
|
||||
|
||||
if ( hRT )
|
||||
{
|
||||
// Must wait for process to terminate to guarantee that it has exited...
|
||||
DWORD res = WaitForSingleObject(hProcess, 1000);
|
||||
CloseHandle(hRT);
|
||||
bSuccess = (res == WAIT_OBJECT_0);
|
||||
dwErr = WAIT_TIMEOUT;
|
||||
}
|
||||
|
||||
if ( !bSuccess )
|
||||
SetLastError(dwErr);
|
||||
|
||||
return bSuccess;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
MIDIDevice *CreateTimidityPPMIDIDevice(const char *args)
|
||||
{
|
||||
|
|
|
@ -733,6 +733,8 @@ public:
|
|||
|
||||
// Only until streaming works.
|
||||
void skip_to(int32_t until_time, MidiEvent *evt_start);
|
||||
int start_midi(MidiEvent *eventlist, int32_t samples);
|
||||
void run_midi(int);
|
||||
int play_midi(MidiEvent *eventlist, int32_t samples);
|
||||
friend MidiEvent *groom_list(int32_t divisions, int32_t *eventsp, int32_t *samplesp);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -28,6 +29,7 @@
|
|||
#include "tables.h"
|
||||
#include "reverb.h"
|
||||
#include "aq.h"
|
||||
#include "tarray.h"
|
||||
#include <math.h>
|
||||
|
||||
namespace TimidityPlus
|
||||
|
@ -124,10 +126,9 @@ void Player::skip_to(int32_t until_time, MidiEvent *evt_start)
|
|||
}
|
||||
|
||||
|
||||
int Player::play_midi(MidiEvent *eventlist, int32_t samples)
|
||||
int Player::start_midi(MidiEvent *eventlist, int32_t samples)
|
||||
{
|
||||
int rc;
|
||||
static int play_count = 0;
|
||||
int i, j;
|
||||
|
||||
sample_count = samples;
|
||||
|
@ -155,29 +156,9 @@ int Player::play_midi(MidiEvent *eventlist, int32_t samples)
|
|||
|
||||
skip_to(0, eventlist);
|
||||
|
||||
rc = RC_OK;
|
||||
for (;;)
|
||||
{
|
||||
rc = play_event(current_event);
|
||||
if (rc != RC_OK)
|
||||
break;
|
||||
current_event++;
|
||||
}
|
||||
|
||||
if (play_count++ > 3)
|
||||
{
|
||||
int cnt;
|
||||
play_count = 0;
|
||||
cnt = free_global_mblock(); /* free unused memory */
|
||||
if (cnt > 0)
|
||||
ctl_cmsg(CMSG_INFO, VERB_VERBOSE,
|
||||
"%d memory blocks are free", cnt);
|
||||
}
|
||||
return rc;
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static MidiEventList *alloc_midi_event()
|
||||
{
|
||||
return (MidiEventList *)new_segment(&mempool, sizeof(MidiEventList));
|
||||
|
@ -1491,23 +1472,7 @@ static MidiEvent *read_midi_file(struct timidity_file *tf, int32_t *count, int32
|
|||
|
||||
//////////////////////////////////////// MID file player
|
||||
|
||||
// temporary crutch
|
||||
static struct timidity_file *open_file(char *name, int decompress, int noise_mode)
|
||||
{
|
||||
FileReader *fr = new FileReader;
|
||||
if (!fr->Open(name))
|
||||
{
|
||||
delete fr;
|
||||
return nullptr;
|
||||
}
|
||||
auto tf = new timidity_file;
|
||||
tf->url = fr;
|
||||
tf->filename = name;
|
||||
return tf;
|
||||
}
|
||||
|
||||
|
||||
static int play_midi_load_file(char *fn,
|
||||
static int play_midi_load_file(FileReader *fr,
|
||||
MidiEvent **event,
|
||||
int32_t *nsamples)
|
||||
{
|
||||
|
@ -1517,16 +1482,14 @@ static int play_midi_load_file(char *fn,
|
|||
|
||||
*event = NULL;
|
||||
|
||||
ctl_cmsg(CMSG_INFO, VERB_VERBOSE, "MIDI file: %s", fn);
|
||||
if ((tf = open_file(fn, 1, OF_VERBOSE)) == NULL)
|
||||
{
|
||||
return RC_ERROR;
|
||||
}
|
||||
tf = new timidity_file;
|
||||
tf->filename = "zdoom";
|
||||
tf->url = fr;
|
||||
|
||||
*event = NULL;
|
||||
rc = RC_OK;
|
||||
|
||||
*event = read_midi_file(tf, &nevents, nsamples, fn);
|
||||
*event = read_midi_file(tf, &nevents, nsamples, "zdoom");
|
||||
close_file(tf);
|
||||
|
||||
if (*event == NULL)
|
||||
|
@ -1564,15 +1527,35 @@ static int play_midi_load_file(char *fn,
|
|||
}
|
||||
|
||||
|
||||
int play_midi_file(char *fn)
|
||||
|
||||
Instruments *instruments;
|
||||
CRITICAL_SECTION critSect;
|
||||
|
||||
|
||||
int load_midi_file(FileReader *fr)
|
||||
{
|
||||
int rc;
|
||||
static int last_rc = RC_OK;
|
||||
MidiEvent *event;
|
||||
int32_t nsamples;
|
||||
|
||||
InitializeCriticalSection(&critSect);
|
||||
if (play_mode->open_output() < 0)
|
||||
{
|
||||
return RC_ERROR;
|
||||
}
|
||||
|
||||
instruments = new Instruments;
|
||||
if (instruments->load("timidity.cfg"))
|
||||
{
|
||||
return RC_ERROR;
|
||||
}
|
||||
|
||||
gplayer = new Player;
|
||||
|
||||
|
||||
/* Set current file information */
|
||||
auto current_file_info = gplayer->get_midi_file_info(fn, 1);
|
||||
auto current_file_info = gplayer->get_midi_file_info("zdoom", 1);
|
||||
|
||||
rc = RC_OK;
|
||||
|
||||
|
@ -1581,31 +1564,39 @@ int play_midi_file(char *fn)
|
|||
midi_restart_time = 0;
|
||||
|
||||
|
||||
rc = play_midi_load_file(fn, &event, &nsamples);
|
||||
rc = play_midi_load_file(fr, &event, &nsamples);
|
||||
if (RC_IS_SKIP_FILE(rc))
|
||||
goto play_end; /* skip playing */
|
||||
return RC_ERROR; /* skip playing */
|
||||
|
||||
rc = gplayer->play_midi(event, nsamples);
|
||||
|
||||
play_end:
|
||||
|
||||
instruments->free_special_patch(-1);
|
||||
|
||||
if (event != NULL)
|
||||
free(event);
|
||||
|
||||
last_rc = rc;
|
||||
return rc;
|
||||
return gplayer->start_midi(event, nsamples);
|
||||
}
|
||||
|
||||
int dumb_pass_playing_list(int number_of_files, char *list_of_files[])
|
||||
|
||||
void Player::run_midi(int samples)
|
||||
{
|
||||
gplayer = new Player;
|
||||
for (;;)
|
||||
auto time = current_event->time + samples;
|
||||
while (current_event->time < samples)
|
||||
{
|
||||
if (play_midi_file(list_of_files[0]) == RC_QUIT) return 0;
|
||||
if (play_event(current_event) != RC_OK)
|
||||
return;
|
||||
current_event++;
|
||||
}
|
||||
delete gplayer;
|
||||
}
|
||||
|
||||
void run_midi(int msec)
|
||||
{
|
||||
gplayer->run_midi(msec);
|
||||
}
|
||||
|
||||
|
||||
void timidity_close()
|
||||
{
|
||||
delete gplayer;
|
||||
delete instruments;
|
||||
play_mode->close_output();
|
||||
DeleteCriticalSection(&critSect);
|
||||
free_global_mblock();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
TiMidity++ -- MIDI to WAVE converter and player
|
||||
Copyright (C) 1999-2008 Masanao Izumo <iz@onicos.co.jp>
|
||||
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#include <shlobj.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "timidity.h"
|
||||
#include "common.h"
|
||||
#include "instrum.h"
|
||||
#include "playmidi.h"
|
||||
#include "tables.h"
|
||||
#include "reverb.h"
|
||||
#include "resample.h"
|
||||
#include "recache.h"
|
||||
#include "aq.h"
|
||||
#include "mix.h"
|
||||
#include "quantity.h"
|
||||
#include "c_cvars.h"
|
||||
|
||||
namespace TimidityPlus
|
||||
{
|
||||
Instruments *instruments;
|
||||
|
||||
/* main interfaces (To be used another main) */
|
||||
|
||||
int timidity_pre_load_configuration(void);
|
||||
void timidity_init_player(void);
|
||||
int timidity_play_main(int nfiles, char **files);
|
||||
int got_a_configuration;
|
||||
|
||||
|
||||
CRITICAL_SECTION critSect;
|
||||
|
||||
/* -------- functions for getopt_long ends here --------- */
|
||||
|
||||
|
||||
|
||||
int timidity_pre_load_configuration(void)
|
||||
{
|
||||
/* Windows */
|
||||
char *strp;
|
||||
char local[1024];
|
||||
|
||||
|
||||
/* First, try read configuration file which is in the
|
||||
* TiMidity directory.
|
||||
*/
|
||||
if(GetModuleFileNameA(NULL, local, 1023))
|
||||
{
|
||||
local[1023] = '\0';
|
||||
if (strp = strrchr(local, '\\'))
|
||||
{
|
||||
*(++strp) = '\0';
|
||||
strncat(local, "TIMIDITY.CFG", sizeof(local) - strlen(local) - 1);
|
||||
if (true)
|
||||
{
|
||||
if (!instruments->load("timidity.cfg"))
|
||||
{
|
||||
got_a_configuration = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int dumb_pass_playing_list(int number_of_files, char *list_of_files[]);
|
||||
|
||||
int timidity_play_main(int nfiles, char **files)
|
||||
{
|
||||
int need_stdin = 0, need_stdout = 0;
|
||||
int output_fail = 0;
|
||||
int retval;
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
|
||||
InitializeCriticalSection(&critSect);
|
||||
|
||||
#endif
|
||||
|
||||
/* Open output device */
|
||||
|
||||
if(play_mode->open_output() < 0)
|
||||
{
|
||||
output_fail = 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
retval=dumb_pass_playing_list(nfiles, files);
|
||||
|
||||
|
||||
play_mode->close_output();
|
||||
#ifdef _WIN32
|
||||
DeleteCriticalSection (&critSect);
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using namespace TimidityPlus;
|
||||
|
||||
void main(int argc, char **argv)
|
||||
{
|
||||
int err;
|
||||
char *files_nbuf = NULL;
|
||||
int main_ret;
|
||||
instruments = new Instruments;
|
||||
|
||||
if ((err = timidity_pre_load_configuration()) != 0)
|
||||
return;
|
||||
|
||||
main_ret = timidity_play_main(1, &argv[1]);
|
||||
//free_readmidi();
|
||||
free_global_mblock();
|
||||
}
|
||||
|
Loading…
Reference in a new issue