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