mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 15:21:51 +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 "tmpfileplus.h"
|
||||||
#include "m_misc.h"
|
#include "m_misc.h"
|
||||||
|
|
||||||
#ifndef _WIN32
|
class TimidityPPMIDIDevice : public SoftSynthMIDIDevice
|
||||||
#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
|
|
||||||
{
|
{
|
||||||
|
TArray<uint8_t> midi;
|
||||||
|
FString CurrentConfig;
|
||||||
public:
|
public:
|
||||||
TimidityPPMIDIDevice(const char *args);
|
TimidityPPMIDIDevice(const char *args);
|
||||||
~TimidityPPMIDIDevice();
|
~TimidityPPMIDIDevice();
|
||||||
|
|
||||||
int Open(MidiCallback, void *userdata);
|
int Open(MidiCallback, void *userdata);
|
||||||
bool Preprocess(MIDIStreamer *song, bool looping);
|
void PrecacheInstruments(const uint16_t *instruments, int count);
|
||||||
bool IsOpen() const;
|
//FString GetStats();
|
||||||
int Resume();
|
|
||||||
|
|
||||||
void Stop();
|
|
||||||
bool IsOpen();
|
|
||||||
void TimidityVolumeChanged();
|
|
||||||
int GetDeviceType() const override { return MDEV_TIMIDITY; }
|
int GetDeviceType() const override { return MDEV_TIMIDITY; }
|
||||||
|
bool Preprocess(MIDIStreamer *song, bool looping);
|
||||||
|
void TimidityVolumeChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool LaunchTimidity();
|
//TimidityPlus::Player *Renderer;
|
||||||
|
|
||||||
FString DiskName;
|
void HandleEvent(int status, int parm1, int parm2);
|
||||||
#ifdef _WIN32
|
void HandleLongEvent(const uint8_t *data, int len);
|
||||||
HANDLE ReadWavePipe;
|
void ComputeOutput(float *buffer, int len);
|
||||||
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
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Config file to use
|
||||||
|
CVAR(String, timidity_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||||
#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)
|
|
||||||
|
|
||||||
// added because Timidity's output is rather loud.
|
// added because Timidity's output is rather loud.
|
||||||
CUSTOM_CVAR (Float, timidity_mastervolume, 1.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
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();
|
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)
|
CUSTOM_CVAR (Int, timidity_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
{ // Clamp frequency to Timidity's limits
|
{ // 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) :
|
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)
|
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
if (args == NULL || *args == 0) args = timidity_config;
|
||||||
WavePipe[0] = WavePipe[1] = -1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (args == NULL || *args == 0) args = timidity_exe;
|
if (CurrentConfig.CompareNoCase(args) != 0)
|
||||||
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')
|
|
||||||
{
|
{
|
||||||
CommandLine += "-c \"";
|
// reload instruments
|
||||||
CommandLine += timidity_config;
|
// if (!reload_inst()) CurrentConfig = "";
|
||||||
CommandLine += "\" ";
|
}
|
||||||
|
if (CurrentConfig.IsNotEmpty())
|
||||||
|
{
|
||||||
|
//Renderer = new TimidityPlus::Player(timidity_frequency, args);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -204,34 +120,14 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) :
|
||||||
|
|
||||||
TimidityPPMIDIDevice::~TimidityPPMIDIDevice ()
|
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)
|
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
|
// Write MIDI song to temporary file
|
||||||
song->CreateSMF(midi, looping ? 0 : 1);
|
song->CreateSMF(midi, looping ? 0 : 1);
|
||||||
|
return midi.Size() > 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -290,414 +148,79 @@ bool TimidityPPMIDIDevice::Preprocess(MIDIStreamer *song, bool looping)
|
||||||
// TimidityPPMIDIDevice :: Open
|
// 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 TimidityPPMIDIDevice::Open(MidiCallback callback, void *userdata)
|
||||||
{
|
{
|
||||||
int pipeSize;
|
int ret = OpenStream(2, 0, callback, userdata);
|
||||||
|
if (ret == 0)
|
||||||
#ifdef _WIN32
|
|
||||||
static SECURITY_ATTRIBUTES inheritable = { sizeof(inheritable), NULL, true };
|
|
||||||
|
|
||||||
if (!Validated && !ValidateTimidity ())
|
|
||||||
{
|
{
|
||||||
return 101;
|
//Renderer->Reset();
|
||||||
|
MemoryReader fr((char*)&midi[0], midi.Size());
|
||||||
|
return !TimidityPlus::load_midi_file(&fr);
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// TimidityPPMIDIDevice :: ValidateTimidity
|
// TimidityPPMIDIDevice :: PrecacheInstruments
|
||||||
//
|
//
|
||||||
// Check that this TiMidity++ knows about the TiMidity Killer event.
|
// Each entry is packed as follows:
|
||||||
// If not, then we can't use it, because Win32 provides no other way
|
// Bits 0- 6: Instrument number
|
||||||
// to conveniently signal it to quit. The check is done by simply
|
// Bits 7-13: Bank number
|
||||||
// searching for the event's name somewhere in the executable.
|
// Bit 14: Select drum set if 1, tone bank if 0
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
#ifdef _WIN32
|
void TimidityPPMIDIDevice::PrecacheInstruments(const uint16_t *instruments, int count)
|
||||||
bool TimidityPPMIDIDevice::ValidateTimidity()
|
|
||||||
{
|
{
|
||||||
char foundPath[MAX_PATH];
|
for (int i = 0; i < count; ++i)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
Printf(PRINT_BOLD, "Please set the timidity_exe cvar to the location of TiMidity++\n");
|
//Renderer->MarkInstrument((instruments[i] >> 7) & 127, instruments[i] >> 14, instruments[i] & 127);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (pathLen > MAX_PATH)
|
//Renderer->load_missing_instruments();
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// 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)
|
void TimidityPPMIDIDevice::HandleLongEvent(const uint8_t *data, int len)
|
||||||
{ // If nothing is available from the pipe, play silence.
|
{
|
||||||
memset (buff, 0, len);
|
//Renderer->HandleLongMessage(data, len);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
didget = 0;
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
ReadFile(song->ReadWavePipe, (uint8_t *)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)
|
// TimidityPPMIDIDevice :: ComputeOutput
|
||||||
{
|
//
|
||||||
memset ((uint8_t *)buff+didget, 0, len-didget);
|
//==========================================================================
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
fd_set rfds;
|
|
||||||
struct timeval tv;
|
|
||||||
|
|
||||||
if (ChildQuit == song->ChildProcess)
|
void TimidityPPMIDIDevice::ComputeOutput(float *buffer, int len)
|
||||||
{
|
{
|
||||||
ChildQuit = 0;
|
TimidityPlus::run_midi(len / 8); // bytes to samples
|
||||||
fprintf(stderr, "child gone\n");
|
memset(buffer, len, 0); // to do
|
||||||
song->ChildProcess = -1;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
FD_ZERO(&rfds);
|
//Renderer->ComputeOutput(buffer, len);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -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)
|
MIDIDevice *CreateTimidityPPMIDIDevice(const char *args)
|
||||||
{
|
{
|
||||||
|
|
|
@ -733,6 +733,8 @@ public:
|
||||||
|
|
||||||
// Only until streaming works.
|
// Only until streaming works.
|
||||||
void skip_to(int32_t until_time, MidiEvent *evt_start);
|
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);
|
int play_midi(MidiEvent *eventlist, int32_t samples);
|
||||||
friend MidiEvent *groom_list(int32_t divisions, int32_t *eventsp, int32_t *samplesp);
|
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
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -28,6 +29,7 @@
|
||||||
#include "tables.h"
|
#include "tables.h"
|
||||||
#include "reverb.h"
|
#include "reverb.h"
|
||||||
#include "aq.h"
|
#include "aq.h"
|
||||||
|
#include "tarray.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
namespace TimidityPlus
|
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;
|
int rc;
|
||||||
static int play_count = 0;
|
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
sample_count = samples;
|
sample_count = samples;
|
||||||
|
@ -155,29 +156,9 @@ int Player::play_midi(MidiEvent *eventlist, int32_t samples)
|
||||||
|
|
||||||
skip_to(0, eventlist);
|
skip_to(0, eventlist);
|
||||||
|
|
||||||
rc = RC_OK;
|
return 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static MidiEventList *alloc_midi_event()
|
static MidiEventList *alloc_midi_event()
|
||||||
{
|
{
|
||||||
return (MidiEventList *)new_segment(&mempool, sizeof(MidiEventList));
|
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
|
//////////////////////////////////////// MID file player
|
||||||
|
|
||||||
// temporary crutch
|
static int play_midi_load_file(FileReader *fr,
|
||||||
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,
|
|
||||||
MidiEvent **event,
|
MidiEvent **event,
|
||||||
int32_t *nsamples)
|
int32_t *nsamples)
|
||||||
{
|
{
|
||||||
|
@ -1517,16 +1482,14 @@ static int play_midi_load_file(char *fn,
|
||||||
|
|
||||||
*event = NULL;
|
*event = NULL;
|
||||||
|
|
||||||
ctl_cmsg(CMSG_INFO, VERB_VERBOSE, "MIDI file: %s", fn);
|
tf = new timidity_file;
|
||||||
if ((tf = open_file(fn, 1, OF_VERBOSE)) == NULL)
|
tf->filename = "zdoom";
|
||||||
{
|
tf->url = fr;
|
||||||
return RC_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
*event = NULL;
|
*event = NULL;
|
||||||
rc = RC_OK;
|
rc = RC_OK;
|
||||||
|
|
||||||
*event = read_midi_file(tf, &nevents, nsamples, fn);
|
*event = read_midi_file(tf, &nevents, nsamples, "zdoom");
|
||||||
close_file(tf);
|
close_file(tf);
|
||||||
|
|
||||||
if (*event == NULL)
|
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;
|
int rc;
|
||||||
static int last_rc = RC_OK;
|
static int last_rc = RC_OK;
|
||||||
MidiEvent *event;
|
MidiEvent *event;
|
||||||
int32_t nsamples;
|
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 */
|
/* 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;
|
rc = RC_OK;
|
||||||
|
|
||||||
|
@ -1581,31 +1564,39 @@ int play_midi_file(char *fn)
|
||||||
midi_restart_time = 0;
|
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))
|
if (RC_IS_SKIP_FILE(rc))
|
||||||
goto play_end; /* skip playing */
|
return RC_ERROR; /* skip playing */
|
||||||
|
|
||||||
rc = gplayer->play_midi(event, nsamples);
|
return gplayer->start_midi(event, nsamples);
|
||||||
|
|
||||||
play_end:
|
|
||||||
|
|
||||||
instruments->free_special_patch(-1);
|
|
||||||
|
|
||||||
if (event != NULL)
|
|
||||||
free(event);
|
|
||||||
|
|
||||||
last_rc = rc;
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int dumb_pass_playing_list(int number_of_files, char *list_of_files[])
|
|
||||||
|
void Player::run_midi(int samples)
|
||||||
{
|
{
|
||||||
gplayer = new Player;
|
auto time = current_event->time + samples;
|
||||||
for (;;)
|
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