EXI_DeviceMic: use Cubeb instead of PortAudio
This commit is contained in:
parent
f6e1da0dc0
commit
48d6168c99
|
@ -269,6 +269,7 @@ set(LIBS
|
||||||
audiocommon
|
audiocommon
|
||||||
bdisasm
|
bdisasm
|
||||||
common
|
common
|
||||||
|
cubeb
|
||||||
discio
|
discio
|
||||||
enet
|
enet
|
||||||
inputcommon
|
inputcommon
|
||||||
|
@ -337,10 +338,6 @@ if(TARGET Hidapi::Hidapi)
|
||||||
add_definitions(-DHAVE_HIDAPI=1)
|
add_definitions(-DHAVE_HIDAPI=1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(PORTAUDIO_FOUND)
|
|
||||||
set(LIBS ${LIBS} ${PORTAUDIO_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(OPROFILE_FOUND)
|
if(OPROFILE_FOUND)
|
||||||
set(LIBS ${LIBS} ${OPROFILE_LIBRARIES})
|
set(LIBS ${LIBS} ${OPROFILE_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -9,8 +9,6 @@
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
#if HAVE_PORTAUDIO
|
|
||||||
|
|
||||||
#include "Core/HW/EXI/EXI_DeviceMic.h"
|
#include "Core/HW/EXI/EXI_DeviceMic.h"
|
||||||
|
|
||||||
#include "Core/CoreTiming.h"
|
#include "Core/CoreTiming.h"
|
||||||
|
@ -18,22 +16,14 @@
|
||||||
#include "Core/HW/GCPad.h"
|
#include "Core/HW/GCPad.h"
|
||||||
#include "Core/HW/SystemTimers.h"
|
#include "Core/HW/SystemTimers.h"
|
||||||
|
|
||||||
#include <portaudio.h>
|
#include <cubeb/cubeb.h>
|
||||||
|
|
||||||
namespace ExpansionInterface
|
namespace ExpansionInterface
|
||||||
{
|
{
|
||||||
void CEXIMic::StreamLog(const char* msg)
|
|
||||||
{
|
|
||||||
INFO_LOG(EXPANSIONINTERFACE, "%s: %s", msg, Pa_GetErrorText(pa_error));
|
|
||||||
}
|
|
||||||
|
|
||||||
void CEXIMic::StreamInit()
|
void CEXIMic::StreamInit()
|
||||||
{
|
{
|
||||||
// Setup the wonderful c-interfaced lib...
|
if (cubeb_init(&m_cubeb_ctx, "Dolphin", NULL) != CUBEB_OK)
|
||||||
pa_stream = nullptr;
|
ERROR_LOG(EXPANSIONINTERFACE, "Error initializing cubeb library");
|
||||||
|
|
||||||
if ((pa_error = Pa_Initialize()) != paNoError)
|
|
||||||
StreamLog("Pa_Initialize");
|
|
||||||
|
|
||||||
stream_buffer = nullptr;
|
stream_buffer = nullptr;
|
||||||
samples_avail = stream_wpos = stream_rpos = 0;
|
samples_avail = stream_wpos = stream_rpos = 0;
|
||||||
|
@ -43,73 +33,89 @@ void CEXIMic::StreamTerminate()
|
||||||
{
|
{
|
||||||
StreamStop();
|
StreamStop();
|
||||||
|
|
||||||
if ((pa_error = Pa_Terminate()) != paNoError)
|
if (m_cubeb_ctx)
|
||||||
StreamLog("Pa_Terminate");
|
{
|
||||||
|
cubeb_destroy(m_cubeb_ctx);
|
||||||
|
m_cubeb_ctx = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Pa_Callback(const void* inputBuffer, void* outputBuffer, unsigned long framesPerBuffer,
|
static void state_callback(cubeb_stream* stream, void* user_data, cubeb_state state)
|
||||||
const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags,
|
|
||||||
void* userData)
|
|
||||||
{
|
{
|
||||||
(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);
|
std::lock_guard<std::mutex> lk(mic->ring_lock);
|
||||||
|
|
||||||
if (mic->stream_wpos + mic->buff_size_samples > mic->stream_size)
|
const s16* buff_in = static_cast<const s16*>(inputbuffer);
|
||||||
mic->stream_wpos = 0;
|
for (long i = 0; i < nframes; i++)
|
||||||
|
|
||||||
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++)
|
mic->stream_buffer[mic->stream_wpos] = buff_in[i];
|
||||||
{
|
mic->stream_wpos = (mic->stream_wpos + 1) % mic->stream_size;
|
||||||
buff_out[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < mic->buff_size_samples; i++)
|
|
||||||
{
|
|
||||||
buff_out[i] = buff_in[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mic->samples_avail += mic->buff_size_samples;
|
mic->samples_avail += nframes;
|
||||||
if (mic->samples_avail > mic->stream_size)
|
if (mic->samples_avail > mic->stream_size)
|
||||||
{
|
{
|
||||||
mic->samples_avail = 0;
|
mic->samples_avail = 0;
|
||||||
mic->status.buff_ovrflw = 1;
|
mic->status.buff_ovrflw = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
mic->stream_wpos += mic->buff_size_samples;
|
return nframes;
|
||||||
mic->stream_wpos %= mic->stream_size;
|
|
||||||
|
|
||||||
return paContinue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIMic::StreamStart()
|
void CEXIMic::StreamStart()
|
||||||
{
|
{
|
||||||
|
if (!m_cubeb_ctx)
|
||||||
|
return;
|
||||||
|
|
||||||
// Open stream with current parameters
|
// Open stream with current parameters
|
||||||
stream_size = buff_size_samples * 500;
|
stream_size = buff_size_samples * 500;
|
||||||
stream_buffer = new s16[stream_size];
|
stream_buffer = new s16[stream_size];
|
||||||
|
|
||||||
pa_error = Pa_OpenDefaultStream(&pa_stream, 1, 0, paInt16, sample_rate, buff_size_samples,
|
cubeb_stream_params params;
|
||||||
Pa_Callback, this);
|
params.format = CUBEB_SAMPLE_S16LE;
|
||||||
StreamLog("Pa_OpenDefaultStream");
|
params.rate = sample_rate;
|
||||||
pa_error = Pa_StartStream(pa_stream);
|
params.channels = 1;
|
||||||
StreamLog("Pa_StartStream");
|
params.layout = CUBEB_LAYOUT_MONO;
|
||||||
|
|
||||||
|
u32 minimum_latency;
|
||||||
|
if (cubeb_get_min_latency(m_cubeb_ctx, params, &minimum_latency) != CUBEB_OK)
|
||||||
|
{
|
||||||
|
WARN_LOG(EXPANSIONINTERFACE, "Error getting minimum latency");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cubeb_stream_init(m_cubeb_ctx, &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()
|
void CEXIMic::StreamStop()
|
||||||
{
|
{
|
||||||
if (pa_stream != nullptr && Pa_IsStreamActive(pa_stream) >= paNoError)
|
if (m_cubeb_stream)
|
||||||
Pa_AbortStream(pa_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;
|
samples_avail = stream_wpos = stream_rpos = 0;
|
||||||
|
|
||||||
|
@ -134,11 +140,11 @@ void CEXIMic::StreamReadOne()
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXI Mic Device
|
// 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
|
// 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
|
// buffer size settings. When the console handles the interrupt, it will send
|
||||||
// cmdGetBuffer, which is when we actually read data from a buffer filled
|
// 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};
|
u8 const CEXIMic::exi_id[] = {0, 0x0a, 0, 0, 0};
|
||||||
|
|
||||||
|
@ -271,4 +277,3 @@ void CEXIMic::TransferByte(u8& byte)
|
||||||
m_position++;
|
m_position++;
|
||||||
}
|
}
|
||||||
} // namespace ExpansionInterface
|
} // namespace ExpansionInterface
|
||||||
#endif
|
|
||||||
|
|
|
@ -8,10 +8,11 @@
|
||||||
#include "Common/Common.h"
|
#include "Common/Common.h"
|
||||||
#include "Core/HW/EXI/EXI_Device.h"
|
#include "Core/HW/EXI/EXI_Device.h"
|
||||||
|
|
||||||
|
struct cubeb;
|
||||||
|
struct cubeb_stream;
|
||||||
|
|
||||||
namespace ExpansionInterface
|
namespace ExpansionInterface
|
||||||
{
|
{
|
||||||
#if HAVE_PORTAUDIO
|
|
||||||
|
|
||||||
class CEXIMic : public IEXIDevice
|
class CEXIMic : public IEXIDevice
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -68,8 +69,8 @@ private:
|
||||||
void UpdateNextInterruptTicks();
|
void UpdateNextInterruptTicks();
|
||||||
|
|
||||||
// Streaming input interface
|
// Streaming input interface
|
||||||
int pa_error; // PaError
|
cubeb* m_cubeb_ctx = nullptr;
|
||||||
void* pa_stream; // PaStream
|
cubeb_stream* m_cubeb_stream = nullptr;
|
||||||
|
|
||||||
void StreamLog(const char* msg);
|
void StreamLog(const char* msg);
|
||||||
void StreamInit();
|
void StreamInit();
|
||||||
|
@ -99,14 +100,4 @@ public:
|
||||||
protected:
|
protected:
|
||||||
void TransferByte(u8& byte) override;
|
void TransferByte(u8& byte) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#else // HAVE_PORTAUDIO
|
|
||||||
|
|
||||||
class CEXIMic : public IEXIDevice
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CEXIMic(const int) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
} // namespace ExpansionInterface
|
} // namespace ExpansionInterface
|
||||||
|
|
|
@ -158,10 +158,7 @@ void GameCubeConfigPane::LoadGUIValues()
|
||||||
slot_devices.Add(_(EXIDEV_MEMDIR_STR));
|
slot_devices.Add(_(EXIDEV_MEMDIR_STR));
|
||||||
slot_devices.Add(_(EXIDEV_GECKO_STR));
|
slot_devices.Add(_(EXIDEV_GECKO_STR));
|
||||||
slot_devices.Add(_(EXIDEV_AGP_STR));
|
slot_devices.Add(_(EXIDEV_AGP_STR));
|
||||||
|
|
||||||
#if HAVE_PORTAUDIO
|
|
||||||
slot_devices.Add(_(EXIDEV_MIC_STR));
|
slot_devices.Add(_(EXIDEV_MIC_STR));
|
||||||
#endif
|
|
||||||
|
|
||||||
wxArrayString sp1_devices;
|
wxArrayString sp1_devices;
|
||||||
sp1_devices.Add(_(DEV_NONE_STR));
|
sp1_devices.Add(_(DEV_NONE_STR));
|
||||||
|
|
Loading…
Reference in New Issue