https://github.com/TASEmulators/hourglass-win32/releases/tag/r88
https://github.com/vadosnaprimer/midilogra/releases/tag/1
- When running the game that uses MIDI music in Hourglass, the above build will create midilog.txt in the game directory.
- Put it near midi.lua and execute the script (just drag'n'drop it into fceux or run via lExecutor). midilogra.txt will be created.
- Run midilogra.bat. midilogra.mid will be created.
- Put that file near fluidsynth binaries, along with whatever soundfont you want to use (natt used WeedsGM3.sf2 for Nikujin and Spyman), and run fluidsynth -F outfile.wav soundfont.sf2 midilogra.mid.
- You can preview the soundfont (and convert to wav) in foobar by installing BASSMIDI, just disable all the looping in MIDI synthesizer host options.
- Mix the resulting wav file with audio you got from hourglass AVI (time shift may be needed?)
Mirroring the code files here for paranoid backup:
Download midi.luaLanguage: lua
function logs(s)
local logfile = io.open("midilogra.txt", "a+")
logfile:write(s)
logfile:close()
end
function dooutput (msg)
local timestr = msg[1]
local i = 3
while (i <= #msg) do
local evtype = msg[i]:match ("^.")
--io.write ("##", evtype, "\n")
if evtype == "c" or evtype == "d" then
logs (timestr..",".."0000"..msg[i + 1]..msg[i].."\n")
i = i + 2
else
logs (timestr..",".."00"..msg[i + 2]..msg[i + 1]..msg[i].."\n")
i = i + 3
end
end
end
for line in io.lines ("midilog.txt") do
-- for now, try ignoring special messages
if line:find ("sysex") then
local msg = {}
for token in line:gmatch ("([^,]+)") do
table.insert (msg, token)
end
dooutput (msg)
elseif line:find ("finalizing...") then
local timestr = line:match ("(%d+)")
local channums = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}
for i, v in ipairs (channums) do
logs (timestr..",00007bb"..v.."\n") -- all notes off
end
end
end
Download midilogra.cLanguage: c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int totalbytes = 0;
void decode (unsigned time, unsigned event, FILE *f)
{
static unsigned lasttime = 0;
static int laststatus = 0;
int status = event & 0xff;
int d1, d2;
if (status & 0x80)
{
laststatus = status;
d1 = event >> 8 & 0xff;
d2 = event >> 16 & 0xff;
}
else
{
d1 = status;
status = laststatus;
d2 = event >> 8 & 0xff;
}
unsigned delta = time - lasttime;
lasttime = time;
// write varlen
char writer[4] = {0, 0, 0, 0};
int pos = 0;
while (delta)
{
writer[pos] = delta & 127;
if (pos)
writer[pos] |= 0x80;
pos++;
delta /= 128;
}
if (!pos)
{
writer[0] = 0;
fwrite (writer, 1, 1, f);
totalbytes++;
}
else
{
while (pos > 0)
{
fwrite (writer + pos - 1, 1, 1, f);
totalbytes++;
pos--;
}
}
// aren't actually writing out running status
switch (status & 0xf0)
{
case 0x80: // off
case 0x90: // on
case 0xa0: // aftertouch
case 0xb0: // controller
case 0xe0: // bend
fwrite (&status, 1, 1, f);
fwrite (&d1, 1, 1, f);
fwrite (&d2, 1, 1, f);
totalbytes += 3;
break;
case 0xc0: // program
case 0xd0: // channel aftertouch
fwrite (&status, 1, 1, f);
fwrite (&d1, 1, 1, f);
totalbytes += 2;
break;
default:
fprintf (stderr, "OH MY GOD\n");
exit (0);
}
return;
}
int main (void)
{
FILE *f = fopen ("midilogra.mid", "wb");
char buff[256];
char bigheader[] = {'M', 'T', 'h', 'd',
0, 0, 0, 6,
0, 0,
0, 1,
0, 1}; // midi clocks per quarternote
fwrite (bigheader, 1, 14, f);
char chunkheader[] = {'M', 'T', 'r', 'k', 0xde, 0xad, 0xbe, 0xef};
fwrite (chunkheader, 1, 8, f);
// tempo event (microseconds per quarternote
char openevent[] = {0x00, 0xff, 0x51, 0x03, 0x00, 0x03, 0xe8};
fwrite (openevent, 1, 7, f);
totalbytes += 6;
while (fgets (buff, 256, stdin))
{
unsigned time;
unsigned ev;
if (sscanf (buff, "%u,%x", &time, &ev) != 2)
{
fprintf (stderr, "NO WAY MAN\n");
exit (0);
}
decode (time, ev, f);
}
// end of track event
// lets give ~10 seconds
// 10000ms = 78, 16 (ce 10)
char endevent[] = {0xce, 0x10, 0xff, 0x2f, 0x00};
fwrite (endevent, 1, 5, f);
totalbytes += 5;
fseek (f, 18, SEEK_SET);
char scratch;
scratch = totalbytes >> 24;
fwrite (&scratch, 1, 1, f);
scratch = totalbytes >> 16;
fwrite (&scratch, 1, 1, f);
scratch = totalbytes >> 8;
fwrite (&scratch, 1, 1, f);
scratch = totalbytes;
fwrite (&scratch, 1, 1, f);
fclose (f);
return 0;
}
^ build by simply running
gcc midilogra.c