12 #ifdef WIN32_ENABLE_DIRECTMUSIC_SUPPORT 15 #include "../stdafx.h" 16 #ifdef WIN32_LEAN_AND_MEAN 17 #undef WIN32_LEAN_AND_MEAN // Don't exclude rarely-used stuff from Windows headers 20 #include "../os/windows/win32.h" 21 #include "../core/mem_func.hpp" 22 #include "../thread/thread.h" 23 #include "../fileio_func.h" 24 #include "../base_media_base.h" 26 #include "midifile.hpp" 34 #include "../safeguards.h" 37 # pragma comment(lib, "ole32.lib") 40 static const int MS_TO_REFTIME = 1000 * 10;
41 static const int MIDITIME_TO_REFTIME = 10;
44 #define FOURCC_INFO mmioFOURCC('I','N','F','O') 45 #define FOURCC_fmt mmioFOURCC('f','m','t',' ') 46 #define FOURCC_data mmioFOURCC('d','a','t','a') 56 std::vector<WLOOP> wave_loops;
57 std::vector<CONNECTION> articulators;
61 struct DLSInstrument {
64 std::vector<CONNECTION> articulators;
65 std::vector<DLSRegion> regions;
73 std::vector<BYTE> data;
76 std::vector<WLOOP> wave_loops;
79 return this->file_offset == offset;
83 std::vector<DLSInstrument> instruments;
84 std::vector<POOLCUE> pool_cues;
85 std::vector<DLSWave> waves;
88 bool LoadFile(
const TCHAR *file);
92 bool ReadDLSArticulation(FILE *f, DWORD list_length, std::vector<CONNECTION> &out);
94 bool ReadDLSRegionList(FILE *f, DWORD list_length, DLSInstrument &instrument);
96 bool ReadDLSRegion(FILE *f, DWORD list_length, std::vector<DLSRegion> &out);
98 bool ReadDLSInstrumentList(FILE *f, DWORD list_length);
100 bool ReadDLSInstrument(FILE *f, DWORD list_length);
102 bool ReadDLSWaveList(FILE *f, DWORD list_length);
104 bool ReadDLSWave(FILE *f, DWORD list_length,
long offset);
108 PACK_N(
struct ChunkHeader {
114 PACK_N(
struct WAVE_DOWNLOAD {
115 DMUS_DOWNLOADINFO dlInfo;
116 ULONG ulOffsetTable[2];
118 DMUS_WAVEDATA dmWaveData;
143 static HANDLE _thread_event = NULL;
148 static IDirectMusic *_music = NULL;
150 static IDirectMusicPort *_port = NULL;
152 static IDirectMusicBuffer *_buffer = NULL;
154 static std::vector<IDirectMusicDownload *> _dls_downloads;
160 bool DLSFile::ReadDLSArticulation(FILE *f, DWORD list_length, std::vector<CONNECTION> &out)
162 while (list_length > 0) {
164 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
165 list_length -= chunk.length +
sizeof(chunk);
167 if (chunk.type == FOURCC_ART1) {
168 CONNECTIONLIST conns;
169 if (fread(&conns,
sizeof(conns), 1, f) != 1)
return false;
170 fseek(f, conns.cbSize -
sizeof(conns), SEEK_CUR);
173 for (ULONG i = 0; i < conns.cConnections; i++) {
175 if (fread(&con,
sizeof(con), 1, f) != 1)
return false;
179 fseek(f, chunk.length, SEEK_CUR);
186 bool DLSFile::ReadDLSRegion(FILE *f, DWORD list_length, std::vector<DLSRegion> &out)
188 out.push_back(DLSRegion());
189 DLSRegion ®ion = out.back();
192 region.wave_sample.cbSize = 0;
194 while (list_length > 0) {
196 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
197 list_length -= chunk.length +
sizeof(chunk);
199 if (chunk.type == FOURCC_LIST) {
201 if (fread(&chunk.type,
sizeof(chunk.type), 1, f) != 1)
return false;
202 chunk.length -=
sizeof(chunk.type);
205 switch (chunk.type) {
207 if (fread(®ion.hdr,
sizeof(region.hdr), 1, f) != 1)
return false;
211 if (fread(®ion.wave_sample,
sizeof(region.wave_sample), 1, f) != 1)
return false;
212 fseek(f, region.wave_sample.cbSize -
sizeof(region.wave_sample), SEEK_CUR);
215 for (ULONG i = 0; i < region.wave_sample.cSampleLoops; i++) {
217 if (fread(&loop,
sizeof(loop), 1, f) != 1)
return false;
218 region.wave_loops.push_back(loop);
223 if (fread(®ion.wave,
sizeof(region.wave), 1, f) != 1)
return false;
227 if (!this->ReadDLSArticulation(f, chunk.length, region.articulators))
return false;
232 fseek(f, chunk.length, SEEK_CUR);
236 DEBUG(driver, 7,
"DLS: Ignoring unkown chunk %c%c%c%c", (
char)(chunk.type & 0xFF), (
char)((chunk.type >> 8) & 0xFF), (
char)((chunk.type >> 16) & 0xFF), (
char)((chunk.type >> 24) & 0xFF));
237 fseek(f, chunk.length, SEEK_CUR);
245 bool DLSFile::ReadDLSRegionList(FILE *f, DWORD list_length, DLSInstrument &instrument)
247 while (list_length > 0) {
249 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
250 list_length -= chunk.length +
sizeof(chunk);
252 if (chunk.type == FOURCC_LIST) {
254 if (fread(&list_type,
sizeof(list_type), 1, f) != 1)
return false;
256 if (list_type == FOURCC_RGN) {
257 this->ReadDLSRegion(f, chunk.length -
sizeof(list_type), instrument.regions);
259 DEBUG(driver, 7,
"DLS: Ignoring unkown list chunk of type %c%c%c%c", (
char)(list_type & 0xFF), (
char)((list_type >> 8) & 0xFF), (
char)((list_type >> 16) & 0xFF), (
char)((list_type >> 24) & 0xFF));
260 fseek(f, chunk.length -
sizeof(list_type), SEEK_CUR);
263 DEBUG(driver, 7,
"DLS: Ignoring chunk %c%c%c%c", (
char)(chunk.type & 0xFF), (
char)((chunk.type >> 8) & 0xFF), (
char)((chunk.type >> 16) & 0xFF), (
char)((chunk.type >> 24) & 0xFF));
264 fseek(f, chunk.length, SEEK_CUR);
271 bool DLSFile::ReadDLSInstrument(FILE *f, DWORD list_length)
273 this->instruments.push_back(DLSInstrument());
274 DLSInstrument &instrument = this->instruments.back();
276 while (list_length > 0) {
278 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
279 list_length -= chunk.length +
sizeof(chunk);
281 if (chunk.type == FOURCC_LIST) {
283 if (fread(&chunk.type,
sizeof(chunk.type), 1, f) != 1)
return false;
284 chunk.length -=
sizeof(chunk.type);
287 switch (chunk.type) {
289 if (fread(&instrument.hdr,
sizeof(instrument.hdr), 1, f) != 1)
return false;
293 if (!this->ReadDLSArticulation(f, chunk.length, instrument.articulators))
return false;
297 if (!this->ReadDLSRegionList(f, chunk.length, instrument))
return false;
302 fseek(f, chunk.length, SEEK_CUR);
306 DEBUG(driver, 7,
"DLS: Ignoring unkown chunk %c%c%c%c", (
char)(chunk.type & 0xFF), (
char)((chunk.type >> 8) & 0xFF), (
char)((chunk.type >> 16) & 0xFF), (
char)((chunk.type >> 24) & 0xFF));
307 fseek(f, chunk.length, SEEK_CUR);
315 bool DLSFile::ReadDLSInstrumentList(FILE *f, DWORD list_length)
317 while (list_length > 0) {
319 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
320 list_length -= chunk.length +
sizeof(chunk);
322 if (chunk.type == FOURCC_LIST) {
324 if (fread(&list_type,
sizeof(list_type), 1, f) != 1)
return false;
326 if (list_type == FOURCC_INS) {
327 DEBUG(driver, 6,
"DLS: Reading instrument %d", (
int)instruments.size());
329 if (!this->ReadDLSInstrument(f, chunk.length -
sizeof(list_type)))
return false;
331 DEBUG(driver, 7,
"DLS: Ignoring unkown list chunk of type %c%c%c%c", (
char)(list_type & 0xFF), (
char)((list_type >> 8) & 0xFF), (
char)((list_type >> 16) & 0xFF), (
char)((list_type >> 24) & 0xFF));
332 fseek(f, chunk.length -
sizeof(list_type), SEEK_CUR);
335 DEBUG(driver, 7,
"DLS: Ignoring chunk %c%c%c%c", (
char)(chunk.type & 0xFF), (
char)((chunk.type >> 8) & 0xFF), (
char)((chunk.type >> 16) & 0xFF), (
char)((chunk.type >> 24) & 0xFF));
336 fseek(f, chunk.length, SEEK_CUR);
343 bool DLSFile::ReadDLSWave(FILE *f, DWORD list_length,
long offset)
345 this->waves.push_back(DLSWave());
346 DLSWave &wave = this->waves.back();
350 wave.wave_sample.cbSize =
sizeof(WSMPL);
351 wave.wave_sample.usUnityNote = 60;
352 wave.file_offset = offset;
354 while (list_length > 0) {
356 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
357 list_length -= chunk.length +
sizeof(chunk);
359 if (chunk.type == FOURCC_LIST) {
361 if (fread(&chunk.type,
sizeof(chunk.type), 1, f) != 1)
return false;
362 chunk.length -=
sizeof(chunk.type);
365 switch (chunk.type) {
367 if (fread(&wave.fmt,
sizeof(wave.fmt), 1, f) != 1)
return false;
368 if (chunk.length >
sizeof(wave.fmt)) fseek(f, chunk.length -
sizeof(wave.fmt), SEEK_CUR);
372 if (fread(&wave.wave_sample,
sizeof(wave.wave_sample), 1, f) != 1)
return false;
373 fseek(f, wave.wave_sample.cbSize -
sizeof(wave.wave_sample), SEEK_CUR);
376 for (ULONG i = 0; i < wave.wave_sample.cSampleLoops; i++) {
378 if (fread(&loop,
sizeof(loop), 1, f) != 1)
return false;
379 wave.wave_loops.push_back(loop);
384 wave.data.resize(chunk.length);
385 if (fread(&wave.data[0],
sizeof(BYTE), wave.data.size(), f) != wave.data.size())
return false;
390 fseek(f, chunk.length, SEEK_CUR);
394 DEBUG(driver, 7,
"DLS: Ignoring unkown chunk %c%c%c%c", (
char)(chunk.type & 0xFF), (
char)((chunk.type >> 8) & 0xFF), (
char)((chunk.type >> 16) & 0xFF), (
char)((chunk.type >> 24) & 0xFF));
395 fseek(f, chunk.length, SEEK_CUR);
403 bool DLSFile::ReadDLSWaveList(FILE *f, DWORD list_length)
405 long base_offset = ftell(f);
407 while (list_length > 0) {
408 long chunk_offset = ftell(f);
411 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
412 list_length -= chunk.length +
sizeof(chunk);
414 if (chunk.type == FOURCC_LIST) {
416 if (fread(&list_type,
sizeof(list_type), 1, f) != 1)
return false;
418 if (list_type == FOURCC_wave) {
419 DEBUG(driver, 6,
"DLS: Reading wave %d", (
int)waves.size());
421 if (!this->ReadDLSWave(f, chunk.length -
sizeof(list_type), chunk_offset - base_offset))
return false;
423 DEBUG(driver, 7,
"DLS: Ignoring unkown list chunk of type %c%c%c%c", (
char)(list_type & 0xFF), (
char)((list_type >> 8) & 0xFF), (
char)((list_type >> 16) & 0xFF), (
char)((list_type >> 24) & 0xFF));
424 fseek(f, chunk.length -
sizeof(list_type), SEEK_CUR);
427 DEBUG(driver, 7,
"DLS: Ignoring chunk %c%c%c%c", (
char)(chunk.type & 0xFF), (
char)((chunk.type >> 8) & 0xFF), (
char)((chunk.type >> 16) & 0xFF), (
char)((chunk.type >> 24) & 0xFF));
428 fseek(f, chunk.length, SEEK_CUR);
435 bool DLSFile::LoadFile(
const TCHAR *file)
437 DEBUG(driver, 2,
"DMusic: Try to load DLS file %s",
FS2OTTD(file));
439 FILE *f = _tfopen(file, _T(
"rb"));
440 if (f == NULL)
return false;
447 if (fread(&hdr,
sizeof(hdr), 1, f) != 1)
return false;
448 if (fread(&dls_type,
sizeof(dls_type), 1, f) != 1)
return false;
449 if (hdr.type != FOURCC_RIFF || dls_type != FOURCC_DLS)
return false;
451 hdr.length -=
sizeof(FOURCC);
453 DEBUG(driver, 2,
"DMusic: Parsing DLS file");
459 while (hdr.length > 0) {
461 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
462 hdr.length -= chunk.length +
sizeof(chunk);
464 if (chunk.type == FOURCC_LIST) {
466 if (fread(&chunk.type,
sizeof(chunk.type), 1, f) != 1)
return false;
467 chunk.length -=
sizeof(chunk.type);
470 switch (chunk.type) {
472 if (fread(&header,
sizeof(header), 1, f) != 1)
return false;
476 if (!this->ReadDLSInstrumentList(f, chunk.length))
return false;
480 if (!this->ReadDLSWaveList(f, chunk.length))
return false;
485 if (fread(&ptbl,
sizeof(ptbl), 1, f) != 1)
return false;
486 fseek(f, ptbl.cbSize -
sizeof(ptbl), SEEK_CUR);
489 for (ULONG i = 0; i < ptbl.cCues; i++) {
491 if (fread(&cue,
sizeof(cue), 1, f) != 1)
return false;
492 this->pool_cues.push_back(cue);
498 fseek(f, chunk.length, SEEK_CUR);
502 DEBUG(driver, 7,
"DLS: Ignoring unkown chunk %c%c%c%c", (
char)(chunk.type & 0xFF), (
char)((chunk.type >> 8) & 0xFF), (
char)((chunk.type >> 16) & 0xFF), (
char)((chunk.type >> 24) & 0xFF));
503 fseek(f, chunk.length, SEEK_CUR);
509 if (header.cInstruments != this->instruments.size())
return false;
512 for (std::vector<POOLCUE>::iterator cue = this->pool_cues.begin(); cue != this->pool_cues.end(); cue++) {
513 std::vector<DLSWave>::iterator w = std::find(this->waves.begin(), this->waves.end(), cue->ulOffset);
514 if (w != this->waves.end()) {
515 cue->ulOffset = (ULONG)(w - this->waves.begin());
525 static byte ScaleVolume(byte original, byte scale)
527 return original * scale / 127;
530 static void TransmitChannelMsg(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, byte status, byte p1, byte p2 = 0)
532 if (buffer->PackStructured(rt, 0, status | (p1 << 8) | (p2 << 16)) == E_OUTOFMEMORY) {
534 _port->PlayBuffer(buffer);
537 buffer->PackStructured(rt, 0, status | (p1 << 8) | (p2 << 16));
541 static void TransmitSysex(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, byte *&msg_start,
size_t &remaining)
544 byte *msg_end = msg_start;
545 while (*msg_end != MIDIST_ENDSYSEX) msg_end++;
548 if (buffer->PackUnstructured(rt, 0, msg_end - msg_start, msg_start) == E_OUTOFMEMORY) {
550 _port->PlayBuffer(buffer);
553 buffer->PackUnstructured(rt, 0, msg_end - msg_start, msg_start);
557 remaining -= msg_end - msg_start;
561 static void TransmitSysexConst(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, byte *msg_start,
size_t length)
563 TransmitSysex(buffer, rt, msg_start, length);
567 static void TransmitNotesOff(IDirectMusicBuffer *buffer, REFERENCE_TIME block_time, REFERENCE_TIME cur_time)
569 for (
int ch = 0; ch < 16; ch++) {
570 TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_MODE_ALLNOTESOFF, 0);
571 TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_SUSTAINSW, 0);
572 TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_MODE_RESETALLCTRL, 0);
576 _port->PlayBuffer(_buffer);
581 for (
int ch = 0; ch < 16; ch++) {
584 TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_RPN_SELECT_LO, 0x00);
585 TransmitChannelMsg(_buffer, block_time + 10, MIDICT_RPN_SELECT_HI, 0x00);
586 TransmitChannelMsg(_buffer, block_time + 10, MIDICT_DATAENTRY, 0x02);
587 TransmitChannelMsg(_buffer, block_time + 10, MIDICT_DATAENTRY_LO, 0x00);
588 TransmitChannelMsg(_buffer, block_time + 10, MIDICT_RPN_SELECT_LO, 0x7F);
589 TransmitChannelMsg(_buffer, block_time + 10, MIDICT_RPN_SELECT_HI, 0x7F);
591 _port->PlayBuffer(_buffer);
596 Sleep(
Clamp((block_time - cur_time) / MS_TO_REFTIME, 5, 1000));
599 static void MidiThreadProc(
void *)
601 DEBUG(driver, 2,
"DMusic: Entering playback thread");
603 REFERENCE_TIME last_volume_time = 0;
604 REFERENCE_TIME block_time = 0;
613 IReferenceClock *clock;
614 _port->GetLatencyClock(&clock);
616 REFERENCE_TIME cur_time;
617 clock->GetTime(&cur_time);
620 static byte gm_enable_sysex[] = { 0xF0, 0x7E, 0x00, 0x09, 0x01, 0xF7 };
621 TransmitSysexConst(_buffer, cur_time, &gm_enable_sysex[0],
sizeof(gm_enable_sysex));
623 static byte roland_reverb_sysex[] = { 0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x01, 0x30, 0x02, 0x04, 0x00, 0x40, 0x40, 0x00, 0x00, 0x09, 0xF7 };
624 TransmitSysexConst(_buffer, cur_time, &roland_reverb_sysex[0],
sizeof(roland_reverb_sysex));
626 _port->PlayBuffer(_buffer);
629 DWORD next_timeout = 1000;
632 DWORD wfso = WaitForSingleObject(_thread_event, next_timeout);
634 if (_playback.shutdown) {
635 _playback.playing =
false;
639 if (_playback.do_stop) {
640 DEBUG(driver, 2,
"DMusic thread: Stopping playback");
643 clock->GetTime(&cur_time);
644 TransmitNotesOff(_buffer, block_time, cur_time);
646 _playback.playing =
false;
647 _playback.do_stop =
false;
653 if (wfso == WAIT_OBJECT_0) {
654 if (_playback.do_start) {
655 DEBUG(driver, 2,
"DMusic thread: Starting playback");
660 current_file.
MoveFrom(_playback.next_file);
661 std::swap(_playback.next_segment, current_segment);
662 current_segment.start_block = 0;
664 _playback.playing =
true;
665 _playback.do_start =
false;
669 clock->GetTime(&cur_time);
670 TransmitNotesOff(_buffer, block_time, cur_time);
675 clock->GetTime(&playback_start_time);
676 playback_start_time += _playback.preload_time * MS_TO_REFTIME;
680 if (_playback.playing) {
682 if (current_segment.start > 0 && current_block == 0 && current_segment.start_block == 0) {
686 size_t preload_bytes = 0;
687 for (
size_t bl = 0; bl < current_file.
blocks.size(); bl++) {
690 if (block.
ticktime >= current_segment.start) {
691 if (current_segment.loop) {
692 DEBUG(driver, 2,
"DMusic: timer: loop from block %d (ticktime %d, realtime %.3f, bytes %d)", (
int)bl, (
int)block.
ticktime, ((
int)block.
realtime) / 1000.0, (
int)preload_bytes);
693 current_segment.start_block = bl;
699 DEBUG(driver, 2,
"DMusic: timer: start from block %d (ticktime %d, realtime %.3f, bytes %d)", (
int)bl, (
int)block.
ticktime, ((
int)block.
realtime) / 1000.0, (
int)preload_bytes);
700 playback_start_time -= block.
realtime * MIDITIME_TO_REFTIME;
708 REFERENCE_TIME current_time;
709 clock->GetTime(¤t_time);
712 if (current_volume != _playback.new_volume) {
713 if (current_time - last_volume_time > 10 * MS_TO_REFTIME) {
714 DEBUG(driver, 2,
"DMusic thread: volume change");
715 current_volume = _playback.new_volume;
716 last_volume_time = current_time;
717 for (
int ch = 0; ch < 16; ch++) {
718 int vol = ScaleVolume(channel_volumes[ch], current_volume);
719 TransmitChannelMsg(_buffer, block_time + 1, MIDIST_CONTROLLER | ch, MIDICT_CHANVOLUME, vol);
721 _port->PlayBuffer(_buffer);
726 while (current_block < current_file.
blocks.size()) {
730 if (current_segment.end > 0 && block.
ticktime >= current_segment.end) {
731 if (current_segment.loop) {
732 DEBUG(driver, 2,
"DMusic thread: Looping song");
733 current_block = current_segment.start_block;
734 playback_start_time = current_time - current_file.
blocks[
current_block].realtime * MIDITIME_TO_REFTIME;
736 _playback.do_stop =
true;
743 if (block.
realtime * MIDITIME_TO_REFTIME > playback_time + 3 *_playback.preload_time * MS_TO_REFTIME) {
745 next_timeout =
Clamp(((int64)block.
realtime * MIDITIME_TO_REFTIME - playback_time) / MS_TO_REFTIME - _playback.preload_time, 0, 1000);
746 DEBUG(driver, 9,
"DMusic thread: Next event in %lu ms (music %u, ref " OTTD_PRINTF64
")", next_timeout, block.
realtime * MIDITIME_TO_REFTIME, playback_time);
751 block_time = playback_start_time + block.
realtime * MIDITIME_TO_REFTIME;
752 DEBUG(driver, 9,
"DMusic thread: Streaming block " PRINTF_SIZE
" (cur=" OTTD_PRINTF64
", block=" OTTD_PRINTF64
")", current_block, (
long long)(current_time / MS_TO_REFTIME), (
long long)(block_time / MS_TO_REFTIME));
756 byte last_status = 0;
757 while (remaining > 0) {
760 byte status = data[0];
762 last_status = status;
766 status = last_status;
768 switch (status & 0xF0) {
770 case MIDIST_CHANPRESS:
772 TransmitChannelMsg(_buffer, block_time, status, data[0]);
778 case MIDIST_POLYPRESS:
779 case MIDIST_PITCHBEND:
781 TransmitChannelMsg(_buffer, block_time, status, data[0], data[1]);
785 case MIDIST_CONTROLLER:
787 if (data[0] == MIDICT_CHANVOLUME) {
789 channel_volumes[status & 0x0F] = data[1];
790 int vol = ScaleVolume(data[1], current_volume);
791 TransmitChannelMsg(_buffer, block_time, status, data[0], vol);
794 TransmitChannelMsg(_buffer, block_time, status, data[0], data[1]);
803 TransmitSysex(_buffer, block_time, data, remaining);
805 case MIDIST_TC_QFRAME:
810 case MIDIST_SONGPOSPTR:
825 DWORD used_buffer = 0;
826 _buffer->GetUsedBytes(&used_buffer);
827 if (used_buffer > 0) {
828 _port->PlayBuffer(_buffer);
833 if (current_block == current_file.
blocks.size()) {
834 if (current_segment.loop) {
835 current_block = current_segment.start_block;
836 playback_start_time = block_time - current_file.
blocks[
current_block].realtime * MIDITIME_TO_REFTIME;
838 _playback.do_stop =
true;
845 DEBUG(driver, 2,
"DMusic: Exiting playback thread");
848 clock->GetTime(&cur_time);
849 TransmitNotesOff(_buffer, block_time, cur_time);
850 Sleep(_playback.preload_time * 4);
855 static void * DownloadArticulationData(
int base_offset,
void *data,
const std::vector<CONNECTION> &artic)
857 DMUS_ARTICULATION2 *art = (DMUS_ARTICULATION2 *)data;
858 art->ulArtIdx = base_offset + 1;
859 art->ulFirstExtCkIdx = 0;
860 art->ulNextArtIdx = 0;
862 CONNECTIONLIST *con_list = (CONNECTIONLIST *)(art + 1);
863 con_list->cbSize =
sizeof(CONNECTIONLIST);
864 con_list->cConnections = (ULONG)artic.size();
865 MemCpyT((CONNECTION *)(con_list + 1), &artic.front(), artic.size());
867 return (CONNECTION *)(con_list + 1) + artic.size();
870 static const char *LoadDefaultDLSFile(
const char *user_dls)
874 caps.dwSize =
sizeof(DMUS_PORTCAPS);
875 _port->GetCaps(&caps);
878 if ((caps.dwFlags & (DMUS_PC_DLS | DMUS_PC_DLS2)) != 0 && (caps.dwFlags & DMUS_PC_GMINHARDWARE) == 0) {
881 if (user_dls == NULL) {
884 if (SUCCEEDED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(
"Software\\Microsoft\\DirectMusic"), 0, KEY_READ, &hkDM))) {
885 TCHAR dls_path[MAX_PATH];
886 DWORD buf_size =
sizeof(dls_path);
887 if (SUCCEEDED(RegQueryValueEx(hkDM, _T(
"GMFilePath"), NULL, NULL, (LPBYTE)dls_path, &buf_size))) {
888 TCHAR expand_path[MAX_PATH * 2];
889 ExpandEnvironmentStrings(dls_path, expand_path,
lengthof(expand_path));
890 if (!dls_file.LoadFile(expand_path))
DEBUG(driver, 1,
"Failed to load default GM DLS file from registry");
896 if (dls_file.instruments.size() == 0) {
897 static const TCHAR *DLS_GM_FILE = _T(
"%windir%\\System32\\drivers\\gm.dls");
898 TCHAR path[MAX_PATH];
899 ExpandEnvironmentStrings(DLS_GM_FILE, path,
lengthof(path));
901 if (!dls_file.LoadFile(path))
return "Can't load GM DLS collection";
904 if (!dls_file.LoadFile(
OTTD2FS(user_dls)))
return "Can't load GM DLS collection";
908 IDirectMusicPortDownload *download_port = NULL;
909 if (FAILED(_port->QueryInterface(IID_IDirectMusicPortDownload, (LPVOID *)&download_port)))
return "Can't get download port";
911 DWORD dlid_wave = 0, dlid_inst = 0;
912 if (FAILED(download_port->GetDLId(&dlid_wave, (DWORD)dls_file.waves.size())) || FAILED(download_port->GetDLId(&dlid_inst, (DWORD)dls_file.instruments.size()))) {
913 download_port->Release();
914 return "Can't get enough DLS ids";
918 download_port->GetAppend(&dwAppend);
921 for (DWORD i = 0; i < dls_file.waves.size(); i++) {
922 IDirectMusicDownload *dl_wave = NULL;
923 if (FAILED(download_port->AllocateBuffer((DWORD)(
sizeof(WAVE_DOWNLOAD) + dwAppend * dls_file.waves[i].fmt.wf.nBlockAlign + dls_file.waves[i].data.size()), &dl_wave))) {
924 download_port->Release();
925 return "Can't allocate wave download buffer";
930 if (FAILED(dl_wave->GetBuffer((LPVOID *)&wave, &wave_size))) {
932 download_port->Release();
933 return "Can't get wave download buffer";
938 wave->dlInfo.dwDLType = DMUS_DOWNLOADINFO_WAVE;
939 wave->dlInfo.cbSize = wave_size;
940 wave->dlInfo.dwDLId = dlid_wave + i;
941 wave->dlInfo.dwNumOffsetTableEntries = 2;
942 wave->ulOffsetTable[0] = offsetof(WAVE_DOWNLOAD, dmWave);
943 wave->ulOffsetTable[1] = offsetof(WAVE_DOWNLOAD, dmWaveData);
944 wave->dmWave.ulWaveDataIdx = 1;
945 MemCpyT((PCMWAVEFORMAT *)&wave->dmWave.WaveformatEx, &dls_file.waves[i].fmt, 1);
946 wave->dmWaveData.cbSize = (DWORD)dls_file.waves[i].data.size();
947 MemCpyT(wave->dmWaveData.byData, &dls_file.waves[i].data[0], dls_file.waves[i].data.size());
949 _dls_downloads.push_back(dl_wave);
950 if (FAILED(download_port->Download(dl_wave))) {
951 download_port->Release();
952 return "Downloading DLS wave failed";
957 for (DWORD i = 0; i < dls_file.instruments.size(); i++) {
958 DWORD offsets = 1 + (DWORD)dls_file.instruments[i].regions.size();
961 size_t i_size =
sizeof(DMUS_DOWNLOADINFO) +
sizeof(DMUS_INSTRUMENT);
962 if (dls_file.instruments[i].articulators.size() > 0) {
965 i_size +=
sizeof(DMUS_ARTICULATION2) +
sizeof(CONNECTIONLIST) +
sizeof(CONNECTION) * dls_file.instruments[i].articulators.size();
968 for (std::vector<DLSFile::DLSRegion>::iterator rgn = dls_file.instruments[i].regions.begin(); rgn != dls_file.instruments[i].regions.end(); rgn++) {
969 if (rgn->articulators.size() > 0) {
971 i_size +=
sizeof(DMUS_ARTICULATION2) +
sizeof(CONNECTIONLIST) +
sizeof(CONNECTION) * rgn->articulators.size();
976 if (rgn->wave_sample.cbSize != 0) {
977 i_size +=
sizeof(DMUS_REGION) -
sizeof(DMUS_REGION::WLOOP) +
sizeof(WLOOP) * rgn->wave_loops.size();
979 i_size +=
sizeof(DMUS_REGION) -
sizeof(DMUS_REGION::WLOOP) +
sizeof(WLOOP) * dls_file.waves[dls_file.pool_cues[rgn->wave.ulTableIndex].ulOffset].wave_loops.size();
983 i_size += offsets *
sizeof(ULONG);
986 IDirectMusicDownload *dl_inst = NULL;
987 if (FAILED(download_port->AllocateBuffer((DWORD)i_size, &dl_inst))) {
988 download_port->Release();
989 return "Can't allocate instrument download buffer";
994 if (FAILED(dl_inst->GetBuffer((LPVOID *)&instrument, &inst_size))) {
996 download_port->Release();
997 return "Can't get instrument download buffer";
999 char *inst_base = (
char *)instrument;
1002 DMUS_DOWNLOADINFO *d_info = (DMUS_DOWNLOADINFO *)instrument;
1003 d_info->dwDLType = DMUS_DOWNLOADINFO_INSTRUMENT2;
1004 d_info->cbSize = inst_size;
1005 d_info->dwDLId = dlid_inst + i;
1006 d_info->dwNumOffsetTableEntries = offsets;
1007 instrument = d_info + 1;
1010 ULONG *offset_table = (ULONG *)instrument;
1011 instrument = offset_table + offsets;
1012 int last_offset = 0;
1015 DMUS_INSTRUMENT *inst_data = (DMUS_INSTRUMENT *)instrument;
1017 offset_table[last_offset++] = (
char *)inst_data - inst_base;
1018 inst_data->ulPatch = (dls_file.instruments[i].hdr.Locale.ulBank & F_INSTRUMENT_DRUMS) | ((dls_file.instruments[i].hdr.Locale.ulBank & 0x7F7F) << 8) | (dls_file.instruments[i].hdr.Locale.ulInstrument & 0x7F);
1019 instrument = inst_data + 1;
1022 if (dls_file.instruments[i].articulators.size() > 0) {
1023 inst_data->ulGlobalArtIdx = last_offset;
1024 offset_table[last_offset++] = (
char *)instrument - inst_base;
1025 offset_table[last_offset++] = (
char *)instrument +
sizeof(DMUS_ARTICULATION2) - inst_base;
1027 instrument = DownloadArticulationData(inst_data->ulGlobalArtIdx, instrument, dls_file.instruments[i].articulators);
1028 assert((
char *)instrument - inst_base <= (ptrdiff_t)inst_size);
1032 inst_data->ulFirstRegionIdx = last_offset;
1033 for (uint j = 0; j < dls_file.instruments[i].regions.size(); j++) {
1034 DLSFile::DLSRegion &rgn = dls_file.instruments[i].regions[j];
1036 DMUS_REGION *inst_region = (DMUS_REGION *)instrument;
1037 offset_table[last_offset++] = (
char *)inst_region - inst_base;
1038 inst_region->RangeKey = rgn.hdr.RangeKey;
1039 inst_region->RangeVelocity = rgn.hdr.RangeVelocity;
1040 inst_region->fusOptions = rgn.hdr.fusOptions;
1041 inst_region->usKeyGroup = rgn.hdr.usKeyGroup;
1042 inst_region->ulFirstExtCkIdx = 0;
1044 ULONG wave_id = dls_file.pool_cues[rgn.wave.ulTableIndex].ulOffset;
1045 inst_region->WaveLink = rgn.wave;
1046 inst_region->WaveLink.ulTableIndex = wave_id + dlid_wave;
1049 if (rgn.wave_sample.cbSize != 0) {
1050 inst_region->WSMP = rgn.wave_sample;
1051 if (rgn.wave_loops.size() > 0)
MemCpyT(inst_region->WLOOP, &rgn.wave_loops.front(), rgn.wave_loops.size());
1053 instrument = (
char *)(inst_region + 1) -
sizeof(DMUS_REGION::WLOOP) +
sizeof(WLOOP) * rgn.wave_loops.size();
1055 inst_region->WSMP = rgn.wave_sample;
1056 if (dls_file.waves[wave_id].wave_loops.size() > 0)
MemCpyT(inst_region->WLOOP, &dls_file.waves[wave_id].wave_loops.front(), dls_file.waves[wave_id].wave_loops.size());
1058 instrument = (
char *)(inst_region + 1) -
sizeof(DMUS_REGION::WLOOP) +
sizeof(WLOOP) * dls_file.waves[wave_id].wave_loops.size();
1062 if (rgn.articulators.size() > 0) {
1063 inst_region->ulRegionArtIdx = last_offset;
1064 offset_table[last_offset++] = (
char *)instrument - inst_base;
1065 offset_table[last_offset++] = (
char *)instrument +
sizeof(DMUS_ARTICULATION2) - inst_base;
1067 instrument = DownloadArticulationData(inst_region->ulRegionArtIdx, instrument, rgn.articulators);
1069 inst_region->ulRegionArtIdx = 0;
1071 assert((
char *)instrument - inst_base <= (ptrdiff_t)inst_size);
1074 inst_region->ulNextRegionIdx = j < dls_file.instruments[i].regions.size() - 1 ? last_offset : 0;
1077 _dls_downloads.push_back(dl_inst);
1078 if (FAILED(download_port->Download(dl_inst))) {
1079 download_port->Release();
1080 return "Downloading DLS instrument failed";
1084 download_port->Release();
1094 if (FAILED(CoInitializeEx(NULL, COINITBASE_MULTITHREADED)))
return "COM initialization failed";
1097 if (FAILED(CoCreateInstance(
1104 return "Failed to create the music object";
1108 if (FAILED(_music->SetDirectSound(NULL, NULL)))
return "Can't set DirectSound interface";
1115 if (_debug_driver_level > 0) {
1117 char desc[DMUS_MAX_DESCRIPTION];
1121 caps.dwSize =
sizeof(DMUS_PORTCAPS);
1123 DEBUG(driver, 1,
"Detected DirectMusic ports:");
1124 for (
int i = 0; _music->EnumPort(i, &caps) == S_OK; i++) {
1125 if (caps.dwClass == DMUS_PC_OUTPUTCLASS) {
1137 caps.dwSize =
sizeof(DMUS_PORTCAPS);
1138 if (FAILED(_music->EnumPort(pIdx, &caps)))
return "Supplied port parameter is not a valid port";
1139 if (caps.dwClass != DMUS_PC_OUTPUTCLASS)
return "Supplied port parameter is not an output port";
1140 guidPort = caps.guidPort;
1142 if (FAILED(_music->GetDefaultPort(&guidPort)))
return "Can't query default music port";
1146 DMUS_PORTPARAMS params;
1148 params.dwSize =
sizeof(DMUS_PORTPARAMS);
1149 params.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
1150 params.dwChannelGroups = 1;
1151 if (FAILED(_music->CreatePort(guidPort, ¶ms, &_port, NULL)))
return "Failed to create port";
1153 if (FAILED(_port->Activate(TRUE)))
return "Failed to activate port";
1156 DMUS_BUFFERDESC desc;
1158 desc.dwSize =
sizeof(DMUS_BUFFERDESC);
1159 desc.guidBufferFormat = KSDATAFORMAT_SUBTYPE_DIRECTMUSIC;
1160 desc.cbBuffer = 1024;
1161 if (FAILED(_music->CreateMusicBuffer(&desc, &_buffer, NULL)))
return "Failed to create music buffer";
1164 const char *dls = LoadDefaultDLSFile(
GetDriverParam(parm,
"dls"));
1165 if (dls != NULL)
return dls;
1168 _thread_event = CreateEvent(NULL, FALSE, FALSE, NULL);
1169 if (_thread_event == NULL)
return "Can't create thread shutdown event";
1171 if (_thread_mutex == NULL)
return "Can't create thread mutex";
1173 if (!
ThreadObject::New(&MidiThreadProc,
this, &_dmusic_thread,
"ottd:dmusic"))
return "Can't create MIDI output thread";
1179 MusicDriver_DMusic::~MusicDriver_DMusic()
1187 if (_dmusic_thread != NULL) {
1188 _playback.shutdown =
true;
1189 SetEvent(_thread_event);
1190 _dmusic_thread->
Join();
1194 if (_dls_downloads.size() > 0) {
1195 IDirectMusicPortDownload *download_port = NULL;
1196 _port->QueryInterface(IID_IDirectMusicPortDownload, (LPVOID *)&download_port);
1200 for (std::vector<IDirectMusicDownload *>::reverse_iterator i = _dls_downloads.rbegin(); download_port != NULL && i != _dls_downloads.rend(); i++) {
1201 download_port->Unload(*i);
1204 _dls_downloads.clear();
1206 if (download_port != NULL) download_port->Release();
1209 if (_buffer != NULL) {
1214 if (_port != NULL) {
1215 _port->Activate(FALSE);
1220 if (_music != NULL) {
1225 CloseHandle(_thread_event);
1226 delete _thread_mutex;
1236 if (!_playback.next_file.LoadSong(song))
return;
1240 _playback.next_segment.loop = song.
loop;
1242 _playback.do_start =
true;
1243 SetEvent(_thread_event);
1249 _playback.do_stop =
true;
1250 SetEvent(_thread_event);
1256 return _playback.playing || _playback.do_start;
1262 _playback.new_volume = vol;
int override_end
MIDI tick to end the song at (0 if no override)
const char * GetDriverParam(const char *const *parm, const char *name)
Get a string parameter the list of parameters.
Metadata about a music track.
Simple mutex locker to keep a mutex locked until the locker goes out of scope.
void Stop()
Stop this driver.
const char * FS2OTTD(const TCHAR *name)
Convert to OpenTTD's encoding from that of the local environment.
MidiFile current_file
file currently being played from
CRITICAL_SECTION lock
synchronization for playback status fields
SmallVector< byte, 8 > data
raw midi data contained in block
size_t current_block
next block index to send
bool IsSongPlaying()
Are we currently playing a song?
int override_start
MIDI ticks to skip over in beginning.
bool playing
flag indicating that playback is active
const T * Begin() const
Get the pointer to the first item (const)
void MoveFrom(MidiFile &other)
Move data from other to this, and clears other.
byte new_volume
volume setting to change to
char * convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen)
Convert to OpenTTD's encoding from that of the environment in UNICODE.
std::vector< DataBlock > blocks
sequential time-annotated data of file, merged to a single track
void PlaySong(const MusicSongInfo &song)
Play a particular song.
uint Length() const
Get the number of items in the list.
void SetVolume(byte vol)
Set the volume, if possible.
byte channel_volumes[16]
last seen volume controller values in raw data
static ThreadMutex * New()
Create a new mutex.
bool operator==(const MultiMapIterator< Tmap_iter1, Tlist_iter1, Tkey, Tvalue1, Tcompare > &iter1, const MultiMapIterator< Tmap_iter2, Tlist_iter2, Tkey, Tvalue2, Tcompare > &iter2)
Compare two MultiMap iterators.
Auto-close a file upon scope exit.
const char * Start(const char *const *param)
Start this driver.
bool do_stop
flag for stopping playback at next opportunity
#define lengthof(x)
Return the length of an fixed size array.
const TCHAR * OTTD2FS(const char *name, bool console_cp)
Convert from OpenTTD's encoding to that of the local environment.
uint32 realtime
real-time (microseconds) since start of file this block should be triggered at
MidiFile next_file
upcoming file to play
static T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
static void MemCpyT(T *destination, const T *source, size_t num=1)
Type-safe version of memcpy().
#define DEBUG(name, level,...)
Output a line of debugging information.
void StopSong()
Stop playing the current song.
virtual void Join()=0
Join this thread.
PlaybackSegment next_segment
segment info for upcoming file
byte current_volume
current effective volume setting
uint32 ticktime
tick number since start of file this block should be triggered at
Factory for the DirectX music player.
bool loop
song should play in a tight loop if possible, never ending
PlaybackSegment current_segment
segment info for current playback
Base of playing music via DirectMusic.
DWORD playback_start_time
timestamp current file began playback
int GetDriverParamInt(const char *const *parm, const char *name, int def)
Get an integer parameter the list of parameters.
A Thread Object which works on all our supported OSes.
static bool New(OTTDThreadFunc proc, void *param, ThreadObject **thread=NULL, const char *name=NULL)
Create a thread; proc will be called as first function inside the thread, with optional params...
bool do_start
flag for starting playback of next_file at next opportunity
static void MemSetT(T *ptr, byte value, size_t num=1)
Type-safe version of memset().