Mic device WIP. define USE_PORTAUDIO and link with portaudio to test it.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2153 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Shawn Hoffman 2009-02-08 18:25:25 +00:00
parent 175abfef0a
commit c3dbbb1f23
4 changed files with 199 additions and 182 deletions

View File

@ -24,16 +24,14 @@
#include "EXI_Device.h" #include "EXI_Device.h"
#include "EXI_DeviceMic.h" #include "EXI_DeviceMic.h"
bool MicButton; bool MicButton = false;
bool IsOpen; bool IsOpen;
// Doing it this way since it's Linux only atm due to portaudio, even though the lib is crossplatform
// I had to include libs in the DolphinWX Sconscript file which I thought was BS. //#define USE_PORTAUDIO
// So I'm committing with all the code ifdeff'ed out #ifndef USE_PORTAUDIO
#if 1
void SetMic(bool Value) void SetMic(bool Value){}
{}
bool GetMic()
{return false;}
CEXIMic::CEXIMic(int _Index){} CEXIMic::CEXIMic(int _Index){}
CEXIMic::~CEXIMic(){} CEXIMic::~CEXIMic(){}
bool CEXIMic::IsPresent() {return false;} bool CEXIMic::IsPresent() {return false;}
@ -41,27 +39,30 @@ void CEXIMic::SetCS(int cs){}
void CEXIMic::Update(){} void CEXIMic::Update(){}
void CEXIMic::TransferByte(u8 &byte){} void CEXIMic::TransferByte(u8 &byte){}
bool CEXIMic::IsInterruptSet(){return false;} bool CEXIMic::IsInterruptSet(){return false;}
#else #else
//////////////////////////////////////////////////////////////////////////
// We use PortAudio for cross-platform audio input.
// It needs the headers and a lib file for the dll
#include <portaudio.h> #include <portaudio.h>
#include <stdio.h>
unsigned char InputData[128*44100]; // Max Data is 128 samples at 44100 #ifdef _WIN32
PaStream *stream; #pragma comment(lib, "C:/Users/Shawn/Desktop/portaudio/portaudio-v19/portaudio_x64.lib")
PaError err; #endif
unsigned short SFreq;
unsigned short SNum; unsigned char InputData[128*44100]; // Max Data is 128 samples at 44100
unsigned int Sample; PaStream *stream;
bool m_bInterruptSet; PaError err;
bool Sampling; unsigned short SFreq;
unsigned short SNum;
unsigned int Sample;
bool m_bInterruptSet;
bool Sampling;
void SetMic(bool Value) void SetMic(bool Value)
{ {
if(Value != MicButton)
{
MicButton = Value; MicButton = Value;
printf("Mic is set to %s\n", MicButton ? "true" : "false");
if(Sampling) if(Sampling)
{ {
if(MicButton) if(MicButton)
@ -69,12 +70,8 @@ void SetMic(bool Value)
else else
Pa_StopStream( stream ); Pa_StopStream( stream );
} }
}
}
bool GetMic()
{
return MicButton;
} }
static unsigned int k = 0; static unsigned int k = 0;
int patestCallback( const void *inputBuffer, void *outputBuffer, int patestCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer, unsigned long framesPerBuffer,
@ -93,27 +90,35 @@ int patestCallback( const void *inputBuffer, void *outputBuffer,
return 0; return 0;
} }
//////////////////////////////////////////////////////////////////////////
// EXI Mic Device
//////////////////////////////////////////////////////////////////////////
CEXIMic::CEXIMic(int _Index) CEXIMic::CEXIMic(int _Index)
{ {
Index = _Index; Index = _Index;
memset(&Status.U16, 0 , sizeof(u16));
command = 0; command = 0;
Sample = 0; Sample = 0;
m_uPosition = 0; m_uPosition = 0;
formatDelay = 0;
ID = 0x0a000000;
m_bInterruptSet = false; m_bInterruptSet = false;
MicButton = false; MicButton = false;
IsOpen = false; IsOpen = false;
Pa_Initialize(); err = Pa_Initialize();
if (err != paNoError)
LOGV(EXPANSIONINTERFACE, 0, "EXI MIC: PortAudio Initialize error %s", Pa_GetErrorText(err));
} }
CEXIMic::~CEXIMic() CEXIMic::~CEXIMic()
{ {
Pa_CloseStream( stream ); err = Pa_CloseStream( stream );
Pa_Terminate(); if (err != paNoError)
LOGV(EXPANSIONINTERFACE, 0, "EXI MIC: PortAudio Close error %s", Pa_GetErrorText(err));
err = Pa_Terminate();
if (err != paNoError)
LOGV(EXPANSIONINTERFACE, 0, "EXI MIC: PortAudio Terminate error %s", Pa_GetErrorText(err));
} }
bool CEXIMic::IsPresent() bool CEXIMic::IsPresent()
@ -132,8 +137,15 @@ void CEXIMic::SetCS(int cs)
{ {
switch (command) switch (command)
{ {
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.
// (shuffle2) Perhaps we should just clear the buffer and effectively "reset" here?
LOGV(EXPANSIONINTERFACE, 1, "EXI MIC: WakeUp cmd");
break;
default: default:
//printf("Don't know Command %x\n", command); LOGV(EXPANSIONINTERFACE, 1, "EXI MIC: unknown CS command %02x\n", command);
break; break;
} }
} }
@ -147,7 +159,7 @@ bool CEXIMic::IsInterruptSet()
{ {
if(m_bInterruptSet) if(m_bInterruptSet)
{ {
//m_bInterruptSet = false; m_bInterruptSet = false;
return true; return true;
} }
else else
@ -158,17 +170,11 @@ bool CEXIMic::IsInterruptSet()
void CEXIMic::TransferByte(u8 &byte) void CEXIMic::TransferByte(u8 &byte)
{ {
LOGV(EXPANSIONINTERFACE, 1, "EXI MIC: > %02x", byte);
if (m_uPosition == 0) if (m_uPosition == 0)
{ {
command = byte; // first byte is command command = byte; // first byte is command
byte = 0xFF; // would be tristate, but we don't care. byte = 0xFF; // would be tristate, but we don't care.
if(command == cmdClearStatus)
{
byte = 0xFF;
m_uPosition = 0;
m_bInterruptSet = false;
}
} }
else else
{ {
@ -176,111 +182,118 @@ void CEXIMic::TransferByte(u8 &byte)
{ {
case cmdID: case cmdID:
if (m_uPosition == 1) if (m_uPosition == 1)
;//byte = 0x80; // dummy cycle ;//byte = 0x80; // dummy cycle - taken from memcard, it doesn't seem to need it here
else else
byte = (u8)(ID >> (24-(((m_uPosition-2) & 3) * 8))); byte = (u8)(EXI_DEVTYPE_MIC >> (24-(((m_uPosition-2) & 3) * 8)));
break; break;
// Setting Bits: REMEMBER THIS! D:< case cmdGetStatus:
// <ector--> var |= (1 << bitnum_from_0)
// <ector--> var &= ~(1 << bitnum_from_0) clears
case cmdStatus:
{ {
if(GetMic()) if (m_uPosition != 1 && m_uPosition != 2)
{ LOGV(EXPANSIONINTERFACE, 0, "EXI MIC: WARNING GetStatus @ pos: %d should never happen", m_uPosition);
Status.U16 |= (1 << 7); if((!Status.button && MicButton)||(Status.button && !MicButton))
} LOGV(EXPANSIONINTERFACE, 0, "EXI MIC: Mic button %s", MicButton ? "pressed" : "released");
else
{
Status.U16 &= ~(1 << 7);
}
byte = (u8)(Status.U16 >> (24-(((m_uPosition-2) & 3) * 8)));
Status.button = MicButton ? 1 : 0;
byte = Status.U8[ (m_uPosition - 1) ? 0 : 1];
} }
break; break;
case cmdSetStatus: 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; Status.U8[ (m_uPosition - 1) ? 0 : 1] = byte;
if(m_uPosition == 2) if(m_uPosition == 2)
{ {
printf("Status is 0x%04x ", Status.U16); Sampling = (Status.sampling == 1) ? true : false;
//Status is 0x7273 1 1 0 0 1 1 1 0\ 0 1 0 0 1 1 1 0
//Status is 0x4b00
// 0 0 0 0 0 0 0 0 : Bit 0-7: Unknown
// 1 : Bit 8 : 1 : Button Pressed
// 1 : Bit 9 : 1 ? Overflow?
// 0 : Bit 10 : Unknown related to 0 and 15 values It seems
// 1 0 : Bit 11-12 : Sample Rate, 00-11025, 01-22050, 10-44100, 11-??
// 0 1 : Bit 13-14 : Period Length, 00-32, 01-64, 10-128, 11-???
// 0 : Bit 15 : If We Are Sampling or Not
if((Status.U16 >> 15) & 1) // We ARE Sampling switch (Status.sRate)
{ {
printf("We are now Sampling"); case 0:
Sampling = true;
}
else
{
Sampling = false;
// Only set to false once we have run out of Data?
//m_bInterruptSet = false;
}
if(!(Status.U16 >> 11) & 1)
if((Status.U16 >> 12) & 1 )
SFreq = 22050;
else
SFreq = 11025; SFreq = 11025;
else break;
case 1:
SFreq = 22050;
break;
case 2:
SFreq = 44100; SFreq = 44100;
break;
default:
LOGV(EXPANSIONINTERFACE, 0, "EXI MIC: Trying to set unknown sampling rate");
SFreq = 44100;
break;
}
if(!(Status.U16 >> 13) & 1) switch (Status.pLength)
if((Status.U16 >> 14) & 1) {
SNum = 64; case 0:
else
SNum = 32; SNum = 32;
else break;
case 1:
SNum = 64;
break;
case 2:
SNum = 128; SNum = 128;
break;
default:
LOGV(EXPANSIONINTERFACE, 0, "EXI MIC: Trying to set unknown period length");
SNum = 128;
break;
}
LOGV(EXPANSIONINTERFACE, 0, "//////////////////////////////////////////////////////////////////////////");
LOGV(EXPANSIONINTERFACE, 0, "EXI MIC: Status is now 0x%04x", Status.U16);
LOGV(EXPANSIONINTERFACE, 0, "\tbutton %i\tsRate %i\tpLength %i\tsampling %i\n",
Status.button, Status.sRate, Status.pLength, Status.sampling);
for(int a = 0;a < 16;a++)
printf("%d ", (Status.U16 >> a) & 1);
printf("\n");
if(!IsOpen) if(!IsOpen)
{ {
// Open Our PortAudio Stream // Open Our PortAudio Stream
// (shuffle2) This (and the callback) are probably wrong, I can't test
err = Pa_OpenDefaultStream( &stream, err = Pa_OpenDefaultStream( &stream,
1, 1, // Input Channels
0, 0, // Output Channels
paUInt8 , paInt16, // Output format - GC wants PCM samples in signed 16-bit format
SFreq, SFreq, // Sample Rate
SNum, SNum, // Period Length (frames per buffer)
patestCallback, patestCallback,// Our callback!
NULL); NULL); // Pointer passed to our callback
if( err != paNoError ) if (err != paNoError)
printf("error %s\n", Pa_GetErrorText (err)); {
LOGV(EXPANSIONINTERFACE, 0, "EXI MIC: PortAudio error %s", Pa_GetErrorText(err));
}
else
IsOpen = true; IsOpen = true;
} }
} }
} }
break; break;
case cmdGetBuffer: case cmdGetBuffer:
{
static unsigned long At = 0; static unsigned long At = 0;
printf("POS %d\n", m_uPosition); LOGV(EXPANSIONINTERFACE, 0, "EXI MIC: POS %d\n", m_uPosition);
// Are we not able to return all the data then? // Are we not able to return all the data then?
// I think if we set the Interrupt to false, it reads another 64 // I think if we set the Interrupt to false, it reads another 64
// Will Look in to it. // Will Look in to it.
// Set to False here? Prevents lock ups maybe? // (sonicadvance1) Set to False here? Prevents lock ups maybe?
// (shuffle2) It seems to play nice with interrupts for the most part.
if(At >= SNum){ if(At >= SNum){
At = 0; At = 0;
k = 0; k = 0;
m_bInterruptSet = false; m_bInterruptSet = true;
} }
byte = InputData[At]; byte = 0xAB;//InputData[At]; (shuffle2) just sending constant dummy data for now
At++; At++;
}
break; break;
default: default:
printf("Don't know command %x in Byte transfer\n", command); LOGV(EXPANSIONINTERFACE, 0, "EXI MIC: unknown command byte %02x\n", command);
break; break;
} }
} }
m_uPosition++; m_uPosition++;
LOGV(EXPANSIONINTERFACE, 1, "EXI MIC: < %02x", byte);
} }
#endif #endif

