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