diff options
| author | Mat M <mathew1800@gmail.com> | 2017-05-27 21:39:03 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-05-27 21:39:03 -0400 |
| commit | 905232fd2b0f0545e524c4c34859bf62576e43f5 (patch) | |
| tree | 88d01f6fe28d6c1312eb19c68693aa3d728f66bf /Source/Core | |
| parent | d4faa099d95edcc408d90fefb601999b1481d308 (diff) | |
| parent | d416cbd9ed5efb391ad65c36ded74c17ab713622 (diff) | |
Merge pull request #5313 from ligfx/addcubeb
Add CubebStream output backend and replace PortAudio for microphones
Diffstat (limited to 'Source/Core')
| -rw-r--r-- | Source/Core/AudioCommon/AudioCommon.cpp | 11 | ||||
| -rw-r--r-- | Source/Core/AudioCommon/AudioCommon.vcxproj | 4 | ||||
| -rw-r--r-- | Source/Core/AudioCommon/AudioCommon.vcxproj.filters | 8 | ||||
| -rw-r--r-- | Source/Core/AudioCommon/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | Source/Core/AudioCommon/CubebStream.cpp | 112 | ||||
| -rw-r--r-- | Source/Core/AudioCommon/CubebStream.h | 32 | ||||
| -rw-r--r-- | Source/Core/AudioCommon/CubebUtils.cpp | 75 | ||||
| -rw-r--r-- | Source/Core/AudioCommon/CubebUtils.h | 14 | ||||
| -rw-r--r-- | Source/Core/Common/Logging/LogManager.cpp | 10 | ||||
| -rw-r--r-- | Source/Core/Common/Logging/LogManager.h | 2 | ||||
| -rw-r--r-- | Source/Core/Core/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | Source/Core/Core/ConfigManager.h | 1 | ||||
| -rw-r--r-- | Source/Core/Core/Core.vcxproj | 6 | ||||
| -rw-r--r-- | Source/Core/Core/HW/EXI/EXI_DeviceMic.cpp | 112 | ||||
| -rw-r--r-- | Source/Core/Core/HW/EXI/EXI_DeviceMic.h | 19 | ||||
| -rw-r--r-- | Source/Core/DolphinQt2/DolphinQt2.vcxproj | 2 | ||||
| -rw-r--r-- | Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp | 3 | ||||
| -rw-r--r-- | Source/Core/DolphinWX/DolphinWX.vcxproj | 2 |
18 files changed, 334 insertions, 88 deletions
diff --git a/Source/Core/AudioCommon/AudioCommon.cpp b/Source/Core/AudioCommon/AudioCommon.cpp index fea933e582..6fc5a70c84 100644 --- a/Source/Core/AudioCommon/AudioCommon.cpp +++ b/Source/Core/AudioCommon/AudioCommon.cpp @@ -5,6 +5,7 @@ #include "AudioCommon/AudioCommon.h" #include "AudioCommon/AlsaSoundStream.h" #include "AudioCommon/CoreAudioSoundStream.h" +#include "AudioCommon/CubebStream.h" #include "AudioCommon/Mixer.h" #include "AudioCommon/NullSoundStream.h" #include "AudioCommon/OpenALStream.h" @@ -30,7 +31,9 @@ static const int AUDIO_VOLUME_MAX = 100; void InitSoundStream() { std::string backend = SConfig::GetInstance().sBackend; - if (backend == BACKEND_OPENAL && OpenALStream::isValid()) + if (backend == BACKEND_CUBEB) + g_sound_stream = std::make_unique<CubebStream>(); + else if (backend == BACKEND_OPENAL && OpenALStream::isValid()) g_sound_stream = std::make_unique<OpenALStream>(); else if (backend == BACKEND_NULLSOUND) g_sound_stream = std::make_unique<NullSound>(); @@ -110,6 +113,7 @@ std::vector<std::string> GetSoundBackends() std::vector<std::string> backends; backends.push_back(BACKEND_NULLSOUND); + backends.push_back(BACKEND_CUBEB); if (XAudio2_7::isValid() || XAudio2::isValid()) backends.push_back(BACKEND_XAUDIO2); if (AlsaSound::isValid()) @@ -131,6 +135,8 @@ bool SupportsDPL2Decoder(const std::string& backend) if (backend == BACKEND_OPENAL) return true; #endif + if (backend == BACKEND_CUBEB) + return true; if (backend == BACKEND_PULSEAUDIO) return true; return false; @@ -146,7 +152,8 @@ bool SupportsVolumeChanges(const std::string& backend) // FIXME: this one should ask the backend whether it supports it. // but getting the backend from string etc. is probably // too much just to enable/disable a stupid slider... - return backend == BACKEND_COREAUDIO || backend == BACKEND_OPENAL || backend == BACKEND_XAUDIO2; + return backend == BACKEND_COREAUDIO || backend == BACKEND_CUBEB || backend == BACKEND_OPENAL || + backend == BACKEND_XAUDIO2; } void UpdateSoundStream() diff --git a/Source/Core/AudioCommon/AudioCommon.vcxproj b/Source/Core/AudioCommon/AudioCommon.vcxproj index afc86a7222..2ccb711ee5 100644 --- a/Source/Core/AudioCommon/AudioCommon.vcxproj +++ b/Source/Core/AudioCommon/AudioCommon.vcxproj @@ -37,6 +37,8 @@ <ItemGroup> <ClCompile Include="aldlist.cpp" /> <ClCompile Include="AudioCommon.cpp" /> + <ClCompile Include="CubebStream.cpp" /> + <ClCompile Include="CubebUtils.cpp" /> <ClCompile Include="DPL2Decoder.cpp" /> <ClCompile Include="Mixer.cpp" /> <ClCompile Include="NullSoundStream.cpp" /> @@ -52,6 +54,8 @@ <ClInclude Include="AlsaSoundStream.h" /> <ClInclude Include="AudioCommon.h" /> <ClInclude Include="CoreAudioSoundStream.h" /> + <ClInclude Include="CubebStream.h" /> + <ClInclude Include="CubebUtils.h" /> <ClInclude Include="DPL2Decoder.h" /> <ClInclude Include="Mixer.h" /> <ClInclude Include="NullSoundStream.h" /> diff --git a/Source/Core/AudioCommon/AudioCommon.vcxproj.filters b/Source/Core/AudioCommon/AudioCommon.vcxproj.filters index 3103ad558e..7c3fe389ee 100644 --- a/Source/Core/AudioCommon/AudioCommon.vcxproj.filters +++ b/Source/Core/AudioCommon/AudioCommon.vcxproj.filters @@ -8,6 +8,7 @@ <ItemGroup> <ClCompile Include="aldlist.cpp" /> <ClCompile Include="AudioCommon.cpp" /> + <ClCompile Include="CubebUtils.cpp" /> <ClCompile Include="DPL2Decoder.cpp" /> <ClCompile Include="Mixer.cpp" /> <ClCompile Include="WaveFile.cpp" /> @@ -23,10 +24,14 @@ <ClCompile Include="XAudio2_7Stream.cpp"> <Filter>SoundStreams</Filter> </ClCompile> + <ClCompile Include="CubebStream.cpp"> + <Filter>SoundStreams</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="aldlist.h" /> <ClInclude Include="AudioCommon.h" /> + <ClInclude Include="CubebUtils.h" /> <ClInclude Include="DPL2Decoder.h" /> <ClInclude Include="Mixer.h" /> <ClInclude Include="WaveFile.h" /> @@ -57,6 +62,9 @@ <ClInclude Include="SoundStream.h"> <Filter>SoundStreams</Filter> </ClInclude> + <ClInclude Include="CubebStream.h"> + <Filter>SoundStreams</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <Text Include="CMakeLists.txt" /> diff --git a/Source/Core/AudioCommon/CMakeLists.txt b/Source/Core/AudioCommon/CMakeLists.txt index 8f0a283db8..94eb45c9ed 100644 --- a/Source/Core/AudioCommon/CMakeLists.txt +++ b/Source/Core/AudioCommon/CMakeLists.txt @@ -1,5 +1,7 @@ set(SRCS AudioCommon.cpp + CubebStream.cpp + CubebUtils.cpp DPL2Decoder.cpp Mixer.cpp WaveFile.cpp @@ -76,4 +78,4 @@ elseif(APPLE) target_sources(audiocommon PRIVATE CoreAudioSoundStream.cpp) endif() -target_link_libraries(audiocommon PRIVATE SoundTouch) +target_link_libraries(audiocommon PRIVATE cubeb SoundTouch) diff --git a/Source/Core/AudioCommon/CubebStream.cpp b/Source/Core/AudioCommon/CubebStream.cpp new file mode 100644 index 0000000000..c9052e29c9 --- /dev/null +++ b/Source/Core/AudioCommon/CubebStream.cpp @@ -0,0 +1,112 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include <cubeb/cubeb.h> + +#include "AudioCommon/CubebStream.h" +#include "AudioCommon/CubebUtils.h" +#include "AudioCommon/DPL2Decoder.h" +#include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" +#include "Common/Thread.h" +#include "Core/ConfigManager.h" + +// ~10 ms - needs to be at least 240 for surround +constexpr u32 BUFFER_SAMPLES = 512; + +long CubebStream::DataCallback(cubeb_stream* stream, void* user_data, const void* /*input_buffer*/, + void* output_buffer, long num_frames) +{ + auto* self = static_cast<CubebStream*>(user_data); + + if (self->m_stereo) + { + self->m_mixer->Mix(static_cast<short*>(output_buffer), num_frames); + } + else + { + size_t required_capacity = num_frames * 2; + if (required_capacity > self->m_short_buffer.capacity() || + required_capacity > self->m_floatstereo_buffer.capacity()) + { + INFO_LOG(AUDIO, "Expanding conversion buffers size: %li frames", num_frames); + self->m_short_buffer.reserve(required_capacity); + self->m_floatstereo_buffer.reserve(required_capacity); + } + + self->m_mixer->Mix(self->m_short_buffer.data(), num_frames); + + // s16 to float + for (size_t i = 0; i < static_cast<size_t>(num_frames) * 2; ++i) + self->m_floatstereo_buffer[i] = self->m_short_buffer[i] / static_cast<float>(1 << 15); + + // DPL2Decode output: LEFTFRONT, RIGHTFRONT, CENTREFRONT, (sub), LEFTREAR, RIGHTREAR + DPL2Decode(self->m_floatstereo_buffer.data(), num_frames, static_cast<float*>(output_buffer)); + } + + return num_frames; +} + +void CubebStream::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) +{ +} + +bool CubebStream::Start() +{ + m_ctx = CubebUtils::GetContext(); + if (!m_ctx) + return false; + + m_stereo = !SConfig::GetInstance().bDPL2Decoder; + + cubeb_stream_params params; + params.rate = m_mixer->GetSampleRate(); + if (m_stereo) + { + params.channels = 2; + params.format = CUBEB_SAMPLE_S16NE; + params.layout = CUBEB_LAYOUT_STEREO; + } + else + { + params.channels = 6; + params.format = CUBEB_SAMPLE_FLOAT32NE; + params.layout = CUBEB_LAYOUT_3F2_LFE; + } + + u32 minimum_latency = 0; + if (cubeb_get_min_latency(m_ctx.get(), params, &minimum_latency) != CUBEB_OK) + ERROR_LOG(AUDIO, "Error getting minimum latency"); + INFO_LOG(AUDIO, "Minimum latency: %i frames", minimum_latency); + + if (cubeb_stream_init(m_ctx.get(), &m_stream, "Dolphin Audio Output", nullptr, nullptr, nullptr, + ¶ms, std::max(BUFFER_SAMPLES, minimum_latency), DataCallback, + StateCallback, this) != CUBEB_OK) + { + ERROR_LOG(AUDIO, "Error initializing cubeb stream"); + return false; + } + + if (cubeb_stream_start(m_stream) != CUBEB_OK) + { + ERROR_LOG(AUDIO, "Error starting cubeb stream"); + return false; + } + return true; +} + +void CubebStream::Stop() +{ + if (cubeb_stream_stop(m_stream) != CUBEB_OK) + { + ERROR_LOG(AUDIO, "Error stopping cubeb stream"); + } + cubeb_stream_destroy(m_stream); + m_ctx.reset(); +} + +void CubebStream::SetVolume(int volume) +{ + cubeb_stream_set_volume(m_stream, volume / 100.0f); +} diff --git a/Source/Core/AudioCommon/CubebStream.h b/Source/Core/AudioCommon/CubebStream.h new file mode 100644 index 0000000000..d0b153975e --- /dev/null +++ b/Source/Core/AudioCommon/CubebStream.h @@ -0,0 +1,32 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include <cstddef> +#include <memory> + +#include "AudioCommon/SoundStream.h" + +#include <cubeb/cubeb.h> + +class CubebStream final : public SoundStream +{ +public: + bool Start() override; + void Stop() override; + void SetVolume(int) override; + +private: + bool m_stereo = false; + std::shared_ptr<cubeb> m_ctx; + cubeb_stream* m_stream = nullptr; + + std::vector<short> m_short_buffer; + std::vector<float> m_floatstereo_buffer; + + static long DataCallback(cubeb_stream* stream, void* user_data, const void* /*input_buffer*/, + void* output_buffer, long num_frames); + static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state); +}; diff --git a/Source/Core/AudioCommon/CubebUtils.cpp b/Source/Core/AudioCommon/CubebUtils.cpp new file mode 100644 index 0000000000..07f4f530d6 --- /dev/null +++ b/Source/Core/AudioCommon/CubebUtils.cpp @@ -0,0 +1,75 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include <cstdarg> +#include <cstddef> +#include <cstring> + +#include "AudioCommon/CubebUtils.h" +#include "Common/CommonPaths.h" +#include "Common/Logging/Log.h" +#include "Common/Logging/LogManager.h" +#include "Common/StringUtil.h" + +#include <cubeb/cubeb.h> + +static ptrdiff_t s_path_cutoff_point = 0; + +static void LogCallback(const char* format, ...) +{ + if (!LogManager::GetInstance()) + return; + + va_list args; + va_start(args, format); + + const char* filename = va_arg(args, const char*) + s_path_cutoff_point; + int lineno = va_arg(args, int); + std::string adapted_format = StripSpaces(format + strlen("%s:%d:")); + + LogManager::GetInstance()->LogWithFullPath(LogTypes::LNOTICE, LogTypes::AUDIO, filename, lineno, + adapted_format.c_str(), args); + va_end(args); +} + +static void DestroyContext(cubeb* ctx) +{ + cubeb_destroy(ctx); + if (cubeb_set_log_callback(CUBEB_LOG_DISABLED, nullptr) != CUBEB_OK) + { + ERROR_LOG(AUDIO, "Error removing cubeb log callback"); + } +} + +std::shared_ptr<cubeb> CubebUtils::GetContext() +{ + static std::weak_ptr<cubeb> weak; + + std::shared_ptr<cubeb> shared = weak.lock(); + // Already initialized + if (shared) + return shared; + + const char* filename = __FILE__; + const char* match_point = strstr(filename, DIR_SEP "Source" DIR_SEP "Core" DIR_SEP); + if (match_point) + { + s_path_cutoff_point = match_point - filename + strlen(DIR_SEP "Externals" DIR_SEP); + } + if (cubeb_set_log_callback(CUBEB_LOG_NORMAL, LogCallback) != CUBEB_OK) + { + ERROR_LOG(AUDIO, "Error setting cubeb log callback"); + } + + cubeb* ctx; + if (cubeb_init(&ctx, "Dolphin", nullptr) != CUBEB_OK) + { + ERROR_LOG(AUDIO, "Error initializing cubeb library"); + return nullptr; + } + INFO_LOG(AUDIO, "Cubeb initialized using %s backend", cubeb_get_backend_id(ctx)); + + weak = shared = {ctx, DestroyContext}; + return shared; +} diff --git a/Source/Core/AudioCommon/CubebUtils.h b/Source/Core/AudioCommon/CubebUtils.h new file mode 100644 index 0000000000..adf6c25484 --- /dev/null +++ b/Source/Core/AudioCommon/CubebUtils.h @@ -0,0 +1,14 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include <memory> + +struct cubeb; + +namespace CubebUtils +{ +std::shared_ptr<cubeb> GetContext(); +} // namespace CubebUtils diff --git a/Source/Core/Common/Logging/LogManager.cpp b/Source/Core/Common/Logging/LogManager.cpp index 18fd57fd43..3b2d925047 100644 --- a/Source/Core/Common/Logging/LogManager.cpp +++ b/Source/Core/Common/Logging/LogManager.cpp @@ -130,6 +130,12 @@ LogManager::~LogManager() void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, const char* format, va_list args) { + return LogWithFullPath(level, type, file + m_path_cutoff_point, line, format, args); +} + +void LogManager::LogWithFullPath(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, + const char* file, int line, const char* format, va_list args) +{ char temp[MAX_MSGLEN]; LogContainer* log = m_Log[type]; @@ -138,10 +144,8 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const CharArrayFromFormatV(temp, MAX_MSGLEN, format, args); - const char* path_to_print = file + m_path_cutoff_point; - std::string msg = StringFromFormat( - "%s %s:%u %c[%s]: %s\n", Common::Timer::GetTimeFormatted().c_str(), path_to_print, line, + "%s %s:%u %c[%s]: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line, LogTypes::LOG_LEVEL_TO_CHAR[(int)level], log->GetShortName().c_str(), temp); for (auto listener_id : *log) diff --git a/Source/Core/Common/Logging/LogManager.h b/Source/Core/Common/Logging/LogManager.h index ea7f2d86a3..0ec3c1f7de 100644 --- a/Source/Core/Common/Logging/LogManager.h +++ b/Source/Core/Common/Logging/LogManager.h @@ -96,6 +96,8 @@ public: static u32 GetMaxLevel() { return MAX_LOGLEVEL; } void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, const char* fmt, va_list args); + void LogWithFullPath(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, + int line, const char* fmt, va_list args); void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) { diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 8bdef30bc6..2712a9f951 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -269,6 +269,7 @@ set(LIBS audiocommon bdisasm common + cubeb discio enet inputcommon @@ -337,10 +338,6 @@ if(TARGET Hidapi::Hidapi) add_definitions(-DHAVE_HIDAPI=1) endif() -if(PORTAUDIO_FOUND) - set(LIBS ${LIBS} ${PORTAUDIO_LIBRARIES}) -endif() - if(OPROFILE_FOUND) set(LIBS ${LIBS} ${OPROFILE_LIBRARIES}) endif() diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index be35ea8e7e..75b8526b75 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -35,6 +35,7 @@ class TMDReader; #define BACKEND_NULLSOUND _trans("No audio output") #define BACKEND_ALSA "ALSA" #define BACKEND_COREAUDIO "CoreAudio" +#define BACKEND_CUBEB "Cubeb" #define BACKEND_OPENAL "OpenAL" #define BACKEND_PULSEAUDIO "Pulse" #define BACKEND_XAUDIO2 "XAudio2" diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index 7b700729d5..f47971e856 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -536,9 +536,6 @@ <ProjectReference Include="$(ExternalsDir)mbedtls\mbedTLS.vcxproj"> <Project>{bdb6578b-0691-4e80-a46c-df21639fd3b8}</Project> </ProjectReference> - <ProjectReference Include="$(ExternalsDir)portaudio\build\portaudio.vcxproj"> - <Project>{0a18a071-125e-442f-aff7-a3f68abecf99}</Project> - </ProjectReference> <ProjectReference Include="$(ExternalsDir)SFML\build\vc2010\SFML_Network.vcxproj"> <Project>{93d73454-2512-424e-9cda-4bb357fe13dd}</Project> </ProjectReference> @@ -560,6 +557,9 @@ <ProjectReference Include="$(CoreDir)VideoCommon\VideoCommon.vcxproj"> <Project>{3de9ee35-3e91-4f27-a014-2866ad8c3fe3}</Project> </ProjectReference> + <ProjectReference Include="..\..\..\Externals\cubeb\msvc\cubeb.vcxproj"> + <Project>{8ea11166-6512-44fc-b7a5-a4d1ecc81170}</Project> + </ProjectReference> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceMic.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceMic.cpp index 47e25ef621..0ad3a263a3 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceMic.cpp +++ b/Source/Core/Core/HW/EXI/EXI_DeviceMic.cpp @@ -5,12 +5,11 @@ #include <cstring> #include <mutex> +#include "AudioCommon/CubebUtils.h" #include "Common/Common.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" -#if HAVE_PORTAUDIO - #include "Core/HW/EXI/EXI_DeviceMic.h" #include "Core/CoreTiming.h" @@ -18,22 +17,13 @@ #include "Core/HW/GCPad.h" #include "Core/HW/SystemTimers.h" -#include <portaudio.h> +#include <cubeb/cubeb.h> namespace ExpansionInterface { -void CEXIMic::StreamLog(const char* msg) -{ - INFO_LOG(EXPANSIONINTERFACE, "%s: %s", msg, Pa_GetErrorText(pa_error)); -} - void CEXIMic::StreamInit() { - // Setup the wonderful c-interfaced lib... - pa_stream = nullptr; - - if ((pa_error = Pa_Initialize()) != paNoError) - StreamLog("Pa_Initialize"); + m_cubeb_ctx = CubebUtils::GetContext(); stream_buffer = nullptr; samples_avail = stream_wpos = stream_rpos = 0; @@ -42,74 +32,85 @@ void CEXIMic::StreamInit() void CEXIMic::StreamTerminate() { StreamStop(); - - if ((pa_error = Pa_Terminate()) != paNoError) - StreamLog("Pa_Terminate"); + m_cubeb_ctx.reset(); } -static int Pa_Callback(const void* inputBuffer, void* outputBuffer, unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, - void* userData) +static void state_callback(cubeb_stream* stream, void* user_data, cubeb_state state) { - (void)outputBuffer; - (void)timeInfo; - (void)statusFlags; +} - CEXIMic* mic = (CEXIMic*)userData; +static long data_callback(cubeb_stream* stream, void* user_data, const void* inputbuffer, + void* /*outputbuffer*/, long nframes) +{ + CEXIMic* mic = static_cast<CEXIMic*>(user_data); std::lock_guard<std::mutex> lk(mic->ring_lock); - if (mic->stream_wpos + mic->buff_size_samples > mic->stream_size) - mic->stream_wpos = 0; - - const s16* buff_in = static_cast<const s16*>(inputBuffer); - s16* buff_out = &mic->stream_buffer[mic->stream_wpos]; - - if (buff_in == nullptr) - { - for (int i = 0; i < mic->buff_size_samples; i++) - { - buff_out[i] = 0; - } - } - else + const s16* buff_in = static_cast<const s16*>(inputbuffer); + for (long i = 0; i < nframes; i++) { - for (int i = 0; i < mic->buff_size_samples; i++) - { - buff_out[i] = buff_in[i]; - } + mic->stream_buffer[mic->stream_wpos] = buff_in[i]; + mic->stream_wpos = (mic->stream_wpos + 1) % mic->stream_size; } - mic->samples_avail += mic->buff_size_samples; + mic->samples_avail += nframes; if (mic->samples_avail > mic->stream_size) { mic->samples_avail = 0; mic->status.buff_ovrflw = 1; } - mic->stream_wpos += mic->buff_size_samples; - mic->stream_wpos %= mic->stream_size; - - return paContinue; + return nframes; } void CEXIMic::StreamStart() { + if (!m_cubeb_ctx) + return; + // Open stream with current parameters stream_size = buff_size_samples * 500; stream_buffer = new s16[stream_size]; - pa_error = Pa_OpenDefaultStream(&pa_stream, 1, 0, paInt16, sample_rate, buff_size_samples, - Pa_Callback, this); - StreamLog("Pa_OpenDefaultStream"); - pa_error = Pa_StartStream(pa_stream); - StreamLog("Pa_StartStream"); + cubeb_stream_params params; + params.format = CUBEB_SAMPLE_S16LE; + params.rate = sample_rate; + params.channels = 1; + params.layout = CUBEB_LAYOUT_MONO; + + u32 minimum_latency; + if (cubeb_get_min_latency(m_cubeb_ctx.get(), params, &minimum_latency) != CUBEB_OK) + { + WARN_LOG(EXPANSIONINTERFACE, "Error getting minimum latency"); + } + + if (cubeb_stream_init(m_cubeb_ctx.get(), &m_cubeb_stream, "Dolphin Emulated GameCube Microphone", + nullptr, ¶ms, nullptr, nullptr, + std::max<u32>(buff_size_samples, minimum_latency), data_callback, + state_callback, this) != CUBEB_OK) + { + ERROR_LOG(EXPANSIONINTERFACE, "Error initializing cubeb stream"); + return; + } + + if (cubeb_stream_start(m_cubeb_stream) != CUBEB_OK) + { + ERROR_LOG(EXPANSIONINTERFACE, "Error starting cubeb stream"); + return; + } + + INFO_LOG(EXPANSIONINTERFACE, "started cubeb stream"); } void CEXIMic::StreamStop() { - if (pa_stream != nullptr && Pa_IsStreamActive(pa_stream) >= paNoError) - Pa_AbortStream(pa_stream); + if (m_cubeb_stream) + { + if (cubeb_stream_stop(m_cubeb_stream) != CUBEB_OK) + ERROR_LOG(EXPANSIONINTERFACE, "Error stopping cubeb stream"); + cubeb_stream_destroy(m_cubeb_stream); + m_cubeb_stream = nullptr; + } samples_avail = stream_wpos = stream_rpos = 0; @@ -134,11 +135,11 @@ void CEXIMic::StreamReadOne() } // EXI Mic Device -// This works by opening and starting a portaudio input stream when the is_active +// This works by opening and starting an input stream when the is_active // bit is set. The interrupt is scheduled in the future based on sample rate and // buffer size settings. When the console handles the interrupt, it will send // cmdGetBuffer, which is when we actually read data from a buffer filled -// in the background by Pa_Callback. +// in the background. u8 const CEXIMic::exi_id[] = {0, 0x0a, 0, 0, 0}; @@ -271,4 +272,3 @@ void CEXIMic::TransferByte(u8& byte) m_position++; } } // namespace ExpansionInterface -#endif diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceMic.h b/Source/Core/Core/HW/EXI/EXI_DeviceMic.h index e8d97f0320..7f43798538 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceMic.h +++ b/Source/Core/Core/HW/EXI/EXI_DeviceMic.h @@ -8,10 +8,11 @@ #include "Common/Common.h" #include "Core/HW/EXI/EXI_Device.h" +struct cubeb; +struct cubeb_stream; + namespace ExpansionInterface { -#if HAVE_PORTAUDIO - class CEXIMic : public IEXIDevice { public: @@ -68,8 +69,8 @@ private: void UpdateNextInterruptTicks(); // Streaming input interface - int pa_error; // PaError - void* pa_stream; // PaStream + std::shared_ptr<cubeb> m_cubeb_ctx = nullptr; + cubeb_stream* m_cubeb_stream = nullptr; void StreamLog(const char* msg); void StreamInit(); @@ -99,14 +100,4 @@ public: protected: void TransferByte(u8& byte) override; }; - -#else // HAVE_PORTAUDIO - -class CEXIMic : public IEXIDevice -{ -public: - CEXIMic(const int) {} -}; - -#endif } // namespace ExpansionInterface diff --git a/Source/Core/DolphinQt2/DolphinQt2.vcxproj b/Source/Core/DolphinQt2/DolphinQt2.vcxproj index 3f349a7996..2c6d5e6a89 100644 --- a/Source/Core/DolphinQt2/DolphinQt2.vcxproj +++ b/Source/Core/DolphinQt2/DolphinQt2.vcxproj @@ -50,7 +50,7 @@ <RandomizedBaseAddress>false</RandomizedBaseAddress> <FixedBaseAddress>true</FixedBaseAddress> <AdditionalLibraryDirectories>$(ExternalsDir)ffmpeg\lib;$(ExternalsDir)OpenAL\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> - <AdditionalDependencies>iphlpapi.lib;winmm.lib;setupapi.lib;opengl32.lib;glu32.lib;rpcrt4.lib;comctl32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>avrt.lib;iphlpapi.lib;winmm.lib;setupapi.lib;opengl32.lib;glu32.lib;rpcrt4.lib;comctl32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;%(AdditionalDependencies)</AdditionalDependencies> <SubSystem Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Windows</SubSystem> <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">/NODEFAULTLIB:libcmt</AdditionalOptions> <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">/NODEFAULTLIB:libcmt</AdditionalOptions> diff --git a/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp b/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp index 84499cd38f..b4350562d4 100644 --- a/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp @@ -158,10 +158,7 @@ void GameCubeConfigPane::LoadGUIValues() slot_devices.Add(_(EXIDEV_MEMDIR_STR)); slot_devices.Add(_(EXIDEV_GECKO_STR)); slot_devices.Add(_(EXIDEV_AGP_STR)); - -#if HAVE_PORTAUDIO slot_devices.Add(_(EXIDEV_MIC_STR)); -#endif wxArrayString sp1_devices; sp1_devices.Add(_(DEV_NONE_STR)); diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj b/Source/Core/DolphinWX/DolphinWX.vcxproj index 17e6105bce..e0a49a255f 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcxproj +++ b/Source/Core/DolphinWX/DolphinWX.vcxproj @@ -41,7 +41,7 @@ <RandomizedBaseAddress>false</RandomizedBaseAddress> <FixedBaseAddress>true</FixedBaseAddress> <AdditionalLibraryDirectories>$(ExternalsDir)ffmpeg\lib;$(ExternalsDir)OpenAL\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> - <AdditionalDependencies>iphlpapi.lib;winmm.lib;setupapi.lib;opengl32.lib;glu32.lib;rpcrt4.lib;comctl32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>avrt.lib;iphlpapi.lib;winmm.lib;setupapi.lib;opengl32.lib;glu32.lib;rpcrt4.lib;comctl32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">/NODEFAULTLIB:libcmt %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">/NODEFAULTLIB:libcmt %(AdditionalOptions)</AdditionalOptions> </Link> |