View File

@ -30,23 +30,18 @@ public:
private: private:
enum
{
EXI_DEVTYPE_MIC = 0x0A000000
};
enum enum
{ {
cmdID = 0x00, cmdID = 0x00,
cmdStatus = 0x40, cmdGetStatus = 0x40,
cmdSetStatus = 0x80, cmdSetStatus = 0x80,
cmdGetBuffer = 0x20, cmdGetBuffer = 0x20,
cmdWriteBuffer = 0x82, cmdWakeUp = 0xFF,
cmdReadStatus = 0x83,
cmdReadID = 0x85,
cmdReadErrorBuffer = 0x86,
cmdWakeUp = 0x87,
cmdSleep = 0x88,
cmdClearStatus = 0x89,
cmdSectorErase = 0xF1,
cmdPageProgram = 0xF2,
cmdExtraByteProgram = 0xF3,
cmdChipErase = 0xF4,
}; };
// STATE_TO_SAVE // STATE_TO_SAVE
@ -56,22 +51,25 @@ private:
{ {
u16 U16; u16 U16;
u8 U8[2]; u8 U8[2];
struct
{
unsigned :8; // Unknown
unsigned button :1; // 1: Button Pressed
unsigned unk1 :1; // 1 ? Overflow?
unsigned unk2 :1; // Unknown related to 0 and 15 values It seems
unsigned sRate :2; // Sample Rate, 00-11025, 01-22050, 10-44100, 11-??
unsigned pLength :2; // Period Length, 00-32, 01-64, 10-128, 11-???
unsigned sampling :1; // If We Are Sampling or Not
};
}; };
int Index; int Index;
u32 m_uPosition; u32 m_uPosition;
u32 formatDelay;
uStatus Status; uStatus Status;
//! memory card parameters
unsigned int ID;
unsigned int address;
protected: protected:
virtual void TransferByte(u8 &byte); virtual void TransferByte(u8 &byte);
}; };
void SetMic(bool Value); void SetMic(bool Value);
bool GetMic();
#endif #endif

