mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-01-17 22:25:37 +00:00
AudioStream: Add cubeb implementation
This commit is contained in:
parent
3ba98e6ef8
commit
9586970a9f
|
@ -41,6 +41,10 @@ public:
|
|||
void WriteSamples(const SampleType* samples, u32 num_samples);
|
||||
void EndWrite(u32 num_samples);
|
||||
|
||||
static std::unique_ptr<AudioStream> CreateNullAudioStream();
|
||||
|
||||
static std::unique_ptr<AudioStream> CreateCubebAudioStream();
|
||||
|
||||
protected:
|
||||
virtual bool OpenDevice() = 0;
|
||||
virtual void PauseDevice(bool paused) = 0;
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
<ClInclude Include="byte_stream.h" />
|
||||
<ClInclude Include="cd_image.h" />
|
||||
<ClInclude Include="cpu_detect.h" />
|
||||
<ClInclude Include="cubeb_audio_stream.h" />
|
||||
<ClInclude Include="d3d11\shader_compiler.h" />
|
||||
<ClInclude Include="d3d11\staging_texture.h" />
|
||||
<ClInclude Include="d3d11\stream_buffer.h" />
|
||||
|
@ -74,6 +75,7 @@
|
|||
<ClCompile Include="cd_image.cpp" />
|
||||
<ClCompile Include="cd_image_bin.cpp" />
|
||||
<ClCompile Include="cd_image_cue.cpp" />
|
||||
<ClCompile Include="cubeb_audio_stream.cpp" />
|
||||
<ClCompile Include="d3d11\shader_compiler.cpp" />
|
||||
<ClCompile Include="d3d11\staging_texture.cpp" />
|
||||
<ClCompile Include="d3d11\stream_buffer.cpp" />
|
||||
|
@ -99,6 +101,9 @@
|
|||
<Natvis Include="bitfield.natvis" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\dep\cubeb\cubeb.vcxproj">
|
||||
<Project>{72f9423c-91ee-4487-aac6-555ed6f61aa1}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\dep\glad\glad.vcxproj">
|
||||
<Project>{43540154-9e1e-409c-834f-b84be5621388}</Project>
|
||||
</ProjectReference>
|
||||
|
@ -243,7 +248,7 @@
|
|||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
|
@ -269,7 +274,7 @@
|
|||
<PreprocessorDefinitions>_ITERATOR_DEBUG_LEVEL=1;WIN32;_DEBUGFAST;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
|
@ -298,7 +303,7 @@
|
|||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
|
@ -324,7 +329,7 @@
|
|||
<PreprocessorDefinitions>_ITERATOR_DEBUG_LEVEL=1;WIN32;_DEBUGFAST;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
|
@ -354,7 +359,7 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
|
@ -384,7 +389,7 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
|
@ -414,7 +419,7 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
|
@ -444,7 +449,7 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
<ClInclude Include="string_util.h" />
|
||||
<ClInclude Include="md5_digest.h" />
|
||||
<ClInclude Include="cpu_detect.h" />
|
||||
<ClInclude Include="cubeb_audio_stream.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="jit_code_buffer.cpp" />
|
||||
|
@ -88,6 +89,7 @@
|
|||
<ClCompile Include="file_system.cpp" />
|
||||
<ClCompile Include="string_util.cpp" />
|
||||
<ClCompile Include="md5_digest.cpp" />
|
||||
<ClCompile Include="cubeb_audio_stream.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="bitfield.natvis" />
|
||||
|
|
120
src/common/cubeb_audio_stream.cpp
Normal file
120
src/common/cubeb_audio_stream.cpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
#include "cubeb_audio_stream.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/log.h"
|
||||
Log_SetChannel(CubebAudioStream);
|
||||
|
||||
CubebAudioStream::CubebAudioStream() = default;
|
||||
|
||||
CubebAudioStream::~CubebAudioStream()
|
||||
{
|
||||
if (IsOpen())
|
||||
CubebAudioStream::CloseDevice();
|
||||
}
|
||||
|
||||
bool CubebAudioStream::OpenDevice()
|
||||
{
|
||||
Assert(!IsOpen());
|
||||
|
||||
int rv = cubeb_init(&m_cubeb_context, "DuckStation", nullptr);
|
||||
if (rv != CUBEB_OK)
|
||||
{
|
||||
Log_ErrorPrintf("Could not initialize cubeb context: %d", rv);
|
||||
return false;
|
||||
}
|
||||
|
||||
cubeb_stream_params params = {};
|
||||
params.format = CUBEB_SAMPLE_S16LE;
|
||||
params.rate = m_output_sample_rate;
|
||||
params.channels = m_channels;
|
||||
params.layout = CUBEB_LAYOUT_UNDEFINED;
|
||||
params.prefs = CUBEB_STREAM_PREF_NONE;
|
||||
|
||||
u32 latency_frames = 0;
|
||||
rv = cubeb_get_min_latency(m_cubeb_context, ¶ms, &latency_frames);
|
||||
if (rv != CUBEB_OK)
|
||||
{
|
||||
Log_ErrorPrintf("Could not get minimum latency: %d", rv);
|
||||
cubeb_destroy(m_cubeb_context);
|
||||
m_cubeb_context = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
Log_InfoPrintf("Minimum latency in frames: %u", latency_frames);
|
||||
if (latency_frames > m_buffer_size)
|
||||
Log_WarningPrintf("Minimum latency is above buffer size: %u vs %u", latency_frames, m_buffer_size);
|
||||
else
|
||||
latency_frames = m_buffer_size;
|
||||
|
||||
char stream_name[32];
|
||||
std::snprintf(stream_name, sizeof(stream_name), "AudioStream_%p", this);
|
||||
|
||||
rv = cubeb_stream_init(m_cubeb_context, &m_cubeb_stream, stream_name, nullptr, nullptr, nullptr, ¶ms,
|
||||
latency_frames, DataCallback, StateCallback, this);
|
||||
if (rv != CUBEB_OK)
|
||||
{
|
||||
Log_ErrorPrintf("Could not create stream: %d", rv);
|
||||
cubeb_destroy(m_cubeb_context);
|
||||
m_cubeb_context = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CubebAudioStream::PauseDevice(bool paused)
|
||||
{
|
||||
if (paused == m_paused)
|
||||
return;
|
||||
|
||||
int rv = paused ? cubeb_stream_stop(m_cubeb_stream) : cubeb_stream_start(m_cubeb_stream);
|
||||
if (rv != CUBEB_OK)
|
||||
{
|
||||
Log_ErrorPrintf("cubeb_stream_%s failed: %d", paused ? "stop" : "start", rv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CubebAudioStream::CloseDevice()
|
||||
{
|
||||
Assert(IsOpen());
|
||||
|
||||
if (!m_paused)
|
||||
cubeb_stream_stop(m_cubeb_stream);
|
||||
|
||||
cubeb_stream_destroy(m_cubeb_stream);
|
||||
m_cubeb_stream = nullptr;
|
||||
|
||||
cubeb_destroy(m_cubeb_context);
|
||||
m_cubeb_context = nullptr;
|
||||
}
|
||||
|
||||
long CubebAudioStream::DataCallback(cubeb_stream* stm, void* user_ptr, const void* input_buffer, void* output_buffer,
|
||||
long nframes)
|
||||
{
|
||||
CubebAudioStream* const this_ptr = static_cast<CubebAudioStream*>(user_ptr);
|
||||
|
||||
const u32 read_frames =
|
||||
this_ptr->ReadSamples(reinterpret_cast<SampleType*>(output_buffer), static_cast<u32>(nframes));
|
||||
const u32 silence_frames = static_cast<u32>(nframes) - read_frames;
|
||||
if (silence_frames > 0)
|
||||
{
|
||||
std::memset(reinterpret_cast<SampleType*>(output_buffer) + (read_frames * this_ptr->m_channels), 0,
|
||||
silence_frames * this_ptr->m_channels * sizeof(SampleType));
|
||||
}
|
||||
|
||||
return nframes;
|
||||
}
|
||||
|
||||
void CubebAudioStream::StateCallback(cubeb_stream* stream, void* user_ptr, cubeb_state state)
|
||||
{
|
||||
CubebAudioStream* const this_ptr = static_cast<CubebAudioStream*>(user_ptr);
|
||||
|
||||
this_ptr->m_paused = (state != CUBEB_STATE_STARTED);
|
||||
}
|
||||
|
||||
void CubebAudioStream::BufferAvailable() {}
|
||||
|
||||
std::unique_ptr<AudioStream> AudioStream::CreateCubebAudioStream()
|
||||
{
|
||||
return std::make_unique<CubebAudioStream>();
|
||||
}
|
27
src/common/cubeb_audio_stream.h
Normal file
27
src/common/cubeb_audio_stream.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
#include "common/audio_stream.h"
|
||||
#include "cubeb/cubeb.h"
|
||||
#include <cstdint>
|
||||
|
||||
class CubebAudioStream final : public AudioStream
|
||||
{
|
||||
public:
|
||||
CubebAudioStream();
|
||||
~CubebAudioStream();
|
||||
|
||||
protected:
|
||||
bool IsOpen() const { return m_cubeb_stream != nullptr; }
|
||||
|
||||
bool OpenDevice() override;
|
||||
void PauseDevice(bool paused) override;
|
||||
void CloseDevice() override;
|
||||
void BufferAvailable() override;
|
||||
|
||||
static long DataCallback(cubeb_stream* stm, void* user_ptr, const void* input_buffer, void* output_buffer,
|
||||
long nframes);
|
||||
static void StateCallback(cubeb_stream* stream, void* user_ptr, cubeb_state state);
|
||||
|
||||
cubeb* m_cubeb_context = nullptr;
|
||||
cubeb_stream* m_cubeb_stream = nullptr;
|
||||
bool m_paused = true;
|
||||
};
|
|
@ -19,7 +19,7 @@ void NullAudioStream::BufferAvailable()
|
|||
DropBuffer();
|
||||
}
|
||||
|
||||
std::unique_ptr<AudioStream> NullAudioStream::Create()
|
||||
std::unique_ptr<AudioStream> AudioStream::CreateNullAudioStream()
|
||||
{
|
||||
return std::unique_ptr<AudioStream>(new NullAudioStream());
|
||||
return std::make_unique<NullAudioStream>();
|
||||
}
|
||||
|
|
|
@ -4,16 +4,12 @@
|
|||
class NullAudioStream final : public AudioStream
|
||||
{
|
||||
public:
|
||||
NullAudioStream();
|
||||
~NullAudioStream();
|
||||
|
||||
static std::unique_ptr<AudioStream> Create();
|
||||
|
||||
protected:
|
||||
bool OpenDevice() override;
|
||||
void PauseDevice(bool paused) override;
|
||||
void CloseDevice() override;
|
||||
void BufferAvailable() override;
|
||||
|
||||
private:
|
||||
NullAudioStream();
|
||||
};
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "common/assert.h"
|
||||
#include "common/byte_stream.h"
|
||||
#include "common/log.h"
|
||||
#include "common/null_audio_stream.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/controller.h"
|
||||
#include "core/game_list.h"
|
||||
|
@ -454,7 +453,7 @@ void QtHostInterface::createAudioStream()
|
|||
|
||||
// fall back to null output
|
||||
m_audio_stream.reset();
|
||||
m_audio_stream = NullAudioStream::Create();
|
||||
m_audio_stream = AudioStream::CreateNullAudioStream();
|
||||
m_audio_stream->Reconfigure(AUDIO_SAMPLE_RATE, AUDIO_CHANNELS, AUDIO_BUFFER_SIZE, 4);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "common/assert.h"
|
||||
#include "common/byte_stream.h"
|
||||
#include "common/log.h"
|
||||
#include "common/null_audio_stream.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/controller.h"
|
||||
#include "core/gpu.h"
|
||||
|
@ -126,7 +125,7 @@ void SDLHostInterface::CreateAudioStream()
|
|||
switch (m_settings.audio_backend)
|
||||
{
|
||||
case AudioBackend::Null:
|
||||
m_audio_stream = NullAudioStream::Create();
|
||||
m_audio_stream = AudioStream::CreateNullAudioStream();
|
||||
break;
|
||||
|
||||
case AudioBackend::Default:
|
||||
|
@ -139,7 +138,7 @@ void SDLHostInterface::CreateAudioStream()
|
|||
{
|
||||
ReportError("Failed to recreate audio stream, falling back to null");
|
||||
m_audio_stream.reset();
|
||||
m_audio_stream = NullAudioStream::Create();
|
||||
m_audio_stream = AudioStream::CreateNullAudioStream();
|
||||
if (!m_audio_stream->Reconfigure(AUDIO_SAMPLE_RATE, AUDIO_CHANNELS))
|
||||
Panic("Failed to reconfigure null audio stream");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue