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