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.h" 23 #include "../fileio_func.h" 24 #include "../base_media_base.h" 26 #include "midifile.hpp" 35 #include "../safeguards.h" 38 # pragma comment(lib, "ole32.lib") 41 static const int MS_TO_REFTIME = 1000 * 10;
42 static const int MIDITIME_TO_REFTIME = 10;
45 #define FOURCC_INFO mmioFOURCC('I','N','F','O') 46 #define FOURCC_fmt mmioFOURCC('f','m','t',' ') 47 #define FOURCC_data mmioFOURCC('d','a','t','a') 57 std::vector<WLOOP> wave_loops;
58 std::vector<CONNECTION> articulators;
62 struct DLSInstrument {
65 std::vector<CONNECTION> articulators;
66 std::vector<DLSRegion> regions;
74 std::vector<BYTE> data;
77 std::vector<WLOOP> wave_loops;
80 return this->file_offset == offset;
84 std::vector<DLSInstrument> instruments;
85 std::vector<POOLCUE> pool_cues;
86 std::vector<DLSWave> waves;
89 bool LoadFile(
const TCHAR *file);
93 bool ReadDLSArticulation(FILE *f, DWORD list_length, std::vector<CONNECTION> &out);
95 bool ReadDLSRegionList(FILE *f, DWORD list_length, DLSInstrument &instrument);
97 bool ReadDLSRegion(FILE *f, DWORD list_length, std::vector<DLSRegion> &out);
99 bool ReadDLSInstrumentList(FILE *f, DWORD list_length);
101 bool ReadDLSInstrument(FILE *f, DWORD list_length);
103 bool ReadDLSWaveList(FILE *f, DWORD list_length);
105 bool ReadDLSWave(FILE *f, DWORD list_length,
long offset);
109 PACK_N(
struct ChunkHeader {
115 PACK_N(
struct WAVE_DOWNLOAD {
116 DMUS_DOWNLOADINFO dlInfo;
117 ULONG ulOffsetTable[2];
119 DMUS_WAVEDATA dmWaveData;
142 static std::thread _dmusic_thread;
144 static HANDLE _thread_event =
nullptr;
146 static std::mutex _thread_mutex;
149 static IDirectMusic *_music =
nullptr;
151 static IDirectMusicPort *_port =
nullptr;
153 static IDirectMusicBuffer *_buffer =
nullptr;
155 static std::vector<IDirectMusicDownload *> _dls_downloads;
161 bool DLSFile::ReadDLSArticulation(FILE *f, DWORD list_length, std::vector<CONNECTION> &out)
163 while (list_length > 0) {
165 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
166 list_length -= chunk.length +
sizeof(chunk);
168 if (chunk.type == FOURCC_ART1) {
169 CONNECTIONLIST conns;
170 if (fread(&conns,
sizeof(conns), 1, f) != 1)
return false;
171 fseek(f, conns.cbSize -
sizeof(conns), SEEK_CUR);
174 for (ULONG i = 0; i < conns.cConnections; i++) {
176 if (fread(&con,
sizeof(con), 1, f) != 1)
return false;
180 fseek(f, chunk.length, SEEK_CUR);
187 bool DLSFile::ReadDLSRegion(FILE *f, DWORD list_length, std::vector<DLSRegion> &out)
189 out.push_back(DLSRegion());
190 DLSRegion ®ion = out.back();
193 region.wave_sample.cbSize = 0;
195 while (list_length > 0) {
197 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
198 list_length -= chunk.length +
sizeof(chunk);
200 if (chunk.type == FOURCC_LIST) {
202 if (fread(&chunk.type,
sizeof(chunk.type), 1, f) != 1)
return false;
203 chunk.length -=
sizeof(chunk.type);
206 switch (chunk.type) {
208 if (fread(®ion.hdr,
sizeof(region.hdr), 1, f) != 1)
return false;
212 if (fread(®ion.wave_sample,
sizeof(region.wave_sample), 1, f) != 1)
return false;
213 fseek(f, region.wave_sample.cbSize -
sizeof(region.wave_sample), SEEK_CUR);
216 for (ULONG i = 0; i < region.wave_sample.cSampleLoops; i++) {
218 if (fread(&loop,
sizeof(loop), 1, f) != 1)
return false;
219 region.wave_loops.push_back(loop);
224 if (fread(®ion.wave,
sizeof(region.wave), 1, f) != 1)
return false;
228 if (!this->ReadDLSArticulation(f, chunk.length, region.articulators))
return false;
233 fseek(f, chunk.length, SEEK_CUR);
237 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));
238 fseek(f, chunk.length, SEEK_CUR);
246 bool DLSFile::ReadDLSRegionList(FILE *f, DWORD list_length, DLSInstrument &instrument)
248 while (list_length > 0) {
250 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
251 list_length -= chunk.length +
sizeof(chunk);
253 if (chunk.type == FOURCC_LIST) {
255 if (fread(&list_type,
sizeof(list_type), 1, f) != 1)
return false;
257 if (list_type == FOURCC_RGN) {
258 this->ReadDLSRegion(f, chunk.length -
sizeof(list_type), instrument.regions);
260 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));
261 fseek(f, chunk.length -
sizeof(list_type), SEEK_CUR);
264 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));
265 fseek(f, chunk.length, SEEK_CUR);
272 bool DLSFile::ReadDLSInstrument(FILE *f, DWORD list_length)
274 this->instruments.push_back(DLSInstrument());
275 DLSInstrument &instrument = this->instruments.back();
277 while (list_length > 0) {
279 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
280 list_length -= chunk.length +
sizeof(chunk);
282 if (chunk.type == FOURCC_LIST) {
284 if (fread(&chunk.type,
sizeof(chunk.type), 1, f) != 1)
return false;
285 chunk.length -=
sizeof(chunk.type);
288 switch (chunk.type) {
290 if (fread(&instrument.hdr,
sizeof(instrument.hdr), 1, f) != 1)
return false;
294 if (!this->ReadDLSArticulation(f, chunk.length, instrument.articulators))
return false;
298 if (!this->ReadDLSRegionList(f, chunk.length, instrument))
return false;
303 fseek(f, chunk.length, SEEK_CUR);
307 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));
308 fseek(f, chunk.length, SEEK_CUR);
316 bool DLSFile::ReadDLSInstrumentList(FILE *f, DWORD list_length)
318 while (list_length > 0) {
320 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
321 list_length -= chunk.length +
sizeof(chunk);
323 if (chunk.type == FOURCC_LIST) {
325 if (fread(&list_type,
sizeof(list_type), 1, f) != 1)
return false;
327 if (list_type == FOURCC_INS) {
328 DEBUG(driver, 6,
"DLS: Reading instrument %d", (
int)instruments.size());
330 if (!this->ReadDLSInstrument(f, chunk.length -
sizeof(list_type)))
return false;
332 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));
333 fseek(f, chunk.length -
sizeof(list_type), SEEK_CUR);
336 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));
337 fseek(f, chunk.length, SEEK_CUR);
344 bool DLSFile::ReadDLSWave(FILE *f, DWORD list_length,
long offset)
346 this->waves.push_back(DLSWave());
347 DLSWave &wave = this->waves.back();
351 wave.wave_sample.cbSize =
sizeof(WSMPL);
352 wave.wave_sample.usUnityNote = 60;
353 wave.file_offset = offset;
355 while (list_length > 0) {
357 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
358 list_length -= chunk.length +
sizeof(chunk);
360 if (chunk.type == FOURCC_LIST) {
362 if (fread(&chunk.type,
sizeof(chunk.type), 1, f) != 1)
return false;
363 chunk.length -=
sizeof(chunk.type);
366 switch (chunk.type) {
368 if (fread(&wave.fmt,
sizeof(wave.fmt), 1, f) != 1)
return false;
369 if (chunk.length >
sizeof(wave.fmt)) fseek(f, chunk.length -
sizeof(wave.fmt), SEEK_CUR);
373 if (fread(&wave.wave_sample,
sizeof(wave.wave_sample), 1, f) != 1)
return false;
374 fseek(f, wave.wave_sample.cbSize -
sizeof(wave.wave_sample), SEEK_CUR);
377 for (ULONG i = 0; i < wave.wave_sample.cSampleLoops; i++) {
379 if (fread(&loop,
sizeof(loop), 1, f) != 1)
return false;
380 wave.wave_loops.push_back(loop);
385 wave.data.resize(chunk.length);
386 if (fread(&wave.data[0],
sizeof(BYTE), wave.data.size(), f) != wave.data.size())
return false;
391 fseek(f, chunk.length, SEEK_CUR);
395 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));
396 fseek(f, chunk.length, SEEK_CUR);
404 bool DLSFile::ReadDLSWaveList(FILE *f, DWORD list_length)
406 long base_offset = ftell(f);
408 while (list_length > 0) {
409 long chunk_offset = ftell(f);
412 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
413 list_length -= chunk.length +
sizeof(chunk);
415 if (chunk.type == FOURCC_LIST) {
417 if (fread(&list_type,
sizeof(list_type), 1, f) != 1)
return false;
419 if (list_type == FOURCC_wave) {
420 DEBUG(driver, 6,
"DLS: Reading wave %d", (
int)waves.size());
422 if (!this->ReadDLSWave(f, chunk.length -
sizeof(list_type), chunk_offset - base_offset))
return false;
424 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));
425 fseek(f, chunk.length -
sizeof(list_type), SEEK_CUR);
428 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));
429 fseek(f, chunk.length, SEEK_CUR);
436 bool DLSFile::LoadFile(
const TCHAR *file)
438 DEBUG(driver, 2,
"DMusic: Try to load DLS file %s",
FS2OTTD(file));
440 FILE *f = _tfopen(file, _T(
"rb"));
441 if (f ==
nullptr)
return false;
448 if (fread(&hdr,
sizeof(hdr), 1, f) != 1)
return false;
449 if (fread(&dls_type,
sizeof(dls_type), 1, f) != 1)
return false;
450 if (hdr.type != FOURCC_RIFF || dls_type != FOURCC_DLS)
return false;
452 hdr.length -=
sizeof(FOURCC);
454 DEBUG(driver, 2,
"DMusic: Parsing DLS file");
460 while (hdr.length > 0) {
462 if (fread(&chunk,
sizeof(chunk), 1, f) != 1)
return false;
463 hdr.length -= chunk.length +
sizeof(chunk);
465 if (chunk.type == FOURCC_LIST) {
467 if (fread(&chunk.type,
sizeof(chunk.type), 1, f) != 1)
return false;
468 chunk.length -=
sizeof(chunk.type);
471 switch (chunk.type) {
473 if (fread(&header,
sizeof(header), 1, f) != 1)
return false;
477 if (!this->ReadDLSInstrumentList(f, chunk.length))
return false;
481 if (!this->ReadDLSWaveList(f, chunk.length))
return false;
486 if (fread(&ptbl,
sizeof(ptbl), 1, f) != 1)
return false;
487 fseek(f, ptbl.cbSize -
sizeof(ptbl), SEEK_CUR);
490 for (ULONG i = 0; i < ptbl.cCues; i++) {
492 if (fread(&cue,
sizeof(cue), 1, f) != 1)
return false;
493 this->pool_cues.push_back(cue);
499 fseek(f, chunk.length, SEEK_CUR);
503 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));
504 fseek(f, chunk.length, SEEK_CUR);
510 if (header.cInstruments != this->instruments.size())
return false;
513 for (std::vector<POOLCUE>::iterator cue = this->pool_cues.begin(); cue != this->pool_cues.end(); cue++) {
514 std::vector<DLSWave>::iterator w = std::find(this->waves.begin(), this->waves.end(), cue->ulOffset);
515 if (w != this->waves.end()) {
516 cue->ulOffset = (ULONG)(w - this->waves.begin());
526 static byte ScaleVolume(byte original, byte scale)
528 return original * scale / 127;
531 static void TransmitChannelMsg(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, byte status, byte p1, byte p2 = 0)
533 if (buffer->PackStructured(rt, 0, status | (p1 << 8) | (p2 << 16)) == E_OUTOFMEMORY) {
535 _port->PlayBuffer(buffer);
538 buffer->PackStructured(rt, 0, status | (p1 << 8) | (p2 << 16));
542 static void TransmitSysex(IDirectMusicBuffer *buffer, REFERENCE_TIME rt,
const byte *&msg_start,
size_t &remaining)
545 const byte *msg_end = msg_start;
546 while (*msg_end != MIDIST_ENDSYSEX) msg_end++;
549 if (buffer->PackUnstructured(rt, 0, msg_end - msg_start, const_cast<LPBYTE>(msg_start)) == E_OUTOFMEMORY) {
551 _port->PlayBuffer(buffer);
554 buffer->PackUnstructured(rt, 0, msg_end - msg_start, const_cast<LPBYTE>(msg_start));
558 remaining -= msg_end - msg_start;
562 static void TransmitStandardSysex(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, MidiSysexMessage msg)
565 const byte *data = MidiGetStandardSysexMessage(msg, length);
566 TransmitSysex(buffer, rt, data, length);
570 static void TransmitNotesOff(IDirectMusicBuffer *buffer, REFERENCE_TIME block_time, REFERENCE_TIME cur_time)
572 for (
int ch = 0; ch < 16; ch++) {
573 TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_MODE_ALLNOTESOFF, 0);
574 TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_SUSTAINSW, 0);
575 TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_MODE_RESETALLCTRL, 0);
579 TransmitStandardSysex(_buffer, block_time + 20, MidiSysexMessage::ResetGM);
580 TransmitStandardSysex(_buffer, block_time + 30, MidiSysexMessage::RolandSetReverb);
584 _port->PlayBuffer(_buffer);
588 Sleep(
Clamp((block_time - cur_time) / MS_TO_REFTIME, 5, 1000));
591 static void MidiThreadProc()
593 DEBUG(driver, 2,
"DMusic: Entering playback thread");
595 REFERENCE_TIME last_volume_time = 0;
596 REFERENCE_TIME block_time = 0;
605 IReferenceClock *clock;
606 _port->GetLatencyClock(&clock);
608 REFERENCE_TIME cur_time;
609 clock->GetTime(&cur_time);
611 _port->PlayBuffer(_buffer);
614 DWORD next_timeout = 1000;
617 DWORD wfso = WaitForSingleObject(_thread_event, next_timeout);
619 if (_playback.shutdown) {
620 _playback.playing =
false;
624 if (_playback.do_stop) {
625 DEBUG(driver, 2,
"DMusic thread: Stopping playback");
628 clock->GetTime(&cur_time);
629 TransmitNotesOff(_buffer, block_time, cur_time);
631 _playback.playing =
false;
632 _playback.do_stop =
false;
638 if (wfso == WAIT_OBJECT_0) {
639 if (_playback.do_start) {
640 DEBUG(driver, 2,
"DMusic thread: Starting playback");
643 std::lock_guard<std::mutex>
lock(_thread_mutex);
645 current_file.
MoveFrom(_playback.next_file);
646 std::swap(_playback.next_segment, current_segment);
647 current_segment.start_block = 0;
649 _playback.playing =
true;
650 _playback.do_start =
false;
654 clock->GetTime(&cur_time);
655 TransmitNotesOff(_buffer, block_time, cur_time);
660 clock->GetTime(&playback_start_time);
661 playback_start_time += _playback.preload_time * MS_TO_REFTIME;
665 if (_playback.playing) {
667 if (current_segment.start > 0 && current_block == 0 && current_segment.start_block == 0) {
671 size_t preload_bytes = 0;
672 for (
size_t bl = 0; bl < current_file.
blocks.size(); bl++) {
674 preload_bytes += block.
data.size();
675 if (block.
ticktime >= current_segment.start) {
676 if (current_segment.loop) {
677 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);
678 current_segment.start_block = bl;
684 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);
685 playback_start_time -= block.
realtime * MIDITIME_TO_REFTIME;
693 REFERENCE_TIME current_time;
694 clock->GetTime(¤t_time);
697 if (current_volume != _playback.new_volume) {
698 if (current_time - last_volume_time > 10 * MS_TO_REFTIME) {
699 DEBUG(driver, 2,
"DMusic thread: volume change");
700 current_volume = _playback.new_volume;
701 last_volume_time = current_time;
702 for (
int ch = 0; ch < 16; ch++) {
703 int vol = ScaleVolume(channel_volumes[ch], current_volume);
704 TransmitChannelMsg(_buffer, block_time + 1, MIDIST_CONTROLLER | ch, MIDICT_CHANVOLUME, vol);
706 _port->PlayBuffer(_buffer);
711 while (current_block < current_file.
blocks.size()) {
715 if (current_segment.end > 0 && block.
ticktime >= current_segment.end) {
716 if (current_segment.loop) {
717 DEBUG(driver, 2,
"DMusic thread: Looping song");
718 current_block = current_segment.start_block;
719 playback_start_time = current_time - current_file.
blocks[
current_block].realtime * MIDITIME_TO_REFTIME;
721 _playback.do_stop =
true;
728 if (block.
realtime * MIDITIME_TO_REFTIME > playback_time + 3 *_playback.preload_time * MS_TO_REFTIME) {
730 next_timeout =
Clamp(((int64)block.
realtime * MIDITIME_TO_REFTIME - playback_time) / MS_TO_REFTIME - _playback.preload_time, 0, 1000);
731 DEBUG(driver, 9,
"DMusic thread: Next event in %lu ms (music %u, ref " OTTD_PRINTF64
")", next_timeout, block.
realtime * MIDITIME_TO_REFTIME, playback_time);
736 block_time = playback_start_time + block.
realtime * MIDITIME_TO_REFTIME;
737 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));
739 const byte *data = block.
data.data();
740 size_t remaining = block.
data.size();
741 byte last_status = 0;
742 while (remaining > 0) {
745 byte status = data[0];
747 last_status = status;
751 status = last_status;
753 switch (status & 0xF0) {
755 case MIDIST_CHANPRESS:
757 TransmitChannelMsg(_buffer, block_time, status, data[0]);
763 case MIDIST_POLYPRESS:
764 case MIDIST_PITCHBEND:
766 TransmitChannelMsg(_buffer, block_time, status, data[0], data[1]);
770 case MIDIST_CONTROLLER:
772 if (data[0] == MIDICT_CHANVOLUME) {
774 channel_volumes[status & 0x0F] = data[1];
775 int vol = ScaleVolume(data[1], current_volume);
776 TransmitChannelMsg(_buffer, block_time, status, data[0], vol);
779 TransmitChannelMsg(_buffer, block_time, status, data[0], data[1]);
788 TransmitSysex(_buffer, block_time, data, remaining);
790 case MIDIST_TC_QFRAME:
795 case MIDIST_SONGPOSPTR:
810 DWORD used_buffer = 0;
811 _buffer->GetUsedBytes(&used_buffer);
812 if (used_buffer > 0) {
813 _port->PlayBuffer(_buffer);
818 if (current_block == current_file.
blocks.size()) {
819 if (current_segment.loop) {
820 current_block = current_segment.start_block;
821 playback_start_time = block_time - current_file.
blocks[
current_block].realtime * MIDITIME_TO_REFTIME;
823 _playback.do_stop =
true;
830 DEBUG(driver, 2,
"DMusic: Exiting playback thread");
833 clock->GetTime(&cur_time);
834 TransmitNotesOff(_buffer, block_time, cur_time);
835 Sleep(_playback.preload_time * 4);
840 static void * DownloadArticulationData(
int base_offset,
void *data,
const std::vector<CONNECTION> &artic)
842 DMUS_ARTICULATION2 *art = (DMUS_ARTICULATION2 *)data;
843 art->ulArtIdx = base_offset + 1;
844 art->ulFirstExtCkIdx = 0;
845 art->ulNextArtIdx = 0;
847 CONNECTIONLIST *con_list = (CONNECTIONLIST *)(art + 1);
848 con_list->cbSize =
sizeof(CONNECTIONLIST);
849 con_list->cConnections = (ULONG)artic.size();
850 MemCpyT((CONNECTION *)(con_list + 1), &artic.front(), artic.size());
852 return (CONNECTION *)(con_list + 1) + artic.size();
855 static const char *LoadDefaultDLSFile(
const char *user_dls)
859 caps.dwSize =
sizeof(DMUS_PORTCAPS);
860 _port->GetCaps(&caps);
863 if ((caps.dwFlags & (DMUS_PC_DLS | DMUS_PC_DLS2)) != 0 && (caps.dwFlags & DMUS_PC_GMINHARDWARE) == 0) {
866 if (user_dls ==
nullptr) {
869 if (SUCCEEDED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(
"Software\\Microsoft\\DirectMusic"), 0, KEY_READ, &hkDM))) {
870 TCHAR dls_path[MAX_PATH];
871 DWORD buf_size =
sizeof(dls_path);
872 if (SUCCEEDED(RegQueryValueEx(hkDM, _T(
"GMFilePath"),
nullptr,
nullptr, (LPBYTE)dls_path, &buf_size))) {
873 TCHAR expand_path[MAX_PATH * 2];
874 ExpandEnvironmentStrings(dls_path, expand_path,
lengthof(expand_path));
875 if (!dls_file.LoadFile(expand_path))
DEBUG(driver, 1,
"Failed to load default GM DLS file from registry");
881 if (dls_file.instruments.size() == 0) {
882 static const TCHAR *DLS_GM_FILE = _T(
"%windir%\\System32\\drivers\\gm.dls");
883 TCHAR path[MAX_PATH];
884 ExpandEnvironmentStrings(DLS_GM_FILE, path,
lengthof(path));
886 if (!dls_file.LoadFile(path))
return "Can't load GM DLS collection";
889 if (!dls_file.LoadFile(
OTTD2FS(user_dls)))
return "Can't load GM DLS collection";
893 IDirectMusicPortDownload *download_port =
nullptr;
894 if (FAILED(_port->QueryInterface(IID_IDirectMusicPortDownload, (LPVOID *)&download_port)))
return "Can't get download port";
896 DWORD dlid_wave = 0, dlid_inst = 0;
897 if (FAILED(download_port->GetDLId(&dlid_wave, (DWORD)dls_file.waves.size())) || FAILED(download_port->GetDLId(&dlid_inst, (DWORD)dls_file.instruments.size()))) {
898 download_port->Release();
899 return "Can't get enough DLS ids";
903 download_port->GetAppend(&dwAppend);
906 for (DWORD i = 0; i < dls_file.waves.size(); i++) {
907 IDirectMusicDownload *dl_wave =
nullptr;
908 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))) {
909 download_port->Release();
910 return "Can't allocate wave download buffer";
915 if (FAILED(dl_wave->GetBuffer((LPVOID *)&wave, &wave_size))) {
917 download_port->Release();
918 return "Can't get wave download buffer";
923 wave->dlInfo.dwDLType = DMUS_DOWNLOADINFO_WAVE;
924 wave->dlInfo.cbSize = wave_size;
925 wave->dlInfo.dwDLId = dlid_wave + i;
926 wave->dlInfo.dwNumOffsetTableEntries = 2;
927 wave->ulOffsetTable[0] = offsetof(WAVE_DOWNLOAD, dmWave);
928 wave->ulOffsetTable[1] = offsetof(WAVE_DOWNLOAD, dmWaveData);
929 wave->dmWave.ulWaveDataIdx = 1;
930 MemCpyT((PCMWAVEFORMAT *)&wave->dmWave.WaveformatEx, &dls_file.waves[i].fmt, 1);
931 wave->dmWaveData.cbSize = (DWORD)dls_file.waves[i].data.size();
932 MemCpyT(wave->dmWaveData.byData, &dls_file.waves[i].data[0], dls_file.waves[i].data.size());
934 _dls_downloads.push_back(dl_wave);
935 if (FAILED(download_port->Download(dl_wave))) {
936 download_port->Release();
937 return "Downloading DLS wave failed";
942 for (DWORD i = 0; i < dls_file.instruments.size(); i++) {
943 DWORD offsets = 1 + (DWORD)dls_file.instruments[i].regions.size();
946 size_t i_size =
sizeof(DMUS_DOWNLOADINFO) +
sizeof(DMUS_INSTRUMENT);
947 if (dls_file.instruments[i].articulators.size() > 0) {
950 i_size +=
sizeof(DMUS_ARTICULATION2) +
sizeof(CONNECTIONLIST) +
sizeof(CONNECTION) * dls_file.instruments[i].articulators.size();
953 for (std::vector<DLSFile::DLSRegion>::iterator rgn = dls_file.instruments[i].regions.begin(); rgn != dls_file.instruments[i].regions.end(); rgn++) {
954 if (rgn->articulators.size() > 0) {
956 i_size +=
sizeof(DMUS_ARTICULATION2) +
sizeof(CONNECTIONLIST) +
sizeof(CONNECTION) * rgn->articulators.size();
961 if (rgn->wave_sample.cbSize != 0) {
962 i_size +=
sizeof(DMUS_REGION) -
sizeof(DMUS_REGION::WLOOP) +
sizeof(WLOOP) * rgn->wave_loops.size();
964 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();
968 i_size += offsets *
sizeof(ULONG);
971 IDirectMusicDownload *dl_inst =
nullptr;
972 if (FAILED(download_port->AllocateBuffer((DWORD)i_size, &dl_inst))) {
973 download_port->Release();
974 return "Can't allocate instrument download buffer";
979 if (FAILED(dl_inst->GetBuffer((LPVOID *)&instrument, &inst_size))) {
981 download_port->Release();
982 return "Can't get instrument download buffer";
984 char *inst_base = (
char *)instrument;
987 DMUS_DOWNLOADINFO *d_info = (DMUS_DOWNLOADINFO *)instrument;
988 d_info->dwDLType = DMUS_DOWNLOADINFO_INSTRUMENT2;
989 d_info->cbSize = inst_size;
990 d_info->dwDLId = dlid_inst + i;
991 d_info->dwNumOffsetTableEntries = offsets;
992 instrument = d_info + 1;
995 ULONG *offset_table = (ULONG *)instrument;
996 instrument = offset_table + offsets;
1000 DMUS_INSTRUMENT *inst_data = (DMUS_INSTRUMENT *)instrument;
1002 offset_table[last_offset++] = (
char *)inst_data - inst_base;
1003 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);
1004 instrument = inst_data + 1;
1007 if (dls_file.instruments[i].articulators.size() > 0) {
1008 inst_data->ulGlobalArtIdx = last_offset;
1009 offset_table[last_offset++] = (
char *)instrument - inst_base;
1010 offset_table[last_offset++] = (
char *)instrument +
sizeof(DMUS_ARTICULATION2) - inst_base;
1012 instrument = DownloadArticulationData(inst_data->ulGlobalArtIdx, instrument, dls_file.instruments[i].articulators);
1013 assert((
char *)instrument - inst_base <= (ptrdiff_t)inst_size);
1017 inst_data->ulFirstRegionIdx = last_offset;
1018 for (uint j = 0; j < dls_file.instruments[i].regions.size(); j++) {
1019 DLSFile::DLSRegion &rgn = dls_file.instruments[i].regions[j];
1021 DMUS_REGION *inst_region = (DMUS_REGION *)instrument;
1022 offset_table[last_offset++] = (
char *)inst_region - inst_base;
1023 inst_region->RangeKey = rgn.hdr.RangeKey;
1024 inst_region->RangeVelocity = rgn.hdr.RangeVelocity;
1025 inst_region->fusOptions = rgn.hdr.fusOptions;
1026 inst_region->usKeyGroup = rgn.hdr.usKeyGroup;
1027 inst_region->ulFirstExtCkIdx = 0;
1029 ULONG wave_id = dls_file.pool_cues[rgn.wave.ulTableIndex].ulOffset;
1030 inst_region->WaveLink = rgn.wave;
1031 inst_region->WaveLink.ulTableIndex = wave_id + dlid_wave;
1034 if (rgn.wave_sample.cbSize != 0) {
1035 inst_region->WSMP = rgn.wave_sample;
1036 if (rgn.wave_loops.size() > 0)
MemCpyT(inst_region->WLOOP, &rgn.wave_loops.front(), rgn.wave_loops.size());
1038 instrument = (
char *)(inst_region + 1) -
sizeof(DMUS_REGION::WLOOP) +
sizeof(WLOOP) * rgn.wave_loops.size();
1040 inst_region->WSMP = rgn.wave_sample;
1041 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());
1043 instrument = (
char *)(inst_region + 1) -
sizeof(DMUS_REGION::WLOOP) +
sizeof(WLOOP) * dls_file.waves[wave_id].wave_loops.size();
1047 if (rgn.articulators.size() > 0) {
1048 inst_region->ulRegionArtIdx = last_offset;
1049 offset_table[last_offset++] = (
char *)instrument - inst_base;
1050 offset_table[last_offset++] = (
char *)instrument +
sizeof(DMUS_ARTICULATION2) - inst_base;
1052 instrument = DownloadArticulationData(inst_region->ulRegionArtIdx, instrument, rgn.articulators);
1054 inst_region->ulRegionArtIdx = 0;
1056 assert((
char *)instrument - inst_base <= (ptrdiff_t)inst_size);
1059 inst_region->ulNextRegionIdx = j < dls_file.instruments[i].regions.size() - 1 ? last_offset : 0;
1062 _dls_downloads.push_back(dl_inst);
1063 if (FAILED(download_port->Download(dl_inst))) {
1064 download_port->Release();
1065 return "Downloading DLS instrument failed";
1069 download_port->Release();
1079 if (FAILED(CoInitializeEx(
nullptr, COINITBASE_MULTITHREADED)))
return "COM initialization failed";
1082 if (FAILED(CoCreateInstance(
1089 return "Failed to create the music object";
1093 if (FAILED(_music->SetDirectSound(
nullptr,
nullptr)))
return "Can't set DirectSound interface";
1100 if (_debug_driver_level > 0) {
1102 char desc[DMUS_MAX_DESCRIPTION];
1106 caps.dwSize =
sizeof(DMUS_PORTCAPS);
1108 DEBUG(driver, 1,
"Detected DirectMusic ports:");
1109 for (
int i = 0; _music->EnumPort(i, &caps) == S_OK; i++) {
1110 if (caps.dwClass == DMUS_PC_OUTPUTCLASS) {
1122 caps.dwSize =
sizeof(DMUS_PORTCAPS);
1123 if (FAILED(_music->EnumPort(pIdx, &caps)))
return "Supplied port parameter is not a valid port";
1124 if (caps.dwClass != DMUS_PC_OUTPUTCLASS)
return "Supplied port parameter is not an output port";
1125 guidPort = caps.guidPort;
1127 if (FAILED(_music->GetDefaultPort(&guidPort)))
return "Can't query default music port";
1131 DMUS_PORTPARAMS params;
1133 params.dwSize =
sizeof(DMUS_PORTPARAMS);
1134 params.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
1135 params.dwChannelGroups = 1;
1136 if (FAILED(_music->CreatePort(guidPort, ¶ms, &_port,
nullptr)))
return "Failed to create port";
1138 if (FAILED(_port->Activate(TRUE)))
return "Failed to activate port";
1141 DMUS_BUFFERDESC desc;
1143 desc.dwSize =
sizeof(DMUS_BUFFERDESC);
1144 desc.guidBufferFormat = KSDATAFORMAT_SUBTYPE_DIRECTMUSIC;
1145 desc.cbBuffer = 1024;
1146 if (FAILED(_music->CreateMusicBuffer(&desc, &_buffer,
nullptr)))
return "Failed to create music buffer";
1149 const char *dls = LoadDefaultDLSFile(
GetDriverParam(parm,
"dls"));
1150 if (dls !=
nullptr)
return dls;
1153 _thread_event = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
1154 if (_thread_event ==
nullptr)
return "Can't create thread shutdown event";
1156 if (!
StartNewThread(&_dmusic_thread,
"ottd:dmusic", &MidiThreadProc))
return "Can't create MIDI output thread";
1162 MusicDriver_DMusic::~MusicDriver_DMusic()
1170 if (_dmusic_thread.joinable()) {
1171 _playback.shutdown =
true;
1172 SetEvent(_thread_event);
1173 _dmusic_thread.join();
1177 if (_dls_downloads.size() > 0) {
1178 IDirectMusicPortDownload *download_port =
nullptr;
1179 _port->QueryInterface(IID_IDirectMusicPortDownload, (LPVOID *)&download_port);
1183 for (std::vector<IDirectMusicDownload *>::reverse_iterator i = _dls_downloads.rbegin(); download_port !=
nullptr && i != _dls_downloads.rend(); i++) {
1184 download_port->Unload(*i);
1187 _dls_downloads.clear();
1189 if (download_port !=
nullptr) download_port->Release();
1192 if (_buffer !=
nullptr) {
1197 if (_port !=
nullptr) {
1198 _port->Activate(FALSE);
1203 if (_music !=
nullptr) {
1208 CloseHandle(_thread_event);
1216 std::lock_guard<std::mutex>
lock(_thread_mutex);
1218 if (!_playback.next_file.LoadSong(song))
return;
1222 _playback.next_segment.loop = song.
loop;
1224 _playback.do_start =
true;
1225 SetEvent(_thread_event);
1231 _playback.do_stop =
true;
1232 SetEvent(_thread_event);
1238 return _playback.playing || _playback.do_start;
1244 _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().