diff options
Diffstat (limited to 'Src/Plugins/Input/in_midi')
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(¬es,0,sizeof(notes)); + memset(&ctrl_tab,0,sizeof(ctrl_tab)); + memset(&ins_tab,0,sizeof(ins_tab)); + + tm_ofs=0; + p_time=0; + hTrd=0; + + ins_set=0; + +#ifdef SEQ_HAVE_PANEL + hCtrl=0; + + tempo=g_tempo; + novol=g_novol; + noins=g_noins; + + last_time_ms=0; + last_time_ret=0; + + mute_mask=0; + initialized=0; +#endif +} + + +#define GET_TIME get_time()//timeGetTime() + +int IS_SPEC_C(int x) {return (x>=0x60 && x<=0x65) || x==6 || x==26 || x>=120;} + +#define n_sysex smap->pos + + +DWORD seq_base::preprocess(DWORD e) +{ + BYTE t=(BYTE)(e&0xF0); + if (t==0xB0) + { + UINT v=(e>>16)&0xFF; + BYTE c=(BYTE)(e>>8); +#ifdef SEQ_HAVE_PANEL + if (c==7) + { + if (mute_mask&(1<<(e&0xF))) v=0; + } +#endif + e=(e&0xFFFF)|((v&0xFF)<<16); + } + else if (t==0xC0) + { + ins_set|=1<<(e&0xF); + } + return e; +} + +void seq_base::send_sysex(int n) +{ +#ifdef USE_LOG + log_write("send_sysex()"); +#endif + if (!smap || n>=n_sysex) return; + _sysex(smap->data+smap->events[n].ofs,smap->events[n].len); +} + +/* +void seq_base::reset_ins() +{ + UINT n; + for(n=0;n<16;n++) + { + cb->shortmsg(0xC0|n); + } +} +*/ + +BOOL seq_base::do_ctrl(DWORD e) +{ + BYTE tp=(BYTE)(e&0xF0); + BYTE ch=(BYTE)(e&0x0F); + if (tp==0xC0) + { +#ifdef SEQ_HAVE_PANEL + if (noins) return 0; +#endif + //if (!cfg_fctrl && (e>>8)==ins_tab[e&0xF]) return 0; + UINT val=e>>8; + ins_tab[ch]=val; +#ifdef SEQ_HAVE_PANEL + if (hCtrl) SetDlgItemInt(hCtrl,INS_ID_P+ch,val,0); +#endif + } else if (tp==0xB0) + { + UINT cn = (e>>8)&0x7F; + UINT val= (e>>16)&0x7F; +#ifdef SEQ_HAVE_PANEL + if (cn==0) + { + if (noins) return 0; + if (hCtrl) SetDlgItemInt(hCtrl,INS_ID_B1+ch,val,0); + } + else if (cn==0x20) + { + if (noins) return 0; + if (hCtrl) SetDlgItemInt(hCtrl,INS_ID_B2+ch,val,0); + } + else if (cn==7) + { + if (novol) return 0; + if (hCtrl) PostMessage(GetDlgItem(hCtrl,VOL_ID+(e&0xF)),TBM_SETPOS,1,0x7F-val); + } + else if (cn==0x27) + { + if (novol) return 0; + } +#endif + if (!IS_SPEC_C(cn)) ctrl_tab[e&0xF][cn]=val; + } + else if (tp==0x90) + { + if (!(ins_set&(1<<ch))) + { + SEND_MSG(0xC0|ch); + } + } + return 1; +} + +void seq_base::reset() +{ + int not,ch; + for(ch=0;ch<16;ch++) + { + if (ctrl_tab[ch][0x40]) + { + seq_shortmsg(0x40B0|ch); + ctrl_tab[ch][0x40]=0; + } + if (ch==9) continue; + for(not=0;not<128;not++) + { + if (note_state(ch,not)) + { + seq_shortmsg((not<<8)|0x80|ch); + note_off(ch,not); + } + } + } +} + + +int seq_base::note_state(int ch,int note) +{ + UINT pos=(ch<<7)+note; + return notes[pos>>3]&(1<<(pos&0x7)); +} + +void seq_base::note_on(int ch,int note) +{ + UINT pos=(ch<<7)+note; + notes[pos>>3]|=(1<<(pos&0x7)); +} + +void seq_base::note_off(int ch,int note) +{ + UINT pos=(ch<<7)+note; + notes[pos>>3]&=~(1<<(pos&0x7)); +} + +UINT seq_base::do_seek(DWORD n,DWORD p) +{ + UINT m,c; + BYTE _ctrl_tab[16][128] = {0}; + BYTE _ins_tab[16] = {0}; + memcpy(_ctrl_tab,ctrl_tab,sizeof(_ctrl_tab)); + memcpy(_ins_tab,ins_tab,sizeof(_ins_tab)); + + if (n==0) + { + memset(ins_tab,0,sizeof(ins_tab)); + for(m=0;m<16;m++) + { + _ctrl_tab[m][0]=_ctrl_tab[m][0x20]=0; + } + } + + while(n<n_events && p>events[n].tm) + { + DWORD e=events[n].ev; + if (!(e&0x80000000)) + { + if (do_ctrl(e)) + { + if (((e&0xF0)==0xB0) && IS_SPEC_C((e>>8)&0xFF)) + { + seq_shortmsg(e); + } + } + } + n++; + } + for(c=0;c<16;c++) + { + for(m=0;m<128;m++) + { + if (!IS_SPEC_C(m) && _ctrl_tab[c][m]!=ctrl_tab[c][m]) + { + SEND_MSG(((DWORD)ctrl_tab[c][m]<<16)|(m<<8)|0xB0|c); + } + } + if (_ins_tab[c]!=ins_tab[c]) + { + SEND_MSG(((DWORD)ins_tab[c]<<8)|0xC0|c); + } + } + return n; +} + +DWORD WINAPI seq_base::seq_trd(void* p) +{ + ((seq_base*)p)->thread(); + return 0; +} + +void seq_base::sysexfunc(seq_base* cb,BYTE* s,UINT sz) +{ + cb->seq_sysex(s,sz); +} + +void seq_base::thread() +{ + tm_ofs=-1; + if (seq_play_start()) + { + + sysex_startup((SYSEXFUNC)sysexfunc,this); + + tm_ofs=GET_TIME; + DWORD pos=0; + while(!kill) + { + DWORD c_t=GET_TIME-tm_ofs; + if (paused) + { + reset(); + while(paused && !kill) MIDI_callback::Idle(); + if (kill) break; + tm_ofs=GET_TIME-c_t; + } + + if (seek_to!=-1) + { +_seek: + DWORD _p=seek_to > c_t ? pos : 0; + c_t=seek_to; + seek_to=-1; + tm_ofs=GET_TIME-c_t; + reset(); + pos=c_t ? do_seek(_p,c_t) : 0; + } + if (events[pos].tm+1600 < c_t) + { + reset(); + pos=do_seek(pos,c_t); + } + while(pos<n_events && events[pos].tm<=c_t && !kill) + { + DWORD e=events[pos++].ev; + if (e) + { + if (e&0x80000000) + { + send_sysex(e&0x7FFFFFFF); + } + else + { + if ((e&0xF0)==0x90) + { + note_on(e&0xf,(e>>8)&0xFF); + } + else if ((e&0xF0)==0x80) + { + note_off(e&0xf,(e>>8)&0xFF); + } + if (do_ctrl(e)) + SEND_MSG(e); + } + } + } + + if (pos>=n_events || c_t >= events[n_events-1].tm) + { + if (loop_start!=-1 && (--c_loop)) + { + c_t=loop_start; + tm_ofs=GET_TIME-c_t; + pos=do_seek(0,c_t); + continue; + } + if (cfg_eof_delay) + { + DWORD t=timeGetTime(); + do + { + MIDI_callback::Idle(); + } while(!kill && seek_to==-1 && t+cfg_eof_delay>timeGetTime()); + if (seek_to!=-1) { + pos=0; + goto _seek; + } + } + if (!kill) MIDI_core::Eof(); + break; + } + if (kill) break; + + MIDI_callback::Idle(); + } + reset(); + } + seq_play_stop(); +} + +int seq_base::gettime() +{ + if (paused) + return (seek_to==-1) ? seek_to>>3 : p_time; + else + return (GET_TIME-tm_ofs)>>3; +} + +int seq_base::settime(int tm) +{ + seek_to=tm<<3; + return 1; +} + + +void seq_base::pause() +{ + paused=1; + p_time=GET_TIME-tm_ofs; +} + +void seq_base::unpause() +{ + paused=0; +} + +int seq_base::seq_cmd_start(DWORD cflags) +{ + mf=MIDI_core::getFile(); +#ifdef SEQ_HAVE_PANEL + mute_mask=0; +#endif + c_loop=cfg_loop_infinite ? -1 : cfg_loop_count; + memset(notes,0,sizeof(notes)); + memset(ctrl_tab,-1,sizeof(ctrl_tab)); + memset(ins_tab,0,sizeof(ins_tab)); + + UINT n; + for(n=0;n<16;n++) ctrl_tab[n][7]=90; + + events=do_table(mf,8,&n_events,&loop_start,cflags); + if (!events) return 0; + + if (!cfg_nosysex && mf->smap && mf->smap->pos) + { + smap=mf->smap; + } + else smap=0; + + kill=0; + seek_to=-1; + paused=0; + +#ifdef SEQ_HAVE_PANEL + if (cfg_seq_showpanel) + { + InitializeCriticalSection(&tm_sec); + WASABI_API_CREATEDIALOGPARAMW(IDD_EXT_IMM, MIDI_callback::GetMainWindow(), CtrlProc, (LPARAM)this); + ShowWindow(hCtrl,cfg_ctrl_min ? SW_SHOWMINIMIZED : SW_SHOW); + } + else + { + tempo=1; + novol=0; + noins=0; + } +#endif + + DWORD id; + hTrd=CreateThread(0,0,seq_trd,this,CREATE_SUSPENDED,&id); +#ifndef _DEBUG + SetThreadPriority(hTrd,THREAD_PRIORITY_TIME_CRITICAL); +#endif + ResumeThread(hTrd); + return 1; +} + +void seq_base::seq_cmd_stop() +{ +#ifdef USE_LOG + log_write("stopping sequencer"); +#endif + if (hTrd) + { +#ifdef USE_LOG + log_write("killing thread"); +#endif + kill=1; + if (WaitForSingleObject(hTrd,4000)!=WAIT_OBJECT_0) + { +#ifdef USE_LOG + log_write("unable to kill thread"); +#endif + TerminateThread(hTrd,0); + } +#ifdef USE_LOG + else log_write("thread killed normally"); +#endif + CloseHandle(hTrd); + } +} +/* +void seq_base::enum_ins() +{ + DWORD ttab[256]; + memset(ttab,-1,sizeof(ttab)); + UINT tpt=0; + UINT n; + DWORD c_ins[16]; + memset(c_ins,0,sizeof(c_ins)); + c_ins[9]=0x80000000; + for(n=0;n<n_events;n++) + { + DWORD t=events[n].ev; + if (t&0xFF000000) continue; + UINT c=t&0xF0; + UINT ch=events[n].ev&0xF; + if ((t&0xFFF0)==0x20B0) + { + c_ins[ch]=(c_ins[ch]&0xFFFF00FF)|((t>>8)&0xFF00); + } + else if ((t&0xFFF0)==0xB0) + { + c_ins[ch]=(c_ins[ch]&0xFF00FFFF)|(t&0xFF0000); + } + else if ((t&0xF0)==0xC0) + { + c_ins[ch]=(c_ins[ch]&0xFFFFFF00)|((t>>8)&0xFF); + } + else if ((t&0xF0)==0x90) + { + UINT n; + for(n=0;n<256;n++) + { + if (ttab[n]==c_ins[ch]) goto ok; + } + cb->enum_ins(ttab[tpt]=c_ins[ch]); + tpt=(tpt+1)&0xFF; +ok:; + } + } +} +*/ 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 |