aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Input/in_midi
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Input/in_midi
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Plugins/Input/in_midi')
-rw-r--r--Src/Plugins/Input/in_midi/CompressionUtility.cpp270
-rw-r--r--Src/Plugins/Input/in_midi/CompressionUtility.h13
-rw-r--r--Src/Plugins/Input/in_midi/In2.h2
-rw-r--r--Src/Plugins/Input/in_midi/cleaner.cpp587
-rw-r--r--Src/Plugins/Input/in_midi/cmf.cpp48
-rw-r--r--Src/Plugins/Input/in_midi/config.cpp1072
-rw-r--r--Src/Plugins/Input/in_midi/core_api.h61
-rw-r--r--Src/Plugins/Input/in_midi/cvt.h21
-rw-r--r--Src/Plugins/Input/in_midi/dmplugin.h281
-rw-r--r--Src/Plugins/Input/in_midi/dmusicc.h784
-rw-r--r--Src/Plugins/Input/in_midi/dmusicf.h2373
-rw-r--r--Src/Plugins/Input/in_midi/dmusici.h1964
-rw-r--r--Src/Plugins/Input/in_midi/fakedsound.cpp244
-rw-r--r--Src/Plugins/Input/in_midi/fakedsound.h3
-rw-r--r--Src/Plugins/Input/in_midi/genres.c103
-rw-r--r--Src/Plugins/Input/in_midi/genres.h3
-rw-r--r--Src/Plugins/Input/in_midi/gmf.cpp27
-rw-r--r--Src/Plugins/Input/in_midi/guids.cpp2
-rw-r--r--Src/Plugins/Input/in_midi/hmi.cpp206
-rw-r--r--Src/Plugins/Input/in_midi/hmp.cpp149
-rw-r--r--Src/Plugins/Input/in_midi/in_midi.rc568
-rw-r--r--Src/Plugins/Input/in_midi/in_midi.sln31
-rw-r--r--Src/Plugins/Input/in_midi/in_midi.vcxproj328
-rw-r--r--Src/Plugins/Input/in_midi/in_midi.vcxproj.filters143
-rw-r--r--Src/Plugins/Input/in_midi/info.cpp940
-rw-r--r--Src/Plugins/Input/in_midi/main.cpp612
-rw-r--r--Src/Plugins/Input/in_midi/main.h230
-rw-r--r--Src/Plugins/Input/in_midi/midi_driver.cpp121
-rw-r--r--Src/Plugins/Input/in_midi/midifile.cpp603
-rw-r--r--Src/Plugins/Input/in_midi/midifile.h89
-rw-r--r--Src/Plugins/Input/in_midi/midiinfo.cpp326
-rw-r--r--Src/Plugins/Input/in_midi/midiout_helper.cpp2
-rw-r--r--Src/Plugins/Input/in_midi/mids.cpp96
-rw-r--r--Src/Plugins/Input/in_midi/mus.cpp184
-rw-r--r--Src/Plugins/Input/in_midi/out_dmusic.cpp962
-rw-r--r--Src/Plugins/Input/in_midi/out_midi.cpp888
-rw-r--r--Src/Plugins/Input/in_midi/resource.h224
-rw-r--r--Src/Plugins/Input/in_midi/sampling.cpp333
-rw-r--r--Src/Plugins/Input/in_midi/seq.cpp852
-rw-r--r--Src/Plugins/Input/in_midi/seq.h75
-rw-r--r--Src/Plugins/Input/in_midi/utils.cpp1064
-rw-r--r--Src/Plugins/Input/in_midi/utils.h193
-rw-r--r--Src/Plugins/Input/in_midi/version.rc239
-rw-r--r--Src/Plugins/Input/in_midi/wa2.cpp820
-rw-r--r--Src/Plugins/Input/in_midi/wa3.cpp395
-rw-r--r--Src/Plugins/Input/in_midi/xmi.cpp310
46 files changed, 18641 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_midi/CompressionUtility.cpp b/Src/Plugins/Input/in_midi/CompressionUtility.cpp
new file mode 100644
index 00000000..2da502d3
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/CompressionUtility.cpp
@@ -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;
+}
diff --git a/Src/Plugins/Input/in_midi/CompressionUtility.h b/Src/Plugins/Input/in_midi/CompressionUtility.h
new file mode 100644
index 00000000..904dc25b
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/CompressionUtility.h
@@ -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);
+};
+
diff --git a/Src/Plugins/Input/in_midi/In2.h b/Src/Plugins/Input/in_midi/In2.h
new file mode 100644
index 00000000..a667545f
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/In2.h
@@ -0,0 +1,2 @@
+
+#include "../Winamp/in2.h" \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/cleaner.cpp b/Src/Plugins/Input/in_midi/cleaner.cpp
new file mode 100644
index 00000000..1c72c668
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/cleaner.cpp
@@ -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;
+}
diff --git a/Src/Plugins/Input/in_midi/cmf.cpp b/Src/Plugins/Input/in_midi/cmf.cpp
new file mode 100644
index 00000000..0eb4f552
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/cmf.cpp
@@ -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;
+} \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/config.cpp b/Src/Plugins/Input/in_midi/config.cpp
new file mode 100644
index 00000000..fa2fd8b1
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/config.cpp
@@ -0,0 +1,1072 @@
+#include "main.h"
+#include <shlobj.h>
+#include <commctrl.h>
+#include "resource.h"
+#include "../winamp/wa_ipc.h"
+#include "../pfc/string_unicode.h"
+
+static HWND g_theConfig;
+
+static struct
+{
+ HWND wnd;
+ int id;
+ UINT l_id;
+} child_dlgs[]={
+ {0,IDD_CONFIG1,IDS_PREFS_DEVICE},
+ {0,IDD_CONFIG8,IDS_PREFS_DISPLAY},
+ {0,IDD_CONFIG2,IDS_PREFS_SAMPLING},
+ {0,IDD_CONFIG3,IDS_PREFS_DIRECTMUSIC},
+ {0,IDD_CONFIG4,IDS_PREFS_MISC},
+ {0,IDD_CONFIG7,IDS_PREFS_FILE_TYPES},
+ {0,IDD_CONFIG5,IDS_PREFS_FILES},
+ {0,IDD_CONFIG6,IDS_PREFS_HARDWARE_SETUP},
+};
+
+enum
+{
+ IDC_CONFIG1,IDC_CONFIG8,IDC_CONFIG2,IDC_CONFIG3,IDC_CONFIG4,IDC_CONFIG7,IDC_CONFIG5,IDC_CONFIG6
+};
+
+static const char CFG_NAME[]="IN_MIDI";
+
+#define FILE_BLAH MessageBoxA(wnd,WASABI_API_LNGSTRING(IDS_UNABLE_TO_LOAD_FILE),0,MB_ICONERROR)
+
+int loop_txt[3]={STRING_LOOP1,STRING_LOOP2,STRING_LOOP3};
+
+#define MAKEID(X,Y) ( ( (DWORD)(X)<<16) | (DWORD)(Y)) //MAKEID(DLG_ID,CTRL_ID)
+
+extern cfg_int cfg_seq_showpanel;
+extern cfg_int cfg_lyrics;
+
+
+cfg_int cfg_smp("smp",0),cfg_reverb("reverb",0),cfg_chorus("chorus",0),cfg_dls_active("dls_active",0);
+
+cfg_int cfg_sampout("sampout",0);
+cfg_int cfg_hardware_reset("hardware_reset",0);
+cfg_int cfg_gm_reset("gm_reset",0),cfg_gm_reset1("gm_reset1",0);
+cfg_int cfg_gs_reset("gs_reset",0),cfg_gs_reset1("gs_reset1",0);
+cfg_int cfg_nosysex("nosysex",0);
+cfg_int cfg_dm_keep_port("dm_keep_port",0);
+cfg_int cfg_recover_tracks("recover_tracks",1);
+cfg_int cfg_rmi_def("rmi_def",0);
+cfg_int cfg_logvol("logvol",1);
+
+cfg_int cfg_ff7loopz("ff7loopz",1);
+cfg_int cfg_samp_revert("samp_revert",1);
+
+cfg_int cfg_hack_xg_drums("hack_xg_drums",0),cfg_hack_dls_instruments("hack_dls_instruments",1),cfg_hack_dls_drums("hack_dls_drums",1);
+
+static const WORD sr_tab[]={8000,11025,16000,22050,24000,32000,44100,48000};
+
+cfg_int cfg_cur_tab("cur_tab",0);
+
+cfg_int cfg_volmode("volmode",2);
+//0 - no volume, 1 - default, 2,3,4 ... - mixers
+cfg_string cfg_extra_exts("extra_exts","");
+
+cfg_int cfg_freq("freq",22050);
+cfg_int cfg_eof_delay("eof_delay",0);
+
+cfg_string cfg_dls_file("dls_file","");
+cfg_int cfg_bugged("bugged",0);
+
+cfg_int cfg_loop_type("loop_type",0),cfg_loop_count("loop_count",1),cfg_loop_infinite("loop_infinite",0);
+
+cfg_int cfg_wavein_dev("wavein_dev",-1),cfg_wavein_sr("wavein_sr",44100),cfg_wavein_ch("wavein_ch",2),cfg_wavein_bps("wavein_bps",16),cfg_wavein_src("wavein_src",0);
+cfg_int cfg_playback_mode("playback_mode",0);
+
+
+static UINT vm_retval=-666;
+
+cfg_struct_t<GUID> cfg_driver("driver",0),cfg_device("device",0);
+
+UINT volmode_detect()
+{
+ if (vm_retval!=-666) return vm_retval;
+ UINT dev;
+ UINT id;
+ UINT n_devz=mixerGetNumDevs();
+ UINT pos=0;
+ for(dev=0;dev<n_devz;dev++)
+ {
+ mixerGetID((HMIXEROBJ)dev,&id,MIXER_OBJECTF_MIXER);
+
+
+ MIXERLINE ml;
+ memset(&ml,0,sizeof(ml));
+ ml.cbStruct=sizeof(ml);
+ ml.dwComponentType=MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
+
+ mixerGetLineInfo((HMIXEROBJ)id,&ml,MIXER_GETLINEINFOF_COMPONENTTYPE|MIXER_OBJECTF_MIXER);
+
+ UINT con;
+ for(con=0;con<ml.cConnections;con++)
+ {
+ MIXERLINE ml1;
+ memset(&ml1,0,sizeof(ml1));
+ ml1.cbStruct=sizeof(ml);
+ ml1.dwSource=con;
+ mixerGetLineInfo((HMIXEROBJ)id,&ml1,MIXER_GETLINEINFOF_SOURCE|MIXER_OBJECTF_MIXER);
+ if (ml1.dwComponentType==MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER)
+ {
+ vm_retval=pos;
+ return vm_retval;
+ }
+ pos++;
+ }
+ }
+ vm_retval=-1;
+ return vm_retval;
+}
+
+//avoid double id shit
+#define _IDC_PORT MAKEID(IDC_CONFIG1,IDC_PORT)
+#define _IDC_DEV_INFO MAKEID(IDC_CONFIG1,IDC_DEV_INFO)
+#define _IDC_HARDWARE_RESET MAKEID(IDC_CONFIG1,IDC_HARDWARE_RESET)
+#define _IDC_VOLMODE MAKEID(IDC_CONFIG1,IDC_VOLMODE)
+#define _IDC_LOGVOL MAKEID(IDC_CONFIG1,IDC_LOGVOL)
+#define _IDC_SAMPLING_ENABLED MAKEID(IDC_CONFIG2,IDC_SAMPLING_ENABLED)
+#define _IDC_WAVEIN MAKEID(IDC_CONFIG2,IDC_WAVEIN)
+#define _IDC_WAVEIN_SRC MAKEID(IDC_CONFIG2,IDC_WAVEIN_SRC)
+#define _IDC_WAVEIN_SR MAKEID(IDC_CONFIG2,IDC_WAVEIN_SR)
+#define _IDC_WAVEIN_S2 MAKEID(IDC_CONFIG2,IDC_WAVEIN_S2)
+#define _IDC_WAVEIN_CH MAKEID(IDC_CONFIG2,IDC_WAVEIN_CH)
+#define _IDC_WAVEIN_BPS MAKEID(IDC_CONFIG2,IDC_WAVEIN_BPS)
+#define _IDC_SAMPLING_DSP MAKEID(IDC_CONFIG2,IDC_SAMPLING_DSP)
+#define _IDC_SAMPLING_OUTPUT MAKEID(IDC_CONFIG2,IDC_SAMPLING_OUTPUT)
+#define _IDC_SAMP_REVERT MAKEID(IDC_CONFIG2,IDC_SAMP_REVERT)
+#define _IDC_REVERB MAKEID(IDC_CONFIG3,IDC_REVERB)
+#define _IDC_CHORUS MAKEID(IDC_CONFIG3,IDC_CHORUS)
+#define _IDC_DM_KEEP_PORT MAKEID(IDC_CONFIG3,IDC_DM_KEEP_PORT)
+#define _IDC_FREQ MAKEID(IDC_CONFIG3,IDC_FREQ)
+#define _IDC_DLS_CB MAKEID(IDC_CONFIG3,IDC_DLS_CB)
+#define _IDC_DLS MAKEID(IDC_CONFIG3,IDC_DLS)
+#define _IDC_DLS_B MAKEID(IDC_CONFIG3,IDC_DLS_B)
+#define _IDC_HACK_DM_RESETS MAKEID(IDC_CONFIG3,IDC_HACK_DM_RESETS)
+#define _IDC_SHOW_PANEL MAKEID(IDC_CONFIG4,IDC_SHOW_PANEL)
+#define _IDC_LOOP_S MAKEID(IDC_CONFIG4,IDC_LOOP_S)
+#define _IDC_LOOP MAKEID(IDC_CONFIG4,IDC_LOOP)
+#define _IDC_LOOP_S1 MAKEID(IDC_CONFIG4,IDC_LOOP_S1)
+#define _IDC_LOOP_S2 MAKEID(IDC_CONFIG4,IDC_LOOP_S2)
+#define _IDC_LOOP_T MAKEID(IDC_CONFIG4,IDC_LOOP_T)
+#define _IDC_LOOP_SP MAKEID(IDC_CONFIG4,IDC_LOOP_SP)
+#define _IDC_LOOP_S3 MAKEID(IDC_CONFIG4,IDC_LOOP_S3)
+#define _IDC_LOOP_S4 MAKEID(IDC_CONFIG4,IDC_LOOP_S4)
+#define _IDC_INFINITE MAKEID(IDC_CONFIG4,IDC_INFINITE)
+#define _IDC_PLAYBACK_METHOD MAKEID(IDC_CONFIG4,IDC_PLAYBACK_METHOD)
+#define _IDC_RESET MAKEID(IDC_CONFIG4,IDC_RESET)
+#define _IDC_RESET1 MAKEID(IDC_CONFIG4,IDC_RESET1)
+#define _IDC_STEREO MAKEID(IDC_CONFIG5,IDC_STEREO)
+#define _IDC_HACKTRACK MAKEID(IDC_CONFIG5,IDC_HACKTRACK)
+
+#define _IDC_HACK_NO_SYSEX MAKEID(IDC_CONFIG5,IDC_HACK_NO_SYSEX)
+#define _IDC_HACK_XG_DRUMS MAKEID(IDC_CONFIG5,IDC_HACK_XG_DRUMS)
+#define _IDC_HACK_DLS_DRUMS MAKEID(IDC_CONFIG5,IDC_HACK_DLS_DRUMS)
+#define _IDC_HACK_DLS_INSTRUMENTS MAKEID(IDC_CONFIG5,IDC_HACK_DLS_INSTRUMENTS)
+
+#define _IDC_LYRICS_ENABLED MAKEID(IDC_CONFIG8,IDC_LYRICS_ENABLED)
+#define _IDC_EOF_DELAY MAKEID(IDC_CONFIG5,IDC_EOF_DELAY)
+#define _IDC_EOF_DELAY_SPIN MAKEID(IDC_CONFIG5,IDC_EOF_DELAY_SPIN)
+
+sysex_table cfg_sysex_table;
+static sysex_table edit_sysex_table;
+
+
+#define _IDC_SYSEX_LIST MAKEID(IDC_CONFIG6,IDC_SYSEX_LIST)
+#define _IDC_IMP_F MAKEID(IDC_CONFIG6,IDC_IMP_F)
+#define _IDC_EXP_F MAKEID(IDC_CONFIG6,IDC_EXP_F)
+#define _IDC_IMP_PR MAKEID(IDC_CONFIG6,IDC_IMP_PR)
+#define _IDC_EXP_PR MAKEID(IDC_CONFIG6,IDC_EXP_PR)
+#define _IDC_SYSEX_ADD MAKEID(IDC_CONFIG6,IDC_SYSEX_ADD)
+#define _IDC_SYSEX_DELETE MAKEID(IDC_CONFIG6,IDC_SYSEX_DELETE)
+#define _IDC_SYSEX_EDIT MAKEID(IDC_CONFIG6,IDC_SYSEX_EDIT)
+#define _IDC_SYSEX_UP MAKEID(IDC_CONFIG6,IDC_SYSEX_UP)
+#define _IDC_SYSEX_DOWN MAKEID(IDC_CONFIG6,IDC_SYSEX_DOWN)
+
+
+#define _IDC_EXTS_LIST MAKEID(IDC_CONFIG7,IDC_EXTS_LIST)
+#define _IDC_EXTS_ED MAKEID(IDC_CONFIG7,IDC_EXTS_ED)
+#define _IDC_RMI_FMT MAKEID(IDC_CONFIG8,IDC_RMI_FMT)
+#define _IDC_RMI_DEF MAKEID(IDC_CONFIG8,IDC_RMI_DEF)
+
+
+#define EnableDlgItem(X,Y,Z) EnableWindow(_GetDlgItem(X,Y),Z)
+
+static HWND cfgGetTab(UINT id)
+{
+ id-=IDC_CONFIG1;
+ if (id>=tabsize(child_dlgs)) return 0;
+ return child_dlgs[id].wnd;
+}
+
+static HWND __getdlgitem(UINT id)
+{
+
+ HWND w=cfgGetTab(id>>16);
+ if (!w) return 0;
+ return GetDlgItem(w,id&0xFFFF);
+}
+
+#define _GetDlgItem(w,id) __getdlgitem(id)
+
+#define _GetDlgItemText(p,id,tx,l) GetWindowText(__getdlgitem(id),tx,l)
+#define _SetDlgItemText(p,id,tx) SetWindowText(__getdlgitem(id),tx)
+#define _SetDlgItemTextW(p,id,tx) SetWindowTextW(__getdlgitem(id),tx)
+#define _GetDlgItemInt(a,b,c,d) __getdlgitemint(b)
+#define _SetDlgItemInt(a,b,c,d) __setdlgitemint(b,c)
+#define _SendDlgItemMessage(a,b,c,d,e) SendMessage(_GetDlgItem(a,b),c,d,e)
+
+static void __setdlgitemint(UINT id,UINT val)
+{
+ char buf[32] = {0};
+ _itoa(val,buf,10);
+ SetWindowTextA(__getdlgitem(id),buf);
+}
+
+static int __getdlgitemint(UINT id)
+{
+ char buf[32] = {0};
+ GetWindowTextA(__getdlgitem(id),buf,32);
+ return atoi(buf);
+}
+
+
+static BOOL CALLBACK cfgVisStatusProc(HWND wnd,LPARAM param)
+{
+ if (GetWindowLong(wnd,GWL_ID)==IDC_SAMPLING_ENABLED)
+ {
+ EnableWindow(wnd,(param & 2) >> 1);
+ }
+ else
+ {
+ EnableWindow(wnd,param & 1);
+ }
+ return 1;
+}
+
+static MIDI_device * get_device(HWND wnd)
+{
+ int idx = _SendDlgItemMessage(wnd,_IDC_PORT,CB_GETCURSEL,0,0);
+ if (idx<0) return 0;
+ return (MIDI_device*)_SendDlgItemMessage(wnd,_IDC_PORT,CB_GETITEMDATA,idx,0);
+}
+
+
+static void cfgVisStatus(HWND wnd)
+{
+ int samp =_SendDlgItemMessage(wnd,_IDC_SAMPLING_ENABLED,BM_GETCHECK,0,0);
+ int output = 0;
+ int flags = 0;
+ MIDI_device * dev = get_device(wnd);
+ if (dev && dev->has_output()) output = 1;
+
+ if (output && samp) {samp = 0;_SendDlgItemMessage(wnd,_IDC_SAMPLING_ENABLED,BM_SETCHECK,0,0);}
+ if (!output)
+ {
+ flags|=2;
+ if (samp) flags|=1;
+ else {
+ _SendDlgItemMessage(wnd,_IDC_SAMPLING_DSP,BM_SETCHECK,0,0);
+ _SendDlgItemMessage(wnd,_IDC_SAMPLING_OUTPUT,BM_SETCHECK,0,0);
+ }
+ }
+
+ EnumChildWindows(cfgGetTab(IDC_CONFIG2),cfgVisStatusProc,flags);
+}
+
+
+static void cfgVisMix(HWND wnd,int dev)
+{
+ HWND w=_GetDlgItem(wnd,_IDC_WAVEIN_SRC);
+ SendMessage(w,CB_RESETCONTENT,0,0);
+ SendMessageW(w,CB_ADDSTRING,0,(long)WASABI_API_LNGSTRINGW(STRING_SAMP_SRC_DEFAULT));
+ SendMessage(w,CB_SETCURSEL,0,0);
+ UINT id=0;
+
+ if (mixerGetID((HMIXEROBJ)dev,&id,MIXER_OBJECTF_WAVEOUT)) return;
+
+ MIXERLINE ml;
+ memset(&ml,0,sizeof(ml));
+ ml.cbStruct=sizeof(ml);
+ ml.dwComponentType=MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
+
+ if (mixerGetLineInfo((HMIXEROBJ)id,&ml,MIXER_GETLINEINFOF_COMPONENTTYPE|MIXER_OBJECTF_MIXER)) return;
+
+ MIXERLINECONTROLS cs;
+ MIXERCONTROL c;
+ memset(&cs,0,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;
+ memset(&c,0,sizeof(c));
+ c.cbStruct=sizeof(c);
+
+ if (!mixerGetLineControls((HMIXEROBJ)id,&cs,MIXER_OBJECTF_MIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE))
+ {
+ MIXERCONTROLDETAILS_LISTTEXT *t = (MIXERCONTROLDETAILS_LISTTEXT*)malloc(sizeof(MIXERCONTROLDETAILS_LISTTEXT)*c.cMultipleItems);
+ MIXERCONTROLDETAILS d;
+ d.cbStruct=sizeof(d);
+ d.dwControlID=c.dwControlID;
+ d.cbDetails=sizeof(*t);
+ d.cChannels=ml.cChannels;
+ d.cMultipleItems=c.cMultipleItems;
+ d.paDetails=t;
+ UINT n;
+ for(n=0;n<c.cMultipleItems;n++)
+ {
+ t[n].dwParam1=ml.dwLineID;
+ }
+ mixerGetControlDetails((HMIXEROBJ)id,&d,MIXER_GETCONTROLDETAILSF_LISTTEXT|MIXER_OBJECTF_MIXER);
+ for(n=0;n<c.cMultipleItems;n++)
+ {
+ SendMessage(w,CB_ADDSTRING,0,(long)t[n].szName);
+ }
+ free(t);
+ }
+}
+
+static void ChangePort(HWND wnd,MIDI_device * dev)
+{
+ cfgVisStatus(wnd);
+
+ {
+ string_w temp;
+ temp+=WASABI_API_LNGSTRINGW(IDS_TYPE);
+ temp+=dev->get_driver()->get_name();
+ temp+=L"\x0d\x0a";
+ temp+=dev->get_info();
+ if (!wcscmp((const wchar_t*)temp + temp.length()-2,L"\x0d\x0a")) temp.truncate(temp.length()-2);
+ _SetDlgItemTextW(wnd,_IDC_DEV_INFO,temp);
+ }
+}
+
+#undef DEV
+
+const static struct
+{
+ UINT id;
+ cfg_int * var;
+} bWnds[]=
+{
+ {_IDC_SAMP_REVERT,&cfg_samp_revert},
+ {_IDC_LOGVOL,&cfg_logvol},
+ {_IDC_RMI_DEF,&cfg_rmi_def},
+ {_IDC_HACK_DLS_DRUMS,&cfg_hack_dls_drums},
+ {_IDC_HACK_DLS_INSTRUMENTS,&cfg_hack_dls_instruments},
+ {_IDC_HACK_XG_DRUMS,&cfg_hack_xg_drums},
+ {_IDC_HACKTRACK,&cfg_recover_tracks},
+ {_IDC_DM_KEEP_PORT,&cfg_dm_keep_port},
+ {_IDC_SAMPLING_ENABLED,&cfg_smp},
+ {_IDC_REVERB,&cfg_reverb},
+ {_IDC_CHORUS,&cfg_chorus},
+ {_IDC_SAMPLING_OUTPUT,&cfg_sampout},
+ {_IDC_HACK_NO_SYSEX,&cfg_nosysex},
+ {_IDC_LYRICS_ENABLED,&cfg_lyrics},
+ {_IDC_SHOW_PANEL,&cfg_seq_showpanel},
+};
+
+#define NUM_BWNDS (sizeof(bWnds)/sizeof(*bWnds))
+
+#define WM_CMDNOTIFY (WM_USER+6)
+
+static BOOL WINAPI CfgChildProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
+{
+ if (msg==WM_COMMAND)
+ {
+#if defined(_WIN64)
+ SendMessage(GetParent(wnd),WM_CMDNOTIFY,wp,MAKEID(GetWindowLong(wnd,DWLP_USER),LOWORD(wp)));
+#else
+ SendMessage(GetParent(wnd), WM_CMDNOTIFY, wp, MAKEID(GetWindowLong(wnd, DWL_USER), LOWORD(wp)));
+#endif
+ }
+ return 0;
+}
+
+
+static bool is_hex(char c) {return (c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F');}
+
+static UINT read_hex(char* t)
+{
+ UINT r=0;
+ while(is_hex(*t))
+ {
+ r<<=4;
+ if (*t>='0' && *t<='9')
+ r|=*t-'0';
+ else if (*t>='a' && *t<='f')
+ r|=*t-'a'+10;
+ else r|=*t-'A'+10;
+ t++;
+ }
+ return r;
+}
+
+BYTE* read_sysex_edit(HWND w,UINT *siz)//used in seq.cpp
+{
+ UINT tl=GetWindowTextLength(w)+2;
+ char* tx=(char*)malloc(tl);
+ if (!tx) return 0;
+ GetWindowTextA(w,tx,tl+2);
+ UINT sl=0;
+ BYTE* tmp=(BYTE*)malloc(tl/2+2);
+ char* t=tx;
+ if (!tmp)
+ {
+ free(tx);
+ return 0;
+ }
+ tmp[sl++]=0xF0;
+ while(t && *t)
+ {
+ while(!is_hex(*t) && *t) t++;
+ if (!*t) break;
+ tmp[sl++]=read_hex(t);
+ while(is_hex(*t)) t++;
+ }
+
+ tmp[sl++]=0xF7;
+ free(tx);
+ *siz=sl;
+ return tmp;
+}
+
+static BOOL WINAPI SysexProc(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
+ SendDlgItemMessage(wnd,IDC_SPIN1,UDM_SETRANGE,0,MAKELONG(9999,0));
+ SetDlgItemInt(wnd,IDC_DELAY,edit_sysex_table.get_time(lp),0);
+ edit_sysex_table.print_edit(lp,GetDlgItem(wnd,IDC_EDIT1));
+ return 1;
+ case WM_COMMAND:
+ switch(wp)
+ {
+ case IDOK:
+ {
+ UINT size;
+ BYTE* data=read_sysex_edit(GetDlgItem(wnd,IDC_EDIT1),&size);
+ if (!data)
+ {
+ EndDialog(wnd,0);
+ break;
+ }
+#if defined(_WIN64)
+ edit_sysex_table.modify_entry(GetWindowLong(wnd, DWLP_USER), data, size, GetDlgItemInt(wnd, IDC_DELAY, 0, 0));
+#else
+ edit_sysex_table.modify_entry(GetWindowLong(wnd, DWL_USER), data, size, GetDlgItemInt(wnd, IDC_DELAY, 0, 0));
+#endif
+ free(data);
+ }
+
+ EndDialog(wnd,1);
+ break;
+ case IDCANCEL:
+ EndDialog(wnd,0);
+ break;
+ }
+ }
+ return 0;
+}
+
+extern int initDefaultDeviceShit();
+
+static BOOL WINAPI CfgProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
+{
+ switch(msg)
+ {
+ case WM_INITDIALOG:
+ if (g_theConfig && g_theConfig!=wnd)
+ {
+ ShowWindow(g_theConfig,SW_SHOW);
+ EndDialog(wnd,0);
+ return 0;
+ }
+
+ initDefaultDeviceShit();
+
+ g_theConfig=wnd;
+ {
+ HWND hTab=GetDlgItem(wnd,IDC_TAB);
+#if defined(_WIN64)
+ SetWindowLong(wnd, DWLP_USER, (long)hTab);
+#else
+ SetWindowLong(wnd, DWL_USER, (long)hTab);
+#endif
+ HWND w;
+ UINT n;
+ TC_ITEMW it=
+ {
+ TCIF_TEXT,
+ 0,0,
+ 0, //pszText
+ 0,
+ -1,0
+ };
+ for(n=0;n<tabsize(child_dlgs);n++)
+ {
+ it.pszText=WASABI_API_LNGSTRINGW(child_dlgs[n].l_id);
+ SendMessage(hTab,TCM_INSERTITEMW,n,(long)&it);
+ }
+ SendMessage(hTab,TCM_SETCURFOCUS,cfg_cur_tab,0);
+ RECT r;
+ GetClientRect(hTab,&r);
+ TabCtrl_AdjustRect(hTab,0,&r);
+ MapWindowPoints(hTab,wnd,(LPPOINT)&r,2);
+
+ for(n=0;n<tabsize(child_dlgs);n++)
+ {
+ child_dlgs[n].wnd=w=WASABI_API_CREATEDIALOGW(child_dlgs[n].id,wnd,CfgChildProc);
+ SendMessage(MIDI_callback::GetMainWindow(),WM_WA_IPC,(WPARAM)w,IPC_USE_UXTHEME_FUNC);
+ SetWindowPos(w,0,r.left,r.top,r.right-r.left,r.bottom-r.top,SWP_NOZORDER);
+#if defined(_WIN64)
+ SetWindowLong(w, DWLP_USER, IDC_CONFIG1 + n);
+#else
+ SetWindowLong(w, DWL_USER, IDC_CONFIG1 + n);
+#endif
+ ShowWindow(w,n==cfg_cur_tab ? SW_SHOW : SW_HIDE);
+ }
+ }
+
+ {
+ UINT n;
+ for(n=0;n<NUM_BWNDS;n++)
+ {
+ _SendDlgItemMessage(wnd,bWnds[n].id,BM_SETCHECK,*bWnds[n].var,0);
+ }
+ }
+
+ SetDlgItemTextA(wnd,_IDC_DLS,cfg_dls_file);
+ _SendDlgItemMessage(wnd,_IDC_DLS_CB,BM_SETCHECK,cfg_dls_active,0);
+ EnableWindow(_GetDlgItem(wnd,_IDC_DLS),cfg_dls_active);
+ EnableWindow(_GetDlgItem(wnd,_IDC_DLS_B),cfg_dls_active);
+ _SetDlgItemInt(wnd,_IDC_LOOP_T,cfg_loop_count,0);
+ _SendDlgItemMessage(wnd,_IDC_INFINITE,BM_SETCHECK,cfg_loop_infinite,0);
+ _SendDlgItemMessage(wnd,_IDC_LOOP_T,EM_LIMITTEXT,3,0);
+ _SendDlgItemMessage(wnd,_IDC_LOOP_SP,UDM_SETRANGE,0,MAKELONG(999,1));
+ {
+ int n;
+ HWND w=_GetDlgItem(wnd,_IDC_LOOP);
+ for(n=0;n<3;n++)
+ {
+ SendMessageW(w,CB_ADDSTRING,0,(long)WASABI_API_LNGSTRINGW(loop_txt[n]));
+ }
+ SendMessage(w,CB_SETCURSEL,cfg_loop_type,0);
+ char tmp[10] = {0};
+ w=_GetDlgItem(wnd,_IDC_FREQ);
+ for(n=0;n<3;n++)
+ {
+ int freq = 11025<<n;
+ _itoa(freq,tmp,10);
+ int idx = SendMessageA(w,CB_ADDSTRING,0,(long)tmp); // Must stay in ANSI
+ if (cfg_freq==freq)
+ SendMessageA(w,CB_SETCURSEL,idx,0); // Must stay in ANSI
+ }
+
+ w=_GetDlgItem(wnd,_IDC_PORT);
+ {
+ int idx_driver=0;
+ MIDI_driver * driver;
+ while(driver = MIDI_driver::driver_enumerate(idx_driver++))
+ {
+ int idx_device=0;
+ MIDI_device * device;
+ while(device = driver->device_enumerate(idx_device++))
+ {
+ string_w temp;
+ temp+=driver->get_name();
+ temp+=L" / ";
+ temp+=device->get_name();
+ int idx_combo = SendMessageW(w,CB_ADDSTRING,0,(LPARAM)(const wchar_t*)temp);
+ SendMessage(w,CB_SETITEMDATA,idx_combo,(long)device);
+
+ if (driver->get_guid() == cfg_driver && device->get_guid() == cfg_device)
+ {
+ SendMessage(w,CB_SETCURSEL,idx_combo,0);
+ ChangePort(wnd,device);
+ }
+ }
+
+ }
+ }
+
+ w=_GetDlgItem(wnd,_IDC_WAVEIN);
+ for(n=-1;n<(int)waveInGetNumDevs();n++)
+ {
+ WAVEINCAPS caps;
+ if (waveInGetDevCaps((UINT)n,&caps,sizeof(caps))==MMSYSERR_NOERROR && caps.dwFormats!=0)
+ {
+ int idx=SendMessage(w,CB_ADDSTRING,0,(long)caps.szPname);
+ SendMessage(w,CB_SETITEMDATA,idx,n);
+ if (n==cfg_wavein_dev) SendMessage(w,CB_SETCURSEL,idx,0);
+ }
+ }
+
+ cfgVisMix(wnd,cfg_wavein_dev);
+ _SendDlgItemMessage(wnd,_IDC_WAVEIN_SRC,CB_SETCURSEL,cfg_wavein_src,0);
+
+ w=_GetDlgItem(wnd,_IDC_PLAYBACK_METHOD);
+ SendMessageW(w,CB_ADDSTRING,0,(long)WASABI_API_LNGSTRINGW(IDS_STREAMED));
+ SendMessageW(w,CB_ADDSTRING,0,(long)WASABI_API_LNGSTRINGW(IDS_IMMEDIATE));
+ SendMessage(w,CB_SETCURSEL,cfg_playback_mode,0);
+
+ w=_GetDlgItem(wnd,_IDC_SYSEX_LIST);
+ edit_sysex_table = cfg_sysex_table;
+
+ {
+ char temp[128] = {0};
+ n=0;
+ while(edit_sysex_table.print_preview(n++,temp)) SendMessage(w,LB_ADDSTRING,0,(long)temp);
+ }
+
+ w=_GetDlgItem(wnd,_IDC_EXTS_LIST);
+ for(n=0;n<MIDI_core::FileTypes_GetNum();n++)
+ {
+ SendMessageA(w,LB_ADDSTRING,0,(long)MIDI_core::FileTypes_GetExtension(n)); // Must stay in ANSI
+
+ if (cfg_ext_mask & (1<<n))
+ SendMessage(w,LB_SETSEL,1,n);
+ }
+ SetDlgItemTextA(wnd,_IDC_EXTS_ED,cfg_extra_exts);
+
+
+ w=_GetDlgItem(wnd,_IDC_VOLMODE);
+ SendMessageW(w,CB_ADDSTRING,0,(long)WASABI_API_LNGSTRINGW(STRING_VOLUME_NONE));
+ SendMessageW(w,CB_ADDSTRING,0,(long)WASABI_API_LNGSTRINGW(STRING_VOLUME_DRIVER_SPECIFIC));
+ SendMessageW(w,CB_ADDSTRING,0,(long)WASABI_API_LNGSTRINGW(STRING_VOLUME_AUTO));
+
+ {
+ UINT id=0;
+ UINT n_devz=mixerGetNumDevs();
+ UINT dev;
+ for(dev=0;dev<n_devz;dev++)
+ {
+ mixerGetID((HMIXEROBJ)dev,&id,MIXER_OBJECTF_MIXER);
+
+ MIXERCAPSW capz;
+ mixerGetDevCapsW(id,&capz,sizeof(capz));
+
+ MIXERLINEW ml;
+ memset(&ml,0,sizeof(ml));
+ ml.cbStruct=sizeof(ml);
+ ml.dwComponentType=MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
+
+ mixerGetLineInfoW((HMIXEROBJ)id,&ml,MIXER_GETLINEINFOF_COMPONENTTYPE|MIXER_OBJECTF_MIXER);
+
+ UINT con;
+ for(con=0;con<ml.cConnections;con++)
+ {
+ MIXERLINEW ml1;
+ memset(&ml1,0,sizeof(ml1));
+ ml1.cbStruct=sizeof(ml);
+ ml1.dwSource=con;
+ mixerGetLineInfoW((HMIXEROBJ)id,&ml1,MIXER_GETLINEINFOF_SOURCE|MIXER_OBJECTF_MIXER);
+ if (n_devz==1) SendMessageW(w,CB_ADDSTRING,0,(long)ml1.szName);
+ else
+ {
+ string_w temp;
+ temp+=capz.szPname;
+ temp+=ml1.szShortName;
+ SendMessageW(w,CB_ADDSTRING,0,(long)(const wchar_t*)temp);
+ }
+ }
+ }
+ }
+
+ SendMessage(w,CB_SETCURSEL,cfg_volmode,0);
+
+ w=_GetDlgItem(wnd,_IDC_WAVEIN_CH);
+ SendMessageW(w,CB_ADDSTRING,0,(long)WASABI_API_LNGSTRINGW(STRING_MONO));
+ SendMessageW(w,CB_ADDSTRING,0,(long)WASABI_API_LNGSTRINGW(STRING_STEREO));
+ SendMessage(w,CB_SETCURSEL,cfg_wavein_ch-1,0);
+ w=_GetDlgItem(wnd,_IDC_WAVEIN_BPS);
+
+ for(n=1;n<=4;n++)
+ {
+ wchar_t foo[32] = {0};
+ wsprintfW(foo,WASABI_API_LNGSTRINGW(STRING_BIT_FMT),n<<3);
+ SendMessageW(w,CB_ADDSTRING,0,(long)foo);
+ }
+ SendMessage(w,CB_SETCURSEL,(cfg_wavein_bps>>3)-1,0);
+
+ w=_GetDlgItem(wnd,_IDC_WAVEIN_SR);
+ for(n=0;n<sizeof(sr_tab)/sizeof(sr_tab[0]);n++)
+ {
+ char foo[8] = {0};
+ _itoa(sr_tab[n],foo,10);
+ SendMessageA(w,CB_ADDSTRING,0,(long)foo); // Must stay in ANSI mode
+ }
+
+ _SetDlgItemInt(wnd,_IDC_WAVEIN_SR,cfg_wavein_sr,0);
+
+ w=_GetDlgItem(wnd,_IDC_HARDWARE_RESET);
+ SendMessageW(w,CB_ADDSTRING,0,(long)WASABI_API_LNGSTRINGW(IDS_NONE));
+ SendMessageW(w,CB_ADDSTRING,0,(long)L"GM (General MIDI)");
+ SendMessageW(w,CB_ADDSTRING,0,(long)L"GS (Roland)");
+ SendMessageW(w,CB_ADDSTRING,0,(long)L"XG (Yamaha)");
+ SendMessageW(w,CB_SETCURSEL,cfg_hardware_reset,0);
+ }
+// f_num=0;
+
+ _SendDlgItemMessage(wnd,_IDC_EOF_DELAY_SPIN,UDM_SETRANGE,0,MAKELONG(0x7FFF,0));
+ _SetDlgItemInt(wnd,_IDC_EOF_DELAY,cfg_eof_delay,0);
+
+
+ return 1;
+ case WM_NOTIFY:
+ switch(wp)
+ {
+ case IDC_TAB:
+ if (((NMHDR*)lp)->code==TCN_SELCHANGE)
+ {
+ UINT n;
+ HWND hTab=((NMHDR*)lp)->hwndFrom;
+ cfg_cur_tab=SendMessage(hTab,TCM_GETCURSEL,0,0);
+ for(n=0;n<tabsize(child_dlgs);n++)
+ {
+ HWND w=cfgGetTab(IDC_CONFIG1+n);
+ ShowWindow(w,n==cfg_cur_tab ? SW_SHOW : SW_HIDE);
+ }
+ }
+ break;
+ }
+ break;
+ case WM_CMDNOTIFY://WM_COMMAND from one of child dialogs
+ if (wp>>16)
+ {
+ switch(lp)
+ {
+ case _IDC_SYSEX_LIST:
+ if (wp>>16==LBN_DBLCLK)
+ {
+ CfgProc(wnd,WM_CMDNOTIFY,0,_IDC_SYSEX_EDIT);
+ }
+ break;
+ case _IDC_WAVEIN:
+ if (wp>>16==CBN_SELCHANGE)
+ {
+ int d=_SendDlgItemMessage(wnd,_IDC_WAVEIN,CB_GETCURSEL,0,0);
+ if (d>=0) cfgVisMix(wnd,_SendDlgItemMessage(wnd,_IDC_WAVEIN,CB_GETITEMDATA,d,0));
+
+ }
+ break;
+ case _IDC_PORT:
+ if (wp>>16==CBN_SELCHANGE)
+ {
+ ChangePort(wnd,get_device(wnd));
+ }
+ break;
+ }
+ }
+ else
+ {
+ switch(lp)
+ {
+ case _IDC_DLS_CB:
+ {
+ int checked = _SendDlgItemMessage(wnd,_IDC_DLS_CB,BM_GETCHECK,0,0);
+ EnableWindow(_GetDlgItem(wnd,_IDC_DLS),checked);
+ EnableWindow(_GetDlgItem(wnd,_IDC_DLS_B),checked);
+ }
+ break;
+ case _IDC_IMP_F:
+ if (edit_sysex_table.num_entries()>0)
+ {
+ char fn[MAX_PATH] = {0};
+ if (DoOpenFile(wnd,fn,IDS_SYSEX_DATA,"SYX",0))
+ {
+ HANDLE f=CreateFileA(fn,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
+ if (f!=INVALID_HANDLE_VALUE)
+ {
+ DWORD sz=GetFileSize(f,0);
+ BYTE * temp=(BYTE*)malloc(sz);
+ if (temp)
+ {
+ DWORD br = 0;
+ ReadFile(f,temp,sz,&br,0);
+ edit_sysex_table.add_entry(temp,sz,0);
+ free(temp);
+ }
+ char tmp[128] = {0};
+ edit_sysex_table.print_preview(edit_sysex_table.num_entries()-1,tmp);
+ _SendDlgItemMessage(wnd,_IDC_SYSEX_LIST,LB_ADDSTRING,0,(long)tmp);
+ CloseHandle(f);
+ }
+ else FILE_BLAH;
+ }
+ }
+ break;
+ case _IDC_IMP_PR:
+ // if (!edit_sysex_table.is_empty())
+ {
+ char fn[MAX_PATH] = {0};
+ fn[0]=0;
+ if (DoOpenFile(wnd,fn,IDS_MIDI_HARDWARE_PRESETS,"MHP",0))
+ {
+ if (!edit_sysex_table.file_read(fn))
+ {
+ FILE_BLAH;
+ }
+ }
+ }
+ break;
+ case _IDC_EXP_PR:
+ if (!edit_sysex_table.is_empty())
+ {
+ char fn[MAX_PATH] = {0};
+ fn[0]=0;
+ if (DoOpenFile(wnd,fn,IDS_MIDI_HARDWARE_PRESETS,"MHP",1))
+ {
+ if (!edit_sysex_table.file_write(fn))
+ {
+ FILE_BLAH;
+ }
+ }
+ }
+ break;
+ case _IDC_EXP_F:
+ if (!edit_sysex_table.is_empty())
+ {
+ UINT ns=_SendDlgItemMessage(wnd,_IDC_SYSEX_LIST,LB_GETCURSEL,0,0);
+ if (ns!=-1)
+ {
+ char fn[MAX_PATH] = {0};
+ fn[0]=0;
+ if (DoOpenFile(wnd,fn,IDS_SYSEX_DATA,"SYX",1))
+ {
+ HANDLE f=CreateFileA(fn,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,0);
+ if (f!=INVALID_HANDLE_VALUE)
+ {
+ BYTE * data;
+ int size = 0;
+ edit_sysex_table.get_entry(ns,&data,&size,0);
+ DWORD bw = 0;
+ WriteFile(f,data,size,&bw,0);
+ CloseHandle(f);
+ }
+ else FILE_BLAH;
+ }
+ }
+ }
+
+ break;
+ case _IDC_SYSEX_EDIT:
+ if (!edit_sysex_table.is_empty())
+ {
+ HWND w=_GetDlgItem(wnd,_IDC_SYSEX_LIST);
+ int n=SendMessage(w,LB_GETCURSEL,0,0);
+ if (n!=-1 && n<edit_sysex_table.num_entries())
+ {
+ if (WASABI_API_DIALOGBOXPARAM(IDD_SYSEX,wnd,SysexProc,n))
+ {
+ SendMessage(w,LB_DELETESTRING,n,0);
+ char tmp[128] = {0};
+ edit_sysex_table.print_preview(n,tmp);
+ SendMessage(w,LB_INSERTSTRING,n,(long)tmp);
+ }
+ }
+ }
+ break;
+ case _IDC_SYSEX_ADD:
+// if (!edit_sysex_table.is_empty())
+ {
+ BYTE data[2]={0xF0,0xF7};
+ edit_sysex_table.add_entry(data,2,0);
+ char tmp[128] = {0};
+ edit_sysex_table.print_preview(edit_sysex_table.num_entries()-1,tmp);
+ _SendDlgItemMessage(wnd,_IDC_SYSEX_LIST,LB_ADDSTRING,0,(long)tmp);
+ }
+ break;
+ case _IDC_SYSEX_DELETE:
+ if (!edit_sysex_table.is_empty())
+ {
+ HWND w=_GetDlgItem(wnd,_IDC_SYSEX_LIST);
+ int n=SendMessage(w,LB_GETCURSEL,0,0);
+ if (n != LB_ERR)
+ {
+ SendMessage(w,LB_DELETESTRING,n,0);
+ edit_sysex_table.remove_entry(n);
+ }
+ }
+ break;
+ case _IDC_SYSEX_UP:
+ {
+ HWND w=_GetDlgItem(wnd,_IDC_SYSEX_LIST);
+ int ns=SendMessage(w,LB_GETCURSEL,0,0);
+ if (ns==-1 || ns==0) break;
+ int ns1=ns-1;
+ BYTE * data;
+ int size,time;
+ edit_sysex_table.get_entry(ns,&data,&size,&time);
+ edit_sysex_table.insert_entry(ns1,data,size,time);
+ edit_sysex_table.remove_entry(ns+1);
+
+ char tmp[128] = {0};
+ SendMessage(w,LB_DELETESTRING,ns1,0);
+ edit_sysex_table.print_preview(ns,tmp);
+ SendMessage(w,LB_INSERTSTRING,ns,(long)tmp);
+ }
+ break;
+ case _IDC_SYSEX_DOWN:
+ {
+ HWND w=_GetDlgItem(wnd,_IDC_SYSEX_LIST);
+ int ns1=SendMessage(w,LB_GETCURSEL,0,0);
+ if (ns1==-1 || ns1==edit_sysex_table.num_entries()-1) break;
+ int ns=ns1+1;
+ BYTE * data;
+ int size,time;
+ edit_sysex_table.get_entry(ns,&data,&size,&time);
+ edit_sysex_table.insert_entry(ns1,data,size,time);
+ edit_sysex_table.remove_entry(ns+1);
+
+ char tmp[128] = {0};
+ SendMessage(w,LB_DELETESTRING,ns,0);
+ edit_sysex_table.print_preview(ns1,tmp);
+ SendMessage(w,LB_INSERTSTRING,ns1,(long)tmp);
+ }
+ break;
+ case _IDC_SAMPLING_ENABLED:
+ cfgVisStatus(wnd);
+ break;
+ case _IDC_DLS_B:
+ {
+ char tmp[MAX_PATH] = {0};
+ GetDlgItemTextA(wnd,_IDC_DLS,tmp,MAX_PATH);
+ if (DoOpenFile(wnd,tmp,IDS_DLS_FILES,"DLS",0)) SetDlgItemTextA(wnd,_IDC_DLS,tmp);
+ }
+ break;
+ }
+ break;
+
+ }
+ break;
+ case WM_COMMAND:
+ switch(wp)
+ {
+ case IDRESET:
+ if (MessageBoxW(wnd,WASABI_API_LNGSTRINGW(STRING_CONFIG_RESET),(wchar_t*)mod.description,
+ MB_ICONWARNING|MB_YESNO)==IDYES)
+ {
+ edit_sysex_table.reset();
+ if (g_theConfig==wnd) g_theConfig=0;
+ EndDialog(wnd,666);
+ }
+ break;
+ case IDCANCEL:
+ edit_sysex_table.reset();
+ if (g_theConfig==wnd) g_theConfig=0;
+ EndDialog(wnd,0);
+ break;
+ case IDOK:
+ {
+ UINT n;
+ for(n=0;n<NUM_BWNDS;n++)
+ {
+ *bWnds[n].var=!!_SendDlgItemMessage(wnd,bWnds[n].id,BM_GETCHECK,0,0);
+ }
+ }
+ cfg_wavein_src=_SendDlgItemMessage(wnd,_IDC_WAVEIN_SRC,CB_GETCURSEL,0,0);
+ cfg_playback_mode = _SendDlgItemMessage(wnd,_IDC_PLAYBACK_METHOD,CB_GETCURSEL,0,0);
+ {
+ MIDI_device * dev = get_device(wnd);
+ if (dev)
+ {
+ cfg_driver = dev->get_driver()->get_guid();
+ cfg_device = dev->get_guid();
+ }
+ }
+
+ {
+ int t=_SendDlgItemMessage(wnd,_IDC_WAVEIN,CB_GETCURSEL,0,0);
+ if (t<0) cfg_wavein_dev=-1;
+ else cfg_wavein_dev = _SendDlgItemMessage(wnd,_IDC_WAVEIN,CB_GETITEMDATA,t,0);
+ }
+
+ cfg_wavein_sr=_GetDlgItemInt(wnd,_IDC_WAVEIN_SR,0,0);
+ cfg_wavein_ch=_SendDlgItemMessage(wnd,_IDC_WAVEIN_CH,CB_GETCURSEL,0,0)+1;
+ cfg_wavein_bps=(_SendDlgItemMessage(wnd,_IDC_WAVEIN_BPS,CB_GETCURSEL,0,0)+1)<<3;
+
+ cfg_loop_type=_SendDlgItemMessage(wnd,_IDC_LOOP,CB_GETCURSEL,0,0);
+ cfg_loop_count=_GetDlgItemInt(wnd,_IDC_LOOP_T,0,0);
+ cfg_loop_infinite=_SendDlgItemMessage(wnd,_IDC_INFINITE,BM_GETCHECK,0,0);
+
+ {
+ int t=_SendDlgItemMessage(wnd,_IDC_FREQ,CB_GETCURSEL,0,0);
+ if (t<0) cfg_freq=22050;
+ else cfg_freq=11025<<t;
+ }
+
+ cfg_dls_file.get_string().from_window(_GetDlgItem(wnd,_IDC_DLS));
+ cfg_dls_active = _SendDlgItemMessage(wnd,_IDC_DLS_CB,BM_GETCHECK,0,0);
+
+ cfg_sysex_table=edit_sysex_table;
+ edit_sysex_table.reset();
+
+ cfg_extra_exts.get_string().from_window(_GetDlgItem(wnd,_IDC_EXTS_ED));
+
+ {
+ int n;
+ HWND w=_GetDlgItem(wnd,_IDC_EXTS_LIST);
+ cfg_ext_mask=0;
+ for(n=0;n<MIDI_core::FileTypes_GetNum();n++)
+ if (SendMessage(w,LB_GETSEL,n,0)) cfg_ext_mask = (int)cfg_ext_mask | (1<<n);
+ }
+
+ cfg_volmode=_SendDlgItemMessage(wnd,_IDC_VOLMODE,CB_GETCURSEL,0,0);
+
+ cfg_eof_delay=_GetDlgItemInt(wnd,_IDC_EOF_DELAY,0,0);
+
+ cfg_hardware_reset=_SendDlgItemMessage(wnd,_IDC_HARDWARE_RESET,CB_GETCURSEL,0,0);
+
+ if (g_theConfig==wnd) g_theConfig=0;
+ EndDialog(wnd,1);
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
+
+int MIDI_core::Config(HWND p)
+{
+ int r;
+db:
+ r=WASABI_API_DIALOGBOXW(IDD_CONFIG,p,CfgProc);
+ if (r==666)
+ {
+ cfg_var::config_reset();
+ goto db;
+ }
+ return r;
+}
+
+int DoAboutMessageBox(HWND parent, wchar_t* title, wchar_t* message)
+{
+ MSGBOXPARAMSW msgbx = {sizeof(MSGBOXPARAMSW),0};
+ msgbx.lpszText = message;
+ msgbx.lpszCaption = title;
+ msgbx.lpszIcon = MAKEINTRESOURCEW(102);
+ msgbx.hInstance = GetModuleHandle(0);
+ msgbx.dwStyle = MB_USERICON;
+ msgbx.hwndOwner = parent;
+ return MessageBoxIndirectW(&msgbx);
+}
+
+void About(HWND hwndParent)
+{
+ wchar_t message[1024] = {0}, text[1024] = {0};
+ WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_MIDI_PLAYER_OLD,text,1024);
+ wsprintfW(message, WASABI_API_LNGSTRINGW(IDS_ABOUT_TEXT),
+ mod.description, __DATE__);
+ DoAboutMessageBox(hwndParent,text,message);
+} \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/core_api.h b/Src/Plugins/Input/in_midi/core_api.h
new file mode 100644
index 00000000..e30979cf
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/core_api.h
@@ -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 \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/cvt.h b/Src/Plugins/Input/in_midi/cvt.h
new file mode 100644
index 00000000..12d8f0c5
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/cvt.h
@@ -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"
diff --git a/Src/Plugins/Input/in_midi/dmplugin.h b/Src/Plugins/Input/in_midi/dmplugin.h
new file mode 100644
index 00000000..821ef7d6
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/dmplugin.h
@@ -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_ */
diff --git a/Src/Plugins/Input/in_midi/dmusicc.h b/Src/Plugins/Input/in_midi/dmusicc.h
new file mode 100644
index 00000000..3608babb
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/dmusicc.h
@@ -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_ */
diff --git a/Src/Plugins/Input/in_midi/dmusicf.h b/Src/Plugins/Input/in_midi/dmusicf.h
new file mode 100644
index 00000000..10908a9b
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/dmusicf.h
@@ -0,0 +1,2373 @@
+/************************************************************************
+* *
+* dmusicf.h -- This module defines the DirectMusic file formats *
+* *
+* Copyright (c) 1998-1999 Microsoft Corporation
+* *
+************************************************************************/
+
+#ifndef _DMUSICF_
+#define _DMUSICF_
+
+
+#include <windows.h>
+
+#define COM_NO_WINDOWS_H
+#include <objbase.h>
+
+#include <mmsystem.h>
+
+#include <pshpack8.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+interface IDirectMusicCollection;
+#ifndef __cplusplus
+typedef interface IDirectMusicCollection IDirectMusicCollection;
+#endif
+
+/* Common chunks */
+
+#define DMUS_FOURCC_GUID_CHUNK mmioFOURCC('g','u','i','d')
+#define DMUS_FOURCC_INFO_LIST mmioFOURCC('I','N','F','O')
+#define DMUS_FOURCC_UNFO_LIST mmioFOURCC('U','N','F','O')
+#define DMUS_FOURCC_UNAM_CHUNK mmioFOURCC('U','N','A','M')
+#define DMUS_FOURCC_UART_CHUNK mmioFOURCC('U','A','R','T')
+#define DMUS_FOURCC_UCOP_CHUNK mmioFOURCC('U','C','O','P')
+#define DMUS_FOURCC_USBJ_CHUNK mmioFOURCC('U','S','B','J')
+#define DMUS_FOURCC_UCMT_CHUNK mmioFOURCC('U','C','M','T')
+#define DMUS_FOURCC_CATEGORY_CHUNK mmioFOURCC('c','a','t','g')
+#define DMUS_FOURCC_VERSION_CHUNK mmioFOURCC('v','e','r','s')
+
+/* The following structures are used by the Tracks, and are the packed structures */
+/* that are passed to the Tracks inside the IStream. */
+
+
+typedef struct _DMUS_IO_SEQ_ITEM
+{
+ MUSIC_TIME mtTime;
+ MUSIC_TIME mtDuration;
+ DWORD dwPChannel;
+ short nOffset;
+ BYTE bStatus;
+ BYTE bByte1;
+ BYTE bByte2;
+} DMUS_IO_SEQ_ITEM;
+
+
+typedef struct _DMUS_IO_CURVE_ITEM
+{
+ MUSIC_TIME mtStart;
+ MUSIC_TIME mtDuration;
+ MUSIC_TIME mtResetDuration;
+ DWORD dwPChannel;
+ short nOffset;
+ short nStartValue;
+ short nEndValue;
+ short nResetValue;
+ BYTE bType;
+ BYTE bCurveShape;
+ BYTE bCCData;
+ BYTE bFlags;
+ /* Following was added for DX8. */
+ WORD wParamType; /* RPN or NRPN parameter number. */
+ WORD wMergeIndex; /* Allows multiple parameters to be merged (pitchbend, volume, and expression.) */
+} DMUS_IO_CURVE_ITEM;
+
+
+typedef struct _DMUS_IO_TEMPO_ITEM
+{
+ MUSIC_TIME lTime;
+ double dblTempo;
+} DMUS_IO_TEMPO_ITEM;
+
+
+typedef struct _DMUS_IO_SYSEX_ITEM
+{
+ MUSIC_TIME mtTime;
+ DWORD dwPChannel;
+ DWORD dwSysExLength;
+} DMUS_IO_SYSEX_ITEM;
+
+typedef DMUS_CHORD_KEY DMUS_CHORD_PARAM; /* DMUS_CHORD_KEY defined in dmusici.h */
+
+typedef struct _DMUS_RHYTHM_PARAM
+{
+ DMUS_TIMESIGNATURE TimeSig;
+ DWORD dwRhythmPattern;
+} DMUS_RHYTHM_PARAM;
+
+typedef struct _DMUS_TEMPO_PARAM
+{
+ MUSIC_TIME mtTime;
+ double dblTempo;
+} DMUS_TEMPO_PARAM;
+
+
+typedef struct _DMUS_MUTE_PARAM
+{
+ DWORD dwPChannel;
+ DWORD dwPChannelMap;
+ BOOL fMute;
+} DMUS_MUTE_PARAM;
+
+/* Style chunks */
+
+#define DMUS_FOURCC_STYLE_FORM mmioFOURCC('D','M','S','T')
+#define DMUS_FOURCC_STYLE_CHUNK mmioFOURCC('s','t','y','h')
+#define DMUS_FOURCC_PART_LIST mmioFOURCC('p','a','r','t')
+#define DMUS_FOURCC_PART_CHUNK mmioFOURCC('p','r','t','h')
+#define DMUS_FOURCC_NOTE_CHUNK mmioFOURCC('n','o','t','e')
+#define DMUS_FOURCC_CURVE_CHUNK mmioFOURCC('c','r','v','e')
+#define DMUS_FOURCC_MARKER_CHUNK mmioFOURCC('m','r','k','r')
+#define DMUS_FOURCC_RESOLUTION_CHUNK mmioFOURCC('r','s','l','n')
+#define DMUS_FOURCC_ANTICIPATION_CHUNK mmioFOURCC('a','n','p','n')
+#define DMUS_FOURCC_PATTERN_LIST mmioFOURCC('p','t','t','n')
+#define DMUS_FOURCC_PATTERN_CHUNK mmioFOURCC('p','t','n','h')
+#define DMUS_FOURCC_RHYTHM_CHUNK mmioFOURCC('r','h','t','m')
+#define DMUS_FOURCC_PARTREF_LIST mmioFOURCC('p','r','e','f')
+#define DMUS_FOURCC_PARTREF_CHUNK mmioFOURCC('p','r','f','c')
+#define DMUS_FOURCC_STYLE_PERS_REF_LIST mmioFOURCC('p','r','r','f')
+#define DMUS_FOURCC_MOTIFSETTINGS_CHUNK mmioFOURCC('m','t','f','s')
+
+/* Flags used by variations: these make up the DWORDs in dwVariationChoices. */
+
+/* These flags determine the types of chords supported by a given variation in DirectMusic */
+/* mode. The first seven flags (bits 1-7) are set if the variation supports major chords */
+/* rooted in scale positions, so, e.g., if bits 1, 2, and 4 are set, the variation */
+/* supports major chords rooted in the tonic, second, and fourth scale positions. The */
+/* next seven flags serve the same purpose, but for minor chords, and the following seven */
+/* flags serve the same purpose for chords that are not major or minor (e.g., SUS 4 */
+/* chords). Bits 22, 23, and 24 are set if the variation supports chords rooted in the */
+/* scale, chords rooted sharp of scale tones, and chords rooted flat of scale tones, */
+/* respectively. For example, to support a C# minor chord in the scale of C Major, */
+/* bits 8 (for tonic minor) and 24 (for sharp) need to be set. Bits 25, 26, an 27 handle */
+/* chords that are triads, 6th or 7th chords, and chords with extensions, respectively. */
+/* bits 28 and 29 handle chords that are followed by tonic and dominant chords, */
+/* respectively. */
+#define DMUS_VARIATIONF_MAJOR 0x0000007F /* Seven positions in the scale - major chords. */
+#define DMUS_VARIATIONF_MINOR 0x00003F80 /* Seven positions in the scale - minor chords. */
+#define DMUS_VARIATIONF_OTHER 0x001FC000 /* Seven positions in the scale - other chords. */
+#define DMUS_VARIATIONF_ROOT_SCALE 0x00200000 /* Handles chord roots in the scale. */
+#define DMUS_VARIATIONF_ROOT_FLAT 0x00400000 /* Handles flat chord roots (based on scale notes). */
+#define DMUS_VARIATIONF_ROOT_SHARP 0x00800000 /* Handles sharp chord roots (based on scale notes). */
+#define DMUS_VARIATIONF_TYPE_TRIAD 0x01000000 /* Handles simple chords - triads. */
+#define DMUS_VARIATIONF_TYPE_6AND7 0x02000000 /* Handles simple chords - 6 and 7. */
+#define DMUS_VARIATIONF_TYPE_COMPLEX 0x04000000 /* Handles complex chords. */
+#define DMUS_VARIATIONF_DEST_TO1 0x08000000 /* Handles transitions to 1 chord. */
+#define DMUS_VARIATIONF_DEST_TO5 0x10000000 /* Handles transitions to 5 chord. */
+#define DMUS_VARIATIONF_DEST_OTHER 0x40000000 /* Handles transitions to chords other than 1 . */
+
+/* legacy mask for variation modes */
+#define DMUS_VARIATIONF_MODES 0xE0000000
+/* Bits 29 and 31 of the variation flags are the Mode bits. If both are 0, it's IMA. */
+/* If bit 29 is 1, it's Direct Music. */
+#define DMUS_VARIATIONF_MODES_EX (0x20000000 | 0x80000000)
+#define DMUS_VARIATIONF_IMA25_MODE 0x00000000
+#define DMUS_VARIATIONF_DMUS_MODE 0x20000000
+
+/* Set this if the part uses marker events */
+#define DMUS_PARTF_USE_MARKERS 0x1
+/* Set this if the part is allowed to switch only on chord-aligned markers */
+#define DMUS_PARTF_ALIGN_CHORDS 0x2
+
+/* These specify if the marker event signals whether to stop a variation or start a
+pattern/variation (or both), and whether new variations must align with a chord */
+#define DMUS_MARKERF_START 0x1
+#define DMUS_MARKERF_STOP 0x2
+#define DMUS_MARKERF_CHORD_ALIGN 0x4
+
+/* if this flag is set, variation settings in a playing pattern-based track's state data will
+persist in the track after it stops playing */
+#define DMUS_PATTERNF_PERSIST_CONTROL 0x1
+
+/* These specify possible values for DMUS_IO_PARTREF.bRandomVariation
+ all but DMUS_VARIATIONT_SEQUENTIAL and DMUS_VARIATIONT_RANDOM are dx8. */
+typedef enum enumDMUS_VARIATIONT_TYPES
+{
+ DMUS_VARIATIONT_SEQUENTIAL = 0, /* Play sequential starting with variation 1. */
+ DMUS_VARIATIONT_RANDOM = 1, /* Play randomly. */
+ DMUS_VARIATIONT_RANDOM_START = 2, /* Play sequential starting with a random variation. */
+ DMUS_VARIATIONT_NO_REPEAT = 3, /* Play randomly, but don't play the same variation twice. */
+ DMUS_VARIATIONT_RANDOM_ROW = 4 /* Play randomly as a row: don't repeat any variation until all have played. */
+} DMUS_VARIATIONT_TYPES;
+
+#pragma pack(2)
+
+typedef struct _DMUS_IO_TIMESIG
+{
+ /* Time signatures define how many beats per measure, which note receives */
+ /* the beat, and the grid resolution. */
+ BYTE bBeatsPerMeasure; /* beats per measure (top of time sig) */
+ BYTE bBeat; /* what note receives the beat (bottom of time sig.) */
+ /* we can assume that 0 means 256th note */
+ WORD wGridsPerBeat; /* grids per beat */
+} DMUS_IO_TIMESIG;
+
+typedef struct _DMUS_IO_STYLE
+{
+ DMUS_IO_TIMESIG timeSig; /* Styles have a default Time Signature */
+ double dblTempo;
+} DMUS_IO_STYLE;
+
+typedef struct _DMUS_IO_VERSION
+{
+ DWORD dwVersionMS; /* Version # high-order 32 bits */
+ DWORD dwVersionLS; /* Version # low-order 32 bits */
+} DMUS_IO_VERSION;
+
+typedef struct _DMUS_IO_PATTERN
+{
+ DMUS_IO_TIMESIG timeSig; /* Patterns can override the Style's Time sig. */
+ BYTE bGrooveBottom; /* bottom of groove range */
+ BYTE bGrooveTop; /* top of groove range */
+ WORD wEmbellishment; /* Fill, Break, Intro, End, Normal, Motif */
+ WORD wNbrMeasures; /* length in measures */
+ BYTE bDestGrooveBottom; /* bottom of groove range for next pattern */
+ BYTE bDestGrooveTop; /* top of groove range for next pattern */
+ DWORD dwFlags; /* various flags */
+} DMUS_IO_PATTERN;
+
+typedef struct _DMUS_IO_STYLEPART
+{
+ DMUS_IO_TIMESIG timeSig; /* can override pattern's */
+ DWORD dwVariationChoices[32]; /* MOAW choice bitfield */
+ GUID guidPartID; /* identifies the part */
+ WORD wNbrMeasures; /* length of the Part */
+ BYTE bPlayModeFlags; /* see PLAYMODE flags */
+ BYTE bInvertUpper; /* inversion upper limit */
+ BYTE bInvertLower; /* inversion lower limit */
+ BYTE bPad[3]; /* for DWORD alignment */
+ DWORD dwFlags; /* various flags */
+} DMUS_IO_STYLEPART;
+
+typedef struct _DMUS_IO_PARTREF
+{
+ GUID guidPartID; /* unique ID for matching up with parts */
+ WORD wLogicalPartID; /* corresponds to port/device/midi channel OBSOLETE */
+ BYTE bVariationLockID; /* parts with the same ID lock variations. */
+ /* high bit is used to identify master Part */
+ BYTE bSubChordLevel; /* tells which sub chord level this part wants */
+ BYTE bPriority; /* 256 priority levels. Parts with lower priority */
+ /* aren't played first when a device runs out of */
+ /* notes */
+ BYTE bRandomVariation; /* when set, matching variations play in random order */
+ /* when clear, matching variations play sequentially */
+ WORD wPad; /* not used */
+ DWORD dwPChannel; /* replaces wLogicalPartID */
+} DMUS_IO_PARTREF;
+
+typedef struct _DMUS_IO_STYLENOTE
+{
+ MUSIC_TIME mtGridStart; /* when this note occurs */
+ DWORD dwVariation; /* variation bits */
+ MUSIC_TIME mtDuration; /* how long this note lasts */
+ short nTimeOffset; /* offset from mtGridStart */
+ WORD wMusicValue; /* Position in scale. */
+ BYTE bVelocity; /* Note velocity. */
+ BYTE bTimeRange; /* Range to randomize start time. */
+ BYTE bDurRange; /* Range to randomize duration. */
+ BYTE bVelRange; /* Range to randomize velocity. */
+ BYTE bInversionID; /* Identifies inversion group to which this note belongs */
+ BYTE bPlayModeFlags; /* Can override part */
+ /* Following exists only under DX8 and on */
+ BYTE bNoteFlags; /* values from DMUS_NOTEF_FLAGS */
+} DMUS_IO_STYLENOTE;
+
+typedef struct _DMUS_IO_STYLECURVE
+{
+ MUSIC_TIME mtGridStart; /* when this curve occurs */
+ DWORD dwVariation; /* variation bits */
+ MUSIC_TIME mtDuration; /* how long this curve lasts */
+ MUSIC_TIME mtResetDuration;/* how long after the end of the curve to reset the curve */
+ short nTimeOffset; /* offset from mtGridStart */
+ short nStartValue; /* curve's start value */
+ short nEndValue; /* curve's end value */
+ short nResetValue; /* the value to which to reset the curve */
+ BYTE bEventType; /* type of curve */
+ BYTE bCurveShape; /* shape of curve */
+ BYTE bCCData; /* CC# */
+ BYTE bFlags; /* Bit 1=TRUE means to send nResetValue. Otherwise, don't.
+ Other bits are reserved. */
+ /* Following was added for DX8. */
+ WORD wParamType; /* RPN or NRPN parameter number. */
+ WORD wMergeIndex; /* Allows multiple parameters to be merged (pitchbend, volume, and expression.) */
+} DMUS_IO_STYLECURVE;
+
+typedef struct _DMUS_IO_STYLEMARKER
+{
+ MUSIC_TIME mtGridStart; /* when this marker occurs */
+ DWORD dwVariation; /* variation bits */
+ WORD wMarkerFlags; /* how the marker is used */
+} DMUS_IO_STYLEMARKER;
+
+typedef struct _DMUS_IO_STYLERESOLUTION
+{
+ DWORD dwVariation; /* variation bits */
+ WORD wMusicValue; /* Position in scale. */
+ BYTE bInversionID; /* Identifies inversion group to which this note belongs */
+ BYTE bPlayModeFlags; /* Can override part */
+} DMUS_IO_STYLERESOLUTION;
+
+typedef struct _DMUS_IO_STYLE_ANTICIPATION
+{
+ MUSIC_TIME mtGridStart; /* when this anticipation occurs */
+ DWORD dwVariation; /* variation bits */
+ short nTimeOffset; /* offset from mtGridStart */
+ BYTE bTimeRange; /* Range to randomize start time. */
+} DMUS_IO_STYLE_ANTICIPATION;
+
+typedef struct _DMUS_IO_MOTIFSETTINGS
+{
+ DWORD dwRepeats; /* Number of repeats. By default, 0. */
+ MUSIC_TIME mtPlayStart; /* Start of playback. By default, 0. */
+ MUSIC_TIME mtLoopStart; /* Start of looping portion. By default, 0. */
+ MUSIC_TIME mtLoopEnd; /* End of loop. Must be greater than mtLoopStart. Or, 0, indicating loop full motif. */
+ DWORD dwResolution; /* Default resolution. */
+} DMUS_IO_MOTIFSETTINGS;
+
+#pragma pack()
+
+
+/*
+RIFF
+(
+ 'DMST' // Style
+ <styh-ck> // Style header chunk
+ <guid-ck> // Every Style has a GUID
+ [<UNFO-list>] // Name, author, copyright info., comments
+ [<vers-ck>] // version chunk
+ <part-list>... // Array of parts in the Style, used by patterns
+ <pttn-list>... // Array of patterns in the Style
+ <DMBD-form>... // Array of bands in the Style
+ [<prrf-list>]...// Optional array of chord map references in the Style
+)
+
+ // <styh-ck>
+ styh
+ (
+ <DMUS_IO_STYLE>
+ )
+
+ // <guid-ck>
+ guid
+ (
+ <GUID>
+ )
+
+ // <vers-ck>
+ vers
+ (
+ <DMUS_IO_VERSION>
+ )
+
+ // <part-list>
+ LIST
+ (
+ 'part'
+ <prth-ck> // Part header chunk
+ [<UNFO-list>] // Name, author, copyright info., comments
+ [<note-ck>] // Optional chunk containing an array of notes in Part
+ [<crve-ck>] // Optional chunk containing an array of curves in Part
+ [<mrkr-ck>] // Optional chunk containing an array of markers in Part
+ [<rsln-ck>] // Optional chunk containing an array of variation resolutions in Part
+ [<anpn-ck>] // Optional chunk containing an array of resolution anticipations in Part
+ )
+
+ // <orth-ck>
+ prth
+ (
+ <DMUS_IO_STYLEPART>
+ )
+
+ // <note-ck>
+ 'note'
+ (
+ // sizeof DMUS_IO_STYLENOTE:DWORD
+ <DMUS_IO_STYLENOTE>...
+ )
+
+ // <crve-ck>
+ 'crve'
+ (
+ // sizeof DMUS_IO_STYLECURVE:DWORD
+ <DMUS_IO_STYLECURVE>...
+ )
+
+ // <mrkr-ck>
+ 'mrkr'
+ (
+ // sizeof DMUS_IO_STYLEMARKER:DWORD
+ <DMUS_IO_STYLEMARKER>...
+ )
+
+ // <rsln-ck>
+ 'rsln'
+ (
+ // sizeof DMUS_IO_STYLERESOLUTION:DWORD
+ <DMUS_IO_STYLERESOLUTION>...
+ )
+
+ // <anpn-ck>
+ 'anpn'
+ (
+ // sizeof DMUS_IO_STYLE_ANTICIPATION:DWORD
+ <DMUS_IO_STYLE_ANTICIPATION>...
+ )
+
+ // <pttn-list>
+ LIST
+ (
+ 'pttn'
+ <ptnh-ck> // Pattern header chunk
+ <rhtm-ck> // Chunk containing an array of rhythms for chord matching
+ [<UNFO-list>] // Name, author, copyright info., comments
+ [<mtfs-ck>] // Motif settings chunk
+ [<DMBD-form>] // Optional band to be associated with the pattern (for motifs)
+ <pref-list>... // Array of part reference id's
+ )
+
+ // <ptnh-ck>
+ ptnh
+ (
+ <DMUS_IO_PATTERN>
+ )
+
+ // <rhtm-ck>
+ 'rhtm'
+ (
+ // DWORD's representing rhythms for chord matching based on number
+ // of measures in the pattern
+ )
+
+
+ // pref-list
+ LIST
+ (
+ 'pref'
+ <prfc-ck> // part ref chunk
+ )
+
+ // <prfc-ck>
+ prfc
+ (
+ <DMUS_IO_PARTREF>
+ )
+
+ // <mtfs-ck>
+ mtfs
+ (
+ <DMUS_IO_MOTIFSETTINGS>
+ )
+
+ // <prrf-list>
+ LIST
+ (
+ 'prrf'
+ <DMRF-list>... // Array of Chordmap references
+ )
+*/
+
+/* Pattern chunk, for use in Pattern tracks */
+
+#define DMUS_FOURCC_PATTERN_FORM mmioFOURCC('D','M','P','T')
+
+/*
+RIFF
+(
+ 'DMPT' // Pattern
+ <styh-ck> // Style header chunk
+ <pttn-list> // The pattern, in single pattern format (includes DMUS_FOURCC_PART_LIST chunks)
+)
+*/
+
+
+/* Chord and command file formats */
+
+/* These specify possible values for DMUS_IO_COMMAND.bRepeatMode (dx8) */
+typedef enum enumDMUS_PATTERNT_TYPES
+{
+ DMUS_PATTERNT_RANDOM = 0, /* Play randomly. (dx7 behavior) */
+ DMUS_PATTERNT_REPEAT = 1, /* Repeat last pattern. */
+ DMUS_PATTERNT_SEQUENTIAL = 2, /* Play sequential starting with first matching pattern. */
+ DMUS_PATTERNT_RANDOM_START = 3, /* Play sequential starting with a random pattern. */
+ DMUS_PATTERNT_NO_REPEAT = 4, /* Play randomly, but don't play the same pattern twice. */
+ DMUS_PATTERNT_RANDOM_ROW = 5 /* Play randomly as a row: don't repeat any pattern until all have played. */
+} DMUS_PATTERNT_TYPES;
+
+#define DMUS_FOURCC_CHORDTRACK_LIST mmioFOURCC('c','o','r','d')
+#define DMUS_FOURCC_CHORDTRACKHEADER_CHUNK mmioFOURCC('c','r','d','h')
+#define DMUS_FOURCC_CHORDTRACKBODY_CHUNK mmioFOURCC('c','r','d','b')
+
+#define DMUS_FOURCC_COMMANDTRACK_CHUNK mmioFOURCC('c','m','n','d')
+
+typedef struct _DMUS_IO_CHORD
+{
+ WCHAR wszName[16]; /* Name of the chord */
+ MUSIC_TIME mtTime; /* Time of this chord */
+ WORD wMeasure; /* Measure this falls on */
+ BYTE bBeat; /* Beat this falls on */
+ BYTE bFlags; /* Various flags */
+} DMUS_IO_CHORD;
+
+typedef struct _DMUS_IO_SUBCHORD
+{
+ DWORD dwChordPattern; /* Notes in the subchord */
+ DWORD dwScalePattern; /* Notes in the scale */
+ DWORD dwInversionPoints; /* Where inversions can occur */
+ DWORD dwLevels; /* Which levels are supported by this subchord */
+ BYTE bChordRoot; /* Root of the subchord */
+ BYTE bScaleRoot; /* Root of the scale */
+} DMUS_IO_SUBCHORD;
+
+typedef struct _DMUS_IO_COMMAND
+{
+ MUSIC_TIME mtTime; /* Time of this command */
+ WORD wMeasure; /* Measure this falls on */
+ BYTE bBeat; /* Beat this falls on */
+ BYTE bCommand; /* Command type (see #defines below) */
+ BYTE bGrooveLevel; /* Groove level (0 if command is not a groove) */
+ BYTE bGrooveRange; /* Groove range */
+ BYTE bRepeatMode; /* Used to control selection of patterns with same groove level */
+} DMUS_IO_COMMAND;
+
+
+/*
+
+ // <cord-list>
+ LIST
+ (
+ 'cord'
+ <crdh-ck>
+ <crdb-ck> // Chord body chunk
+ )
+
+ // <crdh-ck>
+ crdh
+ (
+ // Scale: dword (upper 8 bits for root, lower 24 for scale)
+ )
+
+ // <crdb-ck>
+ crdb
+ (
+ // sizeof DMUS_IO_CHORD:dword
+ <DMUS_IO_CHORD>
+ // # of DMUS_IO_SUBCHORDS:dword
+ // sizeof DMUS_IO_SUBCHORDS:dword
+ // a number of <DMUS_IO_SUBCHORD>
+ )
+
+
+ // <cmnd-list>
+ 'cmnd'
+ (
+ //sizeof DMUS_IO_COMMAND: DWORD
+ <DMUS_IO_COMMAND>...
+ )
+
+*/
+
+/* File io for DirectMusic Tool and ToolGraph objects
+*/
+
+/* RIFF ids: */
+
+#define DMUS_FOURCC_TOOLGRAPH_FORM mmioFOURCC('D','M','T','G')
+#define DMUS_FOURCC_TOOL_LIST mmioFOURCC('t','o','l','l')
+#define DMUS_FOURCC_TOOL_FORM mmioFOURCC('D','M','T','L')
+#define DMUS_FOURCC_TOOL_CHUNK mmioFOURCC('t','o','l','h')
+
+/* io structures: */
+
+typedef struct _DMUS_IO_TOOL_HEADER
+{
+ GUID guidClassID; /* Class id of tool. */
+ long lIndex; /* Position in graph. */
+ DWORD cPChannels; /* Number of items in channels array. */
+ FOURCC ckid; /* chunk ID of tool's data chunk if 0 fccType valid. */
+ FOURCC fccType; /* list type if NULL ckid valid. */
+ DWORD dwPChannels[1]; /* Array of PChannels, size determined by cPChannels. */
+} DMUS_IO_TOOL_HEADER;
+
+/*
+RIFF
+(
+ 'DMTG' // DirectMusic ToolGraph chunk
+ [<guid-ck>] // GUID for ToolGraph
+ [<vers-ck>] // Optional version info
+ [<UNFO-list>] // Name, author, copyright info., comments
+ <toll-list> // List of Tools
+)
+
+ // <guid-ck>
+ 'guid'
+ (
+ <GUID>
+ )
+
+ // <vers-ck>
+ vers
+ (
+ <DMUS_IO_VERSION>
+ )
+
+ // <toll-list>
+ LIST
+ (
+ 'toll' // Array of tools
+ <DMTL-form>... // Each tool is encapsulated in a RIFF chunk
+ )
+
+// <DMTL-form> Tools are embedded in a graph. Theoretically, they can be saved as individual files too.
+RIFF
+(
+ 'DMTL'
+ <tolh-ck>
+ [<data>] // Tool data. Must be a RIFF readable chunk.
+)
+
+ // <tolh-ck> // Tool header chunk
+ (
+ 'tolh'
+ <DMUS_IO_TOOL_HEADER> // Tool header
+ )
+*/
+
+/* The AudioPath file carries everything for describing a specific audio path,
+ including Tool Graph and Buffer Descriptor.
+ This can even be used for configuring a complete performance.
+*/
+
+#define DMUS_FOURCC_AUDIOPATH_FORM mmioFOURCC('D','M','A','P')
+
+/*
+RIFF
+(
+ 'DMAP' // DirectMusic AudioPath chunk
+ [<guid-ck>] // GUID for this Audio Path configuration
+ [<vers-ck>] // Optional version info
+ [<UNFO-list>] // Name, author, copyright info., comments
+ [<DMTG-form>] // Optional ToolGraph
+ [<pcsl-list>] // Optional list of port configurations
+ [<dbfl-list>]...// Optional array of Dsound buffer descriptors
+)
+*/
+
+#define DMUS_FOURCC_PORTCONFIGS_LIST mmioFOURCC('p','c','s','l')
+#define DMUS_FOURCC_PORTCONFIG_LIST mmioFOURCC('p','c','f','l')
+#define DMUS_FOURCC_PORTCONFIG_ITEM mmioFOURCC('p','c','f','h')
+#define DMUS_FOURCC_PORTPARAMS_ITEM mmioFOURCC('p','p','r','h')
+#define DMUS_FOURCC_DSBUFFER_LIST mmioFOURCC('d','b','f','l')
+#define DMUS_FOURCC_DSBUFFATTR_ITEM mmioFOURCC('d','d','a','h')
+#define DMUS_FOURCC_PCHANNELS_LIST mmioFOURCC('p','c','h','l')
+#define DMUS_FOURCC_PCHANNELS_ITEM mmioFOURCC('p','c','h','h')
+
+typedef struct _DMUS_IO_PORTCONFIG_HEADER
+{
+ GUID guidPort; /* GUID of requested port. */
+ DWORD dwPChannelBase; /* PChannel that this should start on. */
+ DWORD dwPChannelCount; /* How many channels. */
+ DWORD dwFlags; /* Various flags. */
+} DMUS_IO_PORTCONFIG_HEADER;
+
+#define DMUS_PORTCONFIGF_DRUMSON10 1 /* This port configured for drums on channel 10. */
+#define DMUS_PORTCONFIGF_USEDEFAULT 2 /* Use the default port. */
+
+/* Each portconfig has one or more pchannel to buffer mappings. Each buffer
+ is identified by a guid. Each pchannel can map to one or more buffers.
+ This is defined with one or more DMUS_IO_PCHANNELTOBUFFER_HEADER
+ structures. Each defines a range of PChannels and the set of buffers
+ that they connect to.
+*/
+
+typedef struct _DMUS_IO_PCHANNELTOBUFFER_HEADER
+{
+ DWORD dwPChannelBase; /* PChannel that this should start on. */
+ DWORD dwPChannelCount; /* How many PChannels. */
+ DWORD dwBufferCount; /* How many buffers do these connect to. */
+ DWORD dwFlags; /* Various flags. Currently reserved for future use. Must be 0. */
+} DMUS_IO_PCHANNELTOBUFFER_HEADER;
+
+/* Each buffer is represented by an DSBC form. This is wrapped by the
+ DMUS_IO_BUFFER_ATTRIBUTES_HEADER which identifies how to use the
+ buffer. In particular, it indicates whether this gets dynamically duplicated
+ or all references to this should share the same instance.
+ To resolve references, the unique GUID of the buffer is also stored
+ in this structure.
+*/
+
+typedef struct _DMUS_IO_BUFFER_ATTRIBUTES_HEADER
+{
+ GUID guidBufferID; /* Each buffer config has a unique ID. */
+ DWORD dwFlags; /* Various flags. */
+} DMUS_IO_BUFFER_ATTRIBUTES_HEADER;
+
+/* DMUS_IO_BUFFER_ATTRIBUTES_HEADER.dwFlags: */
+#define DMUS_BUFFERF_SHARED 1 /* Share this with other audio paths, instead of creating unique copies. */
+#define DMUS_BUFFERF_DEFINED 2 /* Use one of the standard predefined buffers (see GUID_Buffer... in dmusici.h.) */
+#define DMUS_BUFFERF_MIXIN 8 /* This is a mixin buffer. */
+
+/*
+
+LIST
+(
+ 'pcsl' // Array of port configurations
+ <pcfl-list>... // One or more port configurations, each in a list chunk
+)
+
+LIST
+(
+ 'pcfl' // List container for one port configuration.
+ <pcfh-ck> // Portconfig header chunk.
+ <pprh-ck> // Port params, to be used to create the port.
+ [<dbfl-list>]...// Optional array of Dsound buffer descriptors
+ [<pchl-list>] // Optional list of pchannel to buffer assignments
+
+)
+
+ // <pcfh-ck> // Port config header chunk
+ (
+ 'pcfh'
+ <DMUS_IO_PORTCONFIG_HEADER> // Port config header
+ )
+
+ // <pprh-ck> // Port params header chunk
+ (
+ 'pprh'
+ <DMUS_PORTPARAMS8> // Port params header
+ )
+
+LIST
+(
+ 'pchl' // List container for one or more pchannel to buffer assignments.
+ <pchh-ck>... // One or more pchannel to buffer assignment headers and data.
+
+ // <pchh-ck>
+ (
+ 'pchh'
+ <DMUS_IO_PCHANNELTOBUFFER_HEADER> // Description of PChannels
+ <GUID>... // Array of GUIDs defining the buffers they all connect to.
+ )
+)
+
+LIST
+(
+ 'dbfl' // List container for one buffer and buffer attributes header.
+ <ddah-ck> // Buffer attributes header.
+ [<DSBC-form>] // Buffer configuration. Not required when header uses a predefined buffer type.
+
+ // <ddah-ck>
+ (
+ 'ddah'
+ <DMUS_IO_BUFFER_ATTRIBUTES_HEADER> // Buffer attributes.
+ )
+)
+*/
+
+/* File io for DirectMusic Band Track object */
+
+
+/* RIFF ids: */
+#define DMUS_FOURCC_BANDTRACK_FORM mmioFOURCC('D','M','B','T')
+#define DMUS_FOURCC_BANDTRACK_CHUNK mmioFOURCC('b','d','t','h')
+#define DMUS_FOURCC_BANDS_LIST mmioFOURCC('l','b','d','l')
+#define DMUS_FOURCC_BAND_LIST mmioFOURCC('l','b','n','d')
+#define DMUS_FOURCC_BANDITEM_CHUNK mmioFOURCC('b','d','i','h')
+#define DMUS_FOURCC_BANDITEM_CHUNK2 mmioFOURCC('b','d','2','h')
+
+/* io structures */
+typedef struct _DMUS_IO_BAND_TRACK_HEADER
+{
+ BOOL bAutoDownload; /* Determines if Auto-Download is enabled. */
+} DMUS_IO_BAND_TRACK_HEADER;
+
+typedef struct _DMUS_IO_BAND_ITEM_HEADER
+{
+ MUSIC_TIME lBandTime; /* Position in track list. */
+} DMUS_IO_BAND_ITEM_HEADER;
+
+typedef struct _DMUS_IO_BAND_ITEM_HEADER2
+{
+ MUSIC_TIME lBandTimeLogical; /* Position in track list. Time in the music with which band change is associated. */
+ MUSIC_TIME lBandTimePhysical; /* Precise time band change will take effect. Should be close to logical time. */
+} DMUS_IO_BAND_ITEM_HEADER2;
+
+/*
+RIFF
+(
+ 'DMBT' // DirectMusic Band Track form-type
+ [<bdth-ck>] // Band track header
+ [<guid-ck>] // GUID for band track
+ [<vers-ck>] // Optional version info
+ [<UNFO-list>] // Name, author, copyright info., comments
+ <lbdl-list> // List of Band items
+)
+
+ // <bnth-ck>
+ 'bdth'
+ (
+ <DMUS_IO_BAND_TRACK_HEADER>
+ )
+
+ // <guid-ck>
+ 'guid'
+ (
+ <GUID>
+ )
+
+ // <vers-ck>
+ vers
+ (
+ <DMUS_IO_VERSION>
+ )
+
+ // <lbdl-list>
+ LIST
+ (
+ 'lbdl'
+ <lbnd-list>... // Array of bands, each encapsulated in a list chunk
+ )
+
+ // <lbnd-list>
+ LIST
+ (
+ 'lbnd'
+ <bdih-ck> or <bd2h-ck> // bdih is a legacy format. bd2h is preferred for new content.
+ <DMBD-form> // Band
+ )
+
+ // <bdih-ck> or <bd2h-ck> // band item header
+ (
+ <DMUS_IO_BAND_ITEM_HEADER> or <DMUS_IO_BAND_ITEM_HEADER2> // Band item header
+ )
+*/
+
+
+/* File io for DirectMusic Band object
+*/
+
+/* RIFF ids: */
+
+#define DMUS_FOURCC_BAND_FORM mmioFOURCC('D','M','B','D')
+#define DMUS_FOURCC_INSTRUMENTS_LIST mmioFOURCC('l','b','i','l')
+#define DMUS_FOURCC_INSTRUMENT_LIST mmioFOURCC('l','b','i','n')
+#define DMUS_FOURCC_INSTRUMENT_CHUNK mmioFOURCC('b','i','n','s')
+
+/* Flags for DMUS_IO_INSTRUMENT
+ */
+#define DMUS_IO_INST_PATCH (1 << 0) /* dwPatch is valid. */
+#define DMUS_IO_INST_BANKSELECT (1 << 1) /* dwPatch contains a valid Bank Select MSB and LSB part */
+#define DMUS_IO_INST_ASSIGN_PATCH (1 << 3) /* dwAssignPatch is valid */
+#define DMUS_IO_INST_NOTERANGES (1 << 4) /* dwNoteRanges is valid */
+#define DMUS_IO_INST_PAN (1 << 5) /* bPan is valid */
+#define DMUS_IO_INST_VOLUME (1 << 6 ) /* bVolume is valid */
+#define DMUS_IO_INST_TRANSPOSE (1 << 7) /* nTranspose is valid */
+#define DMUS_IO_INST_GM (1 << 8) /* Instrument is from GM collection */
+#define DMUS_IO_INST_GS (1 << 9) /* Instrument is from GS collection */
+#define DMUS_IO_INST_XG (1 << 10) /* Instrument is from XG collection */
+#define DMUS_IO_INST_CHANNEL_PRIORITY (1 << 11) /* dwChannelPriority is valid */
+#define DMUS_IO_INST_USE_DEFAULT_GM_SET (1 << 12) /* Always use the default GM set for this patch, */
+ /* don't rely on the synth caps stating GM or GS in hardware. */
+#define DMUS_IO_INST_PITCHBENDRANGE (1 << 13) /* nPitchBendRange is valid */
+
+/* io structures */
+typedef struct _DMUS_IO_INSTRUMENT
+{
+ DWORD dwPatch; /* MSB, LSB and Program change to define instrument */
+ DWORD dwAssignPatch; /* MSB, LSB and Program change to assign to instrument when downloading */
+ DWORD dwNoteRanges[4]; /* 128 bits; one for each MIDI note instrument needs to able to play */
+ DWORD dwPChannel; /* PChannel instrument plays on */
+ DWORD dwFlags; /* DMUS_IO_INST_ flags */
+ BYTE bPan; /* Pan for instrument */
+ BYTE bVolume; /* Volume for instrument */
+ short nTranspose; /* Number of semitones to transpose notes */
+ DWORD dwChannelPriority; /* Channel priority */
+ short nPitchBendRange; /* Number of semitones shifted by pitch bend */
+} DMUS_IO_INSTRUMENT;
+
+/*
+// <DMBD-form> bands can be embedded in other forms
+RIFF
+(
+ 'DMBD' // DirectMusic Band chunk
+ [<guid-ck>] // GUID for band
+ [<vers-ck>] // Optional version info
+ [<UNFO-list>] // Name, author, copyright info., comments
+ <lbil-list> // List of Instruments
+)
+
+ // <guid-ck>
+ 'guid'
+ (
+ <GUID>
+ )
+
+ // <vers-ck>
+ vers
+ (
+ <DMUS_IO_VERSION>
+ )
+
+ // <lbil-list>
+ LIST
+ (
+ 'lbil' // Array of instruments
+ <lbin-list>... // Each instrument is encapsulated in a list
+ )
+
+ // <lbin-list>
+ LIST
+ (
+ 'lbin'
+ <bins-ck>
+ [<DMRF-list>] // Optional reference to DLS Collection file.
+ )
+
+ // <bins-ck> // Instrument chunk
+ (
+ 'bins'
+ <DMUS_IO_INSTRUMENT> // Instrument header
+ )
+*/
+
+/* This RIFF id and io struct have been added to allow wave files (and the wave object) to
+ differentiate between streaming and one-shot waves, and to give a prefetch for streaming
+ waves */
+
+#define DMUS_FOURCC_WAVEHEADER_CHUNK mmioFOURCC('w','a','v','h')
+
+typedef struct _DMUS_IO_WAVE_HEADER
+{
+ REFERENCE_TIME rtReadAhead; /* How far ahead in the stream wave data will be read (in REFERENCE_TIME). Ignored for one-shot waves. */
+ DWORD dwFlags; /* Various flags, including whether this is a streaming wave and whether it can be invalidated. */
+} DMUS_IO_WAVE_HEADER;
+
+
+/* File io for Wave track */
+
+/* RIFF ids: */
+
+#define DMUS_FOURCC_WAVETRACK_LIST mmioFOURCC('w','a','v','t')
+#define DMUS_FOURCC_WAVETRACK_CHUNK mmioFOURCC('w','a','t','h')
+#define DMUS_FOURCC_WAVEPART_LIST mmioFOURCC('w','a','v','p')
+#define DMUS_FOURCC_WAVEPART_CHUNK mmioFOURCC('w','a','p','h')
+#define DMUS_FOURCC_WAVEITEM_LIST mmioFOURCC('w','a','v','i')
+#define DMUS_FOURCC_WAVE_LIST mmioFOURCC('w','a','v','e')
+#define DMUS_FOURCC_WAVEITEM_CHUNK mmioFOURCC('w','a','i','h')
+
+/* This flag is included in DMUS_IO_WAVE_TRACK_HEADER.dwFlags. If set, the track will get its
+ variations from a pattern track, via GetParam(GUID_Variations). */
+#define DMUS_WAVETRACKF_SYNC_VAR 0x1
+/* This is also included in DMUS_IO_WAVE_TRACK_HEADER.dwFlags. If set, variation control
+ information will persist from one playback instance to the next.*/
+#define DMUS_WAVETRACKF_PERSIST_CONTROL 0x2
+
+typedef struct _DMUS_IO_WAVE_TRACK_HEADER
+{
+ long lVolume; /* Gain, in 1/100th of dB, to be applied to all waves. Note: All gain values should be negative. */
+ DWORD dwFlags; /* Flags, including whether this track syncs to a pattern track for its variations. */
+} DMUS_IO_WAVE_TRACK_HEADER;
+
+typedef struct _DMUS_IO_WAVE_PART_HEADER
+{
+ long lVolume; /* Gain, in 1/100th of dB, to be applied to all waves in wave part. Note: All gain values should be negative. */
+ DWORD dwVariations; /* Variation mask for which of 32 variations */
+ DWORD dwPChannel; /* PChannel */
+ DWORD dwLockToPart; /* Part ID to lock to. */
+ DWORD dwFlags; /* Flags, including stuff for managing how variations are chosen (in low-order nibble) */
+ DWORD dwIndex; /* Index for distinguishing multiple parts on the same PChannel*/
+} DMUS_IO_WAVE_PART_HEADER;
+
+typedef struct _DMUS_IO_WAVE_ITEM_HEADER
+{
+ long lVolume; /* Gain, in 1/100th of dB. Note: All gain values should be negative. */
+ long lPitch; /* Pitch offset in 1/100th of a semitone. */
+ DWORD dwVariations; /* Variation flags for which of 32 variations this wave belongs to. */
+ REFERENCE_TIME rtTime; /* Start time, in REFERENCE_TIME, if clock time track, or MUSIC_TIME for music time track. */
+ REFERENCE_TIME rtStartOffset; /* Distance into wave to start playback, in reference time units. */
+ REFERENCE_TIME rtReserved; /* Reserved field. */
+ REFERENCE_TIME rtDuration; /* Duration, in REFERENCE_TIME or MUSIC_TIME, depending on track timing format. */
+ MUSIC_TIME mtLogicalTime; /* If in music track format, this indicates the musical boundary where this belongs. Otherwise, ignored. */
+ DWORD dwLoopStart; /* Start point for a looping wave. */
+ DWORD dwLoopEnd; /* End point for a looping wave. */
+ DWORD dwFlags; /* Various flags, including whether this is a streaming wave and whether it can be invalidated. */
+} DMUS_IO_WAVE_ITEM_HEADER;
+
+/*
+LIST
+{
+ 'wavt' // Wave track chunk
+ <wath-ck> // Wave track header
+ <wavp-list>... // Array of Wave Parts
+}
+ // <wath-ck>
+ 'wath'
+ {
+ <DMUS_IO_WAVE_TRACK_HEADER>
+ }
+
+ // <wavp-list>
+ LIST
+ {
+ 'wavp'
+ <waph-ck> // Wave Part Header
+ <wavi-list> // List of wave items
+ }
+
+ // <waph-ck>
+ 'waph'
+ {
+ <DMUS_IO_WAVE_PART_HEADER>
+ }
+
+ // <wavi-list>
+ LIST
+ {
+ 'wavi'
+ <wave-list>... // Array of waves; each wave is encapsulated in a list
+ }
+
+ // <wave-list>
+ LIST
+ {
+ 'wave'
+ <waih-ck> // Wave item header
+ <DMRF-list> // Reference to wave object
+ }
+
+ // <waih-ck>
+ 'waih'
+ {
+ <DMUS_IO_WAVE_ITEM_HEADER>
+ }
+
+*/
+
+/* File io for DirectMusic Container file. This embeds a set of related files. And,
+ in turn, it can be embedded within a segment or script file.
+*/
+
+#define DMUS_FOURCC_CONTAINER_FORM mmioFOURCC('D','M','C','N')
+#define DMUS_FOURCC_CONTAINER_CHUNK mmioFOURCC('c','o','n','h')
+#define DMUS_FOURCC_CONTAINED_ALIAS_CHUNK mmioFOURCC('c','o','b','a')
+#define DMUS_FOURCC_CONTAINED_OBJECT_CHUNK mmioFOURCC('c','o','b','h')
+#define DMUS_FOURCC_CONTAINED_OBJECTS_LIST mmioFOURCC('c','o','s','l')
+#define DMUS_FOURCC_CONTAINED_OBJECT_LIST mmioFOURCC('c','o','b','l')
+
+typedef struct _DMUS_IO_CONTAINER_HEADER
+{
+ DWORD dwFlags; /* Flags. */
+} DMUS_IO_CONTAINER_HEADER;
+
+#define DMUS_CONTAINER_NOLOADS (1 << 1) /* Contained items are not loaded when the container is loaded.
+ Entries will be created in the loader (via SetObject) but
+ the actual objects will not be created until they are
+ specifically loaded at a later time. */
+
+typedef struct _DMUS_IO_CONTAINED_OBJECT_HEADER
+{
+ GUID guidClassID; /* Class id of object. */
+ DWORD dwFlags; /* Flags, for example DMUS_CONTAINED_OBJF_KEEP. */
+ FOURCC ckid; /* chunk ID of track's data chunk if 0 fccType valid. */
+ FOURCC fccType; /* list type if NULL ckid valid */
+ /* Note that LIST:DMRF may be used for ckid and fccType in order to reference an
+ object instead of embedding it within the container. */
+} DMUS_IO_CONTAINED_OBJECT_HEADER;
+
+#define DMUS_CONTAINED_OBJF_KEEP 1 /* Keep the object cached in the loader after the container is released. */
+
+/*
+RIFF
+(
+ 'DMCN' // DirectMusic Container chunk
+ <conh-ck> // Container header chunk
+ [<guid-ck>] // GUID for container
+ [<vers-ck>] // Optional version info
+ [<UNFO-list>] // Name, author, copyright info., comments
+ <cosl-list> // List of objects.
+)
+
+ // <conh-ck>
+ 'conh'
+ (
+ <DMUS_IO_CONTAINER_HEADER>
+ )
+
+ // <guid-ck>
+ 'guid'
+ (
+ <GUID>
+ )
+
+ // <vers-ck>
+ vers
+ (
+ <DMUS_IO_VERSION>
+ )
+
+ LIST
+ (
+ 'cosl' // Array of embedded objects.
+ <cobl-list>... // Each object is encapsulated in a LIST chunk
+ )
+
+ // <cobl-list> // Encapsulates one object
+ LIST
+ (
+ 'cobl'
+ [<coba-ck>] // Alias. An alternative name by which this object is known
+ // within the container.
+ <cobh-ck> // Required header, includes CLASS ID for object.
+ [<data>] or <DMRF> // Object data of the type specified in <cobh-ck>.
+ // If DMRF, it is a reference of where to find the object.
+ // Otherwise, it could be any RIFF readable chunk in the
+ // exact same format as a file. The object will load
+ // itself from this data.
+ )
+
+ // <coba-ck>
+ 'coba'
+ (
+ // Alias, stored as NULL terminated string of WCHARs
+ )
+
+ // <cobh-ck>
+ 'cobh'
+ (
+ <DMUS_IO_CONTAINED_OBJECT_HEADER>
+ )
+*/
+
+/* File io for DirectMusic Segment object */
+
+/* RIFF ids: */
+
+#define DMUS_FOURCC_SEGMENT_FORM mmioFOURCC('D','M','S','G')
+#define DMUS_FOURCC_SEGMENT_CHUNK mmioFOURCC('s','e','g','h')
+#define DMUS_FOURCC_TRACK_LIST mmioFOURCC('t','r','k','l')
+#define DMUS_FOURCC_TRACK_FORM mmioFOURCC('D','M','T','K')
+#define DMUS_FOURCC_TRACK_CHUNK mmioFOURCC('t','r','k','h')
+#define DMUS_FOURCC_TRACK_EXTRAS_CHUNK mmioFOURCC('t','r','k','x')
+
+/* io structures:*/
+
+typedef struct _DMUS_IO_SEGMENT_HEADER
+{
+ DWORD dwRepeats; /* Number of repeats. By default, 0. */
+ MUSIC_TIME mtLength; /* Length, in music time. */
+ MUSIC_TIME mtPlayStart; /* Start of playback. By default, 0. */
+ MUSIC_TIME mtLoopStart; /* Start of looping portion. By default, 0. */
+ MUSIC_TIME mtLoopEnd; /* End of loop. Must be greater than dwPlayStart. Or, 0, indicating loop full segment. */
+ DWORD dwResolution; /* Default resolution. */
+ /* Following added for DX8: */
+ REFERENCE_TIME rtLength; /* Length, in reference time (overrides music time length.) */
+ DWORD dwFlags;
+ DWORD dwReserved; /* Reserved. */
+} DMUS_IO_SEGMENT_HEADER;
+
+#define DMUS_SEGIOF_REFLENGTH 1 /* Use the time in rtLength for the segment length. */
+
+typedef struct _DMUS_IO_TRACK_HEADER
+{
+ GUID guidClassID; /* Class id of track. */
+ DWORD dwPosition; /* Position in track list. */
+ DWORD dwGroup; /* Group bits for track. */
+ FOURCC ckid; /* chunk ID of track's data chunk. */
+ FOURCC fccType; /* list type if ckid is RIFF or LIST */
+} DMUS_IO_TRACK_HEADER;
+
+/* Additional parameters for the track header chunk, introduced in DX8 and
+ on, are stored in a separate chunk. */
+
+typedef struct _DMUS_IO_TRACK_EXTRAS_HEADER
+{
+ DWORD dwFlags; /* DX8 Added flags for control tracks. */
+ DWORD dwPriority; /* Priority for composition. */
+} DMUS_IO_TRACK_EXTRAS_HEADER;
+
+/*
+RIFF
+(
+ 'DMSG' // DirectMusic Segment chunk
+ <segh-ck> // Segment header chunk
+ [<guid-ck>] // GUID for segment
+ [<vers-ck>] // Optional version info
+ [<UNFO-list>] // Name, author, copyright info., comments
+ [<DMCN-form>] // Optional container of objects embedded in file. Must precede tracklist.
+ <trkl-list> // List of Tracks
+ [<DMTG-form>] // Optional ToolGraph
+ [<DMAP-form>] // Optional Audio Path
+)
+
+ // <segh-ck>
+ 'segh'
+ (
+ <DMUS_IO_SEGMENT_HEADER>
+ )
+
+ // <guid-ck>
+ 'guid'
+ (
+ <GUID>
+ )
+
+ // <vers-ck>
+ vers
+ (
+ <DMUS_IO_VERSION>
+ )
+
+ // <trkl-list>
+ LIST
+ (
+ 'trkl' // Array of tracks
+ <DMTK-form>... // Each track is encapsulated in a RIFF chunk
+ )
+
+ // <DMTK-form> // Tracks can be embedded in a segment or stored as separate files.
+ RIFF
+ (
+ 'DMTK'
+ <trkh-ck>
+ [<trkx-ck>] // Optional track flags.
+ [<guid-ck>] // Optional GUID for track object instance (not to be confused with Class id in track header)
+ [<vers-ck>] // Optional version info
+ [<UNFO-list>] // Optional name, author, copyright info., comments
+ [<data>] // Track data. Must be a RIFF readable chunk.
+ )
+
+ // <trkh-ck> // Track header chunk
+ (
+ 'trkh'
+ <DMUS_IO_TRACK_HEADER> // Track header
+ )
+
+ // <trkx-ck> // Track flags chunk
+ (
+ 'trkx'
+ <DMUS_IO_TRACK_EXTRAS_HEADER> // DX8 Track flags header
+ )
+*/
+
+/* File io for DirectMusic Song object */
+/* Note: Song file format is not supported in DX8. */
+
+/* RIFF ids: */
+
+#define DMUS_FOURCC_SONG_FORM mmioFOURCC('D','M','S','O') /* Entire song. */
+#define DMUS_FOURCC_SONG_CHUNK mmioFOURCC('s','n','g','h') /* Song header info. */
+#define DMUS_FOURCC_SONGSEGMENTS_LIST mmioFOURCC('s','e','g','l') /* List of embedded segments. */
+#define DMUS_FOURCC_SONGSEGMENT_LIST mmioFOURCC('s','s','g','l') /* Container for a segment or segment reference. */
+#define DMUS_FOURCC_TOOLGRAPHS_LIST mmioFOURCC('t','l','g','l') /* List of embedded tool graphs. */
+#define DMUS_FOURCC_SEGREFS_LIST mmioFOURCC('s','r','s','l') /* List of segment references. */
+#define DMUS_FOURCC_SEGREF_LIST mmioFOURCC('s','g','r','l') /* Container for a segment reference. */
+#define DMUS_FOURCC_SEGREF_CHUNK mmioFOURCC('s','g','r','h') /* Segment reference header. */
+#define DMUS_FOURCC_SEGTRANS_CHUNK mmioFOURCC('s','t','r','h') /* Set of transitions to this segment. */
+#define DMUS_FOURCC_TRACKREFS_LIST mmioFOURCC('t','r','s','l') /* Set of track references within the segment reference. */
+#define DMUS_FOURCC_TRACKREF_LIST mmioFOURCC('t','k','r','l') /* Container for a track reference. */
+#define DMUS_FOURCC_TRACKREF_CHUNK mmioFOURCC('t','k','r','h') /* Track reference header. */
+
+/* io structures:*/
+
+typedef struct _DMUS_IO_SONG_HEADER
+{
+ DWORD dwFlags;
+ DWORD dwStartSegID; /* Id of the segment that starts playback. */
+} DMUS_IO_SONG_HEADER;
+
+typedef struct _DMUS_IO_SEGREF_HEADER
+{
+ DWORD dwID; /* Each has a unique ID. Must be less than DMUS_SONG_MAXSEGID. */
+ DWORD dwSegmentID; /* Optional segment to link to. */
+ DWORD dwToolGraphID; /* Optional tool graph to use for processing. */
+ DWORD dwFlags; /* Various control flags. Currently reserved for future use. Must be 0. */
+ DWORD dwNextPlayID; /* ID of next segment, to chain segments into a song. */
+} DMUS_IO_SEGREF_HEADER;
+
+
+typedef struct _DMUS_IO_TRACKREF_HEADER
+{
+ DWORD dwSegmentID; /* Which segment to find this in. */
+ DWORD dwFlags; /* Reference control flags. */
+} DMUS_IO_TRACKREF_HEADER;
+
+/* Transition definition chunk defines a transition, using an optional transition template
+ segment.
+*/
+
+typedef struct _DMUS_IO_TRANSITION_DEF
+{
+ DWORD dwSegmentID; /* Segment the transition goes to. */
+ DWORD dwTransitionID; /* Template segment to use for the transition. */
+ DWORD dwPlayFlags; /* Flags to use for transition. */
+} DMUS_IO_TRANSITION_DEF;
+
+#define DMUS_SONG_MAXSEGID 0x7FFFFFFF /* Segment ids can not go higher than this. */
+#define DMUS_SONG_ANYSEG 0x80000000 /* Special ID to indicate any segment. */
+#define DMUS_SONG_NOSEG 0xFFFFFFFF /* Special ID to indicate no segment. */
+#define DMUS_SONG_NOFROMSEG 0x80000001 /* Special ID for dwSegmentID to indicate transition from nothing (or outside the song) into this segment. */
+
+/*
+RIFF
+(
+ 'DMSO' // DirectMusic Song chunk
+ <sngh-ck> // Song header chunk
+ [<guid-ck>] // GUID for song
+ [<vers-ck>] // Optional version info
+ [<UNFO-list>] // Name, author, copyright info., comments
+ [<DMCN-form>] // Optional container of objects embedded in file. Must precede segment list.
+ <segl-list> // List of Segments
+ [<tlgl-list>] // Optional list of ToolGraphs
+ [<DMAP-form>] // Optional Audio Path - to be shared by all segments in song.
+ <srsl-list> // List of segment references.
+)
+
+ // <sngh-ck>
+ 'sngh'
+ (
+ <DMUS_IO_SONG_HEADER>
+ )
+
+ // <segl-list>
+ LIST
+ (
+ 'segl' // Array of segments
+ <ssgl-list>... // Each segment is wrapped in this.
+ )
+
+ // <ssgl-list>
+ LIST
+ (
+ 'ssgl' // Segment container.
+ [DMSG-form] // Each segment is either a full embedded segment RIFF form.
+ [DMRF-list] // Or a reference to an external segment.
+ )
+
+ // <tlgl-list>
+ LIST
+ (
+ 'tlgl' // Array of toolgraphs
+ <DMTG-form>... // Each toolgraph is a full RIFF form.
+ )
+
+ // <srsl-list>
+ LIST
+ (
+ 'srsl' // Array of segment references
+ <sgrl-list>... // Each segment reference is contained in a RIFF list.
+ )
+
+ // <sgrl-list> // Segment reference container.
+ LIST
+ (
+ 'sgrl'
+ <sgrh-ck> // Segment reference header chunk.
+ <segh-ck> // Segment header chunk. Defines the segment.
+ <UNFO-list> // Name, author, etc. Primarily for name, though, which is required for Song->GetSegment().
+ [<strh-ck>] // Segment transition chunk. Defines how to do transitions from other segments.
+ [<trsl-list>] // List of track references, to create a segment from tracks in multiple segments.
+ )
+
+ // <sgrh-ck> // Segment reference header chunk
+ (
+ 'sgrh'
+ <DMUS_IO_SEGREF_HEADER> // Segment reference header
+ )
+
+ // <strh-ck> // Segment transition chunk.
+ (
+ 'strh'
+ <DMUS_IO_TRANSITION_DEF> // Default transition.
+ <DMUS_IO_TRANSITION_DEF>... // Additional transitions.
+ )
+
+ // <trsl-list> // Array of track references
+ (
+ 'trsl'
+ <tkrl-list>... // Each track reference is multiple chunks in a tkrl list.
+ )
+
+ // <tkrl-list> // Track reference container
+ (
+ 'tkrl'
+ <tkrh-ck> // Track reference header chunk.
+ <trkh-ck> // Normal track header chunk.
+ [<trkx-ck>] // Optional track flags.
+ )
+
+ // <tkrh-ck> // Track reference header chunk
+ (
+ 'tkrh'
+ <DMUS_IO_TRACKREF_HEADER> // Track reference header
+ )
+*/
+
+/* File io for DirectMusic reference chunk.
+ This is used to embed a reference to an object.
+*/
+
+/* RIFF ids: */
+
+#define DMUS_FOURCC_REF_LIST mmioFOURCC('D','M','R','F')
+#define DMUS_FOURCC_REF_CHUNK mmioFOURCC('r','e','f','h')
+#define DMUS_FOURCC_DATE_CHUNK mmioFOURCC('d','a','t','e')
+#define DMUS_FOURCC_NAME_CHUNK mmioFOURCC('n','a','m','e')
+#define DMUS_FOURCC_FILE_CHUNK mmioFOURCC('f','i','l','e')
+
+typedef struct _DMUS_IO_REFERENCE
+{
+ GUID guidClassID; /* Class id is always required. */
+ DWORD dwValidData; /* Flags. */
+} DMUS_IO_REFERENCE;
+
+/*
+LIST
+(
+ 'DMRF' // DirectMusic Reference chunk
+ <refh-ck> // Reference header chunk
+ [<guid-ck>] // Optional object GUID.
+ [<date-ck>] // Optional file date.
+ [<name-ck>] // Optional name.
+ [<file-ck>] // Optional file name.
+ [<catg-ck>] // Optional category name.
+ [<vers-ck>] // Optional version info.
+)
+
+ // <refh-ck>
+ 'refh'
+ (
+ <DMUS_IO_REFERENCE>
+ )
+
+ // <guid-ck>
+ 'guid'
+ (
+ <GUID>
+ )
+
+ // <date-ck>
+ date
+ (
+ <FILETIME>
+ )
+
+ // <name-ck>
+ name
+ (
+ // Name, stored as NULL terminated string of WCHARs
+ )
+
+ // <file-ck>
+ file
+ (
+ // File name, stored as NULL terminated string of WCHARs
+ )
+
+ // <catg-ck>
+ catg
+ (
+ // Category name, stored as NULL terminated string of WCHARs
+ )
+
+ // <vers-ck>
+ vers
+ (
+ <DMUS_IO_VERSION>
+ )
+*/
+
+/* Chord Maps */
+
+/* runtime chunks */
+#define DMUS_FOURCC_CHORDMAP_FORM mmioFOURCC('D','M','P','R')
+#define DMUS_FOURCC_IOCHORDMAP_CHUNK mmioFOURCC('p','e','r','h')
+#define DMUS_FOURCC_SUBCHORD_CHUNK mmioFOURCC('c','h','d','t')
+#define DMUS_FOURCC_CHORDENTRY_CHUNK mmioFOURCC('c','h','e','h')
+#define DMUS_FOURCC_SUBCHORDID_CHUNK mmioFOURCC('s','b','c','n')
+#define DMUS_FOURCC_IONEXTCHORD_CHUNK mmioFOURCC('n','c','r','d')
+#define DMUS_FOURCC_NEXTCHORDSEQ_CHUNK mmioFOURCC('n','c','s','q')
+#define DMUS_FOURCC_IOSIGNPOST_CHUNK mmioFOURCC('s','p','s','h')
+#define DMUS_FOURCC_CHORDNAME_CHUNK mmioFOURCC('I','N','A','M')
+
+/* runtime list chunks */
+#define DMUS_FOURCC_CHORDENTRY_LIST mmioFOURCC('c','h','o','e')
+#define DMUS_FOURCC_CHORDMAP_LIST mmioFOURCC('c','m','a','p')
+#define DMUS_FOURCC_CHORD_LIST mmioFOURCC('c','h','r','d')
+#define DMUS_FOURCC_CHORDPALETTE_LIST mmioFOURCC('c','h','p','l')
+#define DMUS_FOURCC_CADENCE_LIST mmioFOURCC('c','a','d','e')
+#define DMUS_FOURCC_SIGNPOSTITEM_LIST mmioFOURCC('s','p','s','t')
+
+#define DMUS_FOURCC_SIGNPOST_LIST mmioFOURCC('s','p','s','q')
+
+/* values for dwChord field of DMUS_IO_PERS_SIGNPOST */
+/* DMUS_SIGNPOSTF_ flags are also used in templates (DMUS_IO_SIGNPOST) */
+#define DMUS_SIGNPOSTF_A 1
+#define DMUS_SIGNPOSTF_B 2
+#define DMUS_SIGNPOSTF_C 4
+#define DMUS_SIGNPOSTF_D 8
+#define DMUS_SIGNPOSTF_E 0x10
+#define DMUS_SIGNPOSTF_F 0x20
+#define DMUS_SIGNPOSTF_LETTER (DMUS_SIGNPOSTF_A | DMUS_SIGNPOSTF_B | DMUS_SIGNPOSTF_C | DMUS_SIGNPOSTF_D | DMUS_SIGNPOSTF_E | DMUS_SIGNPOSTF_F)
+#define DMUS_SIGNPOSTF_1 0x100
+#define DMUS_SIGNPOSTF_2 0x200
+#define DMUS_SIGNPOSTF_3 0x400
+#define DMUS_SIGNPOSTF_4 0x800
+#define DMUS_SIGNPOSTF_5 0x1000
+#define DMUS_SIGNPOSTF_6 0x2000
+#define DMUS_SIGNPOSTF_7 0x4000
+#define DMUS_SIGNPOSTF_ROOT (DMUS_SIGNPOSTF_1 | DMUS_SIGNPOSTF_2 | DMUS_SIGNPOSTF_3 | DMUS_SIGNPOSTF_4 | DMUS_SIGNPOSTF_5 | DMUS_SIGNPOSTF_6 | DMUS_SIGNPOSTF_7)
+#define DMUS_SIGNPOSTF_CADENCE 0x8000
+
+/* values for dwFlags field of DMUS_IO_CHORDMAP */
+#define DMUS_CHORDMAPF_VERSION8 1 /* Chordmap is version 8 or above. */
+
+/* values for dwChord field of DMUS_IO_PERS_SIGNPOST */
+#define DMUS_SPOSTCADENCEF_1 2 /* Use the first cadence chord. */
+#define DMUS_SPOSTCADENCEF_2 4 /* Use the second cadence chord. */
+
+/* run time data structs */
+typedef struct _DMUS_IO_CHORDMAP
+{
+ WCHAR wszLoadName[20];
+ DWORD dwScalePattern;
+ DWORD dwFlags; /* Various flags. Only lower 16 bits are significant. */
+} DMUS_IO_CHORDMAP;
+
+typedef struct _DMUS_IO_CHORDMAP_SUBCHORD
+{
+ DWORD dwChordPattern;
+ DWORD dwScalePattern;
+ DWORD dwInvertPattern;
+ BYTE bChordRoot;
+ BYTE bScaleRoot;
+ WORD wCFlags;
+ DWORD dwLevels; /* parts or which subchord levels this chord supports */
+} DMUS_IO_CHORDMAP_SUBCHORD;
+
+/* Legacy name... */
+typedef DMUS_IO_CHORDMAP_SUBCHORD DMUS_IO_PERS_SUBCHORD;
+
+typedef struct _DMUS_IO_CHORDENTRY
+{
+ DWORD dwFlags;
+ WORD wConnectionID; /* replaces runtime "pointer to this" */
+} DMUS_IO_CHORDENTRY;
+
+typedef struct _DMUS_IO_NEXTCHORD
+{
+ DWORD dwFlags;
+ WORD nWeight;
+ WORD wMinBeats;
+ WORD wMaxBeats;
+ WORD wConnectionID; /* points to an ioChordEntry */
+} DMUS_IO_NEXTCHORD;
+
+typedef struct _DMUS_IO_CHORDMAP_SIGNPOST
+{
+ DWORD dwChords; /* 1bit per group */
+ DWORD dwFlags;
+} DMUS_IO_CHORDMAP_SIGNPOST;
+
+/* Legacy name... */
+typedef DMUS_IO_CHORDMAP_SIGNPOST DMUS_IO_PERS_SIGNPOST;
+
+/*
+RIFF
+(
+ 'DMPR'
+ <perh-ck> // Chord map header chunk
+ [<guid-ck>] // guid chunk
+ [<vers-ck>] // version chunk (two DWORDS)
+ [<UNFO-list>] // Unfo chunk
+ <chdt-ck> // subchord database
+ <chpl-list> // chord palette
+ <cmap-list> // chord map
+ <spsq-list> // signpost list
+ )
+
+<cmap-list> ::= LIST('cmap' <choe-list> )
+
+<choe-list> ::= LIST('choe'
+ <cheh-ck> // chord entry data
+ <chrd-list> // chord definition
+ <ncsq-ck> // connecting(next) chords
+ )
+
+<chrd-list> ::= LIST('chrd'
+ <INAM-ck> // name of chord in wide char format
+ <sbcn-ck> // list of subchords composing chord
+ )
+
+<chpl-list> ::= LIST('chpl'
+ <chrd-list> ... // chord definition
+ )
+
+<spsq-list> ::== LIST('spsq' <spst-list> ... )
+
+<spst-list> ::= LIST('spst'
+ <spsh-ck>
+ <chrd-list>
+ [<cade-list>]
+ )
+
+<cade-list> ::= LIST('cade' <chrd-list> ...)
+
+<perh-ck> ::= perh(<DMUS_IO_CHORDMAP>)
+
+<chdt-ck> ::= chdt(<cbChordSize::WORD>
+ <DMUS_IO_PERS_SUBCHORD> ... )
+
+<cheh-ck> ::= cheh(<DMUS_IO_CHORDENTRY>)
+
+<sbcn-ck> ::= sbcn(<cSubChordID:WORD> ...)
+
+<ncsq-ck> ::= ncsq(<wNextChordSize:WORD>
+ <DMUS_IO_NEXTCHORD>...)
+
+<spsh-ck> ::= spsh(<DMUS_IO_PERS_SIGNPOST>)
+
+*/
+
+/* File io for DirectMusic Script object */
+
+/* RIFF ids: */
+
+#define DMUS_FOURCC_SCRIPT_FORM mmioFOURCC('D','M','S','C')
+#define DMUS_FOURCC_SCRIPT_CHUNK mmioFOURCC('s','c','h','d')
+#define DMUS_FOURCC_SCRIPTVERSION_CHUNK mmioFOURCC('s','c','v','e')
+#define DMUS_FOURCC_SCRIPTLANGUAGE_CHUNK mmioFOURCC('s','c','l','a')
+#define DMUS_FOURCC_SCRIPTSOURCE_CHUNK mmioFOURCC('s','c','s','r')
+
+/* io structures:*/
+
+typedef struct _DMUS_IO_SCRIPT_HEADER
+{
+ DWORD dwFlags; /* DMUS_SCRIPTIOF_ flags */
+} DMUS_IO_SCRIPT_HEADER;
+
+#define DMUS_SCRIPTIOF_LOAD_ALL_CONTENT (1 << 0)
+ /* If set, when the script loads it will also load all the content in its container. */
+#define DMUS_SCRIPTIOF_DOWNLOAD_ALL_SEGMENTS (1 << 1)
+ /* If set and LOAD_ALL_CONTENT is also set, when the script initializes it will also download all the segments in its container.
+ If set and LOAD_ALL_CONTENT is not set, when the script calls segment.Load on a segment then the segment will also be downloaded.
+ If not set, the script must manually download and unload by calling segment.DownloadSoundData and segment.UnloadSoundData. */
+
+/*
+RIFF
+(
+ 'DMSC' // DirectMusic Script chunk
+ <schd-ck> // Script header chunk
+ [<guid-ck>] // GUID for script
+ [<vers-ck>] // Optional version info
+ [<UNFO-list>] // Name, author, copyright info., comments
+ <scve-ck> // Version of DirectMusic this script was authored to run against
+ <DMCN-form> // Container of content referenced by the script.
+ <scla-ck> // ActiveX scripting language in which the script is written
+ <scsr-ck> or <DMRF> // The script's source code.
+ // If scsr-ck, the source is embedding in the chunk.
+ // If DMRF, it is a reference of where to find a text file with the source.
+ // Class id (guidClassID in DMUS_IO_REFERENCE) must be GUID_NULL because
+ // this text file is not a DirectMusic object in its own right.
+)
+
+ // <schd-ck>
+ 'schd'
+ (
+ <DMUS_FOURCC_SCRIPT_CHUNK>
+ )
+
+ // <guid-ck>
+ 'guid'
+ (
+ <GUID>
+ )
+
+ // <vers-ck>
+ vers
+ (
+ <DMUS_IO_VERSION>
+ )
+
+ // <scve-ck>
+ scve
+ (
+ <DMUS_IO_VERSION>
+ )
+
+ 'scla'
+ (
+ // Language name, stored as NULL terminated string of WCHARs
+ )
+
+ 'scsr'
+ (
+ // Source code, stored as NULL terminated string of WCHARs
+ )
+*/
+
+/* Signpost tracks */
+
+#define DMUS_FOURCC_SIGNPOST_TRACK_CHUNK mmioFOURCC( 's', 'g', 'n', 'p' )
+
+
+typedef struct _DMUS_IO_SIGNPOST
+{
+ MUSIC_TIME mtTime;
+ DWORD dwChords;
+ WORD wMeasure;
+} DMUS_IO_SIGNPOST;
+
+/*
+
+ // <sgnp-list>
+ 'sgnp'
+ (
+ //sizeof DMUS_IO_SIGNPOST: DWORD
+ <DMUS_IO_SIGNPOST>...
+ )
+
+*/
+
+#define DMUS_FOURCC_MUTE_CHUNK mmioFOURCC('m','u','t','e')
+
+typedef struct _DMUS_IO_MUTE
+{
+ MUSIC_TIME mtTime;
+ DWORD dwPChannel;
+ DWORD dwPChannelMap;
+} DMUS_IO_MUTE;
+
+/*
+
+ // <mute-list>
+ 'mute'
+ (
+ //sizeof DMUS_IO_MUTE:DWORD
+ <DMUS_IO_MUTE>...
+ )
+
+
+*/
+
+/* Used for both style and chord map tracks */
+
+#define DMUS_FOURCC_TIME_STAMP_CHUNK mmioFOURCC('s', 't', 'm', 'p')
+
+/* Style tracks */
+
+#define DMUS_FOURCC_STYLE_TRACK_LIST mmioFOURCC('s', 't', 't', 'r')
+#define DMUS_FOURCC_STYLE_REF_LIST mmioFOURCC('s', 't', 'r', 'f')
+
+/*
+
+ // <sttr-list>
+ LIST('sttr'
+ (
+ <strf-list>... // Array of Style references
+ )
+
+ // <strf-list>
+ LIST('strf'
+ (
+ <stmp-ck>
+ <DMRF>
+ )
+
+ // <stmp-ck>
+ 'stmp'
+ (
+ // time:DWORD
+ )
+
+*/
+
+/* Chord map tracks */
+
+#define DMUS_FOURCC_PERS_TRACK_LIST mmioFOURCC('p', 'f', 't', 'r')
+#define DMUS_FOURCC_PERS_REF_LIST mmioFOURCC('p', 'f', 'r', 'f')
+
+/*
+
+ // <pftr-list>
+ LIST('pftr'
+ (
+ <pfrf-list>... // Array of Chord map references
+ )
+
+ // <pfrf-list>
+ LIST('pfrf'
+ (
+ <stmp-ck>
+ <DMRF>
+ )
+
+ // <stmp-ck>
+ 'stmp'
+ (
+ // time:DWORD
+ )
+
+*/
+
+#define DMUS_FOURCC_TEMPO_TRACK mmioFOURCC('t','e','t','r')
+
+/*
+ // tempo array
+ 'tetr'
+ (
+ // sizeof DMUS_IO_TEMPO_ITEM: DWORD
+ <DMUS_IO_TEMPO_ITEM>...
+ )
+ */
+
+#define DMUS_FOURCC_SEQ_TRACK mmioFOURCC('s','e','q','t')
+#define DMUS_FOURCC_SEQ_LIST mmioFOURCC('e','v','t','l')
+#define DMUS_FOURCC_CURVE_LIST mmioFOURCC('c','u','r','l')
+
+/*
+ // sequence track
+ 'seqt'
+ (
+ // sequence array
+ 'evtl'
+ (
+ // sizeof DMUS_IO_SEQ_ITEM: DWORD
+ <DMUS_IO_SEQ_ITEM>...
+ )
+ // curve array
+ 'curl'
+ (
+ // sizeof DMUS_IO_CURVE_ITEM: DWORD
+ <DMUS_IO_CURVE_ITEM>...
+ )
+ )
+*/
+
+#define DMUS_FOURCC_SYSEX_TRACK mmioFOURCC('s','y','e','x')
+
+/*
+ // sysex track
+ 'syex'
+ (
+ {
+ <DMUS_IO_SYSEX_ITEM>
+ <BYTE>... // Array of bytes, length defined in the DMUS_IO_SYSEXITEM structure
+ }...
+ )
+*/
+
+#define DMUS_FOURCC_TIMESIGNATURE_TRACK mmioFOURCC('t','i','m','s')
+
+typedef struct _DMUS_IO_TIMESIGNATURE_ITEM
+{
+ MUSIC_TIME lTime;
+ BYTE bBeatsPerMeasure; /* beats per measure (top of time sig) */
+ BYTE bBeat; /* what note receives the beat (bottom of time sig.) */
+ /* we can assume that 0 means 256th note */
+ WORD wGridsPerBeat; /* grids per beat */
+} DMUS_IO_TIMESIGNATURE_ITEM;
+
+/* DX6 time signature track
+
+ 'tims'
+ (
+ // size of DMUS_IO_TIMESIGNATURE_ITEM : DWORD
+ <DMUS_IO_TIMESIGNATURE_ITEM>...
+ )
+*/
+
+/* DX8 Time signature track. The track has been updated from DX7 to support a list of
+ RIFF chunks. This will allow the time signature track to expand in the future.
+*/
+
+#define DMUS_FOURCC_TIMESIGTRACK_LIST mmioFOURCC('T','I','M','S')
+#define DMUS_FOURCC_TIMESIG_CHUNK DMUS_FOURCC_TIMESIGNATURE_TRACK
+
+/*
+LIST
+(
+ 'TIMS' // Time Signature Track list-type
+ <tims-ck> // Chunk containing an array of time signatures
+)
+
+ 'tims'
+ (
+ // size of DMUS_IO_TIMESIGNATURE_ITEM : DWORD
+ <DMUS_IO_TIMESIGNATURE_ITEM>...
+ )
+
+*/
+
+/* DX8 Marker track. This is used to store valid start points and other
+ flow control parameters that may come later. For example, if we want
+ to implement more sophisticated looping and branching constructs, they
+ would live in this track.
+*/
+
+#define DMUS_FOURCC_MARKERTRACK_LIST mmioFOURCC('M','A','R','K')
+#define DMUS_FOURCC_VALIDSTART_CHUNK mmioFOURCC('v','a','l','s')
+#define DMUS_FOURCC_PLAYMARKER_CHUNK mmioFOURCC('p','l','a','y')
+
+/* io structures */
+typedef struct _DMUS_IO_VALID_START
+{
+ MUSIC_TIME mtTime; /* Time of a legal start. */
+} DMUS_IO_VALID_START;
+
+typedef struct _DMUS_IO_PLAY_MARKER
+{
+ MUSIC_TIME mtTime; /* Time of a next legal play point marker. */
+} DMUS_IO_PLAY_MARKER;
+
+/*
+LIST
+(
+ 'MARK' // Marker Track list-type
+ [<vals-ck>] // Chunk containing an array of start points
+ [<play-ck>] // Chunk containing an array of play start markers
+)
+
+ 'vals'
+ (
+ // size of DMUS_IO_VALID_START : DWORD
+ <DMUS_IO_VALID_START>...
+ )
+
+ 'play'
+ (
+ // size of DMUS_IO_PLAY_MARKER : DWORD
+ <DMUS_IO_PLAY_MARKER>...
+ )
+
+*/
+
+/* segment trigger tracks */
+
+/* RIFF ids: */
+#define DMUS_FOURCC_SEGTRACK_LIST mmioFOURCC('s','e','g','t')
+#define DMUS_FOURCC_SEGTRACK_CHUNK mmioFOURCC('s','g','t','h')
+#define DMUS_FOURCC_SEGMENTS_LIST mmioFOURCC('l','s','g','l')
+#define DMUS_FOURCC_SEGMENT_LIST mmioFOURCC('l','s','e','g')
+#define DMUS_FOURCC_SEGMENTITEM_CHUNK mmioFOURCC('s','g','i','h')
+#define DMUS_FOURCC_SEGMENTITEMNAME_CHUNK mmioFOURCC('s','n','a','m')
+
+/* io structures */
+typedef struct _DMUS_IO_SEGMENT_TRACK_HEADER
+{
+ DWORD dwFlags; /* Reserved leave as 0. */
+} DMUS_IO_SEGMENT_TRACK_HEADER;
+
+typedef struct _DMUS_IO_SEGMENT_ITEM_HEADER
+{
+ MUSIC_TIME lTimeLogical; /* Position in track list. Time in the music with which the event is associated. */
+ MUSIC_TIME lTimePhysical; /* Precise time event will be triggered. Should be close to logical time. */
+ DWORD dwPlayFlags; /* Flags for PlaySegment(). */
+ DWORD dwFlags; /* Flags. */
+} DMUS_IO_SEGMENT_ITEM_HEADER;
+
+/* values for dwflags field of DMUS_IO_SEGMENT_ITEM_HEADER */
+#define DMUS_SEGMENTTRACKF_MOTIF 1 /* interpret DMRF as link to style, and use snam as the name of a motif within the style */
+
+/*
+LIST
+(
+ 'segt' // DirectMusic Segment Trigger Track form-type
+ [<sgth-ck>] // Segment track header
+ <lsgl-list> // List of Segment Lists
+)
+
+ // <sgth-ck>
+ 'sgth'
+ (
+ <DMUS_IO_SEGMENT_TRACK_HEADER>
+ )
+
+ // <lsgl-list>
+ LIST
+ (
+ 'lsgl' // Array of segments
+ <lseg-list>... // Each segment is encapsulated in a list (that way it can still be riff parsed.)
+ )
+
+ // <lseg-list>
+ LIST
+ (
+ 'lseg'
+ <sgih-ck>
+ <DMRF-list> // Link to a segment or style file.
+ [<snam-ck>] // Name field. Used with DMUS_SEGMENTTRACKF_MOTIF flag.
+ )
+
+ // <sgih-ck> // segment item header
+ (
+ <DMUS_IO_SEGMENT_ITEM_HEADER> // Segment item header
+ )
+
+ // <snam-ck>
+ (
+ // Name, stored as NULL terminated string of WCHARs
+ )
+*/
+
+/* Script track. */
+
+/* RIFF ids: */
+#define DMUS_FOURCC_SCRIPTTRACK_LIST mmioFOURCC('s','c','r','t')
+#define DMUS_FOURCC_SCRIPTTRACKEVENTS_LIST mmioFOURCC('s','c','r','l')
+#define DMUS_FOURCC_SCRIPTTRACKEVENT_LIST mmioFOURCC('s','c','r','e')
+#define DMUS_FOURCC_SCRIPTTRACKEVENTHEADER_CHUNK mmioFOURCC('s','c','r','h')
+#define DMUS_FOURCC_SCRIPTTRACKEVENTNAME_CHUNK mmioFOURCC('s','c','r','n')
+
+/* Flags for DMUS_IO_SCRIPTTRACK_TIMING
+ */
+#define DMUS_IO_SCRIPTTRACKF_PREPARE (1 << 0) /* Fire event in advance of time stamp, at Prepare time. This is the default because it leaves the script time to change the music happening at the target time. */
+#define DMUS_IO_SCRIPTTRACKF_QUEUE (1 << 1) /* Fire event just before time stamp, at Queue time. */
+#define DMUS_IO_SCRIPTTRACKF_ATTIME (1 << 2) /* Fire event right at the time stamp. */
+
+typedef struct _DMUS_IO_SCRIPTTRACK_EVENTHEADER
+{
+ DWORD dwFlags; /* various bits (see DMUS_IO_SCRIPTTRACKF_*) */
+ MUSIC_TIME lTimeLogical; /* Position in track list. Time in the music with which the event is associated. */
+ MUSIC_TIME lTimePhysical; /* Precise time event will be triggered. Should be close to logical time. */
+} DMUS_IO_SCRIPTTRACK_EVENTHEADER;
+
+/*
+ // Script Track
+
+ // <scrt-list>
+ LIST
+ (
+ <scrl-list> // List of script events
+ )
+
+ // <scrl-list>
+ LIST
+ (
+ <scre-list>... // Array of event descriptions
+ )
+
+ // <scre-list>
+ LIST
+ (
+ <scrh-ck> // Event header chunk
+ <DMRF>
+ <scrn-ck> // Routine name
+ )
+
+ 'scrh'
+ (
+ <DMUS_IO_SCRIPTTRACK_EVENTHEADER>
+ )
+
+ 'scrn'
+ (
+ // Name, stored as NULL terminated string of WCHARs
+ )
+*/
+
+/* Lyrics/Notification track. */
+
+/* RIFF ids: */
+#define DMUS_FOURCC_LYRICSTRACK_LIST mmioFOURCC('l','y','r','t')
+#define DMUS_FOURCC_LYRICSTRACKEVENTS_LIST mmioFOURCC('l','y','r','l')
+#define DMUS_FOURCC_LYRICSTRACKEVENT_LIST mmioFOURCC('l','y','r','e')
+#define DMUS_FOURCC_LYRICSTRACKEVENTHEADER_CHUNK mmioFOURCC('l','y','r','h')
+#define DMUS_FOURCC_LYRICSTRACKEVENTTEXT_CHUNK mmioFOURCC('l','y','r','n')
+
+typedef struct _DMUS_IO_LYRICSTRACK_EVENTHEADER
+{
+ DWORD dwFlags; /* Reserved leave as 0. */
+ DWORD dwTimingFlags; /* Combination DMUS_PMSGF_TOOL_* flags. Determines the precise timing of when the notification happens. Invalid with the flag DMUS_PMSGF_REFTIME, DMUS_PMSGF_MUSICTIME, DMUS_PMSGF_TOOL_FLUSH, or DMUS_PMSGF_LOCKTOREFTIME. */
+ MUSIC_TIME lTimeLogical; /* Position in track list. Time in the music with which the event is associated. */
+ MUSIC_TIME lTimePhysical; /* Precise time event will be triggered. Should be close to logical time. */
+} DMUS_IO_LYRICSTRACK_EVENTHEADER;
+
+/*
+ // Lyrics/Notification Track
+
+ // <lyrt-list>
+ LIST
+ (
+ <lyrl-list> // List of notification events
+ )
+
+ // <lyrl-list>
+ LIST
+ (
+ <lyre-list>... // Array of event descriptions
+ )
+
+ // <lyre-list>
+ LIST
+ (
+ <lyrh-ck> // Event header chunk
+ <lyrn-ck> // Notification text
+ )
+
+ 'lyrh'
+ (
+ <DMUS_IO_LYRICSTRACK_EVENTHEADER>
+ )
+
+ 'lyrn'
+ (
+ // Name, stored as NULL terminated string of WCHARs
+ )
+*/
+
+/* Parameter control track */
+
+/* RIFF ids: */
+#define DMUS_FOURCC_PARAMCONTROLTRACK_TRACK_LIST mmioFOURCC('p','r','m','t')
+#define DMUS_FOURCC_PARAMCONTROLTRACK_OBJECT_LIST mmioFOURCC('p','r','o','l')
+#define DMUS_FOURCC_PARAMCONTROLTRACK_OBJECT_CHUNK mmioFOURCC('p','r','o','h')
+#define DMUS_FOURCC_PARAMCONTROLTRACK_PARAM_LIST mmioFOURCC('p','r','p','l')
+#define DMUS_FOURCC_PARAMCONTROLTRACK_PARAM_CHUNK mmioFOURCC('p','r','p','h')
+#define DMUS_FOURCC_PARAMCONTROLTRACK_CURVES_CHUNK mmioFOURCC('p','r','c','c')
+
+typedef struct _DMUS_IO_PARAMCONTROLTRACK_OBJECTHEADER
+{
+ DWORD dwFlags; /* Reserved. Must be zero. */
+ GUID guidTimeFormat; /* Time format to set the object to. Must be GUID_TIME_REFERNCE or GUID_TIME_MUSIC from medparam.h. */
+ /* Path for finding the object. These fields correspond to the first five parameters of IDirectMusicSegmentState::GetObjectInPath. */
+ DWORD dwPChannel;
+ DWORD dwStage;
+ DWORD dwBuffer;
+ GUID guidObject;
+ DWORD dwIndex;
+} DMUS_IO_PARAMCONTROLTRACK_OBJECTHEADER;
+
+typedef struct _DMUS_IO_PARAMCONTROLTRACK_PARAMHEADER
+{
+ DWORD dwFlags; /* Reserved. Must be zero. */
+ DWORD dwIndex; /* Index number of the parameter on the object */
+} DMUS_IO_PARAMCONTROLTRACK_PARAMHEADER;
+
+typedef struct _DMUS_IO_PARAMCONTROLTRACK_CURVEINFO
+{
+ MUSIC_TIME mtStartTime;
+ MUSIC_TIME mtEndTime;
+ float fltStartValue;
+ float fltEndValue;
+ DWORD dwCurveType; /* One of the items from the MP_CURVE_TYPE enum in medparam.h */
+ DWORD dwFlags; /* A combination of the MPF_ENVLP_* constants in medparam.h */
+} DMUS_IO_PARAMCONTROLTRACK_CURVEINFO;
+
+/*
+ // <prmt-list>
+ LIST
+ (
+ <prol-list>... // one for each object
+ )
+
+ // <prol-list>
+ LIST
+ (
+ <proh-ck> // object header chunk
+ <prpl-list>... // one for each parameter
+ )
+
+ // <proh-ck>
+ proh
+ (
+ <DMUS_IO_PARAMCONTROLTRACK_OBJECTHEADER>
+ )
+
+ // <prpl-list>
+ LIST
+ (
+ <prph-ck> // parameter header chunk
+ <prcc-ck> // chunk containing an array of curves
+ )
+
+ // <prph-ck>
+ prph
+ (
+ <DMUS_IO_PARAMCONTROLTRACK_PARAMHEADER>
+ )
+
+ // <prcc-ck>
+ prcc
+ (
+ // sizeof DMUS_IO_PARAMCONTROLTRACK_CURVEINFO:DWORD
+ <DMUS_IO_PARAMCONTROLTRACK_CURVEINFO>... // curves, sorted in order of mtTime
+ )
+*/
+
+/* Melody formulation track */
+/* Note: Melody formulation file format is not supported in DX8. */
+
+typedef DMUS_CONNECTION_RULE DMUS_IO_CONNECTION_RULE; /* defined in dmusici.h */
+
+typedef DMUS_MELODY_FRAGMENT DMUS_IO_MELODY_FRAGMENT; /* defined in dmusici.h */
+
+#define DMUS_FOURCC_MELODYFORM_TRACK_LIST mmioFOURCC( 'm', 'f', 'r', 'm' )
+#define DMUS_FOURCC_MELODYFORM_HEADER_CHUNK mmioFOURCC( 'm', 'l', 'f', 'h' )
+#define DMUS_FOURCC_MELODYFORM_BODY_CHUNK mmioFOURCC( 'm', 'l', 'f', 'b' )
+
+typedef struct _DMUS_IO_MELFORM
+{
+ DWORD dwPlaymode; /* NOT CURRENTLY USED - MUST BE 0 */
+} DMUS_IO_MELFORM;
+
+
+/*
+ // <mfrm-list>
+ LIST
+ (
+ 'mfrm'
+ <mlfh-ck> // Melody formulation header chunk
+ <mlfb-ck> // Melody formulation body chunk
+ )
+
+ // <mlfb-ck>
+ 'mlfb'
+ (
+ <DMUS_IO_MELFORM>
+ )
+
+ // <mlfb-ck>
+ 'mlfb'
+ (
+ //sizeof DMUS_IO_MELODY_FRAGMENT: DWORD
+ <DMUS_IO_MELODY_FRAGMENT>...
+ )
+
+*/
+
+#if (DIRECTSOUND_VERSION >= 0x0800)
+
+/* DirectSoundBufferConfig FX Map */
+
+/* RIFF ids: */
+
+#define DMUS_FOURCC_DSBC_FORM mmioFOURCC('D','S','B','C')
+#define DMUS_FOURCC_DSBD_CHUNK mmioFOURCC('d','s','b','d')
+#define DMUS_FOURCC_BSID_CHUNK mmioFOURCC('b','s','i','d')
+#define DMUS_FOURCC_DS3D_CHUNK mmioFOURCC('d','s','3','d')
+#define DMUS_FOURCC_DSBC_LIST mmioFOURCC('f','x','l','s')
+#define DMUS_FOURCC_DSFX_FORM mmioFOURCC('D','S','F','X')
+#define DMUS_FOURCC_DSFX_CHUNK mmioFOURCC('f','x','h','r')
+#define DMUS_FOURCC_DSFX_DATA mmioFOURCC('d','a','t','a')
+
+/* io structures */
+
+typedef struct _DSOUND_IO_DSBUFFERDESC
+{
+ DWORD dwFlags; /* DirectSound buffer creation flags */
+ WORD nChannels; /* No. of channels (rest of buffer format is determined by owning sink) */
+ LONG lVolume; /* Initial pan; only used if CTRLVOLUME is specified */
+ LONG lPan; /* Initial pan; only used if CTRLPAN is specified */
+ DWORD dwReserved; /* Reserved - must be 0 */
+} DSOUND_IO_DSBUFFERDESC;
+
+typedef struct _DSOUND_IO_DSBUSID
+{
+ DWORD busid[1]; /* Array size determined from chunk size */
+} DSOUND_IO_DSBUSID;
+
+typedef struct _DSOUND_IO_3D
+{
+ GUID guid3DAlgorithm; /* GUID identifying the 3D algorithm to use (defined in dsound.h) */
+ DS3DBUFFER ds3d; /* Initial 3D parameters */
+} DSOUND_IO_3D;
+
+typedef struct _DSOUND_IO_DXDMO_HEADER
+{
+ DWORD dwEffectFlags; /* Effect creation flags - equivalent to DSEFFECTDESC::dwFlags */
+ GUID guidDSFXClass; /* GUID identifying the effect to use - corresponds to a COM CLSID */
+ GUID guidReserved; /* Reserved - must be the null GUID */
+ GUID guidSendBuffer; /* GUID identifying the buffer to send to if this is a send effect */
+ DWORD dwReserved; /* Reserved - must be 0 */
+} DSOUND_IO_DXDMO_HEADER;
+
+typedef struct _DSOUND_IO_DXDMO_DATA
+{
+ DWORD data[1]; /* Array size determined by the DMO involved */
+} DSOUND_IO_DXDMO_DATA;
+
+/*
+RIFF
+(
+ 'DSBC' // DirectSoundBufferConfig chunk
+ [<guid-ck>] // GUID identifier for this DirectSoundBufferConfig
+ [<vers-ck>] // Optional version info
+ [<UNFO-list>] // Name, author, copyright info., comments
+ <dsbd-ck> // DirectSound Buffer descriptor chunk
+ [<bsid-ck>] // Optional bus id array
+ [<ds3d-ck>] // Optional 3d Parameters
+ [<fxls-list>] // Optional list of FX descriptors
+)
+
+ // <guid-ck>
+ 'guid'
+ (
+ <GUID>
+ )
+
+ // <vers-ck>
+ 'vers'
+ (
+ <DMUS_IO_VERSION>
+ )
+
+ // <dsbd-ck>
+ 'dsbd'
+ (
+ <DSOUND_IO_DSBUFFERDESC> // Creation parameters and initial settings for the buffer
+ )
+
+ // <bsid-ck>
+ 'bsid'
+ (
+ <DSOUND_IO_DSBUSID> // The size of DSOUND_IO_DSBUSID is determined by the chunk size
+ )
+
+ // <ds3d-ck>
+ 'ds3d'
+ (
+ <DSOUND_IO_3D> // Initial 3D buffer parameters: position, etc.
+ )
+
+ // <fx-list>
+ LIST
+ (
+ 'fxls' // Array of DMO creation parameter blocks
+ <DSFX-form>... // Each DMO is encapsulated in a RIFF chunk
+ )
+
+// <DSFX-form> // DMOs can be embedded in a buffer configuration or stored as separate files
+RIFF
+(
+ 'DSFX'
+ <fxhr-ck> // FX header chunk
+ [<data-ck>] // FX initial settings chunk
+)
+
+ // <fxhr-ck>
+ 'fxhr'
+ (
+ <DSOUND_IO_DXDMO_HEADER>
+ )
+
+ // <data-ck>
+ 'data'
+ (
+ <DSOUND_IO_DXDMO_DATA> // Opaque data block used by the DMO to load itself.
+ // For our standard included DMOs, this is simply the structure accepted by
+ // the DMO's SetAllParameters() method - e.g. struct DSFXChorus for Chorus.
+ )
+*/
+
+#endif
+
+#ifdef __cplusplus
+}; /* extern "C" */
+#endif
+
+#include <poppack.h>
+
+#endif /* #ifndef _DMUSICF_ */
diff --git a/Src/Plugins/Input/in_midi/dmusici.h b/Src/Plugins/Input/in_midi/dmusici.h
new file mode 100644
index 00000000..c6bc37db
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/dmusici.h
@@ -0,0 +1,1964 @@
+/************************************************************************
+* *
+* dmusici.h -- This module contains the API for the *
+* DirectMusic performance layer *
+* *
+* Copyright (c) 1998-1999 Microsoft Corporation
+* *
+************************************************************************/
+
+#ifndef _DMUSICI_
+#define _DMUSICI_
+
+#include <windows.h>
+
+#define COM_NO_WINDOWS_H
+#include <objbase.h>
+
+#include <mmsystem.h>
+#include <dmusicc.h>
+/* plugin (track and tool) interfaces. This #include will eventually go away. */
+#include <dmplugin.h>
+
+#include <pshpack8.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef WORD TRANSITION_TYPE;
+typedef __int64 REFERENCE_TIME;
+typedef long MUSIC_TIME;
+
+#define MT_MIN 0x80000000 /* Minimum music time value. */
+#define MT_MAX 0x7FFFFFFF /* Maximum music time value. */
+
+#define DMUS_PPQ 768 /* parts per quarter note */
+
+interface IDirectMusicTrack;
+interface IDirectMusicPerformance;
+interface IDirectMusicPerformance8;
+interface IDirectMusicTool;
+interface IDirectMusicSegment;
+interface IDirectMusicSegment8;
+interface IDirectMusicSegmentState;
+interface IDirectMusicSegmentState8;
+interface IDirectMusicGraph;
+interface IDirectMusicBuffer;
+interface IDirectMusicInstrument;
+interface IDirectMusicDownloadedInstrument;
+interface IDirectMusicBand;
+interface IDirectMusicChordMap;
+interface IDirectMusicLoader;
+interface IDirectMusicLoader8;
+interface IDirectMusicScript;
+interface IDirectMusicObject;
+interface IDirectMusicStyle8;
+interface IDirectMusicPatternTrack;
+interface IDirectMusicContainer;
+interface IDirectMusicTool8;
+interface IDirectMusicTrack8;
+interface IDirectMusicSong;
+interface IDirectMusicAudioPath;
+#ifndef __cplusplus
+typedef interface IDirectMusicTrack IDirectMusicTrack;
+typedef interface IDirectMusicPerformance IDirectMusicPerformance;
+typedef interface IDirectMusicPerformance8 IDirectMusicPerformance8;
+typedef interface IDirectMusicTool IDirectMusicTool;
+typedef interface IDirectMusicSegment IDirectMusicSegment;
+typedef interface IDirectMusicSegment8 IDirectMusicSegment8;
+typedef interface IDirectMusicSegmentState IDirectMusicSegmentState;
+typedef interface IDirectMusicSegmentState8 IDirectMusicSegmentState8;
+typedef interface IDirectMusicGraph IDirectMusicGraph;
+typedef interface IDirectMusicBuffer IDirectMusicBuffer;
+typedef interface IDirectMusicInstrument IDirectMusicInstrument;
+typedef interface IDirectMusicDownloadedInstrument IDirectMusicDownloadedInstrument;
+typedef interface IDirectMusicBand IDirectMusicBand;
+typedef interface IDirectMusicChordMap IDirectMusicChordMap;
+typedef interface IDirectMusicObject IDirectMusicObject;
+typedef interface IDirectMusicLoader IDirectMusicLoader;
+typedef interface IDirectMusicLoader8 IDirectMusicLoader8;
+typedef interface IDirectMusicScript IDirectMusicScript;
+typedef interface IDirectMusicStyle8 IDirectMusicStyle8;
+typedef interface IDirectMusicPatternTrack IDirectMusicPatternTrack;
+typedef interface IDirectMusicContainer IDirectMusicContainer;
+typedef interface IDirectMusicTool8 IDirectMusicTool8;
+typedef interface IDirectMusicTrack8 IDirectMusicTrack8;
+typedef interface IDirectMusicSong IDirectMusicSong;
+typedef interface IDirectMusicAudioPath IDirectMusicAudioPath;
+#endif
+
+typedef enum enumDMUS_STYLET_TYPES
+{
+ DMUS_STYLET_PATTERN = 0,
+ DMUS_STYLET_MOTIF = 1,
+ DMUS_STYLET_FRAGMENT = 2,
+} DMUS_STYLET_TYPES;
+
+
+typedef enum enumDMUS_COMMANDT_TYPES
+{
+ DMUS_COMMANDT_GROOVE = 0,
+ DMUS_COMMANDT_FILL = 1,
+ DMUS_COMMANDT_INTRO = 2,
+ DMUS_COMMANDT_BREAK = 3,
+ DMUS_COMMANDT_END = 4,
+ DMUS_COMMANDT_ENDANDINTRO = 5
+} DMUS_COMMANDT_TYPES;
+
+typedef enum enumDMUS_SHAPET_TYPES
+{
+ DMUS_SHAPET_FALLING = 0,
+ DMUS_SHAPET_LEVEL = 1,
+ DMUS_SHAPET_LOOPABLE = 2,
+ DMUS_SHAPET_LOUD = 3,
+ DMUS_SHAPET_QUIET = 4,
+ DMUS_SHAPET_PEAKING = 5,
+ DMUS_SHAPET_RANDOM = 6,
+ DMUS_SHAPET_RISING = 7,
+ DMUS_SHAPET_SONG = 8
+} DMUS_SHAPET_TYPES;
+
+typedef enum enumDMUS_COMPOSEF_FLAGS
+{
+ DMUS_COMPOSEF_NONE = 0,
+ DMUS_COMPOSEF_ALIGN = 0x1,
+ DMUS_COMPOSEF_OVERLAP = 0x2,
+ DMUS_COMPOSEF_IMMEDIATE = 0x4,
+ DMUS_COMPOSEF_GRID = 0x8,
+ DMUS_COMPOSEF_BEAT = 0x10,
+ DMUS_COMPOSEF_MEASURE = 0x20,
+ DMUS_COMPOSEF_AFTERPREPARETIME = 0x40,
+ DMUS_COMPOSEF_VALID_START_BEAT = 0x80, /* In conjunction with DMUS_COMPOSEF_ALIGN, allows the switch to occur on any beat. */
+ DMUS_COMPOSEF_VALID_START_GRID = 0x100, /* In conjunction with DMUS_COMPOSEF_ALIGN, allows the switch to occur on any grid. */
+ DMUS_COMPOSEF_VALID_START_TICK = 0x200, /* In conjunction with DMUS_COMPOSEF_ALIGN, allows the switch to occur any time. */
+ DMUS_COMPOSEF_SEGMENTEND = 0x400, /* Play the transition at the end of the current segment. */
+ DMUS_COMPOSEF_MARKER = 0x800, /* Play the transition at the next marker in the current segment. */
+ DMUS_COMPOSEF_MODULATE = 0x1000,
+ DMUS_COMPOSEF_LONG = 0x2000,
+ DMUS_COMPOSEF_ENTIRE_TRANSITION = 0x4000, /* play the entire transition pattern */
+ DMUS_COMPOSEF_1BAR_TRANSITION = 0x8000, /* play one bar of the transition pattern */
+ DMUS_COMPOSEF_ENTIRE_ADDITION = 0x10000, /* play the additional pattern in its entirety */
+ DMUS_COMPOSEF_1BAR_ADDITION = 0x20000, /* play one bar of the additional pattern */
+ DMUS_COMPOSEF_VALID_START_MEASURE = 0x40000, /* In conjunction with DMUS_COMPOSEF_ALIGN, allows the switch to occur on any bar. */
+ DMUS_COMPOSEF_DEFAULT = 0x80000, /* Use segment's default boundary */
+ DMUS_COMPOSEF_NOINVALIDATE = 0x100000, /* Play without invalidating the currently playing segment(s) */
+ DMUS_COMPOSEF_USE_AUDIOPATH = 0x200000, /* Uses the audio paths that are embedded in the segments */
+ DMUS_COMPOSEF_INVALIDATE_PRI = 0x400000 /* Invalidate only the current primary seg state */
+} DMUS_COMPOSEF_FLAGS;
+
+#define DMUS_PMSG_PART \
+ DWORD dwSize; \
+ REFERENCE_TIME rtTime; /* real time (in 100 nanosecond increments) */ \
+ MUSIC_TIME mtTime; /* music time */ \
+ DWORD dwFlags; /* various bits (see DMUS_PMSGF_FLAGS enumeration) */ \
+ DWORD dwPChannel; /* Performance Channel. The Performance can */ \
+ /* use this to determine the port/channel. */ \
+ DWORD dwVirtualTrackID; /* virtual track ID */ \
+ IDirectMusicTool* pTool; /* tool interface pointer */ \
+ IDirectMusicGraph* pGraph; /* tool graph interface pointer */ \
+ DWORD dwType; /* PMSG type (see DMUS_PMSGT_TYPES defines) */ \
+ DWORD dwVoiceID; /* unique voice id which allows synthesizers to */ \
+ /* identify a specific event. For DirectX 6.0, */ \
+ /* this field should always be 0. */ \
+ DWORD dwGroupID; /* Track group id */ \
+ IUnknown* punkUser; /* user com pointer, auto released upon PMSG free */
+
+/* every DMUS_PMSG is based off of this structure. The Performance needs
+ to access these members consistently in every PMSG that goes through it. */
+typedef struct _DMUS_PMSG
+{
+ /* begin DMUS_PMSG_PART */
+ DMUS_PMSG_PART
+ /* end DMUS_PMSG_PART */
+
+} DMUS_PMSG;
+
+#define DMUS_PCHANNEL_BROADCAST_PERFORMANCE 0xFFFFFFFF /* PMsg is sent on all PChannels of the performance. */
+#define DMUS_PCHANNEL_BROADCAST_AUDIOPATH 0xFFFFFFFE /* PMsg is sent on all PChannels of the audio path. */
+#define DMUS_PCHANNEL_BROADCAST_SEGMENT 0xFFFFFFFD /* PMsg is sent on all PChannels of the segment. */
+#define DMUS_PCHANNEL_BROADCAST_GROUPS 0xFFFFFFFC /* A duplicate PMsg is for each Channels Groups in the performance. */
+
+/* The DMUS_PATH constants are used in conjunction with GetObjectInPath to find a requested
+ interface at a particular stage in the audio path.
+*/
+#define DMUS_PATH_SEGMENT 0x1000 /* Get the segment itself (from a segment state.) */
+#define DMUS_PATH_SEGMENT_TRACK 0x1100 /* Look in Track List of Segment. */
+#define DMUS_PATH_SEGMENT_GRAPH 0x1200 /* Get the segment's tool graph. */
+#define DMUS_PATH_SEGMENT_TOOL 0x1300 /* Look in Tool Graph of Segment. */
+#define DMUS_PATH_AUDIOPATH 0x2000 /* Get the audiopath itself (from a segment state.) */
+#define DMUS_PATH_AUDIOPATH_GRAPH 0x2200 /* Get the audiopath's tool graph. */
+#define DMUS_PATH_AUDIOPATH_TOOL 0x2300 /* Look in Tool Graph of Audio Path. */
+#define DMUS_PATH_PERFORMANCE 0x3000 /* Access the performance. */
+#define DMUS_PATH_PERFORMANCE_GRAPH 0x3200 /* Get the performance's tool graph. */
+#define DMUS_PATH_PERFORMANCE_TOOL 0x3300 /* Look in Tool Graph of Performance. */
+#define DMUS_PATH_PORT 0x4000 /* Access the synth. */
+#define DMUS_PATH_BUFFER 0x6000 /* Look in DirectSoundBuffer. */
+#define DMUS_PATH_BUFFER_DMO 0x6100 /* Access a DMO in the buffer. */
+#define DMUS_PATH_MIXIN_BUFFER 0x7000 /* Look in a global mixin buffer. */
+#define DMUS_PATH_MIXIN_BUFFER_DMO 0x7100 /* Access a DMO in a global mixin buffer. */
+#define DMUS_PATH_PRIMARY_BUFFER 0x8000 /* Access the primary buffer. */
+
+/* To ignore PChannels when calling GetObjectInPath(), use the DMUS_PCHANNEL_ALL constant. */
+#define DMUS_PCHANNEL_ALL 0xFFFFFFFB
+
+/* The DMUS_APATH types are used in conjunction with CreateStandardAudioPath to
+ build default path types. _SHARED_ means the same buffer is shared across multiple
+ instantiations of the audiopath type. _DYNAMIC_ means a unique buffer is created
+ every time.
+*/
+
+#define DMUS_APATH_SHARED_STEREOPLUSREVERB 1 /* A standard music set up with stereo outs and reverb. */
+#define DMUS_APATH_DYNAMIC_3D 6 /* An audio path with one dynamic bus from the synth feeding to a dynamic 3d buffer. Does not send to env reverb. */
+#define DMUS_APATH_DYNAMIC_MONO 7 /* An audio path with one dynamic bus from the synth feeding to a dynamic mono buffer. */
+#define DMUS_APATH_DYNAMIC_STEREO 8 /* An audio path with two dynamic buses from the synth feeding to a dynamic stereo buffer. */
+
+typedef struct _DMUS_AUDIOPARAMS
+{
+ DWORD dwSize; /* Size of this structure. */
+ BOOL fInitNow; /* If true, the sink and synth are created immediately and results returned in this structure. */
+ DWORD dwValidData; /* Flags indicating which fields below are valid. */
+ DWORD dwFeatures; /* Required DMUS_AUDIOF features. */
+ DWORD dwVoices; /* Required number of voices. */
+ DWORD dwSampleRate; /* Sample rate of synths and sink. */
+ CLSID clsidDefaultSynth; /* Class ID of default synthesizer. */
+} DMUS_AUDIOPARAMS;
+
+/* dwFeatures flags. These indicate which features are required for the audio environment. */
+#define DMUS_AUDIOF_3D 0x1 /* Require 3D buffers. */
+#define DMUS_AUDIOF_ENVIRON 0x2 /* Require environmental modeling. */
+#define DMUS_AUDIOF_EAX 0x4 /* Require use of EAX effects. */
+#define DMUS_AUDIOF_DMOS 0x8 /* Require use of additional DMOs. */
+#define DMUS_AUDIOF_STREAMING 0x10 /* Require support for streaming waves. */
+#define DMUS_AUDIOF_BUFFERS 0x20 /* Require support for multiple buffers (all above cases need this.) */
+#define DMUS_AUDIOF_ALL 0x3F /* Requires everything. */
+
+/* dwValidData flags. These indicate which fields in DMUS_AUDIOPARAMS have been filled in. If fInitNow is set, these also return what was allocated. */
+#define DMUS_AUDIOPARAMS_FEATURES 0x00000001
+#define DMUS_AUDIOPARAMS_VOICES 0x00000002
+#define DMUS_AUDIOPARAMS_SAMPLERATE 0x00000004
+#define DMUS_AUDIOPARAMS_DEFAULTSYNTH 0x00000008
+
+/* DMUS_PMSGF_FLAGS fill the DMUS_PMSG's dwFlags member */
+typedef enum enumDMUS_PMSGF_FLAGS
+{
+ DMUS_PMSGF_REFTIME = 1, /* if rtTime is valid */
+ DMUS_PMSGF_MUSICTIME = 2, /* if mtTime is valid */
+ DMUS_PMSGF_TOOL_IMMEDIATE = 4, /* if PMSG should be processed immediately */
+ DMUS_PMSGF_TOOL_QUEUE = 8, /* if PMSG should be processed a little early, at Queue time */
+ DMUS_PMSGF_TOOL_ATTIME = 0x10, /* if PMSG should be processed at the time stamp */
+ DMUS_PMSGF_TOOL_FLUSH = 0x20, /* if PMSG is being flushed */
+ DMUS_PMSGF_LOCKTOREFTIME = 0x40, /* if rtTime can not be overriden by a tempo change. */
+ DMUS_PMSGF_DX8 = 0x80 /* if the message has DX8 or later extensions. */
+ /* The values of DMUS_TIME_RESOLVE_FLAGS may also be used inside the */
+ /* DMUS_PMSG's dwFlags member. */
+} DMUS_PMSGF_FLAGS;
+
+/* DMUS_PMSGT_TYPES fill the DMUS_PMSG's dwType member */
+typedef enum enumDMUS_PMSGT_TYPES
+{
+ DMUS_PMSGT_MIDI = 0, /* MIDI short message */
+ DMUS_PMSGT_NOTE = 1, /* Interactive Music Note */
+ DMUS_PMSGT_SYSEX = 2, /* MIDI long message (system exclusive message) */
+ DMUS_PMSGT_NOTIFICATION = 3, /* Notification message */
+ DMUS_PMSGT_TEMPO = 4, /* Tempo message */
+ DMUS_PMSGT_CURVE = 5, /* Control change / pitch bend, etc. curve */
+ DMUS_PMSGT_TIMESIG = 6, /* Time signature */
+ DMUS_PMSGT_PATCH = 7, /* Patch changes */
+ DMUS_PMSGT_TRANSPOSE = 8, /* Transposition messages */
+ DMUS_PMSGT_CHANNEL_PRIORITY = 9, /* Channel priority */
+ DMUS_PMSGT_STOP = 10, /* Stop message */
+ DMUS_PMSGT_DIRTY = 11, /* Tells Tools that cache GetParam() info to refresh */
+ DMUS_PMSGT_WAVE = 12, /* Carries control information for playing a wave. */
+ DMUS_PMSGT_LYRIC = 13, /* Lyric message from lyric track. */
+ DMUS_PMSGT_SCRIPTLYRIC = 14, /* Lyric message sent by a script with the Trace function. */
+ DMUS_PMSGT_USER = 255 /* User message */
+} DMUS_PMSGT_TYPES;
+
+/* DMUS_SEGF_FLAGS correspond to IDirectMusicPerformance::PlaySegment, and other API */
+typedef enum enumDMUS_SEGF_FLAGS
+{
+ DMUS_SEGF_REFTIME = 1<<6, /* 0x40 Time parameter is in reference time */
+ DMUS_SEGF_SECONDARY = 1<<7, /* 0x80 Secondary segment */
+ DMUS_SEGF_QUEUE = 1<<8, /* 0x100 Queue at the end of the primary segment queue (primary only) */
+ DMUS_SEGF_CONTROL = 1<<9, /* 0x200 Play as a control track (secondary segments only) */
+ DMUS_SEGF_AFTERPREPARETIME = 1<<10, /* 0x400 Play after the prepare time (See IDirectMusicPerformance::GetPrepareTime) */
+ DMUS_SEGF_GRID = 1<<11, /* 0x800 Play on grid boundary */
+ DMUS_SEGF_BEAT = 1<<12, /* 0x1000 Play on beat boundary */
+ DMUS_SEGF_MEASURE = 1<<13, /* 0x2000 Play on measure boundary */
+ DMUS_SEGF_DEFAULT = 1<<14, /* 0x4000 Use segment's default boundary */
+ DMUS_SEGF_NOINVALIDATE = 1<<15, /* 0x8000 Play without invalidating the currently playing segment(s) */
+ DMUS_SEGF_ALIGN = 1<<16, /* 0x10000 Align segment with requested boundary, but switch at first valid point */
+ DMUS_SEGF_VALID_START_BEAT = 1<<17, /* 0x20000 In conjunction with DMUS_SEGF_ALIGN, allows the switch to occur on any beat. */
+ DMUS_SEGF_VALID_START_GRID = 1<<18, /* 0x40000 In conjunction with DMUS_SEGF_ALIGN, allows the switch to occur on any grid. */
+ DMUS_SEGF_VALID_START_TICK = 1<<19, /* 0x80000 In conjunction with DMUS_SEGF_ALIGN, allows the switch to occur any time. */
+ DMUS_SEGF_AUTOTRANSITION = 1<<20, /* 0x100000 Compose and play a transition segment, using either the transition template or transition embedded in song. */
+ DMUS_SEGF_AFTERQUEUETIME = 1<<21, /* 0x200000 Make sure to play after the queue time. This is default for primary segments */
+ DMUS_SEGF_AFTERLATENCYTIME = 1<<22, /* 0x400000 Make sure to play after the latency time. This is true for all segments, so this is a nop */
+ DMUS_SEGF_SEGMENTEND = 1<<23, /* 0x800000 Play at the next end of segment. */
+ DMUS_SEGF_MARKER = 1<<24, /* 0x1000000 Play at next marker in the primary segment. If there are no markers, default to any other resolution requests. */
+ DMUS_SEGF_TIMESIG_ALWAYS = 1<<25, /* 0x2000000 Even if there is no primary segment, align start time with current time signature. */
+ DMUS_SEGF_USE_AUDIOPATH = 1<<26, /* 0x4000000 Uses the audio path that is embedded in the segment or song. */
+ DMUS_SEGF_VALID_START_MEASURE = 1<<27, /* 0x8000000 In conjunction with DMUS_SEGF_ALIGN, allows the switch to occur on any bar. */
+ DMUS_SEGF_INVALIDATE_PRI = 1<<28 /* 0x10000000 invalidate only the current primary seg state */
+} DMUS_SEGF_FLAGS;
+
+#define DMUS_SEG_REPEAT_INFINITE 0xFFFFFFFF /* For IDirectMusicSegment::SetRepeat*/
+#define DMUS_SEG_ALLTRACKS 0x80000000 /* For IDirectMusicSegment::SetParam() and SetTrackConfig() - selects all tracks instead on nth index. */
+#define DMUS_SEG_ANYTRACK 0x80000000 /* For IDirectMusicSegment::GetParam() - checks each track until it finds one that returns data (not DMUS_E_NOT_FOUND.) */
+
+
+/* DMUS_TIME_RESOLVE_FLAGS correspond to IDirectMusicPerformance::GetResolvedTime, and can */
+/* also be used interchangeably with the corresponding DMUS_SEGF_FLAGS, since their values */
+/* are intentionally the same */
+typedef enum enumDMUS_TIME_RESOLVE_FLAGS
+{
+ DMUS_TIME_RESOLVE_AFTERPREPARETIME = DMUS_SEGF_AFTERPREPARETIME,
+ DMUS_TIME_RESOLVE_AFTERQUEUETIME = DMUS_SEGF_AFTERQUEUETIME,
+ DMUS_TIME_RESOLVE_AFTERLATENCYTIME = DMUS_SEGF_AFTERLATENCYTIME,
+ DMUS_TIME_RESOLVE_GRID = DMUS_SEGF_GRID,
+ DMUS_TIME_RESOLVE_BEAT = DMUS_SEGF_BEAT,
+ DMUS_TIME_RESOLVE_MEASURE = DMUS_SEGF_MEASURE,
+ DMUS_TIME_RESOLVE_MARKER = DMUS_SEGF_MARKER,
+ DMUS_TIME_RESOLVE_SEGMENTEND = DMUS_SEGF_SEGMENTEND,
+} DMUS_TIME_RESOLVE_FLAGS;
+
+/* The following flags are sent inside the DMUS_CHORD_KEY.dwFlags parameter */
+typedef enum enumDMUS_CHORDKEYF_FLAGS
+{
+ DMUS_CHORDKEYF_SILENT = 1, /* is the chord silent? */
+} DMUS_CHORDKEYF_FLAGS;
+
+#define DMUS_MAXSUBCHORD 8
+
+typedef struct _DMUS_SUBCHORD
+{
+ DWORD dwChordPattern; /* Notes in the subchord */
+ DWORD dwScalePattern; /* Notes in the scale */
+ DWORD dwInversionPoints; /* Where inversions can occur */
+ DWORD dwLevels; /* Which levels are supported by this subchord */
+ BYTE bChordRoot; /* Root of the subchord */
+ BYTE bScaleRoot; /* Root of the scale */
+} DMUS_SUBCHORD;
+
+typedef struct _DMUS_CHORD_KEY
+{
+ WCHAR wszName[16]; /* Name of the chord */
+ WORD wMeasure; /* Measure this falls on */
+ BYTE bBeat; /* Beat this falls on */
+ BYTE bSubChordCount; /* Number of chords in the list of subchords */
+ DMUS_SUBCHORD SubChordList[DMUS_MAXSUBCHORD]; /* List of sub chords */
+ DWORD dwScale; /* Scale underlying the entire chord */
+ BYTE bKey; /* Key underlying the entire chord */
+ BYTE bFlags; /* Miscelaneous flags */
+} DMUS_CHORD_KEY;
+
+/* DMUS_NOTE_PMSG */
+typedef struct _DMUS_NOTE_PMSG
+{
+ /* begin DMUS_PMSG_PART */
+ DMUS_PMSG_PART
+ /* end DMUS_PMSG_PART */
+
+ MUSIC_TIME mtDuration; /* duration */
+ WORD wMusicValue; /* Description of note in chord and key. */
+ WORD wMeasure; /* Measure in which this note occurs */
+ short nOffset; /* Offset from grid at which this note occurs */
+ BYTE bBeat; /* Beat (in measure) at which this note occurs */
+ BYTE bGrid; /* Grid offset from beat at which this note occurs */
+ BYTE bVelocity; /* Note velocity */
+ BYTE bFlags; /* see DMUS_NOTEF_FLAGS */
+ BYTE bTimeRange; /* Range to randomize time. */
+ BYTE bDurRange; /* Range to randomize duration. */
+ BYTE bVelRange; /* Range to randomize velocity. */
+ BYTE bPlayModeFlags; /* Play mode */
+ BYTE bSubChordLevel; /* Which subchord level this note uses. */
+ BYTE bMidiValue; /* The MIDI note value, converted from wMusicValue */
+ char cTranspose; /* Transposition to add to midi note value after converted from wMusicValue. */
+} DMUS_NOTE_PMSG;
+
+typedef enum enumDMUS_NOTEF_FLAGS
+{
+ DMUS_NOTEF_NOTEON = 1, /* Set if this is a MIDI Note On. Otherwise, it is MIDI Note Off */
+ /* DX8 flags: */
+ DMUS_NOTEF_NOINVALIDATE = 2, /* Don't invalidate this note off. */
+ DMUS_NOTEF_NOINVALIDATE_INSCALE = 4,/* Don't invalidate if still within the scale. */
+ DMUS_NOTEF_NOINVALIDATE_INCHORD = 8,/* Don't invalidate if still within the chord. */
+ DMUS_NOTEF_REGENERATE = 0x10, /* Regenerate the note on an invalidate. */
+} DMUS_NOTEF_FLAGS;
+
+/* The DMUS_PLAYMODE_FLAGS are used to determine how to convert wMusicValue
+ into the appropriate bMidiValue.
+*/
+
+typedef enum enumDMUS_PLAYMODE_FLAGS
+{
+ DMUS_PLAYMODE_KEY_ROOT = 1, /* Transpose on top of the key root. */
+ DMUS_PLAYMODE_CHORD_ROOT = 2, /* Transpose on top of the chord root. */
+ DMUS_PLAYMODE_SCALE_INTERVALS = 4, /* Use scale intervals from scale pattern. */
+ DMUS_PLAYMODE_CHORD_INTERVALS = 8, /* Use chord intervals from chord pattern. */
+ DMUS_PLAYMODE_NONE = 16, /* No mode. Indicates the parent part's mode should be used. */
+} DMUS_PLAYMODE_FLAGS;
+
+/* The following are playback modes that can be created by combining the DMUS_PLAYMODE_FLAGS
+ in various ways:
+*/
+
+/* Fixed. wMusicValue holds final MIDI note value. This is used for drums, sound effects, and sequenced
+ notes that should not be transposed by the chord or scale.
+*/
+#define DMUS_PLAYMODE_FIXED 0
+/* In fixed to key, the musicvalue is again a fixed MIDI value, but it
+ is transposed on top of the key root.
+*/
+#define DMUS_PLAYMODE_FIXEDTOKEY DMUS_PLAYMODE_KEY_ROOT
+/* In fixed to chord, the musicvalue is also a fixed MIDI value, but it
+ is transposed on top of the chord root.
+*/
+#define DMUS_PLAYMODE_FIXEDTOCHORD DMUS_PLAYMODE_CHORD_ROOT
+/* In Pedalpoint, the key root is used and the notes only track the intervals in
+ the scale. The chord root and intervals are completely ignored. This is useful
+ for melodic lines that play relative to the key root.
+*/
+#define DMUS_PLAYMODE_PEDALPOINT (DMUS_PLAYMODE_KEY_ROOT | DMUS_PLAYMODE_SCALE_INTERVALS)
+/* In the Melodic mode, the chord root is used but the notes only track the intervals in
+ the scale. The key root and chord intervals are completely ignored. This is useful
+ for melodic lines that play relative to the chord root.
+*/
+#define DMUS_PLAYMODE_MELODIC (DMUS_PLAYMODE_CHORD_ROOT | DMUS_PLAYMODE_SCALE_INTERVALS)
+/* Normal chord mode is the prevalent playback mode.
+ The notes track the intervals in the chord, which is based on the chord root.
+ If there is a scale component to the MusicValue, the additional intervals
+ are pulled from the scale and added.
+ If the chord does not have an interval to match the chord component of
+ the MusicValue, the note is silent.
+*/
+#define DMUS_PLAYMODE_NORMALCHORD (DMUS_PLAYMODE_CHORD_ROOT | DMUS_PLAYMODE_CHORD_INTERVALS)
+/* If it is desirable to play a note that is above the top of the chord, the
+ always play mode (known as "purpleized" in a former life) finds a position
+ for the note by using intervals from the scale. Essentially, this mode is
+ a combination of the Normal and Melodic playback modes, where a failure
+ in Normal causes a second try in Melodic mode.
+*/
+#define DMUS_PLAYMODE_ALWAYSPLAY (DMUS_PLAYMODE_MELODIC | DMUS_PLAYMODE_NORMALCHORD)
+
+/* These playmodes are new for dx8. */
+/* In PedalpointChord, the key root is used and the notes only track the intervals in
+ the chord. The chord root and scale intervals are completely ignored. This is useful
+ for chordal lines that play relative to the key root.
+*/
+#define DMUS_PLAYMODE_PEDALPOINTCHORD (DMUS_PLAYMODE_KEY_ROOT | DMUS_PLAYMODE_CHORD_INTERVALS)
+
+/* For completeness, here's a mode that tries for pedalpointchord, but if it fails
+ uses scale intervals
+*/
+#define DMUS_PLAYMODE_PEDALPOINTALWAYS (DMUS_PLAYMODE_PEDALPOINT | DMUS_PLAYMODE_PEDALPOINTCHORD)
+
+
+/* Legacy names for modes... */
+#define DMUS_PLAYMODE_PURPLEIZED DMUS_PLAYMODE_ALWAYSPLAY
+#define DMUS_PLAYMODE_SCALE_ROOT DMUS_PLAYMODE_KEY_ROOT
+#define DMUS_PLAYMODE_FIXEDTOSCALE DMUS_PLAYMODE_FIXEDTOKEY
+
+
+/* DMUS_MIDI_PMSG */
+typedef struct _DMUS_MIDI_PMSG
+{
+ /* begin DMUS_PMSG_PART */
+ DMUS_PMSG_PART
+ /* end DMUS_PMSG_PART */
+
+ BYTE bStatus;
+ BYTE bByte1;
+ BYTE bByte2;
+ BYTE bPad[1];
+} DMUS_MIDI_PMSG;
+
+/* DMUS_PATCH_PMSG */
+typedef struct _DMUS_PATCH_PMSG
+{
+ /* begin DMUS_PMSG_PART */
+ DMUS_PMSG_PART
+ /* end DMUS_PMSG_PART */
+
+ BYTE byInstrument;
+ BYTE byMSB;
+ BYTE byLSB;
+ BYTE byPad[1];
+} DMUS_PATCH_PMSG;
+
+/* DMUS_TRANSPOSE_PMSG */
+typedef struct _DMUS_TRANSPOSE_PMSG
+{
+ /* begin DMUS_PMSG_PART */
+ DMUS_PMSG_PART
+ /* end DMUS_PMSG_PART */
+
+ short nTranspose;
+ /* Following exists only under DX8 and on (check dwFlags for DMUS_PMSGF_DX8) */
+ WORD wMergeIndex; /* Allows multiple parameters to be merged (pitchbend, volume, and expression.)*/
+} DMUS_TRANSPOSE_PMSG;
+
+/* DMUS_CHANNEL_PRIORITY_PMSG */
+typedef struct _DMUS_CHANNEL_PRIORITY_PMSG
+{
+ /* begin DMUS_PMSG_PART */
+ DMUS_PMSG_PART
+ /* end DMUS_PMSG_PART */
+
+ DWORD dwChannelPriority;
+} DMUS_CHANNEL_PRIORITY_PMSG;
+
+/* DMUS_TEMPO_PMSG */
+typedef struct _DMUS_TEMPO_PMSG
+{
+ /* begin DMUS_PMSG_PART */
+ DMUS_PMSG_PART
+ /* end DMUS_PMSG_PART */
+
+ double dblTempo; /* the tempo */
+} DMUS_TEMPO_PMSG;
+
+#define DMUS_TEMPO_MAX 1000
+#define DMUS_TEMPO_MIN 1
+
+#define DMUS_MASTERTEMPO_MAX 100.0f
+#define DMUS_MASTERTEMPO_MIN 0.01f
+
+/* DMUS_SYSEX_PMSG */
+typedef struct _DMUS_SYSEX_PMSG
+{
+ /* begin DMUS_PMSG_PART */
+ DMUS_PMSG_PART
+ /* end DMUS_PMSG_PART */
+
+ DWORD dwLen; /* length of the data */
+ BYTE abData[1]; /* array of data, length equal to dwLen */
+} DMUS_SYSEX_PMSG;
+
+/* DMUS_CURVE_PMSG */
+typedef struct _DMUS_CURVE_PMSG
+{
+ /* begin DMUS_PMSG_PART */
+ DMUS_PMSG_PART
+ /* end DMUS_PMSG_PART */
+
+ MUSIC_TIME mtDuration; /* how long this curve lasts */
+ MUSIC_TIME mtOriginalStart; /* must be set to either zero when this PMSG is created or to the original mtTime of the curve */
+ MUSIC_TIME mtResetDuration; /* how long after the curve is finished to allow a flush or
+ invalidation to reset to the reset value, nResetValue */
+ short nStartValue; /* curve's start value */
+ short nEndValue; /* curve's end value */
+ short nResetValue; /* curve's reset value, set when a flush or invalidation
+ occurs within mtDuration + mtResetDuration */
+ WORD wMeasure; /* Measure in which this curve occurs */
+ short nOffset; /* Offset from grid at which this curve occurs */
+ BYTE bBeat; /* Beat (in measure) at which this curve occurs */
+ BYTE bGrid; /* Grid offset from beat at which this curve occurs */
+ BYTE bType; /* type of curve */
+ BYTE bCurveShape; /* shape of curve */
+ BYTE bCCData; /* CC# if this is a control change type */
+ BYTE bFlags; /* Curve reset and start from current value flags. */
+ /* Following exists only under DX8 and on (check dwFlags for DMUS_PMSGF_DX8) */
+ WORD wParamType; /* RPN or NRPN parameter number. */
+ WORD wMergeIndex; /* Allows multiple parameters to be merged (pitchbend, volume, and expression.)*/
+} DMUS_CURVE_PMSG;
+
+typedef enum enumDMUS_CURVE_FLAGS
+{
+ DMUS_CURVE_RESET = 1, /* When set, the nResetValue must be sent when the
+ time is reached or an invalidate occurs because
+ of a transition. If not set, the curve stays
+ permanently stuck at the new value. */
+ DMUS_CURVE_START_FROM_CURRENT = 2/* Ignore Start, start the curve at the current value.
+ This only works for volume, expression, and pitchbend. */
+} DMUS_CURVE_FLAGS;
+
+
+#define DMUS_CURVE_RESET 1
+
+/* Curve shapes */
+enum
+{
+ DMUS_CURVES_LINEAR = 0,
+ DMUS_CURVES_INSTANT = 1,
+ DMUS_CURVES_EXP = 2,
+ DMUS_CURVES_LOG = 3,
+ DMUS_CURVES_SINE = 4
+};
+/* curve types */
+#define DMUS_CURVET_PBCURVE 0x03 /* Pitch bend curve. */
+#define DMUS_CURVET_CCCURVE 0x04 /* Control change curve. */
+#define DMUS_CURVET_MATCURVE 0x05 /* Mono aftertouch curve. */
+#define DMUS_CURVET_PATCURVE 0x06 /* Poly aftertouch curve. */
+#define DMUS_CURVET_RPNCURVE 0x07 /* RPN curve with curve type in wParamType. */
+#define DMUS_CURVET_NRPNCURVE 0x08 /* NRPN curve with curve type in wParamType. */
+
+/* DMUS_TIMESIG_PMSG */
+typedef struct _DMUS_TIMESIG_PMSG
+{
+ /* begin DMUS_PMSG_PART */
+ DMUS_PMSG_PART
+ /* end DMUS_PMSG_PART */
+
+ /* Time signatures define how many beats per measure, which note receives */
+ /* the beat, and the grid resolution. */
+ BYTE bBeatsPerMeasure; /* beats per measure (top of time sig) */
+ BYTE bBeat; /* what note receives the beat (bottom of time sig.) */
+ /* we can assume that 0 means 256th note */
+ WORD wGridsPerBeat; /* grids per beat */
+} DMUS_TIMESIG_PMSG;
+
+
+
+/* notification type values */
+/* The following correspond to GUID_NOTIFICATION_SEGMENT */
+#define DMUS_NOTIFICATION_SEGSTART 0
+#define DMUS_NOTIFICATION_SEGEND 1
+#define DMUS_NOTIFICATION_SEGALMOSTEND 2
+#define DMUS_NOTIFICATION_SEGLOOP 3
+#define DMUS_NOTIFICATION_SEGABORT 4
+/* The following correspond to GUID_NOTIFICATION_PERFORMANCE */
+#define DMUS_NOTIFICATION_MUSICSTARTED 0
+#define DMUS_NOTIFICATION_MUSICSTOPPED 1
+#define DMUS_NOTIFICATION_MUSICALMOSTEND 2
+/* The following corresponds to GUID_NOTIFICATION_MEASUREANDBEAT */
+#define DMUS_NOTIFICATION_MEASUREBEAT 0
+/* The following corresponds to GUID_NOTIFICATION_CHORD */
+#define DMUS_NOTIFICATION_CHORD 0
+/* The following correspond to GUID_NOTIFICATION_COMMAND */
+#define DMUS_NOTIFICATION_GROOVE 0
+#define DMUS_NOTIFICATION_EMBELLISHMENT 1
+/* The following corresponds to GUID_NOTIFICATION_RECOMPOSE */
+#define DMUS_NOTIFICATION_RECOMPOSE 0
+
+/* DMUS_NOTIFICATION_PMSG */
+typedef struct _DMUS_NOTIFICATION_PMSG
+{
+ /* begin DMUS_PMSG_PART */
+ DMUS_PMSG_PART
+ /* end DMUS_PMSG_PART */
+
+ GUID guidNotificationType;
+ DWORD dwNotificationOption;
+ DWORD dwField1;
+ DWORD dwField2;
+} DMUS_NOTIFICATION_PMSG;
+
+/* DMUS_WAVE_PMSG */
+typedef struct _DMUS_WAVE_PMSG
+{
+ /* begin DMUS_PMSG_PART */
+ DMUS_PMSG_PART
+ /* end DMUS_PMSG_PART */
+
+ REFERENCE_TIME rtStartOffset; /* How far into the wave to start, in reference time units only. */
+ REFERENCE_TIME rtDuration; /* Duration of the wave, in either reference time or music time. */
+ long lOffset; /* Offset from actual time to logical time, in music or ref time. */
+ long lVolume; /* Initial volume, in 100ths of a dB. */
+ long lPitch; /* Initial pitch, in 100ths of a semitone. */
+ BYTE bFlags; /* Flags, including DMUS_WAVEF_OFF... */
+} DMUS_WAVE_PMSG;
+
+#define DMUS_WAVEF_OFF 1 /* If wave is playing and this is the off message. */
+#define DMUS_WAVEF_STREAMING 2 /* If wave is streaming. */
+#define DMUS_WAVEF_NOINVALIDATE 4 /* Don't invalidate this wave. */
+#define DMUS_WAVEF_NOPREROLL 8 /* Don't preroll any wave data. */
+
+/* DMUS_LYRIC_PMSG */
+typedef struct _DMUS_LYRIC_PMSG
+{
+ /* begin DMUS_PMSG_PART */
+ DMUS_PMSG_PART
+ /* end DMUS_PMSG_PART */
+
+ WCHAR wszString[1]; /* null-terminated Unicode lyric string (structure is actually larger than size 1) */
+} DMUS_LYRIC_PMSG;
+
+#define DMUS_MAX_NAME 64 /* Maximum object name length. */
+#define DMUS_MAX_CATEGORY 64 /* Maximum object category name length. */
+#define DMUS_MAX_FILENAME MAX_PATH
+
+typedef struct _DMUS_VERSION {
+ DWORD dwVersionMS;
+ DWORD dwVersionLS;
+}DMUS_VERSION, FAR *LPDMUS_VERSION;
+
+/* Time Signature structure, used by IDirectMusicStyle */
+/* Also used as a parameter for GetParam() and SetParam */
+typedef struct _DMUS_TIMESIGNATURE
+{
+ MUSIC_TIME mtTime;
+ BYTE bBeatsPerMeasure; /* beats per measure (top of time sig) */
+ BYTE bBeat; /* what note receives the beat (bottom of time sig.) */
+ /* we can assume that 0 means 256th note */
+ WORD wGridsPerBeat; /* grids per beat */
+} DMUS_TIMESIGNATURE;
+
+typedef struct _DMUS_VALID_START_PARAM
+{
+ MUSIC_TIME mtTime; /* Time of the first legal start
+ point after (or including) the requested time.
+ This is a returned value.
+ Time format is the relative offset from requested time. */
+} DMUS_VALID_START_PARAM;
+
+typedef struct _DMUS_PLAY_MARKER_PARAM
+{
+ MUSIC_TIME mtTime; /* Time of the first legal segment play
+ marker before (or including) the requested time.
+ This is a returned value.
+ Time format is the relative offset from requested time. */
+} DMUS_PLAY_MARKER_PARAM;
+
+/* The DMUSOBJECTDESC structure is used to communicate everything you could */
+/* possibly use to describe a DirectMusic object. */
+
+typedef struct _DMUS_OBJECTDESC
+{
+ DWORD dwSize; /* Size of this structure. */
+ DWORD dwValidData; /* Flags indicating which fields below are valid. */
+ GUID guidObject; /* Unique ID for this object. */
+ GUID guidClass; /* GUID for the class of object. */
+ FILETIME ftDate; /* Last edited date of object. */
+ DMUS_VERSION vVersion; /* Version. */
+ WCHAR wszName[DMUS_MAX_NAME]; /* Name of object. */
+ WCHAR wszCategory[DMUS_MAX_CATEGORY]; /* Category for object (optional). */
+ WCHAR wszFileName[DMUS_MAX_FILENAME]; /* File path. */
+ LONGLONG llMemLength; /* Size of Memory data. */
+ LPBYTE pbMemData; /* Memory pointer for data. */
+ IStream * pStream; /* Stream with data. */
+} DMUS_OBJECTDESC;
+
+typedef DMUS_OBJECTDESC *LPDMUS_OBJECTDESC;
+
+/* Flags for dwValidData. When set, a flag indicates that the */
+/* corresponding field in DMUSOBJECTDESC holds valid data. */
+
+#define DMUS_OBJ_OBJECT (1 << 0) /* Object GUID is valid. */
+#define DMUS_OBJ_CLASS (1 << 1) /* Class GUID is valid. */
+#define DMUS_OBJ_NAME (1 << 2) /* Name is valid. */
+#define DMUS_OBJ_CATEGORY (1 << 3) /* Category is valid. */
+#define DMUS_OBJ_FILENAME (1 << 4) /* File path is valid. */
+#define DMUS_OBJ_FULLPATH (1 << 5) /* Path is full path. */
+#define DMUS_OBJ_URL (1 << 6) /* Path is URL. */
+#define DMUS_OBJ_VERSION (1 << 7) /* Version is valid. */
+#define DMUS_OBJ_DATE (1 << 8) /* Date is valid. */
+#define DMUS_OBJ_LOADED (1 << 9) /* Object is currently loaded in memory. */
+#define DMUS_OBJ_MEMORY (1 << 10) /* Object is pointed to by pbMemData. */
+#define DMUS_OBJ_STREAM (1 << 11) /* Object is stored in pStream. */
+
+/* The DMUS_SCRIPT_ERRORINFO structure describes an error that occurred in a script.
+ It is returned by methods in IDirectMusicScript. */
+typedef struct _DMUS_SCRIPT_ERRORINFO
+{
+ DWORD dwSize; /* Size of this structure. */
+ HRESULT hr;
+ ULONG ulLineNumber;
+ LONG ichCharPosition;
+ WCHAR wszSourceFile[DMUS_MAX_FILENAME];
+ WCHAR wszSourceComponent[DMUS_MAX_FILENAME];
+ WCHAR wszDescription[DMUS_MAX_FILENAME];
+ WCHAR wszSourceLineText[DMUS_MAX_FILENAME];
+} DMUS_SCRIPT_ERRORINFO;
+
+/* Track configuration flags, used with IDirectMusicSegment8::SetTrackConfig() */
+
+#define DMUS_TRACKCONFIG_OVERRIDE_ALL 1 /* This track should get parameters from this segment before controlling and primary tracks. */
+#define DMUS_TRACKCONFIG_OVERRIDE_PRIMARY 2 /* This track should get parameters from this segment before the primary segment tracks. */
+#define DMUS_TRACKCONFIG_FALLBACK 4 /* This track should get parameters from this segment if the primary and controlling segments don't succeed. */
+#define DMUS_TRACKCONFIG_CONTROL_ENABLED 8 /* GetParam() enabled for this track. */
+#define DMUS_TRACKCONFIG_PLAY_ENABLED 0x10 /* Play() enabled for this track. */
+#define DMUS_TRACKCONFIG_NOTIFICATION_ENABLED 0x20 /* Notifications enabled for this track. */
+#define DMUS_TRACKCONFIG_PLAY_CLOCKTIME 0x40 /* This track plays in clock time, not music time. */
+#define DMUS_TRACKCONFIG_PLAY_COMPOSE 0x80 /* This track should regenerate data each time it starts playing. */
+#define DMUS_TRACKCONFIG_LOOP_COMPOSE 0x100 /* This track should regenerate data each time it repeats. */
+#define DMUS_TRACKCONFIG_COMPOSING 0x200 /* This track is used to compose other tracks. */
+#define DMUS_TRACKCONFIG_CONTROL_PLAY 0x10000 /* This track, when played in a controlling segment, overrides playback of primary segment tracks. */
+#define DMUS_TRACKCONFIG_CONTROL_NOTIFICATION 0x20000 /* This track, when played in a controlling segment, overrides notification of primary segment tracks. */
+/* Additional track config flags for composing transitions */
+#define DMUS_TRACKCONFIG_TRANS1_FROMSEGSTART 0x400 /* Get track info from start of From segment */
+#define DMUS_TRACKCONFIG_TRANS1_FROMSEGCURRENT 0x800 /* Get track info from current place in From segment */
+#define DMUS_TRACKCONFIG_TRANS1_TOSEGSTART 0x1000 /* Get track info from start of To segment */
+#define DMUS_TRACKCONFIG_DEFAULT (DMUS_TRACKCONFIG_CONTROL_ENABLED | DMUS_TRACKCONFIG_PLAY_ENABLED | DMUS_TRACKCONFIG_NOTIFICATION_ENABLED)
+
+/* #defines for melody fragments */
+/* Note: Melody formulation is not supported in DX8. */
+
+#define DMUS_MAX_FRAGMENTLABEL 20
+
+#define DMUS_FRAGMENTF_USE_REPEAT 0x1
+#define DMUS_FRAGMENTF_REJECT_REPEAT (0x1 << 1)
+#define DMUS_FRAGMENTF_USE_LABEL (0x1 << 2)
+
+#define DMUS_CONNECTIONF_INTERVALS (0x1 << 1) /* Use transition intervals */
+#define DMUS_CONNECTIONF_OVERLAP (0x1 << 2) /* Use overlapping notes for transitions */
+
+/* Get/SetParam structs for commands */
+/* PARAM structures, used by GetParam() and SetParam() */
+typedef struct _DMUS_COMMAND_PARAM
+{
+ BYTE bCommand;
+ BYTE bGrooveLevel;
+ BYTE bGrooveRange;
+ BYTE bRepeatMode;
+} DMUS_COMMAND_PARAM;
+
+typedef struct _DMUS_COMMAND_PARAM_2
+{
+ MUSIC_TIME mtTime;
+ BYTE bCommand;
+ BYTE bGrooveLevel;
+ BYTE bGrooveRange;
+ BYTE bRepeatMode;
+} DMUS_COMMAND_PARAM_2;
+
+/* Get/SetParam structs for melody fragments */
+/* Note: Melody formulation is not supported in DX8. */
+typedef struct _DMUS_CONNECTION_RULE
+{
+ DWORD dwFlags; /* DMUS_CONNECTIONF_ flags */
+ DWORD dwIntervals; /* Legal transition intervals (first 24 bits; two-octave range) */
+} DMUS_CONNECTION_RULE;
+
+typedef struct _DMUS_MELODY_FRAGMENT
+{
+ MUSIC_TIME mtTime;
+ DWORD dwID; /* This fragment's ID */
+ WCHAR wszVariationLabel[DMUS_MAX_FRAGMENTLABEL]; /* Each style translates this into a set of variations (held in part ref) */
+ DWORD dwVariationFlags; /* A set of variations */
+ DWORD dwRepeatFragmentID; /* ID of a fragment to repeat */
+ DWORD dwFragmentFlags; /* DMUS_FRAGMENTF_ flags */
+ DWORD dwPlayModeFlags; /* NOT CURRENTLY USED - MUST BE 0 */
+ DWORD dwTransposeIntervals; /* Legal transposition intervals (first 24 bits; two-octave range) */
+ DMUS_COMMAND_PARAM Command;
+ DMUS_CONNECTION_RULE ConnectionArc;
+} DMUS_MELODY_FRAGMENT;
+
+typedef IDirectMusicObject __RPC_FAR *LPDMUS_OBJECT;
+typedef IDirectMusicLoader __RPC_FAR *LPDMUS_LOADER;
+typedef IDirectMusicBand __RPC_FAR *LPDMUS_BAND;
+
+#define DMUSB_LOADED (1 << 0) /* Set when band has been loaded */
+#define DMUSB_DEFAULT (1 << 1) /* Set when band is default band for a style */
+
+/*////////////////////////////////////////////////////////////////////
+// IDirectMusicBand */
+#undef INTERFACE
+#define INTERFACE IDirectMusicBand
+DECLARE_INTERFACE_(IDirectMusicBand, IUnknown)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicBand */
+ STDMETHOD(CreateSegment) (THIS_ IDirectMusicSegment** ppSegment) PURE;
+ STDMETHOD(Download) (THIS_ IDirectMusicPerformance* pPerformance) PURE;
+ STDMETHOD(Unload) (THIS_ IDirectMusicPerformance* pPerformance) PURE;
+};
+
+typedef IDirectMusicBand IDirectMusicBand8;
+
+/*////////////////////////////////////////////////////////////////////
+// IDirectMusicObject */
+#undef INTERFACE
+#define INTERFACE IDirectMusicObject
+DECLARE_INTERFACE_(IDirectMusicObject, IUnknown)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicObject */
+ STDMETHOD(GetDescriptor) (THIS_ LPDMUS_OBJECTDESC pDesc) PURE;
+ STDMETHOD(SetDescriptor) (THIS_ LPDMUS_OBJECTDESC pDesc) PURE;
+ STDMETHOD(ParseDescriptor) (THIS_ LPSTREAM pStream,
+ LPDMUS_OBJECTDESC pDesc) PURE;
+};
+
+typedef IDirectMusicObject IDirectMusicObject8;
+
+/*////////////////////////////////////////////////////////////////////
+// IDirectMusicLoader */
+#undef INTERFACE
+#define INTERFACE IDirectMusicLoader
+DECLARE_INTERFACE_(IDirectMusicLoader, IUnknown)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicLoader */
+ STDMETHOD(GetObject) (THIS_ LPDMUS_OBJECTDESC pDesc,
+ REFIID riid,
+ LPVOID FAR *ppv) PURE;
+ STDMETHOD(SetObject) (THIS_ LPDMUS_OBJECTDESC pDesc) PURE;
+ STDMETHOD(SetSearchDirectory) (THIS_ REFGUID rguidClass,
+ WCHAR *pwzPath,
+ BOOL fClear) PURE;
+ STDMETHOD(ScanDirectory) (THIS_ REFGUID rguidClass,
+ WCHAR *pwzFileExtension,
+ WCHAR *pwzScanFileName) PURE;
+ STDMETHOD(CacheObject) (THIS_ IDirectMusicObject * pObject) PURE;
+ STDMETHOD(ReleaseObject) (THIS_ IDirectMusicObject * pObject) PURE;
+ STDMETHOD(ClearCache) (THIS_ REFGUID rguidClass) PURE;
+ STDMETHOD(EnableCache) (THIS_ REFGUID rguidClass,
+ BOOL fEnable) PURE;
+ STDMETHOD(EnumObject) (THIS_ REFGUID rguidClass,
+ DWORD dwIndex,
+ LPDMUS_OBJECTDESC pDesc) PURE;
+};
+
+/*////////////////////////////////////////////////////////////////////
+// IDirectMusicLoader8 */
+#undef INTERFACE
+#define INTERFACE IDirectMusicLoader8
+DECLARE_INTERFACE_(IDirectMusicLoader8, IDirectMusicLoader)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicLoader */
+ STDMETHOD(GetObject) (THIS_ LPDMUS_OBJECTDESC pDesc,
+ REFIID riid,
+ LPVOID FAR *ppv) PURE;
+ STDMETHOD(SetObject) (THIS_ LPDMUS_OBJECTDESC pDesc) PURE;
+ STDMETHOD(SetSearchDirectory) (THIS_ REFGUID rguidClass,
+ WCHAR *pwzPath,
+ BOOL fClear) PURE;
+ STDMETHOD(ScanDirectory) (THIS_ REFGUID rguidClass,
+ WCHAR *pwzFileExtension,
+ WCHAR *pwzScanFileName) PURE;
+ STDMETHOD(CacheObject) (THIS_ IDirectMusicObject * pObject) PURE;
+ STDMETHOD(ReleaseObject) (THIS_ IDirectMusicObject * pObject) PURE;
+ STDMETHOD(ClearCache) (THIS_ REFGUID rguidClass) PURE;
+ STDMETHOD(EnableCache) (THIS_ REFGUID rguidClass,
+ BOOL fEnable) PURE;
+ STDMETHOD(EnumObject) (THIS_ REFGUID rguidClass,
+ DWORD dwIndex,
+ LPDMUS_OBJECTDESC pDesc) PURE;
+
+ /* IDirectMusicLoader8 */
+ STDMETHOD_(void, CollectGarbage) (THIS) PURE;
+ STDMETHOD(ReleaseObjectByUnknown) (THIS_ IUnknown *pObject) PURE;
+ STDMETHOD(LoadObjectFromFile) (THIS_ REFGUID rguidClassID,
+ REFIID iidInterfaceID,
+ WCHAR *pwzFilePath,
+ void ** ppObject) PURE;
+};
+
+/* Stream object supports IDirectMusicGetLoader interface to access loader while file parsing. */
+
+#undef INTERFACE
+#define INTERFACE IDirectMusicGetLoader
+DECLARE_INTERFACE_(IDirectMusicGetLoader, IUnknown)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicGetLoader */
+ STDMETHOD(GetLoader) (THIS_ IDirectMusicLoader ** ppLoader) PURE;
+};
+
+typedef IDirectMusicGetLoader IDirectMusicGetLoader8;
+
+/*////////////////////////////////////////////////////////////////////
+// IDirectMusicSegment */
+#undef INTERFACE
+#define INTERFACE IDirectMusicSegment
+DECLARE_INTERFACE_(IDirectMusicSegment, IUnknown)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicSegment */
+ STDMETHOD(GetLength) (THIS_ MUSIC_TIME* pmtLength) PURE;
+ STDMETHOD(SetLength) (THIS_ MUSIC_TIME mtLength) PURE;
+ STDMETHOD(GetRepeats) (THIS_ DWORD* pdwRepeats) PURE;
+ STDMETHOD(SetRepeats) (THIS_ DWORD dwRepeats) PURE;
+ STDMETHOD(GetDefaultResolution) (THIS_ DWORD* pdwResolution) PURE;
+ STDMETHOD(SetDefaultResolution) (THIS_ DWORD dwResolution) PURE;
+ STDMETHOD(GetTrack) (THIS_ REFGUID rguidType,
+ DWORD dwGroupBits,
+ DWORD dwIndex,
+ IDirectMusicTrack** ppTrack) PURE;
+ STDMETHOD(GetTrackGroup) (THIS_ IDirectMusicTrack* pTrack,
+ DWORD* pdwGroupBits) PURE;
+ STDMETHOD(InsertTrack) (THIS_ IDirectMusicTrack* pTrack,
+ DWORD dwGroupBits) PURE;
+ STDMETHOD(RemoveTrack) (THIS_ IDirectMusicTrack* pTrack) PURE;
+ STDMETHOD(InitPlay) (THIS_ IDirectMusicSegmentState** ppSegState,
+ IDirectMusicPerformance* pPerformance,
+ DWORD dwFlags) PURE;
+ STDMETHOD(GetGraph) (THIS_ IDirectMusicGraph** ppGraph) PURE;
+ STDMETHOD(SetGraph) (THIS_ IDirectMusicGraph* pGraph) PURE;
+ STDMETHOD(AddNotificationType) (THIS_ REFGUID rguidNotificationType) PURE;
+ STDMETHOD(RemoveNotificationType) (THIS_ REFGUID rguidNotificationType) PURE;
+ STDMETHOD(GetParam) (THIS_ REFGUID rguidType,
+ DWORD dwGroupBits,
+ DWORD dwIndex,
+ MUSIC_TIME mtTime,
+ MUSIC_TIME* pmtNext,
+ void* pParam) PURE;
+ STDMETHOD(SetParam) (THIS_ REFGUID rguidType,
+ DWORD dwGroupBits,
+ DWORD dwIndex,
+ MUSIC_TIME mtTime,
+ void* pParam) PURE;
+ STDMETHOD(Clone) (THIS_ MUSIC_TIME mtStart,
+ MUSIC_TIME mtEnd,
+ IDirectMusicSegment** ppSegment) PURE;
+ STDMETHOD(SetStartPoint) (THIS_ MUSIC_TIME mtStart) PURE;
+ STDMETHOD(GetStartPoint) (THIS_ MUSIC_TIME* pmtStart) PURE;
+ STDMETHOD(SetLoopPoints) (THIS_ MUSIC_TIME mtStart,
+ MUSIC_TIME mtEnd) PURE;
+ STDMETHOD(GetLoopPoints) (THIS_ MUSIC_TIME* pmtStart,
+ MUSIC_TIME* pmtEnd) PURE;
+ STDMETHOD(SetPChannelsUsed) (THIS_ DWORD dwNumPChannels,
+ DWORD* paPChannels) PURE;
+};
+
+/*////////////////////////////////////////////////////////////////////
+// IDirectMusicSegment8 */
+#undef INTERFACE
+#define INTERFACE IDirectMusicSegment8
+DECLARE_INTERFACE_(IDirectMusicSegment8, IDirectMusicSegment)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicSegment */
+ STDMETHOD(GetLength) (THIS_ MUSIC_TIME* pmtLength) PURE;
+ STDMETHOD(SetLength) (THIS_ MUSIC_TIME mtLength) PURE;
+ STDMETHOD(GetRepeats) (THIS_ DWORD* pdwRepeats) PURE;
+ STDMETHOD(SetRepeats) (THIS_ DWORD dwRepeats) PURE;
+ STDMETHOD(GetDefaultResolution) (THIS_ DWORD* pdwResolution) PURE;
+ STDMETHOD(SetDefaultResolution) (THIS_ DWORD dwResolution) PURE;
+ STDMETHOD(GetTrack) (THIS_ REFGUID rguidType,
+ DWORD dwGroupBits,
+ DWORD dwIndex,
+ IDirectMusicTrack** ppTrack) PURE;
+ STDMETHOD(GetTrackGroup) (THIS_ IDirectMusicTrack* pTrack,
+ DWORD* pdwGroupBits) PURE;
+ STDMETHOD(InsertTrack) (THIS_ IDirectMusicTrack* pTrack,
+ DWORD dwGroupBits) PURE;
+ STDMETHOD(RemoveTrack) (THIS_ IDirectMusicTrack* pTrack) PURE;
+ STDMETHOD(InitPlay) (THIS_ IDirectMusicSegmentState** ppSegState,
+ IDirectMusicPerformance* pPerformance,
+ DWORD dwFlags) PURE;
+ STDMETHOD(GetGraph) (THIS_ IDirectMusicGraph** ppGraph) PURE;
+ STDMETHOD(SetGraph) (THIS_ IDirectMusicGraph* pGraph) PURE;
+ STDMETHOD(AddNotificationType) (THIS_ REFGUID rguidNotificationType) PURE;
+ STDMETHOD(RemoveNotificationType) (THIS_ REFGUID rguidNotificationType) PURE;
+ STDMETHOD(GetParam) (THIS_ REFGUID rguidType,
+ DWORD dwGroupBits,
+ DWORD dwIndex,
+ MUSIC_TIME mtTime,
+ MUSIC_TIME* pmtNext,
+ void* pParam) PURE;
+ STDMETHOD(SetParam) (THIS_ REFGUID rguidType,
+ DWORD dwGroupBits,
+ DWORD dwIndex,
+ MUSIC_TIME mtTime,
+ void* pParam) PURE;
+ STDMETHOD(Clone) (THIS_ MUSIC_TIME mtStart,
+ MUSIC_TIME mtEnd,
+ IDirectMusicSegment** ppSegment) PURE;
+ STDMETHOD(SetStartPoint) (THIS_ MUSIC_TIME mtStart) PURE;
+ STDMETHOD(GetStartPoint) (THIS_ MUSIC_TIME* pmtStart) PURE;
+ STDMETHOD(SetLoopPoints) (THIS_ MUSIC_TIME mtStart,
+ MUSIC_TIME mtEnd) PURE;
+ STDMETHOD(GetLoopPoints) (THIS_ MUSIC_TIME* pmtStart,
+ MUSIC_TIME* pmtEnd) PURE;
+ STDMETHOD(SetPChannelsUsed) (THIS_ DWORD dwNumPChannels,
+ DWORD* paPChannels) PURE;
+ /* IDirectMusicSegment8 */
+ STDMETHOD(SetTrackConfig) (THIS_ REFGUID rguidTrackClassID, /* Class ID of the type of track on which to set the configuration flags. */
+ DWORD dwGroupBits, /* Group bits. */
+ DWORD dwIndex, /* Nth track (or DMUS_SEG_ALLTRACKS) that matches class id and group id. */
+ DWORD dwFlagsOn, /* DMUS_TRACKCONFIG_ flags to enable. */
+ DWORD dwFlagsOff) PURE; /* DMUS_TRACKCONFIG_ flags to disable. */
+ STDMETHOD(GetAudioPathConfig) (THIS_ IUnknown ** ppAudioPathConfig) PURE;
+ STDMETHOD(Compose) (THIS_ MUSIC_TIME mtTime,
+ IDirectMusicSegment* pFromSegment,
+ IDirectMusicSegment* pToSegment,
+ IDirectMusicSegment** ppComposedSegment) PURE;
+ STDMETHOD(Download) (THIS_ IUnknown *pAudioPath) PURE;
+ STDMETHOD(Unload) (THIS_ IUnknown *pAudioPath) PURE;
+};
+
+/*/////////////////////////////////////////////////////////////////////
+// IDirectMusicSegmentState */
+#undef INTERFACE
+#define INTERFACE IDirectMusicSegmentState
+DECLARE_INTERFACE_(IDirectMusicSegmentState, IUnknown)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicSegmentState */
+ STDMETHOD(GetRepeats) (THIS_ DWORD* pdwRepeats) PURE;
+ STDMETHOD(GetSegment ) (THIS_ IDirectMusicSegment** ppSegment) PURE;
+ STDMETHOD(GetStartTime) (THIS_ MUSIC_TIME* pmtStart) PURE;
+ STDMETHOD(GetSeek) (THIS_ MUSIC_TIME* pmtSeek) PURE;
+ STDMETHOD(GetStartPoint) (THIS_ MUSIC_TIME* pmtStart) PURE;
+};
+
+/*/////////////////////////////////////////////////////////////////////
+// IDirectMusicSegmentState8 */
+#undef INTERFACE
+#define INTERFACE IDirectMusicSegmentState8
+DECLARE_INTERFACE_(IDirectMusicSegmentState8, IDirectMusicSegmentState)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicSegmentState */
+ STDMETHOD(GetRepeats) (THIS_ DWORD* pdwRepeats) PURE;
+ STDMETHOD(GetSegment ) (THIS_ IDirectMusicSegment** ppSegment) PURE;
+ STDMETHOD(GetStartTime) (THIS_ MUSIC_TIME* pmtStart) PURE;
+ STDMETHOD(GetSeek) (THIS_ MUSIC_TIME* pmtSeek) PURE;
+ STDMETHOD(GetStartPoint) (THIS_ MUSIC_TIME* pmtStart) PURE;
+
+ /* IDirectMusicSegmentState8 */
+ STDMETHOD(SetTrackConfig) (THIS_ REFGUID rguidTrackClassID, /* Class ID of the type of track on which to set the configuration flags. */
+ DWORD dwGroupBits, /* Group bits. */
+ DWORD dwIndex, /* Nth track (or DMUS_SEG_ALLTRACKS) that matches class id and group id. */
+ DWORD dwFlagsOn, /* DMUS_TRACKCONFIG_ flags to enable. */
+ DWORD dwFlagsOff) PURE; /* DMUS_TRACKCONFIG_ flags to disable. */
+ STDMETHOD(GetObjectInPath) (THIS_ DWORD dwPChannel, /* PChannel to search. */
+ DWORD dwStage, /* Which stage in the path. */
+ DWORD dwBuffer, /* Which buffer to address, if more than one. */
+ REFGUID guidObject, /* ClassID of object. */
+ DWORD dwIndex, /* Which object of that class. */
+ REFGUID iidInterface,/* Requested COM interface. */
+ void ** ppObject) PURE; /* Pointer to interface. */
+};
+
+/*////////////////////////////////////////////////////////////////////
+// IDirectMusicAudioPath */
+#undef INTERFACE
+#define INTERFACE IDirectMusicAudioPath
+DECLARE_INTERFACE_(IDirectMusicAudioPath, IUnknown)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicAudioPath */
+ STDMETHOD(GetObjectInPath) (THIS_ DWORD dwPChannel, /* PChannel to search. */
+ DWORD dwStage, /* Which stage in the path. */
+ DWORD dwBuffer, /* Which buffer to address, if more than one. */
+ REFGUID guidObject, /* ClassID of object. */
+ DWORD dwIndex, /* Which object of that class. */
+ REFGUID iidInterface,/* Requested COM interface. */
+ void ** ppObject) PURE; /* Pointer to interface. */
+ STDMETHOD(Activate) (THIS_ BOOL fActivate) PURE;/* True to activate, False to deactivate. */
+ STDMETHOD(SetVolume) (THIS_ long lVolume, /* Gain, in 100ths of a dB. This must be negative (0 represents full volume.) */
+ DWORD dwDuration) PURE;/* Duration of volume ramp in milliseconds. Note that 0 is more efficient. */
+ STDMETHOD(ConvertPChannel) (THIS_ DWORD dwPChannelIn, /* Pchannel of source. */
+ DWORD *pdwPChannelOut) PURE; /* Equivalent pchannel on performance. */
+};
+
+typedef IDirectMusicAudioPath IDirectMusicAudioPath8;
+
+/*////////////////////////////////////////////////////////////////////
+// IDirectMusicPerformance */
+#undef INTERFACE
+#define INTERFACE IDirectMusicPerformance
+DECLARE_INTERFACE_(IDirectMusicPerformance, IUnknown)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicPerformance */
+ STDMETHOD(Init) (THIS_ IDirectMusic** ppDirectMusic,
+ LPDIRECTSOUND pDirectSound,
+ HWND hWnd) PURE;
+ STDMETHOD(PlaySegment) (THIS_ IDirectMusicSegment* pSegment,
+ DWORD dwFlags,
+ __int64 i64StartTime,
+ IDirectMusicSegmentState** ppSegmentState) PURE;
+ STDMETHOD(Stop) (THIS_ IDirectMusicSegment* pSegment,
+ IDirectMusicSegmentState* pSegmentState,
+ MUSIC_TIME mtTime,
+ DWORD dwFlags) PURE;
+ STDMETHOD(GetSegmentState) (THIS_ IDirectMusicSegmentState** ppSegmentState,
+ MUSIC_TIME mtTime) PURE;
+ STDMETHOD(SetPrepareTime) (THIS_ DWORD dwMilliSeconds) PURE;
+ STDMETHOD(GetPrepareTime) (THIS_ DWORD* pdwMilliSeconds) PURE;
+ STDMETHOD(SetBumperLength) (THIS_ DWORD dwMilliSeconds) PURE;
+ STDMETHOD(GetBumperLength) (THIS_ DWORD* pdwMilliSeconds) PURE;
+ STDMETHOD(SendPMsg) (THIS_ DMUS_PMSG* pPMSG) PURE;
+ STDMETHOD(MusicToReferenceTime) (THIS_ MUSIC_TIME mtTime,
+ REFERENCE_TIME* prtTime) PURE;
+ STDMETHOD(ReferenceToMusicTime) (THIS_ REFERENCE_TIME rtTime,
+ MUSIC_TIME* pmtTime) PURE;
+ STDMETHOD(IsPlaying) (THIS_ IDirectMusicSegment* pSegment,
+ IDirectMusicSegmentState* pSegState) PURE;
+ STDMETHOD(GetTime) (THIS_ REFERENCE_TIME* prtNow,
+ MUSIC_TIME* pmtNow) PURE;
+ STDMETHOD(AllocPMsg) (THIS_ ULONG cb,
+ DMUS_PMSG** ppPMSG) PURE;
+ STDMETHOD(FreePMsg) (THIS_ DMUS_PMSG* pPMSG) PURE;
+ STDMETHOD(GetGraph) (THIS_ IDirectMusicGraph** ppGraph) PURE;
+ STDMETHOD(SetGraph) (THIS_ IDirectMusicGraph* pGraph) PURE;
+ STDMETHOD(SetNotificationHandle)(THIS_ HANDLE hNotification,
+ REFERENCE_TIME rtMinimum) PURE;
+ STDMETHOD(GetNotificationPMsg) (THIS_ DMUS_NOTIFICATION_PMSG** ppNotificationPMsg) PURE;
+ STDMETHOD(AddNotificationType) (THIS_ REFGUID rguidNotificationType) PURE;
+ STDMETHOD(RemoveNotificationType)(THIS_ REFGUID rguidNotificationType) PURE;
+ STDMETHOD(AddPort) (THIS_ IDirectMusicPort* pPort) PURE;
+ STDMETHOD(RemovePort) (THIS_ IDirectMusicPort* pPort ) PURE;
+ STDMETHOD(AssignPChannelBlock) (THIS_ DWORD dwBlockNum,
+ IDirectMusicPort* pPort,
+ DWORD dwGroup ) PURE;
+ STDMETHOD(AssignPChannel) (THIS_ DWORD dwPChannel,
+ IDirectMusicPort* pPort,
+ DWORD dwGroup,
+ DWORD dwMChannel ) PURE;
+ STDMETHOD(PChannelInfo) (THIS_ DWORD dwPChannel,
+ IDirectMusicPort** ppPort,
+ DWORD* pdwGroup,
+ DWORD* pdwMChannel ) PURE;
+ STDMETHOD(DownloadInstrument) (THIS_ IDirectMusicInstrument* pInst,
+ DWORD dwPChannel,
+ IDirectMusicDownloadedInstrument** ppDownInst,
+ DMUS_NOTERANGE* pNoteRanges,
+ DWORD dwNumNoteRanges,
+ IDirectMusicPort** ppPort,
+ DWORD* pdwGroup,
+ DWORD* pdwMChannel ) PURE;
+ STDMETHOD(Invalidate) (THIS_ MUSIC_TIME mtTime,
+ DWORD dwFlags) PURE;
+ STDMETHOD(GetParam) (THIS_ REFGUID rguidType,
+ DWORD dwGroupBits,
+ DWORD dwIndex,
+ MUSIC_TIME mtTime,
+ MUSIC_TIME* pmtNext,
+ void* pParam) PURE;
+ STDMETHOD(SetParam) (THIS_ REFGUID rguidType,
+ DWORD dwGroupBits,
+ DWORD dwIndex,
+ MUSIC_TIME mtTime,
+ void* pParam) PURE;
+ STDMETHOD(GetGlobalParam) (THIS_ REFGUID rguidType,
+ void* pParam,
+ DWORD dwSize) PURE;
+ STDMETHOD(SetGlobalParam) (THIS_ REFGUID rguidType,
+ void* pParam,
+ DWORD dwSize) PURE;
+ STDMETHOD(GetLatencyTime) (THIS_ REFERENCE_TIME* prtTime) PURE;
+ STDMETHOD(GetQueueTime) (THIS_ REFERENCE_TIME* prtTime) PURE;
+ STDMETHOD(AdjustTime) (THIS_ REFERENCE_TIME rtAmount) PURE;
+ STDMETHOD(CloseDown) (THIS) PURE;
+ STDMETHOD(GetResolvedTime) (THIS_ REFERENCE_TIME rtTime,
+ REFERENCE_TIME* prtResolved,
+ DWORD dwTimeResolveFlags) PURE;
+ STDMETHOD(MIDIToMusic) (THIS_ BYTE bMIDIValue,
+ DMUS_CHORD_KEY* pChord,
+ BYTE bPlayMode,
+ BYTE bChordLevel,
+ WORD *pwMusicValue) PURE;
+ STDMETHOD(MusicToMIDI) (THIS_ WORD wMusicValue,
+ DMUS_CHORD_KEY* pChord,
+ BYTE bPlayMode,
+ BYTE bChordLevel,
+ BYTE *pbMIDIValue) PURE;
+ STDMETHOD(TimeToRhythm) (THIS_ MUSIC_TIME mtTime,
+ DMUS_TIMESIGNATURE *pTimeSig,
+ WORD *pwMeasure,
+ BYTE *pbBeat,
+ BYTE *pbGrid,
+ short *pnOffset) PURE;
+ STDMETHOD(RhythmToTime) (THIS_ WORD wMeasure,
+ BYTE bBeat,
+ BYTE bGrid,
+ short nOffset,
+ DMUS_TIMESIGNATURE *pTimeSig,
+ MUSIC_TIME *pmtTime) PURE;
+};
+
+/*////////////////////////////////////////////////////////////////////
+// IDirectMusicPerformance8 */
+#undef INTERFACE
+#define INTERFACE IDirectMusicPerformance8
+DECLARE_INTERFACE_(IDirectMusicPerformance8, IDirectMusicPerformance)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicPerformance */
+ STDMETHOD(Init) (THIS_ IDirectMusic** ppDirectMusic,
+ LPDIRECTSOUND pDirectSound,
+ HWND hWnd) PURE;
+ STDMETHOD(PlaySegment) (THIS_ IDirectMusicSegment* pSegment,
+ DWORD dwFlags,
+ __int64 i64StartTime,
+ IDirectMusicSegmentState** ppSegmentState) PURE;
+ STDMETHOD(Stop) (THIS_ IDirectMusicSegment* pSegment,
+ IDirectMusicSegmentState* pSegmentState,
+ MUSIC_TIME mtTime,
+ DWORD dwFlags) PURE;
+ STDMETHOD(GetSegmentState) (THIS_ IDirectMusicSegmentState** ppSegmentState,
+ MUSIC_TIME mtTime) PURE;
+ STDMETHOD(SetPrepareTime) (THIS_ DWORD dwMilliSeconds) PURE;
+ STDMETHOD(GetPrepareTime) (THIS_ DWORD* pdwMilliSeconds) PURE;
+ STDMETHOD(SetBumperLength) (THIS_ DWORD dwMilliSeconds) PURE;
+ STDMETHOD(GetBumperLength) (THIS_ DWORD* pdwMilliSeconds) PURE;
+ STDMETHOD(SendPMsg) (THIS_ DMUS_PMSG* pPMSG) PURE;
+ STDMETHOD(MusicToReferenceTime) (THIS_ MUSIC_TIME mtTime,
+ REFERENCE_TIME* prtTime) PURE;
+ STDMETHOD(ReferenceToMusicTime) (THIS_ REFERENCE_TIME rtTime,
+ MUSIC_TIME* pmtTime) PURE;
+ STDMETHOD(IsPlaying) (THIS_ IDirectMusicSegment* pSegment,
+ IDirectMusicSegmentState* pSegState) PURE;
+ STDMETHOD(GetTime) (THIS_ REFERENCE_TIME* prtNow,
+ MUSIC_TIME* pmtNow) PURE;
+ STDMETHOD(AllocPMsg) (THIS_ ULONG cb,
+ DMUS_PMSG** ppPMSG) PURE;
+ STDMETHOD(FreePMsg) (THIS_ DMUS_PMSG* pPMSG) PURE;
+ STDMETHOD(GetGraph) (THIS_ IDirectMusicGraph** ppGraph) PURE;
+ STDMETHOD(SetGraph) (THIS_ IDirectMusicGraph* pGraph) PURE;
+ STDMETHOD(SetNotificationHandle)(THIS_ HANDLE hNotification,
+ REFERENCE_TIME rtMinimum) PURE;
+ STDMETHOD(GetNotificationPMsg) (THIS_ DMUS_NOTIFICATION_PMSG** ppNotificationPMsg) PURE;
+ STDMETHOD(AddNotificationType) (THIS_ REFGUID rguidNotificationType) PURE;
+ STDMETHOD(RemoveNotificationType)(THIS_ REFGUID rguidNotificationType) PURE;
+ STDMETHOD(AddPort) (THIS_ IDirectMusicPort* pPort) PURE;
+ STDMETHOD(RemovePort) (THIS_ IDirectMusicPort* pPort ) PURE;
+ STDMETHOD(AssignPChannelBlock) (THIS_ DWORD dwBlockNum,
+ IDirectMusicPort* pPort,
+ DWORD dwGroup ) PURE;
+ STDMETHOD(AssignPChannel) (THIS_ DWORD dwPChannel,
+ IDirectMusicPort* pPort,
+ DWORD dwGroup,
+ DWORD dwMChannel ) PURE;
+ STDMETHOD(PChannelInfo) (THIS_ DWORD dwPChannel,
+ IDirectMusicPort** ppPort,
+ DWORD* pdwGroup,
+ DWORD* pdwMChannel ) PURE;
+ STDMETHOD(DownloadInstrument) (THIS_ IDirectMusicInstrument* pInst,
+ DWORD dwPChannel,
+ IDirectMusicDownloadedInstrument** ppDownInst,
+ DMUS_NOTERANGE* pNoteRanges,
+ DWORD dwNumNoteRanges,
+ IDirectMusicPort** ppPort,
+ DWORD* pdwGroup,
+ DWORD* pdwMChannel ) PURE;
+ STDMETHOD(Invalidate) (THIS_ MUSIC_TIME mtTime,
+ DWORD dwFlags) PURE;
+ STDMETHOD(GetParam) (THIS_ REFGUID rguidType,
+ DWORD dwGroupBits,
+ DWORD dwIndex,
+ MUSIC_TIME mtTime,
+ MUSIC_TIME* pmtNext,
+ void* pParam) PURE;
+ STDMETHOD(SetParam) (THIS_ REFGUID rguidType,
+ DWORD dwGroupBits,
+ DWORD dwIndex,
+ MUSIC_TIME mtTime,
+ void* pParam) PURE;
+ STDMETHOD(GetGlobalParam) (THIS_ REFGUID rguidType,
+ void* pParam,
+ DWORD dwSize) PURE;
+ STDMETHOD(SetGlobalParam) (THIS_ REFGUID rguidType,
+ void* pParam,
+ DWORD dwSize) PURE;
+ STDMETHOD(GetLatencyTime) (THIS_ REFERENCE_TIME* prtTime) PURE;
+ STDMETHOD(GetQueueTime) (THIS_ REFERENCE_TIME* prtTime) PURE;
+ STDMETHOD(AdjustTime) (THIS_ REFERENCE_TIME rtAmount) PURE;
+ STDMETHOD(CloseDown) (THIS) PURE;
+ STDMETHOD(GetResolvedTime) (THIS_ REFERENCE_TIME rtTime,
+ REFERENCE_TIME* prtResolved,
+ DWORD dwTimeResolveFlags) PURE;
+ STDMETHOD(MIDIToMusic) (THIS_ BYTE bMIDIValue,
+ DMUS_CHORD_KEY* pChord,
+ BYTE bPlayMode,
+ BYTE bChordLevel,
+ WORD *pwMusicValue) PURE;
+ STDMETHOD(MusicToMIDI) (THIS_ WORD wMusicValue,
+ DMUS_CHORD_KEY* pChord,
+ BYTE bPlayMode,
+ BYTE bChordLevel,
+ BYTE *pbMIDIValue) PURE;
+ STDMETHOD(TimeToRhythm) (THIS_ MUSIC_TIME mtTime,
+ DMUS_TIMESIGNATURE *pTimeSig,
+ WORD *pwMeasure,
+ BYTE *pbBeat,
+ BYTE *pbGrid,
+ short *pnOffset) PURE;
+ STDMETHOD(RhythmToTime) (THIS_ WORD wMeasure,
+ BYTE bBeat,
+ BYTE bGrid,
+ short nOffset,
+ DMUS_TIMESIGNATURE *pTimeSig,
+ MUSIC_TIME *pmtTime) PURE;
+ /* IDirectMusicPerformance8 */
+ STDMETHOD(InitAudio) (THIS_ IDirectMusic** ppDirectMusic, /* Optional DMusic pointer. */
+ IDirectSound** ppDirectSound, /* Optional DSound pointer. */
+ HWND hWnd, /* HWND for DSound. */
+ DWORD dwDefaultPathType, /* Requested default audio path type, also optional. */
+ DWORD dwPChannelCount, /* Number of PChannels, if default audio path to be created. */
+ DWORD dwFlags, /* DMUS_AUDIOF flags, if no pParams structure. */
+ DMUS_AUDIOPARAMS *pParams) PURE; /* Optional initialization structure, defining required voices, buffers, etc. */
+ STDMETHOD(PlaySegmentEx) (THIS_ IUnknown* pSource, /* Segment to play. Alternately, could be an IDirectMusicSong (not supported in DX8.) */
+ WCHAR *pwzSegmentName, /* If song, which segment in the song (not supported in DX8.) */
+ IUnknown* pTransition, /* Optional template segment to compose transition with. */
+ DWORD dwFlags, /* DMUS_SEGF_ flags. */
+ __int64 i64StartTime, /* Time to start playback. */
+ IDirectMusicSegmentState** ppSegmentState, /* Returned Segment State. */
+ IUnknown *pFrom, /* Optional segmentstate or audiopath to replace. */
+ IUnknown *pAudioPath) PURE; /* Optional audioPath to play on. */
+ STDMETHOD(StopEx) (THIS_ IUnknown *pObjectToStop, /* Segstate, AudioPath, Segment, or Song. */
+ __int64 i64StopTime,
+ DWORD dwFlags) PURE;
+ STDMETHOD(ClonePMsg) (THIS_ DMUS_PMSG* pSourcePMSG,
+ DMUS_PMSG** ppCopyPMSG) PURE;
+ STDMETHOD(CreateAudioPath) (THIS_ IUnknown *pSourceConfig, /* Source configuration, from AudioPathConfig file. */
+ BOOL fActivate, /* TRUE to activate on creation. */
+ IDirectMusicAudioPath **ppNewPath) PURE; /* Returns created audiopath. */
+ STDMETHOD(CreateStandardAudioPath)(THIS_ DWORD dwType, /* Type of path to create. */
+ DWORD dwPChannelCount, /* How many PChannels to allocate for it. */
+ BOOL fActivate, /* TRUE to activate on creation. */
+ IDirectMusicAudioPath **ppNewPath) PURE; /* Returns created audiopath. */
+ STDMETHOD(SetDefaultAudioPath) (THIS_ IDirectMusicAudioPath *pAudioPath) PURE;
+ STDMETHOD(GetDefaultAudioPath) (THIS_ IDirectMusicAudioPath **ppAudioPath) PURE;
+ STDMETHOD(GetParamEx) (THIS_ REFGUID rguidType, /* GetParam command ID. */
+ DWORD dwTrackID, /* Virtual track ID of caller. */
+ DWORD dwGroupBits, /* Group bits of caller. */
+ DWORD dwIndex, /* Index to Nth parameter. */
+ MUSIC_TIME mtTime, /* Time of requested parameter. */
+ MUSIC_TIME* pmtNext, /* Returned delta to next parameter. */
+ void* pParam) PURE; /* Data structure to fill with parameter. */
+};
+
+
+
+/*////////////////////////////////////////////////////////////////////
+// IDirectMusicGraph */
+#undef INTERFACE
+#define INTERFACE IDirectMusicGraph
+DECLARE_INTERFACE_(IDirectMusicGraph, IUnknown)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicGraph */
+ STDMETHOD(StampPMsg) (THIS_ DMUS_PMSG* pPMSG) PURE;
+ STDMETHOD(InsertTool) (THIS_ IDirectMusicTool* pTool,
+ DWORD* pdwPChannels,
+ DWORD cPChannels,
+ LONG lIndex) PURE;
+ STDMETHOD(GetTool) (THIS_ DWORD dwIndex,
+ IDirectMusicTool** ppTool) PURE;
+ STDMETHOD(RemoveTool) (THIS_ IDirectMusicTool* pTool) PURE;
+};
+
+typedef IDirectMusicGraph IDirectMusicGraph8;
+
+
+/*/////////////////////////////////////////////////////////////////////
+// IDirectMusicStyle */
+#undef INTERFACE
+#define INTERFACE IDirectMusicStyle
+DECLARE_INTERFACE_(IDirectMusicStyle, IUnknown)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicStyle */
+ STDMETHOD(GetBand) (THIS_ WCHAR* pwszName,
+ IDirectMusicBand** ppBand) PURE;
+ STDMETHOD(EnumBand) (THIS_ DWORD dwIndex,
+ WCHAR *pwszName) PURE;
+ STDMETHOD(GetDefaultBand) (THIS_ IDirectMusicBand** ppBand) PURE;
+ STDMETHOD(EnumMotif) (THIS_ DWORD dwIndex,
+ WCHAR* pwszName) PURE;
+ STDMETHOD(GetMotif) (THIS_ WCHAR* pwszName,
+ IDirectMusicSegment** ppSegment) PURE;
+ STDMETHOD(GetDefaultChordMap) (THIS_ IDirectMusicChordMap** ppChordMap) PURE;
+ STDMETHOD(EnumChordMap) (THIS_ DWORD dwIndex,
+ WCHAR *pwszName) PURE;
+ STDMETHOD(GetChordMap) (THIS_ WCHAR* pwszName,
+ IDirectMusicChordMap** ppChordMap) PURE;
+ STDMETHOD(GetTimeSignature) (THIS_ DMUS_TIMESIGNATURE* pTimeSig) PURE;
+ STDMETHOD(GetEmbellishmentLength) (THIS_ DWORD dwType,
+ DWORD dwLevel,
+ DWORD* pdwMin,
+ DWORD* pdwMax) PURE;
+ STDMETHOD(GetTempo) (THIS_ double* pTempo) PURE;
+};
+
+/*/////////////////////////////////////////////////////////////////////
+// IDirectMusicStyle8 */
+#undef INTERFACE
+#define INTERFACE IDirectMusicStyle8
+DECLARE_INTERFACE_(IDirectMusicStyle8, IDirectMusicStyle)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicStyle */
+ STDMETHOD(GetBand) (THIS_ WCHAR* pwszName,
+ IDirectMusicBand** ppBand) PURE;
+ STDMETHOD(EnumBand) (THIS_ DWORD dwIndex,
+ WCHAR *pwszName) PURE;
+ STDMETHOD(GetDefaultBand) (THIS_ IDirectMusicBand** ppBand) PURE;
+ STDMETHOD(EnumMotif) (THIS_ DWORD dwIndex,
+ WCHAR* pwszName) PURE;
+ STDMETHOD(GetMotif) (THIS_ WCHAR* pwszName,
+ IDirectMusicSegment** ppSegment) PURE;
+ STDMETHOD(GetDefaultChordMap) (THIS_ IDirectMusicChordMap** ppChordMap) PURE;
+ STDMETHOD(EnumChordMap) (THIS_ DWORD dwIndex,
+ WCHAR *pwszName) PURE;
+ STDMETHOD(GetChordMap) (THIS_ WCHAR* pwszName,
+ IDirectMusicChordMap** ppChordMap) PURE;
+ STDMETHOD(GetTimeSignature) (THIS_ DMUS_TIMESIGNATURE* pTimeSig) PURE;
+ STDMETHOD(GetEmbellishmentLength) (THIS_ DWORD dwType,
+ DWORD dwLevel,
+ DWORD* pdwMin,
+ DWORD* pdwMax) PURE;
+ STDMETHOD(GetTempo) (THIS_ double* pTempo) PURE;
+
+ /* IDirectMusicStyle8 */
+ STDMETHOD(EnumPattern) (THIS_ DWORD dwIndex,
+ DWORD dwPatternType,
+ WCHAR* pwszName) PURE;
+};
+
+/*/////////////////////////////////////////////////////////////////////
+// IDirectMusicChordMap */
+#undef INTERFACE
+#define INTERFACE IDirectMusicChordMap
+DECLARE_INTERFACE_(IDirectMusicChordMap, IUnknown)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicChordMap */
+ STDMETHOD(GetScale) (THIS_ DWORD* pdwScale) PURE;
+};
+
+typedef IDirectMusicChordMap IDirectMusicChordMap8;
+
+/*/////////////////////////////////////////////////////////////////////
+// IDirectMusicComposer */
+#undef INTERFACE
+#define INTERFACE IDirectMusicComposer
+DECLARE_INTERFACE_(IDirectMusicComposer, IUnknown)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicComposer */
+ STDMETHOD(ComposeSegmentFromTemplate) (THIS_ IDirectMusicStyle* pStyle,
+ IDirectMusicSegment* pTemplate,
+ WORD wActivity,
+ IDirectMusicChordMap* pChordMap,
+ IDirectMusicSegment** ppSegment) PURE;
+ STDMETHOD(ComposeSegmentFromShape) (THIS_ IDirectMusicStyle* pStyle,
+ WORD wNumMeasures,
+ WORD wShape,
+ WORD wActivity,
+ BOOL fIntro,
+ BOOL fEnd,
+ IDirectMusicChordMap* pChordMap,
+ IDirectMusicSegment** ppSegment ) PURE;
+ STDMETHOD(ComposeTransition) (THIS_ IDirectMusicSegment* pFromSeg,
+ IDirectMusicSegment* pToSeg,
+ MUSIC_TIME mtTime,
+ WORD wCommand,
+ DWORD dwFlags,
+ IDirectMusicChordMap* pChordMap,
+ IDirectMusicSegment** ppTransSeg) PURE;
+ STDMETHOD(AutoTransition) (THIS_ IDirectMusicPerformance* pPerformance,
+ IDirectMusicSegment* pToSeg,
+ WORD wCommand,
+ DWORD dwFlags,
+ IDirectMusicChordMap* pChordMap,
+ IDirectMusicSegment** ppTransSeg,
+ IDirectMusicSegmentState** ppToSegState,
+ IDirectMusicSegmentState** ppTransSegState) PURE;
+ STDMETHOD(ComposeTemplateFromShape) (THIS_ WORD wNumMeasures,
+ WORD wShape,
+ BOOL fIntro,
+ BOOL fEnd,
+ WORD wEndLength,
+ IDirectMusicSegment** ppTemplate) PURE;
+ STDMETHOD(ChangeChordMap) (THIS_ IDirectMusicSegment* pSegment,
+ BOOL fTrackScale,
+ IDirectMusicChordMap* pChordMap) PURE;
+};
+
+typedef IDirectMusicComposer IDirectMusicComposer8;
+
+/*/////////////////////////////////////////////////////////////////////
+// IDirectMusicPatternTrack */
+
+#undef INTERFACE
+#define INTERFACE IDirectMusicPatternTrack
+DECLARE_INTERFACE_(IDirectMusicPatternTrack, IUnknown)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicPatternTrack */
+ STDMETHOD(CreateSegment) (THIS_ IDirectMusicStyle* pStyle,
+ IDirectMusicSegment** ppSegment) PURE;
+ STDMETHOD(SetVariation) (THIS_ IDirectMusicSegmentState* pSegState,
+ DWORD dwVariationFlags,
+ DWORD dwPart) PURE;
+ STDMETHOD(SetPatternByName) (THIS_ IDirectMusicSegmentState* pSegState,
+ WCHAR* wszName,
+ IDirectMusicStyle* pStyle,
+ DWORD dwPatternType,
+ DWORD* pdwLength) PURE;
+};
+
+typedef IDirectMusicPatternTrack IDirectMusicPatternTrack8;
+
+/*/////////////////////////////////////////////////////////////////////
+// IDirectMusicScript */
+
+#undef INTERFACE
+#define INTERFACE IDirectMusicScript
+DECLARE_INTERFACE_(IDirectMusicScript, IUnknown)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicScript */
+ STDMETHOD(Init) (THIS_ IDirectMusicPerformance *pPerformance,
+ DMUS_SCRIPT_ERRORINFO *pErrorInfo) PURE;
+ STDMETHOD(CallRoutine) (THIS_ WCHAR *pwszRoutineName,
+ DMUS_SCRIPT_ERRORINFO *pErrorInfo) PURE;
+ STDMETHOD(SetVariableVariant) (THIS_ WCHAR *pwszVariableName,
+ VARIANT varValue,
+ BOOL fSetRef,
+ DMUS_SCRIPT_ERRORINFO *pErrorInfo) PURE;
+ STDMETHOD(GetVariableVariant) (THIS_ WCHAR *pwszVariableName,
+ VARIANT *pvarValue,
+ DMUS_SCRIPT_ERRORINFO *pErrorInfo) PURE;
+ STDMETHOD(SetVariableNumber) (THIS_ WCHAR *pwszVariableName,
+ LONG lValue,
+ DMUS_SCRIPT_ERRORINFO *pErrorInfo) PURE;
+ STDMETHOD(GetVariableNumber) (THIS_ WCHAR *pwszVariableName,
+ LONG *plValue,
+ DMUS_SCRIPT_ERRORINFO *pErrorInfo) PURE;
+ STDMETHOD(SetVariableObject) (THIS_ WCHAR *pwszVariableName,
+ IUnknown *punkValue,
+ DMUS_SCRIPT_ERRORINFO *pErrorInfo) PURE;
+ STDMETHOD(GetVariableObject) (THIS_ WCHAR *pwszVariableName,
+ REFIID riid,
+ LPVOID FAR *ppv,
+ DMUS_SCRIPT_ERRORINFO *pErrorInfo) PURE;
+ STDMETHOD(EnumRoutine) (THIS_ DWORD dwIndex,
+ WCHAR *pwszName) PURE;
+ STDMETHOD(EnumVariable) (THIS_ DWORD dwIndex,
+ WCHAR *pwszName) PURE;
+};
+
+typedef IDirectMusicScript IDirectMusicScript8;
+
+/*/////////////////////////////////////////////////////////////////////
+// IDirectMusicContainer */
+
+#undef INTERFACE
+#define INTERFACE IDirectMusicContainer
+DECLARE_INTERFACE_(IDirectMusicContainer, IUnknown)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicContainer */
+ STDMETHOD(EnumObject) (THIS_ REFGUID rguidClass,
+ DWORD dwIndex,
+ LPDMUS_OBJECTDESC pDesc,
+ WCHAR *pwszAlias) PURE;
+};
+
+typedef IDirectMusicContainer IDirectMusicContainer8;
+
+/*/////////////////////////////////////////////////////////////////////
+// IDirectMusicSong */
+/* Note: Songs are not supported in DX8. */
+
+#undef INTERFACE
+#define INTERFACE IDirectMusicSong
+DECLARE_INTERFACE_(IDirectMusicSong, IUnknown)
+{
+ /* IUnknown */
+ STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
+ STDMETHOD_(ULONG,AddRef) (THIS) PURE;
+ STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+ /* IDirectMusicSong */
+ STDMETHOD(Compose) (THIS) PURE;
+ STDMETHOD(GetParam) (THIS_ REFGUID rguidType,
+ DWORD dwGroupBits,
+ DWORD dwIndex,
+ MUSIC_TIME mtTime,
+ MUSIC_TIME* pmtNext,
+ void* pParam) PURE;
+ STDMETHOD(GetSegment) (THIS_ WCHAR *pwzName, /* Retrieve a specific segment by name. */
+ IDirectMusicSegment **ppSegment) PURE; /* Returned segment. */
+ STDMETHOD(GetAudioPathConfig) (THIS_ IUnknown ** ppAudioPathConfig) PURE; /* Retrieve embedded audiopath configuration. */
+ STDMETHOD(Download) (THIS_ IUnknown *pAudioPath) PURE; /* Download entire song to ports on performance or audiopath. */
+ STDMETHOD(Unload) (THIS_ IUnknown *pAudioPath) PURE; /* Unload entire song from port on performance or audiopath. */
+ STDMETHOD(EnumSegment) (THIS_ DWORD dwIndex, /* Nth segment to retrieve. */
+ IDirectMusicSegment **ppSegment) PURE; /* Pointer to segment. */
+};
+
+typedef IDirectMusicSong IDirectMusicSong8;
+
+/* CLSID's */
+DEFINE_GUID(CLSID_DirectMusicPerformance,0xd2ac2881, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(CLSID_DirectMusicSegment,0xd2ac2882, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(CLSID_DirectMusicSegmentState,0xd2ac2883, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(CLSID_DirectMusicGraph,0xd2ac2884, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(CLSID_DirectMusicStyle,0xd2ac288a, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(CLSID_DirectMusicChordMap,0xd2ac288f, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(CLSID_DirectMusicComposer,0xd2ac2890, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(CLSID_DirectMusicLoader,0xd2ac2892, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(CLSID_DirectMusicBand,0x79ba9e00, 0xb6ee, 0x11d1, 0x86, 0xbe, 0x0, 0xc0, 0x4f, 0xbf, 0x8f, 0xef);
+
+/* New CLSID's for DX8 */
+DEFINE_GUID(CLSID_DirectMusicPatternTrack,0xd2ac2897, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(CLSID_DirectMusicScript,0x810b5013, 0xe88d, 0x11d2, 0x8b, 0xc1, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xb6); /* {810B5013-E88D-11d2-8BC1-00600893B1B6} */
+DEFINE_GUID(CLSID_DirectMusicContainer,0x9301e380, 0x1f22, 0x11d3, 0x82, 0x26, 0xd2, 0xfa, 0x76, 0x25, 0x5d, 0x47);
+DEFINE_GUID(CLSID_DirectSoundWave,0x8a667154, 0xf9cb, 0x11d2, 0xad, 0x8a, 0x0, 0x60, 0xb0, 0x57, 0x5a, 0xbc);
+/* Note: Songs are not supported in DX8. */
+DEFINE_GUID(CLSID_DirectMusicSong, 0xaed5f0a5, 0xd972, 0x483d, 0xa3, 0x84, 0x64, 0x9d, 0xfe, 0xb9, 0xc1, 0x81);
+DEFINE_GUID(CLSID_DirectMusicAudioPathConfig,0xee0b9ca0, 0xa81e, 0x11d3, 0x9b, 0xd1, 0x0, 0x80, 0xc7, 0x15, 0xa, 0x74);
+
+/* Special GUID for all object types. This is used by the loader. */
+DEFINE_GUID(GUID_DirectMusicAllTypes,0xd2ac2893, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* Notification guids */
+DEFINE_GUID(GUID_NOTIFICATION_SEGMENT,0xd2ac2899, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(GUID_NOTIFICATION_PERFORMANCE,0x81f75bc5, 0x4e5d, 0x11d2, 0xbc, 0xc7, 0x0, 0xa0, 0xc9, 0x22, 0xe6, 0xeb);
+DEFINE_GUID(GUID_NOTIFICATION_MEASUREANDBEAT,0xd2ac289a, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(GUID_NOTIFICATION_CHORD,0xd2ac289b, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(GUID_NOTIFICATION_COMMAND,0xd2ac289c, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(GUID_NOTIFICATION_RECOMPOSE, 0xd348372b, 0x945b, 0x45ae, 0xa5, 0x22, 0x45, 0xf, 0x12, 0x5b, 0x84, 0xa5);
+
+/* Track param type guids */
+/* Use to get/set a DMUS_COMMAND_PARAM param in the Command track */
+DEFINE_GUID(GUID_CommandParam,0xd2ac289d, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* Use to get a DMUS_COMMAND_PARAM_2 param in the Command track */
+DEFINE_GUID(GUID_CommandParam2, 0x28f97ef7, 0x9538, 0x11d2, 0x97, 0xa9, 0x0, 0xc0, 0x4f, 0xa3, 0x6e, 0x58);
+
+/* Use to get/set a DMUS_COMMAND_PARAM_2 param to be used as the command following all commands in
+the Command track (this information can't be saved) */
+DEFINE_GUID(GUID_CommandParamNext, 0x472afe7a, 0x281b, 0x11d3, 0x81, 0x7d, 0x0, 0xc0, 0x4f, 0xa3, 0x6e, 0x58);
+
+/* Use to get/set a DMUS_CHORD_PARAM param in the Chord track */
+DEFINE_GUID(GUID_ChordParam,0xd2ac289e, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* Use to get a DMUS_RHYTHM_PARAM param in the Chord track */
+DEFINE_GUID(GUID_RhythmParam,0xd2ac289f, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* Use to get/set an IDirectMusicStyle param in the Style track */
+DEFINE_GUID(GUID_IDirectMusicStyle,0xd2ac28a1, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* Use to get a DMUS_TIMESIGNATURE param in the Style and TimeSig tracks */
+DEFINE_GUID(GUID_TimeSignature,0xd2ac28a4, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* Use to get/set a DMUS_TEMPO_PARAM param in the Tempo track */
+DEFINE_GUID(GUID_TempoParam,0xd2ac28a5, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* Use to get the next valid point in a segment at which it may start */
+DEFINE_GUID(GUID_Valid_Start_Time,0x7f6b1760, 0x1fdb, 0x11d3, 0x82, 0x26, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0);
+
+/* Use to get the next point in the currently playing primary segment at which a new segment may start */
+DEFINE_GUID(GUID_Play_Marker,0xd8761a41, 0x801a, 0x11d3, 0x9b, 0xd1, 0xda, 0xf7, 0xe1, 0xc3, 0xd8, 0x34);
+
+/* Use to get (GetParam) or add (SetParam) bands in the Band track */
+DEFINE_GUID(GUID_BandParam,0x2bb1938, 0xcb8b, 0x11d2, 0x8b, 0xb9, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xb6);
+typedef struct _DMUS_BAND_PARAM
+{
+ MUSIC_TIME mtTimePhysical; /* Note: If this is a clock-time track, then this field is interpreted in the track's internal time format, which is the number of milliseconds after the beginning of playback. */
+ IDirectMusicBand *pBand;
+} DMUS_BAND_PARAM;
+
+/* Obsolete -- doesn't distinguish physical and logical time. Use GUID_BandParam instead. */
+DEFINE_GUID(GUID_IDirectMusicBand,0xd2ac28ac, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* Use to get/set an IDirectMusicChordMap param in the ChordMap track */
+DEFINE_GUID(GUID_IDirectMusicChordMap,0xd2ac28ad, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* Use to get/set a DMUS_MUTE_PARAM param in the Mute track */
+DEFINE_GUID(GUID_MuteParam,0xd2ac28af, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* These guids are used in IDirectMusicSegment::SetParam to tell the band track to perform various actions.
+ Some of these guids (where noted) also apply to wave tracks.
+ */
+/* Download bands/waves for the IDirectMusicSegment */
+DEFINE_GUID(GUID_Download,0xd2ac28a7, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* Unload bands/waves for the IDirectMusicSegment */
+DEFINE_GUID(GUID_Unload,0xd2ac28a8, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* Connect segment's bands to an IDirectMusicCollection */
+DEFINE_GUID(GUID_ConnectToDLSCollection, 0x1db1ae6b, 0xe92e, 0x11d1, 0xa8, 0xc5, 0x0, 0xc0, 0x4f, 0xa3, 0x72, 0x6e);
+
+/* Enable/disable autodownloading of bands/waves */
+DEFINE_GUID(GUID_Enable_Auto_Download,0xd2ac28a9, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(GUID_Disable_Auto_Download,0xd2ac28aa, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* Clear all bands */
+DEFINE_GUID(GUID_Clear_All_Bands,0xd2ac28ab, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* Set segment to manage all program changes, bank selects, etc. for simple playback of a standard MIDI file */
+DEFINE_GUID(GUID_StandardMIDIFile, 0x6621075, 0xe92e, 0x11d1, 0xa8, 0xc5, 0x0, 0xc0, 0x4f, 0xa3, 0x72, 0x6e);
+/* For compatibility with beta releases... */
+#define GUID_IgnoreBankSelectForGM GUID_StandardMIDIFile
+
+/* Disable/enable param guids. Use these in SetParam calls to disable or enable sending
+ * specific PMsg types.
+ */
+DEFINE_GUID(GUID_DisableTimeSig, 0x45fc707b, 0x1db4, 0x11d2, 0xbc, 0xac, 0x0, 0xa0, 0xc9, 0x22, 0xe6, 0xeb);
+DEFINE_GUID(GUID_EnableTimeSig, 0x45fc707c, 0x1db4, 0x11d2, 0xbc, 0xac, 0x0, 0xa0, 0xc9, 0x22, 0xe6, 0xeb);
+DEFINE_GUID(GUID_DisableTempo, 0x45fc707d, 0x1db4, 0x11d2, 0xbc, 0xac, 0x0, 0xa0, 0xc9, 0x22, 0xe6, 0xeb);
+DEFINE_GUID(GUID_EnableTempo, 0x45fc707e, 0x1db4, 0x11d2, 0xbc, 0xac, 0x0, 0xa0, 0xc9, 0x22, 0xe6, 0xeb);
+
+/* Used in SetParam calls for pattern-based tracks. A nonzero value seeds the random number
+generator for variation selection; a value of zero reverts to the default behavior of
+getting the seed from the system clock.
+*/
+DEFINE_GUID(GUID_SeedVariations, 0x65b76fa5, 0xff37, 0x11d2, 0x81, 0x4e, 0x0, 0xc0, 0x4f, 0xa3, 0x6e, 0x58);
+
+/* Used to get/set melody fragments (pParam points to a DMUS_MELODY_FRAGMENT) */
+/* Note: Melody formulation is not supported in DX8. */
+DEFINE_GUID(GUID_MelodyFragment, 0xb291c7f2, 0xb616, 0x11d2, 0x97, 0xfa, 0x0, 0xc0, 0x4f, 0xa3, 0x6e, 0x58);
+
+/* Used to clear all melody fragments */
+/* Note: Melody formulation is not supported in DX8. */
+DEFINE_GUID(GUID_Clear_All_MelodyFragments, 0x8509fee6, 0xb617, 0x11d2, 0x97, 0xfa, 0x0, 0xc0, 0x4f, 0xa3, 0x6e, 0x58);
+
+/* Used to get the variations currently in effect across PChannels */
+DEFINE_GUID(GUID_Variations, 0x11f72cce, 0x26e6, 0x4ecd, 0xaf, 0x2e, 0xd6, 0x68, 0xe6, 0x67, 0x7, 0xd8);
+typedef struct _DMUS_VARIATIONS_PARAM
+{
+ DWORD dwPChannelsUsed; /* number of PChannels in use */
+ DWORD* padwPChannels; /* array of PChannels in use */
+ DWORD* padwVariations; /* array of variations in effect for each PChannel */
+} DMUS_VARIATIONS_PARAM;
+
+/* Download bands/waves for the IDirectMusicSegment, passed an IDirectMusicAudioPath instead of an IDirectMusicPerformance */
+DEFINE_GUID(GUID_DownloadToAudioPath,0x9f2c0341, 0xc5c4, 0x11d3, 0x9b, 0xd1, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0);
+
+/* Unload bands/waves for the IDirectMusicSegment, passed an IDirectMusicAudioPath instead of an IDirectMusicPerformance */
+DEFINE_GUID(GUID_UnloadFromAudioPath,0x9f2c0342, 0xc5c4, 0x11d3, 0x9b, 0xd1, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0);
+
+
+/* Global data guids */
+DEFINE_GUID(GUID_PerfMasterTempo,0xd2ac28b0, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(GUID_PerfMasterVolume,0xd2ac28b1, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(GUID_PerfMasterGrooveLevel,0xd2ac28b2, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(GUID_PerfAutoDownload, 0xfb09565b, 0x3631, 0x11d2, 0xbc, 0xb8, 0x0, 0xa0, 0xc9, 0x22, 0xe6, 0xeb);
+
+/* GUID for default GM/GS dls collection. */
+DEFINE_GUID(GUID_DefaultGMCollection, 0xf17e8673, 0xc3b4, 0x11d1, 0x87, 0xb, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* GUID to define default synth, placed in AudioPath configuration file. */
+DEFINE_GUID(GUID_Synth_Default,0x26bb9432, 0x45fe, 0x48d3, 0xa3, 0x75, 0x24, 0x72, 0xc5, 0xe3, 0xe7, 0x86);
+
+/* GUIDs to define default buffer configurations to place in AudioPath configuration file. */
+DEFINE_GUID(GUID_Buffer_Reverb,0x186cc541, 0xdb29, 0x11d3, 0x9b, 0xd1, 0x0, 0x80, 0xc7, 0x15, 0xa, 0x74);
+DEFINE_GUID(GUID_Buffer_EnvReverb,0x186cc542, 0xdb29, 0x11d3, 0x9b, 0xd1, 0x0, 0x80, 0xc7, 0x15, 0xa, 0x74);
+DEFINE_GUID(GUID_Buffer_Stereo,0x186cc545, 0xdb29, 0x11d3, 0x9b, 0xd1, 0x0, 0x80, 0xc7, 0x15, 0xa, 0x74);
+DEFINE_GUID(GUID_Buffer_3D_Dry,0x186cc546, 0xdb29, 0x11d3, 0x9b, 0xd1, 0x0, 0x80, 0xc7, 0x15, 0xa, 0x74);
+DEFINE_GUID(GUID_Buffer_Mono,0x186cc547, 0xdb29, 0x11d3, 0x9b, 0xd1, 0x0, 0x80, 0xc7, 0x15, 0xa, 0x74);
+
+/* IID's */
+DEFINE_GUID(IID_IDirectMusicLoader, 0x2ffaaca2, 0x5dca, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6);
+DEFINE_GUID(IID_IDirectMusicGetLoader,0x68a04844, 0xd13d, 0x11d1, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6);
+DEFINE_GUID(IID_IDirectMusicObject,0xd2ac28b5, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(IID_IDirectMusicSegment, 0xf96029a2, 0x4282, 0x11d2, 0x87, 0x17, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(IID_IDirectMusicSegmentState, 0xa3afdcc7, 0xd3ee, 0x11d1, 0xbc, 0x8d, 0x0, 0xa0, 0xc9, 0x22, 0xe6, 0xeb);
+DEFINE_GUID(IID_IDirectMusicPerformance,0x7d43d03, 0x6523, 0x11d2, 0x87, 0x1d, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(IID_IDirectMusicGraph,0x2befc277, 0x5497, 0x11d2, 0xbc, 0xcb, 0x0, 0xa0, 0xc9, 0x22, 0xe6, 0xeb);
+DEFINE_GUID(IID_IDirectMusicStyle,0xd2ac28bd, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(IID_IDirectMusicChordMap,0xd2ac28be, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(IID_IDirectMusicComposer,0xd2ac28bf, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+DEFINE_GUID(IID_IDirectMusicBand,0xd2ac28c0, 0xb39b, 0x11d1, 0x87, 0x4, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* Alternate interface IDs, available in DX7 release and after. */
+DEFINE_GUID(IID_IDirectMusicPerformance2,0x6fc2cae0, 0xbc78, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6);
+DEFINE_GUID(IID_IDirectMusicSegment2, 0xd38894d1, 0xc052, 0x11d2, 0x87, 0x2f, 0x0, 0x60, 0x8, 0x93, 0xb1, 0xbd);
+
+/* Interface IDs for DX8 */
+/* changed interfaces (GUID only) */
+DEFINE_GUID(IID_IDirectMusicLoader8, 0x19e7c08c, 0xa44, 0x4e6a, 0xa1, 0x16, 0x59, 0x5a, 0x7c, 0xd5, 0xde, 0x8c);
+DEFINE_GUID(IID_IDirectMusicPerformance8, 0x679c4137, 0xc62e, 0x4147, 0xb2, 0xb4, 0x9d, 0x56, 0x9a, 0xcb, 0x25, 0x4c);
+DEFINE_GUID(IID_IDirectMusicSegment8,0xc6784488, 0x41a3, 0x418f, 0xaa, 0x15, 0xb3, 0x50, 0x93, 0xba, 0x42, 0xd4);
+DEFINE_GUID(IID_IDirectMusicSegmentState8, 0xa50e4730, 0xae4, 0x48a7, 0x98, 0x39, 0xbc, 0x4, 0xbf, 0xe0, 0x77, 0x72);
+DEFINE_GUID(IID_IDirectMusicStyle8, 0xfd24ad8a, 0xa260, 0x453d, 0xbf, 0x50, 0x6f, 0x93, 0x84, 0xf7, 0x9, 0x85);
+/* new interfaces (GUID + alias) */
+DEFINE_GUID(IID_IDirectMusicPatternTrack, 0x51c22e10, 0xb49f, 0x46fc, 0xbe, 0xc2, 0xe6, 0x28, 0x8f, 0xb9, 0xed, 0xe6);
+#define IID_IDirectMusicPatternTrack8 IID_IDirectMusicPatternTrack
+DEFINE_GUID(IID_IDirectMusicScript, 0x2252373a, 0x5814, 0x489b, 0x82, 0x9, 0x31, 0xfe, 0xde, 0xba, 0xf1, 0x37); /* {2252373A-5814-489b-8209-31FEDEBAF137} */
+#define IID_IDirectMusicScript8 IID_IDirectMusicScript
+DEFINE_GUID(IID_IDirectMusicContainer, 0x9301e386, 0x1f22, 0x11d3, 0x82, 0x26, 0xd2, 0xfa, 0x76, 0x25, 0x5d, 0x47);
+#define IID_IDirectMusicContainer8 IID_IDirectMusicContainer
+/* Note: Songs are not supported in DX8. */
+DEFINE_GUID(IID_IDirectMusicSong, 0xa862b2ec, 0x3676, 0x4982, 0x85, 0xa, 0x78, 0x42, 0x77, 0x5e, 0x1d, 0x86);
+#define IID_IDirectMusicSong8 IID_IDirectMusicSong
+DEFINE_GUID(IID_IDirectMusicAudioPath,0xc87631f5, 0x23be, 0x4986, 0x88, 0x36, 0x5, 0x83, 0x2f, 0xcc, 0x48, 0xf9);
+#define IID_IDirectMusicAudioPath8 IID_IDirectMusicAudioPath
+/* unchanged interfaces (alias only) */
+#define IID_IDirectMusicGetLoader8 IID_IDirectMusicGetLoader
+#define IID_IDirectMusicChordMap8 IID_IDirectMusicChordMap
+#define IID_IDirectMusicGraph8 IID_IDirectMusicGraph
+#define IID_IDirectMusicBand8 IID_IDirectMusicBand
+#define IID_IDirectMusicObject8 IID_IDirectMusicObject
+#define IID_IDirectMusicComposer8 IID_IDirectMusicComposer
+
+
+#ifdef __cplusplus
+}; /* extern "C" */
+#endif
+
+#include <poppack.h>
+
+#endif /* #ifndef _DMUSICI_ */
diff --git a/Src/Plugins/Input/in_midi/fakedsound.cpp b/Src/Plugins/Input/in_midi/fakedsound.cpp
new file mode 100644
index 00000000..4332f757
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/fakedsound.cpp
@@ -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;} \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/fakedsound.h b/Src/Plugins/Input/in_midi/fakedsound.h
new file mode 100644
index 00000000..800c0a58
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/fakedsound.h
@@ -0,0 +1,3 @@
+IDirectSoundBuffer* dhb_create(DWORD size,DWORD freq);
+
+IDirectSound * get_ds();
diff --git a/Src/Plugins/Input/in_midi/genres.c b/Src/Plugins/Input/in_midi/genres.c
new file mode 100644
index 00000000..c8add185
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/genres.c
@@ -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);
+}
diff --git a/Src/Plugins/Input/in_midi/genres.h b/Src/Plugins/Input/in_midi/genres.h
new file mode 100644
index 00000000..ceffb3dc
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/genres.h
@@ -0,0 +1,3 @@
+void genres_read(HWND wnd);
+void genres_write(HWND wnd);
+#define MAX_GENRE 256 \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/gmf.cpp b/Src/Plugins/Input/in_midi/gmf.cpp
new file mode 100644
index 00000000..0065e60f
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/gmf.cpp
@@ -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;
+}
diff --git a/Src/Plugins/Input/in_midi/guids.cpp b/Src/Plugins/Input/in_midi/guids.cpp
new file mode 100644
index 00000000..6f48b6eb
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/guids.cpp
@@ -0,0 +1,2 @@
+#define INITGUID
+#include "main.h" \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/hmi.cpp b/Src/Plugins/Input/in_midi/hmi.cpp
new file mode 100644
index 00000000..07b25523
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/hmi.cpp
@@ -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);
+} \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/hmp.cpp b/Src/Plugins/Input/in_midi/hmp.cpp
new file mode 100644
index 00000000..c6c869a7
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/hmp.cpp
@@ -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;
+}
diff --git a/Src/Plugins/Input/in_midi/in_midi.rc b/Src/Plugins/Input/in_midi/in_midi.rc
new file mode 100644
index 00000000..804d289e
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/in_midi.rc
@@ -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
+
diff --git a/Src/Plugins/Input/in_midi/in_midi.sln b/Src/Plugins/Input/in_midi/in_midi.sln
new file mode 100644
index 00000000..c440a567
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/in_midi.sln
@@ -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
diff --git a/Src/Plugins/Input/in_midi/in_midi.vcxproj b/Src/Plugins/Input/in_midi/in_midi.vcxproj
new file mode 100644
index 00000000..dbe34afc
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/in_midi.vcxproj
@@ -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> \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/in_midi.vcxproj.filters b/Src/Plugins/Input/in_midi/in_midi.vcxproj.filters
new file mode 100644
index 00000000..01be7416
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/in_midi.vcxproj.filters
@@ -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> \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/info.cpp b/Src/Plugins/Input/in_midi/info.cpp
new file mode 100644
index 00000000..6881d507
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/info.cpp
@@ -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
diff --git a/Src/Plugins/Input/in_midi/main.cpp b/Src/Plugins/Input/in_midi/main.cpp
new file mode 100644
index 00000000..b9012b56
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/main.cpp
@@ -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; \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/main.h b/Src/Plugins/Input/in_midi/main.h
new file mode 100644
index 00000000..ee73606e
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/main.h
@@ -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; \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/midi_driver.cpp b/Src/Plugins/Input/in_midi/midi_driver.cpp
new file mode 100644
index 00000000..1fd63d15
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/midi_driver.cpp
@@ -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;
+ }
+} \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/midifile.cpp b/Src/Plugins/Input/in_midi/midifile.cpp
new file mode 100644
index 00000000..b7bc7f0d
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/midifile.cpp
@@ -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;
+} \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/midifile.h b/Src/Plugins/Input/in_midi/midifile.h
new file mode 100644
index 00000000..af2b8a78
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/midifile.h
@@ -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 \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/midiinfo.cpp b/Src/Plugins/Input/in_midi/midiinfo.cpp
new file mode 100644
index 00000000..e14b0563
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/midiinfo.cpp
@@ -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;
+} \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/midiout_helper.cpp b/Src/Plugins/Input/in_midi/midiout_helper.cpp
new file mode 100644
index 00000000..ada2e3d8
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/midiout_helper.cpp
@@ -0,0 +1,2 @@
+#include "main.h"
+
diff --git a/Src/Plugins/Input/in_midi/mids.cpp b/Src/Plugins/Input/in_midi/mids.cpp
new file mode 100644
index 00000000..456da30f
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/mids.cpp
@@ -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;
+} \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/mus.cpp b/Src/Plugins/Input/in_midi/mus.cpp
new file mode 100644
index 00000000..18aeb4f4
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/mus.cpp
@@ -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);
+} \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/out_dmusic.cpp b/Src/Plugins/Input/in_midi/out_dmusic.cpp
new file mode 100644
index 00000000..51267141
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/out_dmusic.cpp
@@ -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; \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/out_midi.cpp b/Src/Plugins/Input/in_midi/out_midi.cpp
new file mode 100644
index 00000000..4308c292
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/out_midi.cpp
@@ -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;
+} \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/resource.h b/Src/Plugins/Input/in_midi/resource.h
new file mode 100644
index 00000000..ae56e0ee
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/resource.h
@@ -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
diff --git a/Src/Plugins/Input/in_midi/sampling.cpp b/Src/Plugins/Input/in_midi/sampling.cpp
new file mode 100644
index 00000000..06c34653
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/sampling.cpp
@@ -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;
+} \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/seq.cpp b/Src/Plugins/Input/in_midi/seq.cpp
new file mode 100644
index 00000000..f1fb65fb
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/seq.cpp
@@ -0,0 +1,852 @@
+#include "main.h"
+#include "seq.h"
+#include <commctrl.h>
+#include <math.h>
+#include "resource.h"
+
+#ifdef SEQ_HAVE_PANEL
+
+cfg_int cfg_seq_showpanel("seq_showpanel",0);
+
+enum
+{
+ ID_BASE = 0x6543,
+ MUTE_ID = ID_BASE,
+ VOL_ID = MUTE_ID+16,
+ INS_ID_P = VOL_ID+16,
+ INS_ID_B1 = INS_ID_P+16,
+ INS_ID_B2 = INS_ID_B1+16,
+ SPIN_ID = INS_ID_B2
+
+};
+
+static cfg_int cfg_ctrl_min("ctrl_min",0);
+
+
+static float g_tempo=1;
+static BOOL g_novol,g_noins;
+static char sysex1[256],sysex2[256];
+
+extern BYTE d_GMReset[6];
+extern BYTE d_XGReset[9];
+extern BYTE d_GSReset[11];
+#endif
+
+#define SEND_MSG(X) seq_shortmsg(preprocess(X))
+
+#define _sysex(A,B) seq_sysex(A,B)
+#define rsysex(A) seq_sysex(A,sizeof(A))
+
+#ifdef SEQ_HAVE_PANEL
+void seq_base::set_mute(UINT ch,BOOL st)
+{
+ if (st)
+ {
+ mute_mask|=1<<ch;
+ seq_shortmsg(0x07B0|ch);
+ }
+ else
+ {
+ mute_mask&=~(1<<ch);
+ SEND_MSG(((DWORD)ctrl_tab[ch][7]<<16)|0x07B0|ch);
+ }
+}
+#endif
+
+//debug hack
+#if 0
+#define timeGetTime timehack
+static DWORD timehack()
+{
+ static DWORD t;
+ return t++;
+}
+#endif
+
+DWORD seq_base::get_time()
+{
+#ifndef SEQ_HAVE_PANEL
+ return timeGetTime()<<3;
+#else
+ if (!hCtrl) return timeGetTime()<<3;//*8;
+ EnterCriticalSection(&tm_sec);
+ DWORD cur_t=timeGetTime();
+ if (!last_time_ms) last_time_ms=cur_t;
+ int d=cur_t-last_time_ms;
+ if (d<0) d=0;
+ last_time_ret+=(double)(d*8.0)*tempo;
+
+ last_time_ms=cur_t;
+ DWORD r=(DWORD)last_time_ret;
+ LeaveCriticalSection(&tm_sec);
+ return r;
+#endif
+}
+
+#ifdef SEQ_HAVE_PANEL
+BOOL CALLBACK seq_base::CtrlProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
+{
+ seq_base* s;
+ if (msg==WM_INITDIALOG)
+ {
+ SetWindowLongPtr(wnd,DWLP_USER,lp);
+ s=(seq_base*)lp;
+ if (s) s->hCtrl=wnd;
+ }
+ else
+ {
+#if defined(_WIN64)
+ s = (seq_base*)GetWindowLong(wnd, DWLP_USER);
+#else
+ s = (seq_base*)GetWindowLong(wnd, DWL_USER);
+#endif
+ }
+ if (s)
+ {
+ s->do_msg(msg,wp,lp);
+ }
+ return 0;
+}
+
+static float ui2tempo(int x)
+{
+ return (float)pow(4.0,0.02*(float)(x-50));
+}
+
+static int tempo2ui(float x)
+{
+ return 50+(int) ((50.0 / log(4.0)) * log(x) );
+}
+
+static void do_ttext(HWND w,float t)
+{
+ char tx[32] = {0};
+ _itoa((UINT)(t*100.0),tx,10);
+ char* p=tx;
+ while(p && *p) p++;
+ *(p++)='%';
+ *p=0;
+ SetDlgItemTextA(w,IDC_TDISP,tx);
+}
+
+BYTE* read_sysex_edit(HWND w,UINT *siz);
+
+void CreateControl(DWORD ex,HWND hCtrl,const char * cls,const char * name,DWORD style,UINT x,UINT y,UINT dx,UINT dy,HINSTANCE hDll,UINT id)
+{
+ RECT r={(LONG)x,(LONG)y,(LONG)(x+dx),(LONG)(y+dy)};
+ MapDialogRect(hCtrl,&r);
+ HWND w = CreateWindowExA( ex, cls, name, WS_CHILD | WS_VISIBLE | style, r.left, r.top, r.right - r.left, r.bottom - r.top, hCtrl, 0, hDll, 0 ); // Must stay in ANSI
+ if (w)
+ {
+ if (id) SetWindowLong(w,GWL_ID,id);
+ SendMessage(w,WM_SETFONT,SendMessage(hCtrl,WM_GETFONT,0,0),MAKELONG(0,0));
+ }
+}
+
+static cfg_int cfg_ctrl_x("ctrl_x",0x80000000),cfg_ctrl_y("ctrl_y",0x80000000);
+
+void seq_base::do_msg(UINT msg,WPARAM wp,LPARAM lp)
+{
+ switch(msg)
+ {
+ case WM_CLOSE:
+ ShowWindow(hCtrl,SW_SHOWMINIMIZED);
+ break;
+ case WM_INITDIALOG:
+ {
+ HINSTANCE hCCdll=GetModuleHandle(TEXT("comctl32.dll"));
+ UINT n;
+ HWND w;
+ for(n=0;n<16;n++)
+ {
+ char tmp[16] = {0};
+ itoa(n,tmp,10);
+ CreateControl(0,hCtrl,TRACKBAR_CLASSA,0,TBS_VERT | TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,40+n*28,36,18,80,hCCdll,VOL_ID+n);
+ CreateControl(0,hCtrl,"STATIC",tmp,0,46+n*28,25,8,8,0,0);
+ CreateControl(0,hCtrl,"Button",0,BS_AUTOCHECKBOX | WS_TABSTOP,43+28*n,120,9,8,0,MUTE_ID+n);
+ CreateControl(WS_EX_CLIENTEDGE,hCtrl,"EDIT",0,ES_AUTOHSCROLL | ES_NUMBER,36+28*n,138,26,12,0,INS_ID_P+n);
+ CreateControl(0,hCtrl,"msctls_updown32",0,UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,0,0,0,0,0,SPIN_ID+n);
+ CreateControl(WS_EX_CLIENTEDGE,hCtrl,"EDIT",0,ES_AUTOHSCROLL | ES_NUMBER,36+28*n,150,26,12,0,INS_ID_B1+n);
+ CreateControl(0,hCtrl,"msctls_updown32",0,UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,0,0,0,0,0,SPIN_ID+n+16);
+ CreateControl(WS_EX_CLIENTEDGE,hCtrl,"EDIT",0,ES_AUTOHSCROLL | ES_NUMBER,36+28*n,162,26,12,0,INS_ID_B2+n);
+ CreateControl(0,hCtrl,"msctls_updown32",0,UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,0,0,0,0,0,SPIN_ID+n+32);
+ }
+
+ w=GetDlgItem(hCtrl,IDC_TEMPO);
+ SendMessage(w,TBM_SETRANGE,0,MAKELONG(0,100));
+ SendMessage(w,TBM_SETPOS,1,tempo2ui(tempo));
+ do_ttext(hCtrl,tempo);
+ if (cfg_ctrl_x!=0x80000000 && cfg_ctrl_y!=0x80000000)
+ {
+ int max_x=GetSystemMetrics(SM_CXSCREEN)-10,max_y=GetSystemMetrics(SM_CYSCREEN)-10;
+ if (cfg_ctrl_x>max_x) cfg_ctrl_x=max_x;
+ if (cfg_ctrl_y>max_y) cfg_ctrl_y=max_y;
+ SetWindowPos(hCtrl,0,cfg_ctrl_x,cfg_ctrl_y,0,0,SWP_NOZORDER|SWP_NOSIZE);
+ }
+ for(n=0;n<16;n++)
+ {
+ w=GetDlgItem(hCtrl,VOL_ID+n);
+ SendMessage(w,TBM_SETRANGE,1,MAKELONG(0,0x7f));
+ SendMessage(w,TBM_SETPOS,1,0x7f-90);
+ }
+ SendDlgItemMessage(hCtrl,IDC_NOVOL,BM_SETCHECK,novol,0);
+ SetDlgItemTextA(hCtrl,IDC_SYSEX1,sysex1);
+ SetDlgItemTextA(hCtrl,IDC_SYSEX2,sysex2);
+ for(n=0;n<48;n++)
+ {
+ SendDlgItemMessage(hCtrl,SPIN_ID+n,UDM_SETRANGE,0,MAKELONG(127,0));
+ }
+ for(n=0;n<16;n++)
+ {
+ SendDlgItemMessage(hCtrl,INS_ID_P+n,EM_LIMITTEXT,3,0);
+ SendDlgItemMessage(hCtrl,INS_ID_B1+n,EM_LIMITTEXT,3,0);
+ SendDlgItemMessage(hCtrl,INS_ID_B2+n,EM_LIMITTEXT,3,0);
+ }
+ initialized=1;
+ }
+ break;
+ case WM_COMMAND:
+ {
+ UINT n;
+ if (HIWORD(wp)==0)
+ {
+ if (wp==IDC_SYSEX1_SEND || wp==IDC_SYSEX2_SEND)
+ {
+ UINT sl;
+ BYTE* s=read_sysex_edit(GetDlgItem(hCtrl,(wp==IDC_SYSEX1_SEND)?IDC_SYSEX1:IDC_SYSEX2) , &sl);
+ if (s)
+ {
+ _sysex(s,sl);
+ free(s);
+ }
+ }
+ else if (wp==IDC_NOVOL)
+ {
+ novol=SendMessage((HWND)lp,BM_GETCHECK,0,0);
+ }
+ else if (wp==IDC_NOINS)
+ {
+ noins=SendMessage((HWND)lp,BM_GETCHECK,0,0);
+ }
+ else if (wp==IDC_ALL_ON)
+ {
+ UINT n;
+ for(n=0;n<16;n++)
+ {
+ if (mute_mask&(1<<n))
+ {
+ SendDlgItemMessage(hCtrl,MUTE_ID+n,BM_SETCHECK,0,0);
+ set_mute(n,0);
+ }
+ }
+ }
+ else if (wp==IDC_ALL_OFF)
+ {
+ UINT n;
+ for(n=0;n<16;n++)
+ {
+ if (!(mute_mask&(1<<n)))
+ {
+ SendDlgItemMessage(hCtrl,MUTE_ID+n,BM_SETCHECK,1,0);
+ set_mute(n,1);
+ }
+ }
+ }
+ else if (wp==IDC_GMRESET)
+ {
+ rsysex(d_GMReset);
+ }
+ else if (wp==IDC_GSRESET)
+ {
+ rsysex(d_GSReset);
+ }
+ else if (wp==IDC_XGRESET)
+ {
+ rsysex(d_XGReset);
+ }
+ else for(n=0;n<16;n++)
+ {
+ if (wp==MUTE_ID+n)
+ {
+ set_mute(n,SendMessage((HWND)lp,BM_GETCHECK,0,0));
+ break;
+ }
+ }
+ }
+ else if (HIWORD(wp)==EN_CHANGE)
+ {
+ if (initialized)
+ {
+ wp&=0xFFFF;
+ UINT n;
+ for(n=0;n<16;n++)
+ {
+ if (wp==INS_ID_P+n)
+ {
+ UINT p=GetDlgItemInt(hCtrl,wp,0,0)&0x7F;
+ if (p!=ins_tab[n])
+ {
+ ins_tab[n]=p;
+ SEND_MSG(0xC0|n|(p<<8));
+ }
+ break;
+ }
+ else if (wp==INS_ID_B1+n)
+ {
+ UINT p=GetDlgItemInt(hCtrl,wp,0,0)&0x7F;
+ if (p!=ctrl_tab[n][0])
+ {
+ ctrl_tab[n][0]=p;
+ SEND_MSG(0xB0|n|(p<<16));
+ SEND_MSG(0xC0|n|(ins_tab[n]<<8));
+ }
+ break;
+ }
+ else if (wp==INS_ID_B2+n)
+ {
+ UINT p=GetDlgItemInt(hCtrl,wp,0,0)&0x7F;
+ if (p!=ctrl_tab[n][0x20])
+ {
+ ctrl_tab[n][0x20]=p;
+ SEND_MSG(0x20B0|n|(p<<16));
+ SEND_MSG(0xC0|n|(ins_tab[n]<<8));
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ }
+ break;
+ case WM_VSCROLL:
+ {
+ HWND sb=(HWND)lp;
+ if (sb)
+ {
+ UINT id=GetWindowLong(sb,GWL_ID);
+ UINT n;
+ for(n=0;n<16;n++)
+ {
+ if (id==VOL_ID+n)
+ {
+ UINT val=0x7f-SendMessage(sb,TBM_GETPOS,0,0);
+ ctrl_tab[n][7]=val;
+ SEND_MSG(0x7B0|n|(val<<16));
+ break;
+ }
+
+ }
+ }
+ }
+ break;
+ case WM_HSCROLL:
+ tempo=ui2tempo(SendDlgItemMessage(hCtrl,IDC_TEMPO,TBM_GETPOS,0,0));
+ do_ttext(hCtrl,tempo);
+ break;
+ }
+}
+#endif
+
+seq_base::~seq_base()
+{
+#ifdef SEQ_HAVE_PANEL
+ if (hCtrl)
+ {
+ cfg_ctrl_min=!!IsIconic(hCtrl);
+ RECT r;
+ GetWindowRect(hCtrl,&r);
+ cfg_ctrl_x=r.left;
+ cfg_ctrl_y=r.top;
+ GetDlgItemTextA(hCtrl,IDC_SYSEX1,sysex1,256);
+ GetDlgItemTextA(hCtrl,IDC_SYSEX2,sysex2,256);
+ DestroyWindow(hCtrl);
+ DeleteCriticalSection(&tm_sec);
+ }
+ g_tempo=tempo;
+ g_novol=novol;
+ g_noins=noins;
+#endif
+ if (events) free(events);
+}
+
+seq_base::seq_base()
+{
+ mf=0;
+
+ kill=0;paused=0;
+ smap=0;
+
+ pan=0;vol=0;
+
+ seek_to=0;
+ n_events=0;
+ events=0;
+
+ c_loop=0;
+ loop_start=0;
+ memset(&notes,0,sizeof(notes));
+ memset(&ctrl_tab,0,sizeof(ctrl_tab));
+ memset(&ins_tab,0,sizeof(ins_tab));
+
+ tm_ofs=0;
+ p_time=0;
+ hTrd=0;
+
+ ins_set=0;
+
+#ifdef SEQ_HAVE_PANEL
+ hCtrl=0;
+
+ tempo=g_tempo;
+ novol=g_novol;
+ noins=g_noins;
+
+ last_time_ms=0;
+ last_time_ret=0;
+
+ mute_mask=0;
+ initialized=0;
+#endif
+}
+
+
+#define GET_TIME get_time()//timeGetTime()
+
+int IS_SPEC_C(int x) {return (x>=0x60 && x<=0x65) || x==6 || x==26 || x>=120;}
+
+#define n_sysex smap->pos
+
+
+DWORD seq_base::preprocess(DWORD e)
+{
+ BYTE t=(BYTE)(e&0xF0);
+ if (t==0xB0)
+ {
+ UINT v=(e>>16)&0xFF;
+ BYTE c=(BYTE)(e>>8);
+#ifdef SEQ_HAVE_PANEL
+ if (c==7)
+ {
+ if (mute_mask&(1<<(e&0xF))) v=0;
+ }
+#endif
+ e=(e&0xFFFF)|((v&0xFF)<<16);
+ }
+ else if (t==0xC0)
+ {
+ ins_set|=1<<(e&0xF);
+ }
+ return e;
+}
+
+void seq_base::send_sysex(int n)
+{
+#ifdef USE_LOG
+ log_write("send_sysex()");
+#endif
+ if (!smap || n>=n_sysex) return;
+ _sysex(smap->data+smap->events[n].ofs,smap->events[n].len);
+}
+
+/*
+void seq_base::reset_ins()
+{
+ UINT n;
+ for(n=0;n<16;n++)
+ {
+ cb->shortmsg(0xC0|n);
+ }
+}
+*/
+
+BOOL seq_base::do_ctrl(DWORD e)
+{
+ BYTE tp=(BYTE)(e&0xF0);
+ BYTE ch=(BYTE)(e&0x0F);
+ if (tp==0xC0)
+ {
+#ifdef SEQ_HAVE_PANEL
+ if (noins) return 0;
+#endif
+ //if (!cfg_fctrl && (e>>8)==ins_tab[e&0xF]) return 0;
+ UINT val=e>>8;
+ ins_tab[ch]=val;
+#ifdef SEQ_HAVE_PANEL
+ if (hCtrl) SetDlgItemInt(hCtrl,INS_ID_P+ch,val,0);
+#endif
+ } else if (tp==0xB0)
+ {
+ UINT cn = (e>>8)&0x7F;
+ UINT val= (e>>16)&0x7F;
+#ifdef SEQ_HAVE_PANEL
+ if (cn==0)
+ {
+ if (noins) return 0;
+ if (hCtrl) SetDlgItemInt(hCtrl,INS_ID_B1+ch,val,0);
+ }
+ else if (cn==0x20)
+ {
+ if (noins) return 0;
+ if (hCtrl) SetDlgItemInt(hCtrl,INS_ID_B2+ch,val,0);
+ }
+ else if (cn==7)
+ {
+ if (novol) return 0;
+ if (hCtrl) PostMessage(GetDlgItem(hCtrl,VOL_ID+(e&0xF)),TBM_SETPOS,1,0x7F-val);
+ }
+ else if (cn==0x27)
+ {
+ if (novol) return 0;
+ }
+#endif
+ if (!IS_SPEC_C(cn)) ctrl_tab[e&0xF][cn]=val;
+ }
+ else if (tp==0x90)
+ {
+ if (!(ins_set&(1<<ch)))
+ {
+ SEND_MSG(0xC0|ch);
+ }
+ }
+ return 1;
+}
+
+void seq_base::reset()
+{
+ int not,ch;
+ for(ch=0;ch<16;ch++)
+ {
+ if (ctrl_tab[ch][0x40])
+ {
+ seq_shortmsg(0x40B0|ch);
+ ctrl_tab[ch][0x40]=0;
+ }
+ if (ch==9) continue;
+ for(not=0;not<128;not++)
+ {
+ if (note_state(ch,not))
+ {
+ seq_shortmsg((not<<8)|0x80|ch);
+ note_off(ch,not);
+ }
+ }
+ }
+}
+
+
+int seq_base::note_state(int ch,int note)
+{
+ UINT pos=(ch<<7)+note;
+ return notes[pos>>3]&(1<<(pos&0x7));
+}
+
+void seq_base::note_on(int ch,int note)
+{
+ UINT pos=(ch<<7)+note;
+ notes[pos>>3]|=(1<<(pos&0x7));
+}
+
+void seq_base::note_off(int ch,int note)
+{
+ UINT pos=(ch<<7)+note;
+ notes[pos>>3]&=~(1<<(pos&0x7));
+}
+
+UINT seq_base::do_seek(DWORD n,DWORD p)
+{
+ UINT m,c;
+ BYTE _ctrl_tab[16][128] = {0};
+ BYTE _ins_tab[16] = {0};
+ memcpy(_ctrl_tab,ctrl_tab,sizeof(_ctrl_tab));
+ memcpy(_ins_tab,ins_tab,sizeof(_ins_tab));
+
+ if (n==0)
+ {
+ memset(ins_tab,0,sizeof(ins_tab));
+ for(m=0;m<16;m++)
+ {
+ _ctrl_tab[m][0]=_ctrl_tab[m][0x20]=0;
+ }
+ }
+
+ while(n<n_events && p>events[n].tm)
+ {
+ DWORD e=events[n].ev;
+ if (!(e&0x80000000))
+ {
+ if (do_ctrl(e))
+ {
+ if (((e&0xF0)==0xB0) && IS_SPEC_C((e>>8)&0xFF))
+ {
+ seq_shortmsg(e);
+ }
+ }
+ }
+ n++;
+ }
+ for(c=0;c<16;c++)
+ {
+ for(m=0;m<128;m++)
+ {
+ if (!IS_SPEC_C(m) && _ctrl_tab[c][m]!=ctrl_tab[c][m])
+ {
+ SEND_MSG(((DWORD)ctrl_tab[c][m]<<16)|(m<<8)|0xB0|c);
+ }
+ }
+ if (_ins_tab[c]!=ins_tab[c])
+ {
+ SEND_MSG(((DWORD)ins_tab[c]<<8)|0xC0|c);
+ }
+ }
+ return n;
+}
+
+DWORD WINAPI seq_base::seq_trd(void* p)
+{
+ ((seq_base*)p)->thread();
+ return 0;
+}
+
+void seq_base::sysexfunc(seq_base* cb,BYTE* s,UINT sz)
+{
+ cb->seq_sysex(s,sz);
+}
+
+void seq_base::thread()
+{
+ tm_ofs=-1;
+ if (seq_play_start())
+ {
+
+ sysex_startup((SYSEXFUNC)sysexfunc,this);
+
+ tm_ofs=GET_TIME;
+ DWORD pos=0;
+ while(!kill)
+ {
+ DWORD c_t=GET_TIME-tm_ofs;
+ if (paused)
+ {
+ reset();
+ while(paused && !kill) MIDI_callback::Idle();
+ if (kill) break;
+ tm_ofs=GET_TIME-c_t;
+ }
+
+ if (seek_to!=-1)
+ {
+_seek:
+ DWORD _p=seek_to > c_t ? pos : 0;
+ c_t=seek_to;
+ seek_to=-1;
+ tm_ofs=GET_TIME-c_t;
+ reset();
+ pos=c_t ? do_seek(_p,c_t) : 0;
+ }
+ if (events[pos].tm+1600 < c_t)
+ {
+ reset();
+ pos=do_seek(pos,c_t);
+ }
+ while(pos<n_events && events[pos].tm<=c_t && !kill)
+ {
+ DWORD e=events[pos++].ev;
+ if (e)
+ {
+ if (e&0x80000000)
+ {
+ send_sysex(e&0x7FFFFFFF);
+ }
+ else
+ {
+ if ((e&0xF0)==0x90)
+ {
+ note_on(e&0xf,(e>>8)&0xFF);
+ }
+ else if ((e&0xF0)==0x80)
+ {
+ note_off(e&0xf,(e>>8)&0xFF);
+ }
+ if (do_ctrl(e))
+ SEND_MSG(e);
+ }
+ }
+ }
+
+ if (pos>=n_events || c_t >= events[n_events-1].tm)
+ {
+ if (loop_start!=-1 && (--c_loop))
+ {
+ c_t=loop_start;
+ tm_ofs=GET_TIME-c_t;
+ pos=do_seek(0,c_t);
+ continue;
+ }
+ if (cfg_eof_delay)
+ {
+ DWORD t=timeGetTime();
+ do
+ {
+ MIDI_callback::Idle();
+ } while(!kill && seek_to==-1 && t+cfg_eof_delay>timeGetTime());
+ if (seek_to!=-1) {
+ pos=0;
+ goto _seek;
+ }
+ }
+ if (!kill) MIDI_core::Eof();
+ break;
+ }
+ if (kill) break;
+
+ MIDI_callback::Idle();
+ }
+ reset();
+ }
+ seq_play_stop();
+}
+
+int seq_base::gettime()
+{
+ if (paused)
+ return (seek_to==-1) ? seek_to>>3 : p_time;
+ else
+ return (GET_TIME-tm_ofs)>>3;
+}
+
+int seq_base::settime(int tm)
+{
+ seek_to=tm<<3;
+ return 1;
+}
+
+
+void seq_base::pause()
+{
+ paused=1;
+ p_time=GET_TIME-tm_ofs;
+}
+
+void seq_base::unpause()
+{
+ paused=0;
+}
+
+int seq_base::seq_cmd_start(DWORD cflags)
+{
+ mf=MIDI_core::getFile();
+#ifdef SEQ_HAVE_PANEL
+ mute_mask=0;
+#endif
+ c_loop=cfg_loop_infinite ? -1 : cfg_loop_count;
+ memset(notes,0,sizeof(notes));
+ memset(ctrl_tab,-1,sizeof(ctrl_tab));
+ memset(ins_tab,0,sizeof(ins_tab));
+
+ UINT n;
+ for(n=0;n<16;n++) ctrl_tab[n][7]=90;
+
+ events=do_table(mf,8,&n_events,&loop_start,cflags);
+ if (!events) return 0;
+
+ if (!cfg_nosysex && mf->smap && mf->smap->pos)
+ {
+ smap=mf->smap;
+ }
+ else smap=0;
+
+ kill=0;
+ seek_to=-1;
+ paused=0;
+
+#ifdef SEQ_HAVE_PANEL
+ if (cfg_seq_showpanel)
+ {
+ InitializeCriticalSection(&tm_sec);
+ WASABI_API_CREATEDIALOGPARAMW(IDD_EXT_IMM, MIDI_callback::GetMainWindow(), CtrlProc, (LPARAM)this);
+ ShowWindow(hCtrl,cfg_ctrl_min ? SW_SHOWMINIMIZED : SW_SHOW);
+ }
+ else
+ {
+ tempo=1;
+ novol=0;
+ noins=0;
+ }
+#endif
+
+ DWORD id;
+ hTrd=CreateThread(0,0,seq_trd,this,CREATE_SUSPENDED,&id);
+#ifndef _DEBUG
+ SetThreadPriority(hTrd,THREAD_PRIORITY_TIME_CRITICAL);
+#endif
+ ResumeThread(hTrd);
+ return 1;
+}
+
+void seq_base::seq_cmd_stop()
+{
+#ifdef USE_LOG
+ log_write("stopping sequencer");
+#endif
+ if (hTrd)
+ {
+#ifdef USE_LOG
+ log_write("killing thread");
+#endif
+ kill=1;
+ if (WaitForSingleObject(hTrd,4000)!=WAIT_OBJECT_0)
+ {
+#ifdef USE_LOG
+ log_write("unable to kill thread");
+#endif
+ TerminateThread(hTrd,0);
+ }
+#ifdef USE_LOG
+ else log_write("thread killed normally");
+#endif
+ CloseHandle(hTrd);
+ }
+}
+/*
+void seq_base::enum_ins()
+{
+ DWORD ttab[256];
+ memset(ttab,-1,sizeof(ttab));
+ UINT tpt=0;
+ UINT n;
+ DWORD c_ins[16];
+ memset(c_ins,0,sizeof(c_ins));
+ c_ins[9]=0x80000000;
+ for(n=0;n<n_events;n++)
+ {
+ DWORD t=events[n].ev;
+ if (t&0xFF000000) continue;
+ UINT c=t&0xF0;
+ UINT ch=events[n].ev&0xF;
+ if ((t&0xFFF0)==0x20B0)
+ {
+ c_ins[ch]=(c_ins[ch]&0xFFFF00FF)|((t>>8)&0xFF00);
+ }
+ else if ((t&0xFFF0)==0xB0)
+ {
+ c_ins[ch]=(c_ins[ch]&0xFF00FFFF)|(t&0xFF0000);
+ }
+ else if ((t&0xF0)==0xC0)
+ {
+ c_ins[ch]=(c_ins[ch]&0xFFFFFF00)|((t>>8)&0xFF);
+ }
+ else if ((t&0xF0)==0x90)
+ {
+ UINT n;
+ for(n=0;n<256;n++)
+ {
+ if (ttab[n]==c_ins[ch]) goto ok;
+ }
+ cb->enum_ins(ttab[tpt]=c_ins[ch]);
+ tpt=(tpt+1)&0xFF;
+ok:;
+ }
+ }
+}
+*/
diff --git a/Src/Plugins/Input/in_midi/seq.h b/Src/Plugins/Input/in_midi/seq.h
new file mode 100644
index 00000000..eefc5b6f
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/seq.h
@@ -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
+};
diff --git a/Src/Plugins/Input/in_midi/utils.cpp b/Src/Plugins/Input/in_midi/utils.cpp
new file mode 100644
index 00000000..c76d49f0
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/utils.cpp
@@ -0,0 +1,1064 @@
+#include "main.h"
+#include "../Agave/language/api_language.h"
+#include <commdlg.h>
+#include "resource.h"
+
+DWORD _fastcall rev32(DWORD d) {return _rv(d);}
+
+void CPipe::WriteData(void* b,UINT s)
+{
+ if (closed) return;
+ sec.enter();
+ if (buf_n+s>buf_s)
+ {
+#ifdef USE_LOG
+ log_write("buffer overflow");
+#endif
+ s=buf_s-buf_n;
+ s-=s%align;
+ }
+ if (s)
+ {
+ if (buf_wp+s<buf_s)
+ {
+ memcpy(buf+buf_wp,b,s);
+ buf_wp+=s;
+ }
+ else
+ {
+ UINT d=buf_s-buf_wp;
+ memcpy(buf+buf_wp,b,d);
+ memcpy(buf,(BYTE*)b+d,s-d);
+ buf_wp=s-d;
+ }
+ buf_n+=s;
+ }
+ sec.leave();
+}
+
+UINT CPipe::ReadData(void* _b,UINT s,bool* ks)
+{
+ UINT rv=0;
+ BYTE * b=(BYTE*)_b;
+ sec.enter();
+ while(1)
+ {
+ UINT d=s;
+ if (d>buf_n) d=buf_n;
+ if (d)
+ {
+ if (buf_rp+d<buf_s)
+ {
+ memcpy(b,buf+buf_rp,d);
+ buf_rp+=d;
+ }
+ else
+ {
+ UINT d1=buf_s-buf_rp;
+ memcpy(b,buf+buf_rp,d1);
+ memcpy(b+d1,buf,d-d1);
+ buf_rp=d-d1;
+ }
+ buf_n-=d;
+ s-=d;
+ rv+=d;
+ b+=d;
+ }
+ if (closed || !s || *ks) break;
+ sec.leave();
+ MIDI_callback::Idle();
+ sec.enter();
+ }
+ sec.leave();
+ return rv;
+}
+
+#ifdef USE_LOG
+static HANDLE hLog;
+void log_start()
+{
+ hLog=CreateFile("c:\\in_midi.log",GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_ALWAYS,0,0);
+ SetFilePointer(hLog,0,0,FILE_END);
+ log_write("opening log");
+}
+
+void log_quit() {log_write("closing log");log_write("");log_write("");CloseHandle(hLog);}
+
+void log_write(char* t)
+{
+ DWORD bw;
+ WriteFile(hLog,t,strlen(t),&bw,0);
+ char _t[2]={13,10};
+ WriteFile(hLog,_t,2,&bw,0);
+ FlushFileBuffers(hLog);
+}
+#endif
+
+
+
+
+
+
+
+
+
+
+//tempo map object
+
+CTempoMap* tmap_create()
+{
+ CTempoMap* m=new CTempoMap;
+ if (m)
+ {
+ m->pos=0;
+ m->size=0x100;
+ m->data=(TMAP_ENTRY*)malloc(m->size*sizeof(TMAP_ENTRY));
+ }
+ return m;
+}
+
+void CTempoMap::AddEntry(int _p,int tm)
+{
+ if (!data) {pos=size=0;return;}
+ if (pos && _p<=data[pos-1].pos) {data[pos-1].tm=tm;return;}
+ if (pos==size)
+ {
+ size*=2;
+ data=(TMAP_ENTRY*)realloc(data,size*sizeof(TMAP_ENTRY));
+ if (!data) {pos=0;return;}
+ }
+ data[pos].pos=_p;
+ data[pos].tm=tm;
+ pos++;
+}
+
+int ReadSysex(const BYTE* src,int ml)
+{
+ int r=1;
+ while(r<ml)
+ {
+ r++;
+ if (src[r]==0xF7) return r+1;
+ }
+ unsigned int d;
+ r=1+DecodeDelta(src+1,&d);
+ r+=d;
+ return r;
+}
+
+unsigned int DecodeDelta(const BYTE* src,unsigned int* _d, unsigned int limit)
+{
+ unsigned int l=0;
+ unsigned int d=0;
+ BYTE b;
+ do
+ {
+ if (l >= limit)
+ {
+ *_d=0;
+ return l;
+ }
+ b=src[l++];
+ d=(d<<7)|(b&0x7F);
+ } while(b&0x80);
+ *_d=d;
+ return l;
+}
+
+int EncodeDelta(BYTE* dst,int d)
+{
+ if (d==0)
+ {
+ dst[0]=0;
+ return 1;
+ }
+ else
+ {
+ int r=0;
+ int n=1;
+ unsigned int temp=d;
+ while (temp >>= 7)
+ {
+ n++;
+ }
+
+ do {
+ n--;
+ BYTE b=(BYTE)((d>>(7*n))&0x7F);
+ if (n) b|=0x80;
+ dst[r++]=b;
+ } while(n);
+ return r;
+ }
+}
+
+int CTempoMap::BuildTrack(grow_buf & out)
+{
+ if (!pos) return 0;
+ int start=out.get_size();
+ //BYTE* trk=(BYTE*)malloc(8+4+pos*10);
+ //if (!trk) return 0;
+ out.write_dword(_rv('MTrk'));
+ out.write_dword(0);//track size
+ DWORD ct=0;
+ int n;
+ BYTE t_event[6]={0xFF,0x51,0x03,0,0,0};
+ for(n=0;n<pos;n++)
+ {
+ DWORD t=data[n].pos;
+ gb_write_delta(out,t-ct);
+ ct=t;
+ t=data[n].tm;
+ t_event[3]=(BYTE)(t>>16);
+ t_event[4]=(BYTE)(t>>8);
+ t_event[5]=(BYTE)(t);
+ out.write(t_event,6);
+ }
+ out.write_dword(0x002FFF00);
+ out.write_dword_ptr(rev32(out.get_size()-(start+8)),start+4);
+ return 1;
+}
+
+//sysex map management
+
+void CSysexMap::AddEvent(const BYTE* e,DWORD s,DWORD t)
+{
+ if (!data || !events) return;
+ DWORD np=pos+1;
+ if (np>=e_size)
+ {
+ do {
+ e_size<<=1;
+ } while(np>=e_size);
+ events=(SYSEX_ENTRY*)realloc(events,e_size*sizeof(SYSEX_ENTRY));
+ if (!events) return;
+ }
+ DWORD nd=d_pos+s;
+ if (nd>=d_size)
+ {
+ do {
+ d_size<<=1;
+ } while(nd>=d_size);
+ data=(BYTE*)realloc(data,d_size);
+ if (!data) return;
+ }
+ data[d_pos]=0xF0;
+ unsigned int x;
+ unsigned int sp=DecodeDelta(e+1,&x);
+ if (sp >= s)
+ return;
+ memcpy(data+d_pos+1,e+1+sp,s-1-sp);
+ events[pos].pos=t;
+ events[pos].ofs=d_pos;
+ events[pos].len=s-sp;
+ d_pos=nd-sp;
+ pos++;
+}
+
+CSysexMap* smap_create()
+{
+ CSysexMap* s=new CSysexMap;
+ if (s)
+ {
+ s->e_size=0x10;
+ s->d_size=0x40;
+ s->events=(SYSEX_ENTRY*)malloc(sizeof(SYSEX_ENTRY)*s->e_size);
+ s->data=(BYTE*)malloc(s->d_size);
+ s->d_pos=s->pos=0;
+ }
+ return s;
+}
+
+
+CSysexMap::~CSysexMap()
+{
+ if (data) free(data);
+ if (events) free(events);
+}
+
+BYTE d_GMReset[6]={0xF0,0x7E,0x7F,0x09,0x01,0xF7};
+BYTE d_XGReset[9]={0xf0,0x43,0x10,0x4c,0x00,0x00,0x7e,0x00,0xf7};
+BYTE d_GSReset[11]={0xF0,0x41,0x10,0x42,0x12,0x40,0x00,0x7F,0x00,0x41,0xF7};
+
+CSysexMap* CSysexMap::Translate(MIDI_file * mf)
+{
+ CTempoMap* tmap=mf->tmap;
+ if (!events || !data || !tmap) return 0;
+ CSysexMap* nm=smap_create();
+ if (!nm) return 0;
+ nm->d_size=d_size;
+ nm->d_pos=d_pos;
+ nm->data=(BYTE*)realloc(nm->data,nm->d_size);
+ if (!nm->data) {delete nm;return 0;}
+ memcpy(nm->data,data,d_pos);
+ nm->e_size=e_size;
+ nm->pos=pos;
+ nm->events=(SYSEX_ENTRY*)realloc(nm->events,sizeof(SYSEX_ENTRY)*nm->e_size);
+ if (!nm->events) {delete nm;return 0;}
+
+ int pos_ms=0;
+ int n=0;
+ int cur_temp=0;
+ int ntm=tmap->pos,t_pos=0;
+ int p_t=0;
+ int dtx = rev16(*(WORD*)(mf->data+12))*1000;
+ int pos_tx=0;
+
+ while(n<pos)
+ {
+ pos_tx=events[n].pos;
+ int d=pos_tx-p_t;
+ p_t=pos_tx;
+ while(t_pos<ntm && pos_tx+d>=tmap->data[t_pos].pos)
+ {
+ DWORD d1=tmap->data[t_pos].pos-pos_tx;
+ pos_ms+=MulDiv(cur_temp,d1<<8,dtx);
+ cur_temp=tmap->data[t_pos].tm;
+ t_pos++;
+ pos_tx+=d1;
+ d-=d1;
+ }
+ pos_ms+=MulDiv(cur_temp,d<<8,dtx);
+ pos_tx+=d;
+
+ nm->events[n].pos=pos_ms>>8;
+ nm->events[n].ofs=events[n].ofs;
+ nm->events[n].len=events[n].len;
+ n++;
+ }
+ return nm;
+}
+
+int CSysexMap::BuildTrack(grow_buf & out)
+{
+ if (!pos) return 0;
+
+ int start=out.get_size();
+ out.write_dword(_rv('MTrk'));
+ out.write_dword(0);
+
+ int ct=0;
+ int n;
+ for(n=0;n<pos;n++)
+ {
+ DWORD t=events[n].pos;
+ gb_write_delta(out,t-ct);
+ ct=t;
+ out.write_byte(0xF0);
+ gb_write_delta(out,events[n].len-1);
+ out.write(data+events[n].ofs+1,events[n].len-1);
+ }
+ out.write_dword(0x002FFF00);
+ out.write_dword_ptr(rev32(out.get_size()-(start+8)),start+4);
+ return 1;
+}
+
+const char* CSysexMap::GetType()
+{
+ int ret=0;
+ int n;
+ for(n=0;n<pos;n++)
+ {
+ ret=data[events[n].ofs+1];
+ if (ret!=0x7E) break;
+ }
+
+ switch(ret)
+ {
+ case 0x7E:
+ return "GM";
+ case 0x43:
+ return "XG";
+ case 0x42:
+ return "X5";
+ case 0x41:
+ return "GS";
+ }
+ return 0;
+}
+
+void CSysexMap::CleanUp()
+{
+ if (!pos) return;
+ int n,m;
+ for(n=0;n<pos-1;n++)
+ {
+ for(m=n+1;m<pos;m++)
+ {
+ if (events[n].pos>events[m].pos)
+ {
+ SYSEX_ENTRY t=events[n];
+ events[n]=events[m];
+ events[m]=t;
+ }
+ }
+ }
+}
+
+char* BuildFilterString(UINT res_id, char* ext, int* len)
+{
+ static char filterStr[256];
+ char *f = filterStr;
+ ZeroMemory(filterStr,256);
+ *len = 0;
+ WASABI_API_LNGSTRING_BUF(res_id,filterStr,256);
+ f += (*len = lstrlenA(filterStr) + 1);
+ lstrcatA(f,"*.");
+ f += 2;
+ lstrcatA(f,ext);
+ *(f + lstrlenA(ext)+1) = 0;
+ *len += lstrlenA(ext)+3;
+ return filterStr;
+}
+
+BOOL DoOpenFile(HWND w,char* fn,UINT res_id, char* ext,BOOL save)
+{
+ int len = 0;
+ OPENFILENAMEA ofn = {sizeof(ofn),0};
+ ofn.hwndOwner=w;
+ ofn.lpstrFilter=BuildFilterString(res_id,ext,&len);
+ ofn.lpstrFile=fn;
+ ofn.nMaxFile=MAX_PATH;
+ ofn.lpstrDefExt=ext;
+ if (save)
+ {
+ ofn.Flags=OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY;
+ return GetSaveFileNameA(&ofn);
+ }
+ else
+ {
+ ofn.Flags=OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY;
+ return GetOpenFileNameA(&ofn);
+ }
+}
+
+BOOL DoSaveFile(HWND w, char* fn, char* filt, char* ext)
+{
+ OPENFILENAMEA ofn;
+ ZeroMemory(&ofn,sizeof(ofn));
+ ofn.lStructSize=sizeof(ofn);
+ ofn.hwndOwner=w;
+ ofn.lpstrFilter=filt;
+ ofn.lpstrFile=fn;
+ ofn.nMaxFile=MAX_PATH;
+ ofn.lpstrDefExt=ext;
+ ofn.Flags=OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY;
+ return GetOpenFileNameA(&ofn);
+}
+
+typedef void (*SYSEXFUNC)(void*,BYTE*,UINT);
+
+#define rsysex(X) f(i,X,sizeof(X))
+#define _sysex(X,Y) f(i,X,Y)
+
+bool need_sysex_start()
+{
+ return cfg_hardware_reset>0
+ || cfg_sysex_table.num_entries()>0
+ ;
+}
+
+void sysex_startup(SYSEXFUNC f,void* i)
+{
+ if (cfg_hardware_reset>0)
+ {
+ switch(cfg_hardware_reset)
+ {
+ case 1:rsysex(d_GMReset);break;
+ case 2:rsysex(d_GSReset);break;
+ case 3:rsysex(d_XGReset);break;
+ }
+ MIDI_callback::Idle(200);
+ }
+ if (cfg_sysex_table.num_entries()>0)
+ {
+ int idx=0;
+ BYTE * data;
+ int size,time;
+ while(cfg_sysex_table.get_entry(idx++,&data,&size,&time))
+ {
+ _sysex(data,size);
+ MIDI_callback::Idle(time);
+ }
+ }
+}
+
+
+MIDI_EVENT* do_table(MIDI_file * mf,UINT prec,UINT * size,UINT* _lstart,DWORD cflags)
+{
+ BYTE * data_ptr = 0;
+ int data_size = 0;
+ if (!DoCleanUp(mf,CLEAN_1TRACK|CLEAN_NOSYSEX|CLEAN_NOTEMPO|cflags,(void**)&data_ptr,&data_size)) return 0;
+ if (data_size<=0x0e) {free(data_ptr);return 0;}
+
+ UINT ts;
+ BYTE* track;
+ UINT ntm;
+ track=data_ptr+8+6+8;
+ ts=rev32(*(DWORD*)(track-4));
+ CTempoMap* tmap=mf->tmap;
+ UINT n=0;
+ UINT pt=0;
+ ntm=tmap->pos;
+ CSysexMap* smap;
+
+ if (!cfg_nosysex && mf->smap && mf->smap->pos)
+ {
+ smap=mf->smap;
+ }
+ else smap=0;
+
+ n=0;
+ DWORD pos=0;
+ DWORD pos_ms=0;
+ DWORD t_pos=0;
+ DWORD cur_temp=0;
+ UINT dtx=(UINT)rev16(*(WORD*)(data_ptr+8+4))*1000/prec;
+ grow_buf boo;
+
+ int ns=0;
+ UINT track_pos=0,smap_pos=0;
+ UINT loop_start=-1;
+
+ {
+ unsigned int _d;
+ n+=DecodeDelta(track+n,&_d);
+ track_pos+=_d;
+ }
+
+ if (smap)
+ {
+ smap_pos=smap->events[0].pos;
+ }
+ else smap_pos=-1;
+
+ while(1)
+ {
+ DWORD ev=0;
+ DWORD d=0;
+ {
+ if (n >= (data_size-26))
+ break;
+ if (track_pos<smap_pos)
+ {
+ d=track_pos-pos;
+ ev=(*(DWORD*)(track+n))&0xFFFFFF;
+ if ((ev&0xF0)==0xF0)
+ {
+ track_pos=-1;
+ continue;
+ }
+ if ((ev&0xF0)==0xC0 || (ev&0xF0)==0xD0)
+ {
+ ev&=0xFFFF;n+=2;
+ }
+ else
+ {
+ n+=3;
+ }
+ if ((ev&0xFF00F0)==0x90)
+ {
+ ev=(ev&0xFF0F)|0x7F0080;
+ }
+ unsigned int _d;
+ n+=DecodeDelta(track+n,&_d);
+ track_pos+=_d;
+ if (n >= (data_size-26))
+ break;
+ }
+ else if (smap_pos!=-1)
+ {
+ d=smap_pos-pos;
+ ev=0x80000000|ns;
+ ns++;
+ if (ns==smap->pos)
+ smap_pos=-1;
+ else
+ smap_pos=smap->events[ns].pos;
+ }
+ }
+ if (!ev) break;
+ while(t_pos<ntm && pos+d>=(UINT)tmap->data[t_pos].pos)
+ {
+ DWORD d1=tmap->data[t_pos].pos-pos;
+ if (loop_start==-1 && (UINT)mf->loopstart_t<=pos+d1) loop_start=pos_ms+MulDiv(cur_temp,pos+d1-mf->loopstart_t,dtx);
+ pos_ms+=MulDiv(cur_temp,d1,dtx);
+ cur_temp=tmap->data[t_pos].tm;
+ t_pos++;
+ pos+=d1;
+ d-=d1;
+ }
+ if (loop_start==-1 && (UINT)mf->loopstart_t<=pos+d) loop_start=pos_ms+MulDiv(cur_temp,d,dtx);
+ pos_ms+=MulDiv(cur_temp,d,dtx);
+ pos+=d;
+ {
+ MIDI_EVENT me={pos_ms,ev};
+ boo.write(&me,sizeof(me));
+ }
+ }
+
+ free(data_ptr);
+
+ UINT sz=boo.get_size();
+ MIDI_EVENT* ret=(MIDI_EVENT*)boo.finish();
+ if (ret)
+ {
+ *size=sz>>3;//sz/sizeof(MIDI_EVENT);
+ if (cfg_loop_type==2 && loop_start==-1) loop_start=0;
+ else if (cfg_loop_type==0) loop_start=-1;
+ if (_lstart) *_lstart=loop_start;
+ }
+ return ret;
+}
+
+
+void gb_write_delta(grow_buf & gb,DWORD d)
+{
+ BYTE tmp[8] = {0};
+ gb.write(tmp,EncodeDelta(tmp,d));
+}
+
+void do_messages(HWND w,bool* b)
+{
+ MSG msg;
+ while(b && *b)
+ {
+ BOOL b=GetMessage(&msg,w,0,0);
+ if (b==-1 || !b) break;
+ DispatchMessage(&msg);
+ }
+}
+
+static wchar_t cb_class[]=TEXT("CallbackWndClass0");
+
+ATOM do_callback_class(WNDPROC p)
+{
+ cb_class[sizeof(cb_class)-2]++;
+ WNDCLASS wc=
+ {
+ 0,p,0,4,MIDI_callback::GetInstance(),0,0,0,0,cb_class
+ };
+ return RegisterClassW(&wc);
+}
+
+HWND create_callback_wnd(ATOM cl,void* p)
+{
+ HWND w=CreateWindowA((char*)cl,0,0,0,0,0,0,MIDI_callback::GetMainWindow(),0,MIDI_callback::GetInstance(),0);
+ if (w) SetWindowLong(w,0,(long)p);
+ return w;
+}
+
+CTempoMap* tmap_merge(CTempoMap* m1,CTempoMap* m2)
+{
+ int p1=0,p2=0;
+ CTempoMap * ret=0;
+ if (m1 && m2 && m1->data && m2->data)
+ {
+ ret=tmap_create();
+ if (ret)
+ {
+ while(p1<m1->pos && p2<m2->pos)
+ {
+ if (m1->data[p1].pos<=m2->data[p2].pos)
+ {
+ ret->AddEntry(m1->data[p1].pos,m1->data[p1].tm);
+ p1++;
+ }
+ else
+ {
+ ret->AddEntry(m2->data[p2].pos,m2->data[p2].tm);
+ p2++;
+ }
+ }
+ while(p1<m1->pos)
+ {
+ ret->AddEntry(m1->data[p1].pos,m1->data[p1].tm);
+ p1++;
+ }
+ while(p2<m2->pos)
+ {
+ ret->AddEntry(m2->data[p2].pos,m2->data[p2].tm);
+ p2++;
+ }
+ }
+ }
+ if (m1) delete m1;
+ if (m2) delete m2;
+ return ret;
+
+}
+
+KAR_ENTRY * kmap_create(MIDI_file* mf,UINT prec,UINT * num,char** text)
+{
+ if (!mf->kar_track) return 0;
+ grow_buf b_data,b_map;
+ KAR_ENTRY te;
+ BYTE *track=(BYTE*)mf->data+mf->kar_track+8;
+ BYTE *track_end = track+rev32(*(DWORD*)(mf->data+mf->kar_track+4));
+ int time=0;
+ int ptr=0;
+ BYTE lc=0;
+ while(track<track_end)
+ {
+ unsigned int d;
+ track+=DecodeDelta(track,&d);
+ time+=d;
+ if (*track==0xFF) //meta
+ {
+ BYTE type=track[1];
+ track+=2;
+ track+=DecodeDelta(track,&d);
+ char * ptr=(char*)track;
+ track+=d;
+ if ((type==0x5 || type==0x1) && d && *ptr!='@') //lyrics
+ {
+ te.time=time;
+ te.foo=1;
+ unsigned int n;
+ te.start=b_data.get_size();
+ for(n=0;n<d;n++)
+ {
+ switch(ptr[n])
+ {
+// case '@':
+ case '\\':
+ case '/':
+ case 0x0D:
+ b_data.write("\x0d\x0a",2);
+ break;
+ case 0x0A:
+ break;
+ default:
+ te.foo=0;
+ b_data.write_byte(ptr[n]);
+ break;
+ }
+ }
+ te.end=b_data.get_size();
+ if (te.start<te.end) b_map.write(&te,sizeof(te));
+ }
+ }
+ else if (*track==0xF0)
+ {
+ track++;
+ track+=DecodeDelta(track,&d);
+ track+=d;
+ }
+ else if ((*track&0xF0)==0xF0)
+ {
+ track++;//hack
+ }
+ else
+ {
+ if (*track&0x80) lc=*(track++)&0xF0;
+ if (lc==0 || lc==0xC0 || lc==0xD0) track++;
+ else track+=2;
+ }
+ }
+ int map_siz = b_map.get_size();
+ KAR_ENTRY * map=(KAR_ENTRY*)b_map.finish();
+ map_siz/=sizeof(KAR_ENTRY);
+
+ if (num) *num=map_siz;
+
+ if (text)
+ {
+ b_data.write_byte(0);
+ *text=(char*)b_data.finish();
+ }
+ else b_data.reset();
+
+ if (map)
+ {
+ int n;
+
+ time=0;
+
+ CTempoMap* tmap=mf->tmap;
+
+ int pos_ms=0;
+ int t_pos=0;
+ int cur_temp=0;
+ int dtx=(UINT)rev16(*(WORD*)(mf->data+8+4))*1000/prec;
+
+ for(n=0;n<map_siz;n++)
+ {
+ int d=0;
+ d=map[n].time-time;
+
+ while(t_pos<tmap->pos && time+d>=tmap->data[t_pos].pos)
+ {
+ DWORD d1=tmap->data[t_pos].pos-time;
+ pos_ms+=MulDiv(cur_temp,d1,dtx);
+ cur_temp=tmap->data[t_pos].tm;
+ t_pos++;
+ time+=d1;
+ d-=d1;
+ }
+ pos_ms+=MulDiv(cur_temp,d,dtx);
+ time+=d;
+ map[n].time=pos_ms;
+ }
+ }
+
+ return map;
+}
+
+int sysex_table::num_entries() const
+{
+ int num=0;
+ entry * ptr=entries;
+ while(ptr) {ptr=ptr->next;num++;}
+ return num;
+}
+
+int sysex_table::get_entry(int idx,BYTE ** p_data,int * p_size,int * p_time) const
+{
+ entry * ptr=entries;
+ while(ptr && idx>0) {ptr=ptr->next;idx--;}
+ if (!ptr) return 0;
+ if (p_data) *p_data = ptr->data;
+ if (p_size) *p_size = ptr->size;
+ if (p_time) *p_time = ptr->time;
+ return 1;
+}
+
+void sysex_table::insert_entry(int idx,BYTE * data,int size,int time)
+{
+ entry ** ptr = &entries;
+ while(idx>0 && *ptr)
+ {
+ ptr = &(*ptr)->next;
+ idx--;
+ }
+ entry * insert = new entry;
+ insert->data = (BYTE*)malloc(size);
+ memcpy(insert->data,data,size);
+ insert->size = size;
+ insert->time = time;
+ insert->next = *ptr;
+ *ptr = insert;
+}
+
+int sysex_table::remove_entry(int idx)
+{
+ entry ** ptr = &entries;
+ while(idx>0 && *ptr)
+ {
+ ptr = &(*ptr)->next;
+ idx--;
+ }
+ if (!*ptr) return 0;
+ entry * remove = *ptr;
+ *ptr=remove->next;
+ free(remove->data);
+ delete remove;
+ return 1;
+}
+
+
+int sysex_table::file_write(const char* file) const
+{
+ HANDLE f=CreateFileA(file,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,0);
+ if (f==INVALID_HANDLE_VALUE) return 0;
+
+ int size;
+ void * ptr = memblock_write(&size);
+ DWORD bw = 0;
+ WriteFile(f,ptr,size,&bw,0);
+ free(ptr);
+ CloseHandle(f);
+ return 1;
+}
+
+void * sysex_table::memblock_write(int * size) const
+{
+ grow_buf wb;
+
+ entry * ptr;
+ //MAGIC:DWORD , NUM: DWORD,DATA_SIZE:DWORD, offsets, sleep,data
+ DWORD temp;
+ temp=MHP_MAGIC;
+ wb.write(&temp,4);
+ temp=num_entries();
+ wb.write(&temp,4);
+
+ temp=0;
+ for(ptr=entries;ptr;ptr=ptr->next) temp+=ptr->size;
+ wb.write(&temp,4);
+ temp=0;
+ for(ptr=entries;ptr;ptr=ptr->next)
+ {
+ wb.write(&temp,4);
+ temp+=ptr->size;
+ }
+ for(ptr=entries;ptr;ptr=ptr->next)
+ {
+ temp = ptr->time;
+ wb.write(&temp,4);
+ }
+
+ for(ptr=entries;ptr;ptr=ptr->next)
+ {
+ wb.write(ptr->data,ptr->size);
+ }
+
+ if (size) *size = wb.get_size();
+
+ return wb.finish();
+}
+
+int sysex_table::memblock_read(const void * block,int size)
+{
+ entry * ptr;
+ const BYTE * src = (const BYTE*)block;
+ DWORD temp,total_size,total_num;
+
+
+ if (*(DWORD*)src!=MHP_MAGIC) return 0;
+ src+=4;
+
+ temp=total_num=*(DWORD*)src;
+ src+=4;
+ if (total_num>0xFFFF) return 0;
+
+ reset();
+ while(temp>0)
+ {
+ ptr=new entry;
+ ptr->next=entries;
+ entries = ptr;
+ temp--;
+ }
+
+ total_size=*(DWORD*)src;
+
+ UINT n;
+
+ for(n=0,ptr=entries;ptr;ptr=ptr->next,n++)
+ {
+//offset : 12 + 4 * n;
+//time : 12 + 4 * total_num + 4 * n;
+//data : 12 + 8 * total_num + offset
+ DWORD offset,time,offset2;
+ src = (const BYTE*)block + 12 + 4*n;
+ offset=*(DWORD*)src;
+
+ if (n!=total_num-1) offset2=*(DWORD*)(src+4);
+ else offset2=total_size;
+ ptr->size = offset2-offset;
+ src = (const BYTE*)block + 12 + 4*total_num + 4*n;
+ time = *(DWORD*)src;
+
+ ptr->data = (BYTE*)malloc(offset2);
+ src = (const BYTE*)block + 12 + 8*total_num + offset;
+ memcpy(ptr->data,src,ptr->size);
+
+ ptr->time = time;
+ }
+
+ return 1;
+}
+
+int sysex_table::file_read(const char* file)
+{
+
+ HANDLE f=CreateFileA(file,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
+ if (f==INVALID_HANDLE_VALUE) return 0;
+ int size = GetFileSize(f,0);
+ void * temp = malloc(size);
+ DWORD br = 0;
+ ReadFile(f,temp,size,&br,0);
+ CloseHandle(f);
+ int rv = memblock_read(temp,size);
+ free(temp);
+ return rv;
+}
+
+int sysex_table::print_preview(int idx,char * out) const
+{
+ BYTE* data;
+ int size,time;
+ if (!get_entry(idx,&data,&size,&time)) return 0;
+ int size2=size;
+ if (size2>10) size2=10;
+ wsprintfA(out,WASABI_API_LNGSTRING(STRING_MS_FMT),time);
+ while(out && *out) out++;
+ int n;
+ for(n=0;n<size2;n++)
+ {
+ wsprintfA(out," %02X",data[n]);
+ out+=3;
+ }
+
+ if (size!=size2)
+ {
+ strcpy(out,"...");
+ }
+ return 1;
+}
+
+void sysex_table::print_edit(int idx,HWND wnd) const
+{
+ BYTE* data;
+ int size,time;
+ if (!get_entry(idx,&data,&size,&time)) {SetWindowTextA(wnd,"");return;}
+ if (size<=2) {SetWindowTextA(wnd,"");return;}
+ char *temp = (char*)malloc(3*size);
+ char *ptr = temp;
+ int n;
+ for(n=1;n<size-1;n++)
+ {
+ wsprintfA(ptr,"%02X ",data[n]);
+ ptr+=3;
+ }
+ ptr[-1]=0;
+ SetWindowTextA(wnd,temp);
+ free(temp);
+}
+
+void sysex_table::copy(const sysex_table & src)
+{
+ reset();
+ int idx=0;
+ BYTE * data;
+ int size,time;
+ while(src.get_entry(idx++,&data,&size,&time))//ASS SLOW
+ insert_entry(idx,data,size,time);
+}
+
+//special sysex table cfg_var hack
+class cfg_var_sysex : private cfg_var
+{
+private:
+ sysex_table * tab;
+
+ virtual void read(HKEY hk)
+ {
+ int size=reg_get_struct_size(hk);
+ if (size>0)
+ {
+ void * temp = malloc(size);
+ if (temp)
+ {
+ reg_read_struct(hk,temp,size);
+ tab->memblock_read(temp,size);
+ free(temp);
+ }
+ }
+ }
+ virtual void write(HKEY hk)
+ {
+ void * data;
+ int size;
+ data = tab->memblock_write(&size);
+ if (data) reg_write_struct(hk,data,size);
+
+ }
+ virtual void reset() {tab->reset();}
+
+public:
+ cfg_var_sysex(const char * name,sysex_table * p_tab) : cfg_var(name) {tab=p_tab;}
+};
+
+static cfg_var_sysex thevar("sysex_table",&cfg_sysex_table);
diff --git a/Src/Plugins/Input/in_midi/utils.h b/Src/Plugins/Input/in_midi/utils.h
new file mode 100644
index 00000000..1628e846
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/utils.h
@@ -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
diff --git a/Src/Plugins/Input/in_midi/version.rc2 b/Src/Plugins/Input/in_midi/version.rc2
new file mode 100644
index 00000000..990863e5
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/version.rc2
@@ -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 © 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
diff --git a/Src/Plugins/Input/in_midi/wa2.cpp b/Src/Plugins/Input/in_midi/wa2.cpp
new file mode 100644
index 00000000..71e39ff2
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/wa2.cpp
@@ -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);
+} \ No newline at end of file
diff --git a/Src/Plugins/Input/in_midi/wa3.cpp b/Src/Plugins/Input/in_midi/wa3.cpp
new file mode 100644
index 00000000..661a5001
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/wa3.cpp
@@ -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;
+
+}
+}
diff --git a/Src/Plugins/Input/in_midi/xmi.cpp b/Src/Plugins/Input/in_midi/xmi.cpp
new file mode 100644
index 00000000..6f18ec87
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/xmi.cpp
@@ -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);
+} \ No newline at end of file