10 #ifdef WIN32_ENABLE_DIRECTMUSIC_SUPPORT 13 #include "../stdafx.h" 14 #ifdef WIN32_LEAN_AND_MEAN 15 #undef WIN32_LEAN_AND_MEAN // Don't exclude rarely-used stuff from Windows headers 18 #include "../os/windows/win32.h" 19 #include "../core/mem_func.hpp" 20 #include "../thread.h" 21 #include "../fileio_func.h" 22 #include "../base_media_base.h" 24 #include "midifile.hpp" 33 #include "../safeguards.h" 36 # pragma comment(lib, "ole32.lib") 39 static const int MS_TO_REFTIME = 1000 * 10;
40 static const int MIDITIME_TO_REFTIME = 10;
43 #define FOURCC_INFO mmioFOURCC('I','N','F','O') 44 #define FOURCC_fmt mmioFOURCC('f','m','t',' ') 45 #define FOURCC_data mmioFOURCC('d','a','t','a') 55 std::vector<WLOOP> wave_loops;
56 std::vector<CONNECTION> articulators;
60 struct DLSInstrument {
63 std::vector<CONNECTION> articulators;
64 std::vector<DLSRegion> regions;
72 std::vector<BYTE> data;
75 std::vector<WLOOP> wave_loops;
78 return this->file_offset == offset;
82 std::vector<DLSInstrument> instruments;
83 std::vector<POOLCUE> pool_cues;
84 std::vector<DLSWave> waves;
87 bool LoadFile(
const TCHAR *file);
91 bool ReadDLSArticulation(FILE *f, DWORD list_length, std::vector<CONNECTION> &out);
93 bool ReadDLSRegionList(FILE *f, DWORD list_length, DLSInstrument &instrument);
95 bool ReadDLSRegion(FILE *f, DWORD list_length, std::vector<DLSRegion> &out);
97 bool ReadDLSInstrumentList(FILE *f, DWORD list_length);
99 bool ReadDLSInstrument(FILE *f, DWORD list_length);
101 bool ReadDLSWaveList(FILE *f, DWORD list_length);
103 bool ReadDLSWave(FILE *f, DWORD list_length,
long offset);
107 PACK_N(
struct ChunkHeader {
113 PACK_N(
struct WAVE_DOWNLOAD {
114 DMUS_DOWNLOADINFO dlInfo;
115 ULONG ulOffsetTable[2];
117 DMUS_WAVEDATA dmWaveData;
140 static std::thread _dmusic_thread;
142 static HANDLE _thread_event =
nullptr;
144 static std::mutex _thread_mutex;
147 static IDirectMusic *_music =
nullptr;
149 static IDirectMusicPort *_port =
nullptr;
151 static IDirectMusicBuffer *_buffer =
nullptr;
153 static std::vector<IDirectMusicDownload *> _dls_downloads;
159 bool DLSFile::ReadDLSArticulation(FILE *f, DWORD list_length, std::vector<CONNECTION> &out)
161 while (list_length > 0) {
163 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
164 list_length -= chunk.length +
sizeof(chunk);
166 if (chunk.type == FOURCC_ART1) {
167 CONNECTIONLIST conns;
168 if (fread(&conns,
sizeof(conns), 1, f) != 1)
return false;
169 fseek(f, conns.cbSize -
sizeof(conns), SEEK_CUR);
172 for (ULONG i = 0; i < conns.cConnections; i++) {
174 if (fread(&con,
sizeof(con), 1, f) != 1)
return false;
178 fseek(f, chunk.length, SEEK_CUR);
185 bool DLSFile::ReadDLSRegion(FILE *f, DWORD list_length, std::vector<DLSRegion> &out)
187 out.push_back(DLSRegion());
188 DLSRegion ®ion = out.back();
191 region.wave_sample.cbSize = 0;
193 while (list_length > 0) {
195 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
196 list_length -= chunk.length +
sizeof(chunk);
198 if (chunk.type == FOURCC_LIST) {
200 if (fread(&chunk.type,
sizeof(chunk.type), 1, f) != 1)
return false;
201 chunk.length -=
sizeof(chunk.type);
204 switch (chunk.type) {
206 if (fread(®ion.hdr,
sizeof(region.hdr), 1, f) != 1)
return false;
210 if (fread(®ion.wave_sample,
sizeof(region.wave_sample), 1, f) != 1)
return false;
211 fseek(f, region.wave_sample.cbSize -
sizeof(region.wave_sample), SEEK_CUR);
214 for (ULONG i = 0; i < region.wave_sample.cSampleLoops; i++) {
216 if (fread(&loop,
sizeof(loop), 1, f) != 1)
return false;
217 region.wave_loops.push_back(loop);
222 if (fread(®ion.wave,
sizeof(region.wave), 1, f) != 1)
return false;
226 if (!this->ReadDLSArticulation(f, chunk.length, region.articulators))
return false;
231 fseek(f, chunk.length, SEEK_CUR);
235 DEBUG(driver, 7,
"DLS: Ignoring unknown chunk %c%c%c%c", (
char)(chunk.type & 0xFF), (
char)((chunk.type >> 8) & 0xFF), (
char)((chunk.type >> 16) & 0xFF), (
char)((chunk.type >> 24) & 0xFF));
236 fseek(f, chunk.length, SEEK_CUR);
244 bool DLSFile::ReadDLSRegionList(FILE *f, DWORD list_length, DLSInstrument &instrument)
246 while (list_length > 0) {
248 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
249 list_length -= chunk.length +
sizeof(chunk);
251 if (chunk.type == FOURCC_LIST) {
253 if (fread(&list_type,
sizeof(list_type), 1, f) != 1)
return false;
255 if (list_type == FOURCC_RGN) {
256 this->ReadDLSRegion(f, chunk.length -
sizeof(list_type), instrument.regions);
258 DEBUG(driver, 7,
"DLS: Ignoring unknown 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));
259 fseek(f, chunk.length -
sizeof(list_type), SEEK_CUR);
262 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));
263 fseek(f, chunk.length, SEEK_CUR);
270 bool DLSFile::ReadDLSInstrument(FILE *f, DWORD list_length)
272 this->instruments.push_back(DLSInstrument());
273 DLSInstrument &instrument = this->instruments.back();
275 while (list_length > 0) {
277 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
278 list_length -= chunk.length +
sizeof(chunk);
280 if (chunk.type == FOURCC_LIST) {
282 if (fread(&chunk.type,
sizeof(chunk.type), 1, f) != 1)
return false;
283 chunk.length -=
sizeof(chunk.type);
286 switch (chunk.type) {
288 if (fread(&instrument.hdr,
sizeof(instrument.hdr), 1, f) != 1)
return false;
292 if (!this->ReadDLSArticulation(f, chunk.length, instrument.articulators))
return false;
296 if (!this->ReadDLSRegionList(f, chunk.length, instrument))
return false;
301 fseek(f, chunk.length, SEEK_CUR);
305 DEBUG(driver, 7,
"DLS: Ignoring unknown chunk %c%c%c%c", (
char)(chunk.type & 0xFF), (
char)((chunk.type >> 8) & 0xFF), (
char)((chunk.type >> 16) & 0xFF), (
char)((chunk.type >> 24) & 0xFF));
306 fseek(f, chunk.length, SEEK_CUR);
314 bool DLSFile::ReadDLSInstrumentList(FILE *f, DWORD list_length)
316 while (list_length > 0) {
318 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
319 list_length -= chunk.length +
sizeof(chunk);
321 if (chunk.type == FOURCC_LIST) {
323 if (fread(&list_type,
sizeof(list_type), 1, f) != 1)
return false;
325 if (list_type == FOURCC_INS) {
326 DEBUG(driver, 6,
"DLS: Reading instrument %d", (
int)instruments.size());
328 if (!this->ReadDLSInstrument(f, chunk.length -
sizeof(list_type)))
return false;
330 DEBUG(driver, 7,
"DLS: Ignoring unknown 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));
331 fseek(f, chunk.length -
sizeof(list_type), SEEK_CUR);
334 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));
335 fseek(f, chunk.length, SEEK_CUR);
342 bool DLSFile::ReadDLSWave(FILE *f, DWORD list_length,
long offset)
344 this->waves.push_back(DLSWave());
345 DLSWave &wave = this->waves.back();
349 wave.wave_sample.cbSize =
sizeof(WSMPL);
350 wave.wave_sample.usUnityNote = 60;
351 wave.file_offset = offset;
353 while (list_length > 0) {
355 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
356 list_length -= chunk.length +
sizeof(chunk);
358 if (chunk.type == FOURCC_LIST) {
360 if (fread(&chunk.type,
sizeof(chunk.type), 1, f) != 1)
return false;
361 chunk.length -=
sizeof(chunk.type);
364 switch (chunk.type) {
366 if (fread(&wave.fmt,
sizeof(wave.fmt), 1, f) != 1)
return false;
367 if (chunk.length >
sizeof(wave.fmt)) fseek(f, chunk.length -
sizeof(wave.fmt), SEEK_CUR);
371 if (fread(&wave.wave_sample,
sizeof(wave.wave_sample), 1, f) != 1)
return false;
372 fseek(f, wave.wave_sample.cbSize -
sizeof(wave.wave_sample), SEEK_CUR);
375 for (ULONG i = 0; i < wave.wave_sample.cSampleLoops; i++) {
377 if (fread(&loop,
sizeof(loop), 1, f) != 1)
return false;
378 wave.wave_loops.push_back(loop);
383 wave.data.resize(chunk.length);
384 if (fread(&wave.data[0],
sizeof(BYTE), wave.data.size(), f) != wave.data.size())
return false;
389 fseek(f, chunk.length, SEEK_CUR);
393 DEBUG(driver, 7,
"DLS: Ignoring unknown chunk %c%c%c%c", (
char)(chunk.type & 0xFF), (
char)((chunk.type >> 8) & 0xFF), (
char)((chunk.type >> 16) & 0xFF), (
char)((chunk.type >> 24) & 0xFF));
394 fseek(f, chunk.length, SEEK_CUR);
402 bool DLSFile::ReadDLSWaveList(FILE *f, DWORD list_length)
404 long base_offset = ftell(f);
406 while (list_length > 0) {
407 long chunk_offset = ftell(f);
410 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
411 list_length -= chunk.length +
sizeof(chunk);
413 if (chunk.type == FOURCC_LIST) {
415 if (fread(&list_type,
sizeof(list_type), 1, f) != 1)
return false;
417 if (list_type == FOURCC_wave) {
418 DEBUG(driver, 6,
"DLS: Reading wave %d", (
int)waves.size());
420 if (!this->ReadDLSWave(f, chunk.length -
sizeof(list_type), chunk_offset - base_offset))
return false;
422 DEBUG(driver, 7,
"DLS: Ignoring unknown 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));
423 fseek(f, chunk.length -
sizeof(list_type), SEEK_CUR);
426 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));
427 fseek(f, chunk.length, SEEK_CUR);
434 bool DLSFile::LoadFile(
const TCHAR *file)
436 DEBUG(driver, 2,
"DMusic: Try to load DLS file %s",
FS2OTTD(file));
438 FILE *f = _tfopen(file, _T(
"rb"));
439 if (f ==
nullptr)
return false;
446 if (fread(&hdr,
sizeof(hdr), 1, f) != 1)
return false;
447 if (fread(&dls_type,
sizeof(dls_type), 1, f) != 1)
return false;
448 if (hdr.type != FOURCC_RIFF || dls_type != FOURCC_DLS)
return false;
450 hdr.length -=
sizeof(FOURCC);
452 DEBUG(driver, 2,
"DMusic: Parsing DLS file");
458 while (hdr.length > 0) {
460 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
461 hdr.length -= chunk.length +
sizeof(chunk);
463 if (chunk.type == FOURCC_LIST) {
465 if (fread(&chunk.type,
sizeof(chunk.type), 1, f) != 1)
return false;
466 chunk.length -=
sizeof(chunk.type);
469 switch (chunk.type) {
471 if (fread(&header,
sizeof(header), 1, f) != 1)
return false;
475 if (!this->ReadDLSInstrumentList(f, chunk.length))
return false;
479 if (!this->ReadDLSWaveList(f, chunk.length))
return false;
484 if (fread(&ptbl,
sizeof(ptbl), 1, f) != 1)
return false;
485 fseek(f, ptbl.cbSize -
sizeof(ptbl), SEEK_CUR);
488 for (ULONG i = 0; i < ptbl.cCues; i++) {
490 if (fread(&cue,
sizeof(cue), 1, f) != 1)
return false;
491 this->pool_cues.push_back(cue);
497 fseek(f, chunk.length, SEEK_CUR);
501 DEBUG(driver, 7,
"DLS: Ignoring unknown chunk %c%c%c%c", (
char)(chunk.type & 0xFF), (
char)((chunk.type >> 8) & 0xFF), (
char)((chunk.type >> 16) & 0xFF), (
char)((chunk.type >> 24) & 0xFF));
502 fseek(f, chunk.length, SEEK_CUR);
508 if (header.cInstruments != this->instruments.size())
return false;
511 for (std::vector<POOLCUE>::iterator cue = this->pool_cues.begin(); cue != this->pool_cues.end(); cue++) {
512 std::vector<DLSWave>::iterator w = std::find(this->waves.begin(), this->waves.end(), cue->ulOffset);
513 if (w != this->waves.end()) {
514 cue->ulOffset = (ULONG)(w - this->waves.begin());
524 static byte ScaleVolume(byte original, byte scale)
526 return original * scale / 127;
529 static void TransmitChannelMsg(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, byte status, byte p1, byte p2 = 0)
531 if (buffer->PackStructured(rt, 0, status | (p1 << 8) | (p2 << 16)) == E_OUTOFMEMORY) {
533 _port->PlayBuffer(buffer);
536 buffer->PackStructured(rt, 0, status | (p1 << 8) | (p2 << 16));
540 static void TransmitSysex(IDirectMusicBuffer *buffer, REFERENCE_TIME rt,
const byte *&msg_start,
size_t &remaining)
543 const byte *msg_end = msg_start;
544 while (*msg_end != MIDIST_ENDSYSEX) msg_end++;
547 if (buffer->PackUnstructured(rt, 0, msg_end - msg_start, const_cast<LPBYTE>(msg_start)) == E_OUTOFMEMORY) {
549 _port->PlayBuffer(buffer);
552 buffer->PackUnstructured(rt, 0, msg_end - msg_start, const_cast<LPBYTE>(msg_start));
556 remaining -= msg_end - msg_start;
560 static void TransmitStandardSysex(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, MidiSysexMessage msg)
563 const byte *data = MidiGetStandardSysexMessage(msg, length);
564 TransmitSysex(buffer, rt, data, length);
568 static void TransmitNotesOff(IDirectMusicBuffer *buffer, REFERENCE_TIME block_time, REFERENCE_TIME cur_time)
570 for (
int ch = 0; ch < 16; ch++) {
571 TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_MODE_ALLNOTESOFF, 0);
572 TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_SUSTAINSW, 0);
573 TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_MODE_RESETALLCTRL, 0);
577 TransmitStandardSysex(_buffer, block_time + 20, MidiSysexMessage::ResetGM);
578 TransmitStandardSysex(_buffer, block_time + 30, MidiSysexMessage::RolandSetReverb);
582 _port->PlayBuffer(_buffer);
586 Sleep(
Clamp((block_time - cur_time) / MS_TO_REFTIME, 5, 1000));
589 static void MidiThreadProc()
591 DEBUG(driver, 2,
"DMusic: Entering playback thread");
593 REFERENCE_TIME last_volume_time = 0;
594 REFERENCE_TIME block_time = 0;
603 IReferenceClock *clock;
604 _port->GetLatencyClock(&clock);
606 REFERENCE_TIME cur_time;
607 clock->GetTime(&cur_time);
609 _port->PlayBuffer(_buffer);
612 DWORD next_timeout = 1000;
615 DWORD wfso = WaitForSingleObject(_thread_event, next_timeout);
617 if (_playback.shutdown) {
618 _playback.playing =
false;
622 if (_playback.do_stop) {
623 DEBUG(driver, 2,
"DMusic thread: Stopping playback");
626 clock->GetTime(&cur_time);
627 TransmitNotesOff(_buffer, block_time, cur_time);
629 _playback.playing =
false;
630 _playback.do_stop =
false;
636 if (wfso == WAIT_OBJECT_0) {
637 if (_playback.do_start) {
638 DEBUG(driver, 2,
"DMusic thread: Starting playback");
641 std::lock_guard<std::mutex>
lock(_thread_mutex);
643 current_file.
MoveFrom(_playback.next_file);
644 std::swap(_playback.next_segment, current_segment);
645 current_segment.start_block = 0;
647 _playback.playing =
true;
648 _playback.do_start =
false;
652 clock->GetTime(&cur_time);
653 TransmitNotesOff(_buffer, block_time, cur_time);
658 clock->GetTime(&playback_start_time);
659 playback_start_time += _playback.preload_time * MS_TO_REFTIME;
663 if (_playback.playing) {
665 if (current_segment.start > 0 && current_block == 0 && current_segment.start_block == 0) {
669 size_t preload_bytes = 0;
670 for (
size_t bl = 0; bl < current_file.
blocks.size(); bl++) {
672 preload_bytes += block.
data.size();
673 if (block.
ticktime >= current_segment.start) {
674 if (current_segment.loop) {
675 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);
676 current_segment.start_block = bl;
682 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);
683 playback_start_time -= block.
realtime * MIDITIME_TO_REFTIME;
691 REFERENCE_TIME current_time;
692 clock->GetTime(¤t_time);
695 if (current_volume != _playback.new_volume) {
696 if (current_time - last_volume_time > 10 * MS_TO_REFTIME) {
697 DEBUG(driver, 2,
"DMusic thread: volume change");
698 current_volume = _playback.new_volume;
699 last_volume_time = current_time;
700 for (
int ch = 0; ch < 16; ch++) {
701 int vol = ScaleVolume(channel_volumes[ch], current_volume);
702 TransmitChannelMsg(_buffer, block_time + 1, MIDIST_CONTROLLER | ch, MIDICT_CHANVOLUME, vol);
704 _port->PlayBuffer(_buffer);
709 while (current_block < current_file.
blocks.size()) {
713 if (current_segment.end > 0 && block.
ticktime >= current_segment.end) {
714 if (current_segment.loop) {
715 DEBUG(driver, 2,
"DMusic thread: Looping song");
716 current_block = current_segment.start_block;
717 playback_start_time = current_time - current_file.
blocks[
current_block].realtime * MIDITIME_TO_REFTIME;
719 _playback.do_stop =
true;
726 if (block.
realtime * MIDITIME_TO_REFTIME > playback_time + 3 *_playback.preload_time * MS_TO_REFTIME) {
728 next_timeout =
Clamp(((int64)block.
realtime * MIDITIME_TO_REFTIME - playback_time) / MS_TO_REFTIME - _playback.preload_time, 0, 1000);
729 DEBUG(driver, 9,
"DMusic thread: Next event in %lu ms (music %u, ref " OTTD_PRINTF64
")", next_timeout, block.
realtime * MIDITIME_TO_REFTIME, playback_time);
734 block_time = playback_start_time + block.
realtime * MIDITIME_TO_REFTIME;
735 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));
737 const byte *data = block.
data.data();
738 size_t remaining = block.
data.size();
739 byte last_status = 0;
740 while (remaining > 0) {
743 byte status = data[0];
745 last_status = status;
749 status = last_status;
751 switch (status & 0xF0) {
753 case MIDIST_CHANPRESS:
755 TransmitChannelMsg(_buffer, block_time, status, data[0]);
761 case MIDIST_POLYPRESS:
762 case MIDIST_PITCHBEND:
764 TransmitChannelMsg(_buffer, block_time, status, data[0], data[1]);
768 case MIDIST_CONTROLLER:
770 if (data[0] == MIDICT_CHANVOLUME) {
772 channel_volumes[status & 0x0F] = data[1];
773 int vol = ScaleVolume(data[1], current_volume);
774 TransmitChannelMsg(_buffer, block_time, status, data[0], vol);
777 TransmitChannelMsg(_buffer, block_time, status, data[0], data[1]);
786 TransmitSysex(_buffer, block_time, data, remaining);
788 case MIDIST_TC_QFRAME:
793 case MIDIST_SONGPOSPTR:
808 DWORD used_buffer = 0;
809 _buffer->GetUsedBytes(&used_buffer);
810 if (used_buffer > 0) {
811 _port->PlayBuffer(_buffer);
816 if (current_block == current_file.
blocks.size()) {
817 if (current_segment.loop) {
818 current_block = current_segment.start_block;
819 playback_start_time = block_time - current_file.
blocks[
current_block].realtime * MIDITIME_TO_REFTIME;
821 _playback.do_stop =
true;
828 DEBUG(driver, 2,
"DMusic: Exiting playback thread");
831 clock->GetTime(&cur_time);
832 TransmitNotesOff(_buffer, block_time, cur_time);
833 Sleep(_playback.preload_time * 4);
838 static void * DownloadArticulationData(
int base_offset,
void *data,
const std::vector<CONNECTION> &artic)
840 DMUS_ARTICULATION2 *art = (DMUS_ARTICULATION2 *)data;
841 art->ulArtIdx = base_offset + 1;
842 art->ulFirstExtCkIdx = 0;
843 art->ulNextArtIdx = 0;
845 CONNECTIONLIST *con_list = (CONNECTIONLIST *)(art + 1);
846 con_list->cbSize =
sizeof(CONNECTIONLIST);
847 con_list->cConnections = (ULONG)artic.size();
848 MemCpyT((CONNECTION *)(con_list + 1), &artic.front(), artic.size());
850 return (CONNECTION *)(con_list + 1) + artic.size();
853 static const char *LoadDefaultDLSFile(
const char *user_dls)
857 caps.dwSize =
sizeof(DMUS_PORTCAPS);
858 _port->GetCaps(&caps);
861 if ((caps.dwFlags & (DMUS_PC_DLS | DMUS_PC_DLS2)) != 0 && (caps.dwFlags & DMUS_PC_GMINHARDWARE) == 0) {
864 if (user_dls ==
nullptr) {
867 if (SUCCEEDED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(
"Software\\Microsoft\\DirectMusic"), 0, KEY_READ, &hkDM))) {
868 TCHAR dls_path[MAX_PATH];
869 DWORD buf_size =
sizeof(dls_path);
870 if (SUCCEEDED(RegQueryValueEx(hkDM, _T(
"GMFilePath"),
nullptr,
nullptr, (LPBYTE)dls_path, &buf_size))) {
871 TCHAR expand_path[MAX_PATH * 2];
872 ExpandEnvironmentStrings(dls_path, expand_path,
lengthof(expand_path));
873 if (!dls_file.LoadFile(expand_path))
DEBUG(driver, 1,
"Failed to load default GM DLS file from registry");
879 if (dls_file.instruments.size() == 0) {
880 static const TCHAR *DLS_GM_FILE = _T(
"%windir%\\System32\\drivers\\gm.dls");
881 TCHAR path[MAX_PATH];
882 ExpandEnvironmentStrings(DLS_GM_FILE, path,
lengthof(path));
884 if (!dls_file.LoadFile(path))
return "Can't load GM DLS collection";
887 if (!dls_file.LoadFile(
OTTD2FS(user_dls)))
return "Can't load GM DLS collection";
891 IDirectMusicPortDownload *download_port =
nullptr;
892 if (FAILED(_port->QueryInterface(IID_IDirectMusicPortDownload, (LPVOID *)&download_port)))
return "Can't get download port";
894 DWORD dlid_wave = 0, dlid_inst = 0;
895 if (FAILED(download_port->GetDLId(&dlid_wave, (DWORD)dls_file.waves.size())) || FAILED(download_port->GetDLId(&dlid_inst, (DWORD)dls_file.instruments.size()))) {
896 download_port->Release();
897 return "Can't get enough DLS ids";
901 download_port->GetAppend(&dwAppend);
904 for (DWORD i = 0; i < dls_file.waves.size(); i++) {
905 IDirectMusicDownload *dl_wave =
nullptr;
906 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))) {
907 download_port->Release();
908 return "Can't allocate wave download buffer";
913 if (FAILED(dl_wave->GetBuffer((LPVOID *)&wave, &wave_size))) {
915 download_port->Release();
916 return "Can't get wave download buffer";
921 wave->dlInfo.dwDLType = DMUS_DOWNLOADINFO_WAVE;
922 wave->dlInfo.cbSize = wave_size;
923 wave->dlInfo.dwDLId = dlid_wave + i;
924 wave->dlInfo.dwNumOffsetTableEntries = 2;
925 wave->ulOffsetTable[0] = offsetof(WAVE_DOWNLOAD, dmWave);
926 wave->ulOffsetTable[1] = offsetof(WAVE_DOWNLOAD, dmWaveData);
927 wave->dmWave.ulWaveDataIdx = 1;
928 MemCpyT((PCMWAVEFORMAT *)&wave->dmWave.WaveformatEx, &dls_file.waves[i].fmt, 1);
929 wave->dmWaveData.cbSize = (DWORD)dls_file.waves[i].data.size();
930 MemCpyT(wave->dmWaveData.byData, &dls_file.waves[i].data[0], dls_file.waves[i].data.size());
932 _dls_downloads.push_back(dl_wave);
933 if (FAILED(download_port->Download(dl_wave))) {
934 download_port->Release();
935 return "Downloading DLS wave failed";
940 for (DWORD i = 0; i < dls_file.instruments.size(); i++) {
941 DWORD offsets = 1 + (DWORD)dls_file.instruments[i].regions.size();
944 size_t i_size =
sizeof(DMUS_DOWNLOADINFO) +
sizeof(DMUS_INSTRUMENT);
945 if (dls_file.instruments[i].articulators.size() > 0) {
948 i_size +=
sizeof(DMUS_ARTICULATION2) +
sizeof(CONNECTIONLIST) +
sizeof(CONNECTION) * dls_file.instruments[i].articulators.size();
951 for (std::vector<DLSFile::DLSRegion>::iterator rgn = dls_file.instruments[i].regions.begin(); rgn != dls_file.instruments[i].regions.end(); rgn++) {
952 if (rgn->articulators.size() > 0) {
954 i_size +=
sizeof(DMUS_ARTICULATION2) +
sizeof(CONNECTIONLIST) +
sizeof(CONNECTION) * rgn->articulators.size();
959 if (rgn->wave_sample.cbSize != 0) {
960 i_size +=
sizeof(DMUS_REGION) -
sizeof(DMUS_REGION::WLOOP) +
sizeof(WLOOP) * rgn->wave_loops.size();
962 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();
966 i_size += offsets *
sizeof(ULONG);
969 IDirectMusicDownload *dl_inst =
nullptr;
970 if (FAILED(download_port->AllocateBuffer((DWORD)i_size, &dl_inst))) {
971 download_port->Release();
972 return "Can't allocate instrument download buffer";
977 if (FAILED(dl_inst->GetBuffer((LPVOID *)&instrument, &inst_size))) {
979 download_port->Release();
980 return "Can't get instrument download buffer";
982 char *inst_base = (
char *)instrument;
985 DMUS_DOWNLOADINFO *d_info = (DMUS_DOWNLOADINFO *)instrument;
986 d_info->dwDLType = DMUS_DOWNLOADINFO_INSTRUMENT2;
987 d_info->cbSize = inst_size;
988 d_info->dwDLId = dlid_inst + i;
989 d_info->dwNumOffsetTableEntries = offsets;
990 instrument = d_info + 1;
993 ULONG *offset_table = (ULONG *)instrument;
994 instrument = offset_table + offsets;
998 DMUS_INSTRUMENT *inst_data = (DMUS_INSTRUMENT *)instrument;
1000 offset_table[last_offset++] = (
char *)inst_data - inst_base;
1001 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);
1002 instrument = inst_data + 1;
1005 if (dls_file.instruments[i].articulators.size() > 0) {
1006 inst_data->ulGlobalArtIdx = last_offset;
1007 offset_table[last_offset++] = (
char *)instrument - inst_base;
1008 offset_table[last_offset++] = (
char *)instrument +
sizeof(DMUS_ARTICULATION2) - inst_base;
1010 instrument = DownloadArticulationData(inst_data->ulGlobalArtIdx, instrument, dls_file.instruments[i].articulators);
1011 assert((
char *)instrument - inst_base <= (ptrdiff_t)inst_size);
1015 inst_data->ulFirstRegionIdx = last_offset;
1016 for (uint j = 0; j < dls_file.instruments[i].regions.size(); j++) {
1017 DLSFile::DLSRegion &rgn = dls_file.instruments[i].regions[j];
1019 DMUS_REGION *inst_region = (DMUS_REGION *)instrument;
1020 offset_table[last_offset++] = (
char *)inst_region - inst_base;
1021 inst_region->RangeKey = rgn.hdr.RangeKey;
1022 inst_region->RangeVelocity = rgn.hdr.RangeVelocity;
1023 inst_region->fusOptions = rgn.hdr.fusOptions;
1024 inst_region->usKeyGroup = rgn.hdr.usKeyGroup;
1025 inst_region->ulFirstExtCkIdx = 0;
1027 ULONG wave_id = dls_file.pool_cues[rgn.wave.ulTableIndex].ulOffset;
1028 inst_region->WaveLink = rgn.wave;
1029 inst_region->WaveLink.ulTableIndex = wave_id + dlid_wave;
1032 if (rgn.wave_sample.cbSize != 0) {
1033 inst_region->WSMP = rgn.wave_sample;
1034 if (rgn.wave_loops.size() > 0)
MemCpyT(inst_region->WLOOP, &rgn.wave_loops.front(), rgn.wave_loops.size());
1036 instrument = (
char *)(inst_region + 1) -
sizeof(DMUS_REGION::WLOOP) +
sizeof(WLOOP) * rgn.wave_loops.size();
1038 inst_region->WSMP = rgn.wave_sample;
1039 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());
1041 instrument = (
char *)(inst_region + 1) -
sizeof(DMUS_REGION::WLOOP) +
sizeof(WLOOP) * dls_file.waves[wave_id].wave_loops.size();
1045 if (rgn.articulators.size() > 0) {
1046 inst_region->ulRegionArtIdx = last_offset;
1047 offset_table[last_offset++] = (
char *)instrument - inst_base;
1048 offset_table[last_offset++] = (
char *)instrument +
sizeof(DMUS_ARTICULATION2) - inst_base;
1050 instrument = DownloadArticulationData(inst_region->ulRegionArtIdx, instrument, rgn.articulators);
1052 inst_region->ulRegionArtIdx = 0;
1054 assert((
char *)instrument - inst_base <= (ptrdiff_t)inst_size);
1057 inst_region->ulNextRegionIdx = j < dls_file.instruments[i].regions.size() - 1 ? last_offset : 0;
1060 _dls_downloads.push_back(dl_inst);
1061 if (FAILED(download_port->Download(dl_inst))) {
1062 download_port->Release();
1063 return "Downloading DLS instrument failed";
1067 download_port->Release();
1077 if (FAILED(CoInitializeEx(
nullptr, COINITBASE_MULTITHREADED)))
return "COM initialization failed";
1080 if (FAILED(CoCreateInstance(
1087 return "Failed to create the music object";
1091 if (FAILED(_music->SetDirectSound(
nullptr,
nullptr)))
return "Can't set DirectSound interface";
1098 if (_debug_driver_level > 0) {
1100 char desc[DMUS_MAX_DESCRIPTION];
1104 caps.dwSize =
sizeof(DMUS_PORTCAPS);
1106 DEBUG(driver, 1,
"Detected DirectMusic ports:");
1107 for (
int i = 0; _music->EnumPort(i, &caps) == S_OK; i++) {
1108 if (caps.dwClass == DMUS_PC_OUTPUTCLASS) {
1120 caps.dwSize =
sizeof(DMUS_PORTCAPS);
1121 if (FAILED(_music->EnumPort(pIdx, &caps)))
return "Supplied port parameter is not a valid port";
1122 if (caps.dwClass != DMUS_PC_OUTPUTCLASS)
return "Supplied port parameter is not an output port";
1123 guidPort = caps.guidPort;
1125 if (FAILED(_music->GetDefaultPort(&guidPort)))
return "Can't query default music port";
1129 DMUS_PORTPARAMS params;
1131 params.dwSize =
sizeof(DMUS_PORTPARAMS);
1132 params.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
1133 params.dwChannelGroups = 1;
1134 if (FAILED(_music->CreatePort(guidPort, ¶ms, &_port,
nullptr)))
return "Failed to create port";
1136 if (FAILED(_port->Activate(TRUE)))
return "Failed to activate port";
1139 DMUS_BUFFERDESC desc;
1141 desc.dwSize =
sizeof(DMUS_BUFFERDESC);
1142 desc.guidBufferFormat = KSDATAFORMAT_SUBTYPE_DIRECTMUSIC;
1143 desc.cbBuffer = 1024;
1144 if (FAILED(_music->CreateMusicBuffer(&desc, &_buffer,
nullptr)))
return "Failed to create music buffer";
1147 const char *dls = LoadDefaultDLSFile(
GetDriverParam(parm,
"dls"));
1148 if (dls !=
nullptr)
return dls;
1151 _thread_event = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
1152 if (_thread_event ==
nullptr)
return "Can't create thread shutdown event";
1154 if (!
StartNewThread(&_dmusic_thread,
"ottd:dmusic", &MidiThreadProc))
return "Can't create MIDI output thread";
1160 MusicDriver_DMusic::~MusicDriver_DMusic()
1168 if (_dmusic_thread.joinable()) {
1169 _playback.shutdown =
true;
1170 SetEvent(_thread_event);
1171 _dmusic_thread.join();
1175 if (_dls_downloads.size() > 0) {
1176 IDirectMusicPortDownload *download_port =
nullptr;
1177 _port->QueryInterface(IID_IDirectMusicPortDownload, (LPVOID *)&download_port);
1181 for (std::vector<IDirectMusicDownload *>::reverse_iterator i = _dls_downloads.rbegin(); download_port !=
nullptr && i != _dls_downloads.rend(); i++) {
1182 download_port->Unload(*i);
1185 _dls_downloads.clear();
1187 if (download_port !=
nullptr) download_port->Release();
1190 if (_buffer !=
nullptr) {
1195 if (_port !=
nullptr) {
1196 _port->Activate(FALSE);
1201 if (_music !=
nullptr) {
1206 CloseHandle(_thread_event);
1214 std::lock_guard<std::mutex>
lock(_thread_mutex);
1216 if (!_playback.next_file.LoadSong(song))
return;
1220 _playback.next_segment.loop = song.
loop;
1222 _playback.do_start =
true;
1223 SetEvent(_thread_event);
1229 _playback.do_stop =
true;
1230 SetEvent(_thread_event);
1236 return _playback.playing || _playback.do_start;
1242 _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.
bool IsSongPlaying() override
Are we currently playing a song?
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
void StopSong() override
Stop playing the current song.
size_t current_block
next block index to send
int override_start
MIDI ticks to skip over in beginning.
bool playing
flag indicating that playback is active
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 SetVolume(byte vol) override
Set the volume, if possible.
bool StartNewThread(std::thread *thr, const char *name, TFn &&_Fx, TArgs &&... _Ax)
Start a new thread.
std::mutex lock
synchronization for playback status fields
std::vector< byte > data
raw midi data contained in block
byte channel_volumes[16]
last seen volume controller values in raw data
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.
void PlaySong(const MusicSongInfo &song) override
Play a particular song.
bool do_stop
flag for stopping playback at next opportunity
#define lengthof(x)
Return the length of an fixed size array.
void Stop() override
Stop this driver.
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.
const char * Start(const char *const *param) override
Start this driver.
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.
int 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().