Initial community commit

This commit is contained in:
Jef
2024-09-24 14:54:57 +02:00
parent 37b4fd1b06
commit 0954e03b3a
17196 changed files with 4848281 additions and 2 deletions

View File

@ -0,0 +1,270 @@
#include "CompressionUtility.h"
#include "malloc.h"
#include <cstring>
#include "zlib.h"
#include "minizip/unzip.h"
#define dir_delimter '/'
#define MAX_FILENAME 512
#define READ_SIZE 8192
/// <summary>
/// Compress given buffer as GZIP.
/// Dont forget to free out buffer!!!!
/// </summary>
/// <param name="input"></param>
/// <param name="input_size"></param>
/// <param name="ppvOut"></param>
/// <param name="out_size"></param>
/// <returns></returns>
int CompressionUtility::CompressAsGZip(const void* input, size_t input_size, void** ppvOut, size_t& out_size)
{
z_stream zlib_stream;
zlib_stream.next_in = (Bytef*)input;
zlib_stream.avail_in = (uInt)input_size;
zlib_stream.next_out = Z_NULL;
zlib_stream.avail_out = Z_NULL;
zlib_stream.zalloc = (alloc_func)0;
zlib_stream.zfree = (free_func)0;
zlib_stream.opaque = 0;
int ret = deflateInit2(&zlib_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (16 + MAX_WBITS), 8, Z_DEFAULT_STRATEGY);
unsigned full_length = 2000;
unsigned half_length = input_size / 2;
unsigned compLength = full_length;
unsigned char* comp = (unsigned char*)malloc(compLength);
bool done = false;
while (!done)
{
if (zlib_stream.total_out >= compLength)
{
// Increase size of output buffer
unsigned char* uncomp2 = (unsigned char*)malloc(compLength + half_length);
memcpy(uncomp2, comp, compLength);
compLength += half_length;
free(comp);
comp = uncomp2;
}
zlib_stream.next_out = (Bytef*)(comp + zlib_stream.total_out);
zlib_stream.avail_out = compLength - zlib_stream.total_out;
// Deflate another chunk.
ret = deflate(&zlib_stream, Z_FINISH);
if (Z_STREAM_END == ret)
{
done = true;
}
else if (Z_OK != ret)
{
break;
}
}
if (Z_OK != deflateEnd(&zlib_stream))
{
free(comp);
return ret;
}
*ppvOut = (void*)comp;
out_size = zlib_stream.total_out;
return ret;
}
/// <summary>
/// Decompress given buffer.
/// Dont forget to free out buffer!!!!
/// </summary>
/// <param name="input"></param>
/// <param name="input_size"></param>
/// <param name="ppvOut"></param>
/// <param name="out_size"></param>
/// <returns></returns>
int CompressionUtility::DecompressGZip(const void* input, size_t input_size, void** ppvOut, size_t& out_size)
{
z_stream zlib_stream;
zlib_stream.next_in = (Bytef*)input;
zlib_stream.avail_in = (uInt)input_size;
zlib_stream.next_out = Z_NULL;
zlib_stream.avail_out = Z_NULL;
zlib_stream.zalloc = (alloc_func)0;
zlib_stream.zfree = (free_func)0;
zlib_stream.opaque = Z_NULL;
int ret = inflateInit2(&zlib_stream, (16 + MAX_WBITS));
if (Z_OK != ret)
{
return ret;
}
unsigned full_length = input_size;
unsigned half_length = input_size / 2;
unsigned uncompLength = full_length;
unsigned char* uncomp = (unsigned char*)malloc(uncompLength);
bool done = false;
while (!done)
{
if (zlib_stream.total_out >= uncompLength)
{
// Increase size of output buffer
unsigned char* uncomp2 = (unsigned char*)malloc(uncompLength + half_length);
memcpy(uncomp2, uncomp, uncompLength);
uncompLength += half_length;
free(uncomp);
uncomp = uncomp2;
}
zlib_stream.next_out = (Bytef*)(uncomp + zlib_stream.total_out);
zlib_stream.avail_out = uncompLength - zlib_stream.total_out;
// Inflate another chunk.
ret = inflate(&zlib_stream, Z_SYNC_FLUSH);
if (Z_STREAM_END == ret)
{
done = true;
}
else if (Z_OK != ret)
{
break;
}
}
if (Z_OK != inflateEnd(&zlib_stream))
{
free(uncomp);
return ret;
}
*ppvOut = (void*)uncomp;
out_size = zlib_stream.total_out;
return ret;
}
/// <summary>
/// Returns inflated first file inside the ZIP container,
/// rest are ignored!!!!!
/// </summary>
/// <param name="input"></param>
/// <param name="input_size"></param>
/// <param name="ppvOut"></param>
/// <param name="out_size"></param>
/// <returns></returns>
int CompressionUtility::DecompressPKZip(const char* fn, void** ppvOut, size_t& out_size)
{
// Open the zip file
unzFile zipfile = unzOpen(fn);
if (nullptr == zipfile)
{
// file not found
return -1;
}
// Get info about the zip file
unz_global_info global_info;
if (UNZ_OK != unzGetGlobalInfo(zipfile, &global_info))
{
// could not read file global info
unzClose(zipfile);
return -1;
}
// Buffer to hold data read from the zip file.
//char read_buffer[READ_SIZE];
// Loop to extract all files
for (uLong i = 0; i < global_info.number_entry; ++i)
{
// Get info about current file.
unz_file_info file_info;
char filename[MAX_FILENAME];
if (unzGetCurrentFileInfo(
zipfile,
&file_info,
filename,
MAX_FILENAME,
NULL, 0, NULL, 0) != UNZ_OK)
{
// could not read file info
unzClose(zipfile);
return -1;
}
// Check if this entry is a directory or file.
const size_t filename_length = strlen(filename);
if (filename[filename_length - 1] == dir_delimter)
{
// Entry is a directory, skip it
}
else
{
// Entry is a file, so extract it.
if (unzOpenCurrentFile(zipfile) != UNZ_OK)
{
// could not open file
unzClose(zipfile);
return -1;
}
unsigned full_length = READ_SIZE * 2;
unsigned half_length = READ_SIZE;
unsigned uncompLength = full_length;
unsigned char* uncomp = (unsigned char*)malloc(uncompLength);
size_t total_out = 0;
int error = UNZ_OK;
do
{
if (total_out >= uncompLength)
{
// Increase size of output buffer
unsigned char* uncomp2 = (unsigned char*)malloc(uncompLength + half_length);
memcpy(uncomp2, uncomp, uncompLength);
uncompLength += half_length;
free(uncomp);
uncomp = uncomp2;
}
error = unzReadCurrentFile(zipfile, uncomp + total_out, uncompLength - total_out);
if (error < 0)
{
// something happened
unzCloseCurrentFile(zipfile);
unzClose(zipfile);
return -1;
}
// Write data to buffer.
if (error > 0)
{
total_out += error;
}
} while (error > 0);
*ppvOut = (void*)uncomp;
out_size = total_out;
}
unzCloseCurrentFile(zipfile);
// Go the the next entry listed in the zip file.
//if ((i + 1) < global_info.number_entry)
//{
// if (unzGoToNextFile(zipfile) != UNZ_OK)
// {
// printf("cound not read next file\n");
// unzClose(zipfile);
// return -1;
// }
//}
}
unzClose(zipfile);
return UNZ_OK;
}

View File

@ -0,0 +1,13 @@
#pragma once
/// <summary>
///
/// </summary>
class CompressionUtility
{
public:
static int CompressAsGZip(const void* input, size_t input_size, void** ppvOut, size_t& out_size);
static int DecompressGZip(const void* input, size_t input_size, void** ppvOut, size_t& out_size);
static int DecompressPKZip(const char* fn, void** ppvOut, size_t& out_size);
};

View File

@ -0,0 +1,2 @@
#include "../Winamp/in2.h"

View File

@ -0,0 +1,587 @@
#include "main.h"
#pragma warning(disable:4200)
extern BYTE ff7loopstart[12];
extern BYTE ff7loopend[10];
extern cfg_int cfg_hack_xg_drums, cfg_hack_dls_instruments, cfg_hack_dls_drums, cfg_ff7loopz;
typedef union
{
BYTE b[4];
DWORD dw;
} b_dw;
typedef struct
{
DWORD pos, tm, sz;
BYTE le;
BYTE data[];
}
TRACK;
DWORD _fastcall rev32(DWORD);
//WORD _fastcall rev16(WORD);
int test_drum_kit(DWORD no, IDirectMusicCollection* dls);
void do_dls_check(DWORD * i, IDirectMusicCollection * dls);
class CCleaner
{
public:
INSTRUMENT_DESC* instr, **instr_ptr;
BYTE ctab[16][128];
// UINT dm_vol;
grow_buf outbuf;
UINT ntrax, ntrax1;
UINT maxvol;
TRACK** in_trax;
TRACK* out_trax[16];
DWORD ct;
UINT tf;
MIDI_file* mf;
DWORD vol_set;
bool drumfix, insfix;
b_dw ins[16], ins_set[16];
bool f2, tr1, dm, only_ins, ins_no_lsb;
bool hasnotes[16];
void check_ins(UINT msb, UINT lsb, UINT patch, UINT note, BOOL drum, UINT ch) //called on note
{
if (ins_no_lsb) lsb = 0;
INSTRUMENT_DESC * d = instr;
while (d)
{
if (d->bank_hi == msb && d->bank_lo == lsb && d->patch == patch && d->drum == drum) break;
d = d->next;
}
if (d)
{
d->count++;
if (d->note_max < note) d->note_max = note;
if (d->note_min > note) d->note_min = note;
d->channels |= 1 << ch;
}
else
{
d = new INSTRUMENT_DESC;
*instr_ptr = d;
instr_ptr = &d->next;
d->next = 0;
d->note_min = d->note_max = note;
d->bank_hi = msb;
d->bank_lo = lsb;
d->patch = patch;
d->count = 1;
d->drum = drum;
d->user = 0;
d->channels = 1 << ch;
}
}
void AdvanceTime(TRACK* t);
void AddEvent(BYTE ev, BYTE* data);
void WriteTrack(TRACK* t);
int Run(MIDI_file* mf, DWORD, void ** out_data, int * out_size);
void do_shit(UINT n);
UINT get_next_time()
{
UINT t = -1;
UINT n;
for (n = 0;n < ntrax;n++)
{
UINT t1 = in_trax[n]->tm;
if (t1 < t) t = t1;
}
return t;
}
BOOL event_ok(BYTE e, BYTE* p)
{
BYTE _c = e & 0xF0;
BYTE ch = e & 0xF;
if (_c == 0xB0)
{
if (cfg_hack_xg_drums && ch == 9 && p[1] == 0 && (p[0] == 0 || p[0] == 0x20))
return 0;
if (p[0] > 127)
return 0;
ctab[ch][p[0]] = p[1];
if (p[0] == 0)
{
ins[ch].b[2] = p[1];
if (insfix) return 0;
}
if (p[0] == 0x20)
{
ins[ch].b[1] = p[1];
if (insfix) return 0;
}
if (dm) //keep dm drivers happy...
{
if (p[0] >= 0x20 && p[0] < 0x40) //lsb values
{
return 0;
}
else if (p[0] < 0x20)
{
BYTE data[2] = {(BYTE)(p[0] + 0x20),ctab[ch][p[0] + 0x20]};
AddEvent(e, data);
}
}
return 1;
}
else if (_c == 0xC0)
{
if (ch == 9)
{
if (drumfix && !test_drum_kit(p[0], mf->pDLS)) return 0;
ins[ch].b[0] = p[0];
}
else
{
ins[ch].b[0] = p[0];
if (insfix) return 0;
}
}
else if (_c == 0x90 && p[1])
{
if (only_ins)
check_ins(ins[ch].b[2], ins[ch].b[1], ins[ch].b[0], p[0], ch == 9, ch);
if (ch != 9 && insfix)
{
if (ins_set[ch].dw != ins[ch].dw)
{
do_dls_check(&ins[ch].dw, mf->pDLS);
if (ins_set[ch].b[1] != ins[ch].b[1])
{
BYTE t[2] = {0x20, ins[ch].b[1]};
AddEvent(0xB0 | ch, t);
}
if (ins_set[ch].b[2] != ins[ch].b[2])
{
BYTE t[2] = {0, ins[ch].b[2]};
AddEvent(0xB0 | ch, t);
}
AddEvent(0xC0 | ch, ins[ch].b);
ins_set[ch].dw = ins[ch].dw;
}
}
}
return 1;
}
CCleaner()
{
memset(ins, 0, sizeof(ins));
memset(ins_set, -1, sizeof(ins_set));
memset(hasnotes, 0, sizeof(hasnotes));
memset(out_trax, 0, sizeof(out_trax));
in_trax = 0;
}
~CCleaner()
{
UINT n;
if (in_trax)
{
for (n = 0;n < ntrax;n++)
if (in_trax[n]) {free(in_trax[n]);in_trax[n] = 0;}
free(in_trax);
}
for (n = 0;n < 16;n++)
{
if (out_trax[n])
{
free(out_trax[n]);
out_trax[n] = 0;
}
}
}
};
void CCleaner::do_shit(UINT n)
{
BYTE ce = 0;
TRACK* t = in_trax[n];
if (!t) return ;
while (t->tm == ct)
{
if (t->pos >= t->sz)
{
t->pos = -1;
t->tm = -1;
tf++;
break;
}
BYTE c0 = t->data[t->pos];
if (c0 == 0xFF) //Meta-events
{
if (cfg_ff7loopz
&& (t->sz - t->pos) >= sizeof(ff7loopend) // bounds check
&& !memcmp(t->data + t->pos, ff7loopend, sizeof(ff7loopend)))
{
// MessageBox(GetActiveWindow(),"blah",0,0);
// AdvanceTime(t);
tf = ntrax;
// return;
}
BYTE c1 = t->data[t->pos + 1];
if (c1 == 0x2F)
{
t->pos += 3;
t->tm = -1;
tf++;
}
{
t->pos += 2;
if (t->pos < t->sz)
{
unsigned int _d;
t->pos += DecodeDelta(t->data + t->pos, &_d, t->sz - t->pos);
t->pos += _d;
}
}
} else if (c0 == 0xF0)
{
t->pos += ReadSysex(&t->data[t->pos], t->sz - t->pos);
}
else if (c0 == 0xF7) t->pos++;
else if ((c0&0xF0) == 0xF0) //WTF?
{
t->pos = -1;
t->tm = -1;
tf++;
break;
}
else
{
if (c0&0x80)
{
ce = c0;
t->pos++;
}
else ce = t->le;
if (event_ok(ce, &t->data[t->pos])) AddEvent(ce, &t->data[t->pos]);
if ((ce&0xF0) == 0xC0 || (ce&0xF0) == 0xD0) t->pos++;
else t->pos += 2;
t->le = ce;
}
if (t->tm != -1 && t->pos >= t->sz)
{
t->pos = -1;
t->tm = -1;
tf++;
break;
}
AdvanceTime(t);
}
}
#define WriteBuf(A,B) outbuf.write(A,B)
#pragma pack(push)
#pragma pack(1)
typedef struct
{
WORD t, n, d;
}
MHD;
typedef struct
{
DWORD c, s;
}
CHD;
#pragma pack(pop)
void CCleaner::AdvanceTime(TRACK* t)
{
if (t->tm != -1)
{
unsigned int d;
UINT _n = DecodeDelta(t->data + t->pos, &d, t->sz - t->pos);
if (_n < 4) t->tm += d;
t->pos += _n;
}
}
void CCleaner::AddEvent(BYTE ev, BYTE* data)
{
if (only_ins) return ;
BYTE nt = ev & 0xF;
BYTE ec = ev & 0xF0;
if (tr1) nt = 0;
TRACK *t = out_trax[nt];
ZeroMemory(ctab, sizeof(ctab));
if (!t)
{
t = out_trax[nt] = (TRACK*)malloc(sizeof(TRACK) + 0x1000);
if (!t) return ;
ZeroMemory(t, 16);
t->sz = 0x1000;
t->tm = 0;
}
else if (t->pos > t->sz - 0x10)
{
t->sz *= 2;
out_trax[nt] = (TRACK*)realloc(t, sizeof(TRACK) + t->sz);
if (!out_trax[nt])
{
free(t);
return ;
}
t = out_trax[nt];
}
if (t->tm < ct)
{
t->pos += EncodeDelta(&t->data[t->pos], ct - t->tm);
t->tm = ct;
}
else
{
t->data[t->pos++] = 0;
}
if (ec == 0x90)
{
hasnotes[nt] = 1;
data[0] &= 0x7F; /* don't allow 8bit note numbers */
}
else if (ec == 0x80)
{
data[0] &= 0x7F; /* don't allow 8bit note numbers */
}
/*if (ev!=t->le) */{t->data[t->pos++] = ev;t->le = ev;}
t->data[t->pos++] = data[0];
if (ec != 0xC0 && ec != 0xD0) t->data[t->pos++] = data[1];
}
void CCleaner::WriteTrack(TRACK* t)
{
CHD chd;
chd.c = 'krTM';
chd.s = rev32(t->pos);
WriteBuf(&chd, 8);
WriteBuf(&t->data, t->pos);
ntrax1++;
}
int DoCleanUp(MIDI_file* mf, DWORD mode, void** out_data, int * out_size)
{
CCleaner c;
c.only_ins = 0;
return c.Run(mf, mode, out_data, out_size);
}
int CCleaner::Run(MIDI_file* _mf, DWORD _md, void ** out_data, int * out_size)
{
f2 = *(WORD*)(_mf->data + 8) == 0x0200;
maxvol = 90;
vol_set = 0;
dm = (_md & CLEAN_DM) ? 1 : 0;
tr1 = (_md & CLEAN_1TRACK) ? 1 : 0;
if (_md&CLEAN_DLS)
{
drumfix = dm && cfg_hack_dls_drums;
insfix = dm && cfg_hack_dls_instruments;
}
else
{
drumfix = insfix = 0;
}
mf = _mf;
instr_ptr = &instr;
instr = 0;
UINT n;
ct = 0;
tf = 0;
ntrax = ntrax1 = 0;
CHD chd;
MHD mhd;
DWORD ptr = 8;
mhd = *(MHD*)(mf->data + 8);
ptr += 6;
mhd.t = rev16(mhd.t);
mhd.n = rev16(mhd.n);
if (mhd.t > 2)
goto fail;
ntrax = mhd.n;
n = 0;
in_trax = (TRACK**)malloc(sizeof(void*) * ntrax);
for (;n < ntrax && ptr < (UINT)mf->size;n++)
{
chd = *(CHD*)(mf->data + ptr);
ptr += 8;
if (chd.c != 'krTM' || ptr > (UINT)mf->size)
{
ntrax = n;
break;
}
chd.s = rev32(chd.s);
//if (ptr+chd.s>(UINT)mf->size)
if (chd.s > ((UINT)mf->size - ptr))
{
chd.s = mf->size - ptr;
}
//goto fail;
in_trax[n] = (TRACK*)malloc(16 + chd.s);
in_trax[n]->sz = chd.s;
in_trax[n]->tm = 0;
in_trax[n]->le = 0;
in_trax[n]->pos = 0;
memcpy(in_trax[n]->data, mf->data + ptr, chd.s);
ptr += chd.s;
AdvanceTime(in_trax[n]);
}
if (f2)
{
for (n = 0;n < ntrax;n++)
{
in_trax[n]->tm = ct;
while (tf <= n)
{
do_shit(n);
if (in_trax[n]->tm != -1) ct = in_trax[n]->tm;
}
}
}
else
{
while (tf < ntrax)
{
UINT nt = get_next_time(); //ct++;
if (nt == -1) break;
ct = nt;
for (n = 0;n < ntrax && tf < ntrax;n++)
{
do_shit(n);
}
}
}
if (!only_ins)
{
mhd.t = 0x0100;
mhd.n = 0; //rev16(ntrax1);
chd.c = 'dhTM';
chd.s = 0x06000000;
WriteBuf(&chd, 8);
WriteBuf(&mhd, 6);
if (!(_md&CLEAN_NOTEMPO) && mf->tmap)
{
/* BYTE *tt=mf->tmap->BuildTrack();
if (tt)
{
WriteBuf(tt,rev32(*(DWORD*)(tt+4))+8);
ntrax1++;
free(tt);
}*/
if (mf->tmap->BuildTrack(outbuf))
{
ntrax1++;
}
}
if (!(_md&CLEAN_NOSYSEX) && mf->smap)
{
/* BYTE *st=mf->smap->BuildTrack();
if (st)
{
WriteBuf(st,rev32(*(DWORD*)(st+4))+8);
ntrax1++;
free(st);
}*/
if (mf->smap->BuildTrack(outbuf))
{
ntrax1++;
}
}
for (n = 0;n < 16;n++) if (out_trax[n] && hasnotes[n] && out_trax[n]->pos)
{
TRACK *t = out_trax[n];
t->pos += EncodeDelta(t->data + t->pos, ct - t->tm);
t->data[t->pos++] = 0xFF;
t->data[t->pos++] = 0x2F;
t->data[t->pos++] = 0;
WriteTrack(t);
}
{
WORD t = rev16(ntrax1);
outbuf.write_ptr(&t, 2, 10);
}
if (out_size) *out_size = outbuf.get_size();
if (out_data) *out_data = outbuf.finish();
#if 0
{
HANDLE f = CreateFile("c:\\dump.mid", GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
DWORD bw = 0;
WriteFile(f, rv, bs, &bw, 0);
CloseHandle(f);
}
#endif
}
return 1;
fail:
// ErrorBox("WARNING: cleaner messed up");
return 0;
//TO DESTRUCTOR
}
INSTRUMENT_DESC* GetInstruments(MIDI_file* mf, BOOL do_lsb)
{
CCleaner c;
c.only_ins = 1;
c.ins_no_lsb = !do_lsb;
c.Run(mf, 0, 0, 0);
return c.instr;
}

View File

@ -0,0 +1,48 @@
#include "main.h"
#include "cvt.h"
bool is_cmf(const BYTE* buf,size_t s)
{
return s>0x20 && *(DWORD*)buf == _rv('CTMF');
}
static BYTE tempodat[7]={0,0xFF,0x51,0x03,0,0,0};
bool load_cmf(MIDI_file * mf,const BYTE* ptr,size_t sz)
{
if (sz < 14)
return 0;
WORD music_offset = *(WORD*)(ptr+8);
if ((size_t)music_offset > sz)
return 0;
const BYTE* _t=ptr+music_offset;
size_t total_size=sz - music_offset;
mf->size=14+8+7+total_size;
BYTE* _pt=(BYTE*)malloc(mf->size);
if (!_pt) return 0;
mf->data=_pt;
*(DWORD*)_pt=_rv('MThd');
_pt+=4;
*(DWORD*)_pt=_rv(6);
_pt+=4;
*(WORD*)_pt=0;
_pt+=2;
*(WORD*)_pt=0x0100;
_pt+=2;
*(WORD*)_pt=rev16(*(WORD*)(ptr+10));
_pt+=2;
*(DWORD*)_pt=_rv('MTrk');
_pt+=4;
*(DWORD*)_pt=rev32(total_size+7);
_pt+=4;
DWORD tm=(DWORD)(48000000/(*(WORD*)(ptr+12)));
tempodat[4]=(BYTE)((tm>>16)&0xFF);
tempodat[5]=(BYTE)((tm>>8)&0xFF);
tempodat[6]=(BYTE)(tm&0xFF);
memcpy(_pt,tempodat,7);
_pt+=7;
memcpy(_pt,_t,total_size);
return 1;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,61 @@
#ifndef __CORE_API_H
#define __CORE_API_H
//ancient tempura header. yay.
#ifndef ASSERT
#ifdef _DEBUG
#define ASSERT(x) if (!(x)) MessageBox(NULL,"ASSERT FAILED: " #x,"ASSERT FAILED in " __FILE__ ,MB_OK|MB_ICONSTOP);
#else
#define ASSERT(x)
#endif
#endif
class WReader;
class WPlayer_callback
{
public:
virtual WReader *GetReader(char *url)=0;
virtual void Error(char *reason)=0;
virtual void Warning(char *warning)=0;
virtual void Status(char *status)=0;
virtual void TitleChange(char *new_title)=0;
virtual void InfoChange(char *new_info_str, int new_length)=0;
virtual void UrlChange(char *new_url)=0;
};
class WInfo_callback
{
public:
virtual WReader *GetReader(char *url)=0;
};
class WReader
{
protected:
WReader() : m_player(0) { }
public:
WPlayer_callback *m_player;
virtual char *GetDescription() { return 0; };
virtual int Open(char *url, char *killswitch)=0;
virtual int Read(char *buffer, int length, char *killswitch)=0;
virtual int GetLength(void)=0;
virtual int CanSeek(void)=0;
virtual int Seek(int position, char *killswitch)=0;
virtual char *GetHeader(char *name) { return 0; }
virtual ~WReader() { }
};
#define READ_VER 0x100
#define OF_VER 0x100
typedef struct
{
int version;
char *description;
WReader *(*create)();
int (*ismine)(char *url);
} reader_source;
#endif

View File

@ -0,0 +1,21 @@
#ifndef STRICT
#define STRICT 1
#endif
#include <windows.h>
#include <math.h>
#include <malloc.h>
#include <mmsystem.h>
#include <dsound.h>
#ifndef MF_NO_DMCRAP
#include <dmusici.h>
#include <dmusicf.h>
#endif
class WReader;
struct CTempoMap;
struct CSysexMap;
#include "utils.h"
#include "midifile.h"

View File

@ -0,0 +1,281 @@
/************************************************************************
* *
* dmplugin.h -- This module contains the API for plugins for the *
* DirectMusic performance layer *
* *
* Copyright (c) 1998-1999 Microsoft Corporation *
* *
************************************************************************/
#ifndef _DMPLUGIN_
#define _DMPLUGIN_
#include <windows.h>
#define COM_NO_WINDOWS_H
#include <objbase.h>
#include <mmsystem.h>
#include <dmusici.h>
#include <pshpack8.h>
#ifdef __cplusplus
extern "C" {
#endif
interface IDirectMusicTrack;
interface IDirectMusicTool;
interface IDirectMusicTool8;
interface IDirectMusicTrack8;
interface IDirectMusicPerformance;
interface IDirectMusicPerformance8;
interface IDirectMusicSegment;
interface IDirectMusicSegment8;
interface IDirectMusicSegmentState;
interface IDirectMusicSegmentState8;
interface IDirectMusicGraph;
#ifndef __cplusplus
typedef interface IDirectMusicTrack IDirectMusicTrack;
typedef interface IDirectMusicTool IDirectMusicTool;
typedef interface IDirectMusicTool8 IDirectMusicTool8;
typedef interface IDirectMusicTrack8 IDirectMusicTrack8;
typedef interface IDirectMusicPerformance IDirectMusicPerformance;
typedef interface IDirectMusicPerformance8 IDirectMusicPerformance8;
typedef interface IDirectMusicSegment IDirectMusicSegment;
typedef interface IDirectMusicSegment8 IDirectMusicSegment8;
typedef interface IDirectMusicSegmentState IDirectMusicSegmentState;
typedef interface IDirectMusicSegmentState8 IDirectMusicSegmentState8;
typedef interface IDirectMusicGraph IDirectMusicGraph;
#endif
typedef struct _DMUS_PMSG DMUS_PMSG;
typedef long MUSIC_TIME;
/* Registry location for tools */
#define DMUS_REGSTR_PATH_TOOLS "Software\\Microsoft\\DirectMusic\\Tools"
/*////////////////////////////////////////////////////////////////////
// IDirectMusicTool */
#undef INTERFACE
#define INTERFACE IDirectMusicTool
DECLARE_INTERFACE_(IDirectMusicTool, IUnknown)
{
/* IUnknown */
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
/* IDirectMusicTool */
STDMETHOD(Init) (THIS_ IDirectMusicGraph* pGraph) PURE;
STDMETHOD(GetMsgDeliveryType) (THIS_ DWORD* pdwDeliveryType ) PURE;
STDMETHOD(GetMediaTypeArraySize)(THIS_ DWORD* pdwNumElements ) PURE;
STDMETHOD(GetMediaTypes) (THIS_ DWORD** padwMediaTypes,
DWORD dwNumElements) PURE;
STDMETHOD(ProcessPMsg) (THIS_ IDirectMusicPerformance* pPerf,
DMUS_PMSG* pPMSG) PURE;
STDMETHOD(Flush) (THIS_ IDirectMusicPerformance* pPerf,
DMUS_PMSG* pPMSG,
REFERENCE_TIME rtTime) PURE;
};
/*////////////////////////////////////////////////////////////////////
// IDirectMusicTool8 */
#undef INTERFACE
#define INTERFACE IDirectMusicTool8
DECLARE_INTERFACE_(IDirectMusicTool8, IDirectMusicTool)
{
/* IUnknown */
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
/* IDirectMusicTool */
STDMETHOD(Init) (THIS_ IDirectMusicGraph* pGraph) PURE;
STDMETHOD(GetMsgDeliveryType) (THIS_ DWORD* pdwDeliveryType ) PURE;
STDMETHOD(GetMediaTypeArraySize)(THIS_ DWORD* pdwNumElements ) PURE;
STDMETHOD(GetMediaTypes) (THIS_ DWORD** padwMediaTypes,
DWORD dwNumElements) PURE;
STDMETHOD(ProcessPMsg) (THIS_ IDirectMusicPerformance* pPerf,
DMUS_PMSG* pPMSG) PURE;
STDMETHOD(Flush) (THIS_ IDirectMusicPerformance* pPerf,
DMUS_PMSG* pPMSG,
REFERENCE_TIME rtTime) PURE;
/* IDirectMusicTool8 */
STDMETHOD(Clone) (THIS_ IDirectMusicTool ** ppTool) PURE;
};
/* The following flags are sent in the IDirectMusicTrack::Play() method */
/* inside the dwFlags parameter */
typedef enum enumDMUS_TRACKF_FLAGS
{
DMUS_TRACKF_SEEK = 1, /* set on a seek */
DMUS_TRACKF_LOOP = 2, /* set on a loop (repeat) */
DMUS_TRACKF_START = 4, /* set on first call to Play */
DMUS_TRACKF_FLUSH = 8, /* set when this call is in response to a flush on the perfomance */
DMUS_TRACKF_DIRTY = 0x10, /* set when the track should consider any cached values from a previous call to GetParam to be invalidated */
/* The following flags are DX8 only. */
DMUS_TRACKF_NOTIFY_OFF = 0x20, /* tells track not to send notifications. */
DMUS_TRACKF_PLAY_OFF = 0x40, /* tells track not to play anything (but can still send notifications.) */
DMUS_TRACKF_LOOPEND = 0x80, /* set when the end of range is also a loop end. */
DMUS_TRACKF_STOP = 0x100, /* set when the end of range is also end of playing this segment. */
DMUS_TRACKF_RECOMPOSE = 0x200, /* set to indicate the track should compose. */
DMUS_TRACKF_CLOCK = 0x400, /* set when time parameters are in reference (clock) time. Only valid for PlayEx(). */
} DMUS_TRACKF_FLAGS;
/* The following flags are sent in the IDirectMusicTrack8::GetParamEx() and SetParamEx() methods */
/* inside the dwFlags parameter */
#define DMUS_TRACK_PARAMF_CLOCK 0x01 /* set when the time is measured is in reference (clock) time */
/*////////////////////////////////////////////////////////////////////
// IDirectMusicTrack */
#undef INTERFACE
#define INTERFACE IDirectMusicTrack
DECLARE_INTERFACE_(IDirectMusicTrack, IUnknown)
{
/* IUnknown */
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
/* IDirectMusicTrack */
STDMETHOD(Init) (THIS_ IDirectMusicSegment* pSegment) PURE;
STDMETHOD(InitPlay) (THIS_ IDirectMusicSegmentState* pSegmentState,
IDirectMusicPerformance* pPerformance,
void** ppStateData,
DWORD dwVirtualTrackID,
DWORD dwFlags) PURE;
STDMETHOD(EndPlay) (THIS_ void* pStateData) PURE;
STDMETHOD(Play) (THIS_ void* pStateData,
MUSIC_TIME mtStart,
MUSIC_TIME mtEnd,
MUSIC_TIME mtOffset,
DWORD dwFlags,
IDirectMusicPerformance* pPerf,
IDirectMusicSegmentState* pSegSt,
DWORD dwVirtualID) PURE;
STDMETHOD(GetParam) (THIS_ REFGUID rguidType,
MUSIC_TIME mtTime,
MUSIC_TIME* pmtNext,
void* pParam) PURE;
STDMETHOD(SetParam) (THIS_ REFGUID rguidType,
MUSIC_TIME mtTime,
void* pParam) PURE;
STDMETHOD(IsParamSupported) (THIS_ REFGUID rguidType) PURE;
STDMETHOD(AddNotificationType) (THIS_ REFGUID rguidNotificationType) PURE;
STDMETHOD(RemoveNotificationType) (THIS_ REFGUID rguidNotificationType) PURE;
STDMETHOD(Clone) (THIS_ MUSIC_TIME mtStart,
MUSIC_TIME mtEnd,
IDirectMusicTrack** ppTrack) PURE;
};
/*////////////////////////////////////////////////////////////////////
// IDirectMusicTrack8 */
#undef INTERFACE
#define INTERFACE IDirectMusicTrack8
DECLARE_INTERFACE_(IDirectMusicTrack8, IDirectMusicTrack)
{
/* IUnknown */
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
/* IDirectMusicTrack */
STDMETHOD(Init) (THIS_ IDirectMusicSegment* pSegment) PURE;
STDMETHOD(InitPlay) (THIS_ IDirectMusicSegmentState* pSegmentState,
IDirectMusicPerformance* pPerformance,
void** ppStateData,
DWORD dwVirtualTrackID,
DWORD dwFlags) PURE;
STDMETHOD(EndPlay) (THIS_ void* pStateData) PURE;
STDMETHOD(Play) (THIS_ void* pStateData,
MUSIC_TIME mtStart,
MUSIC_TIME mtEnd,
MUSIC_TIME mtOffset,
DWORD dwFlags,
IDirectMusicPerformance* pPerf,
IDirectMusicSegmentState* pSegSt,
DWORD dwVirtualID) PURE;
STDMETHOD(GetParam) (THIS_ REFGUID rguidType,
MUSIC_TIME mtTime,
MUSIC_TIME* pmtNext,
void* pParam) PURE;
STDMETHOD(SetParam) (THIS_ REFGUID rguidType,
MUSIC_TIME mtTime,
void* pParam) PURE;
STDMETHOD(IsParamSupported) (THIS_ REFGUID rguidType) PURE;
STDMETHOD(AddNotificationType) (THIS_ REFGUID rguidNotificationType) PURE;
STDMETHOD(RemoveNotificationType) (THIS_ REFGUID rguidNotificationType) PURE;
STDMETHOD(Clone) (THIS_ MUSIC_TIME mtStart,
MUSIC_TIME mtEnd,
IDirectMusicTrack** ppTrack) PURE;
/* IDirectMusicTrack8 */
STDMETHOD(PlayEx) (THIS_ void* pStateData,
REFERENCE_TIME rtStart,
REFERENCE_TIME rtEnd,
REFERENCE_TIME rtOffset,
DWORD dwFlags,
IDirectMusicPerformance* pPerf,
IDirectMusicSegmentState* pSegSt,
DWORD dwVirtualID) PURE;
STDMETHOD(GetParamEx) (THIS_ REFGUID rguidType, /* Command type. */
REFERENCE_TIME rtTime, /* Time, in ref time if dwFlags == DMUS_TRACK_PARAMF_CLOCK. Otherwise, music time. */
REFERENCE_TIME* prtNext, /* Time of next parameter, relative to rtTime, in music or clock time units. */
void* pParam, /* Pointer to the parameter data. */
void * pStateData, /* State data for track instance. */
DWORD dwFlags) PURE; /* Control flags. */
STDMETHOD(SetParamEx) (THIS_ REFGUID rguidType,
REFERENCE_TIME rtTime,
void* pParam, /* Pointer to the parameter data. */
void * pStateData, /* State data for track instance. */
DWORD dwFlags) PURE; /* Control flags. */
STDMETHOD(Compose) (THIS_ IUnknown* pContext, /* Context for composition (song or segment) */
DWORD dwTrackGroup,
IDirectMusicTrack** ppResultTrack) PURE;
STDMETHOD(Join) (THIS_ IDirectMusicTrack* pNewTrack,
MUSIC_TIME mtJoin,
IUnknown* pContext, /* Context for joining (song or segment) */
DWORD dwTrackGroup,
IDirectMusicTrack** ppResultTrack) PURE;
};
/* CLSID's */
DEFINE_GUID(CLSID_DirectMusicTempoTrack,0xd2ac2885, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(CLSID_DirectMusicSeqTrack,0xd2ac2886, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(CLSID_DirectMusicSysExTrack,0xd2ac2887, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(CLSID_DirectMusicTimeSigTrack,0xd2ac2888, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(CLSID_DirectMusicChordTrack,0xd2ac288b, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(CLSID_DirectMusicCommandTrack,0xd2ac288c, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(CLSID_DirectMusicStyleTrack,0xd2ac288d, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(CLSID_DirectMusicMotifTrack,0xd2ac288e, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(CLSID_DirectMusicSignPostTrack,0xf17e8672, 0xc3b4, 0x11d1, 0x87, 0xb, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(CLSID_DirectMusicBandTrack,0xd2ac2894, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(CLSID_DirectMusicChordMapTrack,0xd2ac2896, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(CLSID_DirectMusicMuteTrack,0xd2ac2898, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
/* New CLSID's for DX8 */
DEFINE_GUID(CLSID_DirectMusicScriptTrack,0x4108fa85, 0x3586, 0x11d3, 0x8b, 0xd7, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xb6); /* {4108FA85-3586-11d3-8BD7-00600893B1B6} */
DEFINE_GUID(CLSID_DirectMusicMarkerTrack,0x55a8fd00, 0x4288, 0x11d3, 0x9b, 0xd1, 0x8a, 0xd, 0x61, 0xc8, 0x88, 0x35);
DEFINE_GUID(CLSID_DirectMusicSegmentTriggerTrack, 0xbae4d665, 0x4ea1, 0x11d3, 0x8b, 0xda, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xb6); /* {BAE4D665-4EA1-11d3-8BDA-00600893B1B6} */
DEFINE_GUID(CLSID_DirectMusicLyricsTrack, 0x995c1cf5, 0x54ff, 0x11d3, 0x8b, 0xda, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xb6); /* {995C1CF5-54FF-11d3-8BDA-00600893B1B6} */
DEFINE_GUID(CLSID_DirectMusicParamControlTrack, 0x4be0537b, 0x5c19, 0x11d3, 0x8b, 0xdc, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xb6); /* {4BE0537B-5C19-11d3-8BDC-00600893B1B6} */
DEFINE_GUID(CLSID_DirectMusicMelodyFormulationTrack, 0xb0684266, 0xb57f, 0x11d2, 0x97, 0xf9, 0x0, 0xc0, 0x4f, 0xa3, 0x6e, 0x58);
DEFINE_GUID(CLSID_DirectMusicWaveTrack,0xeed36461, 0x9ea5, 0x11d3, 0x9b, 0xd1, 0x0, 0x80, 0xc7, 0x15, 0xa, 0x74);
/* IID's */
DEFINE_GUID(IID_IDirectMusicTrack, 0xf96029a1, 0x4282, 0x11d2, 0x87, 0x17, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(IID_IDirectMusicTool,0xd2ac28ba, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
/* Interface IDs for DX8 */
/* changed interfaces (GUID only) */
DEFINE_GUID(IID_IDirectMusicTool8, 0xe674303, 0x3b05, 0x11d3, 0x9b, 0xd1, 0xf9, 0xe7, 0xf0, 0xa0, 0x15, 0x36);
DEFINE_GUID(IID_IDirectMusicTrack8, 0xe674304, 0x3b05, 0x11d3, 0x9b, 0xd1, 0xf9, 0xe7, 0xf0, 0xa0, 0x15, 0x36);
#ifdef __cplusplus
}; /* extern "C" */
#endif
#include <poppack.h>
#endif /* #ifndef _DMPLUGIN_ */

View File

@ -0,0 +1,784 @@
/************************************************************************
* *
* dmusicc.h -- This module defines the DirectMusic core API's *
* *
* Copyright (c) 1998-1999 Microsoft Corporation
* *
************************************************************************/
#ifndef _DMUSICC_
#define _DMUSICC_
#include <windows.h>
#define COM_NO_WINDOWS_H
#include <objbase.h>
#include <mmsystem.h>
#include "dls1.h"
#include "dmerror.h"
#include "dmdls.h"
#include "dsound.h"
#include "dmusbuff.h"
#include <pshpack8.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef ULONGLONG SAMPLE_TIME;
typedef ULONGLONG SAMPLE_POSITION;
typedef SAMPLE_TIME *LPSAMPLE_TIME;
#define DMUS_MAX_DESCRIPTION 128
#define DMUS_MAX_DRIVER 128
typedef struct _DMUS_BUFFERDESC *LPDMUS_BUFFERDESC;
typedef struct _DMUS_BUFFERDESC
{
DWORD dwSize;
DWORD dwFlags;
GUID guidBufferFormat;
DWORD cbBuffer;
} DMUS_BUFFERDESC;
/* DMUS_EFFECT_ flags are used in the dwEffectFlags fields of both DMUS_PORTCAPS
* and DMUS_PORTPARAMS.
*/
#define DMUS_EFFECT_NONE 0x00000000
#define DMUS_EFFECT_REVERB 0x00000001
#define DMUS_EFFECT_CHORUS 0x00000002
#define DMUS_EFFECT_DELAY 0x00000004
/* For DMUS_PORTCAPS dwClass
*/
#define DMUS_PC_INPUTCLASS (0)
#define DMUS_PC_OUTPUTCLASS (1)
/* For DMUS_PORTCAPS dwFlags
*/
#define DMUS_PC_DLS (0x00000001) // Supports DLS downloading and DLS level 1.
#define DMUS_PC_EXTERNAL (0x00000002) // External MIDI module.
#define DMUS_PC_SOFTWARESYNTH (0x00000004) // Software synthesizer.
#define DMUS_PC_MEMORYSIZEFIXED (0x00000008) // Memory size is fixed.
#define DMUS_PC_GMINHARDWARE (0x00000010) // GM sound set is built in, no need to download.
#define DMUS_PC_GSINHARDWARE (0x00000020) // GS sound set is built in.
#define DMUS_PC_XGINHARDWARE (0x00000040) // XG sound set is built in.
#define DMUS_PC_DIRECTSOUND (0x00000080) // Connects to DirectSound via a DSound buffer.
#define DMUS_PC_SHAREABLE (0x00000100) // Synth can be actively shared by multiple apps at once.
#define DMUS_PC_DLS2 (0x00000200) // Supports DLS2 instruments.
#define DMUS_PC_AUDIOPATH (0x00000400) // Multiple outputs can be connected to DirectSound for audiopaths.
#define DMUS_PC_WAVE (0x00000800) // Supports streaming and one shot waves.
#define DMUS_PC_SYSTEMMEMORY (0x7FFFFFFF) // Sample memory is system memory.
typedef struct _DMUS_PORTCAPS
{
DWORD dwSize;
DWORD dwFlags;
GUID guidPort;
DWORD dwClass;
DWORD dwType;
DWORD dwMemorySize;
DWORD dwMaxChannelGroups;
DWORD dwMaxVoices;
DWORD dwMaxAudioChannels;
DWORD dwEffectFlags;
WCHAR wszDescription[DMUS_MAX_DESCRIPTION];
} DMUS_PORTCAPS;
typedef DMUS_PORTCAPS *LPDMUS_PORTCAPS;
/* Values for DMUS_PORTCAPS dwType. This field indicates the underlying
* driver type of the port.
*/
#define DMUS_PORT_WINMM_DRIVER (0)
#define DMUS_PORT_USER_MODE_SYNTH (1)
#define DMUS_PORT_KERNEL_MODE (2)
/* These flags (set in dwValidParams) indicate which other members of the */
/* DMUS_PORTPARAMS are valid. */
/* */
#define DMUS_PORTPARAMS_VOICES 0x00000001
#define DMUS_PORTPARAMS_CHANNELGROUPS 0x00000002
#define DMUS_PORTPARAMS_AUDIOCHANNELS 0x00000004
#define DMUS_PORTPARAMS_SAMPLERATE 0x00000008
#define DMUS_PORTPARAMS_EFFECTS 0x00000020
#define DMUS_PORTPARAMS_SHARE 0x00000040
#define DMUS_PORTPARAMS_FEATURES 0x00000080 /* DirectX 8.0 and above */
typedef struct _DMUS_PORTPARAMS
{
DWORD dwSize;
DWORD dwValidParams;
DWORD dwVoices;
DWORD dwChannelGroups;
DWORD dwAudioChannels;
DWORD dwSampleRate;
DWORD dwEffectFlags;
BOOL fShare;
} DMUS_PORTPARAMS7;
typedef struct _DMUS_PORTPARAMS8
{
DWORD dwSize;
DWORD dwValidParams;
DWORD dwVoices;
DWORD dwChannelGroups;
DWORD dwAudioChannels;
DWORD dwSampleRate;
DWORD dwEffectFlags;
BOOL fShare;
DWORD dwFeatures;
} DMUS_PORTPARAMS8;
#define DMUS_PORT_FEATURE_AUDIOPATH 0x00000001 /* Supports audiopath connection to DSound buffers. */
#define DMUS_PORT_FEATURE_STREAMING 0x00000002 /* Supports streaming waves through the synth. */
typedef DMUS_PORTPARAMS8 DMUS_PORTPARAMS;
typedef DMUS_PORTPARAMS *LPDMUS_PORTPARAMS;
typedef struct _DMUS_SYNTHSTATS *LPDMUS_SYNTHSTATS;
typedef struct _DMUS_SYNTHSTATS8 *LPDMUS_SYNTHSTATS8;
typedef struct _DMUS_SYNTHSTATS
{
DWORD dwSize; /* Size in bytes of the structure */
DWORD dwValidStats; /* Flags indicating which fields below are valid. */
DWORD dwVoices; /* Average number of voices playing. */
DWORD dwTotalCPU; /* Total CPU usage as percent * 100. */
DWORD dwCPUPerVoice; /* CPU per voice as percent * 100. */
DWORD dwLostNotes; /* Number of notes lost in 1 second. */
DWORD dwFreeMemory; /* Free memory in bytes */
long lPeakVolume; /* Decibel level * 100. */
} DMUS_SYNTHSTATS;
typedef struct _DMUS_SYNTHSTATS8
{
DWORD dwSize; /* Size in bytes of the structure */
DWORD dwValidStats; /* Flags indicating which fields below are valid. */
DWORD dwVoices; /* Average number of voices playing. */
DWORD dwTotalCPU; /* Total CPU usage as percent * 100. */
DWORD dwCPUPerVoice; /* CPU per voice as percent * 100. */
DWORD dwLostNotes; /* Number of notes lost in 1 second. */
DWORD dwFreeMemory; /* Free memory in bytes */
long lPeakVolume; /* Decibel level * 100. */
DWORD dwSynthMemUse; /* Memory used by synth wave data */
} DMUS_SYNTHSTATS8;
#define DMUS_SYNTHSTATS_VOICES (1 << 0)
#define DMUS_SYNTHSTATS_TOTAL_CPU (1 << 1)
#define DMUS_SYNTHSTATS_CPU_PER_VOICE (1 << 2)
#define DMUS_SYNTHSTATS_LOST_NOTES (1 << 3)
#define DMUS_SYNTHSTATS_PEAK_VOLUME (1 << 4)
#define DMUS_SYNTHSTATS_FREE_MEMORY (1 << 5)
#define DMUS_SYNTHSTATS_SYSTEMMEMORY DMUS_PC_SYSTEMMEMORY
typedef struct _DMUS_WAVES_REVERB_PARAMS
{
float fInGain; /* Input gain in dB (to avoid output overflows) */
float fReverbMix; /* Reverb mix in dB. 0dB means 100% wet reverb (no direct signal)
Negative values gives less wet signal.
The coeficients are calculated so that the overall output level stays
(approximately) constant regardless of the ammount of reverb mix. */
float fReverbTime; /* The reverb decay time, in milliseconds. */
float fHighFreqRTRatio; /* The ratio of the high frequencies to the global reverb time.
Unless very 'splashy-bright' reverbs are wanted, this should be set to
a value < 1.0.
For example if dRevTime==1000ms and dHighFreqRTRatio=0.1 than the
decay time for high frequencies will be 100ms.*/
} DMUS_WAVES_REVERB_PARAMS;
/* Note: Default values for Reverb are:
fInGain = 0.0dB (no change in level)
fReverbMix = -10.0dB (a reasonable reverb mix)
fReverbTime = 1000.0ms (one second global reverb time)
fHighFreqRTRatio = 0.001 (the ratio of the high frequencies to the global reverb time)
*/
typedef enum
{
DMUS_CLOCK_SYSTEM = 0,
DMUS_CLOCK_WAVE = 1
} DMUS_CLOCKTYPE;
#define DMUS_CLOCKF_GLOBAL 0x00000001
typedef struct _DMUS_CLOCKINFO7 *LPDMUS_CLOCKINFO7;
typedef struct _DMUS_CLOCKINFO7
{
DWORD dwSize;
DMUS_CLOCKTYPE ctType;
GUID guidClock; /* Identifies this time source */
WCHAR wszDescription[DMUS_MAX_DESCRIPTION];
} DMUS_CLOCKINFO7;
typedef struct _DMUS_CLOCKINFO8 *LPDMUS_CLOCKINFO8;
typedef struct _DMUS_CLOCKINFO8
{
DWORD dwSize;
DMUS_CLOCKTYPE ctType;
GUID guidClock; /* Identifies this time source */
WCHAR wszDescription[DMUS_MAX_DESCRIPTION];
DWORD dwFlags;
} DMUS_CLOCKINFO8;
typedef DMUS_CLOCKINFO8 DMUS_CLOCKINFO;
typedef DMUS_CLOCKINFO *LPDMUS_CLOCKINFO;
/* Default bus identifiers
*
* The first 17 are direct mappings to the destinations defined in both
* the MMA DLS Level 2 specification and the Microsoft Multi-Channel audio
* specification.
*/
#define DSBUSID_FIRST_SPKR_LOC 0
#define DSBUSID_FRONT_LEFT 0
#define DSBUSID_LEFT 0 /* Front left is also just left */
#define DSBUSID_FRONT_RIGHT 1
#define DSBUSID_RIGHT 1 /* Ditto front right */
#define DSBUSID_FRONT_CENTER 2
#define DSBUSID_LOW_FREQUENCY 3
#define DSBUSID_BACK_LEFT 4
#define DSBUSID_BACK_RIGHT 5
#define DSBUSID_FRONT_LEFT_OF_CENTER 6
#define DSBUSID_FRONT_RIGHT_OF_CENTER 7
#define DSBUSID_BACK_CENTER 8
#define DSBUSID_SIDE_LEFT 9
#define DSBUSID_SIDE_RIGHT 10
#define DSBUSID_TOP_CENTER 11
#define DSBUSID_TOP_FRONT_LEFT 12
#define DSBUSID_TOP_FRONT_CENTER 13
#define DSBUSID_TOP_FRONT_RIGHT 14
#define DSBUSID_TOP_BACK_LEFT 15
#define DSBUSID_TOP_BACK_CENTER 16
#define DSBUSID_TOP_BACK_RIGHT 17
#define DSBUSID_LAST_SPKR_LOC 17
#define DSBUSID_IS_SPKR_LOC(id) ( ((id) >= DSBUSID_FIRST_SPKR_LOC) && ((id) <= DSBUSID_LAST_SPKR_LOC) )
/* These bus identifiers are for the standard DLS effect sends
*/
#define DSBUSID_REVERB_SEND 64
#define DSBUSID_CHORUS_SEND 65
/* Dynamic bus identifiers start here. See the documentation for how
* synthesizers map the output of voices to static and dynamic
* bus identifiers.
*/
#define DSBUSID_DYNAMIC_0 512
/* Null bus, used to identify busses that have no function mapping.
*/
#define DSBUSID_NULL 0xFFFFFFFF
interface IDirectMusic;
interface IDirectMusic8;
interface IDirectMusicBuffer;
interface IDirectMusicPort;
interface IDirectMusicThru;
interface IReferenceClock;
#ifndef __cplusplus
typedef interface IDirectMusic IDirectMusic;
typedef interface IDirectMusic8 IDirectMusic8;
typedef interface IDirectMusicPort IDirectMusicPort;
typedef interface IDirectMusicBuffer IDirectMusicBuffer;
typedef interface IDirectMusicThru IDirectMusicThru;
typedef interface IReferenceClock IReferenceClock;
#endif /* C++ */
typedef IDirectMusic *LPDIRECTMUSIC;
typedef IDirectMusic8 *LPDIRECTMUSIC8;
typedef IDirectMusicPort *LPDIRECTMUSICPORT;
typedef IDirectMusicBuffer *LPDIRECTMUSICBUFFER;
#undef INTERFACE
#define INTERFACE IDirectMusic
DECLARE_INTERFACE_(IDirectMusic, IUnknown)
{
/* IUnknown */
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
/* IDirectMusic */
STDMETHOD(EnumPort) (THIS_ DWORD dwIndex,
LPDMUS_PORTCAPS pPortCaps) PURE;
STDMETHOD(CreateMusicBuffer) (THIS_ LPDMUS_BUFFERDESC pBufferDesc,
LPDIRECTMUSICBUFFER *ppBuffer,
LPUNKNOWN pUnkOuter) PURE;
STDMETHOD(CreatePort) (THIS_ REFCLSID rclsidPort,
LPDMUS_PORTPARAMS pPortParams,
LPDIRECTMUSICPORT *ppPort,
LPUNKNOWN pUnkOuter) PURE;
STDMETHOD(EnumMasterClock) (THIS_ DWORD dwIndex,
LPDMUS_CLOCKINFO lpClockInfo) PURE;
STDMETHOD(GetMasterClock) (THIS_ LPGUID pguidClock,
IReferenceClock **ppReferenceClock) PURE;
STDMETHOD(SetMasterClock) (THIS_ REFGUID rguidClock) PURE;
STDMETHOD(Activate) (THIS_ BOOL fEnable) PURE;
STDMETHOD(GetDefaultPort) (THIS_ LPGUID pguidPort) PURE;
STDMETHOD(SetDirectSound) (THIS_ LPDIRECTSOUND pDirectSound,
HWND hWnd) PURE;
};
#undef INTERFACE
#define INTERFACE IDirectMusic8
DECLARE_INTERFACE_(IDirectMusic8, IDirectMusic)
{
/* IUnknown */
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
/* IDirectMusic */
STDMETHOD(EnumPort) (THIS_ DWORD dwIndex,
LPDMUS_PORTCAPS pPortCaps) PURE;
STDMETHOD(CreateMusicBuffer) (THIS_ LPDMUS_BUFFERDESC pBufferDesc,
LPDIRECTMUSICBUFFER *ppBuffer,
LPUNKNOWN pUnkOuter) PURE;
STDMETHOD(CreatePort) (THIS_ REFCLSID rclsidPort,
LPDMUS_PORTPARAMS pPortParams,
LPDIRECTMUSICPORT *ppPort,
LPUNKNOWN pUnkOuter) PURE;
STDMETHOD(EnumMasterClock) (THIS_ DWORD dwIndex,
LPDMUS_CLOCKINFO lpClockInfo) PURE;
STDMETHOD(GetMasterClock) (THIS_ LPGUID pguidClock,
IReferenceClock **ppReferenceClock) PURE;
STDMETHOD(SetMasterClock) (THIS_ REFGUID rguidClock) PURE;
STDMETHOD(Activate) (THIS_ BOOL fEnable) PURE;
STDMETHOD(GetDefaultPort) (THIS_ LPGUID pguidPort) PURE;
STDMETHOD(SetDirectSound) (THIS_ LPDIRECTSOUND pDirectSound,
HWND hWnd) PURE;
/* IDirectMusic8 */
STDMETHOD(SetExternalMasterClock)
(THIS_ IReferenceClock *pClock) PURE;
};
#undef INTERFACE
#define INTERFACE IDirectMusicBuffer
DECLARE_INTERFACE_(IDirectMusicBuffer, IUnknown)
{
/* IUnknown */
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
/* IDirectMusicBuffer */
STDMETHOD(Flush) (THIS) PURE;
STDMETHOD(TotalTime) (THIS_ LPREFERENCE_TIME prtTime) PURE;
STDMETHOD(PackStructured) (THIS_ REFERENCE_TIME rt,
DWORD dwChannelGroup,
DWORD dwChannelMessage) PURE;
STDMETHOD(PackUnstructured) (THIS_ REFERENCE_TIME rt,
DWORD dwChannelGroup,
DWORD cb,
LPBYTE lpb) PURE;
STDMETHOD(ResetReadPtr) (THIS) PURE;
STDMETHOD(GetNextEvent) (THIS_ LPREFERENCE_TIME prt,
LPDWORD pdwChannelGroup,
LPDWORD pdwLength,
LPBYTE *ppData) PURE;
STDMETHOD(GetRawBufferPtr) (THIS_ LPBYTE *ppData) PURE;
STDMETHOD(GetStartTime) (THIS_ LPREFERENCE_TIME prt) PURE;
STDMETHOD(GetUsedBytes) (THIS_ LPDWORD pcb) PURE;
STDMETHOD(GetMaxBytes) (THIS_ LPDWORD pcb) PURE;
STDMETHOD(GetBufferFormat) (THIS_ LPGUID pGuidFormat) PURE;
STDMETHOD(SetStartTime) (THIS_ REFERENCE_TIME rt) PURE;
STDMETHOD(SetUsedBytes) (THIS_ DWORD cb) PURE;
};
typedef IDirectMusicBuffer IDirectMusicBuffer8;
typedef IDirectMusicBuffer8 *LPDIRECTMUSICBUFFER8;
#undef INTERFACE
#define INTERFACE IDirectMusicInstrument
DECLARE_INTERFACE_(IDirectMusicInstrument, IUnknown)
{
/* IUnknown */
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
/* IDirectMusicInstrument */
STDMETHOD(GetPatch) (THIS_ DWORD* pdwPatch) PURE;
STDMETHOD(SetPatch) (THIS_ DWORD dwPatch) PURE;
};
typedef IDirectMusicInstrument IDirectMusicInstrument8;
typedef IDirectMusicInstrument8 *LPDIRECTMUSICINSTRUMENT8;
#undef INTERFACE
#define INTERFACE IDirectMusicDownloadedInstrument
DECLARE_INTERFACE_(IDirectMusicDownloadedInstrument, IUnknown)
{
/* IUnknown */
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
/* IDirectMusicDownloadedInstrument */
/* None at this time */
};
typedef IDirectMusicDownloadedInstrument IDirectMusicDownloadedInstrument8;
typedef IDirectMusicDownloadedInstrument8 *LPDIRECTMUSICDOWNLOADEDINSTRUMENT8;
#undef INTERFACE
#define INTERFACE IDirectMusicCollection
DECLARE_INTERFACE_(IDirectMusicCollection, IUnknown)
{
/* IUnknown */
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
/* IDirectMusicCollection */
STDMETHOD(GetInstrument) (THIS_ DWORD dwPatch,
IDirectMusicInstrument** ppInstrument) PURE;
STDMETHOD(EnumInstrument) (THIS_ DWORD dwIndex,
DWORD* pdwPatch,
LPWSTR pwszName,
DWORD dwNameLen) PURE;
};
typedef IDirectMusicCollection IDirectMusicCollection8;
typedef IDirectMusicCollection8 *LPDIRECTMUSICCOLLECTION8;
#undef INTERFACE
#define INTERFACE IDirectMusicDownload
DECLARE_INTERFACE_(IDirectMusicDownload , IUnknown)
{
/* IUnknown */
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
/* IDirectMusicDownload */
STDMETHOD(GetBuffer) (THIS_ void** ppvBuffer,
DWORD* pdwSize) PURE;
};
typedef IDirectMusicDownload IDirectMusicDownload8;
typedef IDirectMusicDownload8 *LPDIRECTMUSICDOWNLOAD8;
#undef INTERFACE
#define INTERFACE IDirectMusicPortDownload
DECLARE_INTERFACE_(IDirectMusicPortDownload, IUnknown)
{
/* IUnknown */
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
/* IDirectMusicPortDownload */
STDMETHOD(GetBuffer) (THIS_ DWORD dwDLId,
IDirectMusicDownload** ppIDMDownload) PURE;
STDMETHOD(AllocateBuffer) (THIS_ DWORD dwSize,
IDirectMusicDownload** ppIDMDownload) PURE;
STDMETHOD(GetDLId) (THIS_ DWORD* pdwStartDLId,
DWORD dwCount) PURE;
STDMETHOD(GetAppend) (THIS_ DWORD* pdwAppend) PURE;
STDMETHOD(Download) (THIS_ IDirectMusicDownload* pIDMDownload) PURE;
STDMETHOD(Unload) (THIS_ IDirectMusicDownload* pIDMDownload) PURE;
};
typedef IDirectMusicPortDownload IDirectMusicPortDownload8;
typedef IDirectMusicPortDownload8 *LPDIRECTMUSICPORTDOWNLOAD8;
/* Standard values for voice priorities. Numerically higher priorities are higher in priority.
* These priorities are used to set the voice priority for all voices on a channel. They are
* used in the dwPriority parameter of IDirectMusicPort::GetPriority and returned in the
* lpwPriority parameter of pdwPriority.
*
* These priorities are shared with DirectSound.
*/
#ifndef _DIRECTAUDIO_PRIORITIES_DEFINED_
#define _DIRECTAUDIO_PRIORITIES_DEFINED_
#define DAUD_CRITICAL_VOICE_PRIORITY (0xF0000000)
#define DAUD_HIGH_VOICE_PRIORITY (0xC0000000)
#define DAUD_STANDARD_VOICE_PRIORITY (0x80000000)
#define DAUD_LOW_VOICE_PRIORITY (0x40000000)
#define DAUD_PERSIST_VOICE_PRIORITY (0x10000000)
/* These are the default priorities assigned if not overridden. By default priorities are
* equal across channel groups (e.g. channel 5 on channel group 1 has the same priority as
* channel 5 on channel group 2).
*
* In accordance with DLS level 1, channel 10 has the highest priority, followed by 1 through 16
* except for 10.
*/
#define DAUD_CHAN1_VOICE_PRIORITY_OFFSET (0x0000000E)
#define DAUD_CHAN2_VOICE_PRIORITY_OFFSET (0x0000000D)
#define DAUD_CHAN3_VOICE_PRIORITY_OFFSET (0x0000000C)
#define DAUD_CHAN4_VOICE_PRIORITY_OFFSET (0x0000000B)
#define DAUD_CHAN5_VOICE_PRIORITY_OFFSET (0x0000000A)
#define DAUD_CHAN6_VOICE_PRIORITY_OFFSET (0x00000009)
#define DAUD_CHAN7_VOICE_PRIORITY_OFFSET (0x00000008)
#define DAUD_CHAN8_VOICE_PRIORITY_OFFSET (0x00000007)
#define DAUD_CHAN9_VOICE_PRIORITY_OFFSET (0x00000006)
#define DAUD_CHAN10_VOICE_PRIORITY_OFFSET (0x0000000F)
#define DAUD_CHAN11_VOICE_PRIORITY_OFFSET (0x00000005)
#define DAUD_CHAN12_VOICE_PRIORITY_OFFSET (0x00000004)
#define DAUD_CHAN13_VOICE_PRIORITY_OFFSET (0x00000003)
#define DAUD_CHAN14_VOICE_PRIORITY_OFFSET (0x00000002)
#define DAUD_CHAN15_VOICE_PRIORITY_OFFSET (0x00000001)
#define DAUD_CHAN16_VOICE_PRIORITY_OFFSET (0x00000000)
#define DAUD_CHAN1_DEF_VOICE_PRIORITY (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN1_VOICE_PRIORITY_OFFSET)
#define DAUD_CHAN2_DEF_VOICE_PRIORITY (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN2_VOICE_PRIORITY_OFFSET)
#define DAUD_CHAN3_DEF_VOICE_PRIORITY (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN3_VOICE_PRIORITY_OFFSET)
#define DAUD_CHAN4_DEF_VOICE_PRIORITY (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN4_VOICE_PRIORITY_OFFSET)
#define DAUD_CHAN5_DEF_VOICE_PRIORITY (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN5_VOICE_PRIORITY_OFFSET)
#define DAUD_CHAN6_DEF_VOICE_PRIORITY (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN6_VOICE_PRIORITY_OFFSET)
#define DAUD_CHAN7_DEF_VOICE_PRIORITY (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN7_VOICE_PRIORITY_OFFSET)
#define DAUD_CHAN8_DEF_VOICE_PRIORITY (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN8_VOICE_PRIORITY_OFFSET)
#define DAUD_CHAN9_DEF_VOICE_PRIORITY (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN9_VOICE_PRIORITY_OFFSET)
#define DAUD_CHAN10_DEF_VOICE_PRIORITY (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN10_VOICE_PRIORITY_OFFSET)
#define DAUD_CHAN11_DEF_VOICE_PRIORITY (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN11_VOICE_PRIORITY_OFFSET)
#define DAUD_CHAN12_DEF_VOICE_PRIORITY (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN12_VOICE_PRIORITY_OFFSET)
#define DAUD_CHAN13_DEF_VOICE_PRIORITY (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN13_VOICE_PRIORITY_OFFSET)
#define DAUD_CHAN14_DEF_VOICE_PRIORITY (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN14_VOICE_PRIORITY_OFFSET)
#define DAUD_CHAN15_DEF_VOICE_PRIORITY (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN15_VOICE_PRIORITY_OFFSET)
#define DAUD_CHAN16_DEF_VOICE_PRIORITY (DAUD_STANDARD_VOICE_PRIORITY | DAUD_CHAN16_VOICE_PRIORITY_OFFSET)
#endif /* _DIRECTAUDIO_PRIORITIES_DEFINED_ */
#undef INTERFACE
#define INTERFACE IDirectMusicPort
DECLARE_INTERFACE_(IDirectMusicPort, IUnknown)
{
/* IUnknown */
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
/* IDirectMusicPort */
/* */
STDMETHOD(PlayBuffer) (THIS_ LPDIRECTMUSICBUFFER pBuffer) PURE;
STDMETHOD(SetReadNotificationHandle) (THIS_ HANDLE hEvent) PURE;
STDMETHOD(Read) (THIS_ LPDIRECTMUSICBUFFER pBuffer) PURE;
STDMETHOD(DownloadInstrument) (THIS_ IDirectMusicInstrument *pInstrument,
IDirectMusicDownloadedInstrument **ppDownloadedInstrument,
DMUS_NOTERANGE *pNoteRanges,
DWORD dwNumNoteRanges) PURE;
STDMETHOD(UnloadInstrument) (THIS_ IDirectMusicDownloadedInstrument *pDownloadedInstrument) PURE;
STDMETHOD(GetLatencyClock) (THIS_ IReferenceClock **ppClock) PURE;
STDMETHOD(GetRunningStats) (THIS_ LPDMUS_SYNTHSTATS pStats) PURE;
STDMETHOD(Compact) (THIS) PURE;
STDMETHOD(GetCaps) (THIS_ LPDMUS_PORTCAPS pPortCaps) PURE;
STDMETHOD(DeviceIoControl) (THIS_ DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped) PURE;
STDMETHOD(SetNumChannelGroups) (THIS_ DWORD dwChannelGroups) PURE;
STDMETHOD(GetNumChannelGroups) (THIS_ LPDWORD pdwChannelGroups) PURE;
STDMETHOD(Activate) (THIS_ BOOL fActive) PURE;
STDMETHOD(SetChannelPriority) (THIS_ DWORD dwChannelGroup, DWORD dwChannel, DWORD dwPriority) PURE;
STDMETHOD(GetChannelPriority) (THIS_ DWORD dwChannelGroup, DWORD dwChannel, LPDWORD pdwPriority) PURE;
STDMETHOD(SetDirectSound) (THIS_ LPDIRECTSOUND pDirectSound, LPDIRECTSOUNDBUFFER pDirectSoundBuffer) PURE;
STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pWaveFormatEx, LPDWORD pdwWaveFormatExSize, LPDWORD pdwBufferSize) PURE;
};
typedef IDirectMusicPort IDirectMusicPort8;
typedef IDirectMusicPort8 *LPDIRECTMUSICPORT8;
#undef INTERFACE
#define INTERFACE IDirectMusicThru
DECLARE_INTERFACE_(IDirectMusicThru, IUnknown)
{
/* IUnknown */
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
/* IDirectMusicThru
*/
STDMETHOD(ThruChannel) (THIS_ DWORD dwSourceChannelGroup,
DWORD dwSourceChannel,
DWORD dwDestinationChannelGroup,
DWORD dwDestinationChannel,
LPDIRECTMUSICPORT pDestinationPort) PURE;
};
typedef IDirectMusicThru IDirectMusicThru8;
typedef IDirectMusicThru8 *LPDIRECTMUSICTHRU8;
#ifndef __IReferenceClock_INTERFACE_DEFINED__
#define __IReferenceClock_INTERFACE_DEFINED__
DEFINE_GUID(IID_IReferenceClock,0x56a86897,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70);
#undef INTERFACE
#define INTERFACE IReferenceClock
DECLARE_INTERFACE_(IReferenceClock, IUnknown)
{
/* IUnknown */
STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
/* IReferenceClock */
/* */
/* get the time now */
STDMETHOD(GetTime) (THIS_ REFERENCE_TIME *pTime) PURE;
/* ask for an async notification that a time has elapsed */
STDMETHOD(AdviseTime) (THIS_ REFERENCE_TIME baseTime, /* base time */
REFERENCE_TIME streamTime, /* stream offset time */
HANDLE hEvent, /* advise via this event */
DWORD * pdwAdviseCookie) PURE; /* where your cookie goes */
/* ask for an async periodic notification that a time has elapsed */
STDMETHOD(AdvisePeriodic) (THIS_ REFERENCE_TIME startTime, /* starting at this time */
REFERENCE_TIME periodTime, /* time between notifications */
HANDLE hSemaphore, /* advise via a semaphore */
DWORD * pdwAdviseCookie) PURE; /* where your cookie goes */
/* cancel a request for notification */
STDMETHOD(Unadvise) (THIS_ DWORD dwAdviseCookie) PURE;
};
#endif /* __IReferenceClock_INTERFACE_DEFINED__ */
DEFINE_GUID(CLSID_DirectMusic,0x636b9f10,0x0c7d,0x11d1,0x95,0xb2,0x00,0x20,0xaf,0xdc,0x74,0x21);
DEFINE_GUID(CLSID_DirectMusicCollection,0x480ff4b0, 0x28b2, 0x11d1, 0xbe, 0xf7, 0x0, 0xc0, 0x4f, 0xbf, 0x8f, 0xef);
DEFINE_GUID(CLSID_DirectMusicSynth,0x58C2B4D0,0x46E7,0x11D1,0x89,0xAC,0x00,0xA0,0xC9,0x05,0x41,0x29);
DEFINE_GUID(IID_IDirectMusic,0x6536115a,0x7b2d,0x11d2,0xba,0x18,0x00,0x00,0xf8,0x75,0xac,0x12);
DEFINE_GUID(IID_IDirectMusicBuffer,0xd2ac2878, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(IID_IDirectMusicPort, 0x08f2d8c9,0x37c2,0x11d2,0xb9,0xf9,0x00,0x00,0xf8,0x75,0xac,0x12);
DEFINE_GUID(IID_IDirectMusicThru, 0xced153e7, 0x3606, 0x11d2, 0xb9, 0xf9, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
DEFINE_GUID(IID_IDirectMusicPortDownload,0xd2ac287a, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(IID_IDirectMusicDownload,0xd2ac287b, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(IID_IDirectMusicCollection,0xd2ac287c, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(IID_IDirectMusicInstrument,0xd2ac287d, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(IID_IDirectMusicDownloadedInstrument,0xd2ac287e, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
/* Alternate interface ID for IID_IDirectMusic, available in DX7 release and after. */
DEFINE_GUID(IID_IDirectMusic2,0x6fc2cae1, 0xbc78, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6);
DEFINE_GUID(IID_IDirectMusic8,0x2d3629f7,0x813d,0x4939,0x85,0x08,0xf0,0x5c,0x6b,0x75,0xfd,0x97);
#define IID_IDirectMusicThru8 IID_IDirectMusicThru
#define IID_IDirectMusicPortDownload8 IID_IDirectMusicPortDownload
#define IID_IDirectMusicDownload8 IID_IDirectMusicDownload
#define IID_IDirectMusicCollection8 IID_IDirectMusicCollection
#define IID_IDirectMusicInstrument8 IID_IDirectMusicInstrument
#define IID_IDirectMusicDownloadedInstrument8 IID_IDirectMusicDownloadedInstrument
#define IID_IDirectMusicPort8 IID_IDirectMusicPort
/* Property Query GUID_DMUS_PROP_GM_Hardware - Local GM set, no need to download
* Property Query GUID_DMUS_PROP_GS_Hardware - Local GS set, no need to download
* Property Query GUID_DMUS_PROP_XG_Hardware - Local XG set, no need to download
* Property Query GUID_DMUS_PROP_DLS1 - Support DLS level 1
* Property Query GUID_DMUS_PROP_INSTRUMENT2 - Support new INSTRUMENT2 download format
* Property Query GUID_DMUS_PROP_XG_Capable - Support minimum requirements of XG
* Property Query GUID_DMUS_PROP_GS_Capable - Support minimum requirements of GS
* Property Query GUID_DMUS_PROP_SynthSink_DSOUND - Synthsink talks to DSound
* Property Query GUID_DMUS_PROP_SynthSink_WAVE - Synthsink talks to Wave device
*
* Item 0: Supported
* Returns a DWORD which is non-zero if the feature is supported
*/
DEFINE_GUID(GUID_DMUS_PROP_GM_Hardware, 0x178f2f24, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
DEFINE_GUID(GUID_DMUS_PROP_GS_Hardware, 0x178f2f25, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
DEFINE_GUID(GUID_DMUS_PROP_XG_Hardware, 0x178f2f26, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
DEFINE_GUID(GUID_DMUS_PROP_XG_Capable, 0x6496aba1, 0x61b0, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6);
DEFINE_GUID(GUID_DMUS_PROP_GS_Capable, 0x6496aba2, 0x61b0, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6);
DEFINE_GUID(GUID_DMUS_PROP_DLS1, 0x178f2f27, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
DEFINE_GUID(GUID_DMUS_PROP_DLS2, 0xf14599e5, 0x4689, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6);
DEFINE_GUID(GUID_DMUS_PROP_INSTRUMENT2, 0x865fd372, 0x9f67, 0x11d2, 0x87, 0x2a, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(GUID_DMUS_PROP_SynthSink_DSOUND,0xaa97844, 0xc877, 0x11d1, 0x87, 0xc, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(GUID_DMUS_PROP_SynthSink_WAVE,0xaa97845, 0xc877, 0x11d1, 0x87, 0xc, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
DEFINE_GUID(GUID_DMUS_PROP_SampleMemorySize, 0x178f2f28, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
DEFINE_GUID(GUID_DMUS_PROP_SamplePlaybackRate, 0x2a91f713, 0xa4bf, 0x11d2, 0xbb, 0xdf, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);
/* Property Get/Set GUID_DMUS_PROP_WriteLatency
*
* Item 0: Synth buffer write latency, in milliseconds
* Get/Set SynthSink latency, the average time after the play _head that the next buffer gets written.
*/
DEFINE_GUID(GUID_DMUS_PROP_WriteLatency,0x268a0fa0, 0x60f2, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6);
/* Property Get/Set GUID_DMUS_PROP_WritePeriod
*
* Item 0: Synth buffer write period, in milliseconds
* Get/Set SynthSink buffer write period, time span between successive writes.
*/
DEFINE_GUID(GUID_DMUS_PROP_WritePeriod,0x268a0fa1, 0x60f2, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6);
/* Property Get GUID_DMUS_PROP_MemorySize
*
* Item 0: Memory size
* Returns a DWORD containing the total number of bytes of sample RAM
*/
DEFINE_GUID(GUID_DMUS_PROP_MemorySize, 0x178f2f28, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
/* Property Set GUID_DMUS_PROP_WavesReverb
*
* Item 0: DMUS_WAVES_REVERB structure
* Sets reverb parameters
*/
DEFINE_GUID(GUID_DMUS_PROP_WavesReverb,0x4cb5622, 0x32e5, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6);
/* Property Set GUID_DMUS_PROP_Effects
*
* Item 0: DWORD with effects flags.
* Get/Set effects bits, same as dwEffectFlags in DMUS_PORTPARAMS and DMUS_PORTCAPS:
* DMUS_EFFECT_NONE
* DMUS_EFFECT_REVERB
* DMUS_EFFECT_CHORUS
*/
DEFINE_GUID(GUID_DMUS_PROP_Effects, 0xcda8d611, 0x684a, 0x11d2, 0x87, 0x1e, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
/* Property Set GUID_DMUS_PROP_LegacyCaps
*
* Item 0: The MIDINCAPS or MIDIOUTCAPS which describes the port's underlying WinMM device. This property is only supported
* by ports which wrap WinMM devices.
*/
DEFINE_GUID(GUID_DMUS_PROP_LegacyCaps,0xcfa7cdc2, 0x00a1, 0x11d2, 0xaa, 0xd5, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
/* Property Set GUID_DMUS_PROP_Volume
*
* Item 0: A long which contains an offset, in 1/100 dB, to be added to the final volume
*
*/
DEFINE_GUID(GUID_DMUS_PROP_Volume, 0xfedfae25L, 0xe46e, 0x11d1, 0xaa, 0xce, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
/* Min and Max values for setting volume with GUID_DMUS_PROP_Volume */
#define DMUS_VOLUME_MAX 2000 /* +20 dB */
#define DMUS_VOLUME_MIN -20000 /* -200 dB */
#ifdef __cplusplus
}; /* extern "C" */
#endif
#include <poppack.h>
#endif /* #ifndef _DMUSICC_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,244 @@
#include "main.h"
#include "fakedsound.h"
//DirectMusic output capture hack.
class FakeDirectSoundBuffer : public IDirectSoundBuffer
{
private:
ULONG ref;
CPipe* out;
UINT freq;
BYTE * buf;
UINT buf_size;
bool playing;
DWORD pos_play;
DWORD samples_played;
DWORD start;
void do_update();
public:
~FakeDirectSoundBuffer()
{
if (buf) free(buf);
};
HRESULT _stdcall QueryInterface(REFIID iid, void** i)
{
if (IsEqualIID(iid,IID_IUnknown) || IsEqualIID(iid,IID_IDirectSoundBuffer))
{
ref++;
*i = this;
return S_OK;
}
else return E_NOINTERFACE;
}
ULONG _stdcall AddRef() {return ++ref;};
ULONG _stdcall Release()
{
UINT r=--ref;
if (!r)
{
delete this;
}
return r;
}
HRESULT _stdcall GetCaps(LPDSBCAPS _caps)
{
DSBCAPS caps=
{
sizeof(DSBCAPS),
DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_LOCSOFTWARE,
buf_size,
0,0 //CPU crap
};
*_caps = caps;
return S_OK;
}
HRESULT _stdcall Initialize(LPDIRECTSOUND, LPCDSBUFFERDESC) {return DSERR_ALREADYINITIALIZED;}
HRESULT _stdcall SetFormat(LPCWAVEFORMATEX) {return DSERR_INVALIDCALL;}
HRESULT _stdcall GetFormat(LPWAVEFORMATEX wfx,DWORD,LPDWORD w)
{
wfx->wFormatTag=WAVE_FORMAT_PCM;
wfx->nChannels=2;
wfx->nSamplesPerSec=freq;
wfx->nAvgBytesPerSec=4*freq;
wfx->nBlockAlign=4;
wfx->wBitsPerSample=16;
wfx->cbSize=0;
if (w) *w=sizeof(WAVEFORMATEX);
return S_OK;
}
HRESULT _stdcall GetVolume(long* v) {return S_OK;}
HRESULT _stdcall SetVolume(long v) {return S_OK;}
HRESULT _stdcall GetPan(long *p) {return S_OK;}
HRESULT _stdcall SetPan(long p) {return S_OK;}
HRESULT _stdcall GetFrequency(DWORD* f) {*f=freq;return S_OK;}
HRESULT _stdcall SetFrequency(DWORD f) {return S_OK;}
HRESULT _stdcall GetStatus(DWORD* s)
{
*s = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
return S_OK;
}
HRESULT _stdcall SetCurrentPosition(DWORD) {return S_OK;}
HRESULT _stdcall Restore() {return S_OK;}
HRESULT _stdcall Lock(DWORD wr_cur, DWORD wr_b, void** p1, DWORD* s1, void** p2, DWORD* s2, DWORD flagz)
{
if (wr_b>buf_size)
{
return DSERR_INVALIDPARAM;
}
*p1 = buf + wr_cur;
if (wr_cur + wr_b > buf_size)
{
*s1 = buf_size - wr_cur;
*p2 = buf;
*s2 = wr_cur+wr_b - buf_size;
}
else
{
*s1 = wr_b;
*p2 = 0;
*s2 = 0;
}
return S_OK;
}
HRESULT _stdcall GetCurrentPosition(LPDWORD p, LPDWORD w)
{
do_update();
if (p) *p=pos_play;
if (w) *w=pos_play;
return S_OK;
}
HRESULT _stdcall Play(DWORD, DWORD, DWORD)
{
playing=1;
pos_play=0;
samples_played=0;
start=timeGetTime();
return S_OK;
}
HRESULT _stdcall Stop() {do_update();playing=0;return S_OK;}
HRESULT _stdcall Unlock(LPVOID, DWORD, LPVOID, DWORD)
{
do_update();
return S_OK;
}
FakeDirectSoundBuffer(UINT _freq,UINT size)
{
ref=1;
buf_size=size;
buf=(BYTE*)malloc(size);
memset(buf,0,size);
freq=_freq;
out=new CPipe(4,freq);
MIDI_core::player_setSource(out);
playing=0;
pos_play=0;
samples_played=0;
}
};
void FakeDirectSoundBuffer::do_update()
{
if (playing)
{
int ds=MulDiv(timeGetTime()-start,freq,1000)-samples_played;
if (ds>0)
{
UINT todo=ds*4;
while(pos_play+todo>buf_size)
{
out->WriteData(buf+pos_play,buf_size-pos_play);
todo-=buf_size-pos_play;
pos_play=0;
}
if (todo)
{
out->WriteData(buf+pos_play,todo);
pos_play+=todo;
//todo=0;
}
samples_played+=ds;
}
}
}
IDirectSoundBuffer* dhb_create(DWORD s,DWORD f)
{
return new FakeDirectSoundBuffer(f,s);
}
//fake IDirectSound crap. one static instance
static DSCAPS h_caps=
{
sizeof(DSCAPS),
DSCAPS_SECONDARY16BIT|DSCAPS_SECONDARYSTEREO,
1000,
100000,
1,
1000,
1000,
1000,//streaming buffers
1000,
1000,
1000,
0,0,0,0,0,0,//3d crap
1024*1024,
1024*1024,
1024*1024,
0,0, //CPU speed crap
0,0 //reserved crap
};
class FakeDsound : public IDirectSound
{
ULONG ref:1;
HRESULT _stdcall QueryInterface(REFIID iid,void** i)
{
if (IsEqualIID(iid,IID_IUnknown) || IsEqualIID(iid,IID_IDirectSound))
{
ref++;
*i = this;
return S_OK;
}
else return E_NOINTERFACE;
}
ULONG _stdcall AddRef() {return ++ref;}
ULONG _stdcall Release() {return --ref;}
HRESULT _stdcall CreateSoundBuffer(LPCDSBUFFERDESC, LPDIRECTSOUNDBUFFER *, LPUNKNOWN) {return DSERR_INVALIDCALL;}
HRESULT _stdcall GetCaps(LPDSCAPS _caps)
{
*_caps = h_caps;
return S_OK;
}
HRESULT _stdcall DuplicateSoundBuffer(LPDIRECTSOUNDBUFFER, LPDIRECTSOUNDBUFFER *) {return DSERR_INVALIDCALL;}
HRESULT _stdcall SetCooperativeLevel(HWND, DWORD) {return S_OK;}
HRESULT _stdcall Compact() {return S_OK;}
HRESULT _stdcall GetSpeakerConfig(LPDWORD moo) {*moo=0;return S_OK;}
HRESULT _stdcall SetSpeakerConfig(DWORD) {return S_OK;}
HRESULT _stdcall Initialize(LPCGUID) {return DSERR_ALREADYINITIALIZED;}
};
static FakeDsound HACK;
IDirectSound * get_ds() {return &HACK;}

View File

@ -0,0 +1,3 @@
IDirectSoundBuffer* dhb_create(DWORD size,DWORD freq);
IDirectSound * get_ds();

View File

@ -0,0 +1,103 @@
#define STRICT
#include <windows.h>
#include "genres.h"
static char file_path[MAX_PATH];
static void file_init()
{
char * p;
GetModuleFileName(0,file_path,MAX_PATH);
p=strrchr(file_path,'\\');
if (p) p++; else p=file_path;
strcpy(p,"genres.txt");
}
static char eol[2]={13,10};
static char get_char(HANDLE f,BOOL * eof)
{
DWORD br=0;
char r=0;
ReadFile(f,&r,1,&br,0);
if (!br) *eof=1;
return r;
}
void genres_read(HWND wnd)
{
HANDLE f;
char temp[MAX_GENRE] = {0};
char add[MAX_GENRE] = {0};
UINT ptr;
BOOL eof=0;
BOOL start;
char c;
if (!file_path[0]) file_init();
f=CreateFile(file_path,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
if (f==INVALID_HANDLE_VALUE) return;
GetWindowText(wnd,add,MAX_GENRE);
while(!eof)
{
ptr=0;
start=1;
while(ptr<MAX_GENRE-1)
{
c=get_char(f,&eof);
if (eof) break;
if (c==10 || c==13)
{
if (start) continue;
else break;
}
start=0;
temp[ptr++]=c;
}
if (ptr)
{
temp[ptr]=0;
SendMessage(wnd,CB_ADDSTRING,0,(LPARAM)temp);
if (add[0])
{
if (!_stricmp(add,temp)) add[0]=0;
}
}
}
CloseHandle(f);
if (add[0]) SendMessage(wnd,CB_ADDSTRING,0,(LPARAM)add);
}
void genres_write(HWND wnd)
{
char temp[MAX_GENRE] = {0};
UINT max = 0, n = 0;
DWORD bw = 0;
HANDLE f;
{
char add[MAX_GENRE] = {0};
GetWindowText(wnd,add,MAX_GENRE);
if (!add[0]) return;
max=SendMessage(wnd,CB_GETCOUNT,0,0);
for(n=0;n<max;n++)
{
SendMessage(wnd,CB_GETLBTEXT,n,(LPARAM)temp);
if (!_stricmp(temp,add)) return;
}
SendMessage(wnd,CB_ADDSTRING,0,(LPARAM)add);
}
if (!file_path[0]) file_init();
f=CreateFile(file_path,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,0);
if (f==INVALID_HANDLE_VALUE) return;
max=SendMessage(wnd,CB_GETCOUNT,0,0);
for(n=0;n<max;n++)
{
SendMessage(wnd,CB_GETLBTEXT,n,(LPARAM)temp);
bw = 0; WriteFile(f,temp,strlen(temp),&bw,0);
bw = 0; WriteFile(f,eol,2,&bw,0);
}
CloseHandle(f);
}

View File

@ -0,0 +1,3 @@
void genres_read(HWND wnd);
void genres_write(HWND wnd);
#define MAX_GENRE 256

View File

@ -0,0 +1,27 @@
#include "main.h"
#include "cvt.h"
bool is_gmf(const BYTE* p,size_t s)
{
return s>0x20 && *(DWORD*)p==_rv('GMF\x01');
}
bool load_gmf(MIDI_file * mf,const BYTE* buf,size_t siz)
{
grow_buf wb;
wb.write_dword(_rv('MThd'));
wb.write_dword(_rv(6));
MIDIHEADER h={0x000,0x100,0xC000};
wb.write(&h,6);
wb.write_dword(_rv('MTrk'));
int tempo=100000*rev16(*(WORD*)(buf+4));
wb.write_dword(rev32(siz-9+8+3));//MTrk size
BYTE tempo_event[8]={0,0xFF,0x51,0x03,(BYTE)((tempo>>16)&0xFF),(BYTE)((tempo>>8)&0xFF),(BYTE)(tempo&0xFF),0};
wb.write(tempo_event,8);
wb.write(buf+8,siz-9);
wb.write("\xFF\x2F\x00",3);
mf->size = wb.get_size();
mf->data = (BYTE*)wb.finish();
return !!mf->data;
}

View File

@ -0,0 +1,2 @@
#define INITGUID
#include "main.h"

View File

@ -0,0 +1,206 @@
#include "main.h"
#include "cvt.h"
#define _MThd 'dhTM'
#define _MTrk 'krTM'
#define tempo 0x188000
#define Q_MAX 128
struct HMI_cvt
{
public:
struct
{
DWORD tm;
BYTE ch,n;
} q_rel[Q_MAX];
void inline q_add(BYTE ch,BYTE nt,DWORD t)
{
UINT n=0;
while(q_rel[n].tm!=-1) n++;
q_rel[n].tm=t;
q_rel[n].ch=ch;
q_rel[n].n=nt;
}
grow_buf buf;
UINT DoTrack(const BYTE* t,UINT *_bw);
void DoQueue(DWORD ct,DWORD& tw,BYTE& _run);
bool run(MIDI_file * mf,const BYTE* _buf,DWORD sz);
};
#define FixHeader(H) {(H).fmt=rev16((H).fmt);(H).trax=rev16((H).trax);(H).dtx=rev16((H).dtx);}
void HMI_cvt::DoQueue(DWORD ct,DWORD& tw,BYTE& _run)
{
UINT n,mt,_n;
_t:
mt=-1;
for(n=0;n<Q_MAX;n++)
{
if (q_rel[n].tm<mt) {_n=n;mt=q_rel[n].tm;}
}
if (mt>ct) return;
gb_write_delta(buf,mt-tw);
tw=mt;
BYTE _e=q_rel[_n].ch|0x90;
if (_e!=_run) buf.write_byte(_run=_e);
buf.write_byte(q_rel[_n].n);
buf.write_byte(0);
q_rel[_n].tm=-1;
goto _t;
}
extern BYTE ff7loopstart[12];
UINT HMI_cvt::DoTrack(const BYTE* t,UINT *_bw)
{
{
UINT n;
for(n=0;n<Q_MAX;n++) q_rel[n].tm=-1;
}
DWORD pt=0;
DWORD ct=0,tw=0;
BYTE run=0;
BYTE _run=0;
DWORD bw_s=buf.get_size();
while(1)
{
{
unsigned int _d;
pt+=DecodeDelta(t+pt,&_d);
ct+=_d;
}
DoQueue(ct,tw,_run);
BYTE c=t[pt];
if (c==0xFF)
{
DoQueue(-2,tw,_run);
if (t[pt+1]==0x2f)
{
pt+=3;
buf.write_dword(0x002FFF00);
break;
}
return -1;
}
else if (c==0xF0)
{
gb_write_delta(buf,ct-tw);
tw=ct;
UINT _p=pt;
while(t[pt]!=0xF7) pt++;
pt++;
buf.write(t+_p,pt-_p);
}
else if (c==0xFE)
{
c=t[pt+1];
if (c==0x10)
{
pt+=t[pt+4]+9;
}
else if (c==0x14)
{
pt+=4;
gb_write_delta(buf,ct-tw);
tw=ct;
buf.write(ff7loopstart,12);
}
else if (c==0x15) pt+=8;
else return -1;
}
else
{
gb_write_delta(buf,ct-tw);
tw=ct;
if (c&0x80) {pt++;run=c;}
else c=run;
if (c!=_run) buf.write_byte(_run=c);
buf.write_byte(t[pt++]);
BYTE c1=c&0xF0;
if (c1!=0xC0 && c1!=0xD0) buf.write_byte(t[pt++]);
if (c1==0x90)
{
BYTE b=t[pt-2];
unsigned int _t;
pt+=DecodeDelta(t+pt,&_t);
q_add(c&0xF,b,_t+ct);
}
}
}
(*_bw)+=buf.get_size()-bw_s;
return pt;
}
extern BYTE hmp_track0[19]; //hmp.cpp
bool HMI_cvt::run(MIDI_file* mf,const BYTE* _buf,DWORD sz)
{
const BYTE *ptr=_buf;
while(*(DWORD*)ptr!='CART')
{
ptr++;
if (ptr==_buf+sz) {return 0;}
}
buf.write(0,14);
ptr-=8;
UINT ntrax=1;
UINT nft=*(DWORD*)(_buf+0xE4);
buf.write(hmp_track0,sizeof(hmp_track0));
UINT n;
for(n=0;n<nft;n++)
{
if (ptr>_buf+sz) return 0;
UINT _b=0;
ntrax++;
buf.write_dword(_rv('MTrk'));
DWORD _s=buf.get_size();
buf.write(0,4);
{
const BYTE* p1=ptr+ptr[0x4B];
const BYTE* _p=p1+p1[1];
p1+=2;
while(_p[-1]==' ') _p--;
_b=(_p-p1)+4;
BYTE tmp[3]={0,0xFF,1};
buf.write(tmp,3);
gb_write_delta(buf,_p-p1);
buf.write(p1,_p-p1);
p1=_p;
}
ptr+=ptr[0x57];
{
DWORD d=DoTrack(ptr,&_b);
if (d==-1) return 0;
ptr+=d;
}
buf.write_dword_ptr(rev32(_b),_s);
}
buf.write_dword_ptr(_rv('MThd'),0);
buf.write_dword_ptr(_rv(6),4);
MIDIHEADER mhd={0x0100,rev16(ntrax),0xC000};
buf.write_ptr(&mhd,sizeof(mhd),8);
mf->size = buf.get_size();
mf->data = (BYTE*)buf.finish();
return !!mf->data;
}
bool load_hmi(MIDI_file* mf,const BYTE* _buf,size_t sz)
{
HMI_cvt c;
return c.run(mf,_buf,sz);
}

View File

@ -0,0 +1,149 @@
#include "main.h"
#include "cvt.h"
#include <intsafe.h>
#define _MThd 'dhTM'
#define _MTrk 'krTM'
static DWORD ProcessTrack(const BYTE* track,grow_buf & out,int size)
{
UINT s_sz=out.get_size();
const BYTE *pt = track;
BYTE lc1 = 0,lastcom = 0;
DWORD t=0,d;
bool run = 0;
int n1,n2;
while(track < pt + size)
{
if (track[0]&0x80)
{
BYTE b=track[0]&0x7F;
out.write_byte(b);
t+=b;
}
else
{
d = (track[0])&0x7F;
n1 = 0;
while((track[n1]&0x80)==0)
{
n1++;
d+=(track[n1]&0x7F)<<(n1*7);
}
t+=d;
n1 = 1;
while((track[n1]&0x80)==0)
{
n1++;
if (n1==4) return 0;
}
for(n2=0;n2<=n1;n2++)
{
BYTE b=track[n1-n2]&0x7F;
if (n2!=n1) b|=0x80;
out.write_byte(b);
}
track+=n1;
}
track++;
if (*track == 0xFF)//meta
{
unsigned int _d;
UINT s=DecodeDelta(track+2,&_d);
UINT result;
if (UIntAdd(2, s, &result) || UIntAdd(result, _d, &result) == S_OK || !out.write(track,result))
return 0;
if (track[1]==0x2F) break;
}
else
{
lc1=track[0];
if ((lc1&0x80) == 0) return 0;
switch(lc1&0xF0)
{
case 0x80:
case 0x90:
case 0xA0:
case 0xB0:
case 0xE0:
if (lc1!=lastcom)
{
out.write_byte(lc1);
}
out.write(track+1,2);
track+=3;
break;
case 0xC0:
case 0xD0:
if (lc1!=lastcom)
{
out.write_byte(lc1);
}
out.write_byte(track[1]);
track+=2;
break;
default:
return 0;
}
lastcom=lc1;
}
}
return out.get_size()-s_sz;
}
#define FixHeader(H) {(H).fmt=rev16((H).fmt);(H).trax=rev16((H).trax);(H).dtx=rev16((H).dtx);}
BYTE hmp_track0[19]={'M','T','r','k',0,0,0,11,0,0xFF,0x51,0x03,0x18,0x80,0x00,0,0xFF,0x2F,0};
bool load_hmp(MIDI_file* mf,const BYTE* buf, size_t br)
{
MIDIHEADER mhd = {1,0,0xC0};
const BYTE * max = buf+br;
const BYTE* ptr = buf;
BOOL funky=0;
if (!memcmp(buf,"HMIMIDIR",8)) funky=1;
grow_buf dst;
DWORD n1,n2;
dst.write_dword(_rv('MThd'));
dst.write_dword(_rv(6));
dst.write(0,sizeof(mhd));
ptr = buf+(funky ? 0x1a: 0x30);
mhd.trax = *ptr;
if (funky) mhd.dtx=rev16(*(WORD*)(buf+0x4c))/6;
dst.write(hmp_track0,sizeof(hmp_track0));
while(*(WORD*)ptr != 0x2FFF && ptr < max - 4-7) ptr++;
ptr+=funky ? 5 : 7;
if (ptr == max-4) return 0;
UINT n;
for(n=1;n<mhd.trax;n++)
{
n1 = funky ? *(WORD*)ptr : *(DWORD*)ptr - 12;
if (ptr + n1 > max)
{
mhd.trax=n;
break;
}
dst.write_dword(_rv('MTrk'));
if (!funky) ptr += 8;
UINT ts_ofs=dst.get_size();
dst.write_dword(0);
if (!(n2=ProcessTrack(funky ? ptr+4 : ptr,dst,n1))) return 0;
dst.write_dword_ptr(rev32(n2),ts_ofs);
if (funky) ptr+=n1;
else ptr += n1 + 4;
}
FixHeader(mhd);
dst.write_ptr(&mhd,sizeof(mhd),8);
mf->size = dst.get_size();
mf->data = (BYTE*)dst.finish();
return !!mf->data;
}

View File

@ -0,0 +1,568 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"#include ""version.rc2""\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_CONFIG DIALOGEX 0, 0, 354, 174
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_NOFAILCREATE | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Nullsoft Midi Player Preferences"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
CONTROL "Tab1",IDC_TAB,"SysTabControl32",WS_TABSTOP,4,4,346,149
LTEXT "Note: Most settings take effect after restarting playback.",IDC_STATIC,4,158,214,12,SS_CENTERIMAGE
DEFPUSHBUTTON "OK",IDOK,222,157,40,13
PUSHBUTTON "Cancel",IDCANCEL,266,157,40,13
PUSHBUTTON "Reset",IDRESET,310,157,40,13
END
IDD_CONFIG1 DIALOGEX 0, 0, 340, 134
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
LTEXT "Device:",IDC_STATIC,3,6,30,8
COMBOBOX IDC_PORT,37,4,300,68,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
GROUPBOX "Device Info",IDC_STATIC,3,20,190,76
EDITTEXT IDC_DEV_INFO,10,31,177,60,ES_MULTILINE | ES_READONLY | WS_VSCROLL
GROUPBOX "Volume Control",IDC_STATIC,197,20,140,44
COMBOBOX IDC_VOLMODE,204,31,126,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CONTROL "Use as logarithmic",IDC_LOGVOL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,204,49,126,10
GROUPBOX "MIDI Extensions",IDC_STATIC,3,100,334,29
LTEXT "Additional reset commands between tracks:",IDC_STATIC,12,113,150,8
COMBOBOX IDC_HARDWARE_RESET,166,111,164,83,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
END
IDD_CONFIG2 DIALOGEX 0, 0, 340, 134
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
CONTROL "Sampling enabled",IDC_SAMPLING_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,4,72,10
LTEXT "Device:",IDC_STATIC,3,20,30,8
COMBOBOX IDC_WAVEIN,37,18,293,81,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Source:",IDC_STATIC,3,37,30,8
COMBOBOX IDC_WAVEIN_SRC,37,35,293,81,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CONTROL "Revert to previous source on stop",IDC_SAMP_REVERT,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,52,157,10
GROUPBOX "Format",IDC_STATIC,3,65,334,31
COMBOBOX IDC_WAVEIN_SR,10,77,40,70,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
LTEXT "Hz",IDC_WAVEIN_S2,51,79,10,8
COMBOBOX IDC_WAVEIN_CH,69,77,37,40,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_WAVEIN_BPS,117,77,38,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
GROUPBOX "Advanced",IDC_STATIC,3,100,334,29
CONTROL "Send to Winamp's output system",IDC_SAMPLING_OUTPUT,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,113,140,10
END
IDD_CONFIG3 DIALOGEX 0, 0, 340, 134
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
GROUPBOX "Device Settings",IDC_STATIC,3,4,160,44
CONTROL "Reverb",IDC_REVERB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,17,40,10
CONTROL "Chorus",IDC_CHORUS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,96,17,40,10
LTEXT "Mixing frequency:",IDC_STATIC,10,33,64,8
COMBOBOX IDC_FREQ,74,31,43,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Hz",IDC_STATIC,121,33,10,8
GROUPBOX "DLS Settings",IDC_STATIC,167,4,170,44
CONTROL "Use custom DLS file",IDC_DLS_CB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,174,17,100,10
EDITTEXT IDC_DLS,174,31,141,12,ES_AUTOHSCROLL | ES_READONLY
PUSHBUTTON "...",IDC_DLS_B,316,31,14,12
GROUPBOX "Compatibility Settings",IDC_STATIC,3,52,334,36
CONTROL "Keep DirectMusic port active between tracks\nFaster track changes, may cause problems (enable GM reset on device tab, etc)",IDC_DM_KEEP_PORT,
"Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,10,65,320,16
END
IDD_CONFIG4 DIALOGEX 0, 0, 340, 134
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
GROUPBOX "Playback Method",IDC_STATIC,3,4,334,54
COMBOBOX IDC_PLAYBACK_METHOD,10,16,320,66,CBS_DROPDOWNLIST | WS_TABSTOP
CONTROL "Show realtime MIDI control panel\n(works only with immediate playback method)",IDC_SHOW_PANEL,
"Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,10,33,320,18
GROUPBOX "Looping",IDC_LOOP_S,3,62,334,32
COMBOBOX IDC_LOOP,10,75,129,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Loop",IDC_LOOP_S2,156,77,18,8
EDITTEXT IDC_LOOP_T,178,75,28,12,ES_CENTER | ES_AUTOHSCROLL | ES_NUMBER
CONTROL "Spin1",IDC_LOOP_SP,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,198,74,11,14
LTEXT "times",IDC_LOOP_S3,210,77,20,8
CONTROL "Infinite",IDC_INFINITE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,251,76,37,10
END
IDD_CONFIG5 DIALOGEX 0, 0, 340, 134
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
GROUPBOX "Hacks",IDC_STATIC_CLN,3,4,160,69
CONTROL "Fix missing DLS drum kits",IDC_HACK_DLS_DRUMS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,16,146,10
CONTROL "Fix missing DLS instruments",IDC_HACK_DLS_INSTRUMENTS,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,30,146,10
CONTROL "Disable sysex commands",IDC_HACK_NO_SYSEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,44,146,10
CONTROL "Remove B9 00 00 / B9 20 00",IDC_HACK_XG_DRUMS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,57,146,10
GROUPBOX "Misc",IDC_STATIC,167,4,170,45
CONTROL "Try to recover incomplete tracks",IDC_HACKTRACK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,173,16,117,10
LTEXT "Extra silence after end of song:",IDC_STATIC,173,32,105,8
EDITTEXT IDC_EOF_DELAY,282,30,36,12,ES_AUTOHSCROLL | ES_NUMBER
CONTROL "Spin1",IDC_EOF_DELAY_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,310,29,9,14
LTEXT "ms",IDC_STATIC,320,32,10,8
END
IDD_CONFIG6 DIALOGEX 0, 0, 340, 134
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
GROUPBOX "MIDI Hardware Setup (Advanced Users Only)",IDC_STATIC_MOS,3,4,334,125
LISTBOX IDC_SYSEX_LIST,9,12,321,86,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "import file",IDC_IMP_F,9,103,42,14
PUSHBUTTON "export file",IDC_EXP_F,51,103,42,14
PUSHBUTTON "load preset",IDC_IMP_PR,93,103,46,14
PUSHBUTTON "save preset",IDC_EXP_PR,139,103,48,14
PUSHBUTTON "add new",IDC_SYSEX_ADD,187,103,38,14
PUSHBUTTON "delete",IDC_SYSEX_DELETE,225,103,32,14
PUSHBUTTON "edit",IDC_SYSEX_EDIT,257,103,24,14
PUSHBUTTON "up",IDC_SYSEX_UP,282,103,20,14
PUSHBUTTON "down",IDC_SYSEX_DOWN,302,103,28,14
CTEXT "Sysex commands are sent before starting playback.",IDC_STATIC_MOS1,8,119,322,8
END
IDD_CONFIG7 DIALOGEX 0, 0, 340, 134
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
LTEXT "Associate with extensions:",IDC_STATIC,4,4,100,8
LISTBOX IDC_EXTS_LIST,4,15,86,115,NOT LBS_NOTIFY | LBS_MULTIPLESEL | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
LTEXT "Additional extensions (separate with semicolons):",IDC_STATIC,114,4,223,8
EDITTEXT IDC_EXTS_ED,114,15,152,12,ES_AUTOHSCROLL
LTEXT "eg. ""MID;RMI;HMP""",IDC_STATIC,114,31,66,8
END
IDD_CONFIG8 DIALOGEX 0, 0, 340, 134
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
GROUPBOX "RMI Info Settings",IDC_STATIC,3,4,158,30
CONTROL "Display RMI info dialog by default",IDC_RMI_DEF,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,17,145,10
GROUPBOX "Lyrics Display",IDC_STATIC,165,4,172,30
CONTROL "Show lyrics window while playing",IDC_LYRICS_ENABLED,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,172,17,158,10
END
IDD_EXT_IMM DIALOGEX 0, 0, 488, 212
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "MIDI control panel"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
LTEXT "tempo",-1,2,2,20,8
CONTROL "Slider1",IDC_TEMPO,"msctls_trackbar32",TBS_NOTICKS | WS_TABSTOP,24,2,100,11
CTEXT "",IDC_TDISP,48,13,60,8
CONTROL "disable volume commands",IDC_NOVOL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,8,99,10
CONTROL "disable instrument commands",IDC_NOINS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,280,8,108,10
LTEXT "channel",-1,4,24,26,8
LTEXT "volume",-1,6,40,24,8
PUSHBUTTON "all on",IDC_ALL_ON,4,92,28,11
PUSHBUTTON "all off",IDC_ALL_OFF,4,104,28,11
LTEXT "mute",-1,12,119,16,8
GROUPBOX "instruments",-1,0,130,485,46
LTEXT "patch",-1,2,140,19,8
LTEXT "bank MSB",-1,2,152,34,8
LTEXT "bank LSB",-1,2,164,32,8
GROUPBOX "SysEx",-1,4,180,113,28
PUSHBUTTON "reset GM",IDC_GMRESET,8,190,34,12
PUSHBUTTON "reset GS",IDC_GSRESET,44,190,34,12
PUSHBUTTON "reset XG",IDC_XGRESET,80,190,33,12
GROUPBOX "",-1,116,180,125,28
LTEXT "F0",-1,120,193,9,8
EDITTEXT IDC_SYSEX1,132,190,68,12,ES_AUTOHSCROLL
LTEXT "F7",-1,202,193,9,8
PUSHBUTTON "send",IDC_SYSEX1_SEND,214,190,21,12
GROUPBOX "",-1,240,180,125,28
LTEXT "F0",-1,244,193,9,8
EDITTEXT IDC_SYSEX2,256,190,68,12,ES_AUTOHSCROLL
LTEXT "F7",-1,326,193,9,8
PUSHBUTTON "send",IDC_SYSEX2_SEND,338,190,21,12
END
#if defined(APSTUDIO_INVOKED) || defined(IN_MIDI)
#if defined(APSTUDIO_INVOKED)
IDD_INFO$(IN_MIDI) DIALOGEX 0, 0, 295, 86
#else
IDD_INFO DIALOGEX 0, 0, 295, 86
#endif
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_TOOLWINDOW
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
LTEXT "Format:",IDC_STATIC,4,2,24,8
LTEXT "",IDC_FORMAT,32,2,72,8
EDITTEXT IDC_COPYRIGHT,2,12,126,55,ES_MULTILINE | ES_READONLY | WS_VSCROLL
LTEXT "Length:",IDC_STATIC1,2,68,25,8
RTEXT "",IDC_MS,26,68,28,8
RTEXT "",IDC_TIX,26,77,28,8
LTEXT "ms",IDC_STATIC2,58,68,10,8
LTEXT "ticks",IDC_STATIC3,58,77,16,8
CTEXT "",IDC_FSIZE,80,72,44,8
LTEXT "",IDC_NTRAX,133,0,52,8
LISTBOX IDC_TRAX,132,8,160,60,NOT LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | WS_TABSTOP
LTEXT "DLS data present",IDC_DLS,136,68,56,8,WS_DISABLED
LTEXT "loop start found",IDC_LOOP,136,78,50,8,WS_DISABLED
PUSHBUTTON "RMI info...",IDC_RMI_CRAP,196,72,41,12
PUSHBUTTON "Save...",IDC_SAVE,240,72,29,12
DEFPUSHBUTTON "Ok",IDOK,272,72,20,12
END
#endif
IDD_LYRICS DIALOGEX 0, 0, 263, 220
STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION "Lyrics"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
EDITTEXT IDC_BLAH,0,0,260,216,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL
END
#if defined(APSTUDIO_INVOKED) || defined(IN_MIDI)
#if defined(APSTUDIO_INVOKED)
IDD_RMI_SHIZ$(IN_MIDI) DIALOGEX 0, 0, 316, 151
#else
IDD_RMI_SHIZ DIALOGEX 0, 0, 316, 151
#endif
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_NOFAILCREATE | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_TOOLWINDOW
CAPTION "RMI info"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
LTEXT "Display Name:",IDC_STATIC,2,6,46,8
EDITTEXT IDC_DISP,48,4,128,12,ES_AUTOHSCROLL
LTEXT "Name:",IDC_STATIC,26,22,22,8
EDITTEXT IDC_NAME,48,20,128,12,ES_AUTOHSCROLL
LTEXT "Artist:",IDC_STATIC,27,38,24,8
EDITTEXT IDC_ARTIST,48,36,128,12,ES_AUTOHSCROLL
LTEXT "Album:",IDC_STATIC,25,54,22,8
EDITTEXT IDC_ALBUM,48,52,76,12,ES_AUTOHSCROLL
LTEXT "Track:",IDC_STATIC,130,54,22,8
EDITTEXT IDC_TRACK,152,52,24,12,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "Genre:",IDC_STATIC,24,70,22,8
COMBOBOX IDC_GENRE,47,68,129,68,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP
LTEXT "Date Created:",IDC_STATIC,1,86,46,8
EDITTEXT IDC_DATE,47,84,129,12,ES_AUTOHSCROLL
LTEXT "Software:",IDC_STATIC,16,102,31,8
EDITTEXT IDC_SOFTWARE,47,100,129,12,ES_AUTOHSCROLL
LTEXT "Engineer:",IDC_STATIC,16,118,31,8
EDITTEXT IDC_ENGINEER,47,116,129,12,ES_AUTOHSCROLL
LTEXT "Composer:",IDC_STATIC,12,134,34,8
EDITTEXT IDC_COMPOSER,47,132,129,12,ES_AUTOHSCROLL
LTEXT "Copyright:",IDC_STATIC,188,1,34,8
EDITTEXT IDC_COPYRIGHT,188,9,124,36,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL
LTEXT "Comment:",IDC_STATIC,188,46,32,8
EDITTEXT IDC_COMMENT,188,54,124,36,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL
LTEXT "Subject:",IDC_STATIC,188,91,27,8
EDITTEXT IDC_SUBJECT,188,99,96,36,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL
CONTROL "",IDC_BMPVIEW,"BitmapView",WS_TABSTOP,288,100,24,22
DEFPUSHBUTTON "OK",IDOK,206,138,50,12
PUSHBUTTON "Cancel",IDCANCEL,262,138,50,12
END
#endif // APSTUDIO_INVOKED || IN_MIDI
IDD_SYSEX DIALOGEX 0, 0, 336, 38
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Sysex Event Editor"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
LTEXT "F0",IDC_STATIC,4,6,9,8
EDITTEXT IDC_EDIT1,24,4,290,12,ES_AUTOHSCROLL
LTEXT "F7",IDC_STATIC,323,6,9,8
LTEXT "wait",IDC_STATIC,4,23,20,8
EDITTEXT IDC_DELAY,24,21,40,12,ES_AUTOHSCROLL | ES_NUMBER
CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,52,20,11,14
LTEXT "ms after sending",IDC_STATIC,69,23,70,8
DEFPUSHBUTTON "OK",IDOK,228,21,50,13
PUSHBUTTON "Cancel",IDCANCEL,282,21,50,13
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_CONFIG, DIALOG
BEGIN
LEFTMARGIN, 4
RIGHTMARGIN, 350
TOPMARGIN, 4
BOTTOMMARGIN, 170
END
IDD_CONFIG1, DIALOG
BEGIN
LEFTMARGIN, 3
RIGHTMARGIN, 337
TOPMARGIN, 4
BOTTOMMARGIN, 130
END
IDD_CONFIG2, DIALOG
BEGIN
LEFTMARGIN, 3
RIGHTMARGIN, 337
TOPMARGIN, 4
BOTTOMMARGIN, 130
END
IDD_CONFIG3, DIALOG
BEGIN
LEFTMARGIN, 3
RIGHTMARGIN, 337
TOPMARGIN, 4
BOTTOMMARGIN, 130
END
IDD_CONFIG4, DIALOG
BEGIN
LEFTMARGIN, 3
RIGHTMARGIN, 337
TOPMARGIN, 4
BOTTOMMARGIN, 130
END
IDD_CONFIG5, DIALOG
BEGIN
LEFTMARGIN, 3
RIGHTMARGIN, 337
TOPMARGIN, 4
BOTTOMMARGIN, 130
END
IDD_CONFIG6, DIALOG
BEGIN
LEFTMARGIN, 3
RIGHTMARGIN, 337
TOPMARGIN, 4
BOTTOMMARGIN, 129
END
IDD_CONFIG7, DIALOG
BEGIN
LEFTMARGIN, 4
RIGHTMARGIN, 337
TOPMARGIN, 4
BOTTOMMARGIN, 130
END
IDD_CONFIG8, DIALOG
BEGIN
LEFTMARGIN, 3
RIGHTMARGIN, 337
TOPMARGIN, 4
BOTTOMMARGIN, 130
END
"IDD_RMI_SHIZ$(IN_MIDI)", DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 309
TOPMARGIN, 7
BOTTOMMARGIN, 144
END
IDD_SYSEX, DIALOG
BEGIN
LEFTMARGIN, 4
RIGHTMARGIN, 332
TOPMARGIN, 4
BOTTOMMARGIN, 34
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_NULLSOFT_MIDI_PLAYER "Nullsoft MIDI Player v%s"
65535 "{0FED0FEE-C995-4499-AB47-E2482336C046}"
END
STRINGTABLE
BEGIN
IDS_NULLSOFT_MIDI_PLAYER_OLD "Nullsoft MIDI Player"
STRING_FILES_OTHER "Other MIDI types ("
IDS_TO_ENABLE_LYRICS_DISPLAY
"To enable lyrics display again, go to MIDI plug-in config / display tab and check ""Show lyrics window while playing""."
IDS_INFORMATION "Information"
STRING_INCOMPLETE " (incomplete)"
STRING_TRACKS_FMT "%u tracks:"
IDS_MIDIS_ARE_NOT_BURNABLE " MIDIs are not burnable."
IDS_NONE "none"
IDS_STREAMED "Streamed - send data to OS as large blocks / segments"
IDS_IMMEDIATE "Immediate - send MIDI events to OS in realtime"
IDS_CONFIGURATION "Configuration"
IDS_TYPE "type : "
IDS_PREFS_DEVICE "Device"
END
STRINGTABLE
BEGIN
IDS_PREFS_DISPLAY "Display"
IDS_PREFS_SAMPLING "Sampling"
IDS_PREFS_DIRECTMUSIC "DirectMusic"
IDS_PREFS_MISC "Misc"
IDS_PREFS_FILE_TYPES "File Types"
IDS_PREFS_FILES "Files"
IDS_PREFS_HARDWARE_SETUP "Hardware setup"
IDS_UNABLE_TO_LOAD_FILE "Unable to load file."
STRING_RETRIEVING_FILE "Retrieving MIDI file"
STRING_URL_ERROR "URLs only supported in Winamp 2.50+"
STRING_UNKNOWN_MMSYSTEM "Unknown MMSYSTEM error."
STRING_MIDI_INFO_FMT2 "MIDI file info - %s"
STRING_MIDI_INFO_FMT1 "MIDI file info - %s (%s)"
STRING_BYTES_FMT "%u bytes"
STRING_WRITE_ERROR_FMT "Unable to create file: ""%s"""
STRING_INFO_FORMAT_FMT " / format %u"
END
STRINGTABLE
BEGIN
STRING_RMI_INFO_FMT "RMI info - %s"
STRING_CONFIG_RESET "This will reset all settings to default values. Continue?"
STRING_STEREO "Stereo"
STRING_MONO "Mono"
STRING_VOLUME_AUTO "Autodetect"
STRING_VOLUME_DRIVER_SPECIFIC "Driver-specific"
STRING_VOLUME_NONE "None"
STRING_SAMP_SRC_DEFAULT "(default)"
STRING_LOOP1 "never"
STRING_LOOP2 "when loop start detected"
STRING_LOOP3 "always"
STRING_UNKNOWN "unknown (%u)"
STRING_DIRECT_MIDISTREAM "direct midiStream support"
STRING_MOCAPS_WAVETABLE "hardware wavetable synthesizer"
STRING_MOCAPS_SYNTH "synthesizer"
STRING_MOCAPS_SQUARE "square wave synthesizer"
END
STRINGTABLE
BEGIN
STRING_MOCAPS_MAPPER "MIDI mapper"
STRING_MOCAPS_HWPORT "MIDI hardware port"
STRING_MOCAPS_FM "FM synthesizer"
STRING_EFFECTS "effects : "
STRING_DEVICE_TYPE "device type : "
STRING_DMCAPS_WDM "WDM driver"
STRING_DMCAPS_USERMODE "User mode synthesizer"
STRING_DMCAPS_WINMM "Windows Multimedia driver"
STRING_CHORUS "chorus"
STRING_REVERB "reverb"
STRING_DMCAPS_SHARE "device is shareable"
STRING_DMCAPS_DSOUND "uses DirectSound"
STRING_DMCAPS_XG "built-in XG sound set"
STRING_DMCAPS_GS "built-in GS sound set"
STRING_DMCAPS_GM "built-in GM sound set"
STRING_DMCAPS_SOFTSYNTH "software synthesizer"
END
STRINGTABLE
BEGIN
STRING_DMCAPS_DLS2 "supports DLS level 2"
STRING_DMCAPS_DLS1 "supports DLS level 1"
STRING_FILES_SMF "Standard MIDI"
STRING_FILES_CLONE "MIDI Clones"
STRING_FILES_COMPRESSED "Compressed MIDI"
IDS_SYSEX_DATA "Sysex Data"
IDS_MIDI_HARDWARE_PRESETS "MIDI Hardware Presets"
IDS_DLS_FILES "DLS Files"
IDS_MIDI_FILES "MIDI files"
IDS_COMPRESSED_MIDI_FILES "Compressed MIDI files"
IDS_RMI_FILES "RMI files"
IDS_COMPRESSED_RMI_FILES "Compressed RMI files"
IDS_WITH_OUTPUT " (with output)"
IDS_USES_WINAMPS_OUTPUT_PLUGINS "uses Winamp's Output plug-ins"
STRING_MS_FMT "(%u ms)"
STRING_BIT_FMT "%u bit"
END
STRINGTABLE
BEGIN
IDS_FAMILY_STRING_MIDI "MIDI File Format"
IDS_FAMILY_STRING_KARAOKE_MIDI "Karaoke MIDI File"
IDS_FAMILY_STRING_HMI_MIDI "Human Machine Interfaces MIDI File"
IDS_FAMILY_STRING_EXTENDED_MIDI "Extended MIDI File"
IDS_FAMILY_STRING_MSS_MIDI "MSS MIDI File"
IDS_FAMILY_STRING_FINALE_MIDI "Finale Notation MIDI Music File"
IDS_FAMILY_STRING_CREATIVE_MIDI "Creative Music MIDI Format"
IDS_FAMILY_STRING_GENERAL_MIDI_DUMP "General Midi Dump File"
IDS_FAMILY_STRING_COMPRESSED_MIDI "Compressed MIDI File"
IDS_FAMILY_STRING_COMPRESSED_HMI_MIDI
"Compressed Human Machine Interfaces MIDI File"
IDS_ABOUT_TEXT "%s\n<> 2000-2023 Winamp SA\n\nBuild date: %hs"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
#include "version.rc2"
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29613.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "in_midi", "in_midi.vcxproj", "{880DB5D8-1FFB-4FC8-A625-C44884C773FD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{880DB5D8-1FFB-4FC8-A625-C44884C773FD}.Debug|Win32.ActiveCfg = Debug|Win32
{880DB5D8-1FFB-4FC8-A625-C44884C773FD}.Debug|Win32.Build.0 = Debug|Win32
{880DB5D8-1FFB-4FC8-A625-C44884C773FD}.Debug|x64.ActiveCfg = Debug|x64
{880DB5D8-1FFB-4FC8-A625-C44884C773FD}.Debug|x64.Build.0 = Debug|x64
{880DB5D8-1FFB-4FC8-A625-C44884C773FD}.Release|Win32.ActiveCfg = Release|Win32
{880DB5D8-1FFB-4FC8-A625-C44884C773FD}.Release|Win32.Build.0 = Release|Win32
{880DB5D8-1FFB-4FC8-A625-C44884C773FD}.Release|x64.ActiveCfg = Release|x64
{880DB5D8-1FFB-4FC8-A625-C44884C773FD}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6065B54A-493B-411D-8491-E7A9F2C3A87F}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,328 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{880DB5D8-1FFB-4FC8-A625-C44884C773FD}</ProjectGuid>
<RootNamespace>in_midi</RootNamespace>
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Label="Vcpkg">
<VcpkgEnabled>true</VcpkgEnabled>
<VcpkgEnableManifest>false</VcpkgEnableManifest>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<VcpkgInstalledDir>
</VcpkgInstalledDir>
<VcpkgUseStatic>false</VcpkgUseStatic>
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<VcpkgInstalledDir>
</VcpkgInstalledDir>
<VcpkgUseStatic>false</VcpkgUseStatic>
<VcpkgConfiguration>Debug</VcpkgConfiguration>
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
<VcpkgConfiguration>Debug</VcpkgConfiguration>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..\Wasabi;..\..\..\external_dependencies\vcpkg\$(PlatformShortName)-windows-static\include;..\..\..\external_dependencies\vcpkg\$(PlatformShortName)-windows-static\include\minizip;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;IN_MIDI_EXPORTS;IN_MIDI;WINVER=0x601;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<DisableSpecificWarnings>4018;4133;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;IN_MIDI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>winmm.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<DelayLoadDLLs>winmm.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<SubSystem>Windows</SubSystem>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..\Wasabi;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;IN_MIDI_EXPORTS;IN_MIDI;WINVER=0x601;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<DisableSpecificWarnings>4018;4133;4244;4267;4302;4311;4312;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;IN_MIDI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>winmm.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<DelayLoadDLLs>winmm.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<SubSystem>Windows</SubSystem>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MinSpace</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<AdditionalIncludeDirectories>..\..\..\Wasabi;..\..\..\external_dependencies\vcpkg\$(PlatformShortName)-windows-static\include;..\..\..\external_dependencies\vcpkg\$(PlatformShortName)-windows-static\include\minizip;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;IN_MIDI_EXPORTS;IN_MIDI;WINVER=0x601;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>None</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<DisableSpecificWarnings>4018;4133;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;IN_MIDI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>winmm.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<DelayLoadDLLs>winmm.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<SubSystem>Windows</SubSystem>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<Optimization>MinSpace</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<AdditionalIncludeDirectories>..\..\..\Wasabi;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;IN_MIDI_EXPORTS;IN_MIDI;WINVER=0x601;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>None</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<DisableSpecificWarnings>4018;4133;4244;4267;4302;4311;4312;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;IN_MIDI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>winmm.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<DelayLoadDLLs>winmm.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<SubSystem>Windows</SubSystem>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\pfc\cfg_var.cpp" />
<ClCompile Include="..\..\..\pfc\grow_buf.cpp" />
<ClCompile Include="..\..\..\pfc\string.cpp" />
<ClCompile Include="..\..\..\pfc\string_unicode.cpp" />
<ClCompile Include="cleaner.cpp" />
<ClCompile Include="cmf.cpp" />
<ClCompile Include="CompressionUtility.cpp" />
<ClCompile Include="config.cpp" />
<ClCompile Include="fakedsound.cpp" />
<ClCompile Include="genres.c" />
<ClCompile Include="gmf.cpp" />
<ClCompile Include="guids.cpp" />
<ClCompile Include="hmi.cpp" />
<ClCompile Include="hmp.cpp" />
<ClCompile Include="info.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="midifile.cpp" />
<ClCompile Include="midiinfo.cpp" />
<ClCompile Include="midi_driver.cpp" />
<ClCompile Include="mids.cpp" />
<ClCompile Include="mus.cpp" />
<ClCompile Include="out_dmusic.cpp" />
<ClCompile Include="out_midi.cpp" />
<ClCompile Include="sampling.cpp" />
<ClCompile Include="seq.cpp" />
<ClCompile Include="utils.cpp" />
<ClCompile Include="wa2.cpp" />
<ClCompile Include="xmi.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="CompressionUtility.h" />
<ClInclude Include="core_api.h" />
<ClInclude Include="cvt.h" />
<ClInclude Include="fakedsound.h" />
<ClInclude Include="genres.h" />
<ClInclude Include="In2.h" />
<ClInclude Include="main.h" />
<ClInclude Include="midifile.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="seq.h" />
<ClInclude Include="utils.h" />
<ClInclude Include="wa2.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="in_midi.rc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
<Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="cleaner.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="cmf.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="config.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="fakedsound.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="gmf.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="guids.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hmi.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hmp.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="info.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="midi_driver.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="midifile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="midiinfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mids.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mus.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="out_dmusic.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="out_midi.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="sampling.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="seq.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="xmi.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="wa2.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="genres.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CompressionUtility.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\pfc\cfg_var.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\pfc\grow_buf.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\pfc\string.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\pfc\string_unicode.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="wa2.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="seq.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="midifile.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="main.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="In2.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="genres.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="fakedsound.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cvt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="core_api.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CompressionUtility.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{76163c49-62a1-40bf-a79e-3a31abcffa0d}</UniqueIdentifier>
</Filter>
<Filter Include="Ressource Files">
<UniqueIdentifier>{2b6a02a5-067a-4e25-9414-7d18ebf093d5}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{8debc30d-140a-4e48-861b-21f5e29c3a8b}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="in_midi.rc">
<Filter>Ressource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,940 @@
#include "main.h"
#include "resource.h"
#include <shlwapi.h>
#include <commdlg.h>
#include <strsafe.h>
#include "../nu/AutoWide.h"
#include "../nu/AutoCharFn.h"
#include "CompressionUtility.h"
extern In_Module mod;
extern "C"
{
#include "genres.h"
}
#define HAVE_BMPVIEW
#ifdef HAVE_BMPVIEW
static LRESULT CALLBACK BmpViewProc(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_PAINT:
{
RECT r;
GetClientRect(wnd, &r);
HDC wdc = GetDC(wnd);
HDC dc = (HDC)GetWindowLongPtr(wnd, 4);
DrawEdge(wdc, &r, EDGE_SUNKEN, BF_RECT);
if (dc) BitBlt(wdc, 2, 2, r.right - 4, r.bottom - 4, dc, 0, 0, SRCCOPY);
ReleaseDC(wnd, wdc);
ValidateRect(wnd, 0);
return 0;
}
break;
case WM_USER:
{
HDC dc = CreateCompatibleDC(0);
SelectObject(dc, (HBITMAP)lp);
SetWindowLongPtr(wnd, 0, lp);
SetWindowLongPtr(wnd, 4, (LONG_PTR)dc);
//RedrawWindow(wnd,0,0,RDW_INVALIDATE);
}
return 0;
case WM_DESTROY:
{
HBITMAP bmp = (HBITMAP)GetWindowLongPtr(wnd, 0);
HDC dc = (HDC)GetWindowLongPtr(wnd, 4);
if (dc) DeleteDC(dc);
if (bmp) DeleteObject(bmp);
}
break;
}
return DefWindowProc(wnd, msg, wp, lp);
}
void bmpview_init()
{
static bool got_class;
if (!got_class)
{
got_class = 1;
WNDCLASS wc =
{
0,
BmpViewProc,
0, 8,
MIDI_callback::GetInstance(), 0, LoadCursor(0, IDC_ARROW), 0,
0,
L"BitmapView"
};
RegisterClassW(&wc);
}
}
#endif
BOOL SaveFile(HWND w, MIDI_file* mf, BOOL info);
int SaveAsGZip(string filename, const void* buffer, size_t size);
UINT align(UINT x, UINT a)
{
a--;
return (x + a) & ~a;
}
typedef struct
{
UINT ctrl_id;
DWORD riff_id;
// char * name;
}
RMI_TAG;
static void _swap_ptrs(void** a, void* b)
{
void* _a = *a;
*a = b;
if (_a) free(_a);
}
#define swap_ptrs(x,y) _swap_ptrs((void**)&x,(void*)(y))
static RMI_TAG rmi_tagz[] =
{
{IDC_DISP, _rv('DISP')},
{IDC_NAME, _rv('INAM')},
{IDC_ARTIST, _rv('IART')},
{IDC_ALBUM, _rv('IALB')},
{IDC_TRACK, _rv('ITRK')},
{IDC_GENRE, _rv('IGNR')},
{IDC_COMPOSER, _rv('ICMP')},
{IDC_COPYRIGHT, _rv('ICOP')},
{IDC_COMMENT, _rv('ICMT')},
{IDC_DATE, _rv('ICRD')},
{IDC_SOFTWARE, _rv('ISFT')},
{IDC_ENGINEER, _rv('IENG')},
{IDC_SUBJECT, _rv('ISBJ')},
};
void SetDlgItemTextSiz(HWND wnd, UINT id, char* text, UINT siz)
{
if (!text[siz - 1]) SetDlgItemTextA(wnd, id, text);
else
{
char* foo = (char*)alloca(siz + 1);
memcpy(foo, text, siz);
foo[siz] = 0;
SetDlgItemTextA(wnd, id, foo);
}
}
#define N_RMI_TAGZ (sizeof(rmi_tagz)/sizeof(rmi_tagz[0]))
static void set_rmi_dlg_title(HWND wnd, MIDI_file* mf)
{
char t[MAX_PATH + 100] = { 0 };
StringCbPrintfA(t, sizeof(t), WASABI_API_LNGSTRING(STRING_RMI_INFO_FMT), (const char*)mf->path);
SetWindowTextA(wnd, t);
}
static BOOL CALLBACK rmiproc(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_INITDIALOG:
#if defined(_WIN64)
SetWindowLong(wnd, DWLP_USER, lp);
#else
SetWindowLong(wnd, DWL_USER, lp);
#endif
{
MIDI_file* mf = (MIDI_file*)lp;
set_rmi_dlg_title(wnd, mf);
if (mf->title && *mf->title)
{
SetDlgItemTextA(wnd, IDC_DISP, mf->title);
}
if (mf->rmi_data)
{
BYTE* rmi = (BYTE*)mf->rmi_data;
int p = 4;
while (p < mf->rmi_size)
{
DWORD id = *(DWORD*)(rmi + p);
UINT n;
for (n = 0; n < N_RMI_TAGZ; n++)
{
if (id == rmi_tagz[n].riff_id)
{
SetDlgItemTextSiz(wnd, rmi_tagz[n].ctrl_id, (char*)(rmi + p + 8), *(DWORD*)(rmi + p + 4));
break;
}
}
p += 8 + align(*(DWORD*)(rmi + p + 4), 2);
}
}
#ifdef HAVE_BMPVIEW
if (mf->bmp_data)
{
void* pixels;
BITMAPINFOHEADER* foo = (BITMAPINFOHEADER*)mf->bmp_data;
HBITMAP bmp = CreateDIBSection(0, (BITMAPINFO*)foo, DIB_RGB_COLORS, &pixels, 0, 0);
if (bmp)
{
UINT clr_used = foo->biClrUsed;
if (!clr_used) clr_used = 1 << foo->biBitCount;
BYTE* ptr = (BYTE*)foo + foo->biSize + (clr_used << 2);
int max = (BYTE*)mf->bmp_data + mf->bmp_size - ptr;
BITMAP b;
GetObject(bmp, sizeof(b), &b);
int siz = b.bmWidthBytes * b.bmHeight;
if (siz < 0) siz = -siz;
if (siz > max) siz = max;
memcpy(pixels, ptr, siz);
SendDlgItemMessage(wnd, IDC_BMPVIEW, WM_USER, 0, (long)bmp);
}
}
#endif
}
genres_read(GetDlgItem(wnd, IDC_GENRE));
return 1;
case WM_COMMAND:
switch (wp)
{
case IDOK:
{
#if defined(_WIN64)
MIDI_file* mf = (MIDI_file*)GetWindowLong(wnd, DWLP_USER);
#else
MIDI_file* mf = (MIDI_file*)GetWindowLong(wnd, DWL_USER);
#endif
char* title = 0;
HWND w = GetDlgItem(wnd, IDC_DISP);
UINT sz = GetWindowTextLength(w);
if (sz)
{
sz++;
title = (char*)malloc(sz);
GetWindowTextA(w, title, sz);
}
swap_ptrs(mf->title, title);
BYTE* rmi_info = 0;
UINT rmi_siz = 0;
UINT n;
for (n = 0; n < N_RMI_TAGZ; n++)
{
UINT d = GetWindowTextLength(GetDlgItem(wnd, rmi_tagz[n].ctrl_id));
if (d) rmi_siz += align(d + 1, 2) + 8;
}
if (rmi_siz)
{
rmi_siz += 4; //'INFO'
rmi_info = (BYTE*)malloc(rmi_siz);
UINT ptr = 4;
*(DWORD*)rmi_info = _rv('INFO');
for (n = 0; n < N_RMI_TAGZ; n++)
{
w = GetDlgItem(wnd, rmi_tagz[n].ctrl_id);
if (GetWindowTextLength(w))
{
*(DWORD*)(rmi_info + ptr) = rmi_tagz[n].riff_id;
ptr += 4;
char* foo = (char*)(rmi_info + ptr + 4);
GetWindowTextA(w, foo, rmi_siz - (ptr + 4));
UINT s = strlen(foo) + 1;
*(DWORD*)(rmi_info + ptr) = s;
ptr += 4 + align(s, 2);
}
}
rmi_siz = ptr;
}
mf->rmi_size = rmi_siz;
swap_ptrs(mf->rmi_data, rmi_info);
genres_write(GetDlgItem(wnd, IDC_GENRE));
if (SaveFile(wnd, mf, 1)) EndDialog(wnd, 0);
}
break;
case IDCANCEL:
genres_write(GetDlgItem(wnd, IDC_GENRE));
EndDialog(wnd, 1);
break;
}
break;
}
return 0;
}
int show_rmi_info(HWND w, MIDI_file* mf)
{
#ifdef HAVE_BMPVIEW
bmpview_init();
#endif
return WASABI_API_DIALOGBOXPARAM(IDD_RMI_SHIZ, w, rmiproc, (long)mf);
}
static bool is_local(const char* url)
{
if (!_strnicmp(url, "file://", 7) || !strnicmp(url, "partial://", 10)) return 1;
if (url[1] == ':' && url[2] == '\\') return 1;
return strstr(url, "://") ? 0 : 1;
}
static char* fmt_names[] = { "MIDI", "RIFF MIDI", "HMP", "HMI", "XMIDI", "MUS", "CMF", "GMD", "MIDS", "GMF", "MIDI(?)" };
const char* find_tag(MIDI_file* mf, DWORD id, UINT* siz);
char* getfmtstring(MIDI_file* f, char* s)
{
const char* z = fmt_names[f->format];
while (z && *z) *(s++) = *(z++);
if (f->format <= 1) //MID/RMI
{
char foo[32] = { 0 };
StringCbPrintfA(foo, sizeof(foo), WASABI_API_LNGSTRING(STRING_INFO_FORMAT_FMT), f->data[4 + 4 + 1]);
z = foo;
while (z && *z) *(s++) = *(z++);
}
if (f->info.e_type)
{
*(s++) = ' ';
*(s++) = '(';
z = f->info.e_type;
while (z && *z) *(s++) = *(z++);
*(s++) = ')';
}
*s = 0;
return s;
}
void file2title(const char* f, string& t);
static const char* find_tag(MIDI_file* mf, DWORD id, UINT* siz)
{
if (!mf->rmi_data) return 0;
char* rmi = (char*)mf->rmi_data;
int ptr = 4;
while (ptr < mf->rmi_size)
{
if (*(DWORD*)(rmi + ptr) == id)
{
UINT s = *(DWORD*)(rmi + ptr + 4);
UINT s1 = 0;
ptr += 8;
while (rmi[ptr + s1] && s1 < s) s1++;
if (siz) *siz = s1;
return rmi + ptr;
}
ptr += align(*(DWORD*)(rmi + ptr + 4), 2) + 8;
}
return 0;
}
bool KeywordMatch(const char* mainString, const char* keyword)
{
return !_stricmp(mainString, keyword);
}
static const wchar_t* pExtList[] = { L"MID",L"MIDI",L"RMI",L"KAR",L"HMP",L"HMI",L"XMI",L"MSS",L"MUS",L"CMF",L"GMD",L"MIDS",L"MIZ",L"HMZ" };
static const int pExtDescIdList[] = { 0, 0, 0, 1, 2, 2, 3, 4, 5, 6, 7, 0, 8, 9 };
static const int pExtDescList[] =
{
IDS_FAMILY_STRING_MIDI,
IDS_FAMILY_STRING_KARAOKE_MIDI,
IDS_FAMILY_STRING_HMI_MIDI,
IDS_FAMILY_STRING_EXTENDED_MIDI,
IDS_FAMILY_STRING_MSS_MIDI,
IDS_FAMILY_STRING_FINALE_MIDI,
IDS_FAMILY_STRING_CREATIVE_MIDI,
IDS_FAMILY_STRING_GENERAL_MIDI_DUMP,
IDS_FAMILY_STRING_COMPRESSED_MIDI,
IDS_FAMILY_STRING_COMPRESSED_HMI_MIDI
};
MIDI_file* wa2_open_file(const char* url);
extern "C" __declspec(dllexport) int winampGetExtendedFileInfoW(const wchar_t* fn, const char* data, wchar_t* dest, int destlen)
{
MIDI_file* file = 0;
if (KeywordMatch(data, "type"))
{
dest[0] = L'0';
dest[1] = 0;
return 1;
}
if (KeywordMatch(data, "BURNABLE"))
{
dest[0] = L'0';
dest[1] = 0;
return 1;
}
if (KeywordMatch(data, "noburnreason")) // note: this isn't supposed to be any kind of protection - just keeps the burner from misbehaving on protected tracks
{
WASABI_API_LNGSTRINGW_BUF(IDS_MIDIS_ARE_NOT_BURNABLE, dest, destlen);
return 1;
}
if (KeywordMatch(data, "family"))
{
INT index;
LPCWSTR e;
DWORD lcid;
e = PathFindExtensionW(fn);
if (L'.' != *e || 0x00 == *(++e)) return 0;
lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
for (index = sizeof(pExtList) / sizeof(wchar_t*) - 1; index >= 0 && CSTR_EQUAL != CompareStringW(lcid, NORM_IGNORECASE, e, -1, pExtList[index], -1); index--);
if (index >= 0 && S_OK == StringCchCopyW(dest, destlen, WASABI_API_LNGSTRINGW(pExtDescList[pExtDescIdList[index]]))) return 1;
return 0;
}
file = wa2_open_file(AutoCharFn(fn));
if (!file)
{
return 0;
}
const char* ret = 0;
//else if (!_stricmp(tag,"FILEPATH") || !_stricmp(tag,"PATH")) ret=file->path;
//else if (!_stricmp(tag,"DISPLAY")) ret=file->title;
//else if (!_stricmp(tag,"FIRSTTRACK")) ret=file->info.traxnames[0];
if (KeywordMatch(data, "LENGTH"))
{
_itow(file->GetLength(), dest, 10);
file->Free();
return 1;
}
else if (file->rmi_data)
{
if (KeywordMatch(data, "TITLE")) ret = find_tag(file, _rv('INAM'), 0);
else if (KeywordMatch(data, "ARTIST")) ret = find_tag(file, _rv('IART'), 0);
else if (KeywordMatch(data, "COMPOSER")) ret = find_tag(file, _rv('ICMP'), 0);
else if (KeywordMatch(data, "GENRE")) ret = find_tag(file, _rv('IGNR'), 0);
else if (KeywordMatch(data, "ALBUM")) ret = find_tag(file, _rv('IALB'), 0);
else if (KeywordMatch(data, "COPYRIGHT")) ret = find_tag(file, _rv('ICOP'), 0);
else if (KeywordMatch(data, "COMMENT")) ret = find_tag(file, _rv('ICMT'), 0);
else if (KeywordMatch(data, "TRACK")) ret = find_tag(file, _rv('ITRK'), 0);
else if (KeywordMatch(data, "DATE")) ret = find_tag(file, _rv('ICRD'), 0);
else
{
file->Free();
return 0;
}
}
else
{
file->Free();
return 0;
}
if (ret)
{
lstrcpynW(dest, AutoWide(ret), destlen);
}
file->Free();
return !!ret;
}
void MIDI_file::GetTitle(char* buf, int maxlen)
{
string file_title;
file2title(path, file_title);
lstrcpynA(buf, file_title, maxlen);
}
//int save_gzip(MIDI_file* mf, char* path);
static void do_ext(string& s, const char* ext)
{
const char* p = strrchr(s, '.');
if (p) s.truncate(p - (const char*)s);
s += ext;
}
void* build_rmi(MIDI_file* mf, UINT* siz)
{
UINT sz = 0x14 + align(mf->size, 2);
UINT t_sz = 0;
if (mf->title)
{
t_sz = strlen(mf->title);
if (t_sz)
{
t_sz++; //add null;
sz += 12 + align(t_sz, 2);
}
}
if (mf->rmi_data)
{
sz += align(mf->rmi_size + 8, 2);
}
if (mf->bmp_data)
{
sz += align(mf->bmp_size + 12, 2);
}
if (mf->pDLSdata) sz += align(mf->DLSsize, 2);
BYTE* block = (BYTE*)malloc(sz);
BYTE* b_ptr = block;
*(DWORD*)b_ptr = _rv('RIFF');
b_ptr += 4;
*(DWORD*)b_ptr = sz - 8;
b_ptr += 4;
*(DWORD*)b_ptr = _rv('RMID');
b_ptr += 4;
*(DWORD*)b_ptr = _rv('data');
b_ptr += 4;
*(DWORD*)b_ptr = mf->size;
b_ptr += 4;
memcpy(b_ptr, mf->data, mf->size);
b_ptr += align(mf->size, 2);
if (t_sz)
{
*(DWORD*)b_ptr = _rv('DISP');
b_ptr += 4;
*(DWORD*)b_ptr = t_sz + 4;
b_ptr += 4;
*(DWORD*)b_ptr = 1;
b_ptr += 4;
memcpy(b_ptr, mf->title, t_sz);
b_ptr += align(t_sz, 2);
}
if (mf->rmi_data)
{
*(DWORD*)b_ptr = _rv('LIST');
b_ptr += 4;
*(DWORD*)b_ptr = mf->rmi_size;
b_ptr += 4;
memcpy(b_ptr, mf->rmi_data, mf->rmi_size);
b_ptr += align(mf->rmi_size, 2);
}
if (mf->bmp_data)
{
*(DWORD*)b_ptr = _rv('DISP');
b_ptr += 4;
*(DWORD*)b_ptr = mf->bmp_size + 4;
b_ptr += 4;
*(DWORD*)b_ptr = 8;
b_ptr += 4;
memcpy(b_ptr, mf->bmp_data, mf->bmp_size);
b_ptr += align(mf->bmp_size, 2);
}
if (mf->pDLSdata)
{
memcpy(b_ptr, mf->pDLSdata, mf->DLSsize);
b_ptr += align(mf->DLSsize, 2);
}
*siz = sz;
return block;
}
BOOL SaveFile(HWND w, MIDI_file* mf, BOOL info)
{
BOOL rmi_only = info;
string tmp;
if (is_local(mf->path) && _strnicmp(mf->path, "partial://", 10))
{
tmp = mf->path;
if (!info) do_ext(tmp, ".mid");
}
else
{
info = 0;
file2title(mf->path, tmp);
tmp += ".mid";
}
if (mf->format > 1) info = 0; //not MID/RMI
UINT fmt = 0;
BOOL do_gzip = 0;
if (!info)
{
char filter[512] = { 0 };
OPENFILENAMEA ofn = { sizeof(ofn),0 };
ofn.hwndOwner = w;
ofn.lpstrFile = tmp.buffer_get(MAX_PATH + 1);
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrDefExt = "";
ofn.lpstrFilter = filter;
char* pf = filter, * sf = 0;
int len = 0;
#define APPEND(x) {memcpy(pf,x,len);pf+=len;}
if (!rmi_only)
{
sf = BuildFilterString(IDS_MIDI_FILES, "MID", &len);
APPEND(sf);
sf = BuildFilterString(IDS_COMPRESSED_MIDI_FILES, "MIZ", &len);
APPEND(sf);
}
sf = BuildFilterString(IDS_RMI_FILES, "RMI", &len);
APPEND(sf);
sf = BuildFilterString(IDS_COMPRESSED_RMI_FILES, "MIZ", &len);
APPEND(sf);
#undef APPEND
* pf = 0;
if (!GetSaveFileNameA(&ofn)) return 0;
tmp.buffer_done();
fmt = ofn.nFilterIndex - 1;
do_gzip = fmt & 1;
fmt >>= 1;
if (rmi_only) fmt = 1;
if (do_gzip) do_ext(tmp, ".miz");
else if (fmt == 1) do_ext(tmp, ".rmi");
else do_ext(tmp, ".mid");
}
else
{
fmt = 1;
const char* p = strrchr(tmp, '.');
if (p && !_stricmp(p, ".miz")) do_gzip = 1;
}
{
if (fmt > 1) fmt = 0;
BOOL local = 0;
const void* buf = 0;
UINT buf_size = 0;
if (fmt == 0)
{
buf = mf->data;
buf_size = mf->size;
}
else //if (fmt==1)
{
local = 1;
buf = build_rmi(mf, &buf_size);
}
int rv;
if (do_gzip)
{
rv = SaveAsGZip(tmp, buf, buf_size);
}
else
{
HANDLE f = CreateFileA(tmp, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
if (f != INVALID_HANDLE_VALUE)
{
DWORD bw = 0;
WriteFile(f, buf, buf_size, &bw, 0);
CloseHandle(f);
rv = 1;
}
else rv = 0;
}
if (local) free((void*)buf);
if (!_stricmp(mf->path, tmp))
{
mf->format = fmt;
}
if (!rv)
{
char _m[320] = { 0 };
StringCbPrintfA(_m, sizeof(_m), WASABI_API_LNGSTRING(STRING_WRITE_ERROR_FMT), (const char*)tmp);
MessageBoxA(w, _m, ERROR, MB_ICONERROR);
}
return rv;
}
}
/// <summary>
/// Compress given buffer with GZIP format and saves to given filename
/// </summary>
/// <param name="filename"></param>
/// <param name="buffer"></param>
/// <param name="size"></param>
/// <returns></returns>
int SaveAsGZip(string filename, const void* buffer, size_t size)
{
void* data;
size_t data_len = size;
int ret = CompressionUtility::CompressAsGZip(buffer, size, &data, data_len);
if (ret >= 0)
{
try
{
HANDLE f = CreateFileA(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
if (f != INVALID_HANDLE_VALUE)
{
DWORD bw = 0;
WriteFile(f, data, data_len, &bw, 0);
CloseHandle(f);
return 1;
}
}
catch (...)
{
DWORD i = GetLastError();
return 0;
}
}
return 0;
}
#define _pr ((MIDI_file*)(lp))
static cfg_struct_t<RECT> cfg_infpos("infpos", -1);
static UINT inf_x_min = 0x80000000, inf_y_min, inf_c_x, inf_c_y;
static RECT r_trax, r_text;
static void SetWindowRect(HWND w, RECT* r)
{
SetWindowPos(w, 0, r->left, r->top, r->right - r->left, r->bottom - r->top, SWP_NOZORDER);
}
void cGetWindowRect(HWND w, RECT* r)
{
RECT tr, tr1;
GetWindowRect(w, &tr);
SetWindowPos(w, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
GetWindowRect(w, &tr1);
r->left = tr.left - tr1.left;
r->right = tr.right - tr1.left;
r->top = tr.top - tr1.top;
r->bottom = tr.bottom - tr1.top;
SetWindowRect(w, r);
}
#define RB_NUM 3
static struct
{
UINT id, dx, dy;
}
rb_dat[RB_NUM] =
{
{IDC_SAVE, 0, 0},
{IDOK, 0, 0},
{IDC_RMI_CRAP, 0, 0},
};
#define BOTTOM_NUM 8
static struct
{
UINT id;
UINT x, dy;
}
b_dat[BOTTOM_NUM] =
{
{IDC_STATIC1, 0, 0},
{IDC_STATIC2, 0, 0},
{IDC_STATIC3, 0, 0},
{IDC_TIX, 0, 0},
{IDC_MS, 0, 0},
{IDC_FSIZE, 0, 0},
{IDC_DLS, 0, 0},
{IDC_LOOP, 0, 0}
};
static void OnSize(HWND wnd)
{
RECT cl, t;
GetClientRect(wnd, &cl);
t.left = r_text.left;
t.right = r_text.right;
t.top = r_text.top;
t.bottom = cl.bottom - (inf_c_y - r_text.bottom);
SetWindowRect(GetDlgItem(wnd, IDC_COPYRIGHT), &t);
t.left = r_trax.left;
t.right = cl.right - (inf_c_x - r_trax.right);
t.top = r_trax.top;
t.bottom = cl.bottom - (inf_c_y - r_trax.bottom);
SetWindowRect(GetDlgItem(wnd, IDC_TRAX), &t);
UINT n;
for (n = 0; n < BOTTOM_NUM; n++)
{
SetWindowPos(GetDlgItem(wnd, b_dat[n].id), 0, b_dat[n].x, cl.bottom - b_dat[n].dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
}
for (n = 0; n < RB_NUM; n++)
{
SetWindowPos(GetDlgItem(wnd, rb_dat[n].id), 0, cl.right - rb_dat[n].dx, cl.bottom - rb_dat[n].dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
}
}
BOOL WINAPI InfoProc(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_INITDIALOG:
if (inf_x_min == 0x80000000)
{
RECT r;
GetWindowRect(wnd, &r);
inf_x_min = r.right - r.left;
inf_y_min = r.bottom - r.top;
GetClientRect(wnd, &r);
inf_c_x = r.right;
inf_c_y = r.bottom;
cGetWindowRect(GetDlgItem(wnd, IDC_COPYRIGHT), &r_text);
cGetWindowRect(GetDlgItem(wnd, IDC_TRAX), &r_trax);
UINT n;
for (n = 0; n < BOTTOM_NUM; n++)
{
cGetWindowRect(GetDlgItem(wnd, b_dat[n].id), &r);
b_dat[n].x = r.left;
b_dat[n].dy = inf_c_y - r.top;
}
for (n = 0; n < RB_NUM; n++)
{
cGetWindowRect(GetDlgItem(wnd, rb_dat[n].id), &r);
rb_dat[n].dx = inf_c_x - r.left;
rb_dat[n].dy = inf_c_y - r.top;
}
}
if (cfg_infpos.get_val().left != -1)
{
int sx = GetSystemMetrics(SM_CXSCREEN), sy = GetSystemMetrics(SM_CYSCREEN);
if (cfg_infpos.get_val().right > sx)
{
cfg_infpos.get_val().left -= cfg_infpos.get_val().right - sx;
cfg_infpos.get_val().right = sx;
}
if (cfg_infpos.get_val().bottom > sy)
{
cfg_infpos.get_val().top -= cfg_infpos.get_val().bottom - sy;
cfg_infpos.get_val().bottom = sy;
}
if (cfg_infpos.get_val().left < 0)
{
cfg_infpos.get_val().right -= cfg_infpos.get_val().left;
cfg_infpos.get_val().left = 0;
}
if (cfg_infpos.get_val().top < 0)
{
cfg_infpos.get_val().bottom -= cfg_infpos.get_val().top;
cfg_infpos.get_val().top = 0;
}
SetWindowRect(wnd, &cfg_infpos.get_val());
OnSize(wnd);
}
#if defined(_WIN64)
SetWindowLong(wnd, DWLP_USER, lp);
#else
SetWindowLong(wnd, DWL_USER, lp);
#endif
SetDlgItemTextA(wnd, IDC_COPYRIGHT, _pr->info.copyright);
SetDlgItemInt(wnd, IDC_MS, _pr->len, 0);
SetDlgItemInt(wnd, IDC_TIX, _pr->info.tix, 0);
{
char tmp[128] = { 0 };
getfmtstring(_pr, tmp);
SetDlgItemTextA(wnd, IDC_FORMAT, tmp);
HANDLE f = CreateFileA(_pr->path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (f != INVALID_HANDLE_VALUE)
{
StringCbPrintfA(tmp, sizeof(tmp), WASABI_API_LNGSTRING(STRING_BYTES_FMT), GetFileSize(f, 0));
CloseHandle(f);
SetDlgItemTextA(wnd, IDC_FSIZE, tmp);
}
}
{
char tmp[1024] = { 0 };
if (_pr->info.traxnames)
{
HWND lb = GetDlgItem(wnd, IDC_TRAX);
UINT n;
for (n = 0; n < _pr->info.ntrax; n++)
{
StringCbPrintfA(tmp, sizeof(tmp), "(%u) %s", n, (const char*)(_pr->info.traxnames[n]));
SendMessageA(lb, LB_ADDSTRING, 0, (LPARAM)tmp);
}
}
StringCbPrintfA(tmp, sizeof(tmp), WASABI_API_LNGSTRING(STRING_TRACKS_FMT), _pr->info.ntrax);
SetDlgItemTextA(wnd, IDC_NTRAX, tmp);
if (_pr->title)
{
StringCbPrintfA(tmp, sizeof(tmp), WASABI_API_LNGSTRING(STRING_MIDI_INFO_FMT1), (const char*)_pr->title, (const char*)_pr->path);
}
else
{
StringCbPrintfA(tmp, sizeof(tmp), WASABI_API_LNGSTRING(STRING_MIDI_INFO_FMT2), (const char*)_pr->path);
}
if (_pr->flags & FLAG_INCOMPLETE) StringCbCatA(tmp, sizeof(tmp), WASABI_API_LNGSTRING(STRING_INCOMPLETE));
SetWindowTextA(wnd, tmp);
}
if (_pr->pDLSdata) EnableWindow(GetDlgItem(wnd, IDC_DLS), 1);
if (_pr->loopstart) EnableWindow(GetDlgItem(wnd, IDC_LOOP), 1);
//if (_pr->rmi_data) EnableWindow(GetDlgItem(wnd,IDC_RMI_CRAP),1);
return 1;
case WM_SIZE:
OnSize(wnd);
break;
case WM_SIZING:
if (lp)
{
RECT* r = (RECT*)lp;
if ((UINT)(r->right - r->left) < inf_x_min)
{
if (wp != WMSZ_LEFT && wp != WMSZ_TOPLEFT && wp != WMSZ_BOTTOMLEFT)
r->right = r->left + inf_x_min;
else r->left = r->right - inf_x_min;
}
if ((UINT)(r->bottom - r->top) < inf_y_min)
{
if (wp != WMSZ_TOP && wp != WMSZ_TOPLEFT && wp != WMSZ_TOPRIGHT)
r->bottom = r->top + inf_y_min;
else r->top = r->bottom - inf_y_min;
}
}
break;
case WM_COMMAND:
if (wp == IDOK || wp == IDCANCEL)
{
EndDialog(wnd, /*changed ? 0 : 1*/0);
}
else if (wp == IDC_SAVE)
{
#if defined(_WIN64)
SaveFile(wnd, (MIDI_file*)GetWindowLong(wnd, DWLP_USER), 0);
#else
SaveFile(wnd, (MIDI_file*)GetWindowLong(wnd, DWL_USER), 0);
#endif
}
else if (wp == IDC_RMI_CRAP)
{
#if defined(_WIN64)
MIDI_file* mf = (MIDI_file*)GetWindowLong(wnd, DWLP_USER);
#else
MIDI_file* mf = (MIDI_file*)GetWindowLong(wnd, DWL_USER);
#endif
show_rmi_info(wnd, mf);
}
break;
case WM_CLOSE:
EndDialog(wnd, /*changed ? 0 : 1*/0);
break;
case WM_DESTROY:
GetWindowRect(wnd, &cfg_infpos.get_val());
break;
}
return 0;
}
#undef _pr

View File

@ -0,0 +1,612 @@
#include "../Agave/Language/api_language.h"
#include "main.h"
#include <math.h>
#include "resource.h"
#include "../Winamp/in2.h"
#include "../Winamp/wa_ipc.h"
extern In_Module mod;
void get_temp_file(char* fn)
{
static char tmp_path[MAX_PATH];
if (!tmp_path[0]) GetTempPathA(MAX_PATH,tmp_path);
static DWORD num;
if (num==0) num=GetTickCount();
wsprintfA(fn,"%sasdf%x.tmp",tmp_path,num++);
}
void file2title(const char* f,string& t)
{
const char* p1=strrchr(f,'\\'),*p2=strrchr(f,':'),*p3=strrchr(f,'/');
if (p2>p1) p1=p2;
if (p3>p1) p1=p3;
if (p1) p1++;
else p1=(char*)f;
t=p1;
p1=strrchr(t,'.');
if (p1) t.truncate(p1-(const char*)t);
}
static char* exts[]={"MID","MIDI","RMI","KAR","HMP","HMI","XMI","MSS","MUS","CMF","GMD","MIDS","MIZ","HMZ"};
#define N_EXTS tabsize(exts)
static char is_def[N_EXTS]={1,1,1,1,0,0,0,0,0,0,0,0,1,0};
static int get_def_exts()
{
int ret=0;
int n;
for(n=0;n<N_EXTS;n++)
{
if (is_def[n]) ret|=1<<n;
}
return ret;
}
cfg_int cfg_ext_mask("ext_mask",get_def_exts());
static char d_smf[128];
static char d_clo[128];
static char d_cmp[128];
int ext_descs[N_EXTS]={STRING_FILES_SMF,STRING_FILES_SMF,STRING_FILES_SMF,STRING_FILES_SMF,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_COMPRESSED,STRING_FILES_COMPRESSED};
int MIDI_core::FileTypes_GetNum() {return N_EXTS;}
const char * MIDI_core::FileTypes_GetExtension(int n) {return exts[n];}
char * MIDI_core::FileTypes_GetDescription(int n) {
char* s = d_smf;
if(ext_descs[n] == STRING_FILES_SMF) {
if(!d_smf[0]) {
WASABI_API_LNGSTRING_BUF(ext_descs[n],d_smf,128);
}
s = d_smf;
}
else if(ext_descs[n] == STRING_FILES_CLONE) {
if(!d_clo[0]) {
WASABI_API_LNGSTRING_BUF(ext_descs[n],d_clo,128);
}
s = d_clo;
}
else if(ext_descs[n] == STRING_FILES_COMPRESSED) {
if(!d_cmp[0]) {
WASABI_API_LNGSTRING_BUF(ext_descs[n],d_cmp,128);
}
s = d_cmp;
}
return s;
}
static int isourext(const char* ext)
{
UINT n;
for(n=0;n<N_EXTS;n++)
{
if ((cfg_ext_mask&(1<<n)) && !_stricmp(ext,exts[n])) return 1;
}
return 0;
}
int MIDI_core::IsOurFile(const char *fn)
{
const char* p=strrchr(fn,'.');
if (p)
{
if (isourext(p+1)) return 1;
}
return 0;
}
extern UINT volmode_detect();
static BOOL CALLBACK KarProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp);
int MIDI_core::Init()
{
theFile=0;
data_src=0;
plr=0;
eof=0;
mix_dev=0;mix_idx=0;
kwnd=0;
kmap=0;
kmap_size=0;kmap_ptr=0;
kmap_data=0;
format_srate=0;format_nch=0;format_bps=0;
device=MIDI_driver::find_device(cfg_driver,cfg_device);
if (!device) return 0;
use_out=device->has_output() || (cfg_smp && cfg_sampout);
use_smp=cfg_smp && !device->has_output();
if (cfg_volmode>2) volmod=cfg_volmode-1;
else if (cfg_volmode==2) volmod = device->volctrl_happy() ? 1 : volmode_detect()+2;
else volmod=cfg_volmode;
if (volmod>1)
{
UINT idx=volmod-2;
UINT id=0;
UINT n_devz=mixerGetNumDevs();
UINT dev=0;
BOOL found=0;
MIXERLINE ml;
while(dev<n_devz)
{
mixerGetID((HMIXEROBJ)dev,&id,MIXER_OBJECTF_MIXER);
ZeroMemory(&ml,sizeof(ml));
ml.cbStruct=sizeof(ml);
ml.dwComponentType=MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
mixerGetLineInfo((HMIXEROBJ)id,&ml,MIXER_GETLINEINFOF_COMPONENTTYPE|MIXER_OBJECTF_MIXER);
if (idx<ml.cConnections)
{
found=1;
break;
}
idx-=ml.cConnections;
dev++;
}
if (found)
{
mix_dev=id;
mix_idx=idx;
}
else
{
volmod=0;
}
}
return 1;
}
CStream * sampling_create(int srate,int nch,int bps);
cfg_int cfg_lyrics("lyrics",1);
int MIDI_core::OpenFile(MIDI_file * file)
{
#ifdef USE_LOG
log_write("MIDI_core::Open()");
#endif
if (!file) return 0;
format_srate=device->has_freq() ? cfg_freq : 44100;
format_bps=16;
format_nch=2;
theFile=file->AddRef();
#ifdef USE_LOG
log_write("file loaded");
#endif
plr=0;
if (use_smp)
{
#ifdef USE_LOG
log_write("starting sampling");
#endif
format_srate=cfg_wavein_sr;
format_bps=cfg_wavein_bps;
format_nch=cfg_wavein_ch;
data_src=sampling_create(format_srate,format_nch,format_bps);
}
plr=device->create();
if (plr)
{
#ifdef USE_LOG
if (data_src) log_write("got PCM data source");
log_write("playback started");
#endif
if (cfg_lyrics)
{
kmap=kmap_create(theFile,1,&kmap_size,&kmap_data);
if (kmap)
{
kwnd=WASABI_API_CREATEDIALOGPARAMW(IDD_LYRICS,MIDI_callback::GetMainWindow(),KarProc,0);
free(kmap_data); kmap_data=0;//not needed anymore, used only on initdialog to setdlgitemtext
}
}
return 1;
}
else
{
if (data_src) {delete data_src;data_src=0;}
theFile->Free();
theFile=0;
return 0;
}
}
int MIDI_core::GetSamples(void *sample_buffer, int bytes, char *killswitch)
{
#ifdef USE_LOG
log_write("GetSamples");
#endif
if (data_src)
{
return data_src->ReadData(sample_buffer,bytes,(bool*)killswitch);
}
else return 0;
}
void MIDI_core::update_vol()
{
MIXERLINE ml;
ZeroMemory(&ml,sizeof(ml));
ml.cbStruct=sizeof(ml);
ml.dwSource=mix_idx;
mixerGetLineInfo((HMIXEROBJ)mix_dev,&ml,MIXER_GETLINEINFOF_SOURCE|MIXER_OBJECTF_MIXER);
MIXERLINECONTROLS cs;
MIXERCONTROL c;
ZeroMemory(&cs,sizeof(cs));
cs.cbStruct=sizeof(cs);
cs.cControls=1;
cs.dwLineID=ml.dwLineID;
cs.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME;
cs.cbmxctrl=sizeof(c);
cs.pamxctrl=&c;
ZeroMemory(&c,sizeof(c));
c.cbStruct=sizeof(c);
if (!mixerGetLineControls((HMIXEROBJ)mix_dev,&cs,MIXER_OBJECTF_MIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE))
{
DWORD val;
if (cfg_logvol)
{
double _vol=volume>0 ? 20*log10((double)volume/255.0) : -60.0;//in negative db
_vol=_vol/60.0+1;
if (_vol<0) _vol=0;
val=c.Bounds.dwMinimum + (int)( _vol * (double)(c.Bounds.dwMaximum-c.Bounds.dwMinimum) );
}
else val=c.Bounds.dwMinimum + volume * (c.Bounds.dwMaximum-c.Bounds.dwMinimum) / 255;
if (ml.cChannels==1)
{
MIXERCONTROLDETAILS_UNSIGNED ds={val};
MIXERCONTROLDETAILS d;
d.cbStruct=sizeof(d);
d.dwControlID=c.dwControlID;
d.cChannels=1;
d.cMultipleItems=0;
d.cbDetails=sizeof(ds);
d.paDetails=&ds;
mixerSetControlDetails((HMIXEROBJ)mix_dev,&d,MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_MIXER);
}
else if (ml.cChannels<16)
{
MIXERCONTROLDETAILS_UNSIGNED ds[16];
UINT n;
for(n=0;n<16;n++) ds[n].dwValue=val;
if (pan<0)
{
ds[1].dwValue=ds[1].dwValue*(128+pan)>>7;
}
else
{
ds[0].dwValue=ds[0].dwValue*(128-pan)>>7;
}
MIXERCONTROLDETAILS d;
d.cbStruct=sizeof(d);
d.dwControlID=c.dwControlID;
d.cChannels=ml.cChannels;
d.cMultipleItems=0;
d.cbDetails=sizeof(ds[0]);
d.paDetails=&ds;
mixerSetControlDetails((HMIXEROBJ)mix_dev,&d,MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_MIXER);
}
}
/*
ZeroMemory(&cs,sizeof(cs));
cs.cbStruct=sizeof(cs);
cs.cControls=1;
cs.dwLineID=ml.dwLineID;
cs.dwControlType=MIXERCONTROL_CONTROLTYPE_PAN;
cs.cbmxctrl=sizeof(c);
cs.pamxctrl=&c;
ZeroMemory(&c,sizeof(c));
c.cbStruct=sizeof(c);
if (!mixerGetLineControls((HMIXEROBJ)mix_dev,&cs,MIXER_OBJECTF_MIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE))
{
MIXERCONTROLDETAILS_SIGNED ds={c.Bounds.lMinimum + (pan+128) * (c.Bounds.lMaximum-c.Bounds.lMinimum) / 255};
MIXERCONTROLDETAILS d;
d.cbStruct=sizeof(d);
d.dwControlID=c.dwControlID;
d.cbDetails=sizeof(ds);
d.cChannels=ml.cChannels;
d.cMultipleItems=c.cMultipleItems;
d.paDetails=&ds;
mixerSetControlDetails((HMIXEROBJ)mix_dev,&d,MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_MIXER);
}*/
}
int MIDI_core::SetVolume(int _volume)
{
volume=_volume;
if (volmod==0) return 0;
else
{
if (volmod==1)
{
if ((use_out && !use_smp) || !plr)
{
return 0;
}
else
{
return plr->setvol(player_getVol());
}
}
update_vol();
return 1;
}
}
int MIDI_core::SetPan(int _pan)
{
pan=_pan;
if (volmod==0) return 0;
else
{
if (volmod==1)
{
if (plr) return plr->setpan(player_getPan());
else return 0;
}
else
{
update_vol();
return 1;
}
}
}
int MIDI_core::SetPosition(int pos)
{
if (!plr) return 0;
if (!plr->settime(pos)) return 0;
sync.enter();
kmap_ptr=0;
LeaveCriticalSection(&sync);
if (data_src) data_src->Flush();
return 1;
}
void MIDI_core::Pause(int pause)
{
if (plr)
{
if (pause) plr->pause();
else plr->unpause();
}
if (data_src) data_src->Pause(pause);
}
int MIDI_core::GetPosition(void)
{
int i=0;
if (plr)
{
i=plr->gettime();
if (i<0) i=0;
}
return i;
}
int MIDI_core::GetLength(void)
{
if (theFile) return theFile->len;
else return -1;
}
void MIDI_core::Close()
{
#ifdef USE_LOG
log_write("shutting down MIDI_core");
#endif
if (plr) {delete plr;plr=0;}
if (data_src) {delete data_src;data_src=0;}
if (kwnd) {DestroyWindow(kwnd);kwnd=0;}
if (kmap) {free(kmap);kmap=0;}
if (theFile) {theFile->Free();theFile=0;}
}
void MIDI_core::Eof()
{
eof=1;
if (data_src)
data_src->Eof();
else
MIDI_callback::NotifyEOF();
}
static char INI_FILE[MAX_PATH];
void MIDI_core::GlobalInit()
{
#ifdef USE_LOG
log_start();
log_write("initializing");
log_write(NAME);
#endif
char *p;
if (mod.hMainWindow &&
(p = (char *)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILE))
&& p!= (char *)1)
{
strcpy(INI_FILE, p);
}
else
{
GetModuleFileNameA(NULL,INI_FILE,sizeof(INI_FILE));
p = INI_FILE + strlen(INI_FILE);
while (p >= INI_FILE && *p != '.') p--;
strcpy(++p,"ini");
}
cfg_var::config_read(INI_FILE,"in_midi");
}
void MIDI_core::GlobalQuit()
{
MIDI_driver::shutdown();
log_quit();
}
void MIDI_core::WriteConfig()
{
cfg_var::config_write(INI_FILE,"in_midi");
}
void MIDI_core::MM_error(DWORD code)
{
string temp;
if (!mciGetErrorStringA(code,string_buffer_a(temp,256),256))
{
temp=WASABI_API_LNGSTRING(STRING_UNKNOWN_MMSYSTEM);
}
MIDI_callback::Error(temp);
}
static void fix_size(HWND wnd)
{
RECT r;
GetClientRect(wnd,&r);
SetWindowPos(GetDlgItem(wnd,IDC_BLAH),0,0,0,r.right,r.bottom,SWP_NOZORDER|SWP_NOACTIVATE);
}
static cfg_struct_t<RECT> cfg_lyrics_pos("lyrics_pos",-1);
static void SetWindowRect(HWND w,RECT* r)
{
SetWindowPos(w,0,r->left,r->top,r->right-r->left,r->bottom-r->top,SWP_NOZORDER);
}
static cfg_int cfg_lyrics_min("lyrics_min",0),cfg_lyrics_max("lyrics_max",0);
BOOL CALLBACK MIDI_core::KarProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
{
switch(msg)
{
case WM_INITDIALOG:
SetDlgItemTextA(wnd,IDC_BLAH,MIDI_core::kmap_data);
if (cfg_lyrics_pos.get_val().left!=-1)
{
int sx=GetSystemMetrics(SM_CXSCREEN),sy=GetSystemMetrics(SM_CYSCREEN);
if (cfg_lyrics_pos.get_val().right>sx)
{
cfg_lyrics_pos.get_val().left-=cfg_lyrics_pos.get_val().right-sx;
cfg_lyrics_pos.get_val().right=sx;
}
if (cfg_lyrics_pos.get_val().bottom>sy)
{
cfg_lyrics_pos.get_val().top-=cfg_lyrics_pos.get_val().bottom-sy;
cfg_lyrics_pos.get_val().bottom=sy;
}
if (cfg_lyrics_pos.get_val().left<0)
{
cfg_lyrics_pos.get_val().right-=cfg_lyrics_pos.get_val().left;
cfg_lyrics_pos.get_val().left=0;
}
if (cfg_lyrics_pos.get_val().top<0)
{
cfg_lyrics_pos.get_val().bottom-=cfg_lyrics_pos.get_val().top;
cfg_lyrics_pos.get_val().top=0;
}
SetWindowRect(wnd,&cfg_lyrics_pos.get_val());
}
if (cfg_lyrics_min)
{
ShowWindow(wnd,SW_MINIMIZE);
}
else if (cfg_lyrics_max)
{
ShowWindow(wnd,SW_MAXIMIZE);
}
fix_size(wnd);
SetTimer(wnd,1,100,0);
return 1;
case WM_TIMER:
{
sync.enter();
UINT time=GetPosition();
KAR_ENTRY * set=0;
UINT ptr=kmap_ptr;
while(ptr<kmap_size && kmap[ptr].time<time)
{
if (!kmap[ptr].foo) set=&kmap[ptr];
ptr++;
}
kmap_ptr=ptr;
sync.leave();
if (set)
{
SendDlgItemMessage(wnd,IDC_BLAH,EM_SETSEL,set->start,set->end);
}
}
break;
case WM_DESTROY:
KillTimer(wnd,1);
kwnd=0;
GetWindowRect(wnd,&cfg_lyrics_pos.get_val());
cfg_lyrics_max=!!IsZoomed(wnd);
cfg_lyrics_min=!!IsIconic(wnd);
break;
case WM_CLOSE:
cfg_lyrics=0;
if (!((int)cfg_bugged & BUGGED_BLAH))
{
char title[32] = {0};
cfg_bugged = (int)cfg_bugged | BUGGED_BLAH;
MessageBoxA(wnd,WASABI_API_LNGSTRING(IDS_TO_ENABLE_LYRICS_DISPLAY),
WASABI_API_LNGSTRING_BUF(IDS_INFORMATION,title,32),MB_ICONINFORMATION);
}
DestroyWindow(wnd);
break;
case WM_SIZE:
fix_size(wnd);
break;
}
return 0;
}
//MIDI_core static crap
bool MIDI_core::use_out;
MIDI_file* MIDI_core::theFile;
CStream* MIDI_core::data_src;
player_base* MIDI_core::plr;
int MIDI_core::format_srate,MIDI_core::format_nch,MIDI_core::format_bps;
int MIDI_core::volume=255,MIDI_core::pan=0;
bool MIDI_core::eof;
UINT MIDI_core::volmod;
UINT MIDI_core::mix_dev,MIDI_core::mix_idx;
MIDI_device * MIDI_core::device;
bool MIDI_core::use_smp;
HWND MIDI_core::kwnd;
KAR_ENTRY* MIDI_core::kmap;
UINT MIDI_core::kmap_size,MIDI_core::kmap_ptr;
char * MIDI_core::kmap_data;
critical_section MIDI_core::sync;

View File

@ -0,0 +1,230 @@
#ifndef STRICT
#define STRICT
#endif
#include "../Agave/Language/api_language.h"
#include <windows.h>
#include <malloc.h>
#ifndef NOVTABLE
#define NOVTABLE _declspec(novtable)
#endif
#include <mmsystem.h>
#include "core_api.h"
#include "../pfc/string_unicode.h"
#include "locale.h"
#define VER L"3.57"
#include "utils.h"
//#define USE_LOG
#ifdef USE_LOG
void log_write(char*);
void log_start();
void log_quit();
#else
#define log_write(X)
#define log_start()
#define log_quit()
#endif
class CStream;
struct CTempoMap;
struct CSysexMap;
class player_base;
class NOVTABLE MIDI_device
{
friend class MIDI_driver;
private:
MIDI_device * next;
MIDI_driver * driver;
string_w dev_name,dev_info;
protected:
void set_name(const wchar_t * src) {dev_name=src;}
void set_info(const wchar_t * src) {dev_info=src;}
public:
//override me
virtual player_base * create()=0;
virtual GUID get_guid()=0;
virtual ~MIDI_device() {};
virtual bool is_default() {return 0;}
virtual bool has_output() {return 0;}
virtual bool has_dls() {return 0;}
virtual bool has_freq() {return 0;}
virtual bool volctrl_happy() {return 0;}
const wchar_t * get_name() {return dev_name;}
const wchar_t * get_info() {return dev_info;}
MIDI_driver * get_driver() {return driver;}
};
class NOVTABLE MIDI_driver//ONLY for static objects !!!!!
{
private:
static MIDI_driver * driver_list;
MIDI_driver * next;
MIDI_device * device_list;
bool inited;
void init() {if (!inited) {do_init();inited=1;};}
void deinit() {if (inited) {do_deinit();reset_devices();inited=0;};}
protected:
MIDI_driver();
~MIDI_driver();
void reset_devices();
void add_device(MIDI_device * dev);//call this to add new device
//override me
virtual void do_init() {};
virtual void do_deinit() {}
public:
static MIDI_driver * driver_enumerate(int n);
static int driver_count();
MIDI_device * device_enumerate(int n);
int device_count();
static MIDI_device * find_device(GUID guid_driver,GUID guid_device);
static MIDI_driver * find_driver(GUID guid_driver);
static MIDI_device * find_device_default();
static void shutdown();
//override me
virtual const wchar_t * get_name()=0;
virtual GUID get_guid()=0;
virtual bool is_default() {return 0;}
};
#include "midifile.h"
class NOVTABLE player_base
{
public:
virtual ~player_base() {}
virtual int gettime()=0;
virtual int settime(int)=0;
virtual void pause()=0;
virtual void unpause()=0;
virtual int setvol(int) {return 0;};
virtual int setpan(int) {return 0;};
};
class MIDI_core
{
public:
static int Init();
static int UsesOutput() {return use_out;}
static int OpenFile(MIDI_file * file);
static void Close();
static int GetSamples(void *sample_buffer, int bytes, char *killswitch);
static void GetPCM(int * srate,int * nch,int * bps) {*srate=format_srate;*nch=format_nch;*bps=format_bps;}
static int SetPosition(int);
static void Pause(int pause);
static int GetPosition(void);
static int GetLength(void);
static void Eof();
static int SetVolume(int volume);
static int SetPan(int pan);
//setvolune/setpan safe to call at any moment
static int player_getVol() {return volume;}
static int player_getPan() {return pan;}
static inline void player_setSource(CStream *s) {data_src=s;}
static void MM_error(DWORD code);
static inline MIDI_file * getFile() {return theFile;}
static inline MIDI_device * getDevice() {return device;}
static inline bool HavePCM() {return !!data_src;}
static inline bool HavePlayer() {return !!plr;}
static int IsOurFile(const char *fn);
static void GlobalInit();
static void GlobalQuit();
static int Config(HWND wnd);
static void WriteConfig();
static int FileTypes_GetNum();
static const char * FileTypes_GetExtension(int);
static char * FileTypes_GetDescription(int);
private:
static BOOL CALLBACK KarProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp);
static void update_vol();
static bool use_out,use_smp;
static MIDI_file* theFile;
static CStream* data_src;
static player_base* plr;
static int format_srate,format_nch,format_bps;
static int volume,pan;
static bool eof;
static UINT volmod;
static UINT mix_dev,mix_idx;
static HWND kwnd;
static KAR_ENTRY *kmap;
static UINT kmap_size,kmap_ptr;
static char * kmap_data;
static critical_section sync;
static MIDI_device * device;
};
namespace MIDI_callback //per-winamp implementations
{
HWND GetMainWindow();
HINSTANCE GetInstance();
void NotifyEOF();
void Error(const char *);
void Idle(int ms=0);
};
//#pragma warning(disable:4800)
void get_temp_file(char* fn);
extern cfg_int cfg_hardware_reset;
extern cfg_int cfg_smp,cfg_reverb,cfg_chorus,cfg_nosysex;
extern cfg_int cfg_sampout,cfg_dm_imm;
extern cfg_int cfg_loop_type,cfg_loop_count,cfg_loop_infinite;
extern cfg_int cfg_wavein_dev,cfg_wavein_sr,cfg_wavein_ch,cfg_wavein_bps,cfg_wavein_src;
extern cfg_int cfg_ctrl_x,cfg_ctrl_y;
extern cfg_int cfg_ext_mask;
extern cfg_string cfg_extra_exts;
extern cfg_int cfg_volmode;
extern cfg_int cfg_recover_tracks;
extern cfg_int cfg_quick_seek;
extern cfg_int cfg_rmi_def;
extern cfg_int cfg_logvol;
extern cfg_struct_t<GUID> cfg_driver,cfg_device;
extern cfg_int cfg_playback_mode;
extern cfg_int cfg_eof_delay;
extern cfg_int cfg_bugged;
extern cfg_int cfg_freq;
extern cfg_int cfg_cur_tab;
enum{BUGGED_BLAH=0x10};
extern sysex_table cfg_sysex_table;
void ReleaseObject(IUnknown* o);
#include "in2.h"
extern In_Module mod;

View File

@ -0,0 +1,121 @@
#include "main.h"
MIDI_driver * MIDI_driver::driver_list=0;
MIDI_driver::MIDI_driver()
{
next=driver_list;
driver_list=this;
inited=0;
device_list=0;
}
void MIDI_driver::reset_devices()
{
while(device_list)
{
MIDI_device * ptr = device_list->next;
delete device_list;
device_list = ptr;
}
}
MIDI_driver::~MIDI_driver()
{
reset_devices();
}
void MIDI_driver::add_device(MIDI_device * dev)
{
MIDI_device **ptr = &device_list;
while(ptr && *ptr) ptr = &(*ptr)->next;
*ptr=dev;
dev->next=0;
dev->driver=this;
}
MIDI_driver * MIDI_driver::driver_enumerate(int n)
{
MIDI_driver * ptr = driver_list;
while(ptr && n>0) {ptr=ptr->next;n--;}
return ptr;
}
int MIDI_driver::driver_count()
{
int n=0;
MIDI_driver * ptr = driver_list;
while(ptr) {ptr=ptr->next;n++;}
return n;
}
MIDI_device * MIDI_driver::device_enumerate(int n)
{
init();
MIDI_device * ptr = device_list;
while(ptr && n>0) {ptr=ptr->next;n--;}
return ptr;
}
int MIDI_driver::device_count()
{
init();
int n=0;
MIDI_device * ptr = device_list;
while(ptr) {ptr=ptr->next;n++;}
return n;
}
MIDI_device * MIDI_driver::find_device(GUID guid_driver,GUID guid_device)
{
MIDI_driver * driver_ptr = find_driver(guid_driver);
if (!driver_ptr) return 0;
MIDI_device * device_ptr;
int idx=0;
while(device_ptr = driver_ptr->device_enumerate(idx++))
{
if (device_ptr->get_guid()==guid_device) return device_ptr;
}
return 0;
}
MIDI_driver * MIDI_driver::find_driver(GUID guid_driver)
{
MIDI_driver * driver_ptr = driver_list;
while(driver_ptr)
{
if (driver_ptr->get_guid()==guid_driver) break;
driver_ptr = driver_ptr->next;
}
return driver_ptr;
}
MIDI_device * MIDI_driver::find_device_default()
{
MIDI_driver * driver_ptr = driver_list;
while(driver_ptr)
{
if (driver_ptr->is_default())
{
MIDI_device * device_ptr;
int idx=0;
while(device_ptr = driver_ptr->device_enumerate(idx++))
{
if (device_ptr->is_default()) return device_ptr;
}
}
driver_ptr = driver_ptr->next;
}
return 0;
}
void MIDI_driver::shutdown()
{
MIDI_driver * driver_ptr = driver_list;
while(driver_ptr)
{
driver_ptr->deinit();
driver_ptr = driver_ptr->next;
}
}

View File

@ -0,0 +1,603 @@
#include "main.h"
#include <intsafe.h>
//#define HUNT_LEAKS
#ifdef MF_USE_DMCRAP
extern IDirectMusicCollection *pCDLS;
#endif
#ifdef HUNT_LEAKS
static UINT n_files;
#endif
MIDI_file::MIDI_file(const char * fn) : path(fn)
{
flags=0;
format=0;
len=0;tix=0;
size=0;
data=0;
#ifdef MF_USE_DMCRAP
pSeg=0;
pDLS=0;
pDLSdata=0;
DLSsize=0;
#endif
info.fmt=info.ntrax=info.tix=0;
info.channels=0;
info.e_type=0;
loopstart=0;loopend=0;
loopstart_t=0;
rmi_data=0;
rmi_size=0;
bmp_data=0;
bmp_size=0;
kar_track=0;
tmap=0;
smap=0;
#ifdef HUNT_LEAKS
n_files++;
#endif
refcount=1;
info.traxnames=0;
}
#ifdef MF_USE_DMCRAP
extern IDirectMusicCollection *pCDLS;
extern IDirectMusicLoader* pLoader;
#endif
static bool is_gmd(const BYTE* b,size_t s)
{
return s>12 && *(DWORD*)b==_rv('MIDI') && *(DWORD*)(b+8)==_rv('MDpg');
}
static bool is_hmi(const BYTE* b,size_t s)
{
return s>12 && *(DWORD*)b==_rv('HMI-') && *(DWORD*)(b+4)==_rv('MIDI') && *(DWORD*)(b+8)==_rv('SONG');
}
static bool is_hmp(const BYTE* b,size_t s)
{
if (s>8 && ((DWORD*)b)[0]==_rv('HMIM') && (((DWORD*)b)[1]==_rv('IDIP') || ((DWORD*)b)[1]==_rv('IDIR')) )
{
//DWORD d=*(DWORD*)(b+0x30);
//return (d<0x40 && d);
return 1;
}
else return 0;
}
static bool is_xmidi(const BYTE* b,size_t s)
{
return s>0x20 && *(DWORD*)b==_rv('FORM') && *(DWORD*)(b+8)==_rv('XDIR') && *(DWORD*)(b+0x1e)==_rv('XMID');
}
static bool is_rmi(const BYTE* b,size_t s)
{
return s>20+8+6+8 && *(DWORD*)b==_rv('RIFF') && *(DWORD*)(b+8)==_rv('RMID') && *(DWORD*)(b+12)==_rv('data');
}
static bool is_midi(const BYTE* b,size_t s)
{
return s>8+6+8 && *(DWORD*)b==_rv('MThd') && *(DWORD*)(b+4)==0x06000000 && *(DWORD*)(b+14)==_rv('MTrk');
}
static bool is_midi_scan(const BYTE* b,size_t s)
{
int x,m=s;
if (m>256) m=256;
m-=8+6+8;
for(x=0;x<m;x++)
if (is_midi(b+x,s-x)) return 1;
return 0;
}
#define REM (unsigned int)(sz-ptr)
static bool load_midi_fix(MIDI_file* mf,const BYTE* buf,size_t sz,int n_track,size_t p_ofs)
{
if (!cfg_recover_tracks)
return 0;
size_t malloc_sz;
if (SizeTAdd(sz, 0x10, &malloc_sz) != S_OK)
return false;
BYTE* outbuf=(BYTE*)malloc(malloc_sz);
if (!outbuf) return 0;
size_t ptr=p_ofs;
size_t bp=ptr;
BYTE lc=0;
while(1)
{
bp=ptr;
if (REM<4) break;
while(buf[ptr]&0x80)
{
if (ptr==bp+4) break;
ptr++;
}
ptr++;
if (REM<3) break;
BYTE b=buf[ptr];
if (b==0xFF)
{
ptr+=2;
if (REM<4) break;
unsigned int d;
unsigned int l=DecodeDelta(buf+ptr,&d, sz-ptr);
if (l+d>REM) break;
ptr+=l+d;
}
else if (b==0xF0)
{
ptr++;
if (REM<4) break;
unsigned int d;
unsigned int l=DecodeDelta(buf+ptr,&d, sz-ptr);
if (l+d>REM) break;
ptr+=l+d;
}
else
{
if (b&0x80)
{
lc=b&0xF0;
if (lc==0xF0) break;
ptr++;
}
else if (!lc) break;
if (lc==0xC0 || lc==0xD0) ptr++;
else ptr+=2;
}
}
memcpy(outbuf,buf,ptr);
ptr=bp;
outbuf[ptr++]=0;
outbuf[ptr++]=0xFF;
outbuf[ptr++]=0x2F;
outbuf[ptr++]=0;
*(DWORD*)(outbuf+p_ofs-4)=rev32(ptr-p_ofs);
mf->data=outbuf;
mf->size=ptr;
return 1;
}
#undef REM
static bool load_midi(MIDI_file* mf,const BYTE* buf,size_t sz)
{
int trax=rev16(*(WORD*)(buf+4+4+2));
size_t ofs=6+8;
int n;
for(n=0;n<trax;n++)
{
if (ofs>(sz-12) || *(DWORD*)(buf+ofs)!=_rv('MTrk'))
{
mf->flags|=FLAG_INCOMPLETE;
*(WORD*)(buf+4+4+2)=rev16(n);
sz=ofs;
break;
}
if (SizeTAdd(ofs, 8, &ofs) != S_OK)
return false;
size_t p_ofs=ofs;
DWORD next = rev32(*(DWORD*)(buf+ofs-4));
if (SizeTAdd(ofs, next, &ofs) != S_OK)
return false;
if (ofs>sz)
{
mf->flags|=FLAG_INCOMPLETE;
*(WORD*)(buf+4+4+2)=rev16(n+1);
if (!load_midi_fix(mf,buf,sz,n,p_ofs))
{
*(WORD*)(buf+4+4+2)=rev16(n);
sz=p_ofs-8;
break;
}
else return 1;
}
}
BYTE * out = (BYTE*)malloc(sz);
if (!out)
return 0;
memcpy(out,buf,sz);
mf->data=out;
mf->size=sz;
return 1;
}
static bool load_gmd(MIDI_file* mf,const BYTE* buf,size_t sz)
{
if (sz<=0x10) return 0;
DWORD s=rev32(*(DWORD*)(buf+4));
if ((sz-8)<s) return 0;
DWORD ofs=rev32(*(DWORD*)(buf+12))+0x10;
s-=ofs;
BYTE * out=(BYTE*)malloc(s);
if (!out) return 0;
mf->size=s;
memcpy(out,buf+ofs,s);
mf->data=out;
return 1;
}
#ifdef MF_USE_DMCRAP
void ReleaseObject(IUnknown* o);
#endif
static bool load_rmi(MIDI_file* mf,const BYTE* source,size_t source_size)
{
if (source_size < 8)
return 0;
unsigned int sx=*(DWORD*)(source+4);
size_t _p=0;
BYTE * out;
if (sx>source_size-8) goto _er;
mf->size=*(DWORD*)(source+16);
if (mf->size+20>source_size) goto _er;
out=(BYTE*)malloc(mf->size);
if (!out) goto _er;
memcpy(out,source+20,mf->size);
mf->data = out;
_p=20+mf->size;
if (_p&1) _p++;
while(_p<source_size)
{
if (! mf->bmp_data && *(DWORD*)(source+_p)==_rv('DISP') && *(DWORD*)(source+_p+8)==8)//bitmap
{
DWORD s=*(DWORD*)(source+_p+4)-4;
void * r=malloc(s);
if (r)
{
memcpy(r,source+_p+12,s);
mf->bmp_size=s;
mf->bmp_data=r;
}
}
else if (! mf->title && *(DWORD*)(source+_p)==_rv('DISP') && *(DWORD*)(source+_p+8)==1)
{
DWORD s=*(DWORD*)(source+_p+4)-4;
char * src=(char*)(source+_p+12); //remove eol's
char * dst=mf->title.buffer_get(s+1);
char * src_b=src;
while(src && *src && (UINT)(src-src_b)<s)
{
if (*src!=10 && *src!=13) *(dst++)=*src;
src++;
}
*dst=0;
mf->title.buffer_done();
}
else if (! mf->rmi_data && *(DWORD*)(source+_p)==_rv('LIST') && *(DWORD*)(source+_p+8)==_rv('INFO'))
{
DWORD s=*(DWORD*)(source+_p+4);
void * r=malloc(s);
if (r)
{
memcpy(r,source+_p+8,s);
mf->rmi_size=s;
mf->rmi_data=r;
}
}
#ifdef MF_USE_DMCRAP
else if (!mf->pDLSdata && *(DWORD*)(source+_p)==_rv('RIFF') && *(DWORD*)(source+_p+8)==_rv('DLS '))
{
int rs=*(long*)(source+_p+4)+8;
if (rs+_p>source_size) break;
mf->DLSsize=rs;
mf->pDLSdata=(BYTE*)malloc(rs);
memcpy(mf->pDLSdata,source+_p,rs);
}
#endif
_p+=*(DWORD*)(source+_p+4)+8;
if (_p&1) _p++;
}
return 1;
_er:
return 0;
}
bool load_xmi(MIDI_file* mf,const BYTE*,size_t);
bool load_hmp(MIDI_file* mf,const BYTE*,size_t);
bool load_hmi(MIDI_file* mf,const BYTE*,size_t);
bool load_mus(MIDI_file* mf,const BYTE*,size_t);
bool load_cmf(MIDI_file* mf,const BYTE*,size_t);
bool load_mids(MIDI_file* mf,const BYTE*,size_t);
bool load_gmf(MIDI_file* mf,const BYTE*,size_t);
bool is_mus(const BYTE*,size_t);
bool is_cmf(const BYTE*,size_t);
bool is_mids(const BYTE*,size_t);
bool is_gmf(const BYTE*,size_t);
static bool load_midi_scan(MIDI_file* mf,const BYTE* ptr,size_t size)
{
int max = size-3;
if (max>256) max=256;
int x;
for(x=0;x<256;x++)
{
if (*(DWORD*)(ptr+x)==_rv('MThd') && *(DWORD*)(ptr+x+4)==_rv(6))
{
size-=x;
ptr+=x;
void * buf=malloc(size);
if (!buf) return 0;
memcpy(buf,ptr,size);
bool r=load_midi(mf,(BYTE*)buf,size);
if (!r) free(buf);
return r;
}
}
return 0;
}
struct
{
bool ( * test ) (const BYTE* b,size_t s);
bool ( * load ) (MIDI_file* mf,const BYTE* ptr,size_t size);
} format_list[] =
{
{is_midi,load_midi},
{is_rmi,load_rmi},
{is_hmp,load_hmp},
{is_hmi,load_hmi},
{is_xmidi,load_xmi},
{is_mus,load_mus},
{is_cmf,load_cmf},
{is_gmd,load_gmd},
{is_mids,load_mids},
{is_gmf,load_gmf},
{is_midi_scan,load_midi_scan}
};
//static fmtfunc fmts[]={is_midi,is_rmi,is_hmp,is_hmi,is_xmidi,is_mus,is_cmf,is_gmd,is_mids,is_gmf,is_midi_scan};
//loadfunc loaders[]={load_midi,load_rmi,load_hmp,load_hmi,load_xmi,load_mus,load_cmf,load_gmd,load_mids,load_gmf,load_midi_scan};
#ifdef MF_USE_DMCRAP
void LoadDLS(MIDI_file* mf)
{
if (mf->pDLSdata && ! mf->pDLS)
{
DMUS_OBJECTDESC ObjDesc;
ZeroMemory(&ObjDesc,sizeof(ObjDesc));
ObjDesc.dwSize = sizeof(DMUS_OBJECTDESC);
ObjDesc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_MEMORY;
ObjDesc.llMemLength = mf->DLSsize;
ObjDesc.pbMemData = mf->pDLSdata;
ObjDesc.guidClass = CLSID_DirectMusicCollection;
pLoader->GetObject(&ObjDesc,IID_IDirectMusicCollection,(void**)&mf->pDLS);
if (mf->pDLS)
{
ReleaseObject(mf->pDLS);
}
}
}
void _LoadSegment(MIDI_file* mf)
{
#ifdef USE_LOG
log_write("_LoadSegment()");
#endif
mf->pSeg=0;
int data_size=0;
void * data_ptr=0;
if (
!DoCleanUp(mf,CLEAN_DM|CLEAN_DLS|(cfg_nosysex ? CLEAN_NOSYSEX : 0),&data_ptr,&data_size)
)
return;
IDirectMusicSegment* pSeg=0;
DMUS_OBJECTDESC ObjDesc;
ZeroMemory(&ObjDesc,sizeof(ObjDesc));
ObjDesc.dwSize=sizeof(ObjDesc);
ObjDesc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_MEMORY;
ObjDesc.llMemLength = data_size;
ObjDesc.pbMemData = (BYTE*)data_ptr;
ObjDesc.guidClass=CLSID_DirectMusicSegment;
#ifdef USE_LOG
log_write("pLoader->EnableCache(GUID_DirectMusicAllTypes,1);");
#endif
pLoader->EnableCache(GUID_DirectMusicAllTypes,1);
// pLoader->ClearCache(CLSID_DirectMusicSegment); //%$%&%@! this->sucks = TRUE
#ifdef USE_LOG
log_write("pLoader->GetObject(&ObjDesc,IID_IDirectMusicSegment,(void**)&pSeg);");
#endif
pLoader->GetObject(&ObjDesc,IID_IDirectMusicSegment,(void**)&pSeg);
if (!pSeg)
{
#ifdef USE_LOG
log_write("attempting memdump");
#endif
char tmpf[MAX_PATH] = {0};
get_temp_file(tmpf);
HANDLE f=CreateFileA(tmpf,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,0);
if (f!=INVALID_HANDLE_VALUE)
{
DWORD bw = 0;
WriteFile(f,data_ptr,data_size,&bw,0);
CloseHandle(f);
mbstowcs(ObjDesc.wszFileName,tmpf,MAX_PATH);
ObjDesc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FULLPATH | DMUS_OBJ_FILENAME;
pLoader->GetObject(&ObjDesc,IID_IDirectMusicSegment,(void**)&pSeg);
DeleteFileA(tmpf);
}
}
if (pSeg)
{
#ifdef USE_LOG
log_write("got IDirectMusicSegment");
log_write("pSeg->SetParam(GUID_StandardMIDIFile,-1,0,0,0);");
#endif
pSeg->SetParam(GUID_StandardMIDIFile,-1,0,0,0);
#ifdef USE_LOG
log_write("pSeg->SetStartPoint(0);");
#endif
pSeg->SetStartPoint(0);
#ifdef USE_LOG
log_write("pSeg->SetLength();");
#endif
{
bool ok=0;
if (cfg_eof_delay)
{
MUSIC_TIME mnt;
DMUS_TEMPO_PARAM tp;
if (SUCCEEDED(pSeg->GetParam(GUID_TempoParam,-1,0,mf->tix,&mnt,&tp)))
{
pSeg->SetLength((MUSIC_TIME)(mf->tix+(double)cfg_eof_delay*78.0/tp.dblTempo));
ok=1;
}
}
if (!ok) pSeg->SetLength(mf->tix);
}
mf->pSeg=pSeg;
LoadDLS(mf);
if (pCDLS) pSeg->SetParam(GUID_ConnectToDLSCollection,0xFFFFFFFF,0,0,(void*)pCDLS);
if (mf->pDLS) pSeg->SetParam(GUID_ConnectToDLSCollection,0xFFFFFFFF,0,0,(void*)mf->pDLS);
if (mf->loopstart)
{
pSeg->SetLoopPoints(mf->loopstart,mf->loopend);
}
}
free(data_ptr);
pLoader->EnableCache(GUID_DirectMusicAllTypes,0);
}
IDirectMusicSegment* LoadSegment(MIDI_file* mf)
{
#ifdef USE_LOG
log_write("LoadSegment()");
#endif
if (!pLoader) return 0;
IDirectMusicSegment* pSeg=0;
if (!mf->pSeg) _LoadSegment(mf);
if (mf->pSeg)
{
#ifdef USE_LOG
log_write("LoadSegment() : got IDirectMusicSegment");
#endif
pSeg=mf->pSeg;
#ifdef USE_LOG
log_write("pSeg->AddRef()");
#endif
pSeg->AddRef();
#ifdef USE_LOG
log_write("pSeg->AddRef() returned");
#endif
}
#ifdef USE_LOG
log_write("LoadSegment() returning");
#endif
return pSeg;
}
#endif
MIDI_file::~MIDI_file()
{
#ifdef MF_USE_DMCRAP
if (pSeg) pSeg->Release();
if (pDLS) pDLS->Release();
if (pDLSdata) free(pDLSdata);
#endif
if (data) free((BYTE*)data);
if (tmap) delete tmap;
if (smap) delete smap;
if (info.traxnames) delete[] info.traxnames;
if (rmi_data) free(rmi_data);
if (bmp_data) free(bmp_data);
#ifdef HUNT_LEAKS
n_files--;
#endif
}
bool GetMidiInfo(MIDI_file*);
static bool try_format(const void * data,int size,int idx)
{
bool rv;
try {
rv = format_list[idx].test((const BYTE*)data,size);
} catch(...)
{
rv = 0;
}
return rv;
}
int MIDI_file::HeaderTest(const void * data,int size)
{
int n;
for(n=0;n<tabsize(format_list);n++)
{
if (try_format(data,size,n)) return 1;
}
return 0;
}
int MIDI_file::Load(const void * data,int size)
{
#ifdef USE_LOG
log_write("Load()");
#endif
{
int n;
int fmt=-1;
for(n=0;n<tabsize(format_list);n++)
{
if (try_format(data,size,n)) {fmt=n;break;}
}
if (fmt==-1) return 0;
format = fmt;
}
{
bool r;
try {
r=format_list[format].load(this,(const BYTE*)data,size);
} catch(...) {
#ifdef USE_LOG
log_write("midi loader crashed");
#endif
r=0;
}
if (!r) return 0;
}
return GetMidiInfo(this);
}
MIDI_file* MIDI_file::Create(const char* fn,const void * data, size_t size)
{
MIDI_file* mf=new MIDI_file(fn);
if (!mf->Load(data,size))
{
delete mf;
mf=0;
}
return mf;
}

View File

@ -0,0 +1,89 @@
#ifndef NULLSOFT_IN_MIDI_MIDIFILE_H
#define NULLSOFT_IN_MIDI_MIDIFILE_H
#include <dsound.h>
#ifndef MF_NO_DMCRAP
#define MF_USE_DMCRAP
#endif
#ifdef MF_USE_DMCRAP
#include <dmusici.h>
#include <dmusicf.h>
#endif
typedef struct
{
UINT fmt,ntrax,tix;
UINT channels;
const char* e_type;
string copyright;
string * traxnames;
} MIDIINFO;
#define FLAG_INCOMPLETE 1
typedef struct tagINSDESC
{
tagINSDESC * next;
UINT bank_hi,bank_lo,patch,count,note_max,note_min,channels,user;
BOOL drum;
} INSTRUMENT_DESC;
class MIDI_file
{
public:
string path;
string title;
int flags;
int format;
int len,tix;
int size;
const BYTE* data;
#ifdef MF_USE_DMCRAP
IDirectMusicSegment *pSeg;
IDirectMusicCollection *pDLS;
BYTE* pDLSdata;
int DLSsize;
#endif
MIDIINFO info;
int loopstart,loopend;
int loopstart_t;
void * rmi_data;//extra RMI crap
int rmi_size;
void * bmp_data;//RMI-style bitmap data w/o BITMAPFILEHEADER
int bmp_size;
int kar_track;
CTempoMap * tmap;
CSysexMap * smap;
void GetTitle(char *buf, int maxlen);
inline int GetLength(void) {return len;}
static MIDI_file* Create(const char* fn,const void * data, size_t size);
void Free() {if (--refcount==0) delete this;}
MIDI_file * AddRef() {refcount++;return this;}
static int HeaderTest(const void * data,int total_size);//test first 256 bytes of file
private:
int refcount;
MIDI_file(const char * fn);
int Load(const void * data,int size);
~MIDI_file();
};
#define CLEAN_DM 1
#define CLEAN_1TRACK 2
#define CLEAN_NOSYSEX 4
#define CLEAN_NOTEMPO 8
#define CLEAN_DLS 16
int DoCleanUp(MIDI_file*,DWORD,void** out_data,int * out_size);
INSTRUMENT_DESC* GetInstruments(MIDI_file*,BOOL do_lsb);
#ifdef MF_USE_DMCRAP
IDirectMusicSegment * LoadSegment(MIDI_file*);
void LoadDLS(MIDI_file* mf);
#endif
#endif

View File

@ -0,0 +1,326 @@
#include "main.h"
#include <intsafe.h>
#define _RIFF 'FFIR'
#define _MThd 'dhTM'
#define _MTrk 'krTM'
#define _RMID 'DIMR'
#define _data 'atad'
//#define BLAH
static cfg_int cfg_loop_ctrl("cfg_loop_ctrl",255),cfg_loop_meta("cfg_loop_meta",255);
class CGetInfo
{
public:
MIDI_file * mf;
int loop;
int nch;
int got_notes;
int cur_track_start;
int c_track,s_track;
bool is_blah,f2;
int max_ff_track,max_ff_num;
CTempoMap *tmap,*ttmap;
CSysexMap *smap;
void CleanTempo();
int DoTrack(const BYTE* track,size_t size,string& name,int);
bool Run(MIDI_file* mf);
};
static bool memicmp(char* b1,char* b2,int s)
{
for(int n = 0; n < s; n++)
{
if (tolower(b1[n]) != tolower(b2[n]))
return 1;
}
return 0;
}
static bool is_kar(char* ptr,int siz) //hack
{
siz -= 7;//strlen("karaoke");
for(int n = 0; n <= siz; n++)
{
// lameness to just prevent a crash on broken
// files no idea what else it'll break though
if ((int)(ptr+n) > siz) return 0;
if (!memicmp(ptr+n,"karaoke",7)) return 1;
}
return 0;
}
extern cfg_int cfg_ff7loopz;
BYTE ff7loopstart[12]={0xFF,6,9,'l','o','o','p','S','t','a','r','t'};
BYTE ff7loopend[10]={0xFF,6,7,'l','o','o','p','E','n','d'};
int CGetInfo::DoTrack(const BYTE* track,size_t size,string& name,int cpos)
{
int res=0,_res=0;
size_t n=0;
BYTE lc1=0,lastcom=0;
bool run=0;
int ff_num=0;
while(n<size)
{
{
unsigned int d=0;
unsigned int _n=DecodeDelta(track+n,&d);
if (_n<4) res+=d;
n+=_n;
}
if (track[n]==0xFF) //meta-events
{
if (f2) _res=res;
if (cfg_ff7loopz
&& (size-n)>=sizeof(ff7loopstart) // bounds check
&& !memcmp(&track[n],ff7loopstart,sizeof(ff7loopstart)))
{
if (loop==-1) loop=res;
}
if ((UINT)track[n+1]==(UINT)cfg_loop_meta && loop==-1) loop=res;
if (track[n+1]==0x51 && track[n+2]==0x03) //tempo
{
if (ttmap) ttmap->AddEntry(cpos+res,((DWORD)track[n+3]<<16)+((DWORD)track[n+4]<<8)+((DWORD)track[n+5]));
n+=6;
}
else if (track[n+1]==0x2F && track[n+2]==0x00)
{
if (ff_num>max_ff_num)
{
max_ff_num=ff_num;
max_ff_track=cur_track_start;
}
return _res;
}
else
{
DWORD _l=0,l1;
UINT n1=0;
{
do
{
_l=(_l<<7)|(track[n+2+n1++]&0x7F);
}
while((n+1+n1< size) && track[n+1+n1]&0x80);
}
if (_l>255) l1=255;
else l1=_l;
if (track[n+1]<0x10) ff_num++;
switch(track[n+1])
{
case 6:
// if (!cpr || *cpr) break;
case 2:
if (n + 1 + n1 + l1 >= size)
return -1;
mf->info.copyright.add_string_n((char*)(track+n+n1+2),l1);
mf->info.copyright.add_string("\x0d\x0a");
break;
case 5:
is_blah=1;
break;
case 3:
case 1:
if (is_kar((char*)track+n+n1+2,_l)) is_blah=1;
case 4:
if (name.length()==0)
{
name.add_string_n((char*)(track+n+n1+2),l1);
}
break;
}
size_t n_increment;
if (SizeTAdd(2, n1, &n_increment) != S_OK || SizeTAdd(n_increment, _l, &n_increment) != S_OK || SizeTAdd(n_increment, n, &n) != S_OK)
return -1;
}
}
else if ((track[n]&0xF0)==0xF0)
{
if (track[n]==0xF0)
{
_res=res;
UINT s=ReadSysex(&track[n],size-n);
smap->AddEvent(&track[n],s,cpos+res);
n+=s;
if (s_track==-1) s_track=c_track;
else if (s_track!=c_track) s_track=-2;
}
else //hack...
if (track[n]==0xF7) n++;
else
{
#ifdef BLAH
char tmp[32] = {0};
wsprintf(tmp,"invalid Fx event at %x",n);
MessageBox(0,tmp,0,0);
#endif
return -1;
}
}
else
{
lc1=track[n];
// if (lc1 == 0) return -1;
if ((lc1&0x80)==0)
{
if (lastcom==0)
return -1;
run=1;
lc1=lastcom;
n--;
} else run=0;
_res=res;
switch(lc1&0xF0)
{
case 0x80:
case 0x90:
if (!(got_notes&(1<<(lc1&0xF))))
{
nch++;
got_notes|=1<<(lc1&0xF);
}
case 0xB0:
if (track[n+1]==cfg_loop_ctrl && loop==-1)
loop=res;
case 0xA0:
case 0xE0:
n+=3;
lastcom=lc1;
break;
case 0xC0:
case 0xD0:
n+=2;
lastcom=lc1;
break;
default:
return -1;
}
}
}
return _res;
}
bool GetMidiInfo(MIDI_file* mf)
{
CGetInfo i;
return i.Run(mf);
}
bool CGetInfo::Run(MIDI_file* _mf)
{
mf=_mf;
nch=0;
s_track=-1;
is_blah=0;
max_ff_track=max_ff_num=0;
MIDIHEADER hd = *(MIDIHEADER*)(mf->data+8);
tmap=tmap_create();
if (!tmap) return 0;
smap=smap_create();
ttmap=0;
mf->tmap=tmap;//avoid stupid memleaks
mf->smap=smap;
loop=-1;
tmap->AddEntry(0,500000);
DWORD sz = mf->size-14;
FixHeader(hd);
got_notes=0;
nch=0;
const BYTE* trax=mf->data+14;
const BYTE* ntrak=trax;
if (hd.trax>0x100 || hd.fmt>2) return 0;
f2=hd.fmt==2;
int n,tmp;
int size=0;
mf->info.traxnames = new string[hd.trax];
for(c_track=0;c_track<hd.trax;c_track++)
{
if (!ttmap) ttmap=tmap_create();
if ((UINT)(ntrak-trax)>=(UINT)sz || *((DWORD*)ntrak)!='krTM' || (tmp=rev32(*((DWORD*)ntrak+1)))+ntrak>sz+trax) return 0;
cur_track_start=ntrak-mf->data;
tmp=DoTrack(ntrak+8,tmp,mf->info.traxnames[c_track],f2 ? size : 0);
if (tmp==-1)
{
/* ntrak[8]=0;
ntrak[9]=0xFF;
ntrak[10]=0x2F;
ntrak[11]=0;*/
#ifdef BLAH
{
char e[128] = {0};
wsprintf(e,"Bad track #%u",c_track);
MessageBox(0,e,ERROR,0);
}
#endif
}
else
{
if (f2) size+=tmp;
else if (tmp>size) size=tmp;
if (ttmap->pos)
{
mf->tmap=tmap=tmap_merge(tmap,ttmap);
ttmap=0;
}
}
ntrak+=rev32(*((DWORD*)ntrak+1))+8;
}
if (ttmap) delete ttmap;
if (!tmap) return 0;
mf->tix=MulDiv(size+50,768,hd.dtx);
DWORDLONG res=0;
for(n=0;n<tmap->pos-1 && tmap->data[n].pos<size;n++)
{
res+=UInt32x32To64(tmap->data[n].tm,tmap->data[n+1].pos-tmap->data[n].pos);
}
if (tmap->data[n].pos<size) res+=UInt32x32To64(tmap->data[n].tm,size-tmap->data[n].pos);
mf->len=(DWORD)(res/(hd.dtx*1000));
if (loop!=-1 && loop<size)
{
mf->loopstart=loop;
}
mf->info.channels=nch;
mf->info.fmt=hd.fmt;
mf->info.ntrax=hd.trax;
mf->info.tix=size;
if (mf->loopstart)
{
mf->loopstart_t=mf->loopstart;
mf->loopstart=MulDiv(mf->loopstart,768,hd.dtx);
mf->loopend=MulDiv(size+15,768,hd.dtx);
}
else mf->loopstart_t=-1;
if (!f2 && smap && s_track==-2) smap->CleanUp(); //todo: optimize this shit...
/* mf->tmap=tmap;
mf->smap=smap;*/
mf->info.e_type=smap->GetType();
if (is_blah)
{
mf->kar_track=max_ff_track;
}
return 1;
}

View File

@ -0,0 +1,2 @@
#include "main.h"

View File

@ -0,0 +1,96 @@
#include "main.h"
#include "cvt.h"
bool is_mids(const BYTE* buf,size_t s)
{
return s>0x20 && *(DWORD*)buf==_rv('RIFF') && *(DWORD*)(buf+8)==_rv('MIDS') && *(DWORD*)(buf+12)==_rv('fmt ');
}
typedef struct
{
DWORD dwTimeFormat;
DWORD cbMaxBuffer;
DWORD dwFlags;
} MIDSFMT;
#define WRITE(X,Y) out.write(X,Y)
#define WRITE_DELTA(X) gb_write_delta(out,X)
#define D_WRITE {WRITE_DELTA(ct-tw);tw=ct;}
bool load_mids(MIDI_file* mf,const BYTE* buf,size_t sz)
{
if (sz<*(long*)(buf+4)+8) return 0;
MIDSFMT* fmt=(MIDSFMT*)(buf+0x14);
DWORD ofs;
ofs=*(DWORD*)(buf+0x10)+0x14;
if (*(DWORD*)(buf+ofs)!=_rv('data')) return 0;
//ofs+=8+*(DWORD*)(buf+ofs+4);
ofs+=8;
DWORD ss=*(DWORD*)(buf+ofs-4);
DWORD nc=*(DWORD*)(buf+ofs);
DWORD* ptr=(DWORD*)(buf+ofs);
grow_buf out;
ss>>=2;
DWORD mhdr[2];
mhdr[0]=_rv('MThd');
mhdr[1]=_rv(6);
WRITE(mhdr,8);
WORD w=0;
WRITE(&w,2);
w=0x100;
WRITE(&w,2);
w=rev16((WORD)fmt->dwTimeFormat);
WRITE(&w,2);
mhdr[0]=_rv('MTrk');
WRITE(mhdr,8);
DWORD tw=0,ct=0;
DWORD cc=0;
DWORD cs;
DWORD pos=1;
while(cc<nc)
{
cs = (ptr[pos+1]>>2)+pos;
if (cs>ss) break;
pos+=2;
while(pos<cs)
{
ct+=ptr[pos];
pos+=2;
DWORD e=ptr[pos];
if (e&MEVT_F_LONG)
{
pos+=e&0xFFFFFF;
}
else
{
if (e>>24==MEVT_TEMPO)
{
D_WRITE;
BYTE tmp[6]={0xFF,0x51,0x03,(BYTE)((e>>16)&0xFF),(BYTE)((e>>8)&0xFF),(BYTE)(e&0xFF)};
WRITE(tmp,6);
}
else if (!(e>>24))
{
BYTE c=(BYTE)(e&0xF0);
if (c!=0xF0)
{
D_WRITE;
DWORD l=(c==0xC0 || c==0xD0) ? 2 : 3;
WRITE(&e,l);
}
}
pos++;
}
}
}
WRITE("\x00\xFF\x2F",4);
out.write_dword_ptr(rev32(out.get_size()-(8+6+8)),8+6+4);
mf->size = out.get_size();
mf->data = (BYTE*)out.finish();
return !!mf->data;
}

View File

@ -0,0 +1,184 @@
#include "main.h"
#include "cvt.h"
bool is_mus(const BYTE* buf,size_t s)
{
if (s>0x20 && *(DWORD*)buf == '\x1ASUM')
{
int ofs = ((WORD*)buf)[3];
int n_ins = ((WORD*)buf)[6];
if (ofs>=16+(n_ins<<1) && ofs<16+(n_ins<<2) && ofs<s)
{
return 1;
}
}
return 0;
}
static BYTE tempodat[] = {0x00,0xFF,0x51,0x03,0x09,0xA3,0x1A};
static BYTE controllers[15] = {0,0,1,7,10,11,91,93,64,67,120,123,126,127,121};
#define abort _abort_
struct MUS_cvt
{
public:
bool abort;
DWORD ct;
DWORD lt;
grow_buf out;
void AddEvent(DWORD ev,int l);
bool run(MIDI_file* mf,const BYTE* ptr,DWORD sz);
};
void MUS_cvt::AddEvent(DWORD ev,int l)
{
DWORD dt = ct - lt;
int tl=3;
gb_write_delta(out,dt);
lt = ct;
BYTE ec=(BYTE)(ev&0xF0);
out.write(&ev,l);
}
bool MUS_cvt::run(MIDI_file* mf,const BYTE* ptr,DWORD sz)
{
#pragma pack(push)
#pragma pack(1)
struct
{
char id[4];
WORD len;
WORD ofs;
WORD ch1,ch2;
WORD n_ins;
WORD dummy;
} hdr;
#pragma pack(pop)
DWORD _pt=0;
memcpy(&hdr,ptr,sizeof(hdr));
const BYTE* score = ptr+sizeof(hdr)+2*hdr.n_ins;
long x;
static BYTE _hd_[]={'M','T','h','d',0,0,0,6, 0,0,0,1,0,0x59,'M','T','r','k'};
out.write(_hd_,sizeof(_hd_));
DWORD ts_ofs=out.get_size();
out.write_dword(0);
lt=0;
abort = 0;
ct = 0;
out.write(tempodat,sizeof(tempodat));
x=0;
bool t;
BYTE ch;
BYTE vols[16];
ZeroMemory(vols,sizeof(vols));
union
{
BYTE b[4];
DWORD dw;
} ev;
while(x<hdr.len && score[x]!=0x60)
{
ev.dw = 0;
t=(score[x]&0x80)?1:0;
ch = score[x]&0xF;
if (ch == 0xF) ch = 9;//hdr.ch1+1;
else if (ch>=9) ch++;
switch(score[x]&0x70)
{
case 0: //release note
ev.b[0]=0x80|ch;
ev.b[1]=score[x+1];
ev.b[2]=0;//vols[ch];
AddEvent(ev.dw,3);
x+=2;
break;
case 0x10: //play note
ev.b[0]=0x90|ch;
ev.b[1]=score[x+1]&0x7F;
if (score[x+1]&0x80)
{
vols[ch]=score[x+2];
x+=3;
}
else
{
x+=2;
}
ev.b[2]=vols[ch];
AddEvent(ev.dw,3);
break;
case 0x20: //pitch wheel
ev.b[0]=0xE0|ch;
ev.b[1]=0;
ev.b[2]=score[x+1]>>1;
AddEvent(ev.dw,3);
x+=2;
break;
case 0x30: //system event
if (score[x+1]>=10 && score[x+1]<=14)
{
ev.b[0]=0xB0|ch;
ev.b[1]=controllers[score[x+1]];
ev.b[2]=1;
AddEvent(ev.dw,3);
x+=2;
break;
}
else return 0;
case 0x40: //change controller
if (score[x+1])
{
if (score[x+1]<10)
{
ev.b[0]=0xB0|ch;
ev.b[1]=controllers[score[x+1]];
ev.b[2]=score[x+2];
AddEvent(ev.dw,3);
x+=3;
}
else return 0;
}
else
{
ev.b[0]=0xC0|ch;
ev.b[1]=score[x+2];
AddEvent(ev.dw,2);
x+=3;
};
break;
case 0x50:
case 0x70:
case 0x60:
return 0;
}
if (abort) return 0;
if (t)
{
DWORD dt=0;
do
{
dt = (dt<<7) + (score[x]&0x7F);
} while(score[x++]&0x80);
ct+=dt;
}
}
out.write_dword(0x002FFF00);
out.write_dword_ptr(rev32(out.get_size()-(ts_ofs+4)),ts_ofs);
mf->size = out.get_size();
mf->data = (BYTE*)out.finish();
return !!mf->data;
}
bool load_mus(MIDI_file* mf,const BYTE* ptr,size_t sz)
{
MUS_cvt c;
return c.run(mf,ptr,sz);
}

View File

@ -0,0 +1,962 @@
#include "main.h"
#include <math.h>
#include "seq.h"
#include "fakedsound.h"
#include "resource.h"
// {B84EB58A-29F5-410b-880A-EB473BF34291}
static const GUID guid_output =
{ 0xb84eb58a, 0x29f5, 0x410b, { 0x88, 0xa, 0xeb, 0x47, 0x3b, 0xf3, 0x42, 0x91 } };
// {DF0800B6-D1E1-4b53-9C1E-642AF4CB7136}
static const GUID dmusic_driver_guid =
{ 0xdf0800b6, 0xd1e1, 0x4b53, { 0x9c, 0x1e, 0x64, 0x2a, 0xf4, 0xcb, 0x71, 0x36 } };
enum
{
MDD_OUT=1,
};
extern cfg_int cfg_dls_active,cfg_dm_keep_port;
extern cfg_string cfg_dls_file;
class MIDI_device_dmusic : public MIDI_device
{
private:
GUID guid,guid_dmusic;
DWORD dmFlags;
bool f_has_output;
virtual player_base * create();
virtual bool is_default() {return 0;}
virtual bool has_freq() {return !!(dmFlags&DMUS_PC_DIRECTSOUND);}
virtual bool volctrl_happy() {return (dmFlags&DMUS_PC_DIRECTSOUND) || (dmFlags&DMUS_PC_SOFTWARESYNTH);}
public:
MIDI_device_dmusic(GUID p_guid,bool p_has_output,DWORD p_dmFlags,const wchar_t * p_name,const wchar_t * p_info)
{
guid = p_guid;
guid_dmusic = p_guid;
dmFlags = p_dmFlags;
set_name(p_name);
set_info(p_info);
f_has_output = p_has_output;
if (f_has_output)
{
const BYTE * src = (const BYTE*) &guid_output;
BYTE * dst = (BYTE*) &guid;
int n;
for(n=0;n<sizeof(GUID);n++) dst[n]^=src[n];
}
}
virtual GUID get_guid() {return guid;}
GUID get_dm_guid() {return guid_dmusic;}
virtual bool has_output() {return f_has_output;}
virtual bool has_dls() {return !!(dmFlags&DMUS_PC_DLS);}
};
//bool IsDrumBankOK(BYTE n);
IDirectMusicLoader* pLoader=0;
IDirectMusicPerformance* pPerf=0;
static IDirectMusicCollection *pGM=0;
static IDirectMusic* pDM;
static IDirectMusicPort *pPort;
static IDirectSoundBuffer* pHack;
IDirectMusicCollection *pCDLS=0;
static void SendMsg(IDirectMusicPerformance *pPerf,DWORD msg)
{
DMUS_MIDI_PMSG *pMSG;
if(SUCCEEDED(pPerf->AllocPMsg(sizeof(DMUS_MIDI_PMSG),(DMUS_PMSG**)&pMSG)))
{
ZeroMemory(pMSG, sizeof(DMUS_MIDI_PMSG));
pMSG->dwSize = sizeof(DMUS_MIDI_PMSG);
pMSG->dwPChannel = msg&0xF;
pMSG->dwVirtualTrackID = 0;
pMSG->dwType = DMUS_PMSGT_MIDI;
pMSG->dwVoiceID = 0;
pMSG->dwGroupID = 0xFFFFFFFF;
pMSG->mtTime=0;
pMSG->dwFlags = DMUS_PMSGF_REFTIME|DMUS_PMSGF_TOOL_IMMEDIATE;//pMSG->dwFlags = DMUS_PMSGF_REFTIME|DMUS_PMSGF_TOOL_IMMEDIATE;
pMSG->bStatus=(BYTE)(msg&0xFF);
pMSG->bByte1=(BYTE)((msg>>8)&0xFF);
pMSG->bByte2=(BYTE)((msg>>16)&0xFF);
if (FAILED(pPerf->SendPMsg((DMUS_PMSG*)pMSG)))
{
pPerf->FreePMsg((DMUS_PMSG*)pMSG);
}
}
}
static void SendSysex(IDirectMusicPerformance *pPerf,BYTE* data,UINT len)
{
DMUS_SYSEX_PMSG *pMSG;
if(SUCCEEDED(pPerf->AllocPMsg(sizeof(DMUS_SYSEX_PMSG) + len,(DMUS_PMSG**)&pMSG)))
{
ZeroMemory(pMSG, sizeof(DMUS_SYSEX_PMSG)+len);
pMSG->dwSize = sizeof(DMUS_SYSEX_PMSG);
pMSG->dwPChannel = 0;
pMSG->dwVirtualTrackID = 0;
pMSG->dwType = DMUS_PMSGT_SYSEX;
pMSG->dwVoiceID = 0;
pMSG->dwGroupID = 0xFFFFFFFF;
pMSG->dwLen = len;
memcpy(pMSG->abData, (void*)data, len);
pMSG->mtTime=0;
pMSG->dwFlags = DMUS_PMSGF_REFTIME|DMUS_PMSGF_TOOL_IMMEDIATE;//pMSG->dwFlags = |DMUS_PMSGF_TOOL_IMMEDIATE;
if (FAILED(pPerf->SendPMsg((DMUS_PMSG*)pMSG)))
{
pPerf->FreePMsg((DMUS_PMSG*)pMSG);
}
}
}
static void PortKill()
{
#ifdef USE_LOG
log_write("portkill()");
#endif
if (pPort)
{
pPort->Activate(0);
if (pPerf) pPerf->RemovePort(pPort);
pPort->Release();
pPort=0;
}
}
static int PortInit(MIDI_device_dmusic * dev)
{
#ifdef USE_LOG
log_write("portinit()");
#endif
static int _act_freq;
static int _cfg_reverb,_cfg_chorus;
static GUID last_port;
if (!pPort || last_port!=dev->get_guid() || _act_freq!=cfg_freq || _cfg_reverb!=cfg_reverb || _cfg_chorus!=cfg_chorus)
{
#ifdef USE_LOG
log_write("port settings changed");
#endif
if (pPort) PortKill();
DMUS_PORTPARAMS dmpp;
ZeroMemory(&dmpp,sizeof(dmpp));
dmpp.dwSize=sizeof(dmpp);
dmpp.dwValidParams=DMUS_PORTPARAMS_EFFECTS|DMUS_PORTPARAMS_SAMPLERATE|DMUS_PORTPARAMS_CHANNELGROUPS;
dmpp.dwChannelGroups=1;
dmpp.dwSampleRate=cfg_freq;
if (cfg_reverb) dmpp.dwEffectFlags=DMUS_EFFECT_REVERB;
if (cfg_chorus) dmpp.dwEffectFlags|=DMUS_EFFECT_CHORUS;
if (FAILED( pDM->CreatePort(dev->get_dm_guid(),&dmpp,&pPort,0) )) return 0;
pPerf->AddPort(pPort);
pPerf->AssignPChannelBlock(0,pPort,1);
last_port = dev->get_guid();
_act_freq=cfg_freq;
_cfg_reverb=cfg_reverb;
_cfg_chorus=cfg_chorus;
}
if ((dev->has_output()))
{
#ifdef USE_LOG
log_write("initializing output hack");
#endif
DWORD buf_s=0,blah=0;
pPort->GetFormat(0,&blah,&buf_s);
pHack=dhb_create(buf_s,cfg_freq);
if (FAILED(pPort->SetDirectSound(get_ds(),pHack)))
{//BORK
PortKill();
return 0;
}
}
return 1;
}
/*
int lastvol1=(vol==0)?0x80000000:((int)(2000.0*log((double)vol/256.0)));
if (pPerf)
{
return SUCCEEDED(pPerf->SetGlobalParam(GUID_PerfMasterVolume,&lastvol1,4));
}
*/
static int DM_setvol(int vol)
{
int lastvol1=(vol==0)?0x80000000:((int)(2000.0*log10((double)vol/255.0)));
if (pPerf)
{
return SUCCEEDED(pPerf->SetGlobalParam(GUID_PerfMasterVolume,&lastvol1,4));
}
return 0;
}
class player_dmusic_imm : public seq_base
{
private:
MIDI_device_dmusic * dev;
UINT n_ins,s_ins;
IDirectMusicDownloadedInstrument ** ins;
IDirectMusicCollection *edls;
protected:
virtual void seq_shortmsg(DWORD msg) {SendMsg(pPerf,msg);}
virtual void seq_sysex(BYTE* d,UINT l) {SendSysex(pPerf,d,l);}
virtual void eof() {MIDI_core::Eof();}
int setvol(int t) {return DM_setvol(t);}
public:
player_dmusic_imm(MIDI_device_dmusic * p_dev)
{
dev=p_dev;
s_ins=n_ins=0;
ins=0;
edls=0;
if (dev->has_dls())
{
s_ins=0x100;
ins=(IDirectMusicDownloadedInstrument**)malloc(s_ins*sizeof(void*));
}
}
~player_dmusic_imm();
int play();
};
int player_dmusic_imm::play()
{
if (!PortInit(dev)) return 0;
MIDI_file * mf=MIDI_core::getFile();
if (ins)
{
if (mf->pDLSdata)
{
LoadDLS(mf);
if (mf->pDLS)
{
edls=mf->pDLS;
}
}
if (!edls) edls=pCDLS;
{
INSTRUMENT_DESC* instr=GetInstruments(mf,1);
while(instr)
{
DWORD i=instr->patch | (instr->bank_lo<<8) | (instr->bank_hi<<16);
if (instr->drum) i|=0x80000000;
if (n_ins>=s_ins)
{
s_ins<<=1;
void *t=realloc(ins,s_ins);
// if (!t) {s_ins>>=1;return ;}
ins=(IDirectMusicDownloadedInstrument**)t;
}
IDirectMusicInstrument * pi=0;
start:
if (edls)
{
edls->GetInstrument(i,&pi);
}
if (!pi && pGM)
{
pGM->GetInstrument(i,&pi);
}
if (!pi) //cleaner's hacks don't work here
{
if (i&0x80000000)
{
if (i&0xFFFF00) {i&=0x800000FF;goto start;}
}
else
{
if (i&0xFF00) {i&=0xFF00FF;goto start;}
if (i&0xFF0000) {i&=0xFF;goto start;}
}
}
#if 0
if (!pi)
{
char tmp[128] = {0};
if (i&0x80000000)
wsprintf(tmp,"missing drum kit: %u",i&0xFF);
else
wsprintf(tmp,"missing instrument: bank %x:%x / patch %x",(i>>16)&0xFF,(i>>8)&0xFF,i&0xFF);
Warning(tmp);
}
#endif
if (pi)
{
// DMUS_NOTERANGE nr = {instr->note_min,instr->note_max};
// pPort->DownloadInstrument(pi,&ins[n_ins++],&nr,1);
pPort->DownloadInstrument(pi,&ins[n_ins++],0,0);
pi->Release();
}
{
INSTRUMENT_DESC * d=instr->next;
delete instr;
instr=d;
}
}
}
}
/* UINT n;
for(n=0;n<16;n++)
{
pPort->SetChannelPriority(0,n,DAUD_CRITICAL_VOICE_PRIORITY);
}*/
pPort->Activate(1);
DM_setvol(MIDI_core::player_getVol());
return seq_cmd_start(CLEAN_DM);
}
player_dmusic_imm::~player_dmusic_imm()
{
seq_cmd_stop();
if (ins)
{
if (pPort)
{
pPort->Activate(0);
UINT n;
for(n=0;n<n_ins;n++)
{
if (ins[n])
{
pPort->UnloadInstrument(ins[n]);
ins[n]=0;
}
}
}
free(ins);
}
if (pHack)
{
pPort->SetDirectSound(0,0);
pHack->Release();
pHack=0;
}
if (!cfg_dm_keep_port) PortKill();
}
static void CALLBACK TimerProc(HWND,UINT,UINT id,DWORD)
{
DMUS_NOTIFICATION_PMSG* pMsg;
while(pPerf->GetNotificationPMsg(&pMsg)==S_OK)
{
if (IsEqualGUID(pMsg->guidNotificationType,GUID_NOTIFICATION_SEGMENT))
{
if (MIDI_core::HavePlayer() && pMsg->dwNotificationOption == DMUS_NOTIFICATION_SEGEND)
{
MIDI_core::Eof();
}
}
pPerf->FreePMsg((DMUS_PMSG*)pMsg);
}
}
class player_dmusic : public player_base
{
public:
~player_dmusic();
int gettime();
int settime(int);
int setvol(int vol) {return DM_setvol(vol);}
void pause();
void unpause();
int play();
player_dmusic(MIDI_device_dmusic * p_dev)
{
dev = p_dev;
pSeg=0;
pSS=0;
rtStart=rtOffset=0;
mtStart=mtOffset=0;
}
private:
MIDI_device_dmusic * dev;
IDirectMusicSegment* pSeg;
IDirectMusicSegmentState* pSS;
REFERENCE_TIME rtStart,rtOffset;
MUSIC_TIME mtOffset,mtStart;
bool dloaded,paused;
UINT timer_id;
};
player_base * MIDI_device_dmusic::create()
{
#ifdef USE_LOG
log_write("DM_create");
#endif
CoInitialize(0);
if (!pLoader)
{
try {
CoCreateInstance(CLSID_DirectMusicLoader,0,CLSCTX_INPROC,IID_IDirectMusicLoader,(void**)&pLoader);
if (!pLoader) return 0;
pLoader->EnableCache(GUID_DirectMusicAllTypes,0);
} catch(...) {
return 0;
}
}
if (!pPerf)
{
try {
CoCreateInstance(CLSID_DirectMusicPerformance,0,CLSCTX_INPROC,IID_IDirectMusicPerformance,(void**)&pPerf);
if (!pPerf) return 0;
pPerf->Init(&pDM,0,0);
pPerf->AddNotificationType(GUID_NOTIFICATION_SEGMENT);
} catch(...) {
return 0;
}
}
if (!pGM)
{
DMUS_OBJECTDESC desc;
ZeroMemory(&desc,sizeof(desc));
desc.dwSize=sizeof(desc);
desc.dwValidData=DMUS_OBJ_OBJECT|DMUS_OBJ_CLASS;
desc.guidObject=GUID_DefaultGMCollection;
desc.guidClass=CLSID_DirectMusicCollection;
try {
pLoader->GetObject(&desc,IID_IDirectMusicCollection,(void**)&pGM);
} catch(...) {
return 0;
}
}
if (has_dls())
{
static string current_dls;
if (!cfg_dls_active)
{
if (pCDLS) {pCDLS->Release();pCDLS=0;}
}
else
{
if (pCDLS && _stricmp(current_dls,cfg_dls_file)) {pCDLS->Release();pCDLS=0;}
if (!pCDLS)
{
DMUS_OBJECTDESC desc;
ZeroMemory(&desc,sizeof(desc));
desc.dwSize=sizeof(desc);
desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME;
desc.guidClass = CLSID_DirectMusicCollection;
mbstowcs(desc.wszFileName,cfg_dls_file,DMUS_MAX_FILENAME);
if (FAILED(pLoader->GetObject(&desc,IID_IDirectMusicCollection,(void**)&pCDLS)))
{
// ErrorBox(Can't load DLS file.);
pCDLS=0;
cfg_dls_active=0;
}
else
{
ReleaseObject(pCDLS);
current_dls = cfg_dls_file;
}
}
}
}
if (cfg_playback_mode)
{
player_dmusic_imm * p=new player_dmusic_imm(this);
if (p)
{
if (!p->play())
{
delete p;
p=0;
}
}
return p;
}
else
{
player_dmusic* p=new player_dmusic(this);
if (p)
{
if (!p->play()) {delete p;p=0;}
}
return p;
}
}
MUSIC_TIME GetMTforMS(IDirectMusicSegment* pS,DWORD ms)
{
MUSIC_TIME mtSeg,mct=0,mnt;
DMUS_TEMPO_PARAM tp;
pS->GetLength(&mtSeg);
double _r=0,r1;
while(mct<mtSeg)
{
if (FAILED(pS->GetParam(GUID_TempoParam,-1,0,mct,&mnt,&tp))) break;
if (!mnt) mnt=mtSeg-mct;
r1=_r;
_r+=(mnt)/tp.dblTempo*78;
if (_r>ms)
{
return (MUSIC_TIME)(mct+mnt*((double)ms-r1)/(_r-r1));
}
mct+=mnt;
}
return mtSeg;
}
DWORD GetSegLen(IDirectMusicSegment* pS)
{
MUSIC_TIME mtSeg,mct=0,mnt;
DMUS_TEMPO_PARAM tp;
pS->GetLength(&mtSeg);
double _r=0;
while(mct<mtSeg)
{
pS->GetParam(GUID_TempoParam,-1,0,mct,&mnt,&tp);
if (!mnt) mnt=mtSeg-mct;
_r+=(double)mnt/tp.dblTempo*78;
mct+=mnt;
}
return (DWORD)_r;
}
void ReleaseObject(IUnknown* o)
{
IDirectMusicObject* pObject=0;
if (pLoader && SUCCEEDED(o->QueryInterface(IID_IDirectMusicObject,(void**)&pObject)))
{
pLoader->ReleaseObject(pObject);
pObject->Release();
}
}
player_dmusic::~player_dmusic()
{
pPerf->Stop(0,0,0,0);
if (pPort) pPort->Activate(0);
// pPerf->Invalidate(0,0);
mtOffset=0;
rtOffset=0;
mtStart=0;
rtStart=0;
if (pSS) {pSS->Release();pSS=0;}
if (pSeg)
{
if (dloaded) pSeg->SetParam(GUID_Unload,0xFFFFFFFF,0,0,(void*)pPerf);
pSeg->Release();
pSeg=0;
}
if (pHack)
{
pPort->SetDirectSound(0,0);
pHack->Release();
pHack=0;
}
if (!cfg_dm_keep_port) PortKill();
if (timer_id) KillTimer(0,timer_id);
}
void player_dmusic::pause()
{
MUSIC_TIME mt;
REFERENCE_TIME rt;
pPerf->Stop(0,0,0,0);
if (pSS)
{
pSS->Release();
pSS=0;
}
pPerf->GetTime(&rt,&mt);
mtOffset+=mt-mtStart;
rtOffset+=rt-rtStart;
pSeg->SetStartPoint(mtOffset);
paused=1;
}
void player_dmusic::unpause()
{
if (pSS)
{
pSS->Release();
pSS=0;
}
if (SUCCEEDED(pPerf->PlaySegment(pSeg,0,0,&pSS)))
{
pSS->GetStartTime(&mtStart);
pPerf->MusicToReferenceTime(mtStart,&rtStart);
}
paused=0;
}
int player_dmusic::gettime()
{
static DWORD tm;
if (pSS)
{
REFERENCE_TIME rt;
pPerf->GetTime(&rt,0);
tm=(int)((rt-rtStart+rtOffset)/10000);
}
return tm;
}
int player_dmusic::play()
{
#ifdef USE_LOG
log_write("player_dmusic::play()");
#endif
if (!PortInit(dev)) return 0;
pSeg=LoadSegment(MIDI_core::getFile());
if (!pSeg)
{
#ifdef USE_LOG
log_write("LoadSegment() failed");
#endif
// Error("Unable to get IDirectMusicSegment.");
return 0;
}
#ifdef USE_LOG
log_write("player_dmusic::play() : got IDirectMusicSegment");
#endif
pSeg->SetRepeats( (cfg_loop_type==2 || (cfg_loop_type==1 && MIDI_core::getFile()->loopstart)) ? (cfg_loop_infinite ? -1 : cfg_loop_count-1) : 0);
dloaded=0;
if (dev->has_dls())
if (SUCCEEDED(pSeg->SetParam(GUID_Download,-1,0,0,(void*)pPerf)))
dloaded=1;
pSeg->SetStartPoint(0);
#ifdef USE_LOG
log_write("Activating port...");
#endif
pPort->Activate(1);
#ifdef USE_LOG
log_write("IDirectMusicPort::Activate() returned");
#endif
sysex_startup((SYSEXFUNC)SendSysex,pPerf);
#ifdef USE_LOG
log_write("IDirectMusicPerformance::PlaySegment()");
#endif
pSS=0;
DM_setvol(MIDI_core::player_getVol());
if (FAILED(pPerf->PlaySegment(pSeg,DMUS_SEGF_DEFAULT,0,&pSS)))
{
// Error("IDirectMusicPerformance::PlaySegment() failed.");
return 0;
}
#ifdef USE_LOG
log_write("IDirectMusicPerformance::PlaySegment() returned OK");
#endif
rtOffset=0;
if (pSS)
{
pSS->GetStartTime(&mtStart);
}
else
{
#ifdef USE_LOG
log_write("no segment starte. WTF ?");
#endif
mtStart=0;
}
pPerf->MusicToReferenceTime(mtStart,&rtStart);
timer_id=SetTimer(0,0,33,(TIMERPROC)TimerProc);
return 1;
}
static struct
{
int name;
UINT flag;
} DMCAPZ[]=
{
/*
#define DMUS_PC_DLS (0x00000001) // Supports DLS downloading and DLS level 1.
#define DMUS_PC_EXTERNAL (0x00000002) // External MIDI module.
#define DMUS_PC_SOFTWARESYNTH (0x00000004) // Software synthesizer.
#define DMUS_PC_MEMORYSIZEFIXED (0x00000008) // Memory size is fixed.
#define DMUS_PC_GMINHARDWARE (0x00000010) // GM sound set is built in, no need to download.
#define DMUS_PC_GSINHARDWARE (0x00000020) // GS sound set is built in.
#define DMUS_PC_XGINHARDWARE (0x00000040) // XG sound set is built in.
#define DMUS_PC_DIRECTSOUND (0x00000080) // Connects to DirectSound via a DSound buffer.
#define DMUS_PC_SHAREABLE (0x00000100) // Synth can be actively shared by multiple apps at once.
#define DMUS_PC_DLS2 (0x00000200) // Supports DLS2 instruments.
#define DMUS_PC_AUDIOPATH (0x00000400) // Multiple outputs can be connected to DirectSound for audiopaths.
#define DMUS_PC_WAVE (0x00000800) // Supports streaming and one shot waves.
*/
{STRING_DMCAPS_DLS1,DMUS_PC_DLS},
{STRING_DMCAPS_DLS2,DMUS_PC_DLS2},
{STRING_DMCAPS_SOFTSYNTH,DMUS_PC_SOFTWARESYNTH},
{STRING_DMCAPS_GM,DMUS_PC_GMINHARDWARE},
{STRING_DMCAPS_GS,DMUS_PC_GSINHARDWARE},
{STRING_DMCAPS_XG,DMUS_PC_XGINHARDWARE},
// {STRING_DMCAPS_DSOUND,DMUS_PC_DIRECTSOUND},
{STRING_DMCAPS_SHARE,DMUS_PC_SHAREABLE},
};
#define N_DMCAPZ (sizeof(DMCAPZ)/sizeof(DMCAPZ[0]))
static struct
{
int name;
UINT flag;
} DMCAPZ1[]= //effects
{
{STRING_REVERB,DMUS_EFFECT_REVERB},
{STRING_CHORUS,DMUS_EFFECT_CHORUS},
};
#define N_DMCAPZ1 (sizeof(DMCAPZ1)/sizeof(DMCAPZ1[0]))
int player_dmusic::settime(int tm)
{
int rv;
#ifdef USE_LOG
log_write("player_dmusic::settime");
#endif
rtOffset=UInt32x32To64(tm,10000);
#ifdef USE_LOG
log_write("calling IDirectMusicPerformance::Stop()");
#endif
if (!paused)
{
#ifdef USE_LOG
log_write("IDirectMusicPerformance::Stop() returned");
#endif
if (pSS) {pSS->Release();pSS=0;}
}
// not ideal but a pause, seek and unpause seems to resolve a failed seek issue
// with the 'Direct Music / Microsoft Synthesizer' and 'streamed' output mode
pause();
MUSIC_TIME time=GetMTforMS(pSeg,tm);
rv = SUCCEEDED( pSeg->SetStartPoint(time) );
if (rv) mtOffset=time;
unpause();
if (!paused)
{
#ifdef USE_LOG
log_write("calling IDirectMusicPerformance::PlaySegment()");
#endif
pSS=0;
pPerf->PlaySegment(pSeg,0,0,&pSS);
if (pSS) pSS->GetStartTime(&mtStart);
pPerf->MusicToReferenceTime(mtStart,&rtStart);
}
return rv;
}
BOOL test_ins_dls(DWORD patch,IDirectMusicCollection* pDLS)
{
IDirectMusicInstrument *pi=0;
BOOL rv=0;
if (SUCCEEDED(pDLS->GetInstrument(patch,&pi)))
{
pi->Release();
rv=1;
}
return rv;
}
int test_drum_kit(DWORD no,IDirectMusicCollection* dls)
{
DWORD p=no|0x80000000;
if (pGM)
if (test_ins_dls(p,pGM)) return 1;
if (pCDLS)
if (test_ins_dls(p,pCDLS)) return 1;
if (dls)
if (test_ins_dls(p,dls)) return 1;
return 0;
}
void do_dls_check(DWORD * i,IDirectMusicCollection * dls)
{
start:
if (pGM)
if (test_ins_dls(*i,pGM)) return;
if (pCDLS)
if (test_ins_dls(*i,pCDLS)) return;
if (dls)
if (test_ins_dls(*i,dls)) return;
//hack hack hack
if (*i&0xFF00)
{
*i&=0xFF00FF;
goto start;
}
if (*i&0xFF0000)
{
*i&=0xFF;
return;
}
}
static cfg_int cfg_show_all("dmusic_show_all",0);
class MIDI_driver_dmusic : MIDI_driver
{
bool dm_inited;
virtual void do_init()
{
dm_inited=1;
try {
#ifdef USE_LOG
log_write("CoInitialize()");
#endif
CoInitialize(0);
#ifdef USE_LOG
log_write("CoCreateInstance / IDirectMusic");
#endif
IDirectMusic* pDM=0;
if (SUCCEEDED(CoCreateInstance(CLSID_DirectMusic,0,CLSCTX_INPROC,IID_IDirectMusic,(void**)&pDM)) && pDM)
{
#ifdef USE_LOG
log_write("IDirectMusic created OK");
#endif
DMUS_PORTCAPS dmpc;
memset(&dmpc,0,sizeof(dmpc));
dmpc.dwSize=sizeof(dmpc);
UINT np=0;
GUID def;
pDM->GetDefaultPort(&def);
while(1)
{
if (pDM->EnumPort(np++,&dmpc)==S_FALSE) break;
if (dmpc.dwClass==DMUS_PC_OUTPUTCLASS && (cfg_show_all || (dmpc.dwType!=DMUS_PORT_WINMM_DRIVER && dmpc.dwType==DMUS_PORT_KERNEL_MODE) || (dmpc.dwFlags&DMUS_PC_DLS) ))
{
wchar_t name_mbs[2*DMUS_MAX_DESCRIPTION] = {0};
wcsncpy(name_mbs,dmpc.wszDescription,256);
string_w info;
{
if (dmpc.dwType<3)
{
int dmport_types[3]={STRING_DMCAPS_WINMM,STRING_DMCAPS_USERMODE,STRING_DMCAPS_WDM};
info+=WASABI_API_LNGSTRINGW(STRING_DEVICE_TYPE);
info+=WASABI_API_LNGSTRINGW(dmport_types[dmpc.dwType]);
info+=L"\x0d\x0a";
}
UINT z;
for(z=0;z<N_DMCAPZ;z++)
{
if (dmpc.dwFlags & DMCAPZ[z].flag)
{
info+=WASABI_API_LNGSTRINGW(DMCAPZ[z].name);
info+=L"\x0d\x0a";
}
}
UINT n_effects=0;
for(z=0;z<N_DMCAPZ1;z++)
{
if (dmpc.dwEffectFlags&DMCAPZ1[z].flag)
{
info+=n_effects ? L", " : WASABI_API_LNGSTRINGW(STRING_EFFECTS);
info+=WASABI_API_LNGSTRINGW(DMCAPZ1[z].name);
n_effects++;
}
}
if (n_effects) info+=L"\x0d\x0a";
}
add_device(new MIDI_device_dmusic(dmpc.guidPort,0,dmpc.dwFlags,name_mbs,info));
if ((dmpc.dwFlags&DMUS_PC_DIRECTSOUND)&&(dmpc.dwFlags&DMUS_PC_SOFTWARESYNTH))
{
wcscat(name_mbs,WASABI_API_LNGSTRINGW(IDS_WITH_OUTPUT));
info+=WASABI_API_LNGSTRINGW(IDS_USES_WINAMPS_OUTPUT_PLUGINS);
add_device(new MIDI_device_dmusic(dmpc.guidPort,1,dmpc.dwFlags,name_mbs,info));
}
}
}
pDM->Release();
}
} catch(...) {
// bewm.
reset_devices();
}
}
virtual const wchar_t * get_name() {return L"DirectMusic";}
virtual GUID get_guid() {return dmusic_driver_guid;}
public:
MIDI_driver_dmusic() {dm_inited=0;}
protected:
void do_deinit()
{
if (!dm_inited) return;
if (pGM)
{
pGM->Release();
pGM=0;
}
if (pCDLS) {pCDLS->Release();pCDLS=0;}
if (pLoader) {pLoader->Release();pLoader=0;}
if (pPort) PortKill();
if (pDM)
{
pDM->Release();
pDM=0;
}
if (pPerf)
{
pPerf->CloseDown();
pPerf->Release();
pPerf=0;
}
CoUninitialize();
}
};
static MIDI_driver_dmusic midi_driver_dmusic;

View File

@ -0,0 +1,888 @@
#include "main.h"
#include "seq.h"
#include <math.h>
#include "resource.h"
// {76B6A32D-99A9-4d51-B1F5-DAD3F47FE75D}
static const GUID midiout_guid =
{ 0x76b6a32d, 0x99a9, 0x4d51, { 0xb1, 0xf5, 0xda, 0xd3, 0xf4, 0x7f, 0xe7, 0x5d } };
// {7F00BC9C-AEA3-472a-BBB9-D74ABD4FCA58}
static const GUID midiout_driver_guid =
{ 0x7f00bc9c, 0xaea3, 0x472a, { 0xbb, 0xb9, 0xd7, 0x4a, 0xbd, 0x4f, 0xca, 0x58 } };
static MMRESULT midiOutOpen_wrap(HMIDIOUT * hMo,int id)
{
try {
return midiOutOpen(hMo,(UINT)id,0,0,CALLBACK_NULL);
}
catch(...)
{
return -1;
}
}
class MIDI_device_midiout : public MIDI_device
{
private:
GUID guid;
UINT id;
DWORD flags;
UINT type;
virtual player_base * create();
virtual GUID get_guid() {return guid;}
virtual bool is_default() {return id==(UINT)(-1);}
virtual bool volctrl_happy() {return (type==7) && (flags & MIDICAPS_VOLUME);}
public:
MIDI_device_midiout(UINT p_id,DWORD p_flags,UINT p_type,const wchar_t * p_name,const wchar_t * p_info)
{
id=p_id;
guid = midiout_guid;
*(DWORD*)&guid+=id;
flags = p_flags;
type = p_type;
set_name(p_name);
set_info(p_info);
}
inline DWORD get_flags() {return flags;}
inline DWORD get_id() {return id;}
};
static void midiout_sysex(HMIDIOUT hMo,BYTE* p,UINT len)
{
MIDIHDR h;
ZeroMemory(&h,sizeof(h));
h.dwBytesRecorded=h.dwBufferLength=len;
h.lpData=(char*)p;
if (FAILED(midiOutPrepareHeader(hMo,&h,sizeof(h)))) {
#ifdef USE_LOG
log_write("unable to send sysex");
#endif
return;
}
if (SUCCEEDED(midiOutLongMsg(hMo,&h,sizeof(h))))
{
while(!(h.dwFlags&MHDR_DONE)) MIDI_callback::Idle();
}
midiOutUnprepareHeader(hMo,&h,sizeof(h));
//log_write("sysex sent OK");
}
void midiout_sysex(HMIDIOUT hMo,BYTE* p,UINT len);
static void sysex_startup_midiout(UINT m_id)
{
if (need_sysex_start())
{
// MessageBox(GetActiveWindow(),"blah",0,0);
HMIDIOUT hMo;
MMRESULT r=midiOutOpen_wrap(&hMo,m_id);
if (!r)
{
sysex_startup((SYSEXFUNC)midiout_sysex,hMo);
midiOutClose(hMo);
}
}
}
class midiout_volctrl
{
private:
HMIDIOUT hMo;
int vol,pan;
void _setvol();
static UINT map_vol(UINT volume,UINT scale);
public:
void volctrl_init(HMIDIOUT,MIDI_device_midiout*);
int volctrl_setvol(int);
int volctrl_setpan(int);
};
class player_midiout : public seq_base, private midiout_volctrl
{
public:
virtual ~player_midiout();
virtual int setvol(int i) {return volctrl_setvol(i);};
virtual int setpan(int i) {return volctrl_setpan(i);};
player_midiout(MIDI_device_midiout * p_dev)
{
dev=p_dev;
hMo=0;
}
int play();
private:
MIDI_device_midiout * dev;
HMIDIOUT hMo;
virtual void seq_shortmsg(DWORD msg) {midiOutShortMsg(hMo,msg);}
virtual void seq_sysex(BYTE* ptr,UINT len) {midiout_sysex(hMo,ptr,len);}
virtual int seq_play_start();
virtual void seq_play_stop();
};
int player_midiout::seq_play_start()
{
return 1;
}
void player_midiout::seq_play_stop()
{
if (hMo)
{
#ifdef USE_LOG
log_write("midiOutClose");
#endif
DWORD r=midiOutClose(hMo);
if (r==MIDIERR_STILLPLAYING)
{
log_write("still playing (?), calling midiOutReset");
midiOutReset(hMo);
r=midiOutClose(hMo);
}
#ifdef USE_LOG
if (r) log_write("warning: unable to close midiOut");
else log_write("midiOut closed OK");
#endif
}
hMo=0;
}
int player_midiout::play()
{
DWORD r=midiOutOpen_wrap(&hMo,dev->get_id());
if (r)
{
if (r!=-1) MIDI_core::MM_error(r);
return 0;
}
volctrl_init(hMo,dev);
if (!seq_cmd_start(0))
{
midiOutClose(hMo);
hMo=0;
return 0;
}
return 1;
}
player_midiout::~player_midiout()
{
#ifdef USE_LOG
log_write("shutting down midiOut");
#endif
seq_cmd_stop();
}
class MIDI_driver_midiout : MIDI_driver
{
virtual void do_init()
{
MIDIOUTCAPSW caps;
UINT n_mo_dev=midiOutGetNumDevs()+1;
UINT n;
for(n=0;n<n_mo_dev;n++)
{
midiOutGetDevCapsW(n-1,&caps,sizeof(MIDIOUTCAPSW));
//d.id = TYPE_MIDIOUT | n;
//d.name=(char*)_strdup(caps.szPname);
string_w info;
{
wchar_t moo[128], *t=0;
switch(caps.wTechnology)
{
case MOD_FMSYNTH:
t=WASABI_API_LNGSTRINGW_BUF(STRING_MOCAPS_FM,moo,128);
break;
case MOD_MAPPER:
t=WASABI_API_LNGSTRINGW_BUF(STRING_MOCAPS_MAPPER,moo,128);
break;
case MOD_MIDIPORT:
t=WASABI_API_LNGSTRINGW_BUF(STRING_MOCAPS_HWPORT,moo,128);
break;
case MOD_SQSYNTH:
t=WASABI_API_LNGSTRINGW_BUF(STRING_MOCAPS_SQUARE,moo,128);
break;
case MOD_SYNTH:
t=WASABI_API_LNGSTRINGW_BUF(STRING_MOCAPS_SYNTH,moo,128);
break;
case 6:
t=WASABI_API_LNGSTRINGW_BUF(STRING_MOCAPS_WAVETABLE,moo,128);
break;
case 7:
t=WASABI_API_LNGSTRINGW_BUF(STRING_DMCAPS_SOFTSYNTH,moo,128);
break;
default:
wsprintfW(moo,WASABI_API_LNGSTRINGW(STRING_UNKNOWN),caps.wTechnology);
t=moo;
break;
}
if (t)
{
info+=WASABI_API_LNGSTRINGW(STRING_DEVICE_TYPE);
info+=t;
info+=L"\x0d\x0a";
}
if (caps.dwSupport & MIDICAPS_STREAM)
{
info+=WASABI_API_LNGSTRINGW(STRING_DIRECT_MIDISTREAM);
info+=L"\x0d\x0a";
}
}
add_device(new MIDI_device_midiout(n-1,caps.dwSupport,caps.wTechnology,caps.szPname,info));
}
}
virtual const wchar_t * get_name() {return L"midiOut";}
virtual bool is_default() {return 1;}
virtual GUID get_guid() {return midiout_driver_guid;}
};
static MIDI_driver_midiout midi_driver_midiout;
#define WM_SEEK (WM_USER+4)
#define GET_TIME timeGetTime()
int IS_SPEC_C(int x);
#define BUF_MAX 0x1000//0x3C00
#define BUF_MAX_F (BUF_MAX+0x40)
#define N_BUFS 4
#define BUF_MASK (N_BUFS-1)
typedef struct
{
MIDIHDR h;
DWORD data[BUF_MAX_F];
} MIDIBUF;
class player_midistream : public player_base, private midiout_volctrl
{
public:
int gettime();
int settime(int);
void pause();
void unpause();
virtual int setvol(int i) {return volctrl_setvol(i);};
virtual int setpan(int i) {return volctrl_setpan(i);};
int play();
player_midistream(MIDI_device_midiout *);
~player_midistream();
private:
UINT renderbuf(MIDIHDR* buf,DWORD ts,UINT start,UINT end);
UINT renderbuf_seek(UINT start,UINT end);
void renderbuf_wait(MIDIHDR* buf,UINT len);
DWORD pos4time(DWORD t);
MIDI_device_midiout * dev;
UINT m_id;
UINT c_loop;
CSysexMap* smap;
HMIDISTRM hMo;
UINT n_events;
MIDI_EVENT* events;
DWORD tm_ofs,p_time;
UINT loop_start,total_len;
MIDIBUF hdrs[N_BUFS];
MIDIBUF seekbuf;
UINT cur_buf;
UINT in_mm,n_free;
DWORD ct,cp;
bool got_eof,paused,quitting;
UINT seek_to;
HWND wnd;
DWORD trd_id;
void do_bufs();
void buf_done(MIDIHDR*);
static LRESULT WINAPI midiOutProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp);
};
/*
static void _sysex(player_midistream* pl,BYTE* p,UINT len)
{//assumes thread to be OK
HMIDISTRM hMo=pl->hMo;
MIDIHDR h;
ZeroMemory(&h,sizeof(h));
h.dwUser=1;
DWORD l=12+len;
if (l&3) l=(l+4)&~3;
DWORD* ev=(DWORD*)alloca(l);
ev[0]=ev[1]=0;
ev[2]=MEVT_F_LONG|len;
memcpy(ev+3,p,len);
h.dwBytesRecorded=h.dwBufferLength=l;
h.lpData=(char*)ev;
if (FAILED(midiOutPrepareHeader((HMIDIOUT)hMo,&h,sizeof(h)))) return;
if (FAILED(midiStreamOut(hMo,&h,sizeof(h))))
{
midiOutUnprepareHeader((HMIDIOUT)hMo,&h,sizeof(h));
return;
}
pl->in_mm++;
do_messages(pl->wnd,(bool*)&h.dwUser);
log_write("sysex sent OK");
}*/
DWORD player_midistream::pos4time(DWORD t)
{
DWORD r=0;
while(r<n_events && events[r].tm<t) r++;
return r;
}
static cfg_int cfg_midistream_quick_seek("midistream_quick_seek",0);
void player_midistream::do_bufs()
{
if (seek_to!=-1)
{
UINT sp=pos4time(ct=seek_to);
if (!cfg_midistream_quick_seek)
{
UINT st=cp;
if (sp<cp) st=0;
if (renderbuf_seek(st,sp)!=-1)
{
if (!midiOutPrepareHeader((HMIDIOUT)hMo,&seekbuf.h,sizeof(MIDIHDR)))
{
if (!midiStreamOut(hMo,&seekbuf.h,sizeof(MIDIHDR)))
{
in_mm++;
}
else midiOutUnprepareHeader((HMIDIOUT)hMo,&seekbuf.h,sizeof(MIDIHDR));
}
}
}
cp=sp;
seek_to=-1;
}
while(n_free && !got_eof)
{
MIDIHDR* hdr=&hdrs[cur_buf].h;
cp=renderbuf(hdr,ct,cp,-1);
if (cp==-1)
{
if (loop_start!=-1 && c_loop>1)
{
c_loop--;
cp=pos4time(ct=loop_start);
continue;
}
else
{
got_eof=1;
if (cfg_eof_delay)
{
renderbuf_wait(hdr,cfg_eof_delay);
}
else break;
}
}
if (midiOutPrepareHeader((HMIDIOUT)hMo,hdr,sizeof(MIDIHDR)))
{
got_eof=1;
break;
}
if (midiStreamOut(hMo,hdr,sizeof(MIDIHDR)))
{
got_eof=1;
break;
}
cur_buf=(cur_buf+1)&BUF_MASK;
in_mm++;
n_free--;
if (!got_eof)
ct=cp ? events[cp-1].tm : 0;
}
}
UINT player_midistream::renderbuf(MIDIHDR* buf,DWORD ts,UINT start,UINT end)
{
UINT n=start;
UINT p=0;
DWORD* pEv=(DWORD*)buf->lpData;
UINT c_t=ts;
while(n<end && n<n_events && p<(BUF_MAX-3))
{
int dt=events[n].tm-c_t;
if (dt<0) dt=0;
pEv[p++]=dt;
c_t+=dt;
pEv[p++]=0;
if (events[n].ev&0x80000000)
{
SYSEX_ENTRY* se=&smap->events[events[n].ev&0x7FFFFFFF];
if (p+(se->len>>2)>=BUF_MAX)
{
p-=2;
break;
}
pEv[p++]=MEVT_F_LONG|se->len;
DWORD d=se->len>>2;
if (se->len&3)
{
pEv[p+(d++)]=0;
}
memcpy(pEv+p,smap->data+se->ofs,se->len);
p+=d;
}
else
{
pEv[p++]=events[n].ev;
}
n++;
}
if (p==0)
return -1;
buf->dwBufferLength=p<<2;
buf->dwBytesRecorded=p<<2;
buf->dwFlags=0;
return n;
}
void player_midistream::renderbuf_wait(MIDIHDR* buf,UINT len)
{
UINT p=0;
DWORD* pEv=(DWORD*)buf->lpData;
pEv[p++]=len<<3;
pEv[p++]=0;
pEv[p++]=MEVT_NOP<<24;
buf->dwBufferLength=p<<2;
buf->dwBytesRecorded=p<<2;
buf->dwFlags=0;
}
UINT player_midistream::renderbuf_seek(UINT start,UINT end)
{
BYTE ins_tab[16] = {0};
memset(ins_tab,-1,sizeof(ins_tab));
BYTE ctrl_tab[16][128] = {0};
memset(ctrl_tab,-1,sizeof(ctrl_tab));
UINT n=start;
DWORD* pEv=(DWORD*)seekbuf.h.lpData;
while(n<end)
{
DWORD ec=events[n].ev;
if (ec&0x80000000) {n++;continue;}
UINT ch,cd;
ch=ec&0xF;
cd=ec&0xF0;
if (cd==0xB0) ctrl_tab[ch][(ec>>8)&0x7F]=(BYTE)(ec>>16);
else if (cd==0xC0) ins_tab[ch]=(BYTE)(ec>>8);
n++;
}
UINT c;
UINT p=0;
for(c=0;c<16;c++)
{
for(n=0;n<128;n++)
{
if (!(ctrl_tab[c][n]&0x80))
{
pEv[p++]=0;
pEv[p++]=0;
pEv[p++]=0xB0|c|(n<<8)|(ctrl_tab[c][n]<<16);
}
if (p>=BUF_MAX)
goto q;
}
if (!(ins_tab[c]&0x80))
{
pEv[p++]=0;
pEv[p++]=0;
pEv[p++]=0xC0|c|(ins_tab[c]<<8);
}
if (p>=BUF_MAX)
goto q;
}
q:
if (p==0) return -1;
seekbuf.h.dwBufferLength=p<<2;
seekbuf.h.dwBytesRecorded=p<<2;
seekbuf.h.dwFlags=0;
return n;
}
void player_midistream::buf_done(MIDIHDR* h)
{
in_mm--;
midiOutUnprepareHeader((HMIDIOUT)hMo,h,sizeof(MIDIHDR));
if (h->dwUser)
{
h->dwUser=0;
return;
}
if (h==&seekbuf.h) return;
n_free++;
if (quitting) return;
if (!in_mm && got_eof)
MIDI_core::Eof();
else if (!got_eof)
{
do_bufs();
}
}
LRESULT WINAPI player_midistream::midiOutProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
{
if (msg==MM_MOM_DONE)
{
player_midistream* p=(player_midistream*)GetWindowLong(wnd,0);
if (p) p->buf_done((MIDIHDR*)lp);
}
else if (msg==WM_SEEK)
{
player_midistream* p=(player_midistream*)GetWindowLong(wnd,0);
if (p) p->settime(lp);
}
return DefWindowProc(wnd,msg,wp,lp);
}
player_midistream::player_midistream(MIDI_device_midiout * p_dev)
{
dev=p_dev;
m_id=0;
c_loop=0;
smap=0;
hMo=0;
n_events=0;
events=0;
tm_ofs=0;p_time=0;
loop_start=0;
total_len=0;
memset(&hdrs,0,sizeof(hdrs));
memset(&seekbuf,0,sizeof(seekbuf));
cur_buf=0;
in_mm=0;n_free=0;
ct=0;cp=0;
got_eof=0;
paused=0;
quitting=0;
seek_to=0;
wnd=0;
trd_id=0;
static ATOM cb_class;
if (!cb_class) cb_class=do_callback_class(midiOutProc);
wnd=create_callback_wnd(cb_class,this);
c_loop=cfg_loop_infinite ? -1 : cfg_loop_count;
}
player_base* MIDI_device_midiout::create()
{
if (cfg_playback_mode)
{
player_midiout *p=new player_midiout(this);
if (p)
{
if (!p->play()) {delete p;p=0;}
}
return p;
}
else
{
player_midistream *p=new player_midistream(this);
if (p)
{
if (!p->play()) {delete p;p=0;}
}
return p;
}
}
//extern bool cfg_alt_sysex;
int player_midistream::play()
{
trd_id=GetCurrentThreadId();
UINT n;
for(n=0;n<N_BUFS;n++)
{
hdrs[n].h.lpData=(char*)hdrs[n].data;
}
seekbuf.h.lpData=(char*)seekbuf.data;
//bool alt_sysex=cfg_alt_sysex;
//if (alt_sysex)
{
sysex_startup_midiout(dev->get_id());
}
#ifdef USE_LOG
log_write("starting midiOut / streamed");
#endif
{
UINT id=dev->get_id();
DWORD err=midiStreamOpen(&hMo,&id,1,(DWORD)wnd,0,CALLBACK_WINDOW);
if (err)
{
MIDI_core::MM_error(err);
return 0;
}
MIDIPROPTIMEDIV td;
td.cbStruct=sizeof(td);
td.dwTimeDiv=1*8;//tix / q
err=midiStreamProperty(hMo,(BYTE*)&td,MIDIPROP_SET|MIDIPROP_TIMEDIV);
if (err)
{
midiStreamClose(hMo);
MIDI_core::MM_error(err);
return 0;
}
MIDIPROPTEMPO tempo;
tempo.cbStruct=sizeof(tempo);
tempo.dwTempo=1000;//ns / q
err=midiStreamProperty(hMo,(BYTE*)&tempo,MIDIPROP_SET|MIDIPROP_TEMPO);
if (err)
{
midiStreamClose(hMo);
MIDI_core::MM_error(err);
return 0;
}
}
events=do_table(MIDI_core::getFile(),8,&n_events,&loop_start,0);
if (!events)
{
midiStreamClose(hMo);
hMo=0;
return 0;
}
total_len=events[n_events-1].tm>>3;
if (!cfg_nosysex && MIDI_core::getFile()->smap && MIDI_core::getFile()->smap->pos)
{
smap=MIDI_core::getFile()->smap;
}
else smap=0;
paused=0;
volctrl_init((HMIDIOUT)hMo,dev);
midiStreamPause(hMo);
//sysex_startup((SYSEXFUNC)midiout_sysex,hMo);
seek_to=-1;
tm_ofs=GET_TIME;
cur_buf=0;
in_mm=0;
n_free=N_BUFS;
ct=cp=0;
do_bufs();
#ifdef USE_LOG
log_write("started OK");
#endif
midiStreamRestart(hMo);
return 1;
}
player_midistream::~player_midistream()
{
// bool alt_sysex=cfg_alt_sysex;
#ifdef USE_LOG
log_write("shutting down midistream");
#endif
if (hMo)
{
//ASSERT(trd_id!=GetCurrentThreadId());
quitting=1;
#ifdef USE_LOG
log_write("midiStreamStop");
#endif
midiStreamStop(hMo);
// do_messages(wnd,(bool*)&in_mm);
if (n_free!=N_BUFS)
{
UINT n;
for(n=0;n<N_BUFS;n++)
{
if (hdrs[n].h.dwFlags&MHDR_PREPARED)
{
midiOutUnprepareHeader((HMIDIOUT)hMo,&hdrs[n].h,sizeof(MIDIHDR));
in_mm--;
n_free++;
}
}
}
#ifdef HUNT_LEAKS
if (n_free!=N_BUFS) Warning("Not all buffers collected.");
#endif
#ifdef USE_LOG
log_write("midiStreamClose");
#endif
midiStreamClose(hMo);
//if (midiStreamClose(hMo)) Warning(STRING_MIDISTREAM_WARNING);
}
if (events) free(events);
if (wnd) DestroyWindow(wnd);
#ifdef USE_LOG
log_write("midistream shut down");
#endif
}
int player_midistream::gettime()
{
DWORD ret;
if (paused) ret=p_time;
else if (!tm_ofs) ret=0;
else
{
ret=GET_TIME-tm_ofs;
if (loop_start!=-1 && ret>total_len)
{
UINT _ls=loop_start>>3;
ret=(ret-_ls)%(total_len-_ls)+_ls;
}
}
return ret;
}
int player_midistream::settime(int tm)
{
if (!paused)
{
if (trd_id==GetCurrentThreadId())
{
seek_to=tm<<3;
got_eof=0;
tm_ofs=GET_TIME-tm;
midiStreamStop(hMo);
midiStreamPause(hMo);
quitting=1;
do_messages(wnd,(bool*)&in_mm);
quitting=0;
do_bufs();
midiStreamRestart(hMo);
}
else PostMessage(wnd,WM_SEEK,0,tm);
}
else
{
p_time=tm;
}
return 1;
}
void player_midistream::pause()
{
p_time=GET_TIME-tm_ofs;
paused=1;
midiStreamPause(hMo);
}
void player_midistream::unpause()
{
tm_ofs=GET_TIME-p_time;
paused=0;
if (seek_to!=-1)
{
midiStreamStop(hMo);
midiStreamPause(hMo);
if (trd_id==GetCurrentThreadId())
{
quitting=1;
do_messages(wnd,(bool*)&in_mm);
quitting=0;
do_bufs();
}
}
midiStreamRestart(hMo);
}
UINT midiout_volctrl::map_vol(UINT volume,UINT scale)
{
double _vol=volume>0 ? 20*log10((double)volume/(double)scale) : -60.0;//in negative db
_vol=_vol/60.0+1;
if (_vol<0) _vol=0;
return (UINT)(_vol*(double)scale);
}
void midiout_volctrl::_setvol()
{
DWORD _vol=257*vol;
DWORD vol1=_vol,vol2=_vol;
if (pan!=666)
{
if (pan<0)
{
vol2=(vol2*(128+pan))>>7;
}
else if (pan>0)
{
vol1=(vol1*(128-pan))>>7;
}
}
if (cfg_logvol)
{
vol1=map_vol(vol1,0xFFFF);
vol2=map_vol(vol2,0xFFFF);
}
midiOutSetVolume((HMIDIOUT)hMo,(vol2<<16)|vol1);
}
void midiout_volctrl::volctrl_init(HMIDIOUT _hMo,MIDI_device_midiout * dev)
{
hMo=_hMo;
pan=(dev->get_flags()&MIDICAPS_LRVOLUME) ? MIDI_core::player_getPan() : 666;
vol=(dev->get_flags()&MIDICAPS_VOLUME) ? MIDI_core::player_getVol() : 666;
_setvol();
}
int midiout_volctrl::volctrl_setvol(int _vol)
{
if (vol!=666)
{
vol=_vol;
_setvol();
return 1;
}
else return 0;
}
int midiout_volctrl::volctrl_setpan(int _pan)
{
if (pan!=666)
{
pan=_pan;
_setvol();
return 1;
}
else return 0;
}

View File

@ -0,0 +1,224 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by in_midi.rc
//
#define IDS_NULLSOFT_MIDI_PLAYER_OLD 0
#define STRING_FILES_OTHER 2
#define IDRESET 3
#define IDS_TO_ENABLE_LYRICS_DISPLAY 3
#define IDS_INFORMATION 4
#define STRING_INCOMPLETE 5
#define STRING_TRACKS_FMT 6
#define IDS_MIDIS_ARE_NOT_BURNABLE 7
#define IDS_ABOUT_TITLE 9
#define IDS_NONE 10
#define IDS_STREAMED 11
#define IDS_IMMEDIATE 12
#define IDS_CONFIGURATION 13
#define IDS_TYPE 14
#define IDS_PREFS_DEVICE 15
#define IDS_PREFS_DISPLAY 16
#define IDS_PREFS_SAMPLING 17
#define IDS_PREFS_DIRECTMUSIC 18
#define IDS_PREFS_MISC 19
#define IDS_PREFS_FILE_TYPES 20
#define IDS_PREFS_FILES 21
#define IDS_PREFS_HARDWARE_SETUP 22
#define IDS_UNABLE_TO_LOAD_FILE 23
#define STRING_RETRIEVING_FILE 24
#define STRING_URL_ERROR 25
#define STRING_UNKNOWN_MMSYSTEM 26
#define STRING_MIDI_INFO_FMT2 27
#define STRING_MIDI_INFO_FMT1 28
#define STRING_BYTES_FMT 29
#define STRING_WRITE_ERROR_FMT 30
#define STRING_INFO_FORMAT_FMT 31
#define STRING_RMI_INFO_FMT 32
#define STRING_CONFIG_RESET 33
#define STRING_STEREO 34
#define STRING_MONO 35
#define STRING_VOLUME_AUTO 36
#define STRING_VOLUME_DRIVER_SPECIFIC 37
#define STRING_VOLUME_NONE 38
#define STRING_SAMP_SRC_DEFAULT 39
#define STRING_LOOP1 40
#define STRING_LOOP2 41
#define STRING_LOOP3 42
#define STRING_UNKNOWN 43
#define STRING_DIRECT_MIDISTREAM 44
#define STRING_MOCAPS_WAVETABLE 45
#define STRING_MOCAPS_SYNTH 46
#define STRING_MOCAPS_SQUARE 47
#define STRING_MOCAPS_MAPPER 48
#define STRING_MOCAPS_HWPORT 49
#define STRING_MOCAPS_FM 50
#define STRING_EFFECTS 51
#define STRING_DEVICE_TYPE 52
#define STRING_DMCAPS_WDM 53
#define STRING_DMCAPS_USERMODE 54
#define STRING_DMCAPS_WINMM 55
#define STRING_CHORUS 56
#define STRING_REVERB 57
#define STRING_DMCAPS_SHARE 58
#define STRING_DMCAPS_DSOUND 59
#define STRING_DMCAPS_XG 60
#define STRING_DMCAPS_GS 61
#define STRING_DMCAPS_GM 62
#define STRING_DMCAPS_SOFTSYNTH 63
#define STRING_DMCAPS_DLS2 64
#define STRING_DMCAPS_DLS1 65
#define STRING_FILES_SMF 66
#define STRING_FILES_CLONE 67
#define STRING_FILES_COMPRESSED 68
#define IDS_SYSEX_DATA 69
#define IDS_MIDI_HARDWARE_PRESETS 70
#define IDS_DLS_FILES 71
#define IDS_MIDI_FILES 72
#define IDS_COMPRESSED_MIDI_FILES 73
#define IDS_RMI_FILES 74
#define IDS_COMPRESSED_RMI_FILES 75
#define IDS_WITH_OUTPUT 76
#define IDS_STRING105 77
#define IDS_USES_WINAMPS_OUTPUT_PLUGINS 77
#define STRING_MS_FMT 78
#define STRING_BIT_FMT 79
#define IDS_FAMILY_STRING_MIDI 80
#define IDS_FAMILY_STRING_KARAOKE_MIDI 81
#define IDS_FAMILY_STRING_HMI_MIDI 82
#define IDS_FAMILY_STRING_EXTENDED_MIDI 83
#define IDS_FAMILY_STRING_MSS_MIDI 84
#define IDS_FAMILY_STRING_FINALE_MIDI 85
#define IDS_FAMILY_STRING_CREATIVE_MIDI 86
#define IDS_FAMILY_STRING_GENERAL_MIDI_DUMP 87
#define IDS_FAMILY_STRING_COMPRESSED_MIDI 88
#define IDS_FAMILY_STRING_COMPRESSED_HMI_MIDI 89
#define IDS_ABOUT 90
#define IDS_ABOUT_TEXT 90
#define IDD_CONFIG 101
#define IDD_INFO 102
#define IDD_CONFIG1 117
#define IDD_CONFIG2 118
#define IDD_CONFIG3 119
#define IDD_CONFIG4 120
#define IDD_CONFIG5 121
#define IDD_CONFIG6 122
#define IDD_SYSEX 123
#define IDD_EXT_IMM 124
#define IDD_CONFIG7 125
#define IDD_RMI_SHIZ 127
#define IDD_CONFIG8 128
#define IDD_LYRICS 129
#define IDC_PORT 1001
#define IDC_MS 1011
#define IDC_TIX 1012
#define IDC_FORMAT 1013
#define IDC_NTRAX 1014
#define IDC_TRAX 1017
#define IDC_COPYRIGHT 1018
#define IDC_COMMENT 1019
#define IDC_SUBJECT 1020
#define IDC_FREQ 1030
#define IDC_REVERB 1031
#define IDC_DLS_CB 1032
#define IDC_DLS 1033
#define IDC_DLS_B 1034
#define IDC_CHORUS 1036
#define IDC_SAVE 1040
#define IDC_RMI_CRAP 1041
#define IDC_SAMPLING_ENABLED 1041
#define IDC_RTFM 1050
#define IDC_EDIT1 1052
#define IDC_ARTIST 1054
#define IDC_LOOP 1055
#define IDC_DATE 1055
#define IDC_ALBUM 1056
#define IDC_LOOP_S 1057
#define IDC_SOFTWARE 1057
#define IDC_LOOP_S2 1058
#define IDC_TRACK 1058
#define IDC_FSIZE 1059
#define IDC_ENGINEER 1059
#define IDC_COMPOSER 1060
#define IDC_NAME 1071
#define IDC_SAMPLING_DSP 1072
#define IDC_SAMPLING_OUTPUT 1073
#define IDC_STATIC1 1075
#define IDC_STATIC2 1077
#define IDC_STATIC3 1079
#define IDC_DEV_INFO 1081
#define IDC_INFINITE 1084
#define IDC_LOOP_T 1086
#define IDC_LOOP_SP 1088
#define IDC_LOOP_S3 1089
#define IDC_WAVEIN 1090
#define IDC_WAVEIN_SRC 1094
#define IDC_HACK_NO_SYSEX 1096
#define IDC_PLAYBACK_METHOD 1107
#define IDC_TAB 1108
#define IDC_STATIC_CLN 1124
#define IDC_STATIC_MOS 1126
#define IDC_IMP_F 1127
#define IDC_EXP_F 1128
#define IDC_IMP_PR 1129
#define IDC_EXP_PR 1130
#define IDC_SYSEX_EDIT 1131
#define IDC_SYSEX_DELETE 1132
#define IDC_SYSEX_ADD 1133
#define IDC_SYSEX_LIST 1134
#define IDC_DELAY 1135
#define IDC_SYSEX_UP 1136
#define IDC_SPIN1 1137
#define IDC_SYSEX_DOWN 1138
#define IDC_STATIC_MOS1 1139
#define IDC_NOVOL 1140
#define IDC_DM_IMM 1141
#define IDC_HACK_DM_RESETS 1142
#define IDC_TEMPO 1145
#define IDC_SHOW_PANEL 1146
#define IDC_TDISP 1147
#define IDC_ALL_ON 1180
#define IDC_ALL_OFF 1181
#define IDC_GMRESET 1182
#define IDC_GSRESET 1183
#define IDC_DM_KEEP_PORT 1184
#define IDC_XGRESET 1185
#define IDC_EXTS_LIST 1207
#define IDC_EXTS_ED 1208
#define IDC_SYSEX1 1215
#define IDC_SYSEX1_SEND 1216
#define IDC_VOLMODE 1217
#define IDC_HARDWARE_RESET 1218
#define IDC_SYSEX2 1221
#define IDC_SYSEX2_SEND 1222
#define IDC_NOINS 1223
#define IDC_HACKTRACK 1225
#define IDC_HACK_DLS_DRUMS 1226
#define IDC_HACK_XG_DRUMS 1228
#define IDC_HACK_DLS_INSTRUMENTS 1229
#define IDC_WAVEIN_SR 1234
#define IDC_WAVEIN_CH 1235
#define IDC_WAVEIN_BPS 1236
#define IDC_WAVEIN_S2 1237
#define IDC_DISP 1238
#define IDC_GENRE 1241
#define IDC_EOF_DELAY 1242
#define IDC_EOF_DELAY_SPIN 1243
#define IDC_LOGVOL 1244
#define IDC_BLAH 1245
#define IDC_BMPVIEW 1251
#define IDC_SAMP_REVERT 1261
#define IDC_RMI_DEF 2000
#define IDC_RMI_FMT 2002
#define IDC_LYRICS_ENABLED 2003
#define IDS_NULLSOFT_MIDI_PLAYER 65534
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 109
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@ -0,0 +1,333 @@
#include "main.h"
#include <ks.h>
#include <ksmedia.h>
#include <malloc.h>
static void make_wfx(WAVEFORMATEX * wfx,int srate,int nch,int bps)
{
wfx->wFormatTag=WAVE_FORMAT_PCM;
wfx->nChannels=nch;
wfx->nSamplesPerSec=srate;
wfx->nAvgBytesPerSec=srate*nch*(bps>>3);
wfx->nBlockAlign=nch * (bps>>3);
wfx->wBitsPerSample=bps;
wfx->cbSize=0;
}
static void make_wfxe(WAVEFORMATEXTENSIBLE * wfx,int srate,int nch,int bps)
{
make_wfx(&wfx->Format,srate,nch,bps);
wfx->Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE;
wfx->Format.cbSize=22;
wfx->Samples.wReserved=0;
wfx->dwChannelMask=0;
wfx->SubFormat=KSDATAFORMAT_SUBTYPE_PCM;
}
#ifndef IN_MIDI_NO_WAVEIN_SOURCE
extern cfg_int cfg_samp_revert;
#define MMBOOL MIXERCONTROLDETAILS_BOOLEAN
static MMBOOL *do_mixer_shit(DWORD param,DWORD type,BOOL store,UINT input,MMBOOL *tab)
{
UINT id=0;
mixerGetID((HMIXEROBJ)param,&id,type);
MIXERCAPS caps;
mixerGetDevCaps(id,&caps,sizeof(caps));
MIXERLINE ml;
ZeroMemory(&ml,sizeof(ml));
ml.cbStruct=sizeof(ml);
ml.dwComponentType=MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
mixerGetLineInfo((HMIXEROBJ)id,&ml,MIXER_GETLINEINFOF_COMPONENTTYPE|MIXER_OBJECTF_MIXER);
MIXERLINECONTROLS cs;
MIXERCONTROL c;
ZeroMemory(&cs,sizeof(cs));
cs.cbStruct=sizeof(cs);
cs.cControls=1;
cs.dwLineID=ml.dwLineID;
cs.dwControlType=MIXERCONTROL_CONTROLTYPE_MUX;
cs.cbmxctrl=sizeof(c);
cs.pamxctrl=&c;
ZeroMemory(&c,sizeof(c));
c.cbStruct=sizeof(c);
if (!mixerGetLineControls((HMIXEROBJ)id,&cs,MIXER_OBJECTF_MIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE))
{
if (store)
{
if (!tab)
{
tab=(MMBOOL*)alloca(sizeof(MMBOOL)*c.cMultipleItems);
memset(tab,0,sizeof(MMBOOL)*c.cMultipleItems);
tab[input].fValue=1;
}
}
else
{
if (!tab) tab=new MMBOOL[c.cMultipleItems];
}
if (tab)
{
MIXERCONTROLDETAILS d;
d.cbStruct=sizeof(d);
d.dwControlID=c.dwControlID;
d.cbDetails=sizeof(MMBOOL);
d.cChannels=ml.cChannels;
d.cMultipleItems=c.cMultipleItems;
d.paDetails=tab;
if (store) mixerSetControlDetails((HMIXEROBJ)id,&d,MIXER_SETCONTROLDETAILSF_VALUE |MIXER_OBJECTF_MIXER);
else mixerGetControlDetails((HMIXEROBJ)id,&d,MIXER_GETCONTROLDETAILSF_VALUE |MIXER_OBJECTF_MIXER);
}
}
return tab;
}
#endif
class CVis : public CStream
{
private:
#ifndef IN_MIDI_NO_WAVEIN_SOURCE
MMBOOL * old_settings;
UINT wavein_id;
void src_init()
{
wavein_id=(UINT)cfg_wavein_dev;
if (cfg_wavein_src)
{
if (cfg_samp_revert) old_settings = do_mixer_shit(wavein_id,MIXER_OBJECTF_WAVEIN,0,0,0);
do_mixer_shit(wavein_id,MIXER_OBJECTF_WAVEIN,1,cfg_wavein_src-1,0);
}
}
void src_deinit()
{
if (old_settings)
{
do_mixer_shit(wavein_id,MIXER_OBJECTF_WAVEIN,1,0,old_settings);
delete[] old_settings;
old_settings=0;
}
}
#endif
bool eof;
public:
bool init(int p_srate,int p_nch,int p_bps);
void Eof() {eof=1;}
virtual void Pause(int);
virtual UINT ReadData(void*,UINT,bool*);
virtual void Flush();
virtual ~CVis();
CVis()
{
#ifndef IN_MIDI_NO_WAVEIN_SOURCE
old_settings=0;
#endif
eof=0;buffer=0;blox=0;hWi=0;}
private:
BYTE * buffer;
UINT bufsize;
UINT read_pos;
UINT data;
UINT blocksize;
HWAVEIN hWi;
WAVEHDR *blox;
UINT numblocks;
UINT cur_block,cur_done;
int paused;
UINT in_mm;
int srate,nch,bps;
// void on_done(WAVEBUFFER*);
};
void CVis::Flush()
{
if (paused) return;
waveInReset(hWi);
UINT n;
for(n=0;n<numblocks;n++)
{
blox[n].dwUser=0;
waveInAddBuffer(hWi,&blox[n],sizeof(WAVEHDR));
}
cur_block=0;
cur_done=0;
in_mm=numblocks;//added all blocks already
read_pos=0;
data=0;
waveInStart(hWi);
}
void CALLBACK waveInProc(HWAVEIN hWi,UINT msg,DWORD dwIns,DWORD p1,DWORD p2)
{
if (msg==WIM_DATA && p1)
{
((WAVEHDR*)p1)->dwUser=1;
}
}
bool CVis::init(int p_srate,int p_nch,int p_bps)
{
srate=p_srate;
nch=p_nch;
bps=p_bps;
blocksize=576 * (bps/8) * (nch);
if (cfg_sampout) blocksize<<=3;
numblocks=(2 * srate * nch * (bps>>3))/blocksize;
bufsize=numblocks*blocksize;
blox=new WAVEHDR[numblocks];
memset(blox,0,sizeof(WAVEHDR)*numblocks);
buffer=(BYTE*)malloc(bufsize);
try
{
WAVEFORMATEX wfx;
make_wfx(&wfx,srate,nch,bps);
if (waveInOpen(&hWi,cfg_wavein_dev,&wfx,(DWORD)waveInProc,0,CALLBACK_FUNCTION))
{
WAVEFORMATEXTENSIBLE wfxe = {0};
make_wfxe(&wfxe,srate,nch,bps);
if (waveInOpen(&hWi,cfg_wavein_dev,&wfxe.Format,(DWORD)waveInProc,0,CALLBACK_FUNCTION))
{
return 0;
}
}
} catch(...)//gay drivers etc
{
return 0;
}
#ifndef IN_MIDI_NO_WAVEIN_SOURCE
src_init();
#endif
UINT n;
for(n=0;n<numblocks;n++)
{
blox[n].lpData=(char*)(buffer+blocksize*n);
blox[n].dwBufferLength=blocksize;
waveInPrepareHeader(hWi,&blox[n],sizeof(WAVEHDR));
}
paused=0;
Flush();
#ifdef USE_LOG
log_write("sampling started OK");
#endif
return 1;
}
CVis::~CVis()
{
#ifdef USE_LOG
log_write("shutting down sampling");
#endif
if (hWi)
{
waveInReset(hWi);
UINT n;
for(n=0;n<numblocks;n++)
{
waveInUnprepareHeader(hWi,&blox[n],sizeof(WAVEHDR));
}
#ifndef IN_MIDI_NO_WAVEIN_SOURCE
src_deinit();
#endif
waveInClose(hWi);
hWi=0;
}
#ifdef USE_LOG
log_write("sampling shut down OK");
#endif
if (blox) delete[] blox;
if (buffer) free(buffer);
}
UINT CVis::ReadData(void * _dst,UINT bytes,bool * ks)
{
if (eof) return 0;
BYTE * dst=(BYTE*)_dst;
if (paused) return 0;
while(!*ks)
{
while(blox[cur_done].dwUser)
{
blox[cur_done].dwUser=0;
cur_done=(cur_done+1)%numblocks;
in_mm--;
data+=blocksize;
}
{
UINT d=data;
if (d)
{
if (d>bytes) d=bytes;
if (read_pos+d>bufsize)
{
UINT foo=bufsize-read_pos;
memcpy(dst,buffer+read_pos,foo);
memcpy(dst+foo,buffer,read_pos=d-foo);
}
else
{
memcpy(dst,buffer+read_pos,d);
read_pos+=d;
}
dst+=d;
data-=d;
bytes-=d;
}
}
{
UINT max=numblocks-(data+blocksize-1)/blocksize;
while(in_mm < max)
{
waveInAddBuffer(hWi,&blox[cur_block],sizeof(WAVEHDR));
cur_block=(cur_block+1)%numblocks;
in_mm++;
}
}
if (!bytes) break;
MIDI_callback::Idle();
}
return dst-(BYTE*)_dst;
}
void CVis::Pause(int b)
{
paused=b;
if (b)
{
waveInStop(hWi);
}
else
{
Flush();
}
}
CStream * sampling_create(int srate,int nch,int bps)
{
CVis * ptr = new CVis;
if (!ptr->init(srate,nch,bps))
{
delete ptr;
ptr=0;
}
return ptr;
}

View File

@ -0,0 +1,852 @@
#include "main.h"
#include "seq.h"
#include <commctrl.h>
#include <math.h>
#include "resource.h"
#ifdef SEQ_HAVE_PANEL
cfg_int cfg_seq_showpanel("seq_showpanel",0);
enum
{
ID_BASE = 0x6543,
MUTE_ID = ID_BASE,
VOL_ID = MUTE_ID+16,
INS_ID_P = VOL_ID+16,
INS_ID_B1 = INS_ID_P+16,
INS_ID_B2 = INS_ID_B1+16,
SPIN_ID = INS_ID_B2
};
static cfg_int cfg_ctrl_min("ctrl_min",0);
static float g_tempo=1;
static BOOL g_novol,g_noins;
static char sysex1[256],sysex2[256];
extern BYTE d_GMReset[6];
extern BYTE d_XGReset[9];
extern BYTE d_GSReset[11];
#endif
#define SEND_MSG(X) seq_shortmsg(preprocess(X))
#define _sysex(A,B) seq_sysex(A,B)
#define rsysex(A) seq_sysex(A,sizeof(A))
#ifdef SEQ_HAVE_PANEL
void seq_base::set_mute(UINT ch,BOOL st)
{
if (st)
{
mute_mask|=1<<ch;
seq_shortmsg(0x07B0|ch);
}
else
{
mute_mask&=~(1<<ch);
SEND_MSG(((DWORD)ctrl_tab[ch][7]<<16)|0x07B0|ch);
}
}
#endif
//debug hack
#if 0
#define timeGetTime timehack
static DWORD timehack()
{
static DWORD t;
return t++;
}
#endif
DWORD seq_base::get_time()
{
#ifndef SEQ_HAVE_PANEL
return timeGetTime()<<3;
#else
if (!hCtrl) return timeGetTime()<<3;//*8;
EnterCriticalSection(&tm_sec);
DWORD cur_t=timeGetTime();
if (!last_time_ms) last_time_ms=cur_t;
int d=cur_t-last_time_ms;
if (d<0) d=0;
last_time_ret+=(double)(d*8.0)*tempo;
last_time_ms=cur_t;
DWORD r=(DWORD)last_time_ret;
LeaveCriticalSection(&tm_sec);
return r;
#endif
}
#ifdef SEQ_HAVE_PANEL
BOOL CALLBACK seq_base::CtrlProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
{
seq_base* s;
if (msg==WM_INITDIALOG)
{
SetWindowLongPtr(wnd,DWLP_USER,lp);
s=(seq_base*)lp;
if (s) s->hCtrl=wnd;
}
else
{
#if defined(_WIN64)
s = (seq_base*)GetWindowLong(wnd, DWLP_USER);
#else
s = (seq_base*)GetWindowLong(wnd, DWL_USER);
#endif
}
if (s)
{
s->do_msg(msg,wp,lp);
}
return 0;
}
static float ui2tempo(int x)
{
return (float)pow(4.0,0.02*(float)(x-50));
}
static int tempo2ui(float x)
{
return 50+(int) ((50.0 / log(4.0)) * log(x) );
}
static void do_ttext(HWND w,float t)
{
char tx[32] = {0};
_itoa((UINT)(t*100.0),tx,10);
char* p=tx;
while(p && *p) p++;
*(p++)='%';
*p=0;
SetDlgItemTextA(w,IDC_TDISP,tx);
}
BYTE* read_sysex_edit(HWND w,UINT *siz);
void CreateControl(DWORD ex,HWND hCtrl,const char * cls,const char * name,DWORD style,UINT x,UINT y,UINT dx,UINT dy,HINSTANCE hDll,UINT id)
{
RECT r={(LONG)x,(LONG)y,(LONG)(x+dx),(LONG)(y+dy)};
MapDialogRect(hCtrl,&r);
HWND w = CreateWindowExA( ex, cls, name, WS_CHILD | WS_VISIBLE | style, r.left, r.top, r.right - r.left, r.bottom - r.top, hCtrl, 0, hDll, 0 ); // Must stay in ANSI
if (w)
{
if (id) SetWindowLong(w,GWL_ID,id);
SendMessage(w,WM_SETFONT,SendMessage(hCtrl,WM_GETFONT,0,0),MAKELONG(0,0));
}
}
static cfg_int cfg_ctrl_x("ctrl_x",0x80000000),cfg_ctrl_y("ctrl_y",0x80000000);
void seq_base::do_msg(UINT msg,WPARAM wp,LPARAM lp)
{
switch(msg)
{
case WM_CLOSE:
ShowWindow(hCtrl,SW_SHOWMINIMIZED);
break;
case WM_INITDIALOG:
{
HINSTANCE hCCdll=GetModuleHandle(TEXT("comctl32.dll"));
UINT n;
HWND w;
for(n=0;n<16;n++)
{
char tmp[16] = {0};
itoa(n,tmp,10);
CreateControl(0,hCtrl,TRACKBAR_CLASSA,0,TBS_VERT | TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,40+n*28,36,18,80,hCCdll,VOL_ID+n);
CreateControl(0,hCtrl,"STATIC",tmp,0,46+n*28,25,8,8,0,0);
CreateControl(0,hCtrl,"Button",0,BS_AUTOCHECKBOX | WS_TABSTOP,43+28*n,120,9,8,0,MUTE_ID+n);
CreateControl(WS_EX_CLIENTEDGE,hCtrl,"EDIT",0,ES_AUTOHSCROLL | ES_NUMBER,36+28*n,138,26,12,0,INS_ID_P+n);
CreateControl(0,hCtrl,"msctls_updown32",0,UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,0,0,0,0,0,SPIN_ID+n);
CreateControl(WS_EX_CLIENTEDGE,hCtrl,"EDIT",0,ES_AUTOHSCROLL | ES_NUMBER,36+28*n,150,26,12,0,INS_ID_B1+n);
CreateControl(0,hCtrl,"msctls_updown32",0,UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,0,0,0,0,0,SPIN_ID+n+16);
CreateControl(WS_EX_CLIENTEDGE,hCtrl,"EDIT",0,ES_AUTOHSCROLL | ES_NUMBER,36+28*n,162,26,12,0,INS_ID_B2+n);
CreateControl(0,hCtrl,"msctls_updown32",0,UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,0,0,0,0,0,SPIN_ID+n+32);
}
w=GetDlgItem(hCtrl,IDC_TEMPO);
SendMessage(w,TBM_SETRANGE,0,MAKELONG(0,100));
SendMessage(w,TBM_SETPOS,1,tempo2ui(tempo));
do_ttext(hCtrl,tempo);
if (cfg_ctrl_x!=0x80000000 && cfg_ctrl_y!=0x80000000)
{
int max_x=GetSystemMetrics(SM_CXSCREEN)-10,max_y=GetSystemMetrics(SM_CYSCREEN)-10;
if (cfg_ctrl_x>max_x) cfg_ctrl_x=max_x;
if (cfg_ctrl_y>max_y) cfg_ctrl_y=max_y;
SetWindowPos(hCtrl,0,cfg_ctrl_x,cfg_ctrl_y,0,0,SWP_NOZORDER|SWP_NOSIZE);
}
for(n=0;n<16;n++)
{
w=GetDlgItem(hCtrl,VOL_ID+n);
SendMessage(w,TBM_SETRANGE,1,MAKELONG(0,0x7f));
SendMessage(w,TBM_SETPOS,1,0x7f-90);
}
SendDlgItemMessage(hCtrl,IDC_NOVOL,BM_SETCHECK,novol,0);
SetDlgItemTextA(hCtrl,IDC_SYSEX1,sysex1);
SetDlgItemTextA(hCtrl,IDC_SYSEX2,sysex2);
for(n=0;n<48;n++)
{
SendDlgItemMessage(hCtrl,SPIN_ID+n,UDM_SETRANGE,0,MAKELONG(127,0));
}
for(n=0;n<16;n++)
{
SendDlgItemMessage(hCtrl,INS_ID_P+n,EM_LIMITTEXT,3,0);
SendDlgItemMessage(hCtrl,INS_ID_B1+n,EM_LIMITTEXT,3,0);
SendDlgItemMessage(hCtrl,INS_ID_B2+n,EM_LIMITTEXT,3,0);
}
initialized=1;
}
break;
case WM_COMMAND:
{
UINT n;
if (HIWORD(wp)==0)
{
if (wp==IDC_SYSEX1_SEND || wp==IDC_SYSEX2_SEND)
{
UINT sl;
BYTE* s=read_sysex_edit(GetDlgItem(hCtrl,(wp==IDC_SYSEX1_SEND)?IDC_SYSEX1:IDC_SYSEX2) , &sl);
if (s)
{
_sysex(s,sl);
free(s);
}
}
else if (wp==IDC_NOVOL)
{
novol=SendMessage((HWND)lp,BM_GETCHECK,0,0);
}
else if (wp==IDC_NOINS)
{
noins=SendMessage((HWND)lp,BM_GETCHECK,0,0);
}
else if (wp==IDC_ALL_ON)
{
UINT n;
for(n=0;n<16;n++)
{
if (mute_mask&(1<<n))
{
SendDlgItemMessage(hCtrl,MUTE_ID+n,BM_SETCHECK,0,0);
set_mute(n,0);
}
}
}
else if (wp==IDC_ALL_OFF)
{
UINT n;
for(n=0;n<16;n++)
{
if (!(mute_mask&(1<<n)))
{
SendDlgItemMessage(hCtrl,MUTE_ID+n,BM_SETCHECK,1,0);
set_mute(n,1);
}
}
}
else if (wp==IDC_GMRESET)
{
rsysex(d_GMReset);
}
else if (wp==IDC_GSRESET)
{
rsysex(d_GSReset);
}
else if (wp==IDC_XGRESET)
{
rsysex(d_XGReset);
}
else for(n=0;n<16;n++)
{
if (wp==MUTE_ID+n)
{
set_mute(n,SendMessage((HWND)lp,BM_GETCHECK,0,0));
break;
}
}
}
else if (HIWORD(wp)==EN_CHANGE)
{
if (initialized)
{
wp&=0xFFFF;
UINT n;
for(n=0;n<16;n++)
{
if (wp==INS_ID_P+n)
{
UINT p=GetDlgItemInt(hCtrl,wp,0,0)&0x7F;
if (p!=ins_tab[n])
{
ins_tab[n]=p;
SEND_MSG(0xC0|n|(p<<8));
}
break;
}
else if (wp==INS_ID_B1+n)
{
UINT p=GetDlgItemInt(hCtrl,wp,0,0)&0x7F;
if (p!=ctrl_tab[n][0])
{
ctrl_tab[n][0]=p;
SEND_MSG(0xB0|n|(p<<16));
SEND_MSG(0xC0|n|(ins_tab[n]<<8));
}
break;
}
else if (wp==INS_ID_B2+n)
{
UINT p=GetDlgItemInt(hCtrl,wp,0,0)&0x7F;
if (p!=ctrl_tab[n][0x20])
{
ctrl_tab[n][0x20]=p;
SEND_MSG(0x20B0|n|(p<<16));
SEND_MSG(0xC0|n|(ins_tab[n]<<8));
}
break;
}
}
}
}
}
break;
case WM_VSCROLL:
{
HWND sb=(HWND)lp;
if (sb)
{
UINT id=GetWindowLong(sb,GWL_ID);
UINT n;
for(n=0;n<16;n++)
{
if (id==VOL_ID+n)
{
UINT val=0x7f-SendMessage(sb,TBM_GETPOS,0,0);
ctrl_tab[n][7]=val;
SEND_MSG(0x7B0|n|(val<<16));
break;
}
}
}
}
break;
case WM_HSCROLL:
tempo=ui2tempo(SendDlgItemMessage(hCtrl,IDC_TEMPO,TBM_GETPOS,0,0));
do_ttext(hCtrl,tempo);
break;
}
}
#endif
seq_base::~seq_base()
{
#ifdef SEQ_HAVE_PANEL
if (hCtrl)
{
cfg_ctrl_min=!!IsIconic(hCtrl);
RECT r;
GetWindowRect(hCtrl,&r);
cfg_ctrl_x=r.left;
cfg_ctrl_y=r.top;
GetDlgItemTextA(hCtrl,IDC_SYSEX1,sysex1,256);
GetDlgItemTextA(hCtrl,IDC_SYSEX2,sysex2,256);
DestroyWindow(hCtrl);
DeleteCriticalSection(&tm_sec);
}
g_tempo=tempo;
g_novol=novol;
g_noins=noins;
#endif
if (events) free(events);
}
seq_base::seq_base()
{
mf=0;
kill=0;paused=0;
smap=0;
pan=0;vol=0;
seek_to=0;
n_events=0;
events=0;
c_loop=0;
loop_start=0;
memset(&notes,0,sizeof(notes));
memset(&ctrl_tab,0,sizeof(ctrl_tab));
memset(&ins_tab,0,sizeof(ins_tab));
tm_ofs=0;
p_time=0;
hTrd=0;
ins_set=0;
#ifdef SEQ_HAVE_PANEL
hCtrl=0;
tempo=g_tempo;
novol=g_novol;
noins=g_noins;
last_time_ms=0;
last_time_ret=0;
mute_mask=0;
initialized=0;
#endif
}
#define GET_TIME get_time()//timeGetTime()
int IS_SPEC_C(int x) {return (x>=0x60 && x<=0x65) || x==6 || x==26 || x>=120;}
#define n_sysex smap->pos
DWORD seq_base::preprocess(DWORD e)
{
BYTE t=(BYTE)(e&0xF0);
if (t==0xB0)
{
UINT v=(e>>16)&0xFF;
BYTE c=(BYTE)(e>>8);
#ifdef SEQ_HAVE_PANEL
if (c==7)
{
if (mute_mask&(1<<(e&0xF))) v=0;
}
#endif
e=(e&0xFFFF)|((v&0xFF)<<16);
}
else if (t==0xC0)
{
ins_set|=1<<(e&0xF);
}
return e;
}
void seq_base::send_sysex(int n)
{
#ifdef USE_LOG
log_write("send_sysex()");
#endif
if (!smap || n>=n_sysex) return;
_sysex(smap->data+smap->events[n].ofs,smap->events[n].len);
}
/*
void seq_base::reset_ins()
{
UINT n;
for(n=0;n<16;n++)
{
cb->shortmsg(0xC0|n);
}
}
*/
BOOL seq_base::do_ctrl(DWORD e)
{
BYTE tp=(BYTE)(e&0xF0);
BYTE ch=(BYTE)(e&0x0F);
if (tp==0xC0)
{
#ifdef SEQ_HAVE_PANEL
if (noins) return 0;
#endif
//if (!cfg_fctrl && (e>>8)==ins_tab[e&0xF]) return 0;
UINT val=e>>8;
ins_tab[ch]=val;
#ifdef SEQ_HAVE_PANEL
if (hCtrl) SetDlgItemInt(hCtrl,INS_ID_P+ch,val,0);
#endif
} else if (tp==0xB0)
{
UINT cn = (e>>8)&0x7F;
UINT val= (e>>16)&0x7F;
#ifdef SEQ_HAVE_PANEL
if (cn==0)
{
if (noins) return 0;
if (hCtrl) SetDlgItemInt(hCtrl,INS_ID_B1+ch,val,0);
}
else if (cn==0x20)
{
if (noins) return 0;
if (hCtrl) SetDlgItemInt(hCtrl,INS_ID_B2+ch,val,0);
}
else if (cn==7)
{
if (novol) return 0;
if (hCtrl) PostMessage(GetDlgItem(hCtrl,VOL_ID+(e&0xF)),TBM_SETPOS,1,0x7F-val);
}
else if (cn==0x27)
{
if (novol) return 0;
}
#endif
if (!IS_SPEC_C(cn)) ctrl_tab[e&0xF][cn]=val;
}
else if (tp==0x90)
{
if (!(ins_set&(1<<ch)))
{
SEND_MSG(0xC0|ch);
}
}
return 1;
}
void seq_base::reset()
{
int not,ch;
for(ch=0;ch<16;ch++)
{
if (ctrl_tab[ch][0x40])
{
seq_shortmsg(0x40B0|ch);
ctrl_tab[ch][0x40]=0;
}
if (ch==9) continue;
for(not=0;not<128;not++)
{
if (note_state(ch,not))
{
seq_shortmsg((not<<8)|0x80|ch);
note_off(ch,not);
}
}
}
}
int seq_base::note_state(int ch,int note)
{
UINT pos=(ch<<7)+note;
return notes[pos>>3]&(1<<(pos&0x7));
}
void seq_base::note_on(int ch,int note)
{
UINT pos=(ch<<7)+note;
notes[pos>>3]|=(1<<(pos&0x7));
}
void seq_base::note_off(int ch,int note)
{
UINT pos=(ch<<7)+note;
notes[pos>>3]&=~(1<<(pos&0x7));
}
UINT seq_base::do_seek(DWORD n,DWORD p)
{
UINT m,c;
BYTE _ctrl_tab[16][128] = {0};
BYTE _ins_tab[16] = {0};
memcpy(_ctrl_tab,ctrl_tab,sizeof(_ctrl_tab));
memcpy(_ins_tab,ins_tab,sizeof(_ins_tab));
if (n==0)
{
memset(ins_tab,0,sizeof(ins_tab));
for(m=0;m<16;m++)
{
_ctrl_tab[m][0]=_ctrl_tab[m][0x20]=0;
}
}
while(n<n_events && p>events[n].tm)
{
DWORD e=events[n].ev;
if (!(e&0x80000000))
{
if (do_ctrl(e))
{
if (((e&0xF0)==0xB0) && IS_SPEC_C((e>>8)&0xFF))
{
seq_shortmsg(e);
}
}
}
n++;
}
for(c=0;c<16;c++)
{
for(m=0;m<128;m++)
{
if (!IS_SPEC_C(m) && _ctrl_tab[c][m]!=ctrl_tab[c][m])
{
SEND_MSG(((DWORD)ctrl_tab[c][m]<<16)|(m<<8)|0xB0|c);
}
}
if (_ins_tab[c]!=ins_tab[c])
{
SEND_MSG(((DWORD)ins_tab[c]<<8)|0xC0|c);
}
}
return n;
}
DWORD WINAPI seq_base::seq_trd(void* p)
{
((seq_base*)p)->thread();
return 0;
}
void seq_base::sysexfunc(seq_base* cb,BYTE* s,UINT sz)
{
cb->seq_sysex(s,sz);
}
void seq_base::thread()
{
tm_ofs=-1;
if (seq_play_start())
{
sysex_startup((SYSEXFUNC)sysexfunc,this);
tm_ofs=GET_TIME;
DWORD pos=0;
while(!kill)
{
DWORD c_t=GET_TIME-tm_ofs;
if (paused)
{
reset();
while(paused && !kill) MIDI_callback::Idle();
if (kill) break;
tm_ofs=GET_TIME-c_t;
}
if (seek_to!=-1)
{
_seek:
DWORD _p=seek_to > c_t ? pos : 0;
c_t=seek_to;
seek_to=-1;
tm_ofs=GET_TIME-c_t;
reset();
pos=c_t ? do_seek(_p,c_t) : 0;
}
if (events[pos].tm+1600 < c_t)
{
reset();
pos=do_seek(pos,c_t);
}
while(pos<n_events && events[pos].tm<=c_t && !kill)
{
DWORD e=events[pos++].ev;
if (e)
{
if (e&0x80000000)
{
send_sysex(e&0x7FFFFFFF);
}
else
{
if ((e&0xF0)==0x90)
{
note_on(e&0xf,(e>>8)&0xFF);
}
else if ((e&0xF0)==0x80)
{
note_off(e&0xf,(e>>8)&0xFF);
}
if (do_ctrl(e))
SEND_MSG(e);
}
}
}
if (pos>=n_events || c_t >= events[n_events-1].tm)
{
if (loop_start!=-1 && (--c_loop))
{
c_t=loop_start;
tm_ofs=GET_TIME-c_t;
pos=do_seek(0,c_t);
continue;
}
if (cfg_eof_delay)
{
DWORD t=timeGetTime();
do
{
MIDI_callback::Idle();
} while(!kill && seek_to==-1 && t+cfg_eof_delay>timeGetTime());
if (seek_to!=-1) {
pos=0;
goto _seek;
}
}
if (!kill) MIDI_core::Eof();
break;
}
if (kill) break;
MIDI_callback::Idle();
}
reset();
}
seq_play_stop();
}
int seq_base::gettime()
{
if (paused)
return (seek_to==-1) ? seek_to>>3 : p_time;
else
return (GET_TIME-tm_ofs)>>3;
}
int seq_base::settime(int tm)
{
seek_to=tm<<3;
return 1;
}
void seq_base::pause()
{
paused=1;
p_time=GET_TIME-tm_ofs;
}
void seq_base::unpause()
{
paused=0;
}
int seq_base::seq_cmd_start(DWORD cflags)
{
mf=MIDI_core::getFile();
#ifdef SEQ_HAVE_PANEL
mute_mask=0;
#endif
c_loop=cfg_loop_infinite ? -1 : cfg_loop_count;
memset(notes,0,sizeof(notes));
memset(ctrl_tab,-1,sizeof(ctrl_tab));
memset(ins_tab,0,sizeof(ins_tab));
UINT n;
for(n=0;n<16;n++) ctrl_tab[n][7]=90;
events=do_table(mf,8,&n_events,&loop_start,cflags);
if (!events) return 0;
if (!cfg_nosysex && mf->smap && mf->smap->pos)
{
smap=mf->smap;
}
else smap=0;
kill=0;
seek_to=-1;
paused=0;
#ifdef SEQ_HAVE_PANEL
if (cfg_seq_showpanel)
{
InitializeCriticalSection(&tm_sec);
WASABI_API_CREATEDIALOGPARAMW(IDD_EXT_IMM, MIDI_callback::GetMainWindow(), CtrlProc, (LPARAM)this);
ShowWindow(hCtrl,cfg_ctrl_min ? SW_SHOWMINIMIZED : SW_SHOW);
}
else
{
tempo=1;
novol=0;
noins=0;
}
#endif
DWORD id;
hTrd=CreateThread(0,0,seq_trd,this,CREATE_SUSPENDED,&id);
#ifndef _DEBUG
SetThreadPriority(hTrd,THREAD_PRIORITY_TIME_CRITICAL);
#endif
ResumeThread(hTrd);
return 1;
}
void seq_base::seq_cmd_stop()
{
#ifdef USE_LOG
log_write("stopping sequencer");
#endif
if (hTrd)
{
#ifdef USE_LOG
log_write("killing thread");
#endif
kill=1;
if (WaitForSingleObject(hTrd,4000)!=WAIT_OBJECT_0)
{
#ifdef USE_LOG
log_write("unable to kill thread");
#endif
TerminateThread(hTrd,0);
}
#ifdef USE_LOG
else log_write("thread killed normally");
#endif
CloseHandle(hTrd);
}
}
/*
void seq_base::enum_ins()
{
DWORD ttab[256];
memset(ttab,-1,sizeof(ttab));
UINT tpt=0;
UINT n;
DWORD c_ins[16];
memset(c_ins,0,sizeof(c_ins));
c_ins[9]=0x80000000;
for(n=0;n<n_events;n++)
{
DWORD t=events[n].ev;
if (t&0xFF000000) continue;
UINT c=t&0xF0;
UINT ch=events[n].ev&0xF;
if ((t&0xFFF0)==0x20B0)
{
c_ins[ch]=(c_ins[ch]&0xFFFF00FF)|((t>>8)&0xFF00);
}
else if ((t&0xFFF0)==0xB0)
{
c_ins[ch]=(c_ins[ch]&0xFF00FFFF)|(t&0xFF0000);
}
else if ((t&0xF0)==0xC0)
{
c_ins[ch]=(c_ins[ch]&0xFFFFFF00)|((t>>8)&0xFF);
}
else if ((t&0xF0)==0x90)
{
UINT n;
for(n=0;n<256;n++)
{
if (ttab[n]==c_ins[ch]) goto ok;
}
cb->enum_ins(ttab[tpt]=c_ins[ch]);
tpt=(tpt+1)&0xFF;
ok:;
}
}
}
*/

View File

@ -0,0 +1,75 @@
#define SEQ_HAVE_PANEL
class seq_base : public player_base
{
protected:
int seq_cmd_start(DWORD cflags);
void seq_cmd_stop();
virtual ~seq_base();
//OVERRIDE ME
virtual void seq_shortmsg(DWORD msg)=0;
virtual void seq_sysex(BYTE*,UINT)=0;
virtual int seq_play_start() {return 1;}
virtual void seq_play_stop() {}
seq_base();
private:
virtual int gettime();
virtual int settime(int);
virtual void unpause();
virtual void pause();
DWORD preprocess(DWORD e);
void send_sysex(int n);
// void reset_ins();
UINT do_sysex(UINT src,UINT tm);
BOOL do_ctrl(DWORD e);
void reset();
int note_state(int ch,int note);
void note_on(int ch,int note);
void note_off(int ch,int note);
UINT do_seek(DWORD n,DWORD p);
void thread();
DWORD get_time();
void get_ins(UINT c);
static DWORD WINAPI seq_trd(void* p);
static void sysexfunc(seq_base* cb,BYTE* s,UINT sz);
MIDI_file* mf;
bool kill,paused;
CSysexMap* smap;
int pan,vol;
UINT seek_to,n_events;
MIDI_EVENT* events;
UINT c_loop,loop_start;
BYTE notes[256];
BYTE ctrl_tab[16][128];
BYTE ins_tab[16];
DWORD tm_ofs,p_time;
HANDLE hTrd;
DWORD ins_set;
#ifdef SEQ_HAVE_PANEL
HWND hCtrl;
float tempo;
BOOL novol,noins;
DWORD last_time_ms;
double last_time_ret;
CRITICAL_SECTION tm_sec;
DWORD mute_mask;
bool initialized;
static BOOL CALLBACK CtrlProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp);
void do_msg(UINT msg,WPARAM wp,LPARAM lp);
void set_mute(UINT ch,BOOL st);
#endif
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,193 @@
#if !defined(_UTILS_H_INCLUDED_)
#define _UTILS_H_INCLUDED_
#include "../pfc/pfc.h"
class NOVTABLE CStream
{
public:
virtual UINT ReadData(void*,UINT,bool*)=0;
virtual void Flush()=0;
virtual ~CStream() {};
//for sampling
virtual void Pause(int) {};
virtual void Eof() {}
};
class CPipe : public CStream
{
BYTE* buf;
volatile UINT buf_s,buf_n,buf_rp,buf_wp;
critical_section sec;
UINT align;
volatile bool closed;
public:
void WriteData(void*,UINT);
UINT CanWrite() {return buf_s-buf_n;}
UINT ReadData(void*,UINT,bool*);
void Flush()
{
sec.enter();
buf_n=0;
sec.leave();
}
CPipe(UINT _align=4,UINT freq=44100)
{
buf_s=MulDiv(1024*256,freq,22050);
buf=(BYTE*)malloc(buf_s);
buf_wp=buf_rp=0;
buf_n=0;
align=_align;
closed=0;
}
~CPipe()
{
if (buf) free(buf);
}
void Eof() {closed=1;}
};
class MIDI_file;
#pragma pack(push)
#pragma pack(1)
typedef struct
{
WORD fmt,trax,dtx;
} MIDIHEADER;
#pragma pack(pop)
WORD _inline rev16(WORD x) {return (x>>8)|(x<<8);}
//#define rev16(X) (((X)&0xFF)<<8)|(((X)>>8)&0xFF)
DWORD _fastcall rev32(DWORD);
#define _rv(X) ((((DWORD)(X)&0xFF)<<24)|(((DWORD)(X)&0xFF00)<<8)|(((DWORD)(X)&0xFF0000)>>8)|(((DWORD)(X)&0xFF000000)>>24))
#define FixHeader(H) {(H).fmt=rev16((H).fmt);(H).trax=rev16((H).trax);(H).dtx=rev16((H).dtx);}
struct write_buf;
typedef struct
{
int pos,tm;
} TMAP_ENTRY;
struct CTempoMap
{
public:
TMAP_ENTRY *data;
int pos,size;
void AddEntry(int _p,int tm);
~CTempoMap() {if (data) free(data);}
int BuildTrack(grow_buf & out);
};
CTempoMap* tmap_merge(CTempoMap*,CTempoMap*);
typedef struct
{
int pos,ofs,len;
} SYSEX_ENTRY;
struct CSysexMap
{
public:
DWORD d_size,e_size;
SYSEX_ENTRY *events;
BYTE* data;
int pos,d_pos;
void CleanUp();
void AddEvent(const BYTE* e,DWORD s,DWORD t);
~CSysexMap();
CSysexMap* Translate(MIDI_file* _mf);//MIDI_file* mf
int BuildTrack(grow_buf & out);
const char* GetType();
};
typedef struct tagKAR
{
UINT time;
UINT start,end;
BOOL foo;
} KAR_ENTRY;
KAR_ENTRY * kmap_create(MIDI_file* mf,UINT prec,UINT * num,char** text);
CTempoMap* tmap_create();
CSysexMap* smap_create();
int EncodeDelta(BYTE* dst,int d);
unsigned int DecodeDelta(const BYTE* src,unsigned int* _d, unsigned int limit=-1);
int ReadSysex(const BYTE* src,int ml);
char* BuildFilterString(UINT res_id, char* ext, int* len);
BOOL DoOpenFile(HWND w,char* fn,UINT res_id,char* ext,BOOL save);
typedef void (*SYSEXFUNC)(void*,BYTE*,UINT);
void sysex_startup(SYSEXFUNC,void*);
void sysex_startup_midiout(UINT m_id);
bool need_sysex_start();
typedef struct
{
DWORD tm;
DWORD ev;
} MIDI_EVENT;
MIDI_EVENT* do_table(MIDI_file* mf,UINT prec,UINT * size,UINT* _lstart,DWORD cflags);
void gb_write_delta(grow_buf & gb,DWORD d);
void do_messages(HWND w,bool* br);
ATOM do_callback_class(WNDPROC p);
HWND create_callback_wnd(ATOM cl,void* p);
class sysex_table
{
private:
struct entry
{
entry * next;
int size,time;
BYTE * data;
};
entry * entries;
enum {MHP_MAGIC='0PHM'};
public:
sysex_table() {entries=0;}
~sysex_table() {reset();}
int num_entries() const;
int get_entry(int idx,BYTE ** p_data,int * p_size,int * p_time) const;
void insert_entry(int idx,BYTE * data,int size,int time);
int remove_entry(int idx);
inline void add_entry(BYTE * data,int size,int time) {insert_entry(num_entries(),data,size,time);}
inline void modify_entry(int idx,BYTE * data,int size,int time) {remove_entry(idx);insert_entry(idx,data,size,time);}
inline void reset() {while(entries) remove_entry(0);}
inline int get_time(int idx) const {int time;return get_entry(idx,0,0,&time) ? time : 0;}
int file_read(const char * path);
int file_write(const char * path) const;
void * memblock_write(int * size) const;
int memblock_read(const void * ptr,int size);
int print_preview(int idx,char * out) const;
void print_edit(int idx,HWND wnd) const;
void copy(const sysex_table & src);
sysex_table(const sysex_table & src) {entries=0;copy(src);}
sysex_table& operator=(const sysex_table & src) {copy(src);return *this;}
int is_empty() {return !entries;}
};
#endif

View File

@ -0,0 +1,39 @@
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
#include "../../../Winamp/buildType.h"
VS_VERSION_INFO VERSIONINFO
FILEVERSION 3,57,0,0
PRODUCTVERSION WINAMP_PRODUCTVER
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Winamp SA"
VALUE "FileDescription", "Winamp Input Plug-in"
VALUE "FileVersion", "3,57,0,0"
VALUE "InternalName", "Nullsoft MIDI Player"
VALUE "LegalCopyright", "Copyright <20> 2000-2023 Winamp SA"
VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
VALUE "OriginalFilename", "in_midi.dll"
VALUE "ProductName", "Winamp"
VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

View File

@ -0,0 +1,820 @@
#include "main.h"
#include "resource.h"
#include <shlwapi.h>
#include <api/service/waServiceFactory.h>
#include "../winamp/wa_ipc.h"
#include "../Agave/language/api_language.h"
#include "CompressionUtility.h"
#include "minizip/unzip.h"
static bool paused;
static int volume=255;
static int pan=0;
static string cur_file;
static HANDLE thread;
static HINSTANCE hRFdll;
static reader_source * pRF;
// wasabi based services for localisation support
api_language *WASABI_API_LNG = 0;
HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
#define IPC_GETHTTPGETTER 240
typedef int (*t_getf)(HWND hwnd, char *url, char *file, char *dlgtitle);
static WReader * get_reader(const char * fn);//wa2 hack
static int reader_process_file(WReader * r,const char * fn,void * &out_data, size_t &out_size)
{
void * data=0;
int size=0;
char ks=0;
if (r->Open((char*)fn,&ks))
return 0;
size = r->GetLength();
if (size==-1 || size<0x20)
return 0;
data=malloc(size);//scan funcs assume that theres at least 256 data
if (!data)
return 0;
if (r->Read((char*)data,size,&ks)!=size)
{
free(data);
return 0;
}
void* pvOut;
size_t nSizeOut = 0;
// GZIP
if (((*(DWORD*)data) & 0xFFFFFF) == 0x088b1f)
{
if (CompressionUtility::DecompressGZip(data, size, &pvOut, nSizeOut) >= 0)
{
out_data = pvOut;
out_size = nSizeOut;
return 1;
}
else
{
return 0;
}
}
// PKZIP
else if (*(DWORD*)data == 0x04034B50)
{
if (CompressionUtility::DecompressPKZip(fn, &pvOut, nSizeOut) >= 0)
{
out_data = pvOut;
out_size = nSizeOut;
return 1;
}
else
{
return 0;
}
}
out_size = size;
out_data = data;
return 1;
}
MIDI_file * wa2_open_file(const char * url)
{
WReader * r=get_reader(url);
if (!r) return 0;
void * data=0;
size_t size=0;
MIDI_file* mf=0;
if (reader_process_file(r,url,data,size))
{
mf=MIDI_file::Create(url,data,size);
free(data);
}
delete r;
return mf;
}
static void build_fmtstring();
static cfg_int cfg_mod_output("dev_output",1);
static void wa2_onCfgUpdate()
{
MIDI_device * dev = MIDI_driver::find_device(cfg_driver,cfg_device);
if (!dev)
{
dev = MIDI_driver::find_device_default();
}
//hack for wa2input.wac in wa3
mod.UsesOutputPlug=(dev->has_output() || (cfg_smp && cfg_sampout)) ? 1 : 0x8001;
cfg_mod_output=mod.UsesOutputPlug;
build_fmtstring();
}
static char fmts_string[1024];
#define NSEEK(a) {while(!(cfg_ext_mask&(1<<a)) && a<n_exts) a++;}
static void build_fmtstring()
{
UINT n_exts = MIDI_core::FileTypes_GetNum();
if (!cfg_ext_mask)
{
fmts_string[1]=fmts_string[0]=0;
return;
}
UINT n=0;
NSEEK(n);
const char* d=MIDI_core::FileTypes_GetDescription(n);
char* o=fmts_string;
while(1)
{
UINT f=n;
while(n<n_exts && d==MIDI_core::FileTypes_GetDescription(n))
{
const char * e=MIDI_core::FileTypes_GetExtension(n);
while(e && *e) *(o++)=*(e++);
n++;
NSEEK(n);
*(o++)=';';
}
o[-1]=0;
while(d && *d) *(o++)=*(d++);
*(o++)=' ';
*(o++)='(';
while(f<n)
{
const char * e=MIDI_core::FileTypes_GetExtension(f);
while(e && *e) *(o++)=*(e++);
f++;
NSEEK(f);
*(o++)=',';
}
o[-1]=')';
*(o++)=0;
if (n>=n_exts) break;
d=MIDI_core::FileTypes_GetDescription(n);
}
if (cfg_extra_exts.get_string().length()>0)
{
d=cfg_extra_exts;
while(d && *d) *(o++)=*(d++);
*(o++)=0;
d=WASABI_API_LNGSTRING(STRING_FILES_OTHER);
while(d && *d) *(o++)=*(d++);
d=cfg_extra_exts;
while(d && *d)
{
if (*d==';') *o=',';
else *o=*d;
o++;
d++;
}
*(o++)=')';
*(o++)=0;
}
*(o++)=0;
}
#undef NSEEK
static void Config(HWND p)
{
if (MIDI_core::Config(p))
{
MIDI_core::WriteConfig();
wa2_onCfgUpdate();
}
}
void About(HWND);
class CMemReader : public WReader
{
public:
BYTE* mem;
UINT sz;
UINT pos;
int Open(char *url, char *killswitch);
int Read(char *buffer, int length, char* killswitch) {if (!mem) return 0;if (length+pos>sz) length=sz-pos;memcpy(buffer,mem+pos,length);pos+=length;return length;}
int GetLength(void) {return sz;}
int CanSeek(void) {return 1;};
int Seek(int position, char*killswitch) {pos=position;return 0;};
CMemReader() {mem=0;sz=0;pos=0;}
~CMemReader() {if (mem) free(mem);}
};
static int Download(char* url,UINT* f_size,BYTE** m_buf)
{
typedef int (*t_getf)(HWND hwnd, char *url, char *file, char *dlgtitle);
t_getf getf;
int t=SendMessage(mod.hMainWindow,WM_USER,0,IPC_GETHTTPGETTER);
if (!t || t==1)
{
#ifndef WINAMPX
MessageBoxA(mod.hMainWindow,WASABI_API_LNGSTRING(STRING_URL_ERROR),ERROR,MB_ICONERROR);
#endif
return 0;
}
else
{
int rv=0;
char tmp[MAX_PATH] = {0};
get_temp_file(tmp);
HANDLE f;
DWORD br = 0,s = 0;
void* b;
getf=(t_getf)t;
if (getf(mod.hMainWindow,url,tmp,WASABI_API_LNGSTRING(STRING_RETRIEVING_FILE))) goto fail;
f=CreateFileA(tmp,GENERIC_READ,0,0,OPEN_EXISTING,0,0);
if (f==INVALID_HANDLE_VALUE) goto fail;
br=0;
s=GetFileSize(f,0);
if (!s) goto fail;
b=malloc(s);
if (!b) goto fail;
ReadFile(f,b,s,&br,0);
rv=1;
*f_size=br;
*m_buf=(BYTE*)b;
fail:
CloseHandle(f);
DeleteFileA(tmp);
return rv;
}
}
int CMemReader::Open(char* url,char*)
{
sz=pos=0;
if (mem) {free(mem);mem=0;}
HANDLE f=CreateFileA(url,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,0,OPEN_EXISTING,0,0);
if (f!=INVALID_HANDLE_VALUE)
{
sz=GetFileSize(f,0);
mem=(BYTE*)malloc(sz);
if (!mem) {CloseHandle(f);return 1;}
ReadFile(f,mem,sz,(DWORD*)&sz,0);
CloseHandle(f);
return 0;
}
return !Download(url,&sz,&mem);
}
class CFileReader : public WReader
{
public:
HANDLE f;
CFileReader() {f=0;};
~CFileReader() {if (f) CloseHandle(f);}
int Open(char *url, char*killswitch) {f=CreateFileA(url,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,0,OPEN_EXISTING,0,0);return f==INVALID_HANDLE_VALUE;}
int Read(char *buffer, int length, char*killswitch) {DWORD br=0;ReadFile(f,buffer,length,&br,0);return br;}
int GetLength(void) {return GetFileSize(f,0);}
int CanSeek(void) {return 1;};
int Seek(int position, char*killswitch) {SetFilePointer(f,position,0,FILE_BEGIN);return 0;}
};
static WReader *get_reader(const char* url)
{
if (!_strnicmp(url,"file://",7)) url+=7;
WReader* ret=0;
if (pRF && pRF->ismine((char*)url)) ret=pRF->create();
if (ret)
{
ret->m_player=0;
return ret;
}
if (_strnicmp(url,"http://",7)==0 || _strnicmp(url,"ftp://",6)==0 || _strnicmp(url,"https://",8)==0) return new CMemReader;
return new CFileReader();
}
int Init()
{
if (!IsWindow(mod.hMainWindow))
return IN_INIT_FAILURE;
// loader so that we can get the localisation service api for use
waServiceFactory *sf = mod.service->service_getServiceByGuid(languageApiGUID);
if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
// need to have this initialised before we try to do anything with localisation features
WASABI_API_START_LANG(mod.hDllInstance,InMidiLangGUID);
static wchar_t szDescription[256];
swprintf(szDescription,256,WASABI_API_LNGSTRINGW(IDS_NULLSOFT_MIDI_PLAYER),VER);
mod.description = (char*)szDescription;
MIDI_core::GlobalInit();
mod.UsesOutputPlug=cfg_mod_output;
build_fmtstring();
return IN_INIT_SUCCESS;
}
void Quit()
{
MIDI_core::GlobalQuit();
}
void GetFileInfo(const char *url, char *title, int *len)
{
if (!url || !*url)
{
url=cur_file;
}
if (len) *len=0;
if (title) *title=0;
char ks=0;
bool file_local=0;
MIDI_file * file=0;
if (MIDI_core::getFile() && !_stricmp(url,MIDI_core::getFile()->path))
{
file = MIDI_core::getFile()->AddRef();
}
if (!file)
{
file = wa2_open_file(url);
if (!file) {
return;
}
file_local=1;
}
if (len)
*len=file->GetLength();
if (title)
file->GetTitle(title,256);
file->Free();
}
BOOL CALLBACK InfoProc(HWND,UINT,WPARAM,LPARAM);
int show_rmi_info(HWND w,MIDI_file* mf);
int infoDlg(const char *fn, HWND hwnd)
{
int rv=1;
MIDI_file *mf=wa2_open_file(fn);
if (!mf) return INFOBOX_UNCHANGED;
if (cfg_rmi_def) rv=show_rmi_info(hwnd,mf);
else
{
rv = WASABI_API_DIALOGBOXPARAM(IDD_INFO,hwnd,InfoProc,(LPARAM)mf);
}
if (!rv && !_stricmp(mf->path,cur_file))
{
PostMessage(mod.hMainWindow,WM_USER,0,243);
}
mf->Free();
return rv;
}
int InfoBox(const char *file, HWND parent)
{
if (!file) file=cur_file;
return infoDlg(file,parent);
}
static char kill;
static int pos_ms;
static int seek_to;
static bool out_open;
DWORD WINAPI PlayThread(void*)
{
#ifdef USE_LOG
log_write("PlayThread");
#endif
short * visbuf;
char *sample_buf;
int sr,bps,nch;
pos_ms=0;
int pos_base=0;
int samp_wr=0;
int max_l=0;
MIDI_core::GetPCM(&sr,&nch,&bps);
int s_size=576 * (bps/8) * nch;
if (bps>16)
{
visbuf=(short*)malloc(576*2*nch);
}
else visbuf=0;
sample_buf = (char*)malloc(576 * 2 * (bps/8) * nch);
bool done=0;
while(!(kill&1))
{
#ifdef USE_LOG
log_write("main loop");
#endif
if (paused) {
#ifdef USE_LOG
log_write("paused");
#endif
Sleep(10);
continue;
}
if (seek_to!=-1)
{
#ifdef USE_LOG
log_write("seeking");
#endif
if (MIDI_core::SetPosition(seek_to))
{
pos_ms=seek_to;
if (out_open)
{
mod.outMod->Flush(pos_ms);
}
pos_base=pos_ms;
samp_wr=0;
done=0;
}
kill&=~2;
seek_to=-1;
}
if (done)
{
#ifdef USE_LOG
log_write("done");
#endif
if (!mod.outMod->IsPlaying())
{
PostMessage(mod.hMainWindow,WM_WA_MPEG_EOF,0,0);
break;
}
Sleep(10);continue;
}
#ifdef USE_LOG
log_write("calling GetSamples");
#endif
int l=MIDI_core::GetSamples(sample_buf,s_size,&kill);
if (kill&1) {
#ifdef USE_LOG
log_write("kill&1");
#endif
break;
}
if (kill&2) {
#ifdef USE_LOG
log_write("kill&2");
#endif
continue;
}
if (l<=0 && !paused)
{
#ifdef USE_LOG
log_write("done(?)");
#endif
done=1;
if (out_open)
{
mod.outMod->Write(sample_buf,0);
continue;
}
else
{
PostMessage(mod.hMainWindow,WM_WA_MPEG_EOF,0,0);
break;
}
}
if (mod.dsp_isactive())
{
#ifdef USE_LOG
log_write("DSP");
#endif
l=(8*l)/(bps*nch);
l=mod.dsp_dosamples((short*)sample_buf,l,bps,nch,sr);
l*=(nch*bps)/8;
}
if (out_open)
{
#ifdef USE_LOG
log_write("sending to output");
#endif
if (kill&1) break;
while(mod.outMod->CanWrite()<l && !kill) Sleep(2);
if (kill&1) break;
if (!kill) mod.outMod->Write((char*)sample_buf,l);
}
{
char * vis=sample_buf;
UINT vis_bps=bps;
if (bps>16)
{
int n;
UINT d=bps>>3;
char * foo=sample_buf+d-2;
for(n=0;n<576*nch;n++)
{
visbuf[n]=*(short*)foo;
foo+=d;
}
vis=(char*)visbuf;
vis_bps=16;
}
#ifdef USE_LOG
log_write("doing vis");
#endif
mod.SAAddPCMData(vis,nch,vis_bps,pos_ms);
mod.VSAAddPCMData(vis,nch,vis_bps,pos_ms);
}
samp_wr+=(8*l)/(bps*nch);
pos_ms=pos_base+MulDiv(1000,samp_wr,sr);
}
free(sample_buf);
if (visbuf) free(visbuf);
return 0;
}
int initDefaultDeviceShit()
{
//CT> find default device if no device set
MIDI_device * dev = MIDI_driver::find_device(cfg_driver,cfg_device);
if(dev) return 1;
//reinit to default
MIDI_driver *driver=MIDI_driver::driver_enumerate(0);
if(!driver) return 0;
MIDI_device *device=driver->device_enumerate(0);
if(!device) return 0;
cfg_driver=driver->get_guid();
cfg_device=device->get_guid();
return 1;
}
int Play(const char *fn)
{
if(!initDefaultDeviceShit()) return 0;
paused=0;
seek_to=-1;
kill=0;
if (!MIDI_core::Init()) return 0;
if (!MIDI_core::UsesOutput())
{
MIDI_core::SetVolume(volume);
MIDI_core::SetPan(pan);
}
else
{
MIDI_core::SetVolume(255);
MIDI_core::SetPan(0);
}
MIDI_file * file = wa2_open_file(fn);
if (!file) return -1;
int rv=MIDI_core::OpenFile(file);
file->Free();
if (rv==0)
{
MIDI_core::Close();
return 1;
}
cur_file=fn;
int sr,nch,bps;
MIDI_core::GetPCM(&sr,&nch,&bps);
{
MIDI_file * mf=MIDI_core::getFile();
UINT nc=0;
if (mf) nc=mf->info.channels;
mod.SetInfo(nc*10000,sr/1000,2,1);
}
if (MIDI_core::HavePCM())
{
int max_l=0;
MIDI_core::GetPCM(&sr,&nch,&bps);
if (MIDI_core::UsesOutput())
{
#ifdef USE_LOG
log_write("output init");
#endif
max_l=mod.outMod->Open(sr,nch,bps,-1,-1);
if (max_l<0)
{
MIDI_core::Close();
return 1;
}
out_open=1;
mod.outMod->SetVolume(volume);
mod.outMod->SetPan(pan);
}
mod.SAVSAInit(max_l,sr);
mod.VSASetInfo(sr,nch);
#ifdef USE_LOG
log_write("Creating thread");
#endif
DWORD id;
thread=CreateThread(0,0,PlayThread,0,CREATE_SUSPENDED,&id);
#ifndef _DEBUG
SetThreadPriority(thread,THREAD_PRIORITY_TIME_CRITICAL);
#endif
ResumeThread(thread);
}
else
{
#ifdef USE_LOG
log_write("threadless mode");
#endif
thread=0;
}
return 0;
}
void Pause()
{
if (MIDI_core::HavePlayer() && !paused)
{
MIDI_core::Pause(paused=1);
if (MIDI_core::UsesOutput()) mod.outMod->Pause(1);
}
}
void UnPause()
{
if (MIDI_core::HavePlayer() && paused)
{
MIDI_core::Pause(paused=0);
if (MIDI_core::UsesOutput())
{
mod.outMod->Flush(0);
mod.outMod->Pause(0);
}
}
}
int IsPaused()
{
return paused;
}
void Stop()
{
if (thread)
{
kill|=1;
WaitForSingleObject(thread,INFINITE);
CloseHandle(thread);
thread=0;
mod.SAVSADeInit();
if (out_open)
{
out_open=0;
mod.outMod->Close();
}
}
MIDI_core::Close();
}
void EQSet(int on, char data[10], int preamp)
{
}
int GetLength()
{
return MIDI_core::GetLength();
}
int GetOutputTime()
{
if (seek_to!=-1) return seek_to;
if (thread && MIDI_core::UsesOutput()) return pos_ms+mod.outMod->GetOutputTime()-mod.outMod->GetWrittenTime();
else return MIDI_core::GetPosition();
}
void SetOutputTime(int t)
{
if (thread)
{
seek_to=t;
kill|=2;
}
else MIDI_core::SetPosition(t);
}
void SetVolume(int v)
{
volume=v;
if (MIDI_core::UsesOutput()) mod.outMod->SetVolume(v);
else MIDI_core::SetVolume(v);
}
void SetPan(int p)
{
pan=p;
if (MIDI_core::UsesOutput()) mod.outMod->SetPan(p);
else MIDI_core::SetPan(p);
}
In_Module mod=
{
IN_VER_RET,
"nullsoft(in_midi.dll)",
0,0,
fmts_string,
1,
1,
Config,
About,
Init,
Quit,
GetFileInfo,
InfoBox,
MIDI_core::IsOurFile,
Play,
Pause,
UnPause,
IsPaused,
Stop,
GetLength,
GetOutputTime,
SetOutputTime,
SetVolume,
SetPan,
0,0,0,0,0,0,0,0,0,0,0,
EQSet,
0,
0,
};
extern "C"
{
__declspec( dllexport ) In_Module * winampGetInModule2()
{
return &mod;
}
}
void MIDI_callback::NotifyEOF() {PostMessage(mod.hMainWindow,WM_WA_MPEG_EOF,0,0);}
HWND MIDI_callback::GetMainWindow() {return mod.hMainWindow;}
HINSTANCE MIDI_callback::GetInstance() {return mod.hDllInstance;}
void MIDI_callback::Error(const char * tx)
{
#ifndef WINAMPX
MessageBoxA(mod.hMainWindow,tx,0,MB_ICONERROR);
#endif
}
BOOL APIENTRY DllMain(HANDLE hMod,DWORD r,void*)
{
if (r==DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls((HMODULE)hMod);
}
return 1;
}
void MIDI_callback::Idle(int ms)
{
int start = timeGetTime();
do Sleep(1); while( (int)timeGetTime() - start < ms);
}

View File

@ -0,0 +1,395 @@
#include "../studio/services/svc_mediaconverter.h"
#include "../studio/wac.h"
#include "../common/rootcomp.h"
#include "../studio/services/svc_action.h"
#include "../unpack/unpack_helper.h"
#include "main.h"
#define WACNAME WACcnv_midi
class WACNAME : public WAComponentClient{
public:
WACNAME();
virtual ~WACNAME();
virtual const char *getName() { return NAME; };
virtual GUID getGUID();
virtual void onCreate();
virtual void onDestroy();
virtual int getDisplayComponent() { return FALSE; };
virtual CfgItem *getCfgInterface(int n) { return this; }
private:
};
static WACNAME wac;
WAComponentClient *the = &wac;
// {28FDCD38-26A2-482c-A691-55901A355D9E}
static const GUID guid =
{ 0x28fdcd38, 0x26a2, 0x482c, { 0xa6, 0x91, 0x55, 0x90, 0x1a, 0x35, 0x5d, 0x9e } };
GUID WACNAME::getGUID() {
return guid;
}
static void update_extensions()
{
static int old_mask;
int new_mask = cfg_ext_mask;
int n;
for(n=0;n<MIDI_core::FileTypes_GetNum();n++)
{
int bit = 1<<n;
if ( (new_mask & bit) && !(old_mask & bit) )
api->core_registerExtension(StringPrintf("*.%s",MIDI_core::FileTypes_GetExtension(n)),MIDI_core::FileTypes_GetDescription(n),"Audio");
else if ( !(new_mask & bit) && (old_mask & bit) )
{
api->core_unregisterExtension(StringPrintf("*.%s",MIDI_core::FileTypes_GetExtension(n)));
}
}
old_mask = new_mask;
}
void WACNAME::onCreate()
{
// {EDAA0599-3E43-4eb5-A65D-C0A0484240E7}
static const GUID cfg_audio_guid =
{ 0xedaa0599, 0x3e43, 0x4eb5, { 0xa6, 0x5d, 0xc0, 0xa0, 0x48, 0x42, 0x40, 0xe7 } };
registerSkinFile("xml/midi-prefs.xml");
api->preferences_registerGroup("winamp.preferences.midi", "MIDI playback", guid, cfg_audio_guid);
MIDI_core::GlobalInit();
update_extensions();
}
void WACNAME::onDestroy() {
MIDI_core::GlobalQuit();
}
static void check_messages()
{
MSG msg;
while(PeekMessage(&msg,0,0,0,PM_REMOVE))
DispatchMessage(&msg);
}
//note: multiinstance support is NOT working, and will never be; it makes no sense anyway. also, multiinstance safety was totally fuct in directmusic drivers last time i bothered trying.
class cnv_MIDI : public svc_mediaConverterI {
private:
static critical_section core_owner_sync;
static cnv_MIDI * core_owner;
DWORD thread_id;
MemBlock<char> sample_buffer;
MIDI_file * file;
int is_open;
int eof_flag;
void core_reset()
{
core_owner_sync.enter();
if (core_owner==this) {core_owner=0;MIDI_core::Close();}
core_owner_sync.leave();
if (file) {file->Free();file=0;}
is_open=0;
eof_flag=0;
}
int core_takeover()
{
core_owner_sync.enter();
if (core_owner!=this)
{
if (core_owner!=0) {core_owner_sync.leave();return 0;}
core_owner=this;
thread_id = GetCurrentThreadId();
MIDI_core::Init();
}
core_owner_sync.leave();
return 1;
}
int check_file(MediaInfo * infos)
{
if (file && !STRICMP(file->path,infos->getFilename())) return 1;
core_reset();
MemBlock<char> data;
int size;
try {
svc_fileReader * reader = infos->getReader();
if (!reader) return 0;
size = reader->getLength();
if (size<=0) return 0;
reader->seek(0);
int firstread = size > 256 ? 256 : size;
data.setSize(firstread);
if (reader->read(data.getMemory(),firstread)!=firstread) return 0;
if (MIDI_file::HeaderTest(data.getMemory(),size))
{
if (firstread != size)
{
if (data.setSize(size)==0) return 0;
if (reader->read(data.getMemory()+firstread,size-firstread)!=size-firstread) return 0;
}
}
else
{
void * unpack = unpack_helper::unpack_getHandle(reader);
if (!unpack) return 0;
size = api->fileGetFileSize(unpack);
firstread = size > 256 ? 256 : size;
data.setSize(firstread);
if (api->fileRead(data.getMemory(),firstread,unpack)!=firstread) {api->fileClose(unpack);return 0;}
if (!MIDI_file::HeaderTest(data.getMemory(),size)) {api->fileClose(unpack);return 0;}
if (firstread != size)
{
if (data.setSize(size)==0) {api->fileClose(unpack);return 0;}
if (api->fileRead(data.getMemory()+firstread,size-firstread,unpack)!=size-firstread) {api->fileClose(unpack);return 0;}
}
api->fileClose(unpack);
}
file = MIDI_file::Create(infos->getFilename(),data.getMemory(),size);
return !!file;
}
catch(...)
{
file = 0;
return 0;
}
}
public:
static const char *getServiceName() { return NAME; }
cnv_MIDI()
{
file=0;
is_open=0;
eof_flag=0;
thread_id=0;
}
~cnv_MIDI()
{
core_reset();
}
virtual int canConvertFrom(svc_fileReader *reader, const char *name, const char *chunktype)
{
return reader && !chunktype && name && MIDI_core::IsOurFile(name);
}
virtual const char *getConverterTo()
{
if (!core_takeover()) return "FINAL";
return MIDI_core::UsesOutput() ? "PCM" : "FINAL";
}
virtual int getInfos(MediaInfo *infos)
{
if (!check_file(infos)) return 0;
infos->setTitle(Std::filename(file->path));
infos->setLength(file->len);
infos->setInfo(
StringPrintf("%sMIDI %i channels",
file->info.e_type ? StringPrintf("%s ",file->info.e_type) : ""
,file->info.channels)
);
return 1;
}
virtual int processData(MediaInfo *infos, ChunkList *chunk_list, bool *killswitch)
{
if (!check_file(infos)) return 0;
if (!core_takeover()) return 0;
if (!is_open)
{
MIDI_core::SetVolume(api->core_getVolume(m_coretoken));
MIDI_core::SetPan(api->core_getPan(m_coretoken));
if (!MIDI_core::OpenFile(file))
return 0;
is_open=1;
eof_flag=0;
}
check_messages();
if (!MIDI_core::HavePCM()) {Sleep(1);check_messages();return eof_flag ? 0 : 1;}
else
{
int srate,nch,bps;
int size;
MIDI_core::GetPCM(&srate,&nch,&bps);
size = 576 * nch * (bps/8);
if (sample_buffer.getSize()<size) sample_buffer.setSize(size);
size = MIDI_core::GetSamples(sample_buffer.getMemory(),size,(char*)killswitch);
if (size<=0)
return 0;
ChunkInfosI *ci=new ChunkInfosI();
ci->addInfo("srate",srate);
ci->addInfo("bps",bps);
ci->addInfo("nch",nch);
chunk_list->setChunk("PCM",sample_buffer.getMemory(),size,ci);
return 1;
}
}
virtual int getLatency(void) { return 0; }
// callbacks
virtual int corecb_onSeeked(int newpos)
{
if (core_owner==this) MIDI_core::SetPosition(newpos);
return 0;
}
int getPosition(void)
{
if (core_owner==this && !MIDI_core::UsesOutput()) return MIDI_core::GetPosition();
return -1;
}
virtual int corecb_onVolumeChange(int v)
{
if (core_owner==this) MIDI_core::SetVolume(v);
return 0;
}
virtual int corecb_onPanChange(int v)
{
if (core_owner==this) MIDI_core::SetPan(v);
return 0;
}
virtual int corecb_onAbortCurrentSong() {return 0;};
virtual int corecb_onPaused()
{
if (core_owner==this) MIDI_core::Pause(1);
return 0;
}
virtual int corecb_onUnpaused()
{
if (core_owner==this) MIDI_core::Pause(0);
return 0;
}
static void notify_eof()
{
core_owner_sync.enter();
if (core_owner) core_owner->eof_flag=1;
core_owner_sync.leave();
}
static DWORD get_core_thread()
{
DWORD ret = 0;
core_owner_sync.enter();
if (core_owner) ret = core_owner->thread_id;
core_owner_sync.leave();
return ret;
}
};
cnv_MIDI * cnv_MIDI::core_owner=0;
critical_section cnv_MIDI::core_owner_sync;
static waServiceFactoryT<svc_mediaConverter, cnv_MIDI> midi_svc;
#define ACTIONID_CONFIG "MIDI:CONFIG"
class MIDI_actions : public svc_actionI {
public:
MIDI_actions() {
registerAction(ACTIONID_CONFIG, 0);
}
virtual ~MIDI_actions() { }
virtual int onActionId(int id, const char *action, const char *param,int,int,void*,int,RootWnd*) {
switch (id) {
case 0:
if (!_stricmp(action,ACTIONID_CONFIG))
{
if (MIDI_core::Config(MIDI_callback::GetMainWindow()))
{
update_extensions();
}
}
return 1;
}
return 0;
}
static const char *getServiceName() { return "MIDI Player Actions Service"; }
};
static waServiceFactoryTSingle<svc_actionI, MIDI_actions> actions;
WACNAME::WACNAME() {
#ifdef FORTIFY
FortifySetName("cnv_midi.wac");
FortifyEnterScope();
#endif
registerService(&midi_svc);
registerService(&actions);
}
WACNAME::~WACNAME() {
#ifdef FORTIFY
FortifyLeaveScope();
#endif
}
void MIDI_callback::NotifyEOF() {cnv_MIDI::notify_eof();}
HWND MIDI_callback::GetMainWindow() {return api->main_getRootWnd()->gethWnd();}
HINSTANCE MIDI_callback::GetInstance() {return wac.gethInstance();}
void MIDI_callback::Error(const char * tx) {}
void MIDI_callback::Idle(int ms)
{
int core_thread = (GetCurrentThreadId() == cnv_MIDI::get_core_thread());
int start = timeGetTime();
do {
if (core_thread) check_messages();
Sleep(1);
} while((int)timeGetTime() - start < ms);
if (core_thread) check_messages();
}
extern "C" {
BOOL APIENTRY DllMain(HANDLE hMod,DWORD r,void*)
{
if (r==DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls((HMODULE)hMod);
}
return 1;
}
}

View File

@ -0,0 +1,310 @@
#include "main.h"
#include "cvt.h"
#pragma pack(push)
#pragma pack(1)
typedef struct
{
DWORD mthd,hdsize;
MIDIHEADER mhd;
} FILEHEADER;
typedef struct
{
DWORD mtrk,size;
} TRACKHEADER;
#pragma pack(pop)
struct XMI_cvt
{
public:
grow_buf out;
bool _end;
DWORD tr_sz;
DWORD cur_time,wr_time;
// DWORD loopstart;
bool hasevents;
void q_add(BYTE ch,BYTE note,DWORD tm);
void WriteDelta(DWORD _d);
void DoQueue();
DWORD ProcessNote(const BYTE* e);
DWORD ProcessDelta(const BYTE* d);
DWORD WriteEvent(const BYTE* e);
bool run(MIDI_file* mf,const BYTE*,DWORD);
#pragma pack(push)
#pragma pack(1)
#define Q_MAX 512
struct
{
DWORD time;
BYTE note;
BYTE channel;
} ch_q[Q_MAX];
#pragma pack(pop)
};
#define WriteBuf(A,B) out.write(A,B)
#define WriteBufB(A) out.write_byte(A)
#define WriteBufD(A) out.write_dword(A)
//WORD _fastcall rev16(WORD);
DWORD _fastcall rev32(DWORD);
#define FixHeader(H) {(H).fmt=rev16((H).fmt);(H).trax=rev16((H).trax);(H).dtx=rev16((H).dtx);}
#define MThd 'dhTM'
#define MTrk 'krTM'
#define EVNT 'TNVE'
void XMI_cvt::q_add(BYTE ch,BYTE note,DWORD tm)
{
UINT n,_n=-1;
for(n=0;n<Q_MAX;n++)
{
if (ch_q[n].note==note && ch_q[n].channel==ch && ch_q[n].time!=-1)
{
/*if (ch_q[n].time>tm) */ch_q[n].time=tm;
// q_notes++;
return;
}
else if (ch_q[n].time==-1) _n=n;
}
if (_n!=-1)
{
ch_q[_n].channel=ch;
ch_q[_n].time=tm;
ch_q[_n].note=note;
// q_notes++;
}
}
void XMI_cvt::WriteDelta(DWORD _d)
{
DWORD d=_d-wr_time;
wr_time=_d;
int st=out.get_size();
gb_write_delta(out,d);
tr_sz+=out.get_size()-st;
}
DWORD _inline ReadDelta1(const BYTE* d,DWORD* _l)
{
DWORD r=d[0],l=0;
while(!(d[l+1]&0x80))
{
r+=d[++l];
}
*_l=l+1;
return r;
}
void XMI_cvt::DoQueue()
{
while(1)
{
DWORD _i=-1;
DWORD _mt=-1;
UINT i;
for(i=0;i<Q_MAX;i++)
{
if (ch_q[i].time<_mt) {_i=i;_mt=ch_q[i].time;}
}
if (_mt<=cur_time)
{
WriteDelta(_mt);
BYTE t[3]={(BYTE)(0x80|ch_q[_i].channel),ch_q[_i].note,0};
WriteBuf(t,3);
ch_q[_i].time=-1;
tr_sz+=3;
// q_notes--;
}
else break;
}
}
DWORD XMI_cvt::ProcessNote(const BYTE* e)
{
DoQueue();
WriteDelta(cur_time);
WriteBuf(e,3);
tr_sz+=3;
DWORD l=3;
unsigned int _d;
l+=DecodeDelta(e+l,&_d);
if (e[2]) q_add(e[0]&0xF,e[1],cur_time+_d);
return l;
}
DWORD XMI_cvt::ProcessDelta(const BYTE* d)
{
DWORD l;
cur_time+=ReadDelta1(d,&l);
return l;
}
DWORD XMI_cvt::WriteEvent(const BYTE* e)
{
if ((e[0]&0xF0)==0xF0 && e[0]!=0xFF && e[0]!=0xF0)//hack
{
UINT l=1;
while(!(e[l]&0x80)) l++;
return l;
}
else if (e[0]==0xFF)
{
if (e[1]==0x2F)
{
DWORD _ct=cur_time;
cur_time=-2;
DoQueue();
// loopstart=_ct-wr_time;
cur_time=_ct;
DWORD _ev=0x002FFF00;
WriteBuf(&_ev,4);
tr_sz+=4;
_end=1;
return 3;
}
else
{
UINT l=e[2];
if (l&0x80)
{
l=((l<<7)|e[3])+1;
}
return 3+l;
}
}
DoQueue();
WriteDelta(cur_time);
if (e[0]==0xF0)
{
unsigned int d;
UINT l = 1 + DecodeDelta(e+1,&d);
l+=d;
WriteBuf(e,l);
tr_sz+=l;
return l;
}
DWORD l;
//hasevents=1;
if ((e[0]&0xF0)==0xC0 || (e[0]&0xF0)==0xD0) l=2;
else l=3;
WriteBuf(e,l);
tr_sz+=l;
return l;
}
BYTE xmi_track0[19]={'M','T','r','k',0,0,0,11,0,0xFF,0x51,0x03,0x20,0x8d,0xb7,0,0xFF,0x2F,0};
void ReleaseObject(IUnknown* o);
bool XMI_cvt::run(MIDI_file * mf,const BYTE* buf,DWORD sz)
{
// q_notes=0;
FILEHEADER fhd=
{
MThd,
0x06000000,
0x0100,0x0000,0x0001
};
WriteBuf(&fhd,sizeof(fhd));
UINT ptr=0x22;
DWORD _sz;
DWORD sp;
UINT ntrax=1;
WriteBuf(xmi_track0,sizeof(xmi_track0));
while(ptr<sz-4 && *(DWORD*)(buf+ptr)!=EVNT) ptr++;
if (*(DWORD*)(buf+ptr)!=EVNT) goto fail;
// loopstart=0;
_track:
cur_time=wr_time=0;
WriteBufD(_rv('MTrk'));
sp=out.get_size();
WriteBufD(0);
ntrax++;
tr_sz=0;
ptr+=4;
_sz=ptr+4+rev32(*(DWORD*)(buf+ptr));
if (_sz>sz+1) goto fail;
ptr+=4;
_end=0;
{
UINT n;
for(n=0;n<Q_MAX;n++) ch_q[n].time=-1;
}
hasevents=0;
while(ptr<sz-1 && !_end)
{
if ((buf[ptr]&0x80)==0)
{
ptr+=ProcessDelta(buf+ptr);
}
if ((buf[ptr]&0xF0)==0x90)
{
hasevents=1;
ptr+=ProcessNote(buf+ptr);
}
else ptr+=WriteEvent(buf+ptr);
}
if (!hasevents) {out.truncate(sp-4);ntrax--;}
else out.write_dword_ptr(rev32(tr_sz),sp);
if (ptr&1) ptr++;
if (ptr>=sz) goto _e;
if (*(DWORD*)(buf+ptr)==_rv('FORM') && *(DWORD*)(buf+ptr+8)==_rv('XMID'))
{
ptr+=12;
_te: if (ptr&1) ptr++;
if (*(DWORD*)(buf+ptr)==_rv('EVNT')) goto _track;
else if (*(DWORD*)(buf+ptr)==_rv('TIMB'))
{
ptr+=8+rev32(*(DWORD*)(buf+ptr+4));
if (ptr<sz) goto _te;
}
}
_e:
{
WORD w=rev16(ntrax);
out.write_ptr(&w,2,10);
if (ntrax>1)
w=0x200;
out.write_ptr(&w,2,8);
}
mf->size = out.get_size();
mf->data = (BYTE*)out.finish();
if (!mf->data) return 0;
// if (loopstart>0x10) mf->loopstart=loopstart;
#ifdef MF_USE_DMCRAP
if (sz>ptr+0x20 && *(DWORD*)(buf+ptr)==_rv('FORM') && *(DWORD*)(buf+ptr+8)==_rv('XDLS'))
{
DWORD rs=rev32(*(DWORD*)(buf+_sz+4));
if (rs+12+_sz>sz) goto _ret;
if (*(DWORD*)(buf+ptr+0x14)!=_rv('DLS ')) goto _ret;
mf->DLSsize=rs;
mf->pDLSdata=(BYTE*)malloc(rs);
memcpy(mf->pDLSdata,buf+_sz+12,rs);
}
#endif
_ret:
return 1;
fail:
return 0;
}
bool load_xmi(MIDI_file * mf,const BYTE* buf,size_t sz)
{
XMI_cvt c;
return c.run(mf,buf,sz);
}