Initial community commit
This commit is contained in:
270
Src/Plugins/Input/in_midi/CompressionUtility.cpp
Normal file
270
Src/Plugins/Input/in_midi/CompressionUtility.cpp
Normal 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;
|
||||
}
|
13
Src/Plugins/Input/in_midi/CompressionUtility.h
Normal file
13
Src/Plugins/Input/in_midi/CompressionUtility.h
Normal 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);
|
||||
};
|
||||
|
2
Src/Plugins/Input/in_midi/In2.h
Normal file
2
Src/Plugins/Input/in_midi/In2.h
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
#include "../Winamp/in2.h"
|
587
Src/Plugins/Input/in_midi/cleaner.cpp
Normal file
587
Src/Plugins/Input/in_midi/cleaner.cpp
Normal 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;
|
||||
}
|
48
Src/Plugins/Input/in_midi/cmf.cpp
Normal file
48
Src/Plugins/Input/in_midi/cmf.cpp
Normal 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;
|
||||
}
|
1072
Src/Plugins/Input/in_midi/config.cpp
Normal file
1072
Src/Plugins/Input/in_midi/config.cpp
Normal file
File diff suppressed because it is too large
Load Diff
61
Src/Plugins/Input/in_midi/core_api.h
Normal file
61
Src/Plugins/Input/in_midi/core_api.h
Normal 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
|
21
Src/Plugins/Input/in_midi/cvt.h
Normal file
21
Src/Plugins/Input/in_midi/cvt.h
Normal 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"
|
281
Src/Plugins/Input/in_midi/dmplugin.h
Normal file
281
Src/Plugins/Input/in_midi/dmplugin.h
Normal 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_ */
|
784
Src/Plugins/Input/in_midi/dmusicc.h
Normal file
784
Src/Plugins/Input/in_midi/dmusicc.h
Normal 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_ */
|
2373
Src/Plugins/Input/in_midi/dmusicf.h
Normal file
2373
Src/Plugins/Input/in_midi/dmusicf.h
Normal file
File diff suppressed because it is too large
Load Diff
1964
Src/Plugins/Input/in_midi/dmusici.h
Normal file
1964
Src/Plugins/Input/in_midi/dmusici.h
Normal file
File diff suppressed because it is too large
Load Diff
244
Src/Plugins/Input/in_midi/fakedsound.cpp
Normal file
244
Src/Plugins/Input/in_midi/fakedsound.cpp
Normal 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;}
|
3
Src/Plugins/Input/in_midi/fakedsound.h
Normal file
3
Src/Plugins/Input/in_midi/fakedsound.h
Normal file
@ -0,0 +1,3 @@
|
||||
IDirectSoundBuffer* dhb_create(DWORD size,DWORD freq);
|
||||
|
||||
IDirectSound * get_ds();
|
103
Src/Plugins/Input/in_midi/genres.c
Normal file
103
Src/Plugins/Input/in_midi/genres.c
Normal 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);
|
||||
}
|
3
Src/Plugins/Input/in_midi/genres.h
Normal file
3
Src/Plugins/Input/in_midi/genres.h
Normal file
@ -0,0 +1,3 @@
|
||||
void genres_read(HWND wnd);
|
||||
void genres_write(HWND wnd);
|
||||
#define MAX_GENRE 256
|
27
Src/Plugins/Input/in_midi/gmf.cpp
Normal file
27
Src/Plugins/Input/in_midi/gmf.cpp
Normal 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;
|
||||
}
|
2
Src/Plugins/Input/in_midi/guids.cpp
Normal file
2
Src/Plugins/Input/in_midi/guids.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#define INITGUID
|
||||
#include "main.h"
|
206
Src/Plugins/Input/in_midi/hmi.cpp
Normal file
206
Src/Plugins/Input/in_midi/hmi.cpp
Normal 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);
|
||||
}
|
149
Src/Plugins/Input/in_midi/hmp.cpp
Normal file
149
Src/Plugins/Input/in_midi/hmp.cpp
Normal 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;
|
||||
}
|
568
Src/Plugins/Input/in_midi/in_midi.rc
Normal file
568
Src/Plugins/Input/in_midi/in_midi.rc
Normal 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
|
||||
|
31
Src/Plugins/Input/in_midi/in_midi.sln
Normal file
31
Src/Plugins/Input/in_midi/in_midi.sln
Normal 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
|
328
Src/Plugins/Input/in_midi/in_midi.vcxproj
Normal file
328
Src/Plugins/Input/in_midi/in_midi.vcxproj
Normal 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>
|
143
Src/Plugins/Input/in_midi/in_midi.vcxproj.filters
Normal file
143
Src/Plugins/Input/in_midi/in_midi.vcxproj.filters
Normal 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>
|
940
Src/Plugins/Input/in_midi/info.cpp
Normal file
940
Src/Plugins/Input/in_midi/info.cpp
Normal 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
|
612
Src/Plugins/Input/in_midi/main.cpp
Normal file
612
Src/Plugins/Input/in_midi/main.cpp
Normal 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;
|
230
Src/Plugins/Input/in_midi/main.h
Normal file
230
Src/Plugins/Input/in_midi/main.h
Normal 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;
|
121
Src/Plugins/Input/in_midi/midi_driver.cpp
Normal file
121
Src/Plugins/Input/in_midi/midi_driver.cpp
Normal 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;
|
||||
}
|
||||
}
|
603
Src/Plugins/Input/in_midi/midifile.cpp
Normal file
603
Src/Plugins/Input/in_midi/midifile.cpp
Normal 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;
|
||||
}
|
89
Src/Plugins/Input/in_midi/midifile.h
Normal file
89
Src/Plugins/Input/in_midi/midifile.h
Normal 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
|
326
Src/Plugins/Input/in_midi/midiinfo.cpp
Normal file
326
Src/Plugins/Input/in_midi/midiinfo.cpp
Normal 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;
|
||||
}
|
2
Src/Plugins/Input/in_midi/midiout_helper.cpp
Normal file
2
Src/Plugins/Input/in_midi/midiout_helper.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "main.h"
|
||||
|
96
Src/Plugins/Input/in_midi/mids.cpp
Normal file
96
Src/Plugins/Input/in_midi/mids.cpp
Normal 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;
|
||||
}
|
184
Src/Plugins/Input/in_midi/mus.cpp
Normal file
184
Src/Plugins/Input/in_midi/mus.cpp
Normal 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);
|
||||
}
|
962
Src/Plugins/Input/in_midi/out_dmusic.cpp
Normal file
962
Src/Plugins/Input/in_midi/out_dmusic.cpp
Normal 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;
|
888
Src/Plugins/Input/in_midi/out_midi.cpp
Normal file
888
Src/Plugins/Input/in_midi/out_midi.cpp
Normal 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;
|
||||
}
|
224
Src/Plugins/Input/in_midi/resource.h
Normal file
224
Src/Plugins/Input/in_midi/resource.h
Normal 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
|
333
Src/Plugins/Input/in_midi/sampling.cpp
Normal file
333
Src/Plugins/Input/in_midi/sampling.cpp
Normal 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;
|
||||
}
|
852
Src/Plugins/Input/in_midi/seq.cpp
Normal file
852
Src/Plugins/Input/in_midi/seq.cpp
Normal 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(¬es,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:;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
75
Src/Plugins/Input/in_midi/seq.h
Normal file
75
Src/Plugins/Input/in_midi/seq.h
Normal 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
|
||||
};
|
1064
Src/Plugins/Input/in_midi/utils.cpp
Normal file
1064
Src/Plugins/Input/in_midi/utils.cpp
Normal file
File diff suppressed because it is too large
Load Diff
193
Src/Plugins/Input/in_midi/utils.h
Normal file
193
Src/Plugins/Input/in_midi/utils.h
Normal 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
|
39
Src/Plugins/Input/in_midi/version.rc2
Normal file
39
Src/Plugins/Input/in_midi/version.rc2
Normal 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
|
820
Src/Plugins/Input/in_midi/wa2.cpp
Normal file
820
Src/Plugins/Input/in_midi/wa2.cpp
Normal 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);
|
||||
}
|
395
Src/Plugins/Input/in_midi/wa3.cpp
Normal file
395
Src/Plugins/Input/in_midi/wa3.cpp
Normal 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;
|
||||
|
||||
}
|
||||
}
|
310
Src/Plugins/Input/in_midi/xmi.cpp
Normal file
310
Src/Plugins/Input/in_midi/xmi.cpp
Normal 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);
|
||||
}
|
Reference in New Issue
Block a user