Added Wiimote speaker support by hack patching out the IsBusyStream function using HLE. DSP LLE is required to process the speaker data. This commit works with real Wiimotes. I have added the code to decode the audio from the emulated wiimotes but have not added the code to output their audio to the PC speakers.

* Added HLE function IsBusyStream which signals that the Wiimote is ready to accept speaker data.  This function is not a conversion from the real PPC code.  It a simple function that returns the "ready" status after being polled.
* Added code to find and patch HLE functions on boot
* Added 4bit Yamaha ADPCM decoder from the ffmpeg project
* Removed some test code
* Added some copyright notices

Fixes issue 438.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7225 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
skidau 2011-02-22 12:48:35 +00:00
parent f2a086c44c
commit d92aad4430
11 changed files with 194 additions and 114 deletions

Binary file not shown.

View File

@ -47,6 +47,7 @@
#include "../ConfigManager.h"
#include "VolumeCreator.h" // DiscIO
#include "NANDContentLoader.h"
#include "CommonPaths.h"
void CBoot::Load_FST(bool _bIsWii)
{
@ -217,6 +218,19 @@ bool CBoot::BootUp()
EmulatedBS2(_StartupPara.bWii);
}
// Scan for common HLE functions
if (!_StartupPara.bEnableDebugging)
{
PPCAnalyst::FindFunctions(0x80000000, 0x81800000, &g_symbolDB);
SignatureDB db;
if (db.Load((File::GetSysDirectory() + TOTALDB).c_str()))
{
db.Apply(&g_symbolDB);
}
HLE::PatchFunctions();
g_symbolDB.Clear();
}
/* Try to load the symbol map if there is one, and then scan it for
and eventually replace code */
if (LoadMapFromFilename(_StartupPara.m_strFilename, gameID))

View File

@ -68,6 +68,7 @@ static const SPatch OSPatches[] =
// wii only
//{ "__OSInitAudioSystem", HLE_Misc::UnimplementedFunction },
{ "IsBusyStrm_", HLE_Misc::IsBusyStream },
// Super Monkey Ball - no longer needed.
//{ ".evil_vec_cosine", HLE_Misc::SMB_EvilVecCosine },
@ -91,7 +92,7 @@ static const SPatch OSPatches[] =
// { "GXPeekARGB", HLE_Misc::GXPeekARGB},
// Name doesn't matter, installed in CBoot::BootUp()
{ "HBReload", HLE_Misc::HBReload },
{ "HBReload", HLE_Misc::HBReload },
};
static const SPatch OSBreakPoints[] =

View File

@ -22,6 +22,7 @@
#include "../PowerPC/PowerPC.h"
#include "../HW/Memmap.h"
#include "../Host.h"
#include "CoreTiming.h"
namespace HLE_Misc
{
@ -282,4 +283,28 @@ void HBReload()
Host_Message(WM_USER_STOP);
}
u8 isBusyPoll = 0;
// Hack: Wiimotes are never too busy to process speaker data
void IsBusyStream()
{
isBusyPoll++;
// Signal that the wiimote is idle for a few cycles, allowing sound
// to be processed.
if (isBusyPoll < 5)
{
// Wiimote is idle
GPR(3) = 0;
}
else
{
// Wiimote is busy
GPR(3) = 1;
if (isBusyPoll >= 8)
isBusyPoll = 0;
}
NPC = LR;
}
}

View File

@ -39,6 +39,7 @@ namespace HLE_Misc
void FZ_sqrt_internal();
void FZ_rsqrt_internal();
void HBReload();
void IsBusyStream();
}
#endif

View File

@ -1,3 +1,20 @@
// 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/
// Adapted from in_cube by hcs & destop
#include "StreamADPCM.h"

View File

@ -1,3 +1,20 @@
// 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/
// Adapted from in_cube by hcs & destop
#ifndef _STREAMADPCM_H

View File

