summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorMat M <mathew1800@gmail.com>2017-05-27 21:39:03 -0400
committerGitHub <noreply@github.com>2017-05-27 21:39:03 -0400
commit905232fd2b0f0545e524c4c34859bf62576e43f5 (patch)
tree88d01f6fe28d6c1312eb19c68693aa3d728f66bf /Source/Core
parentd4faa099d95edcc408d90fefb601999b1481d308 (diff)
parentd416cbd9ed5efb391ad65c36ded74c17ab713622 (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.cpp11
-rw-r--r--Source/Core/AudioCommon/AudioCommon.vcxproj4
-rw-r--r--Source/Core/AudioCommon/AudioCommon.vcxproj.filters8
-rw-r--r--Source/Core/AudioCommon/CMakeLists.txt4
-rw-r--r--Source/Core/AudioCommon/CubebStream.cpp112
-rw-r--r--Source/Core/AudioCommon/CubebStream.h32
-rw-r--r--Source/Core/AudioCommon/CubebUtils.cpp75
-rw-r--r--Source/Core/AudioCommon/CubebUtils.h14
-rw-r--r--Source/Core/Common/Logging/LogManager.cpp10
-rw-r--r--Source/Core/Common/Logging/LogManager.h2
-rw-r--r--Source/Core/Core/CMakeLists.txt5
-rw-r--r--Source/Core/Core/ConfigManager.h1
-rw-r--r--Source/Core/Core/Core.vcxproj6
-rw-r--r--Source/Core/Core/HW/EXI/EXI_DeviceMic.cpp112
-rw-r--r--Source/Core/Core/HW/EXI/EXI_DeviceMic.h19
-rw-r--r--Source/Core/DolphinQt2/DolphinQt2.vcxproj2
-rw-r--r--Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp3
-rw-r--r--Source/Core/DolphinWX/DolphinWX.vcxproj2
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,
+ &params, 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, &params, 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>