| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  | // Copyright 2018 yuzu Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2 or any later version
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-30 23:57:53 -04:00
										 |  |  | #include <algorithm>
 | 
					
						
							|  |  |  | #include <cmath>
 | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-28 13:44:50 -04:00
										 |  |  | #include "audio_core/sink.h"
 | 
					
						
							|  |  |  | #include "audio_core/sink_details.h"
 | 
					
						
							| 
									
										
										
										
											2018-09-14 12:06:00 -04:00
										 |  |  | #include "audio_core/sink_stream.h"
 | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  | #include "audio_core/stream.h"
 | 
					
						
							| 
									
										
										
										
											2018-07-30 23:57:53 -04:00
										 |  |  | #include "common/assert.h"
 | 
					
						
							|  |  |  | #include "common/logging/log.h"
 | 
					
						
							|  |  |  | #include "core/core_timing.h"
 | 
					
						
							|  |  |  | #include "core/core_timing_util.h"
 | 
					
						
							|  |  |  | #include "core/settings.h"
 | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace AudioCore { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-15 15:21:06 +02:00
										 |  |  | constexpr std::size_t MaxAudioBufferCount{32}; | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-28 13:35:22 -04:00
										 |  |  | u32 Stream::GetNumChannels() const { | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  |     switch (format) { | 
					
						
							| 
									
										
										
										
											2018-07-28 13:35:22 -04:00
										 |  |  |     case Format::Mono16: | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |     case Format::Stereo16: | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  |         return 2; | 
					
						
							| 
									
										
										
										
											2018-07-28 13:35:22 -04:00
										 |  |  |     case Format::Multi51Channel16: | 
					
						
							|  |  |  |         return 6; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-12-28 14:04:44 -05:00
										 |  |  |     UNIMPLEMENTED_MSG("Unimplemented format={}", static_cast<u32>(format)); | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  |     return {}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-14 12:42:58 -05:00
										 |  |  | Stream::Stream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, Format format, | 
					
						
							|  |  |  |                ReleaseCallback&& release_callback, SinkStream& sink_stream, std::string&& name_) | 
					
						
							| 
									
										
										
										
											2018-07-28 13:44:50 -04:00
										 |  |  |     : sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)}, | 
					
						
							| 
									
										
										
										
											2019-02-14 12:42:58 -05:00
										 |  |  |       sink_stream{sink_stream}, core_timing{core_timing}, name{std::move(name_)} { | 
					
						
							| 
									
										
										
										
											2018-07-28 13:44:50 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-14 12:42:58 -05:00
										 |  |  |     release_event = core_timing.RegisterEvent( | 
					
						
							| 
									
										
										
										
											2019-03-24 18:11:32 -04:00
										 |  |  |         name, [this](u64 userdata, s64 cycles_late) { ReleaseActiveBuffer(); }); | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Stream::Play() { | 
					
						
							|  |  |  |     state = State::Playing; | 
					
						
							|  |  |  |     PlayNextBuffer(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Stream::Stop() { | 
					
						
							| 
									
										
										
										
											2018-09-23 22:32:01 +10:00
										 |  |  |     state = State::Stopped; | 
					
						
							| 
									
										
										
										
											2018-12-28 14:04:44 -05:00
										 |  |  |     UNIMPLEMENTED(); | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-16 19:06:33 +10:00
										 |  |  | void Stream::SetVolume(float volume) { | 
					
						
							|  |  |  |     game_volume = volume; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-23 20:01:02 -04:00
										 |  |  | Stream::State Stream::GetState() const { | 
					
						
							|  |  |  |     return state; | 
					
						
							| 
									
										
										
										
											2018-09-23 22:32:01 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  | s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const { | 
					
						
							| 
									
										
										
										
											2018-09-15 15:21:06 +02:00
										 |  |  |     const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()}; | 
					
						
							| 
									
										
										
										
											2019-06-04 19:52:42 -04:00
										 |  |  |     const auto us = | 
					
						
							|  |  |  |         std::chrono::microseconds((static_cast<u64>(num_samples) * 1000000) / sample_rate); | 
					
						
							|  |  |  |     return Core::Timing::usToCycles(us); | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-16 19:06:33 +10:00
										 |  |  | static void VolumeAdjustSamples(std::vector<s16>& samples, float game_volume) { | 
					
						
							|  |  |  |     const float volume{std::clamp(Settings::values.volume - (1.0f - game_volume), 0.0f, 1.0f)}; | 
					
						
							| 
									
										
										
										
											2018-07-30 23:57:53 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (volume == 1.0f) { | 
					
						
							| 
									
										
										
										
											2018-08-04 00:03:12 -04:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2018-07-30 23:57:53 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Implementation of a volume slider with a dynamic range of 60 dB
 | 
					
						
							| 
									
										
										
										
											2019-01-26 14:53:58 +01:00
										 |  |  |     const float volume_scale_factor = volume == 0 ? 0 : std::exp(6.90775f * volume) * 0.001f; | 
					
						
							| 
									
										
										
										
											2018-07-30 23:57:53 -04:00
										 |  |  |     for (auto& sample : samples) { | 
					
						
							|  |  |  |         sample = static_cast<s16>(sample * volume_scale_factor); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  | void Stream::PlayNextBuffer() { | 
					
						
							|  |  |  |     if (!IsPlaying()) { | 
					
						
							|  |  |  |         // Ensure we are in playing state before playing the next buffer
 | 
					
						
							| 
									
										
										
										
											2018-09-12 18:07:16 +01:00
										 |  |  |         sink_stream.Flush(); | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (active_buffer) { | 
					
						
							|  |  |  |         // Do not queue a new buffer if we are already playing a buffer
 | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (queued_buffers.empty()) { | 
					
						
							|  |  |  |         // No queued buffers - we are effectively paused
 | 
					
						
							| 
									
										
										
										
											2018-09-12 18:07:16 +01:00
										 |  |  |         sink_stream.Flush(); | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     active_buffer = queued_buffers.front(); | 
					
						
							|  |  |  |     queued_buffers.pop(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-16 19:06:33 +10:00
										 |  |  |     VolumeAdjustSamples(active_buffer->GetSamples(), game_volume); | 
					
						
							| 
									
										
										
										
											2018-08-23 14:33:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-04 00:03:12 -04:00
										 |  |  |     sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples()); | 
					
						
							| 
									
										
										
										
											2018-07-28 13:44:50 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-15 10:12:41 -04:00
										 |  |  |     core_timing.ScheduleEvent(GetBufferReleaseCycles(*active_buffer), release_event, {}); | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Stream::ReleaseActiveBuffer() { | 
					
						
							| 
									
										
										
										
											2018-08-02 18:27:22 -04:00
										 |  |  |     ASSERT(active_buffer); | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  |     released_buffers.push(std::move(active_buffer)); | 
					
						
							|  |  |  |     release_callback(); | 
					
						
							|  |  |  |     PlayNextBuffer(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool Stream::QueueBuffer(BufferPtr&& buffer) { | 
					
						
							|  |  |  |     if (queued_buffers.size() < MaxAudioBufferCount) { | 
					
						
							|  |  |  |         queued_buffers.push(std::move(buffer)); | 
					
						
							|  |  |  |         PlayNextBuffer(); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool Stream::ContainsBuffer(Buffer::Tag tag) const { | 
					
						
							| 
									
										
										
										
											2018-12-28 14:04:44 -05:00
										 |  |  |     UNIMPLEMENTED(); | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  |     return {}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-15 15:21:06 +02:00
										 |  |  | std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers(std::size_t max_count) { | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  |     std::vector<Buffer::Tag> tags; | 
					
						
							| 
									
										
										
										
											2018-09-15 15:21:06 +02:00
										 |  |  |     for (std::size_t count = 0; count < max_count && !released_buffers.empty(); ++count) { | 
					
						
							| 
									
										
										
										
											2018-07-26 20:01:37 -04:00
										 |  |  |         tags.push_back(released_buffers.front()->GetTag()); | 
					
						
							|  |  |  |         released_buffers.pop(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return tags; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace AudioCore
 |