@ -140,9 +140,7 @@ void Wiimote::HidOutputReport(const wm_report* const sr, const bool send_ack)
break;
case WM_WRITE_SPEAKER_DATA : // 0x18
#ifdef USE_WIIMOTE_EMU_SPEAKER
SpeakerData((wm_speaker_data*)sr->data);
#endif
Wiimote::SpeakerData((wm_speaker_data*)sr->data);
// TODO: Does this need an ack?
return; // no ack
break;
@ -150,11 +148,9 @@ void Wiimote::HidOutputReport(const wm_report* const sr, const bool send_ack)
case WM_SPEAKER_MUTE : // 0x19
//INFO_LOG(WIIMOTE, "WM Speaker Mute: 0x%02x", sr->data[0]);
//PanicAlert( "WM Speaker Mute: %d", sr->data[0] & 0x04 );
#ifdef USE_WIIMOTE_EMU_SPEAKER
// testing
if (sr->data[0] & 0x04)
memset(&m_channel_status, 0, sizeof(m_channel_status));
#endif
//if (sr->data[0] & 0x04)
// memset(&m_channel_status, 0, sizeof(m_channel_status));
m_speaker_mute = sr->enable;
if (false == sr->ack)
return;

View File

@ -1,38 +1,95 @@
#include "WiimoteEmu.h"
// Copyright (C) 2003 Dolphin Project.
#ifdef USE_WIIMOTE_EMU_SPEAKER
// 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 "WiimoteEmu.h"
#include <fstream>
// Yamaha ADPCM decoder code based on The ffmpeg Project (Copyright (c) 2001-2003)
typedef struct ADPCMChannelStatus
{
int predictor;
int step;
} ADPCMChannelStatus;
static const int yamaha_difflookup[] = {
1, 3, 5, 7, 9, 11, 13, 15,
-1, -3, -5, -7, -9, -11, -13, -15
};
static const int yamaha_indexscale[] = {
230, 230, 230, 230, 307, 409, 512, 614,
230, 230, 230, 230, 307, 409, 512, 614
};
static u16 av_clip_int16(int a)
{
if ((a+32768) & ~65535) return (a>>31) ^ 32767;
else return a;
}
static int av_clip(int a, int amin, int amax)
{
if (a < amin) return amin;
else if (a > amax) return amax;
else return a;
}
static s16 adpcm_yamaha_expand_nibble(ADPCMChannelStatus *c, unsigned char nibble)
{
if(!c->step) {
c->predictor = 0;
c->step = 127;
}
c->predictor += (c->step * yamaha_difflookup[nibble]) / 8;
c->predictor = av_clip_int16(c->predictor);
c->step = (c->step * yamaha_indexscale[nibble]) >> 8;
c->step = av_clip(c->step, 127, 24567);
return c->predictor;
}
namespace WiimoteEmu
{
ADPCMChannelStatus cs;
void Wiimote::SpeakerData(wm_speaker_data* sd)
{
SoundBuffer sb;
sb.samples = new s16[sd->length * 2];
s16 samples[40];
u16 sampleRate = 6000000 / Common::swap16(m_reg_speaker.sample_rate);
s16* s = sb.samples;
const u8* const e = sd->data + sd->length;
for ( const u8* i = sd->data; i<e; ++i )
if (m_reg_speaker.format == 0x40)
{
*s++ = NGCADPCM::ADPDecodeSample(*i & 0x0F, sd->data[0] & 0x0F, &m_channel_status.hist1p, &m_channel_status.hist2p);
*s++ = NGCADPCM::ADPDecodeSample(*i >> 4, sd->data[0] >> 4, &m_channel_status.hist1p, &m_channel_status.hist2p);
// 8 bit PCM
for (int i = 0; i < 20; ++i)
{
samples[i] = (s16)(s8)sd->data[i];
}
}
else if (m_reg_speaker.format == 0x00)
{
// 4 bit Yamaha ADPCM
// TODO: The first byte of the source data = length?
for (int i = 0; i < 20; ++i)
{
samples[i * 2] = adpcm_yamaha_expand_nibble(&cs, sd->data[i] & 0x0F);
samples[i * 2 + 1] = adpcm_yamaha_expand_nibble(&cs, (sd->data[i] >> 4) & 0x0F);
}
}
alGenBuffers(1, &sb.buffer);
// TODO make this not always 3000
alBufferData(sb.buffer, AL_FORMAT_MONO16, sb.samples, (sd->length * sizeof(short) * 2), 3360);
// testing
//alBufferData(sb.buffer, AL_FORMAT_MONO16, sb.samples, (sd->length * sizeof(short) * 2), 48000/m_reg_speaker->sample_rate);
alSourceQueueBuffers(m_audio_source, 1, &sb.buffer);
ALint state;
alGetSourcei(m_audio_source, AL_SOURCE_STATE, &state);
if (AL_PLAYING != state)
alSourcePlay(m_audio_source);
m_audio_buffers.push(sb);
}
}
#endif

