From d92aad44309d5ac47ca260667372f80c199405b5 Mon Sep 17 00:00:00 2001 From: skidau Date: Tue, 22 Feb 2011 12:48:35 +0000 Subject: [PATCH] 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 --- Data/Sys/totaldb.dsy | Bin 722980 -> 723116 bytes Source/Core/Core/Src/Boot/Boot.cpp | 14 +++ Source/Core/Core/Src/HLE/HLE.cpp | 3 +- Source/Core/Core/Src/HLE/HLE_Misc.cpp | 25 ++++ Source/Core/Core/Src/HLE/HLE_Misc.h | 1 + Source/Core/Core/Src/HW/StreamADPCM.cpp | 17 +++ Source/Core/Core/Src/HW/StreamADPCM.h | 17 +++ .../Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp | 10 +- .../Core/Core/Src/HW/WiimoteEmu/Speaker.cpp | 107 ++++++++++++++---- .../Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp | 72 +++--------- .../Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.h | 42 +++---- 11 files changed, 194 insertions(+), 114 deletions(-) diff --git a/Data/Sys/totaldb.dsy b/Data/Sys/totaldb.dsy index 790a942eaefc071dfcad998bcc985dc239e2582f..bd758342b055c1cb9fb8db53cbdb6873fd76253c 100644 GIT binary patch delta 72 zcmZ27L1)cG9mb=LjIE47#MH{j+{(z(%E;Qv$kxip-pa_)%E;Nu$hDP`TbV<6?z+7$ a7K{uGp2be3#g)M&MY-{l4Rwl{7#IM#H4@SQ delta 45 zcmZ28QD?~n9mXS#jIE47#MH{j+{(z(%E;Qv$kxip-pa_)%E;Nu$hDP`TbTm@A6*J? diff --git a/Source/Core/Core/Src/Boot/Boot.cpp b/Source/Core/Core/Src/Boot/Boot.cpp index 743aba2c77..87b6c7246f 100644 --- a/Source/Core/Core/Src/Boot/Boot.cpp +++ b/Source/Core/Core/Src/Boot/Boot.cpp @@ -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)) diff --git a/Source/Core/Core/Src/HLE/HLE.cpp b/Source/Core/Core/Src/HLE/HLE.cpp index bc8a25b36a..f10cbd6e42 100644 --- a/Source/Core/Core/Src/HLE/HLE.cpp +++ b/Source/Core/Core/Src/HLE/HLE.cpp @@ -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[] = diff --git a/Source/Core/Core/Src/HLE/HLE_Misc.cpp b/Source/Core/Core/Src/HLE/HLE_Misc.cpp index d69bf09680..b9da971608 100644 --- a/Source/Core/Core/Src/HLE/HLE_Misc.cpp +++ b/Source/Core/Core/Src/HLE/HLE_Misc.cpp @@ -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; +} + } diff --git a/Source/Core/Core/Src/HLE/HLE_Misc.h b/Source/Core/Core/Src/HLE/HLE_Misc.h index 6c932258a7..dd3bef679f 100644 --- a/Source/Core/Core/Src/HLE/HLE_Misc.h +++ b/Source/Core/Core/Src/HLE/HLE_Misc.h @@ -39,6 +39,7 @@ namespace HLE_Misc void FZ_sqrt_internal(); void FZ_rsqrt_internal(); void HBReload(); + void IsBusyStream(); } #endif diff --git a/Source/Core/Core/Src/HW/StreamADPCM.cpp b/Source/Core/Core/Src/HW/StreamADPCM.cpp index 1fd9d12bc7..da0fac6868 100644 --- a/Source/Core/Core/Src/HW/StreamADPCM.cpp +++ b/Source/Core/Core/Src/HW/StreamADPCM.cpp @@ -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" diff --git a/Source/Core/Core/Src/HW/StreamADPCM.h b/Source/Core/Core/Src/HW/StreamADPCM.h index bff80e93fc..324ee249ae 100644 --- a/Source/Core/Core/Src/HW/StreamADPCM.h +++ b/Source/Core/Core/Src/HW/StreamADPCM.h @@ -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 diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp index 4e78459098..4cd69d268d 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp @@ -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; diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/Speaker.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/Speaker.cpp index fee5b778cf..108a111950 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/Speaker.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/Speaker.cpp @@ -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 + +// 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; idata[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 diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp index d503230c2e..0944ea9639 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp @@ -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)); diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.h b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.h index 01271c80ca..8e5ec4b25a 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.h +++ b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.h @@ -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 -//#include -// just used to get the OpenAL includes :p -//#include - #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 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];