DWORD Player::InstancePlayThread() { Timer timer; uint64_t current_cycles=0,prev_cycles=0; double span_accumulator = 0; double update_time = 1000.0; double timer_res = timer.resolution(); uint32_t samples_to_render = uint32_t(update_time * 0.001 * audio_interface_->wave_format().nSamplesPerSec); uint32_t buffer_size = samples_to_render * audio_interface_->wave_format().nBlockAlign; thread_time_span = 0; while (1) { EnterCriticalSection(&cs); if (thread_msg == WM_SP_QUIT) { thread_msg = 0; break; } else if (thread_msg == WM_SP_PLAY) { if (state_ != kStatePlaying) { prev_cycles = timer.GetCurrentCycles(); state_ = kStatePlaying; span_accumulator = update_time; audio_interface_->Play(); } } else if (thread_msg == WM_SP_PAUSE) { if (state_ != kStatePaused) { ResetEvent(player_event); state_ = kStatePaused; memset(output_buffer,0,output_buffer_samples_*sizeof(short)); audio_interface_->Write(output_buffer,output_buffer_samples_*sizeof(short)); } } else if (thread_msg == WM_SP_STOP) { if (state_ != kStateStopped) { ResetEvent(player_event); state_ = kStateStopped; synth_->Reset(); song_counter_ms = 0; audio_interface_->Stop(); thread_time_span = 0; } } thread_msg = 0; LeaveCriticalSection(&cs); if (state_ == kStatePlaying) { current_cycles = timer.GetCurrentCycles(); double time_span = (current_cycles - prev_cycles) * timer_res; if (time_span >= output_buffer_length_ms_) //should be at max, output buffer length in ms time_span = output_buffer_length_ms_; while (span_accumulator >= update_time) { //memset(mix_buffer,0,output_buffer_samples_*sizeof(real_t)); synth_->RenderSamplesStereo(samples_to_render,mix_buffer); song_counter_ms += update_time; if (TryEnterCriticalSection(&vis_cs) != 0) { if (visual_addon_ != nullptr && samples_to_render >= 256) visual_addon_->AddPCMData256(mix_buffer,2,update_time); LeaveCriticalSection(&vis_cs); } clamp(output_buffer,mix_buffer,samples_to_render<<1); audio_interface_->Write(output_buffer,buffer_size); span_accumulator -= update_time; } span_accumulator += time_span; thread_time_span += time_span; prev_cycles = current_cycles; } else { //wait for pause/stop events with timer WaitForSingleObject(player_event,2000); } } return S_OK; }