View File

@ -1,3 +1,19 @@
// 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 "Attachment/Classic.h"
#include "Attachment/Nunchuk.h"
@ -282,32 +298,6 @@ Wiimote::Wiimote( const unsigned int index )
m_options->settings.push_back(new ControlGroup::Setting(_trans("Background Input"), false));
m_options->settings.push_back(new ControlGroup::Setting(_trans("Sideways Wiimote"), false));
m_options->settings.push_back(new ControlGroup::Setting(_trans("Upright Wiimote"), false));
#ifdef USE_WIIMOTE_EMU_SPEAKER
// set up speaker stuff
// this doesnt belong here
// TODO: i never clean up any of this audio stuff
if (0 == m_index) // very dumb
{
ALCdevice* pDevice;
ALchar DeviceName[] = "DirectSound3D";
pDevice = alcOpenDevice(DeviceName);
ALCcontext* pContext;
pContext = alcCreateContext(pDevice, NULL);
alcMakeContextCurrent(pContext);
}
alListener3f(AL_POSITION, 0.0, 0.0, 0.0);
alListener3f(AL_VELOCITY, 0.0, 0.0, 0.0);
alListener3f(AL_DIRECTION, 0.0, 0.0, 0.0);
alGenSources(1, &m_audio_source);
alSourcef(m_audio_source, AL_PITCH, 1.0);
alSourcef(m_audio_source, AL_GAIN, 1.0);
alSourcei(m_audio_source, AL_LOOPING, false);
#endif
// --- reset eeprom/register/values to default ---
Reset();
@ -634,36 +624,6 @@ void Wiimote::Update()
if (Step())
return;
// ----speaker----
#ifdef USE_WIIMOTE_EMU_SPEAKER
ALint processed = 0;
alGetSourcei(m_audio_source, AL_BUFFERS_PROCESSED, &processed);
while (processed--)
{
//PanicAlert("Buffer Processed");
alSourceUnqueueBuffers(m_audio_source, 1, &m_audio_buffers.front().buffer);
alDeleteBuffers(1, &m_audio_buffers.front().buffer);
delete[] m_audio_buffers.front().samples;
m_audio_buffers.pop();
}
// testing speaker crap
//m_rumble->controls[0]->control_ref->State( m_speaker_data.size() > 0 );
//if ( m_speaker_data.size() )
//m_speaker_data.pop();
//while ( m_speaker_data.size() )
//{
// std::ofstream file;
// file.open( "test.pcm", std::ios::app | std::ios::out | std::ios::binary );
// file.put(m_speaker_data.front());
// file.close();
// m_speaker_data.pop();
//}
#endif
u8 data[MAX_PAYLOAD];
memset(data, 0, sizeof(data));

View File

@ -1,13 +1,23 @@
// 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 _CONEMU_WIIMOTE_H_
#define _CONEMU_WIIMOTE_H_
//#define USE_WIIMOTE_EMU_SPEAKER
//#include <Core.h>
//#include <HW/StreamADPCM.h>
// just used to get the OpenAL includes :p
//#include <OpenALStream.h>
#include "../../Core.h"
#include "ControllerEmu.h"
@ -123,10 +133,7 @@ private:
void ReadData(const wm_read_data* const rd);
void WriteData(const wm_write_data* const wd);
void SendReadDataReply(ReadRequest& _request);
#ifdef USE_WIIMOTE_EMU_SPEAKER
void SpeakerData(wm_speaker_data* sd);
#endif
// control groups
Buttons *m_buttons, *m_dpad, *m_shake;
@ -165,21 +172,6 @@ private:
// maybe read requests cancel any current requests
std::queue< ReadRequest > m_read_requests;
#ifdef USE_WIIMOTE_EMU_SPEAKER
// speaker stuff
struct SoundBuffer
{
s16* samples;
ALuint buffer;
};
std::queue<SoundBuffer> m_audio_buffers;
ALuint m_audio_source;
struct
{
int hist1p, hist2p;
} m_channel_status;
#endif
wiimote_key m_ext_key;
u8 m_eeprom[WIIMOTE_EEPROM_SIZE];