OpenTTD
dmusic.cpp
Go to the documentation of this file.
1 /* $Id$ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8  */
9 
12 #ifdef WIN32_ENABLE_DIRECTMUSIC_SUPPORT
13 
14 #define INITGUID
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
18 #endif
19 #include "../debug.h"
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"
25 #include "dmusic.h"
26 #include "midifile.hpp"
27 #include "midi.h"
28 
29 #include <windows.h>
30 #include <dmksctrl.h>
31 #include <dmusicc.h>
32 #include <algorithm>
33 #include <mutex>
34 
35 #include "../safeguards.h"
36 
37 #if defined(_MSC_VER)
38 # pragma comment(lib, "ole32.lib")
39 #endif /* defined(_MSC_VER) */
40 
41 static const int MS_TO_REFTIME = 1000 * 10;
42 static const int MIDITIME_TO_REFTIME = 10;
43 
44 
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')
48 
50 struct DLSFile {
52  struct DLSRegion {
53  RGNHEADER hdr;
54  WAVELINK wave;
55  WSMPL wave_sample;
56 
57  std::vector<WLOOP> wave_loops;
58  std::vector<CONNECTION> articulators;
59  };
60 
62  struct DLSInstrument {
63  INSTHEADER hdr;
64 
65  std::vector<CONNECTION> articulators;
66  std::vector<DLSRegion> regions;
67  };
68 
70  struct DLSWave {
71  long file_offset;
72 
73  PCMWAVEFORMAT fmt;
74  std::vector<BYTE> data;
75 
76  WSMPL wave_sample;
77  std::vector<WLOOP> wave_loops;
78 
79  bool operator ==(long offset) const {
80  return this->file_offset == offset;
81  }
82  };
83 
84  std::vector<DLSInstrument> instruments;
85  std::vector<POOLCUE> pool_cues;
86  std::vector<DLSWave> waves;
87 
89  bool LoadFile(const TCHAR *file);
90 
91 private:
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);
106 };
107 
109 PACK_N(struct ChunkHeader {
110  FOURCC type;
111  DWORD length;
112 }, 2);
113 
115 PACK_N(struct WAVE_DOWNLOAD {
116  DMUS_DOWNLOADINFO dlInfo;
117  ULONG ulOffsetTable[2];
118  DMUS_WAVE dmWave;
119  DMUS_WAVEDATA dmWaveData;
120 }, 2);
121 
122 struct PlaybackSegment {
123  uint32 start, end;
124  size_t start_block;
125  bool loop;
126 };
127 
128 static struct {
129  bool shutdown;
130  bool playing;
131  bool do_start;
132  bool do_stop;
133 
134  int preload_time;
135  byte new_volume;
136 
139 } _playback;
140 
142 static std::thread _dmusic_thread;
144 static HANDLE _thread_event = nullptr;
146 static std::mutex _thread_mutex;
147 
149 static IDirectMusic *_music = nullptr;
151 static IDirectMusicPort *_port = nullptr;
153 static IDirectMusicBuffer *_buffer = nullptr;
155 static std::vector<IDirectMusicDownload *> _dls_downloads;
156 
157 
158 static FMusicDriver_DMusic iFMusicDriver_DMusic;
159 
160 
161 bool DLSFile::ReadDLSArticulation(FILE *f, DWORD list_length, std::vector<CONNECTION> &out)
162 {
163  while (list_length > 0) {
164  ChunkHeader chunk;
165  if (fread(&chunk, sizeof(chunk), 1, f) != 1) return false;
166  list_length -= chunk.length + sizeof(chunk);
167 
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);
172 
173  /* Read all defined articulations. */
174  for (ULONG i = 0; i < conns.cConnections; i++) {
175  CONNECTION con;
176  if (fread(&con, sizeof(con), 1, f) != 1) return false;
177  out.push_back(con);
178  }
179  } else {
180  fseek(f, chunk.length, SEEK_CUR);
181  }
182  }
183 
184  return true;
185 }
186 
187 bool DLSFile::ReadDLSRegion(FILE *f, DWORD list_length, std::vector<DLSRegion> &out)
188 {
189  out.push_back(DLSRegion());
190  DLSRegion &region = out.back();
191 
192  /* Set default values. */
193  region.wave_sample.cbSize = 0;
194 
195  while (list_length > 0) {
196  ChunkHeader chunk;
197  if (fread(&chunk, sizeof(chunk), 1, f) != 1) return false;
198  list_length -= chunk.length + sizeof(chunk);
199 
200  if (chunk.type == FOURCC_LIST) {
201  /* Unwrap list header. */
202  if (fread(&chunk.type, sizeof(chunk.type), 1, f) != 1) return false;
203  chunk.length -= sizeof(chunk.type);
204  }
205 
206  switch (chunk.type) {
207  case FOURCC_RGNH:
208  if (fread(&region.hdr, sizeof(region.hdr), 1, f) != 1) return false;
209  break;
210 
211  case FOURCC_WSMP:
212  if (fread(&region.wave_sample, sizeof(region.wave_sample), 1, f) != 1) return false;
213  fseek(f, region.wave_sample.cbSize - sizeof(region.wave_sample), SEEK_CUR);
214 
215  /* Read all defined sample loops. */
216  for (ULONG i = 0; i < region.wave_sample.cSampleLoops; i++) {
217  WLOOP loop;
218  if (fread(&loop, sizeof(loop), 1, f) != 1) return false;
219  region.wave_loops.push_back(loop);
220  }
221  break;
222 
223  case FOURCC_WLNK:
224  if (fread(&region.wave, sizeof(region.wave), 1, f) != 1) return false;
225  break;
226 
227  case FOURCC_LART: // List chunk
228  if (!this->ReadDLSArticulation(f, chunk.length, region.articulators)) return false;
229  break;
230 
231  case FOURCC_INFO:
232  /* We don't care about info stuff. */
233  fseek(f, chunk.length, SEEK_CUR);
234  break;
235 
236  default:
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);
239  break;
240  }
241  }
242 
243  return true;
244 }
245 
246 bool DLSFile::ReadDLSRegionList(FILE *f, DWORD list_length, DLSInstrument &instrument)
247 {
248  while (list_length > 0) {
249  ChunkHeader chunk;
250  if (fread(&chunk, sizeof(chunk), 1, f) != 1) return false;
251  list_length -= chunk.length + sizeof(chunk);
252 
253  if (chunk.type == FOURCC_LIST) {
254  FOURCC list_type;
255  if (fread(&list_type, sizeof(list_type), 1, f) != 1) return false;
256 
257  if (list_type == FOURCC_RGN) {
258  this->ReadDLSRegion(f, chunk.length - sizeof(list_type), instrument.regions);
259  } else {
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);
262  }
263  } else {
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);
266  }
267  }
268 
269  return true;
270 }
271 
272 bool DLSFile::ReadDLSInstrument(FILE *f, DWORD list_length)
273 {
274  this->instruments.push_back(DLSInstrument());
275  DLSInstrument &instrument = this->instruments.back();
276 
277  while (list_length > 0) {
278  ChunkHeader chunk;
279  if (fread(&chunk, sizeof(chunk), 1, f) != 1) return false;
280  list_length -= chunk.length + sizeof(chunk);
281 
282  if (chunk.type == FOURCC_LIST) {
283  /* Unwrap list header. */
284  if (fread(&chunk.type, sizeof(chunk.type), 1, f) != 1) return false;
285  chunk.length -= sizeof(chunk.type);
286  }
287 
288  switch (chunk.type) {
289  case FOURCC_INSH:
290  if (fread(&instrument.hdr, sizeof(instrument.hdr), 1, f) != 1) return false;
291  break;
292 
293  case FOURCC_LART: // List chunk
294  if (!this->ReadDLSArticulation(f, chunk.length, instrument.articulators)) return false;
295  break;
296 
297  case FOURCC_LRGN: // List chunk
298  if (!this->ReadDLSRegionList(f, chunk.length, instrument)) return false;
299  break;
300 
301  case FOURCC_INFO:
302  /* We don't care about info stuff. */
303  fseek(f, chunk.length, SEEK_CUR);
304  break;
305 
306  default:
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);
309  break;
310  }
311  }
312 
313  return true;
314 }
315 
316 bool DLSFile::ReadDLSInstrumentList(FILE *f, DWORD list_length)
317 {
318  while (list_length > 0) {
319  ChunkHeader chunk;
320  if (fread(&chunk, sizeof(chunk), 1, f) != 1) return false;
321  list_length -= chunk.length + sizeof(chunk);
322 
323  if (chunk.type == FOURCC_LIST) {
324  FOURCC list_type;
325  if (fread(&list_type, sizeof(list_type), 1, f) != 1) return false;
326 
327  if (list_type == FOURCC_INS) {
328  DEBUG(driver, 6, "DLS: Reading instrument %d", (int)instruments.size());
329 
330  if (!this->ReadDLSInstrument(f, chunk.length - sizeof(list_type))) return false;
331  } else {
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);
334  }
335  } else {
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);
338  }
339  }
340 
341  return true;
342 }
343 
344 bool DLSFile::ReadDLSWave(FILE *f, DWORD list_length, long offset)
345 {
346  this->waves.push_back(DLSWave());
347  DLSWave &wave = this->waves.back();
348 
349  /* Set default values. */
350  MemSetT(&wave.wave_sample, 0);
351  wave.wave_sample.cbSize = sizeof(WSMPL);
352  wave.wave_sample.usUnityNote = 60;
353  wave.file_offset = offset; // Store file offset so we can resolve the wave pool table later on.
354 
355  while (list_length > 0) {
356  ChunkHeader chunk;
357  if (fread(&chunk, sizeof(chunk), 1, f) != 1) return false;
358  list_length -= chunk.length + sizeof(chunk);
359 
360  if (chunk.type == FOURCC_LIST) {
361  /* Unwrap list header. */
362  if (fread(&chunk.type, sizeof(chunk.type), 1, f) != 1) return false;
363  chunk.length -= sizeof(chunk.type);
364  }
365 
366  switch (chunk.type) {
367  case FOURCC_fmt:
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);
370  break;
371 
372  case FOURCC_WSMP:
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);
375 
376  /* Read all defined sample loops. */
377  for (ULONG i = 0; i < wave.wave_sample.cSampleLoops; i++) {
378  WLOOP loop;
379  if (fread(&loop, sizeof(loop), 1, f) != 1) return false;
380  wave.wave_loops.push_back(loop);
381  }
382  break;
383 
384  case FOURCC_data:
385  wave.data.resize(chunk.length);
386  if (fread(&wave.data[0], sizeof(BYTE), wave.data.size(), f) != wave.data.size()) return false;
387  break;
388 
389  case FOURCC_INFO:
390  /* We don't care about info stuff. */
391  fseek(f, chunk.length, SEEK_CUR);
392  break;
393 
394  default:
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);
397  break;
398  }
399  }
400 
401  return true;
402 }
403 
404 bool DLSFile::ReadDLSWaveList(FILE *f, DWORD list_length)
405 {
406  long base_offset = ftell(f);
407 
408  while (list_length > 0) {
409  long chunk_offset = ftell(f);
410 
411  ChunkHeader chunk;
412  if (fread(&chunk, sizeof(chunk), 1, f) != 1) return false;
413  list_length -= chunk.length + sizeof(chunk);
414 
415  if (chunk.type == FOURCC_LIST) {
416  FOURCC list_type;
417  if (fread(&list_type, sizeof(list_type), 1, f) != 1) return false;
418 
419  if (list_type == FOURCC_wave) {
420  DEBUG(driver, 6, "DLS: Reading wave %d", (int)waves.size());
421 
422  if (!this->ReadDLSWave(f, chunk.length - sizeof(list_type), chunk_offset - base_offset)) return false;
423  } else {
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);
426  }
427  } else {
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);
430  }
431  }
432 
433  return true;
434 }
435 
436 bool DLSFile::LoadFile(const TCHAR *file)
437 {
438  DEBUG(driver, 2, "DMusic: Try to load DLS file %s", FS2OTTD(file));
439 
440  FILE *f = _tfopen(file, _T("rb"));
441  if (f == nullptr) return false;
442 
443  FileCloser f_scope(f);
444 
445  /* Check DLS file header. */
446  ChunkHeader hdr;
447  FOURCC dls_type;
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;
451 
452  hdr.length -= sizeof(FOURCC);
453 
454  DEBUG(driver, 2, "DMusic: Parsing DLS file");
455 
456  DLSHEADER header;
457  MemSetT(&header, 0);
458 
459  /* Iterate over all chunks in the file. */
460  while (hdr.length > 0) {
461  ChunkHeader chunk;
462  if (fread(&chunk, sizeof(chunk), 1, f) != 1) return false;
463  hdr.length -= chunk.length + sizeof(chunk);
464 
465  if (chunk.type == FOURCC_LIST) {
466  /* Unwrap list header. */
467  if (fread(&chunk.type, sizeof(chunk.type), 1, f) != 1) return false;
468  chunk.length -= sizeof(chunk.type);
469  }
470 
471  switch (chunk.type) {
472  case FOURCC_COLH:
473  if (fread(&header, sizeof(header), 1, f) != 1) return false;
474  break;
475 
476  case FOURCC_LINS: // List chunk
477  if (!this->ReadDLSInstrumentList(f, chunk.length)) return false;
478  break;
479 
480  case FOURCC_WVPL: // List chunk
481  if (!this->ReadDLSWaveList(f, chunk.length)) return false;
482  break;
483 
484  case FOURCC_PTBL:
485  POOLTABLE ptbl;
486  if (fread(&ptbl, sizeof(ptbl), 1, f) != 1) return false;
487  fseek(f, ptbl.cbSize - sizeof(ptbl), SEEK_CUR);
488 
489  /* Read all defined cues. */
490  for (ULONG i = 0; i < ptbl.cCues; i++) {
491  POOLCUE cue;
492  if (fread(&cue, sizeof(cue), 1, f) != 1) return false;
493  this->pool_cues.push_back(cue);
494  }
495  break;
496 
497  case FOURCC_INFO:
498  /* We don't care about info stuff. */
499  fseek(f, chunk.length, SEEK_CUR);
500  break;
501 
502  default:
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);
505  break;
506  }
507  }
508 
509  /* Have we read as many instruments as indicated? */
510  if (header.cInstruments != this->instruments.size()) return false;
511 
512  /* Resolve wave pool table. */
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());
517  } else {
518  cue->ulOffset = 0;
519  }
520  }
521 
522  return true;
523 }
524 
525 
526 static byte ScaleVolume(byte original, byte scale)
527 {
528  return original * scale / 127;
529 }
530 
531 static void TransmitChannelMsg(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, byte status, byte p1, byte p2 = 0)
532 {
533  if (buffer->PackStructured(rt, 0, status | (p1 << 8) | (p2 << 16)) == E_OUTOFMEMORY) {
534  /* Buffer is full, clear it and try again. */
535  _port->PlayBuffer(buffer);
536  buffer->Flush();
537 
538  buffer->PackStructured(rt, 0, status | (p1 << 8) | (p2 << 16));
539  }
540 }
541 
542 static void TransmitSysex(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, const byte *&msg_start, size_t &remaining)
543 {
544  /* Find end of message. */
545  const byte *msg_end = msg_start;
546  while (*msg_end != MIDIST_ENDSYSEX) msg_end++;
547  msg_end++; // Also include SysEx end byte.
548 
549  if (buffer->PackUnstructured(rt, 0, msg_end - msg_start, const_cast<LPBYTE>(msg_start)) == E_OUTOFMEMORY) {
550  /* Buffer is full, clear it and try again. */
551  _port->PlayBuffer(buffer);
552  buffer->Flush();
553 
554  buffer->PackUnstructured(rt, 0, msg_end - msg_start, const_cast<LPBYTE>(msg_start));
555  }
556 
557  /* Update position in buffer. */
558  remaining -= msg_end - msg_start;
559  msg_start = msg_end;
560 }
561 
562 static void TransmitStandardSysex(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, MidiSysexMessage msg)
563 {
564  size_t length = 0;
565  const byte *data = MidiGetStandardSysexMessage(msg, length);
566  TransmitSysex(buffer, rt, data, length);
567 }
568 
570 static void TransmitNotesOff(IDirectMusicBuffer *buffer, REFERENCE_TIME block_time, REFERENCE_TIME cur_time)
571 {
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);
576  }
577 
578  /* Performing a GM reset stops all sound and resets all parameters. */
579  TransmitStandardSysex(_buffer, block_time + 20, MidiSysexMessage::ResetGM);
580  TransmitStandardSysex(_buffer, block_time + 30, MidiSysexMessage::RolandSetReverb);
581 
582  /* Explicitly flush buffer to make sure the messages are processed,
583  * as we want sound to stop immediately. */
584  _port->PlayBuffer(_buffer);
585  _buffer->Flush();
586 
587  /* Wait until message time has passed. */
588  Sleep(Clamp((block_time - cur_time) / MS_TO_REFTIME, 5, 1000));
589 }
590 
591 static void MidiThreadProc()
592 {
593  DEBUG(driver, 2, "DMusic: Entering playback thread");
594 
595  REFERENCE_TIME last_volume_time = 0; // timestamp of the last volume change
596  REFERENCE_TIME block_time = 0; // timestamp of the last block sent to the port
597  REFERENCE_TIME playback_start_time; // timestamp current file began playback
598  MidiFile current_file; // file currently being played from
599  PlaybackSegment current_segment; // segment info for current playback
600  size_t current_block = 0; // next block index to send
601  byte current_volume = 0; // current effective volume setting
602  byte channel_volumes[16]; // last seen volume controller values in raw data
603 
604  /* Get pointer to the reference clock of our output port. */
605  IReferenceClock *clock;
606  _port->GetLatencyClock(&clock);
607 
608  REFERENCE_TIME cur_time;
609  clock->GetTime(&cur_time);
610 
611  _port->PlayBuffer(_buffer);
612  _buffer->Flush();
613 
614  DWORD next_timeout = 1000;
615  while (true) {
616  /* Wait for a signal from the GUI thread or until the time for the next event has come. */
617  DWORD wfso = WaitForSingleObject(_thread_event, next_timeout);
618 
619  if (_playback.shutdown) {
620  _playback.playing = false;
621  break;
622  }
623 
624  if (_playback.do_stop) {
625  DEBUG(driver, 2, "DMusic thread: Stopping playback");
626 
627  /* Turn all notes off and wait a bit to allow the messages to be handled. */
628  clock->GetTime(&cur_time);
629  TransmitNotesOff(_buffer, block_time, cur_time);
630 
631  _playback.playing = false;
632  _playback.do_stop = false;
633  block_time = 0;
634  next_timeout = 1000;
635  continue;
636  }
637 
638  if (wfso == WAIT_OBJECT_0) {
639  if (_playback.do_start) {
640  DEBUG(driver, 2, "DMusic thread: Starting playback");
641  {
642  /* New scope to limit the time the mutex is locked. */
643  std::lock_guard<std::mutex> lock(_thread_mutex);
644 
645  current_file.MoveFrom(_playback.next_file);
646  std::swap(_playback.next_segment, current_segment);
647  current_segment.start_block = 0;
648  current_block = 0;
649  _playback.playing = true;
650  _playback.do_start = false;
651  }
652 
653  /* Reset playback device between songs. */
654  clock->GetTime(&cur_time);
655  TransmitNotesOff(_buffer, block_time, cur_time);
656 
657  MemSetT<byte>(channel_volumes, 127, lengthof(channel_volumes));
658 
659  /* Take the current time plus the preload time as the music start time. */
660  clock->GetTime(&playback_start_time);
661  playback_start_time += _playback.preload_time * MS_TO_REFTIME;
662  }
663  }
664 
665  if (_playback.playing) {
666  /* skip beginning of file? */
667  if (current_segment.start > 0 && current_block == 0 && current_segment.start_block == 0) {
668  /* find first block after start time and pretend playback started earlier
669  * this is to allow all blocks prior to the actual start to still affect playback,
670  * as they may contain important controller and program changes */
671  size_t preload_bytes = 0;
672  for (size_t bl = 0; bl < current_file.blocks.size(); bl++) {
673  MidiFile::DataBlock &block = current_file.blocks[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;
679  break;
680  } else {
681  /* Skip the transmission delay compensation performed in the Win32 MIDI driver.
682  * The DMusic driver will most likely be used with the MS softsynth, which is not subject to transmission delays.
683  */
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;
686  break;
687  }
688  }
689  }
690  }
691 
692  /* Get current playback timestamp. */
693  REFERENCE_TIME current_time;
694  clock->GetTime(&current_time);
695 
696  /* Check for volume change. */
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);
705  }
706  _port->PlayBuffer(_buffer);
707  _buffer->Flush();
708  }
709  }
710 
711  while (current_block < current_file.blocks.size()) {
712  MidiFile::DataBlock &block = current_file.blocks[current_block];
713 
714  /* check that block isn't at end-of-song override */
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;
720  } else {
721  _playback.do_stop = true;
722  }
723  next_timeout = 0;
724  break;
725  }
726  /* check that block is not in the future */
727  REFERENCE_TIME playback_time = current_time - playback_start_time;
728  if (block.realtime * MIDITIME_TO_REFTIME > playback_time + 3 *_playback.preload_time * MS_TO_REFTIME) {
729  /* Stop the thread loop until we are at the preload time of the next block. */
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);
732  break;
733  }
734 
735  /* Timestamp of the current block. */
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));
738 
739  const byte *data = block.data.data();
740  size_t remaining = block.data.size();
741  byte last_status = 0;
742  while (remaining > 0) {
743  /* MidiFile ought to have converted everything out of running status,
744  * but handle it anyway just to be safe */
745  byte status = data[0];
746  if (status & 0x80) {
747  last_status = status;
748  data++;
749  remaining--;
750  } else {
751  status = last_status;
752  }
753  switch (status & 0xF0) {
754  case MIDIST_PROGCHG:
755  case MIDIST_CHANPRESS:
756  /* 2 byte channel messages */
757  TransmitChannelMsg(_buffer, block_time, status, data[0]);
758  data++;
759  remaining--;
760  break;
761  case MIDIST_NOTEOFF:
762  case MIDIST_NOTEON:
763  case MIDIST_POLYPRESS:
764  case MIDIST_PITCHBEND:
765  /* 3 byte channel messages */
766  TransmitChannelMsg(_buffer, block_time, status, data[0], data[1]);
767  data += 2;
768  remaining -= 2;
769  break;
770  case MIDIST_CONTROLLER:
771  /* controller change */
772  if (data[0] == MIDICT_CHANVOLUME) {
773  /* volume controller, adjust for user volume */
774  channel_volumes[status & 0x0F] = data[1];
775  int vol = ScaleVolume(data[1], current_volume);
776  TransmitChannelMsg(_buffer, block_time, status, data[0], vol);
777  } else {
778  /* handle other controllers normally */
779  TransmitChannelMsg(_buffer, block_time, status, data[0], data[1]);
780  }
781  data += 2;
782  remaining -= 2;
783  break;
784  case 0xF0:
785  /* system messages */
786  switch (status) {
787  case MIDIST_SYSEX: /* system exclusive */
788  TransmitSysex(_buffer, block_time, data, remaining);
789  break;
790  case MIDIST_TC_QFRAME: /* time code quarter frame */
791  case MIDIST_SONGSEL: /* song select */
792  data++;
793  remaining--;
794  break;
795  case MIDIST_SONGPOSPTR: /* song position pointer */
796  data += 2;
797  remaining -= 2;
798  break;
799  default: /* remaining have no data bytes */
800  break;
801  }
802  break;
803  }
804  }
805 
806  current_block++;
807  }
808 
809  /* Anything in the playback buffer? Send it down the port. */
810  DWORD used_buffer = 0;
811  _buffer->GetUsedBytes(&used_buffer);
812  if (used_buffer > 0) {
813  _port->PlayBuffer(_buffer);
814  _buffer->Flush();
815  }
816 
817  /* end? */
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;
822  } else {
823  _playback.do_stop = true;
824  }
825  next_timeout = 0;
826  }
827  }
828  }
829 
830  DEBUG(driver, 2, "DMusic: Exiting playback thread");
831 
832  /* Turn all notes off and wait a bit to allow the messages to be handled by real hardware. */
833  clock->GetTime(&cur_time);
834  TransmitNotesOff(_buffer, block_time, cur_time);
835  Sleep(_playback.preload_time * 4);
836 
837  clock->Release();
838 }
839 
840 static void * DownloadArticulationData(int base_offset, void *data, const std::vector<CONNECTION> &artic)
841 {
842  DMUS_ARTICULATION2 *art = (DMUS_ARTICULATION2 *)data;
843  art->ulArtIdx = base_offset + 1;
844  art->ulFirstExtCkIdx = 0;
845  art->ulNextArtIdx = 0;
846 
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());
851 
852  return (CONNECTION *)(con_list + 1) + artic.size();
853 }
854 
855 static const char *LoadDefaultDLSFile(const char *user_dls)
856 {
857  DMUS_PORTCAPS caps;
858  MemSetT(&caps, 0);
859  caps.dwSize = sizeof(DMUS_PORTCAPS);
860  _port->GetCaps(&caps);
861 
862  /* Nothing to unless it is a synth with instrument download that doesn't come with GM voices by default. */
863  if ((caps.dwFlags & (DMUS_PC_DLS | DMUS_PC_DLS2)) != 0 && (caps.dwFlags & DMUS_PC_GMINHARDWARE) == 0) {
864  DLSFile dls_file;
865 
866  if (user_dls == nullptr) {
867  /* Try loading the default GM DLS file stored in the registry. */
868  HKEY hkDM;
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); // Buffer size as to be given in bytes!
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");
876  }
877  RegCloseKey(hkDM);
878  }
879 
880  /* If we couldn't load the file from the registry, try again at the default install path of the GM DLS file. */
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));
885 
886  if (!dls_file.LoadFile(path)) return "Can't load GM DLS collection";
887  }
888  } else {
889  if (!dls_file.LoadFile(OTTD2FS(user_dls))) return "Can't load GM DLS collection";
890  }
891 
892  /* Get download port and allocate download IDs. */
893  IDirectMusicPortDownload *download_port = nullptr;
894  if (FAILED(_port->QueryInterface(IID_IDirectMusicPortDownload, (LPVOID *)&download_port))) return "Can't get download port";
895 
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";
900  }
901 
902  DWORD dwAppend = 0;
903  download_port->GetAppend(&dwAppend);
904 
905  /* Download wave data. */
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";
911  }
912 
913  WAVE_DOWNLOAD *wave;
914  DWORD wave_size = 0;
915  if (FAILED(dl_wave->GetBuffer((LPVOID *)&wave, &wave_size))) {
916  dl_wave->Release();
917  download_port->Release();
918  return "Can't get wave download buffer";
919  }
920 
921  /* Fill download data. */
922  MemSetT(wave, 0);
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());
933 
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";
938  }
939  }
940 
941  /* Download instrument data. */
942  for (DWORD i = 0; i < dls_file.instruments.size(); i++) {
943  DWORD offsets = 1 + (DWORD)dls_file.instruments[i].regions.size();
944 
945  /* Calculate download size for the instrument. */
946  size_t i_size = sizeof(DMUS_DOWNLOADINFO) + sizeof(DMUS_INSTRUMENT);
947  if (dls_file.instruments[i].articulators.size() > 0) {
948  /* Articulations are stored as two chunks, one containing meta data and one with the actual articulation data. */
949  offsets += 2;
950  i_size += sizeof(DMUS_ARTICULATION2) + sizeof(CONNECTIONLIST) + sizeof(CONNECTION) * dls_file.instruments[i].articulators.size();
951  }
952 
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) {
955  offsets += 2;
956  i_size += sizeof(DMUS_ARTICULATION2) + sizeof(CONNECTIONLIST) + sizeof(CONNECTION) * rgn->articulators.size();
957  }
958 
959  /* Region size depends on the number of wave loops. The size of the
960  * declared structure already accounts for one loop. */
961  if (rgn->wave_sample.cbSize != 0) {
962  i_size += sizeof(DMUS_REGION) - sizeof(DMUS_REGION::WLOOP) + sizeof(WLOOP) * rgn->wave_loops.size();
963  } else {
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();
965  }
966  }
967 
968  i_size += offsets * sizeof(ULONG);
969 
970  /* Allocate download buffer. */
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";
975  }
976 
977  void *instrument;
978  DWORD inst_size = 0;
979  if (FAILED(dl_inst->GetBuffer((LPVOID *)&instrument, &inst_size))) {
980  dl_inst->Release();
981  download_port->Release();
982  return "Can't get instrument download buffer";
983  }
984  char *inst_base = (char *)instrument;
985 
986  /* Fill download header. */
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;
993 
994  /* Download offset table; contains the offsets of all chunks relative to the buffer start. */
995  ULONG *offset_table = (ULONG *)instrument;
996  instrument = offset_table + offsets;
997  int last_offset = 0;
998 
999  /* Instrument header. */
1000  DMUS_INSTRUMENT *inst_data = (DMUS_INSTRUMENT *)instrument;
1001  MemSetT(inst_data, 0);
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;
1005 
1006  /* Write global articulations. */
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;
1011 
1012  instrument = DownloadArticulationData(inst_data->ulGlobalArtIdx, instrument, dls_file.instruments[i].articulators);
1013  assert((char *)instrument - inst_base <= (ptrdiff_t)inst_size);
1014  }
1015 
1016  /* Write out regions. */
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];
1020 
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;
1028 
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;
1032 
1033  /* The wave sample data will be taken from the region, if defined, otherwise from the wave itself. */
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());
1037 
1038  instrument = (char *)(inst_region + 1) - sizeof(DMUS_REGION::WLOOP) + sizeof(WLOOP) * rgn.wave_loops.size();
1039  } else {
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());
1042 
1043  instrument = (char *)(inst_region + 1) - sizeof(DMUS_REGION::WLOOP) + sizeof(WLOOP) * dls_file.waves[wave_id].wave_loops.size();
1044  }
1045 
1046  /* Write local articulator data. */
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;
1051 
1052  instrument = DownloadArticulationData(inst_region->ulRegionArtIdx, instrument, rgn.articulators);
1053  } else {
1054  inst_region->ulRegionArtIdx = 0;
1055  }
1056  assert((char *)instrument - inst_base <= (ptrdiff_t)inst_size);
1057 
1058  /* Link to the next region unless this was the last one.*/
1059  inst_region->ulNextRegionIdx = j < dls_file.instruments[i].regions.size() - 1 ? last_offset : 0;
1060  }
1061 
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";
1066  }
1067  }
1068 
1069  download_port->Release();
1070  }
1071 
1072  return nullptr;
1073 }
1074 
1075 
1076 const char *MusicDriver_DMusic::Start(const char * const *parm)
1077 {
1078  /* Initialize COM */
1079  if (FAILED(CoInitializeEx(nullptr, COINITBASE_MULTITHREADED))) return "COM initialization failed";
1080 
1081  /* Create the DirectMusic object */
1082  if (FAILED(CoCreateInstance(
1083  CLSID_DirectMusic,
1084  nullptr,
1085  CLSCTX_INPROC,
1086  IID_IDirectMusic,
1087  (LPVOID*)&_music
1088  ))) {
1089  return "Failed to create the music object";
1090  }
1091 
1092  /* Assign sound output device. */
1093  if (FAILED(_music->SetDirectSound(nullptr, nullptr))) return "Can't set DirectSound interface";
1094 
1095  /* MIDI events need to be send to the synth in time before their playback time
1096  * has come. By default, we try send any events at least 50 ms before playback. */
1097  _playback.preload_time = GetDriverParamInt(parm, "preload", 50);
1098 
1099  int pIdx = GetDriverParamInt(parm, "port", -1);
1100  if (_debug_driver_level > 0) {
1101  /* Print all valid output ports. */
1102  char desc[DMUS_MAX_DESCRIPTION];
1103 
1104  DMUS_PORTCAPS caps;
1105  MemSetT(&caps, 0);
1106  caps.dwSize = sizeof(DMUS_PORTCAPS);
1107 
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) {
1111  /* Description is UNICODE even for ANSI build. */
1112  DEBUG(driver, 1, " %d: %s%s", i, convert_from_fs(caps.wszDescription, desc, lengthof(desc)), i == pIdx ? " (selected)" : "");
1113  }
1114  }
1115  }
1116 
1117  GUID guidPort;
1118  if (pIdx >= 0) {
1119  /* Check if the passed port is a valid port. */
1120  DMUS_PORTCAPS caps;
1121  MemSetT(&caps, 0);
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;
1126  } else {
1127  if (FAILED(_music->GetDefaultPort(&guidPort))) return "Can't query default music port";
1128  }
1129 
1130  /* Create new port. */
1131  DMUS_PORTPARAMS params;
1132  MemSetT(&params, 0);
1133  params.dwSize = sizeof(DMUS_PORTPARAMS);
1134  params.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
1135  params.dwChannelGroups = 1;
1136  if (FAILED(_music->CreatePort(guidPort, &params, &_port, nullptr))) return "Failed to create port";
1137  /* Activate port. */
1138  if (FAILED(_port->Activate(TRUE))) return "Failed to activate port";
1139 
1140  /* Create playback buffer. */
1141  DMUS_BUFFERDESC desc;
1142  MemSetT(&desc, 0);
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";
1147 
1148  /* On soft-synths (e.g. the default DirectMusic one), we might need to load a wavetable set to get music. */
1149  const char *dls = LoadDefaultDLSFile(GetDriverParam(parm, "dls"));
1150  if (dls != nullptr) return dls;
1151 
1152  /* Create playback thread and synchronization primitives. */
1153  _thread_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
1154  if (_thread_event == nullptr) return "Can't create thread shutdown event";
1155 
1156  if (!StartNewThread(&_dmusic_thread, "ottd:dmusic", &MidiThreadProc)) return "Can't create MIDI output thread";
1157 
1158  return nullptr;
1159 }
1160 
1161 
1162 MusicDriver_DMusic::~MusicDriver_DMusic()
1163 {
1164  this->Stop();
1165 }
1166 
1167 
1169 {
1170  if (_dmusic_thread.joinable()) {
1171  _playback.shutdown = true;
1172  SetEvent(_thread_event);
1173  _dmusic_thread.join();
1174  }
1175 
1176  /* Unloaded any instruments we loaded. */
1177  if (_dls_downloads.size() > 0) {
1178  IDirectMusicPortDownload *download_port = nullptr;
1179  _port->QueryInterface(IID_IDirectMusicPortDownload, (LPVOID *)&download_port);
1180 
1181  /* Instruments refer to waves. As the waves are at the beginning of the download list,
1182  * do the unload from the back so that references are cleared properly. */
1183  for (std::vector<IDirectMusicDownload *>::reverse_iterator i = _dls_downloads.rbegin(); download_port != nullptr && i != _dls_downloads.rend(); i++) {
1184  download_port->Unload(*i);
1185  (*i)->Release();
1186  }
1187  _dls_downloads.clear();
1188 
1189  if (download_port != nullptr) download_port->Release();
1190  }
1191 
1192  if (_buffer != nullptr) {
1193  _buffer->Release();
1194  _buffer = nullptr;
1195  }
1196 
1197  if (_port != nullptr) {
1198  _port->Activate(FALSE);
1199  _port->Release();
1200  _port = nullptr;
1201  }
1202 
1203  if (_music != nullptr) {
1204  _music->Release();
1205  _music = nullptr;
1206  }
1207 
1208  CloseHandle(_thread_event);
1209 
1210  CoUninitialize();
1211 }
1212 
1213 
1215 {
1216  std::lock_guard<std::mutex> lock(_thread_mutex);
1217 
1218  if (!_playback.next_file.LoadSong(song)) return;
1219 
1220  _playback.next_segment.start = song.override_start;
1221  _playback.next_segment.end = song.override_end;
1222  _playback.next_segment.loop = song.loop;
1223 
1224  _playback.do_start = true;
1225  SetEvent(_thread_event);
1226 }
1227 
1228 
1230 {
1231  _playback.do_stop = true;
1232  SetEvent(_thread_event);
1233 }
1234 
1235 
1237 {
1238  return _playback.playing || _playback.do_start;
1239 }
1240 
1241 
1242 void MusicDriver_DMusic::SetVolume(byte vol)
1243 {
1244  _playback.new_volume = vol;
1245 }
1246 
1247 
1248 #endif /* WIN32_ENABLE_DIRECTMUSIC_SUPPORT */
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.
Definition: driver.cpp:39
Metadata about a music track.
bool IsSongPlaying() override
Are we currently playing a song?
const char * FS2OTTD(const TCHAR *name)
Convert to OpenTTD&#39;s encoding from that of the local environment.
Definition: win32.cpp:560
MidiFile current_file
file currently being played from
Definition: win32_m.cpp:44
void StopSong() override
Stop playing the current song.
size_t current_block
next block index to send
Definition: win32_m.cpp:47
int override_start
MIDI ticks to skip over in beginning.
bool playing
flag indicating that playback is active
Definition: win32_m.cpp:38
void MoveFrom(MidiFile &other)
Move data from other to this, and clears other.
Definition: midifile.cpp:876
byte new_volume
volume setting to change to
Definition: win32_m.cpp:42
char * convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen)
Convert to OpenTTD&#39;s encoding from that of the environment in UNICODE.
Definition: win32.cpp:593
std::vector< DataBlock > blocks
sequential time-annotated data of file, merged to a single track
Definition: midifile.hpp:36
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.
Definition: thread.h:50
std::mutex lock
synchronization for playback status fields
Definition: win32_m.cpp:36
std::vector< byte > data
raw midi data contained in block
Definition: midifile.hpp:27
byte channel_volumes[16]
last seen volume controller values in raw data
Definition: win32_m.cpp:51
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.
Definition: multimap.hpp:205
Auto-close a file upon scope exit.
Definition: fileio_func.h:153
void PlaySong(const MusicSongInfo &song) override
Play a particular song.
bool do_stop
flag for stopping playback at next opportunity
Definition: win32_m.cpp:40
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:42
void Stop() override
Stop this driver.
const TCHAR * OTTD2FS(const char *name, bool console_cp)
Convert from OpenTTD&#39;s encoding to that of the local environment.
Definition: win32.cpp:578
uint32 realtime
real-time (microseconds) since start of file this block should be triggered at
Definition: midifile.hpp:26
MidiFile next_file
upcoming file to play
Definition: win32_m.cpp:48
static T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:139
static void MemCpyT(T *destination, const T *source, size_t num=1)
Type-safe version of memcpy().
Definition: mem_func.hpp:25
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:37
const char * Start(const char *const *param) override
Start this driver.
PlaybackSegment next_segment
segment info for upcoming file
Definition: win32_m.cpp:49
byte current_volume
current effective volume setting
Definition: win32_m.cpp:41
uint32 ticktime
tick number since start of file this block should be triggered at
Definition: midifile.hpp:25
Factory for the DirectX music player.
Definition: dmusic.h:37
bool loop
song should play in a tight loop if possible, never ending
PlaybackSegment current_segment
segment info for current playback
Definition: win32_m.cpp:45
Base of playing music via DirectMusic.
DWORD playback_start_time
timestamp current file began playback
Definition: win32_m.cpp:46
int GetDriverParamInt(const char *const *parm, const char *name, int def)
Get an integer parameter the list of parameters.
Definition: driver.cpp:75
int do_start
flag for starting playback of next_file at next opportunity
Definition: win32_m.cpp:39
static void MemSetT(T *ptr, byte value, size_t num=1)
Type-safe version of memset().
Definition: mem_func.hpp:51