OpenTTD Source: src/music/dmusic.cpp Source File

OpenTTD Source 14.0-beta1

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 {
76 return this->file_offset == offset;
77 }
78 };
79
80 std::vector<DLSInstrument> instruments;
81 std::vector<POOLCUE> pool_cues;
82 std::vector<DLSWave> waves;
83
85 bool LoadFile(const wchar_t *file);
86
87 private:
89 bool ReadDLSArticulation(FILE *f, DWORD list_length, std::vector<CONNECTION> &out);
91 bool ReadDLSRegionList(FILE *f, DWORD list_length, DLSInstrument &instrument);
93 bool ReadDLSRegion(FILE *f, DWORD list_length, std::vector<DLSRegion> &out);
95 bool ReadDLSInstrumentList(FILE *f, DWORD list_length);
97 bool ReadDLSInstrument(FILE *f, DWORD list_length);
99 bool ReadDLSWaveList(FILE *f, DWORD list_length);
101 bool ReadDLSWave(FILE *f, DWORD list_length, long offset);
102 };
103
105 PACK_N(struct ChunkHeader {
106 FOURCC type;
107 DWORD length;
108 }, 2);
109
111 PACK_N(struct WAVE_DOWNLOAD {
112 DMUS_DOWNLOADINFO dlInfo;
113 ULONG ulOffsetTable[2];
114 DMUS_WAVE dmWave;
115 DMUS_WAVEDATA dmWaveData;
116 }, 2);
117
118 struct PlaybackSegment {
119 uint32_t start, end;
120 size_t start_block;
121 bool loop;
122 };
123
124 static struct {
125 bool shutdown;
126 bool playing;
127 bool do_start;
128 bool do_stop;
129
130 int preload_time;
131 byte new_volume;
132
133 MidiFile next_file;
134 PlaybackSegment next_segment;
135 } _playback;
136
138 static std::thread _dmusic_thread;
140 static HANDLE _thread_event = nullptr;
142 static std::mutex _thread_mutex;
143
145 static IDirectMusic *_music = nullptr;
147 static IDirectMusicPort *_port = nullptr;
149 static IDirectMusicBuffer *_buffer = nullptr;
151 static std::vector<IDirectMusicDownload *> _dls_downloads;
152
153
154 static FMusicDriver_DMusic iFMusicDriver_DMusic;
155
156
157 bool DLSFile::ReadDLSArticulation(FILE *f, DWORD list_length, std::vector<CONNECTION> &out)
158 {
159 while (list_length > 0) {
160 ChunkHeader chunk;
161 if (fread(&chunk, sizeof(chunk), 1, f) != 1) return false;
162 list_length -= chunk.length + sizeof(chunk);
163
164 if (chunk.type == FOURCC_ART1) {
165 CONNECTIONLIST conns;
166 if (fread(&conns, sizeof(conns), 1, f) != 1) return false;
167 fseek(f, conns.cbSize - sizeof(conns), SEEK_CUR);
168
169 /* Read all defined articulations. */
170 for (ULONG i = 0; i < conns.cConnections; i++) {
171 CONNECTION con;
172 if (fread(&con, sizeof(con), 1, f) != 1) return false;
173 out.push_back(con);
174 }
175 } else {
176 fseek(f, chunk.length, SEEK_CUR);
177 }
178 }
179
180 return true;
181 }
182
183 bool DLSFile::ReadDLSRegion(FILE *f, DWORD list_length, std::vector<DLSRegion> &out)
184 {
185 out.push_back(DLSRegion());
186 DLSRegion &region = out.back();
187
188 /* Set default values. */
189 region.wave_sample.cbSize = 0;
190
191 while (list_length > 0) {
192 ChunkHeader chunk;
193 if (fread(&chunk, sizeof(chunk), 1, f) != 1) return false;
194 list_length -= chunk.length + sizeof(chunk);
195
196 if (chunk.type == FOURCC_LIST) {
197 /* Unwrap list header. */
198 if (fread(&chunk.type, sizeof(chunk.type), 1, f) != 1) return false;
199 chunk.length -= sizeof(chunk.type);
200 }
201
202 switch (chunk.type) {
203 case FOURCC_RGNH:
204 if (fread(&region.hdr, sizeof(region.hdr), 1, f) != 1) return false;
205 break;
206
207 case FOURCC_WSMP:
208 if (fread(&region.wave_sample, sizeof(region.wave_sample), 1, f) != 1) return false;
209 fseek(f, region.wave_sample.cbSize - sizeof(region.wave_sample), SEEK_CUR);
210
211 /* Read all defined sample loops. */
212 for (ULONG i = 0; i < region.wave_sample.cSampleLoops; i++) {
213 WLOOP loop;
214 if (fread(&loop, sizeof(loop), 1, f) != 1) return false;
215 region.wave_loops.push_back(loop);
216 }
217 break;
218
219 case FOURCC_WLNK:
220 if (fread(&region.wave, sizeof(region.wave), 1, f) != 1) return false;
221 break;
222
223 case FOURCC_LART: // List chunk
224 if (!this->ReadDLSArticulation(f, chunk.length, region.articulators)) return false;
225 break;
226
227 case FOURCC_INFO:
228 /* We don't care about info stuff. */
229 fseek(f, chunk.length, SEEK_CUR);
230 break;
231
232 default:
233 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));
234 fseek(f, chunk.length, SEEK_CUR);
235 break;
236 }
237 }
238
239 return true;
240 }
241
242 bool DLSFile::ReadDLSRegionList(FILE *f, DWORD list_length, DLSInstrument &instrument)
243 {
244 while (list_length > 0) {
245 ChunkHeader chunk;
246 if (fread(&chunk, sizeof(chunk), 1, f) != 1) return false;
247 list_length -= chunk.length + sizeof(chunk);
248
249 if (chunk.type == FOURCC_LIST) {
250 FOURCC list_type;
251 if (fread(&list_type, sizeof(list_type), 1, f) != 1) return false;
252
253 if (list_type == FOURCC_RGN) {
254 this->ReadDLSRegion(f, chunk.length - sizeof(list_type), instrument.regions);
255 } else {
256 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));
257 fseek(f, chunk.length - sizeof(list_type), SEEK_CUR);
258 }
259 } else {
260 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));
261 fseek(f, chunk.length, SEEK_CUR);
262 }
263 }
264
265 return true;
266 }
267
268 bool DLSFile::ReadDLSInstrument(FILE *f, DWORD list_length)
269 {
270 this->instruments.push_back(DLSInstrument());
271 DLSInstrument &instrument = this->instruments.back();
272
273 while (list_length > 0) {
274 ChunkHeader chunk;
275 if (fread(&chunk, sizeof(chunk), 1, f) != 1) return false;
276 list_length -= chunk.length + sizeof(chunk);
277
278 if (chunk.type == FOURCC_LIST) {
279 /* Unwrap list header. */
280 if (fread(&chunk.type, sizeof(chunk.type), 1, f) != 1) return false;
281 chunk.length -= sizeof(chunk.type);
282 }
283
284 switch (chunk.type) {
285 case FOURCC_INSH:
286 if (fread(&instrument.hdr, sizeof(instrument.hdr), 1, f) != 1) return false;
287 break;
288
289 case FOURCC_LART: // List chunk
290 if (!this->ReadDLSArticulation(f, chunk.length, instrument.articulators)) return false;
291 break;
292
293 case FOURCC_LRGN: // List chunk
294 if (!this->ReadDLSRegionList(f, chunk.length, instrument)) return false;
295 break;
296
297 case FOURCC_INFO:
298 /* We don't care about info stuff. */
299 fseek(f, chunk.length, SEEK_CUR);
300 break;
301
302 default:
303 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));
304 fseek(f, chunk.length, SEEK_CUR);
305 break;
306 }
307 }
308
309 return true;
310 }
311
312 bool DLSFile::ReadDLSInstrumentList(FILE *f, DWORD list_length)
313 {
314 while (list_length > 0) {
315 ChunkHeader chunk;
316 if (fread(&chunk, sizeof(chunk), 1, f) != 1) return false;
317 list_length -= chunk.length + sizeof(chunk);
318
319 if (chunk.type == FOURCC_LIST) {
320 FOURCC list_type;
321 if (fread(&list_type, sizeof(list_type), 1, f) != 1) return false;
322
323 if (list_type == FOURCC_INS) {
324 Debug(driver, 6, "DLS: Reading instrument {}", (int)instruments.size());
325
326 if (!this->ReadDLSInstrument(f, chunk.length - sizeof(list_type))) return false;
327 } else {
328 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));
329 fseek(f, chunk.length - sizeof(list_type), SEEK_CUR);
330 }
331 } else {
332 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));
333 fseek(f, chunk.length, SEEK_CUR);
334 }
335 }
336
337 return true;
338 }
339
340 bool DLSFile::ReadDLSWave(FILE *f, DWORD list_length, long offset)
341 {
342 this->waves.push_back(DLSWave());
343 DLSWave &wave = this->waves.back();
344
345 /* Set default values. */
346 MemSetT(&wave.wave_sample, 0);
347 wave.wave_sample.cbSize = sizeof(WSMPL);
348 wave.wave_sample.usUnityNote = 60;
349 wave.file_offset = offset; // Store file offset so we can resolve the wave pool table later on.
350
351 while (list_length > 0) {
352 ChunkHeader chunk;
353 if (fread(&chunk, sizeof(chunk), 1, f) != 1) return false;
354 list_length -= chunk.length + sizeof(chunk);
355
356 if (chunk.type == FOURCC_LIST) {
357 /* Unwrap list header. */
358 if (fread(&chunk.type, sizeof(chunk.type), 1, f) != 1) return false;
359 chunk.length -= sizeof(chunk.type);
360 }
361
362 switch (chunk.type) {
363 case FOURCC_fmt:
364 if (fread(&wave.fmt, sizeof(wave.fmt), 1, f) != 1) return false;
365 if (chunk.length > sizeof(wave.fmt)) fseek(f, chunk.length - sizeof(wave.fmt), SEEK_CUR);
366 break;
367
368 case FOURCC_WSMP:
369 if (fread(&wave.wave_sample, sizeof(wave.wave_sample), 1, f) != 1) return false;
370 fseek(f, wave.wave_sample.cbSize - sizeof(wave.wave_sample), SEEK_CUR);
371
372 /* Read all defined sample loops. */
373 for (ULONG i = 0; i < wave.wave_sample.cSampleLoops; i++) {
374 WLOOP loop;
375 if (fread(&loop, sizeof(loop), 1, f) != 1) return false;
376 wave.wave_loops.push_back(loop);
377 }
378 break;
379
380 case FOURCC_data:
381 wave.data.resize(chunk.length);
382 if (fread(&wave.data[0], sizeof(BYTE), wave.data.size(), f) != wave.data.size()) return false;
383 break;
384
385 case FOURCC_INFO:
386 /* We don't care about info stuff. */
387 fseek(f, chunk.length, SEEK_CUR);
388 break;
389
390 default:
391 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));
392 fseek(f, chunk.length, SEEK_CUR);
393 break;
394 }
395 }
396
397 return true;
398 }
399
400 bool DLSFile::ReadDLSWaveList(FILE *f, DWORD list_length)
401 {
402 long base_offset = ftell(f);
403
404 while (list_length > 0) {
405 long chunk_offset = ftell(f);
406
407 ChunkHeader chunk;
408 if (fread(&chunk, sizeof(chunk), 1, f) != 1) return false;
409 list_length -= chunk.length + sizeof(chunk);
410
411 if (chunk.type == FOURCC_LIST) {
412 FOURCC list_type;
413 if (fread(&list_type, sizeof(list_type), 1, f) != 1) return false;
414
415 if (list_type == FOURCC_wave) {
416 Debug(driver, 6, "DLS: Reading wave {}", waves.size());
417
418 if (!this->ReadDLSWave(f, chunk.length - sizeof(list_type), chunk_offset - base_offset)) return false;
419 } else {
420 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));
421 fseek(f, chunk.length - sizeof(list_type), SEEK_CUR);
422 }
423 } else {
424 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));
425 fseek(f, chunk.length, SEEK_CUR);
426 }
427 }
428
429 return true;
430 }
431
432 bool DLSFile::LoadFile(const wchar_t *file)
433 {
434 Debug(driver, 2, "DMusic: Try to load DLS file {}", FS2OTTD(file));
435
436 FILE *f = _wfopen(file, L"rb");
437 if (f == nullptr) return false;
438
439 FileCloser f_scope(f);
440
441 /* Check DLS file header. */
442 ChunkHeader hdr;
443 FOURCC dls_type;
444 if (fread(&hdr, sizeof(hdr), 1, f) != 1) return false;
445 if (fread(&dls_type, sizeof(dls_type), 1, f) != 1) return false;
446 if (hdr.type != FOURCC_RIFF || dls_type != FOURCC_DLS) return false;
447
448 hdr.length -= sizeof(FOURCC);
449
450 Debug(driver, 2, "DMusic: Parsing DLS file");
451
452 DLSHEADER header;
453 MemSetT(&header, 0);
454
455 /* Iterate over all chunks in the file. */
456 while (hdr.length > 0) {
457 ChunkHeader chunk;
458 if (fread(&chunk, sizeof(chunk), 1, f) != 1) return false;
459 hdr.length -= chunk.length + sizeof(chunk);
460
461 if (chunk.type == FOURCC_LIST) {
462 /* Unwrap list header. */
463 if (fread(&chunk.type, sizeof(chunk.type), 1, f) != 1) return false;
464 chunk.length -= sizeof(chunk.type);
465 }
466
467 switch (chunk.type) {
468 case FOURCC_COLH:
469 if (fread(&header, sizeof(header), 1, f) != 1) return false;
470 break;
471
472 case FOURCC_LINS: // List chunk
473 if (!this->ReadDLSInstrumentList(f, chunk.length)) return false;
474 break;
475
476 case FOURCC_WVPL: // List chunk
477 if (!this->ReadDLSWaveList(f, chunk.length)) return false;
478 break;
479
480 case FOURCC_PTBL:
481 POOLTABLE ptbl;
482 if (fread(&ptbl, sizeof(ptbl), 1, f) != 1) return false;
483 fseek(f, ptbl.cbSize - sizeof(ptbl), SEEK_CUR);
484
485 /* Read all defined cues. */
486 for (ULONG i = 0; i < ptbl.cCues; i++) {
487 POOLCUE cue;
488 if (fread(&cue, sizeof(cue), 1, f) != 1) return false;
489 this->pool_cues.push_back(cue);
490 }
491 break;
492
493 case FOURCC_INFO:
494 /* We don't care about info stuff. */
495 fseek(f, chunk.length, SEEK_CUR);
496 break;
497
498 default:
499 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));
500 fseek(f, chunk.length, SEEK_CUR);
501 break;
502 }
503 }
504
505 /* Have we read as many instruments as indicated? */
506 if (header.cInstruments != this->instruments.size()) return false;
507
508 /* Resolve wave pool table. */
509 for (std::vector<POOLCUE>::iterator cue = this->pool_cues.begin(); cue != this->pool_cues.end(); cue++) {
510 std::vector<DLSWave>::iterator w = std::find(this->waves.begin(), this->waves.end(), cue->ulOffset);
511 if (w != this->waves.end()) {
512 cue->ulOffset = (ULONG)(w - this->waves.begin());
513 } else {
514 cue->ulOffset = 0;
515 }
516 }
517
518 return true;
519 }
520
521
522 static byte ScaleVolume(byte original, byte scale)
523 {
524 return original * scale / 127;
525 }
526
527 static void TransmitChannelMsg(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, byte status, byte p1, byte p2 = 0)
528 {
529 if (buffer->PackStructured(rt, 0, status | (p1 << 8) | (p2 << 16)) == E_OUTOFMEMORY) {
530 /* Buffer is full, clear it and try again. */
531 _port->PlayBuffer(buffer);
532 buffer->Flush();
533
534 buffer->PackStructured(rt, 0, status | (p1 << 8) | (p2 << 16));
535 }
536 }
537
538 static void TransmitSysex(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, const byte *&msg_start, size_t &remaining)
539 {
540 /* Find end of message. */
541 const byte *msg_end = msg_start;
542 while (*msg_end != MIDIST_ENDSYSEX) msg_end++;
543 msg_end++; // Also include SysEx end byte.
544
545 if (buffer->PackUnstructured(rt, 0, msg_end - msg_start, const_cast<LPBYTE>(msg_start)) == E_OUTOFMEMORY) {
546 /* Buffer is full, clear it and try again. */
547 _port->PlayBuffer(buffer);
548 buffer->Flush();
549
550 buffer->PackUnstructured(rt, 0, msg_end - msg_start, const_cast<LPBYTE>(msg_start));
551 }
552
553 /* Update position in buffer. */
554 remaining -= msg_end - msg_start;
555 msg_start = msg_end;
556 }
557
558 static void TransmitStandardSysex(IDirectMusicBuffer *buffer, REFERENCE_TIME rt, MidiSysexMessage msg)
559 {
560 size_t length = 0;
561 const byte *data = MidiGetStandardSysexMessage(msg, length);
562 TransmitSysex(buffer, rt, data, length);
563 }
564
566 static void TransmitNotesOff(IDirectMusicBuffer *buffer, REFERENCE_TIME block_time, REFERENCE_TIME cur_time)
567 {
568 for (int ch = 0; ch < 16; ch++) {
569 TransmitChannelMsg(buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_MODE_ALLNOTESOFF, 0);
570 TransmitChannelMsg(buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_SUSTAINSW, 0);
571 TransmitChannelMsg(buffer, block_time + 10, MIDIST_CONTROLLER | ch, MIDICT_MODE_RESETALLCTRL, 0);
572 }
573
574 /* Performing a GM reset stops all sound and resets all parameters. */
575 TransmitStandardSysex(buffer, block_time + 20, MidiSysexMessage::ResetGM);
576 TransmitStandardSysex(buffer, block_time + 30, MidiSysexMessage::RolandSetReverb);
577
578 /* Explicitly flush buffer to make sure the messages are processed,
579 * as we want sound to stop immediately. */
580 _port->PlayBuffer(buffer);
581 buffer->Flush();
582
583 /* Wait until message time has passed. */
584 Sleep(Clamp((block_time - cur_time) / MS_TO_REFTIME, 5, 1000));
585 }
586
587 static void MidiThreadProc()
588 {
589 Debug(driver, 2, "DMusic: Entering playback thread");
590
591 REFERENCE_TIME last_volume_time = 0; // timestamp of the last volume change
592 REFERENCE_TIME block_time = 0; // timestamp of the last block sent to the port
593 REFERENCE_TIME playback_start_time; // timestamp current file began playback
594 MidiFile current_file; // file currently being played from
595 PlaybackSegment current_segment; // segment info for current playback
596 size_t current_block = 0; // next block index to send
597 byte current_volume = 0; // current effective volume setting
598 byte channel_volumes[16]; // last seen volume controller values in raw data
599
600 /* Get pointer to the reference clock of our output port. */
601 IReferenceClock *clock;
602 _port->GetLatencyClock(&clock);
603
604 REFERENCE_TIME cur_time;
605 clock->GetTime(&cur_time);
606
607 _port->PlayBuffer(_buffer);
608 _buffer->Flush();
609
610 DWORD next_timeout = 1000;
611 while (true) {
612 /* Wait for a signal from the GUI thread or until the time for the next event has come. */
613 DWORD wfso = WaitForSingleObject(_thread_event, next_timeout);
614
615 if (_playback.shutdown) {
616 _playback.playing = false;
617 break;
618 }
619
620 if (_playback.do_stop) {
621 Debug(driver, 2, "DMusic thread: Stopping playback");
622
623 /* Turn all notes off and wait a bit to allow the messages to be handled. */
624 clock->GetTime(&cur_time);
625 TransmitNotesOff(_buffer, block_time, cur_time);
626
627 _playback.playing = false;
628 _playback.do_stop = false;
629 block_time = 0;
630 next_timeout = 1000;
631 continue;
632 }
633
634 if (wfso == WAIT_OBJECT_0) {
635 if (_playback.do_start) {
636 Debug(driver, 2, "DMusic thread: Starting playback");
637 {
638 /* New scope to limit the time the mutex is locked. */
639 std::lock_guard<std::mutex> lock(_thread_mutex);
640
641 current_file.MoveFrom(_playback.next_file);
642 std::swap(_playback.next_segment, current_segment);
643 current_segment.start_block = 0;
644 current_block = 0;
645 _playback.playing = true;
646 _playback.do_start = false;
647 }
648
649 /* Reset playback device between songs. */
650 clock->GetTime(&cur_time);
651 TransmitNotesOff(_buffer, block_time, cur_time);
652
653 MemSetT<byte>(channel_volumes, 127, lengthof(channel_volumes));
654 /* Invalidate current volume. */
655 current_volume = UINT8_MAX;
656 last_volume_time = 0;
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.size();
674 if (block.ticktime >= current_segment.start) {
675 if (current_segment.loop) {
676 Debug(driver, 2, "DMusic: timer: loop from block {} (ticktime {}, realtime {:.3f}, bytes {})", bl, block.ticktime, ((int)block.realtime) / 1000.0, 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 {} (ticktime {}, realtime {:.3f}, bytes {})", bl, block.ticktime, ((int)block.realtime) / 1000.0, 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_t)block.realtime * MIDITIME_TO_REFTIME - playback_time) / MS_TO_REFTIME - _playback.preload_time, 0, 1000);
730 Debug(driver, 9, "DMusic thread: Next event in {} ms (music {}, ref {})", 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 {} (cur={}, block={})", current_block, (long long)(current_time / MS_TO_REFTIME), (long long)(block_time / MS_TO_REFTIME));
737
738 const byte *data = block.data.data();
739 size_t remaining = block.data.size();
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 == nullptr) {
866 /* Try loading the default GM DLS file stored in the registry. */
867 HKEY hkDM;
868 if (SUCCEEDED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\DirectMusic", 0, KEY_READ, &hkDM))) {
869 wchar_t dls_path[MAX_PATH];
870 DWORD buf_size = sizeof(dls_path); // Buffer size as to be given in bytes!
871 if (SUCCEEDED(RegQueryValueEx(hkDM, L"GMFilePath", nullptr, nullptr, (LPBYTE)dls_path, &buf_size))) {
872 wchar_t 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.empty()) {
881 static const wchar_t *DLS_GM_FILE = L"%windir%\\System32\\drivers\\gm.dls";
882 wchar_t 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).c_str())) return "Can't load GM DLS collection";
889 }
890
891 /* Get download port and allocate download IDs. */
892 IDirectMusicPortDownload *download_port = nullptr;
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 = nullptr;
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.empty()) {
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.empty()) {
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 = nullptr;
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.empty()) {
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.empty()) 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.empty()) 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.empty()) {
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 nullptr;
1072 }
1073
1074
1075 const char *MusicDriver_DMusic::Start(const StringList &parm)
1076 {
1077 /* Initialize COM */
1078 if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) return "COM initialization failed";
1079
1080 /* Create the DirectMusic object */
1081 if (FAILED(CoCreateInstance(
1082 CLSID_DirectMusic,
1083 nullptr,
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(nullptr, nullptr))) 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 Debug(driver, 1, " {}: {}{}", i, convert_from_fs(caps.wszDescription, desc, lengthof(desc)), i == pIdx ? " (selected)" : "");
1111 }
1112 }
1113 }
1114
1115 GUID guidPort;
1116 if (pIdx >= 0) {
1117 /* Check if the passed port is a valid port. */
1118 DMUS_PORTCAPS caps;
1119 MemSetT(&caps, 0);
1120 caps.dwSize = sizeof(DMUS_PORTCAPS);
1121 if (FAILED(_music->EnumPort(pIdx, &caps))) return "Supplied port parameter is not a valid port";
1122 if (caps.dwClass != DMUS_PC_OUTPUTCLASS) return "Supplied port parameter is not an output port";
1123 guidPort = caps.guidPort;
1124 } else {
1125 if (FAILED(_music->GetDefaultPort(&guidPort))) return "Can't query default music port";
1126 }
1127
1128 /* Create new port. */
1129 DMUS_PORTPARAMS params;
1130 MemSetT(&params, 0);
1131 params.dwSize = sizeof(DMUS_PORTPARAMS);
1132 params.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
1133 params.dwChannelGroups = 1;
1134 if (FAILED(_music->CreatePort(guidPort, &params, &_port, nullptr))) return "Failed to create port";
1135 /* Activate port. */
1136 if (FAILED(_port->Activate(TRUE))) return "Failed to activate port";
1137
1138 /* Create playback buffer. */
1139 DMUS_BUFFERDESC desc;
1140 MemSetT(&desc, 0);
1141 desc.dwSize = sizeof(DMUS_BUFFERDESC);
1142 desc.guidBufferFormat = KSDATAFORMAT_SUBTYPE_DIRECTMUSIC;
1143 desc.cbBuffer = 1024;
1144 if (FAILED(_music->CreateMusicBuffer(&desc, &_buffer, nullptr))) return "Failed to create music buffer";
1145
1146 /* On soft-synths (e.g. the default DirectMusic one), we might need to load a wavetable set to get music. */
1147 const char *dls = LoadDefaultDLSFile(GetDriverParam(parm, "dls"));
1148 if (dls != nullptr) return dls;
1149
1150 /* Create playback thread and synchronization primitives. */
1151 _thread_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
1152 if (_thread_event == nullptr) return "Can't create thread shutdown event";
1153
1154 if (!StartNewThread(&_dmusic_thread, "ottd:dmusic", &MidiThreadProc)) return "Can't create MIDI output thread";
1155
1156 return nullptr;
1157 }
1158
1159
1160 MusicDriver_DMusic::~MusicDriver_DMusic()
1161 {
1162 this->Stop();
1163 }
1164
1165
1166 void MusicDriver_DMusic::Stop()
1167 {
1168 if (_dmusic_thread.joinable()) {
1169 _playback.shutdown = true;
1170 SetEvent(_thread_event);
1171 _dmusic_thread.join();
1172 }
1173
1174 /* Unloaded any instruments we loaded. */
1175 if (!_dls_downloads.empty()) {
1176 IDirectMusicPortDownload *download_port = nullptr;
1177 _port->QueryInterface(IID_IDirectMusicPortDownload, (LPVOID *)&download_port);
1178
1179 /* Instruments refer to waves. As the waves are at the beginning of the download list,
1180 * do the unload from the back so that references are cleared properly. */
1181 for (std::vector<IDirectMusicDownload *>::reverse_iterator i = _dls_downloads.rbegin(); download_port != nullptr && i != _dls_downloads.rend(); i++) {
1182 download_port->Unload(*i);
1183 (*i)->Release();
1184 }
1185 _dls_downloads.clear();
1186
1187 if (download_port != nullptr) download_port->Release();
1188 }
1189
1190 if (_buffer != nullptr) {
1191 _buffer->Release();
1192 _buffer = nullptr;
1193 }
1194
1195 if (_port != nullptr) {
1196 _port->Activate(FALSE);
1197 _port->Release();
1198 _port = nullptr;
1199 }
1200
1201 if (_music != nullptr) {
1202 _music->Release();
1203 _music = nullptr;
1204 }
1205
1206 CloseHandle(_thread_event);
1207
1208 CoUninitialize();
1209 }
1210
1211
1212 void MusicDriver_DMusic::PlaySong(const MusicSongInfo &song)
1213 {
1214 std::lock_guard<std::mutex> lock(_thread_mutex);
1215
1216 if (!_playback.next_file.LoadSong(song)) return;
1217
1218 _playback.next_segment.start = song.override_start;
1219 _playback.next_segment.end = song.override_end;
1220 _playback.next_segment.loop = song.loop;
1221
1222 _playback.do_start = true;
1223 SetEvent(_thread_event);
1224 }
1225
1226
1227 void MusicDriver_DMusic::StopSong()
1228 {
1229 _playback.do_stop = true;
1230 SetEvent(_thread_event);
1231 }
1232
1233
1234 bool MusicDriver_DMusic::IsSongPlaying()
1235 {
1236 return _playback.playing || _playback.do_start;
1237 }
1238
1239
1240 void MusicDriver_DMusic::SetVolume(byte vol)
1241 {
1242 _playback.new_volume = vol;
1243 }
DLSFile::ReadDLSWaveList
bool ReadDLSWaveList(FILE *f, DWORD list_length)
Load a list of waves from a DLS file.
Definition: dmusic.cpp:400
_port
static IDirectMusicPort * _port
The port object lets us send MIDI data to the synthesizer.
Definition: dmusic.cpp:147
MidiFile
Definition: midifile.hpp:18
PlaybackSegment
Definition: dmusic.cpp:118
lock
std::mutex lock
synchronization for playback status fields
Definition: win32_m.cpp:35
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:332
MusicSongInfo::loop
bool loop
song should play in a tight loop if possible, never ending
Definition: base_media_base.h:331
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:183
do_stop
bool do_stop
flag for stopping playback at next opportunity
Definition: dmusic.cpp:128
GetDriverParam
const char * GetDriverParam(const StringList &parm, const char *name)
Get a string parameter the list of parameters.
Definition: driver.cpp:50
DLSFile::ReadDLSArticulation
bool ReadDLSArticulation(FILE *f, DWORD list_length, std::vector< CONNECTION > &out)
Load an articulation structure from a DLS file.
Definition: dmusic.cpp:157
current_volume
byte current_volume
current effective volume setting
Definition: win32_m.cpp:40
MusicSongInfo::override_end
int override_end
MIDI tick to end the song at (0 if no override)
Definition: base_media_base.h:333
Debug
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
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
MemCpyT
void MemCpyT(T *destination, const T *source, size_t num=1)
Type-safe version of memcpy().
Definition: mem_func.hpp:23
DLSFile::LoadFile
bool LoadFile(const wchar_t *file)
Try loading a DLS file into memory.
Definition: dmusic.cpp:432
FileCloser
Auto-close a file upon scope exit.
Definition: fileio_func.h:118
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:498
MusicDriver_DMusic::StopSong
void StopSong() override
Stop playing the current song.
Definition: dmusic.cpp:1227
shutdown
bool shutdown
flag to indicate playback thread shutdown
Definition: dmusic.cpp:125
_buffer
static IDirectMusicBuffer * _buffer
The buffer object collects the data to sent.
Definition: dmusic.cpp:149
FS2OTTD
std::string FS2OTTD(const std::wstring &name)
Convert to OpenTTD's encoding from a wide string.
Definition: win32.cpp:462
_thread_mutex
static std::mutex _thread_mutex
Lock access to playback data that is not thread-safe.
Definition: dmusic.cpp:142
MusicDriver_DMusic::IsSongPlaying
bool IsSongPlaying() override
Are we currently playing a song?
Definition: dmusic.cpp:1234
do_start
bool do_start
flag for starting playback of next_file at next opportunity
Definition: dmusic.cpp:127
next_file
MidiFile next_file
upcoming file to play
Definition: dmusic.cpp:133
channel_volumes
byte channel_volumes[16]
last seen volume controller values in raw data
Definition: win32_m.cpp:50
DLSFile::ReadDLSInstrumentList
bool ReadDLSInstrumentList(FILE *f, DWORD list_length)
Load a list of instruments from a DLS file.
Definition: dmusic.cpp:312
current_segment
PlaybackSegment current_segment
segment info for current playback
Definition: win32_m.cpp:44
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:325
_thread_event
static HANDLE _thread_event
Event to signal the thread that it should look at a state change.
Definition: dmusic.cpp:140
StringList
std::vector< std::string > StringList
Type for a list of strings.
Definition: string_type.h:60
MusicDriver_DMusic::Start
const char * Start(const StringList &param) override
Start this driver.
Definition: dmusic.cpp:1075
MusicDriver_DMusic::Stop
void Stop() override
Stop this driver.
Definition: dmusic.cpp:1166
MusicDriver_DMusic::PlaySong
void PlaySong(const MusicSongInfo &song) override
Play a particular song.
Definition: dmusic.cpp:1212
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:566
GetDriverParamInt
int GetDriverParamInt(const StringList &parm, const char *name, int def)
Get an integer parameter the list of parameters.
Definition: driver.cpp:82
_music
static IDirectMusic * _music
The direct music object manages buffers and ports.
Definition: dmusic.cpp:145
MidiFile::blocks
std::vector< DataBlock > blocks
sequential time-annotated data of file, merged to a single track
Definition: midifile.hpp:31
current_file
MidiFile current_file
file currently being played from
Definition: win32_m.cpp:43
_dls_downloads
static std::vector< IDirectMusicDownload * > _dls_downloads
List of downloaded DLS instruments.
Definition: dmusic.cpp:151
MusicDriver_DMusic::SetVolume
void SetVolume(byte vol) override
Set the volume, if possible.
Definition: dmusic.cpp:1240
_dmusic_thread
static std::thread _dmusic_thread
Handle to our worker thread.
Definition: dmusic.cpp:138
new_volume
byte new_volume
volume setting to change to
Definition: dmusic.cpp:131
lengthof
#define lengthof(x)
Return the length of an fixed size array.
Definition: stdafx.h:300
MemSetT
void MemSetT(T *ptr, byte value, size_t num=1)
Type-safe version of memset().
Definition: mem_func.hpp:49
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:865
MidiFile::DataBlock::data
std::vector< byte > data
raw midi data contained in block
Definition: midifile.hpp:22
playing
bool playing
flag indicating that playback is active
Definition: dmusic.cpp:126
DLSFile::ReadDLSWave
bool ReadDLSWave(FILE *f, DWORD list_length, long offset)
Load a single wave from a DLS file.
Definition: dmusic.cpp:340
DLSFile::ReadDLSRegionList
bool ReadDLSRegionList(FILE *f, DWORD list_length, DLSInstrument &instrument)
Load a list of regions from a DLS file.
Definition: dmusic.cpp:242
DLSFile::ReadDLSInstrument
bool ReadDLSInstrument(FILE *f, DWORD list_length)
Load a single instrument from a DLS file.
Definition: dmusic.cpp:268
current_block
size_t current_block
next block index to send
Definition: win32_m.cpp:46
DLSFile::DLSInstrument
Instrument definition read from a DLS file.
Definition: dmusic.cpp:57
Clamp
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:79
preload_time
int preload_time
preload time for music blocks.
Definition: dmusic.cpp:130
MidiFile::DataBlock::realtime
uint32_t realtime
real-time (microseconds) since start of file this block should be triggered at
Definition: midifile.hpp:21
DLSFile::DLSWave
Wave data definition from a DLS file.
Definition: dmusic.cpp:65
MidiFile::DataBlock
Definition: midifile.hpp:19
MidiFile::DataBlock::ticktime
uint32_t ticktime
tick number since start of file this block should be triggered at
Definition: midifile.hpp:20
playback_start_time
DWORD playback_start_time
timestamp current file began playback
Definition: win32_m.cpp:45
OTTD2FS
std::wstring OTTD2FS(const std::string &name)
Convert from OpenTTD's encoding to a wide string.
Definition: win32.cpp:479
DLSFile
A DLS file.
Definition: dmusic.cpp:45
dmusic.h
next_segment
PlaybackSegment next_segment
segment info for upcoming file
Definition: dmusic.cpp:134