View File

@ -590,6 +590,7 @@
LinkIncremental="1" LinkIncremental="1"
SuppressStartupBanner="true" SuppressStartupBanner="true"
GenerateManifest="false" GenerateManifest="false"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb" ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb"
RandomizedBaseAddress="1" RandomizedBaseAddress="1"
DataExecutionPrevention="0" DataExecutionPrevention="0"

View File

@ -334,6 +334,8 @@ void DInput_Read(int _numPAD, SPADStatus* _pPADStatus)
if (dinput.diks[pad[_numPAD].keyForControl[CTL_DPADLEFT]] & 0xFF){_pPADStatus->button |= PAD_BUTTON_LEFT;} if (dinput.diks[pad[_numPAD].keyForControl[CTL_DPADLEFT]] & 0xFF){_pPADStatus->button |= PAD_BUTTON_LEFT;}
if (dinput.diks[pad[_numPAD].keyForControl[CTL_DPADRIGHT]]& 0xFF){_pPADStatus->button |= PAD_BUTTON_RIGHT;} if (dinput.diks[pad[_numPAD].keyForControl[CTL_DPADRIGHT]]& 0xFF){_pPADStatus->button |= PAD_BUTTON_RIGHT;}
if (dinput.diks[pad[_numPAD].keyForControl[CTL_START]] & 0xFF){_pPADStatus->button |= PAD_BUTTON_START;} if (dinput.diks[pad[_numPAD].keyForControl[CTL_START]] & 0xFF){_pPADStatus->button |= PAD_BUTTON_START;}
_pPADStatus->MicButton = (dinput.diks[pad[_numPAD].keyForControl[CTL_MIC]] & 0xFF) ? true : false;
} }
bool XInput_Read(int XPadPlayer, SPADStatus* _pPADStatus) bool XInput_Read(int XPadPlayer, SPADStatus* _pPADStatus)
@ -381,6 +383,8 @@ bool XInput_Read(int XPadPlayer, SPADStatus* _pPADStatus)
if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_UP) {_pPADStatus->button |= PAD_BUTTON_UP;} if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_UP) {_pPADStatus->button |= PAD_BUTTON_UP;}
if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) {_pPADStatus->button |= PAD_BUTTON_DOWN;} if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) {_pPADStatus->button |= PAD_BUTTON_DOWN;}
//_pPADStatus->MicButton = (xpad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) ? true : false;
return true; return true;
} }
else else
@ -742,7 +746,8 @@ void LoadConfig()
DIK_G, DIK_G,
DIK_F, DIK_F,
DIK_H, DIK_H,
DIK_LSHIFT DIK_LSHIFT, //halfpress
DIK_M //Mic
}; };
#elif defined(HAVE_X11) && HAVE_X11 #elif defined(HAVE_X11) && HAVE_X11
const int defaultKeyForControl[NUMCONTROLS] = const int defaultKeyForControl[NUMCONTROLS] =
@ -768,7 +773,7 @@ void LoadConfig()
XK_f, XK_f,
XK_h, XK_h,
XK_Shift_L, //halfpress XK_Shift_L, //halfpress
XK_p XK_p //Mic
}; };
#elif defined(HAVE_COCOA) && HAVE_COCOA #elif defined(HAVE_COCOA) && HAVE_COCOA
const int defaultKeyForControl[NUMCONTROLS] = const int defaultKeyForControl[NUMCONTROLS] =
@ -794,7 +799,7 @@ void LoadConfig()
3, 3,
4, 4,
56, //halfpress 56, //halfpress
35 35 //Mic
}; };
#endif #endif
IniFile file; IniFile file;