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,
const byte *&msg_start,
size_t &remaining)
544 const byte *msg_end = msg_start;
545 while (*msg_end != MIDIST_ENDSYSEX) msg_end++;
548 if (buffer->PackUnstructured(rt, 0, msg_end - msg_start, const_cast<LPBYTE>(msg_start)) == E_OUTOFMEMORY) {
550 _port->PlayBuffer(buffer);
553 buffer->PackUnstructured(rt, 0, msg_end - msg_start, const_cast<LPBYTE>(msg_start));
557 remaining -= msg_end - msg_start;
561 static void TransmitStandardSysex(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, MidiSysexMessage msg)
564 const byte *data = MidiGetStandardSysexMessage(msg, length);
565 TransmitSysex(buffer, rt, data, length);
569 static void TransmitNotesOff(IDirectMusicBuffer *buffer, REFERENCE_TIME block_time, REFERENCE_TIME cur_time)
571 for (
int ch = 0; ch < 16; ch++) {
572 TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_MODE_ALLNOTESOFF, 0);
573 TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_SUSTAINSW, 0);
574 TransmitChannelMsg(_buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_MODE_RESETALLCTRL, 0);
578 TransmitStandardSysex(_buffer, block_time + 20, MidiSysexMessage::ResetGM);
579 TransmitStandardSysex(_buffer, block_time + 30, MidiSysexMessage::RolandSetReverb);
583 _port->PlayBuffer(_buffer);
587 Sleep(
Clamp((block_time - cur_time) / MS_TO_REFTIME, 5, 1000));
590 static void MidiThreadProc(
void *)
592 DEBUG(driver, 2,
"DMusic: Entering playback thread");
594 REFERENCE_TIME last_volume_time = 0;
595 REFERENCE_TIME block_time = 0;
604 IReferenceClock *clock;
605 _port->GetLatencyClock(&clock);
607 REFERENCE_TIME cur_time;
608 clock->GetTime(&cur_time);
610 _port->PlayBuffer(_buffer);
613 DWORD next_timeout = 1000;
616 DWORD wfso = WaitForSingleObject(_thread_event, next_timeout);
618 if (_playback.shutdown) {
619 _playback.playing =
false;
623 if (_playback.do_stop) {
624 DEBUG(driver, 2,
"DMusic thread: Stopping playback");
627 clock->GetTime(&cur_time);
628 TransmitNotesOff(_buffer, block_time, cur_time);
630 _playback.playing =
false;
631 _playback.do_stop =
false;
637 if (wfso == WAIT_OBJECT_0) {
638 if (_playback.do_start) {
639 DEBUG(driver, 2,
"DMusic thread: Starting playback");
644 current_file.
MoveFrom(_playback.next_file);
645 std::swap(_playback.next_segment, current_segment);
646 current_segment.start_block = 0;
648 _playback.playing =
true;
649 _playback.do_start =
false;
653 clock->GetTime(&cur_time);
654 TransmitNotesOff(_buffer, block_time, cur_time);
659 clock->GetTime(&playback_start_time);
660 playback_start_time += _playback.preload_time * MS_TO_REFTIME;
664 if (_playback.playing) {
666 if (current_segment.start > 0 && current_block == 0 && current_segment.start_block == 0) {
670 size_t preload_bytes = 0;
671 for (
size_t bl = 0; bl < current_file.
blocks.size(); bl++) {
674 if (block.
ticktime >= current_segment.start) {
675 if (current_segment.loop) {
676 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);
677 current_segment.start_block = bl;
683 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);
684 playback_start_time -= block.
realtime * MIDITIME_TO_REFTIME;
692 REFERENCE_TIME current_time;
693 clock->GetTime(¤t_time);
696 if (current_volume != _playback.new_volume) {
697 if (current_time - last_volume_time > 10 * MS_TO_REFTIME) {
698 DEBUG(driver, 2,
"DMusic thread: volume change");
699 current_volume = _playback.new_volume;
700 last_volume_time = current_time;
701 for (
int ch = 0; ch < 16; ch++) {
702 int vol = ScaleVolume(channel_volumes[ch], current_volume);
703 TransmitChannelMsg(_buffer, block_time + 1, MIDIST_CONTROLLER | ch, MIDICT_CHANVOLUME, vol);
705 _port->PlayBuffer(_buffer);
710 while (current_block < current_file.
blocks.size()) {
714 if (current_segment.end > 0 && block.
ticktime >= current_segment.end) {
715 if (current_segment.loop) {
716 DEBUG(driver, 2,
"DMusic thread: Looping song");
717 current_block = current_segment.start_block;
718 playback_start_time = current_time - current_file.
blocks[
current_block].realtime * MIDITIME_TO_REFTIME;
720 _playback.do_stop =
true;
727 if (block.
realtime * MIDITIME_TO_REFTIME > playback_time + 3 *_playback.preload_time * MS_TO_REFTIME) {
729 next_timeout =
Clamp(((int64)block.
realtime * MIDITIME_TO_REFTIME - playback_time) / MS_TO_REFTIME - _playback.preload_time, 0, 1000);
730 DEBUG(driver, 9,
"DMusic thread: Next event in %lu ms (music %u, ref " OTTD_PRINTF64
")", next_timeout, block.
realtime * MIDITIME_TO_REFTIME, playback_time);
735 block_time = playback_start_time + block.
realtime * MIDITIME_TO_REFTIME;
736 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));
740 byte last_status = 0;
741 while (remaining > 0) {
744 byte status = data[0];
746 last_status = status;
750 status = last_status;
752 switch (status & 0xF0) {
754 case MIDIST_CHANPRESS:
756 TransmitChannelMsg(_buffer, block_time, status, data[0]);
762 case MIDIST_POLYPRESS:
763 case MIDIST_PITCHBEND:
765 TransmitChannelMsg(_buffer, block_time, status, data[0], data[1]);
769 case MIDIST_CONTROLLER:
771 if (data[0] == MIDICT_CHANVOLUME) {
773 channel_volumes[status & 0x0F] = data[1];
774 int vol = ScaleVolume(data[1], current_volume);
775 TransmitChannelMsg(_buffer, block_time, status, data[0], vol);
778 TransmitChannelMsg(_buffer, block_time, status, data[0], data[1]);
787 TransmitSysex(_buffer, block_time, data, remaining);
789 case MIDIST_TC_QFRAME:
794 case MIDIST_SONGPOSPTR:
809 DWORD used_buffer = 0;
810 _buffer->GetUsedBytes(&used_buffer);
811 if (used_buffer > 0) {
812 _port->PlayBuffer(_buffer);
817 if (current_block == current_file.
blocks.size()) {
818 if (current_segment.loop) {
819 current_block = current_segment.start_block;
820 playback_start_time = block_time - current_file.
blocks[
current_block].realtime * MIDITIME_TO_REFTIME;
822 _playback.do_stop =
true;
829 DEBUG(driver, 2,
"DMusic: Exiting playback thread");
832 clock->GetTime(&cur_time);
833 TransmitNotesOff(_buffer, block_time, cur_time);
834 Sleep(_playback.preload_time * 4);
839 static void * DownloadArticulationData(
int base_offset,
void *data,
const std::vector<CONNECTION> &artic)
841 DMUS_ARTICULATION2 *art = (DMUS_ARTICULATION2 *)data;
842 art->ulArtIdx = base_offset + 1;
843 art->ulFirstExtCkIdx = 0;
844 art->ulNextArtIdx = 0;
846 CONNECTIONLIST *con_list = (CONNECTIONLIST *)(art + 1);
847 con_list->cbSize =
sizeof(CONNECTIONLIST);
848 con_list->cConnections = (ULONG)artic.size();
849 MemCpyT((CONNECTION *)(con_list + 1), &artic.front(), artic.size());
851 return (CONNECTION *)(con_list + 1) + artic.size();
854 static const char *LoadDefaultDLSFile(
const char *user_dls)
858 caps.dwSize =
sizeof(DMUS_PORTCAPS);
859 _port->GetCaps(&caps);
862 if ((caps.dwFlags & (DMUS_PC_DLS | DMUS_PC_DLS2)) != 0 && (caps.dwFlags & DMUS_PC_GMINHARDWARE) == 0) {
865 if (user_dls == NULL) {
868 if (SUCCEEDED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(
"Software\\Microsoft\\DirectMusic"), 0, KEY_READ, &hkDM))) {
869 TCHAR dls_path[MAX_PATH];
870 DWORD buf_size =
sizeof(dls_path);
871 if (SUCCEEDED(RegQueryValueEx(hkDM, _T(
"GMFilePath"), NULL, NULL, (LPBYTE)dls_path, &buf_size))) {
872 TCHAR expand_path[MAX_PATH * 2];
873 ExpandEnvironmentStrings(dls_path, expand_path,
lengthof(expand_path));
874 if (!dls_file.LoadFile(expand_path))
DEBUG(driver, 1,
"Failed to load default GM DLS file from registry");
880 if (dls_file.instruments.size() == 0) {
881 static const TCHAR *DLS_GM_FILE = _T(
"%windir%\\System32\\drivers\\gm.dls");
882 TCHAR path[MAX_PATH];
883 ExpandEnvironmentStrings(DLS_GM_FILE, path,
lengthof(path));
885 if (!dls_file.LoadFile(path))
return "Can't load GM DLS collection";
888 if (!dls_file.LoadFile(
OTTD2FS(user_dls)))
return "Can't load GM DLS collection";
892 IDirectMusicPortDownload *download_port = NULL;
893 if (FAILED(_port->QueryInterface(IID_IDirectMusicPortDownload, (LPVOID *)&download_port)))
return "Can't get download port";
895 DWORD dlid_wave = 0, dlid_inst = 0;
896 if (FAILED(download_port->GetDLId(&dlid_wave, (DWORD)dls_file.waves.size())) || FAILED(download_port->GetDLId(&dlid_inst, (DWORD)dls_file.instruments.size()))) {
897 download_port->Release();
898 return "Can't get enough DLS ids";
902 download_port->GetAppend(&dwAppend);
905 for (DWORD i = 0; i < dls_file.waves.size(); i++) {
906 IDirectMusicDownload *dl_wave = NULL;
907 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))) {
908 download_port->Release();
909 return "Can't allocate wave download buffer";
914 if (FAILED(dl_wave->GetBuffer((LPVOID *)&wave, &wave_size))) {
916 download_port->Release();
917 return "Can't get wave download buffer";
922 wave->dlInfo.dwDLType = DMUS_DOWNLOADINFO_WAVE;
923 wave->dlInfo.cbSize = wave_size;
924 wave->dlInfo.dwDLId = dlid_wave + i;
925 wave->dlInfo.dwNumOffsetTableEntries = 2;
926 wave->ulOffsetTable[0] = offsetof(WAVE_DOWNLOAD, dmWave);
927 wave->ulOffsetTable[1] = offsetof(WAVE_DOWNLOAD, dmWaveData);
928 wave->dmWave.ulWaveDataIdx = 1;
929 MemCpyT((PCMWAVEFORMAT *)&wave->dmWave.WaveformatEx, &dls_file.waves[i].fmt, 1);
930 wave->dmWaveData.cbSize = (DWORD)dls_file.waves[i].data.size();
931 MemCpyT(wave->dmWaveData.byData, &dls_file.waves[i].data[0], dls_file.waves[i].data.size());
933 _dls_downloads.push_back(dl_wave);
934 if (FAILED(download_port->Download(dl_wave))) {
935 download_port->Release();
936 return "Downloading DLS wave failed";
941 for (DWORD i = 0; i < dls_file.instruments.size(); i++) {
942 DWORD offsets = 1 + (DWORD)dls_file.instruments[i].regions.size();
945 size_t i_size =
sizeof(DMUS_DOWNLOADINFO) +
sizeof(DMUS_INSTRUMENT);
946 if (dls_file.instruments[i].articulators.size() > 0) {
949 i_size +=
sizeof(DMUS_ARTICULATION2) +
sizeof(CONNECTIONLIST) +
sizeof(CONNECTION) * dls_file.instruments[i].articulators.size();
952 for (std::vector<DLSFile::DLSRegion>::iterator rgn = dls_file.instruments[i].regions.begin(); rgn != dls_file.instruments[i].regions.end(); rgn++) {
953 if (rgn->articulators.size() > 0) {
955 i_size +=
sizeof(DMUS_ARTICULATION2) +
sizeof(CONNECTIONLIST) +
sizeof(CONNECTION) * rgn->articulators.size();
960 if (rgn->wave_sample.cbSize != 0) {
961 i_size +=
sizeof(DMUS_REGION) -
sizeof(DMUS_REGION::WLOOP) +
sizeof(WLOOP) * rgn->wave_loops.size();
963 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();
967 i_size += offsets *
sizeof(ULONG);
970 IDirectMusicDownload *dl_inst = NULL;
971 if (FAILED(download_port->AllocateBuffer((DWORD)i_size, &dl_inst))) {
972 download_port->Release();
973 return "Can't allocate instrument download buffer";
978 if (FAILED(dl_inst->GetBuffer((LPVOID *)&instrument, &inst_size))) {
980 download_port->Release();
981 return "Can't get instrument download buffer";
983 char *inst_base = (
char *)instrument;
986 DMUS_DOWNLOADINFO *d_info = (DMUS_DOWNLOADINFO *)instrument;
987 d_info->dwDLType = DMUS_DOWNLOADINFO_INSTRUMENT2;
988 d_info->cbSize = inst_size;
989 d_info->dwDLId = dlid_inst + i;
990 d_info->dwNumOffsetTableEntries = offsets;
991 instrument = d_info + 1;
994 ULONG *offset_table = (ULONG *)instrument;
995 instrument = offset_table + offsets;
999 DMUS_INSTRUMENT *inst_data = (DMUS_INSTRUMENT *)instrument;
1001 offset_table[last_offset++] = (
char *)inst_data - inst_base;
1002 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);
1003 instrument = inst_data + 1;
1006 if (dls_file.instruments[i].articulators.size() > 0) {
1007 inst_data->ulGlobalArtIdx = last_offset;
1008 offset_table[last_offset++] = (
char *)instrument - inst_base;
1009 offset_table[last_offset++] = (
char *)instrument +
sizeof(DMUS_ARTICULATION2) - inst_base;
1011 instrument = DownloadArticulationData(inst_data->ulGlobalArtIdx, instrument, dls_file.instruments[i].articulators);
1012 assert((
char *)instrument - inst_base <= (ptrdiff_t)inst_size);
1016 inst_data->ulFirstRegionIdx = last_offset;
1017 for (uint j = 0; j < dls_file.instruments[i].regions.size(); j++) {
1018 DLSFile::DLSRegion &rgn = dls_file.instruments[i].regions[j];
1020 DMUS_REGION *inst_region = (DMUS_REGION *)instrument;
1021 offset_table[last_offset++] = (
char *)inst_region - inst_base;
1022 inst_region->RangeKey = rgn.hdr.RangeKey;
1023 inst_region->RangeVelocity = rgn.hdr.RangeVelocity;
1024 inst_region->fusOptions = rgn.hdr.fusOptions;
1025 inst_region->usKeyGroup = rgn.hdr.usKeyGroup;
1026 inst_region->ulFirstExtCkIdx = 0;
1028 ULONG wave_id = dls_file.pool_cues[rgn.wave.ulTableIndex].ulOffset;
1029 inst_region->WaveLink = rgn.wave;
1030 inst_region->WaveLink.ulTableIndex = wave_id + dlid_wave;
1033 if (rgn.wave_sample.cbSize != 0) {
1034 inst_region->WSMP = rgn.wave_sample;
1035 if (rgn.wave_loops.size() > 0)
MemCpyT(inst_region->WLOOP, &rgn.wave_loops.front(), rgn.wave_loops.size());
1037 instrument = (
char *)(inst_region + 1) -
sizeof(DMUS_REGION::WLOOP) +
sizeof(WLOOP) * rgn.wave_loops.size();
1039 inst_region->WSMP = rgn.wave_sample;
1040 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());
1042 instrument = (
char *)(inst_region + 1) -
sizeof(DMUS_REGION::WLOOP) +
sizeof(WLOOP) * dls_file.waves[wave_id].wave_loops.size();
1046 if (rgn.articulators.size() > 0) {
1047 inst_region->ulRegionArtIdx = last_offset;
1048 offset_table[last_offset++] = (
char *)instrument - inst_base;
1049 offset_table[last_offset++] = (
char *)instrument +
sizeof(DMUS_ARTICULATION2) - inst_base;
1051 instrument = DownloadArticulationData(inst_region->ulRegionArtIdx, instrument, rgn.articulators);
1053 inst_region->ulRegionArtIdx = 0;
1055 assert((
char *)instrument - inst_base <= (ptrdiff_t)inst_size);
1058 inst_region->ulNextRegionIdx = j < dls_file.instruments[i].regions.size() - 1 ? last_offset : 0;
1061 _dls_downloads.push_back(dl_inst);
1062 if (FAILED(download_port->Download(dl_inst))) {
1063 download_port->Release();
1064 return "Downloading DLS instrument failed";
1068 download_port->Release();
1078 if (FAILED(CoInitializeEx(NULL, COINITBASE_MULTITHREADED)))
return "COM initialization failed";
1081 if (FAILED(CoCreateInstance(
1088 return "Failed to create the music object";
1092 if (FAILED(_music->SetDirectSound(NULL, NULL)))
return "Can't set DirectSound interface";
1099 if (_debug_driver_level > 0) {
1101 char desc[DMUS_MAX_DESCRIPTION];
1105 caps.dwSize =
sizeof(DMUS_PORTCAPS);
1107 DEBUG(driver, 1,
"Detected DirectMusic ports:");
1108 for (
int i = 0; _music->EnumPort(i, &caps) == S_OK; i++) {
1109 if (caps.dwClass == DMUS_PC_OUTPUTCLASS) {
1121 caps.dwSize =
sizeof(DMUS_PORTCAPS);
1122 if (FAILED(_music->EnumPort(pIdx, &caps)))
return "Supplied port parameter is not a valid port";
1123 if (caps.dwClass != DMUS_PC_OUTPUTCLASS)
return "Supplied port parameter is not an output port";
1124 guidPort = caps.guidPort;
1126 if (FAILED(_music->GetDefaultPort(&guidPort)))
return "Can't query default music port";
1130 DMUS_PORTPARAMS params;
1132 params.dwSize =
sizeof(DMUS_PORTPARAMS);
1133 params.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
1134 params.dwChannelGroups = 1;
1135 if (FAILED(_music->CreatePort(guidPort, ¶ms, &_port, NULL)))
return "Failed to create port";
1137 if (FAILED(_port->Activate(TRUE)))
return "Failed to activate port";
1140 DMUS_BUFFERDESC desc;
1142 desc.dwSize =
sizeof(DMUS_BUFFERDESC);
1143 desc.guidBufferFormat = KSDATAFORMAT_SUBTYPE_DIRECTMUSIC;
1144 desc.cbBuffer = 1024;
1145 if (FAILED(_music->CreateMusicBuffer(&desc, &_buffer, NULL)))
return "Failed to create music buffer";
1148 const char *dls = LoadDefaultDLSFile(
GetDriverParam(parm,
"dls"));
1149 if (dls != NULL)
return dls;
1152 _thread_event = CreateEvent(NULL, FALSE, FALSE, NULL);
1153 if (_thread_event == NULL)
return "Can't create thread shutdown event";
1155 if (_thread_mutex == NULL)
return "Can't create thread mutex";
1157 if (!
ThreadObject::New(&MidiThreadProc,
this, &_dmusic_thread,
"ottd:dmusic"))
return "Can't create MIDI output thread";
1163 MusicDriver_DMusic::~MusicDriver_DMusic()
1171 if (_dmusic_thread != NULL) {
1172 _playback.shutdown =
true;
1173 SetEvent(_thread_event);
1174 _dmusic_thread->
Join();
1178 if (_dls_downloads.size() > 0) {
1179 IDirectMusicPortDownload *download_port = NULL;
1180 _port->QueryInterface(IID_IDirectMusicPortDownload, (LPVOID *)&download_port);
1184 for (std::vector<IDirectMusicDownload *>::reverse_iterator i = _dls_downloads.rbegin(); download_port != NULL && i != _dls_downloads.rend(); i++) {
1185 download_port->Unload(*i);
1188 _dls_downloads.clear();
1190 if (download_port != NULL) download_port->Release();
1193 if (_buffer != NULL) {
1198 if (_port != NULL) {
1199 _port->Activate(FALSE);
1204 if (_music != NULL) {
1209 CloseHandle(_thread_event);
1210 delete _thread_mutex;
1220 if (!_playback.next_file.LoadSong(song))
return;
1224 _playback.next_segment.loop = song.
loop;
1226 _playback.do_start =
true;
1227 SetEvent(_thread_event);
1233 _playback.do_stop =
true;
1234 SetEvent(_thread_event);
1240 return _playback.playing || _playback.do_start;
1246 _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.
int do_start
flag for starting playback of next_file at next opportunity
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...
static void MemSetT(T *ptr, byte value, size_t num=1)
Type-safe version of memset().