| 574 | } |
| 575 | |
| 576 | static void MidiThreadProc() |
| 577 | { |
| 578 | Debug(driver, 2, "DMusic: Entering playback thread"); |
| 579 | |
| 580 | REFERENCE_TIME last_volume_time = 0; // timestamp of the last volume change |
| 581 | REFERENCE_TIME block_time = 0; // timestamp of the last block sent to the port |
| 582 | REFERENCE_TIME playback_start_time; // timestamp current file began playback |
| 583 | MidiFile current_file; // file currently being played from |
| 584 | PlaybackSegment current_segment; // segment info for current playback |
| 585 | size_t current_block = 0; // next block index to send |
| 586 | uint8_t current_volume = 0; // current effective volume setting |
| 587 | std::array<uint8_t, 16> channel_volumes; // last seen volume controller values in raw data |
| 588 | |
| 589 | /* Get pointer to the reference clock of our output port. */ |
| 590 | IReferenceClock *clock; |
| 591 | _port->GetLatencyClock(&clock); |
| 592 | |
| 593 | REFERENCE_TIME cur_time; |
| 594 | clock->GetTime(&cur_time); |
| 595 | |
| 596 | _port->PlayBuffer(_buffer); |
| 597 | _buffer->Flush(); |
| 598 | |
| 599 | DWORD next_timeout = 1000; |
| 600 | while (true) { |
| 601 | /* Wait for a signal from the GUI thread or until the time for the next event has come. */ |
| 602 | DWORD wfso = WaitForSingleObject(_thread_event, next_timeout); |
| 603 | |
| 604 | if (_playback.shutdown) { |
| 605 | _playback.playing = false; |
| 606 | break; |
| 607 | } |
| 608 | |
| 609 | if (_playback.do_stop) { |
| 610 | Debug(driver, 2, "DMusic thread: Stopping playback"); |
| 611 | |
| 612 | /* Turn all notes off and wait a bit to allow the messages to be handled. */ |
| 613 | clock->GetTime(&cur_time); |
| 614 | TransmitNotesOff(_buffer, block_time, cur_time); |
| 615 | |
| 616 | _playback.playing = false; |
| 617 | _playback.do_stop = false; |
| 618 | block_time = 0; |
| 619 | next_timeout = 1000; |
| 620 | continue; |
| 621 | } |
| 622 | |
| 623 | if (wfso == WAIT_OBJECT_0) { |
| 624 | if (_playback.do_start) { |
| 625 | Debug(driver, 2, "DMusic thread: Starting playback"); |
| 626 | { |
| 627 | /* New scope to limit the time the mutex is locked. */ |
| 628 | std::lock_guard<std::mutex> lock(_thread_mutex); |
| 629 | |
| 630 | current_file.MoveFrom(_playback.next_file); |
| 631 | std::swap(_playback.next_segment, current_segment); |
| 632 | current_segment.start_block = 0; |
| 633 | current_block = 0; |
nothing calls this directly
no test coverage detected