mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
Merge branch 'gc-mic'
Added GameCube Microphone support. Uses your default audio recording device. The Microphone is selectable from the Slot A/Slot B pulldowns under the GameCube tab. The Microphone button can be set under GCPad configuration for pad 1 and 2. Thanks to MooglyGuy and skidau.
This commit is contained in:
@ -89,6 +89,8 @@ private:
|
||||
// Since it is always around on windows
|
||||
#define HAVE_WX 1
|
||||
|
||||
#define HAVE_PORTAUDIO 1
|
||||
|
||||
// Debug definitions
|
||||
#if defined(_DEBUG)
|
||||
#include <crtdbg.h>
|
||||
|
@ -115,7 +115,7 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@ -127,7 +127,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@ -139,7 +139,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@ -153,7 +153,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@ -167,7 +167,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@ -181,7 +181,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -355,7 +355,7 @@ void SConfig::LoadSettings()
|
||||
ini.Get("Core", "MemcardA", &m_strMemoryCardA);
|
||||
ini.Get("Core", "MemcardB", &m_strMemoryCardB);
|
||||
ini.Get("Core", "ReloadMemcardOnState", &b_reloadMCOnState, true);
|
||||
ini.Get("Core", "SlotA", (int*)&m_EXIDevice[0], EXIDEVICE_MEMORYCARD_A);
|
||||
ini.Get("Core", "SlotA", (int*)&m_EXIDevice[0], EXIDEVICE_MEMORYCARD);
|
||||
ini.Get("Core", "SlotB", (int*)&m_EXIDevice[1], EXIDEVICE_NONE);
|
||||
ini.Get("Core", "SerialPort1", (int*)&m_EXIDevice[2], EXIDEVICE_NONE);
|
||||
ini.Get("Core", "BBA_MAC", &m_bba_mac);
|
||||
|
@ -75,18 +75,18 @@ void DoState(PointerWrap &p)
|
||||
void ChangeDeviceCallback(u64 userdata, int cyclesLate)
|
||||
{
|
||||
u8 channel = (u8)(userdata >> 32);
|
||||
u8 device = (u8)(userdata >> 16);
|
||||
u8 slot = (u8)userdata;
|
||||
u8 type = (u8)(userdata >> 16);
|
||||
u8 num = (u8)userdata;
|
||||
|
||||
g_Channels[channel]->AddDevice((TEXIDevices)device, slot);
|
||||
g_Channels[channel]->AddDevice((TEXIDevices)type, num);
|
||||
}
|
||||
|
||||
void ChangeDevice(u8 channel, TEXIDevices device, u8 slot)
|
||||
void ChangeDevice(const u8 channel, const TEXIDevices device_type, const u8 device_num)
|
||||
{
|
||||
// Called from GUI, so we need to make it thread safe.
|
||||
// Let the hardware see no device for .5b cycles
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | ((u64)EXIDEVICE_NONE << 16) | slot);
|
||||
CoreTiming::ScheduleEvent_Threadsafe(500000000, changeDevice, ((u64)channel << 32) | ((u64)device << 16) | slot);
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | ((u64)EXIDEVICE_NONE << 16) | device_num);
|
||||
CoreTiming::ScheduleEvent_Threadsafe(500000000, changeDevice, ((u64)channel << 32) | ((u64)device_type << 16) | device_num);
|
||||
}
|
||||
|
||||
// Unused (?!)
|
||||
|
@ -33,7 +33,7 @@ void Update();
|
||||
void UpdateInterrupts();
|
||||
|
||||
void ChangeDeviceCallback(u64 userdata, int cyclesLate);
|
||||
void ChangeDevice(u8 channel, TEXIDevices device, u8 slot);
|
||||
void ChangeDevice(const u8 channel, const TEXIDevices device_type, const u8 device_num);
|
||||
|
||||
void Read32(u32& _uReturnValue, const u32 _iAddress);
|
||||
void Write32(const u32 _iValue, const u32 _iAddress);
|
||||
|
@ -42,7 +42,7 @@ CEXIChannel::CEXIChannel(u32 ChannelId) :
|
||||
m_Status.CHIP_SELECT = 1;
|
||||
|
||||
for (int i = 0; i < NUM_DEVICES; i++)
|
||||
m_pDevices[i] = EXIDevice_Create(EXIDEVICE_NONE);
|
||||
m_pDevices[i] = EXIDevice_Create(EXIDEVICE_NONE, m_ChannelId);
|
||||
}
|
||||
|
||||
CEXIChannel::~CEXIChannel()
|
||||
@ -59,19 +59,19 @@ void CEXIChannel::RemoveDevices()
|
||||
}
|
||||
}
|
||||
|
||||
void CEXIChannel::AddDevice(const TEXIDevices _device, const unsigned int _iSlot)
|
||||
void CEXIChannel::AddDevice(const TEXIDevices device_type, const int device_num)
|
||||
{
|
||||
_dbg_assert_(EXPANSIONINTERFACE, _iSlot < NUM_DEVICES);
|
||||
_dbg_assert_(EXPANSIONINTERFACE, device_num < NUM_DEVICES);
|
||||
|
||||
// delete the old device
|
||||
if (m_pDevices[_iSlot] != NULL)
|
||||
if (m_pDevices[device_num] != NULL)
|
||||
{
|
||||
delete m_pDevices[_iSlot];
|
||||
m_pDevices[_iSlot] = NULL;
|
||||
delete m_pDevices[device_num];
|
||||
m_pDevices[device_num] = NULL;
|
||||
}
|
||||
|
||||
// create the new one
|
||||
m_pDevices[_iSlot] = EXIDevice_Create(_device);
|
||||
m_pDevices[device_num] = EXIDevice_Create(device_type, m_ChannelId);
|
||||
|
||||
// This means "device presence changed", software has to check
|
||||
// m_Status.EXT to see if it is now present or not
|
||||
@ -107,9 +107,9 @@ bool CEXIChannel::IsCausingInterrupt()
|
||||
}
|
||||
}
|
||||
|
||||
IEXIDevice* CEXIChannel::GetDevice(u8 _CHIP_SELECT)
|
||||
IEXIDevice* CEXIChannel::GetDevice(const u8 chip_select)
|
||||
{
|
||||
switch(_CHIP_SELECT)
|
||||
switch (chip_select)
|
||||
{
|
||||
case 1: return m_pDevices[0];
|
||||
case 2: return m_pDevices[1];
|
||||
|
@ -112,12 +112,12 @@ private:
|
||||
|
||||
public:
|
||||
// get device
|
||||
IEXIDevice* GetDevice(u8 _CHIP_SELECT);
|
||||
IEXIDevice* GetDevice(const u8 _CHIP_SELECT);
|
||||
|
||||
CEXIChannel(u32 ChannelId);
|
||||
~CEXIChannel();
|
||||
|
||||
void AddDevice(const TEXIDevices _device, const unsigned int _iSlot);
|
||||
void AddDevice(const TEXIDevices device_type, const int device_num);
|
||||
|
||||
// Remove all devices
|
||||
void RemoveDevices();
|
||||
|
@ -102,20 +102,16 @@ public:
|
||||
|
||||
|
||||
// F A C T O R Y
|
||||
IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice)
|
||||
IEXIDevice* EXIDevice_Create(TEXIDevices device_type, const int channel_num)
|
||||
{
|
||||
switch(_EXIDevice)
|
||||
switch (device_type)
|
||||
{
|
||||
case EXIDEVICE_DUMMY:
|
||||
return new CEXIDummy("Dummy");
|
||||
break;
|
||||
|
||||
case EXIDEVICE_MEMORYCARD_A:
|
||||
return new CEXIMemoryCard("MemoryCardA", SConfig::GetInstance().m_strMemoryCardA, 0);
|
||||
break;
|
||||
|
||||
case EXIDEVICE_MEMORYCARD_B:
|
||||
return new CEXIMemoryCard("MemoryCardB", SConfig::GetInstance().m_strMemoryCardB, 1);
|
||||
case EXIDEVICE_MEMORYCARD:
|
||||
return new CEXIMemoryCard(channel_num);
|
||||
break;
|
||||
|
||||
case EXIDEVICE_MASKROM:
|
||||
@ -127,7 +123,7 @@ IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice)
|
||||
break;
|
||||
|
||||
case EXIDEVICE_MIC:
|
||||
return new CEXIMic(1);
|
||||
return new CEXIMic(channel_num);
|
||||
break;
|
||||
|
||||
case EXIDEVICE_ETH:
|
||||
|
@ -53,8 +53,7 @@ public:
|
||||
enum TEXIDevices
|
||||
{
|
||||
EXIDEVICE_DUMMY,
|
||||
EXIDEVICE_MEMORYCARD_A,
|
||||
EXIDEVICE_MEMORYCARD_B,
|
||||
EXIDEVICE_MEMORYCARD,
|
||||
EXIDEVICE_MASKROM,
|
||||
EXIDEVICE_AD16,
|
||||
EXIDEVICE_MIC,
|
||||
@ -64,6 +63,6 @@ enum TEXIDevices
|
||||
EXIDEVICE_NONE = (u8)-1
|
||||
};
|
||||
|
||||
extern IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice);
|
||||
extern IEXIDevice* EXIDevice_Create(const TEXIDevices device_type, const int channel_num);
|
||||
|
||||
#endif
|
||||
|
@ -45,13 +45,13 @@ void CEXIMemoryCard::FlushCallback(u64 userdata, int cyclesLate)
|
||||
ptr->Flush();
|
||||
}
|
||||
|
||||
CEXIMemoryCard::CEXIMemoryCard(const std::string& _rName, const std::string& _rFilename, int _card_index) :
|
||||
m_strFilename(_rFilename),
|
||||
card_index(_card_index),
|
||||
m_bDirty(false)
|
||||
CEXIMemoryCard::CEXIMemoryCard(const int index)
|
||||
: card_index(index)
|
||||
, m_bDirty(false)
|
||||
{
|
||||
cards[_card_index] = this;
|
||||
et_this_card = CoreTiming::RegisterEvent(_rName.c_str(), FlushCallback);
|
||||
m_strFilename = (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : SConfig::GetInstance().m_strMemoryCardB;
|
||||
cards[card_index] = this;
|
||||
et_this_card = CoreTiming::RegisterEvent((card_index == 0) ? "memcardA" : "memcardB", FlushCallback);
|
||||
reloadOnState = SConfig::GetInstance().b_reloadMCOnState;
|
||||
|
||||
interruptSwitch = 0;
|
||||
@ -427,9 +427,6 @@ void CEXIMemoryCard::DoState(PointerWrap &p)
|
||||
{
|
||||
if (reloadOnState)
|
||||
{
|
||||
int slot = 0;
|
||||
if (GetFileName() == SConfig::GetInstance().m_strMemoryCardA)
|
||||
slot = 1;
|
||||
ExpansionInterface::ChangeDevice(slot, slot ? EXIDEVICE_MEMORYCARD_B : EXIDEVICE_MEMORYCARD_A, 0);
|
||||
ExpansionInterface::ChangeDevice(card_index, EXIDEVICE_MEMORYCARD, 0);
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ struct FlushData
|
||||
class CEXIMemoryCard : public IEXIDevice
|
||||
{
|
||||
public:
|
||||
CEXIMemoryCard(const std::string& _rName, const std::string& _rFilename, int card_index);
|
||||
CEXIMemoryCard(const int index);
|
||||
virtual ~CEXIMemoryCard();
|
||||
void SetCS(int cs);
|
||||
void Update();
|
||||
@ -40,8 +40,6 @@ public:
|
||||
bool IsPresent();
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
inline const std::string &GetFileName() const { return m_strFilename; };
|
||||
|
||||
private:
|
||||
// This is scheduled whenever a page write is issued. The this pointer is passed
|
||||
// through the userdata parameter, so that it can then call Flush on the right card.
|
||||
|
@ -16,115 +16,165 @@
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Common.h"
|
||||
#include "FileUtil.h"
|
||||
#include "StringUtil.h"
|
||||
#include "../Core.h"
|
||||
|
||||
#if HAVE_PORTAUDIO
|
||||
|
||||
#include "../CoreTiming.h"
|
||||
#include "SystemTimers.h"
|
||||
|
||||
#include "EXI_Device.h"
|
||||
#include "EXI_DeviceMic.h"
|
||||
|
||||
// Unfortunately this must be enabled in Common.h for windows users. Scons should enable it otherwise
|
||||
#if !HAVE_PORTAUDIO
|
||||
|
||||
void SetMic(bool Value){}
|
||||
|
||||
CEXIMic::CEXIMic(int _Index){}
|
||||
CEXIMic::~CEXIMic(){}
|
||||
bool CEXIMic::IsPresent() {return false;}
|
||||
void CEXIMic::SetCS(int cs){}
|
||||
void CEXIMic::Update(){}
|
||||
void CEXIMic::TransferByte(u8 &byte){}
|
||||
bool CEXIMic::IsInterruptSet(){return false;}
|
||||
|
||||
#else
|
||||
|
||||
// We use PortAudio for cross-platform audio input.
|
||||
// It needs the headers and a lib file for the dll
|
||||
#include <portaudio.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma comment(lib, "C:/Users/Shawn/Desktop/portaudio/portaudio-v19/portaudio_x64.lib")
|
||||
#endif
|
||||
#include "GCPad.h"
|
||||
|
||||
static bool MicButton = false;
|
||||
static bool IsOpen;
|
||||
|
||||
union InputData
|
||||
void CEXIMic::StreamLog(const char *msg)
|
||||
{
|
||||
s16 word;
|
||||
u8 byte[2];
|
||||
};
|
||||
|
||||
InputData inputData[64]; // 64 words = Max 128 bytes returned????
|
||||
PaStream *stream;
|
||||
PaError err;
|
||||
unsigned short SFreq;
|
||||
unsigned short SNum;
|
||||
bool m_bInterruptSet;
|
||||
bool Sampling;
|
||||
|
||||
|
||||
void SetMic(bool Value)
|
||||
{
|
||||
MicButton = Value;
|
||||
if(Sampling)
|
||||
Pa_StartStream( stream );
|
||||
else
|
||||
Pa_StopStream( stream );
|
||||
DEBUG_LOG(EXPANSIONINTERFACE, "%s: %s",
|
||||
msg, Pa_GetErrorText(pa_error));
|
||||
}
|
||||
|
||||
int patestCallback( const void *inputBuffer, void *outputBuffer,
|
||||
unsigned long frameCount,
|
||||
const PaStreamCallbackTimeInfo* timeInfo,
|
||||
PaStreamCallbackFlags statusFlags,
|
||||
void *userData )
|
||||
void CEXIMic::StreamInit()
|
||||
{
|
||||
s16 *data = (s16*)inputBuffer;
|
||||
//s16 *out = (s16*)outputBuffer;
|
||||
// Setup the wonderful c-interfaced lib...
|
||||
pa_stream = NULL;
|
||||
|
||||
if (!m_bInterruptSet && Sampling)
|
||||
if ((pa_error = Pa_Initialize()) != paNoError)
|
||||
StreamLog("Pa_Initialize");
|
||||
|
||||
stream_buffer = NULL;
|
||||
samples_avail = stream_wpos = stream_rpos = 0;
|
||||
}
|
||||
|
||||
void CEXIMic::StreamTerminate()
|
||||
{
|
||||
StreamStop();
|
||||
|
||||
if ((pa_error = Pa_Terminate()) != paNoError)
|
||||
StreamLog("Pa_Terminate");
|
||||
}
|
||||
|
||||
static int Pa_Callback(const void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
const PaStreamCallbackTimeInfo *timeInfo,
|
||||
PaStreamCallbackFlags statusFlags,
|
||||
void *userData)
|
||||
{
|
||||
(void)outputBuffer;
|
||||
(void)timeInfo;
|
||||
(void)statusFlags;
|
||||
|
||||
CEXIMic *mic = (CEXIMic *)userData;
|
||||
|
||||
std::lock_guard<std::mutex> lk(mic->ring_lock);
|
||||
|
||||
if (mic->stream_wpos + mic->buff_size_samples > mic->stream_size)
|
||||
mic->stream_wpos = 0;
|
||||
|
||||
s16 *buff_in = (s16 *)inputBuffer;
|
||||
s16 *buff_out = &mic->stream_buffer[mic->stream_wpos];
|
||||
|
||||
if (buff_in == NULL)
|
||||
{
|
||||
for(unsigned int i = 0; i < SNum; ++i)
|
||||
for (int i = 0; i < mic->buff_size_samples; i++)
|
||||
{
|
||||
inputData[i].word = data[i];
|
||||
//out[i] = inputData[i].word;
|
||||
buff_out[i] = 0;
|
||||
}
|
||||
m_bInterruptSet = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < mic->buff_size_samples; i++)
|
||||
{
|
||||
buff_out[i] = buff_in[i];
|
||||
}
|
||||
}
|
||||
|
||||
mic->samples_avail += mic->buff_size_samples;
|
||||
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;
|
||||
}
|
||||
|
||||
void CEXIMic::StreamStart()
|
||||
{
|
||||
// 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");
|
||||
}
|
||||
|
||||
void CEXIMic::StreamStop()
|
||||
{
|
||||
if (pa_stream != NULL && Pa_IsStreamActive(pa_stream) >= paNoError)
|
||||
Pa_AbortStream(pa_stream);
|
||||
|
||||
delete [] stream_buffer;
|
||||
stream_buffer = NULL;
|
||||
}
|
||||
|
||||
void CEXIMic::StreamReadOne()
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(ring_lock);
|
||||
|
||||
if (samples_avail >= buff_size_samples)
|
||||
{
|
||||
s16 *last_buffer = &stream_buffer[stream_rpos];
|
||||
memcpy(ring_buffer, last_buffer, buff_size);
|
||||
|
||||
samples_avail -= buff_size_samples;
|
||||
|
||||
stream_rpos += buff_size_samples;
|
||||
stream_rpos %= stream_size;
|
||||
}
|
||||
}
|
||||
|
||||
// EXI Mic Device
|
||||
// This works by opening and starting a portaudio 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.
|
||||
|
||||
CEXIMic::CEXIMic(int _Index)
|
||||
u8 const CEXIMic::exi_id[] = { 0, 0x0a, 0, 0, 0 };
|
||||
|
||||
CEXIMic::CEXIMic(int index)
|
||||
: slot(index)
|
||||
{
|
||||
Index = _Index;
|
||||
|
||||
memset(&inputData, 0 , sizeof(inputData));
|
||||
memset(&Status.U16, 0 , sizeof(u16));
|
||||
m_position = 0;
|
||||
command = 0;
|
||||
m_uPosition = 0;
|
||||
m_bInterruptSet = false;
|
||||
MicButton = false;
|
||||
IsOpen = false;
|
||||
err = Pa_Initialize();
|
||||
if (err != paNoError)
|
||||
ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: PortAudio Initialize error %s", Pa_GetErrorText(err));
|
||||
status.U16 = 0;
|
||||
|
||||
sample_rate = rate_base;
|
||||
buff_size = ring_base;
|
||||
buff_size_samples = buff_size / sample_size;
|
||||
|
||||
ring_pos = 0;
|
||||
memset(ring_buffer, 0, sizeof(ring_buffer));
|
||||
|
||||
next_int_ticks = 0;
|
||||
|
||||
StreamInit();
|
||||
}
|
||||
|
||||
CEXIMic::~CEXIMic()
|
||||
{
|
||||
err = Pa_CloseStream( stream );
|
||||
if (err != paNoError)
|
||||
ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: PortAudio Close error %s", Pa_GetErrorText(err));
|
||||
err = Pa_Terminate();
|
||||
if (err != paNoError)
|
||||
ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: PortAudio Terminate error %s", Pa_GetErrorText(err));
|
||||
StreamTerminate();
|
||||
}
|
||||
|
||||
bool CEXIMic::IsPresent()
|
||||
bool CEXIMic::IsPresent()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -132,38 +182,26 @@ bool CEXIMic::IsPresent()
|
||||
void CEXIMic::SetCS(int cs)
|
||||
{
|
||||
if (cs) // not-selected to selected
|
||||
m_uPosition = 0;
|
||||
else
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case cmdID:
|
||||
case cmdGetStatus:
|
||||
case cmdSetStatus:
|
||||
case cmdGetBuffer:
|
||||
break;
|
||||
case cmdWakeUp:
|
||||
// This is probably not a command, but anyway...
|
||||
// The command 0xff seems to be used to get in sync with the microphone or to wake it up.
|
||||
// Normally, it is issued before any other command, or to recover from errors.
|
||||
WARN_LOG(EXPANSIONINTERFACE, "EXI MIC: WakeUp cmd");
|
||||
break;
|
||||
default:
|
||||
WARN_LOG(EXPANSIONINTERFACE, "EXI MIC: unknown CS command %02x\n", command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_position = 0;
|
||||
// Doesn't appear to do anything we care about
|
||||
//else if (command == cmdReset)
|
||||
}
|
||||
|
||||
void CEXIMic::Update()
|
||||
void CEXIMic::UpdateNextInterruptTicks()
|
||||
{
|
||||
next_int_ticks = CoreTiming::GetTicks() +
|
||||
(SystemTimers::GetTicksPerSecond() / sample_rate) * buff_size_samples;
|
||||
}
|
||||
|
||||
bool CEXIMic::IsInterruptSet()
|
||||
{
|
||||
if(m_bInterruptSet)
|
||||
if (next_int_ticks && CoreTiming::GetTicks() >= next_int_ticks)
|
||||
{
|
||||
m_bInterruptSet = false;
|
||||
if (status.is_active)
|
||||
UpdateNextInterruptTicks();
|
||||
else
|
||||
next_int_ticks = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -174,124 +212,70 @@ bool CEXIMic::IsInterruptSet()
|
||||
|
||||
void CEXIMic::TransferByte(u8 &byte)
|
||||
{
|
||||
if (m_uPosition == 0)
|
||||
if (m_position == 0)
|
||||
{
|
||||
command = byte; // first byte is command
|
||||
byte = 0xFF; // would be tristate, but we don't care.
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case cmdID:
|
||||
if (m_uPosition == 1)
|
||||
;//byte = 0x80; // dummy cycle - taken from memcard, it doesn't seem to need it here
|
||||
else
|
||||
byte = (u8)(EXI_DEVTYPE_MIC >> (24-(((m_uPosition-2) & 3) * 8)));
|
||||
break;
|
||||
case cmdGetStatus:
|
||||
{
|
||||
if (m_uPosition != 1 && m_uPosition != 2)
|
||||
WARN_LOG(EXPANSIONINTERFACE, "EXI MIC: WARNING GetStatus @ pos: %d should never happen", m_uPosition);
|
||||
if((!Status.button && MicButton)||(Status.button && !MicButton))
|
||||
WARN_LOG(EXPANSIONINTERFACE, "EXI MIC: Mic button %s", MicButton ? "pressed" : "released");
|
||||
|
||||
Status.button = MicButton ? 1 : 0;
|
||||
byte = Status.U8[ (m_uPosition - 1) ? 0 : 1];
|
||||
INFO_LOG(EXPANSIONINTERFACE, "EXI MIC: Status is 0x%04x", Status.U16);
|
||||
}
|
||||
break;
|
||||
case cmdSetStatus:
|
||||
{
|
||||
// 0x80 0xXX 0xYY
|
||||
// cmd pos1 pos2
|
||||
|
||||
// Here we assign the byte to the proper place in Status and update portaudio settings
|
||||
Status.U8[ (m_uPosition - 1) ? 0 : 1] = byte;
|
||||
|
||||
if(m_uPosition == 2)
|
||||
{
|
||||
Sampling = (Status.sampling == 1) ? true : false;
|
||||
|
||||
switch (Status.sRate)
|
||||
{
|
||||
case 0:
|
||||
SFreq = 11025;
|
||||
break;
|
||||
case 1:
|
||||
SFreq = 22050;
|
||||
break;
|
||||
case 2:
|
||||
SFreq = 44100;
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: Trying to set unknown sampling rate");
|
||||
SFreq = 44100;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (Status.pLength)
|
||||
{
|
||||
case 0:
|
||||
SNum = 32;
|
||||
break;
|
||||
case 1:
|
||||
SNum = 64;
|
||||
break;
|
||||
case 2:
|
||||
SNum = 128;
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: Trying to set unknown period length");
|
||||
SNum = 128;
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_LOG(EXPANSIONINTERFACE, "//////////////////////////////////////////////////////////////////////////");
|
||||
DEBUG_LOG(EXPANSIONINTERFACE, "EXI MIC: Status is now 0x%04x", Status.U16);
|
||||
DEBUG_LOG(EXPANSIONINTERFACE, "\tbutton %i\tsRate %i\tpLength %i\tsampling %i\n",
|
||||
Status.button, SFreq, SNum, Status.sampling);
|
||||
|
||||
if(!IsOpen)
|
||||
{
|
||||
// Open Our PortAudio Stream
|
||||
// (shuffle2) This (and the callback) could still be wrong
|
||||
err = Pa_OpenDefaultStream(
|
||||
&stream, // Our PaStream
|
||||
1, // Input Channels
|
||||
0, // Output Channels
|
||||
paInt16, // Output format - GC wants PCM samples in signed 16-bit format
|
||||
SFreq, // Sample Rate
|
||||
SNum, // Period Length (frames per buffer)
|
||||
patestCallback,// Our callback!
|
||||
NULL); // Pointer passed to our callback
|
||||
if (err != paNoError)
|
||||
{
|
||||
ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: PortAudio error %s", Pa_GetErrorText(err));
|
||||
}
|
||||
else
|
||||
IsOpen = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case cmdGetBuffer:
|
||||
{
|
||||
int pos = m_uPosition - 1;
|
||||
// (sonicadvance1)I think if we set the Interrupt to false, it reads another 64
|
||||
// Will Look in to it.
|
||||
// (shuffle2)Seems like games just continuously get the buffer as long as
|
||||
// they're sampling and the mic is generating interrupts
|
||||
byte = inputData[pos].byte[ (pos & 1) ? 0 : 1 ];
|
||||
INFO_LOG(EXPANSIONINTERFACE, "EXI MIC: GetBuffer%s%d/%d byte: 0x%02x",
|
||||
(pos > 9) ? " " : " ", pos, SNum, byte);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: unknown command byte %02x\n", command);
|
||||
break;
|
||||
}
|
||||
m_position++;
|
||||
return;
|
||||
}
|
||||
m_uPosition++;
|
||||
|
||||
int pos = m_position - 1;
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case cmdID:
|
||||
byte = exi_id[pos];
|
||||
break;
|
||||
|
||||
case cmdGetStatus:
|
||||
if (pos == 0)
|
||||
status.button = Pad::GetMicButton(slot);
|
||||
|
||||
byte = status.U8[pos ^ 1];
|
||||
|
||||
if (pos == 1)
|
||||
status.buff_ovrflw = 0;
|
||||
break;
|
||||
|
||||
case cmdSetStatus:
|
||||
{
|
||||
bool wasactive = status.is_active;
|
||||
status.U8[pos ^ 1] = byte;
|
||||
|
||||
// safe to do since these can only be entered if both bytes of status have been written
|
||||
if (!wasactive && status.is_active)
|
||||
{
|
||||
sample_rate = rate_base << status.sample_rate;
|
||||
buff_size = ring_base << status.buff_size;
|
||||
buff_size_samples = buff_size / sample_size;
|
||||
|
||||
UpdateNextInterruptTicks();
|
||||
|
||||
StreamStart();
|
||||
}
|
||||
else if (wasactive && !status.is_active)
|
||||
{
|
||||
StreamStop();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case cmdGetBuffer:
|
||||
{
|
||||
if (ring_pos == 0)
|
||||
StreamReadOne();
|
||||
|
||||
byte = ring_buffer[ring_pos ^ 1];
|
||||
ring_pos = (ring_pos + 1) % buff_size;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: unknown command byte %02x", command);
|
||||
break;
|
||||
}
|
||||
|
||||
m_position++;
|
||||
}
|
||||
#endif
|
||||
|
@ -18,58 +18,106 @@
|
||||
#ifndef _EXI_DEVICEMIC_H
|
||||
#define _EXI_DEVICEMIC_H
|
||||
|
||||
#if HAVE_PORTAUDIO
|
||||
|
||||
#include "StdMutex.h"
|
||||
|
||||
class CEXIMic : public IEXIDevice
|
||||
{
|
||||
public:
|
||||
CEXIMic(int _Index);
|
||||
CEXIMic(const int index);
|
||||
virtual ~CEXIMic();
|
||||
void SetCS(int cs);
|
||||
void Update();
|
||||
bool IsInterruptSet();
|
||||
bool IsPresent();
|
||||
|
||||
private:
|
||||
static u8 const exi_id[];
|
||||
static int const sample_size = sizeof(s16);
|
||||
static int const rate_base = 11025;
|
||||
static int const ring_base = 32;
|
||||
|
||||
enum
|
||||
{
|
||||
EXI_DEVTYPE_MIC = 0x0A000000
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
cmdID = 0x00,
|
||||
cmdGetStatus = 0x40,
|
||||
cmdSetStatus = 0x80,
|
||||
cmdGetBuffer = 0x20,
|
||||
cmdWakeUp = 0xFF,
|
||||
cmdReset = 0xFF,
|
||||
};
|
||||
|
||||
// STATE_TO_SAVE
|
||||
int interruptSwitch;
|
||||
int slot;
|
||||
|
||||
u32 m_position;
|
||||
int command;
|
||||
union uStatus
|
||||
union UStatus
|
||||
{
|
||||
u16 U16;
|
||||
u8 U8[2];
|
||||
struct
|
||||
{
|
||||
u16 :8; // Unknown
|
||||
u16 button :1; // 1: Button Pressed
|
||||
u16 unk1 :1; // 1 ? Overflow?
|
||||
u16 unk2 :1; // Unknown related to 0 and 15 values It seems
|
||||
u16 sRate :2; // Sample Rate, 00-11025, 01-22050, 10-44100, 11-??
|
||||
u16 pLength :2; // Period Length, 00-32, 01-64, 10-128, 11-???
|
||||
u16 sampling :1; // If We Are Sampling or Not
|
||||
u16 out :4; // MICSet/GetOut...???
|
||||
u16 id :1; // Used for MICGetDeviceID (always 0)
|
||||
u16 button_unk :3; // Button bits which appear unused
|
||||
u16 button :1; // The actual button on the mic
|
||||
u16 buff_ovrflw :1; // Ring buffer wrote over bytes which weren't read by console
|
||||
u16 gain :1; // Gain: 0dB or 15dB
|
||||
u16 sample_rate :2; // Sample rate, 00-11025, 01-22050, 10-44100, 11-??
|
||||
u16 buff_size :2; // Ring buffer size in bytes, 00-32, 01-64, 10-128, 11-???
|
||||
u16 is_active :1; // If we are sampling or not
|
||||
};
|
||||
};
|
||||
int Index;
|
||||
u32 m_uPosition;
|
||||
uStatus Status;
|
||||
|
||||
// 64 is the max size, can be 16 or 32 as well
|
||||
int ring_pos;
|
||||
u8 ring_buffer[64 * sample_size];
|
||||
|
||||
// 0 to disable interrupts, else it will be checked against current cpu ticks
|
||||
// to determine if interrupt should be raised
|
||||
u64 next_int_ticks;
|
||||
void UpdateNextInterruptTicks();
|
||||
|
||||
// Streaming input interface
|
||||
int pa_error; // PaError
|
||||
void *pa_stream; // PaStream
|
||||
|
||||
void StreamLog(const char *msg);
|
||||
void StreamInit();
|
||||
void StreamTerminate();
|
||||
void StreamStart();
|
||||
void StreamStop();
|
||||
void StreamReadOne();
|
||||
|
||||
public:
|
||||
UStatus status;
|
||||
|
||||
std::mutex ring_lock;
|
||||
|
||||
// status bits converted to nice numbers
|
||||
int sample_rate;
|
||||
int buff_size;
|
||||
int buff_size_samples;
|
||||
|
||||
// Arbitrarily small ringbuffer used by audio input backend in order to
|
||||
// keep delay tolerable
|
||||
s16 *stream_buffer;
|
||||
int stream_size;
|
||||
int stream_wpos;
|
||||
int stream_rpos;
|
||||
int samples_avail;
|
||||
|
||||
protected:
|
||||
virtual void TransferByte(u8 &byte);
|
||||
};
|
||||
|
||||
void SetMic(bool Value);
|
||||
#else // HAVE_PORTAUDIO
|
||||
|
||||
class CEXIMic : public IEXIDevice
|
||||
{
|
||||
public:
|
||||
CEXIMic(const int) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _EXI_DEVICEMIC_H
|
||||
|
@ -107,4 +107,15 @@ void Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength)
|
||||
}
|
||||
}
|
||||
|
||||
bool GetMicButton(u8 pad)
|
||||
{
|
||||
|
||||
std::unique_lock<std::recursive_mutex> lk(g_plugin.controls_lock, std::try_to_lock);
|
||||
|
||||
if (!lk.owns_lock())
|
||||
return false;
|
||||
|
||||
return ((GCPad*)g_plugin.controllers[pad])->GetMicButton();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ InputPlugin *GetPlugin();
|
||||
void GetStatus(u8 _numPAD, SPADStatus* _pPADStatus);
|
||||
void Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength);
|
||||
|
||||
bool GetMicButton(u8 pad);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -25,7 +25,8 @@ const u16 button_bitmasks[] =
|
||||
PAD_BUTTON_X,
|
||||
PAD_BUTTON_Y,
|
||||
PAD_TRIGGER_Z,
|
||||
PAD_BUTTON_START
|
||||
PAD_BUTTON_START,
|
||||
0 // MIC HAX
|
||||
};
|
||||
|
||||
const u16 trigger_bitmasks[] =
|
||||
@ -47,6 +48,7 @@ const char* const named_buttons[] =
|
||||
"Y",
|
||||
"Z",
|
||||
_trans("Start"),
|
||||
"Mic"
|
||||
};
|
||||
|
||||
const char* const named_triggers[] =
|
||||
@ -63,10 +65,11 @@ const char* const named_triggers[] =
|
||||
|
||||
GCPad::GCPad(const unsigned int index) : m_index(index)
|
||||
{
|
||||
int const mic_hax = index > 1;
|
||||
|
||||
// buttons
|
||||
groups.push_back(m_buttons = new Buttons(_trans("Buttons")));
|
||||
for (unsigned int i=0; i < sizeof(named_buttons)/sizeof(*named_buttons); ++i)
|
||||
for (unsigned int i=0; i < sizeof(named_buttons)/sizeof(*named_buttons) - mic_hax; ++i)
|
||||
m_buttons->controls.push_back(new ControlGroup::Input(named_buttons[i]));
|
||||
|
||||
// sticks
|
||||
@ -203,3 +206,8 @@ void GCPad::LoadDefaults(const ControllerInterface& ciface)
|
||||
set_control(m_triggers, 0, "Q"); // L
|
||||
set_control(m_triggers, 1, "W"); // R
|
||||
}
|
||||
|
||||
bool GCPad::GetMicButton() const
|
||||
{
|
||||
return m_buttons->controls.back()->control_ref->State();
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ public:
|
||||
GCPad(const unsigned int index);
|
||||
void GetInput(SPADStatus* const pad);
|
||||
void SetOutput(const bool on);
|
||||
|
||||
bool GetMicButton() const;
|
||||
|
||||
std::string GetName() const;
|
||||
|
||||
|
@ -239,8 +239,6 @@ bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low)
|
||||
}
|
||||
}
|
||||
|
||||
SetMic(PadStatus.MicButton); // This is dumb and should not be here
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -483,10 +483,8 @@ void PlayController(SPADStatus *PadStatus, int controllerID)
|
||||
|
||||
// dtm files don't save the mic button or error bit. not sure if they're actually
|
||||
// used, but better safe than sorry
|
||||
bool m = PadStatus->MicButton;
|
||||
signed char e = PadStatus->err;
|
||||
memset(PadStatus, 0, sizeof(SPADStatus));
|
||||
PadStatus->MicButton = m;
|
||||
PadStatus->err = e;
|
||||
|
||||
memcpy(&g_padState, &(tmpInput[inputOffset]), 8);
|
||||
|
@ -206,14 +206,11 @@ void Jit64AsmRoutineManager::Generate()
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
|
||||
|
||||
testExceptions = GetCodePtr();
|
||||
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
|
||||
FixupBranch skipExceptions = J_CC(CC_Z);
|
||||
MOV(32, R(EAX), M(&PC));
|
||||
MOV(32, M(&NPC), R(EAX));
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
||||
MOV(32, R(EAX), M(&NPC));
|
||||
MOV(32, M(&PC), R(EAX));
|
||||
SetJumpTarget(skipExceptions);
|
||||
MOV(32, R(EAX), M(&PC));
|
||||
MOV(32, M(&NPC), R(EAX));
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
||||
MOV(32, R(EAX), M(&NPC));
|
||||
MOV(32, M(&PC), R(EAX));
|
||||
|
||||
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
|
||||
J_CC(CC_Z, outerLoop, true);
|
||||
|
@ -210,14 +210,11 @@ void JitILAsmRoutineManager::Generate()
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
|
||||
|
||||
testExceptions = GetCodePtr();
|
||||
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
|
||||
FixupBranch skipExceptions = J_CC(CC_Z);
|
||||
MOV(32, R(EAX), M(&PC));
|
||||
MOV(32, M(&NPC), R(EAX));
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
||||
MOV(32, R(EAX), M(&NPC));
|
||||
MOV(32, M(&PC), R(EAX));
|
||||
SetJumpTarget(skipExceptions);
|
||||
MOV(32, R(EAX), M(&PC));
|
||||
MOV(32, M(&NPC), R(EAX));
|
||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
||||
MOV(32, R(EAX), M(&NPC));
|
||||
MOV(32, M(&PC), R(EAX));
|
||||
|
||||
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
|
||||
J_CC(CC_Z, outerLoop, true);
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "CPUCoreBase.h"
|
||||
|
||||
#include "../Host.h"
|
||||
#include "HW/EXI.h"
|
||||
|
||||
CPUCoreBase *cpu_core_base;
|
||||
|
||||
@ -268,10 +269,13 @@ void Stop()
|
||||
|
||||
void CheckExceptions()
|
||||
{
|
||||
// Make sure we are checking against the latest EXI status. This is required
|
||||
// for devices which interrupt frequently, such as the gc mic
|
||||
ExpansionInterface::UpdateInterrupts();
|
||||
|
||||
// Read volatile data once
|
||||
u32 exceptions = ppcState.Exceptions;
|
||||
|
||||
// This check is unnecessary in JIT mode. However, it probably doesn't really hurt.
|
||||
if (!exceptions)
|
||||
return;
|
||||
|
||||
|
@ -236,6 +236,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
||||
<ClCompile Include="Src\FrameAui.cpp" />
|
||||
<ClCompile Include="Src\FrameTools.cpp" />
|
||||
<ClCompile Include="Src\GameListCtrl.cpp" />
|
||||
<ClCompile Include="Src\GCMicDlg.cpp" />
|
||||
<ClCompile Include="Src\GeckoCodeDiag.cpp" />
|
||||
<ClCompile Include="Src\HotkeyDlg.cpp" />
|
||||
<ClCompile Include="Src\InputConfigDiag.cpp" />
|
||||
@ -297,6 +298,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
||||
<ClInclude Include="Src\FifoPlayerDlg.h" />
|
||||
<ClInclude Include="Src\Frame.h" />
|
||||
<ClInclude Include="Src\GameListCtrl.h" />
|
||||
<ClInclude Include="Src\GCMicDlg.h" />
|
||||
<ClInclude Include="Src\GeckoCodeDiag.h" />
|
||||
<ClInclude Include="Src\Globals.h" />
|
||||
<ClInclude Include="Src\HotkeyDlg.h" />
|
||||
|
@ -132,6 +132,9 @@
|
||||
<ClCompile Include="Src\TASInputDlg.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\GCMicDlg.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Src\Main.h" />
|
||||
@ -258,6 +261,9 @@
|
||||
<ClInclude Include="Src\TASInputDlg.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\GCMicDlg.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Src\SConscript" />
|
||||
|
@ -406,8 +406,7 @@ void CConfigMain::InitializeGUIValues()
|
||||
case EXIDEVICE_NONE:
|
||||
GCEXIDevice[i]->SetStringSelection(SlotDevices[0]);
|
||||
break;
|
||||
case EXIDEVICE_MEMORYCARD_A:
|
||||
case EXIDEVICE_MEMORYCARD_B:
|
||||
case EXIDEVICE_MEMORYCARD:
|
||||
isMemcard = GCEXIDevice[i]->SetStringSelection(SlotDevices[2]);
|
||||
break;
|
||||
case EXIDEVICE_MIC:
|
||||
@ -1030,7 +1029,7 @@ void CConfigMain::ChooseMemcardPath(std::string& strMemcard, bool isSlotA)
|
||||
// Change memcard to the new file
|
||||
ExpansionInterface::ChangeDevice(
|
||||
isSlotA ? 0 : 1, // SlotA: channel 0, SlotB channel 1
|
||||
isSlotA ? EXIDEVICE_MEMORYCARD_A : EXIDEVICE_MEMORYCARD_B,
|
||||
EXIDEVICE_MEMORYCARD,
|
||||
0); // SP1 is device 2, slots are device 0
|
||||
}
|
||||
}
|
||||
@ -1068,7 +1067,7 @@ void CConfigMain::ChooseEXIDevice(std::string deviceName, int deviceNum)
|
||||
TEXIDevices tempType;
|
||||
|
||||
if (!deviceName.compare(CSTR_TRANS(EXIDEV_MEMCARD_STR)))
|
||||
tempType = deviceNum ? EXIDEVICE_MEMORYCARD_B : EXIDEVICE_MEMORYCARD_A;
|
||||
tempType = EXIDEVICE_MEMORYCARD;
|
||||
else if (!deviceName.compare(CSTR_TRANS(EXIDEV_MIC_STR)))
|
||||
tempType = EXIDEVICE_MIC;
|
||||
else if (!deviceName.compare(EXIDEV_BBA_STR))
|
||||
@ -1083,7 +1082,7 @@ void CConfigMain::ChooseEXIDevice(std::string deviceName, int deviceNum)
|
||||
tempType = EXIDEVICE_DUMMY;
|
||||
|
||||
// Gray out the memcard path button if we're not on a memcard
|
||||
if (tempType == EXIDEVICE_MEMORYCARD_A || tempType == EXIDEVICE_MEMORYCARD_B)
|
||||
if (tempType == EXIDEVICE_MEMORYCARD)
|
||||
GCMemcardPath[deviceNum]->Enable();
|
||||
else if (deviceNum == 0 || deviceNum == 1)
|
||||
GCMemcardPath[deviceNum]->Disable();
|
||||
|
290
Source/Core/DolphinWX/Src/GCMicDlg.cpp
Normal file
290
Source/Core/DolphinWX/Src/GCMicDlg.cpp
Normal file
@ -0,0 +1,290 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <wx/notebook.h>
|
||||
|
||||
#include "GCMicDlg.h"
|
||||
#include "ConfigManager.h"
|
||||
|
||||
BEGIN_EVENT_TABLE(GCMicDialog,wxDialog)
|
||||
EVT_COMMAND_RANGE(0, NUM_HOTKEYS - 1,
|
||||
wxEVT_COMMAND_BUTTON_CLICKED, GCMicDialog::OnButtonClick)
|
||||
EVT_TIMER(wxID_ANY, GCMicDialog::OnButtonTimer)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
GCMicDialog::GCMicDialog(wxWindow *parent, wxWindowID id, const wxString &title,
|
||||
const wxPoint &position, const wxSize& size, long style)
|
||||
: wxDialog(parent, id, title, position, size, style)
|
||||
{
|
||||
CreateHotkeyGUIControls();
|
||||
|
||||
#if wxUSE_TIMER
|
||||
m_ButtonMappingTimer = new wxTimer(this, wxID_ANY);
|
||||
g_Pressed = 0;
|
||||
g_Modkey = 0;
|
||||
ClickedButton = NULL;
|
||||
GetButtonWaitingID = 0;
|
||||
GetButtonWaitingTimer = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
GCMicDialog::~GCMicDialog()
|
||||
{
|
||||
delete m_ButtonMappingTimer;
|
||||
}
|
||||
|
||||
// Save keyboard key mapping
|
||||
void GCMicDialog::SaveButtonMapping(int Id, int Key, int Modkey)
|
||||
{
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.iHotkey[Id] = Key;
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.iHotkeyModifier[Id] = Modkey;
|
||||
}
|
||||
|
||||
void GCMicDialog::EndGetButtons(void)
|
||||
{
|
||||
wxTheApp->Disconnect(wxID_ANY, wxEVT_KEY_DOWN, // Keyboard
|
||||
wxKeyEventHandler(GCMicDialog::OnKeyDown),
|
||||
(wxObject*)0, this);
|
||||
m_ButtonMappingTimer->Stop();
|
||||
GetButtonWaitingTimer = 0;
|
||||
GetButtonWaitingID = 0;
|
||||
ClickedButton = NULL;
|
||||
SetEscapeId(wxID_ANY);
|
||||
}
|
||||
|
||||
void GCMicDialog::OnKeyDown(wxKeyEvent& event)
|
||||
{
|
||||
if(ClickedButton != NULL)
|
||||
{
|
||||
// Save the key
|
||||
g_Pressed = event.GetKeyCode();
|
||||
g_Modkey = event.GetModifiers();
|
||||
|
||||
// Don't allow modifier keys
|
||||
if (g_Pressed == WXK_CONTROL || g_Pressed == WXK_ALT ||
|
||||
g_Pressed == WXK_SHIFT || g_Pressed == WXK_COMMAND)
|
||||
return;
|
||||
|
||||
// Use the space key to set a blank key
|
||||
if (g_Pressed == WXK_SPACE)
|
||||
{
|
||||
SaveButtonMapping(ClickedButton->GetId(), -1, 0);
|
||||
SetButtonText(ClickedButton->GetId(), wxString());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetButtonText(ClickedButton->GetId(),
|
||||
InputCommon::WXKeyToString(g_Pressed),
|
||||
InputCommon::WXKeymodToString(g_Modkey));
|
||||
SaveButtonMapping(ClickedButton->GetId(), g_Pressed, g_Modkey);
|
||||
}
|
||||
EndGetButtons();
|
||||
}
|
||||
}
|
||||
|
||||
// Update the textbox for the buttons
|
||||
void GCMicDialog::SetButtonText(int id, const wxString &keystr, const wxString &modkeystr)
|
||||
{
|
||||
m_Button_Hotkeys[id]->SetLabel(modkeystr + keystr);
|
||||
}
|
||||
|
||||
void GCMicDialog::DoGetButtons(int _GetId)
|
||||
{
|
||||
// Values used in this function
|
||||
const int Seconds = 4; // Seconds to wait for
|
||||
const int TimesPerSecond = 40; // How often to run the check
|
||||
|
||||
// If the Id has changed or the timer is not running we should start one
|
||||
if( GetButtonWaitingID != _GetId || !m_ButtonMappingTimer->IsRunning() )
|
||||
{
|
||||
if(m_ButtonMappingTimer->IsRunning())
|
||||
m_ButtonMappingTimer->Stop();
|
||||
|
||||
// Save the button Id
|
||||
GetButtonWaitingID = _GetId;
|
||||
GetButtonWaitingTimer = 0;
|
||||
|
||||
// Start the timer
|
||||
#if wxUSE_TIMER
|
||||
m_ButtonMappingTimer->Start(1000 / TimesPerSecond);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Process results
|
||||
// Count each time
|
||||
GetButtonWaitingTimer++;
|
||||
|
||||
// This is run every second
|
||||
if (GetButtonWaitingTimer % TimesPerSecond == 0)
|
||||
{
|
||||
// Current time
|
||||
int TmpTime = Seconds - (GetButtonWaitingTimer / TimesPerSecond);
|
||||
// Update text
|
||||
SetButtonText(_GetId, wxString::Format(wxT("[ %d ]"), TmpTime));
|
||||
}
|
||||
|
||||
// Time's up
|
||||
if (GetButtonWaitingTimer / TimesPerSecond >= Seconds)
|
||||
{
|
||||
// Revert back to old label
|
||||
SetButtonText(_GetId, OldLabel);
|
||||
EndGetButtons();
|
||||
}
|
||||
}
|
||||
|
||||
// Input button clicked
|
||||
void GCMicDialog::OnButtonClick(wxCommandEvent& event)
|
||||
{
|
||||
event.Skip();
|
||||
|
||||
if (m_ButtonMappingTimer->IsRunning()) return;
|
||||
|
||||
wxTheApp->Connect(wxID_ANY, wxEVT_KEY_DOWN, // Keyboard
|
||||
wxKeyEventHandler(GCMicDialog::OnKeyDown),
|
||||
(wxObject*)0, this);
|
||||
|
||||
// Get the button
|
||||
ClickedButton = (wxButton *)event.GetEventObject();
|
||||
SetEscapeId(wxID_CANCEL);
|
||||
// Save old label so we can revert back
|
||||
OldLabel = ClickedButton->GetLabel();
|
||||
ClickedButton->SetWindowStyle(wxWANTS_CHARS);
|
||||
ClickedButton->SetLabel(_("<Press Key>"));
|
||||
DoGetButtons(ClickedButton->GetId());
|
||||
}
|
||||
|
||||
#define HOTKEY_NUM_COLUMNS 2
|
||||
|
||||
void GCMicDialog::CreateHotkeyGUIControls(void)
|
||||
{
|
||||
const wxString pageNames[] =
|
||||
{
|
||||
_("General"),
|
||||
_("State Saves")
|
||||
};
|
||||
|
||||
const wxString hkText[] =
|
||||
{
|
||||
_("Open"),
|
||||
_("Change Disc"),
|
||||
_("Refresh List"),
|
||||
|
||||
_("Play/Pause"),
|
||||
_("Stop"),
|
||||
_("Reset"),
|
||||
_("Frame Advance"),
|
||||
|
||||
_("Start Recording"),
|
||||
_("Play Recording"),
|
||||
_("Export Recording"),
|
||||
_("Read-only mode"),
|
||||
|
||||
_("Toggle Fullscreen"),
|
||||
_("Take Screenshot"),
|
||||
|
||||
_("Connect Wiimote 1"),
|
||||
_("Connect Wiimote 2"),
|
||||
_("Connect Wiimote 3"),
|
||||
_("Connect Wiimote 4"),
|
||||
|
||||
_("Load State Slot 1"),
|
||||
_("Load State Slot 2"),
|
||||
_("Load State Slot 3"),
|
||||
_("Load State Slot 4"),
|
||||
_("Load State Slot 5"),
|
||||
_("Load State Slot 6"),
|
||||
_("Load State Slot 7"),
|
||||
_("Load State Slot 8"),
|
||||
|
||||
_("Save State Slot 1"),
|
||||
_("Save State Slot 2"),
|
||||
_("Save State Slot 3"),
|
||||
_("Save State Slot 4"),
|
||||
_("Save State Slot 5"),
|
||||
_("Save State Slot 6"),
|
||||
_("Save State Slot 7"),
|
||||
_("Save State Slot 8")
|
||||
};
|
||||
|
||||
const int page_breaks[3] = {HK_OPEN, HK_LOAD_STATE_SLOT_1, NUM_HOTKEYS};
|
||||
|
||||
// Configuration controls sizes
|
||||
wxSize size(100,20);
|
||||
// A small type font
|
||||
wxFont m_SmallFont(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
|
||||
|
||||
wxNotebook *Notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
|
||||
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
wxPanel *Page = new wxPanel(Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize);
|
||||
Notebook->AddPage(Page, pageNames[j]);
|
||||
|
||||
wxGridBagSizer *sHotkeys = new wxGridBagSizer();
|
||||
|
||||
// Header line
|
||||
for (int i = 0; i < HOTKEY_NUM_COLUMNS; i++)
|
||||
{
|
||||
wxBoxSizer *HeaderSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxStaticText *StaticTextHeader = new wxStaticText(Page, wxID_ANY, _("Action"));
|
||||
HeaderSizer->Add(StaticTextHeader, 1, wxALL, 2);
|
||||
StaticTextHeader = new wxStaticText(Page, wxID_ANY, _("Key"), wxDefaultPosition, size);
|
||||
HeaderSizer->Add(StaticTextHeader, 0, wxALL, 2);
|
||||
sHotkeys->Add(HeaderSizer, wxGBPosition(0, i), wxDefaultSpan, wxEXPAND | wxLEFT, (i > 0) ? 30 : 1);
|
||||
}
|
||||
|
||||
int column_break = (page_breaks[j+1] + page_breaks[j] + 1) / 2;
|
||||
|
||||
for (int i = page_breaks[j]; i < page_breaks[j+1]; i++)
|
||||
{
|
||||
// Text for the action
|
||||
wxStaticText *stHotkeys = new wxStaticText(Page, wxID_ANY, hkText[i]);
|
||||
|
||||
// Key selection button
|
||||
m_Button_Hotkeys[i] = new wxButton(Page, i, wxEmptyString,
|
||||
wxDefaultPosition, size);
|
||||
m_Button_Hotkeys[i]->SetFont(m_SmallFont);
|
||||
m_Button_Hotkeys[i]->SetToolTip(_("Left click to detect hotkeys.\nEnter space to clear."));
|
||||
SetButtonText(i,
|
||||
InputCommon::WXKeyToString(SConfig::GetInstance().m_LocalCoreStartupParameter.iHotkey[i]),
|
||||
InputCommon::WXKeymodToString(
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.iHotkeyModifier[i]));
|
||||
|
||||
wxBoxSizer *sHotkey = new wxBoxSizer(wxHORIZONTAL);
|
||||
sHotkey->Add(stHotkeys, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 2);
|
||||
sHotkey->Add(m_Button_Hotkeys[i], 0, wxALL, 2);
|
||||
sHotkeys->Add(sHotkey,
|
||||
wxGBPosition((i < column_break) ? i - page_breaks[j] + 1 : i - column_break + 1,
|
||||
(i < column_break) ? 0 : 1),
|
||||
wxDefaultSpan, wxEXPAND | wxLEFT, (i < column_break) ? 1 : 30);
|
||||
}
|
||||
|
||||
wxStaticBoxSizer *sHotkeyBox = new wxStaticBoxSizer(wxVERTICAL, Page, _("Hotkeys"));
|
||||
sHotkeyBox->Add(sHotkeys);
|
||||
|
||||
wxBoxSizer* const sPage = new wxBoxSizer(wxVERTICAL);
|
||||
sPage->Add(sHotkeyBox, 0, wxEXPAND | wxALL, 5);
|
||||
Page->SetSizer(sPage);
|
||||
}
|
||||
|
||||
wxBoxSizer *sMainSizer = new wxBoxSizer(wxVERTICAL);
|
||||
sMainSizer->Add(Notebook, 0, wxEXPAND | wxALL, 5);
|
||||
sMainSizer->Add(CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT | wxDOWN, 5);
|
||||
SetSizerAndFit(sMainSizer);
|
||||
SetFocus();
|
||||
}
|
||||
|
74
Source/Core/DolphinWX/Src/GCMicDlg.h
Normal file
74
Source/Core/DolphinWX/Src/GCMicDlg.h
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef __HOTKEYDIALOG_h__
|
||||
#define __HOTKEYDIALOG_h__
|
||||
|
||||
#include <wx/wx.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/combobox.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/gbsizer.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "CoreParameter.h"
|
||||
#include "WXInputBase.h"
|
||||
|
||||
#if defined(HAVE_X11) && HAVE_X11
|
||||
#include "X11InputBase.h"
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/keysym.h>
|
||||
#endif
|
||||
|
||||
class GCMicDialog : public wxDialog
|
||||
{
|
||||
public:
|
||||
GCMicDialog(wxWindow *parent,
|
||||
wxWindowID id = 1,
|
||||
const wxString &title = _("GCMic Configuration"),
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = wxDEFAULT_DIALOG_STYLE);
|
||||
virtual ~GCMicDialog();
|
||||
|
||||
private:
|
||||
DECLARE_EVENT_TABLE();
|
||||
|
||||
wxString OldLabel;
|
||||
|
||||
wxButton *ClickedButton,
|
||||
*m_Button_Hotkeys[NUM_HOTKEYS];
|
||||
|
||||
wxTimer *m_ButtonMappingTimer;
|
||||
|
||||
void OnButtonTimer(wxTimerEvent& WXUNUSED(event)) { DoGetButtons(GetButtonWaitingID); }
|
||||
void OnButtonClick(wxCommandEvent& event);
|
||||
void OnKeyDown(wxKeyEvent& event);
|
||||
void SaveButtonMapping(int Id, int Key, int Modkey);
|
||||
void CreateHotkeyGUIControls(void);
|
||||
|
||||
void SetButtonText(int id, const wxString &keystr, const wxString &modkeystr = wxString());
|
||||
|
||||
void DoGetButtons(int id);
|
||||
void EndGetButtons(void);
|
||||
|
||||
int GetButtonWaitingID, GetButtonWaitingTimer, g_Pressed, g_Modkey;
|
||||
};
|
||||
#endif
|
||||
|
@ -51,7 +51,6 @@ typedef struct
|
||||
unsigned char triggerRight; // 0 <= triggerRight <= 255
|
||||
unsigned char analogA; // 0 <= analogA <= 255
|
||||
unsigned char analogB; // 0 <= analogB <= 255
|
||||
bool MicButton; // HAX
|
||||
signed char err; // one of PAD_ERR_* number
|
||||
} SPADStatus;
|
||||
|
||||
|
@ -7,8 +7,8 @@
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\SDL\$(PlatformName);..\..\..\Externals\GLew;..\..\..\Externals\Cg</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>dsound.lib;dxerr.lib;iphlpapi.lib;winmm.lib;setupapi.lib;xinput.lib;vfw32.lib;cg.lib;cgGL.lib;opengl32.lib;glew32s.lib;glu32.lib;rpcrt4.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\SDL\$(PlatformName);..\..\..\Externals\GLew;..\..\..\Externals\Cg;..\..\..\Externals\portaudio\$(PlatformName)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>portaudio.lib;dsound.lib;dxerr.lib;iphlpapi.lib;winmm.lib;setupapi.lib;xinput.lib;vfw32.lib;cg.lib;cgGL.lib;opengl32.lib;glew32s.lib;glu32.lib;rpcrt4.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup />
|
||||
|
@ -8,8 +8,8 @@
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\SDL\$(PlatformName);..\..\..\Externals\GLew;..\..\..\Externals\Cg64</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>dsound.lib;dxerr.lib;iphlpapi.lib;winmm.lib;setupapi.lib;xinput.lib;vfw32.lib;cg.lib;cgGL.lib;opengl32.lib;glew64s.lib;glu32.lib;rpcrt4.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\SDL\$(PlatformName);..\..\..\Externals\GLew;..\..\..\Externals\Cg64;..\..\..\Externals\portaudio\$(PlatformName)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>portaudio.lib;dsound.lib;dxerr.lib;iphlpapi.lib;winmm.lib;setupapi.lib;xinput.lib;vfw32.lib;cg.lib;cgGL.lib;opengl32.lib;glew64s.lib;glu32.lib;rpcrt4.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup />
|
||||
|
Reference in New Issue
Block a user