Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
RemoteSpeaker + Manager
Browse files Browse the repository at this point in the history
robojumper committed Nov 6, 2024
1 parent 888d6b7 commit 58fdbe5
Showing 7 changed files with 465 additions and 21 deletions.
2 changes: 2 additions & 0 deletions config/SOUE01/splits.txt
Original file line number Diff line number Diff line change
@@ -1571,6 +1571,8 @@ nw4r/snd/snd_RemoteSpeaker.cpp:

nw4r/snd/snd_RemoteSpeakerManager.cpp:
.text start:0x80470C90 end:0x80470ED8
.sbss start:0x805766A0 end:0x805766A8
.bss start:0x80659410 end:0x806596E8

nw4r/snd/snd_SeqFile.cpp:
.text start:0x80470EE0 end:0x80471018
10 changes: 5 additions & 5 deletions config/SOUE01/symbols.txt
Original file line number Diff line number Diff line change
@@ -21750,9 +21750,9 @@ fn_8039DBF0 = .text:0x8039DBF0; // type:function size:0x4
fn_8039DC00 = .text:0x8039DC00; // type:function size:0xEC
fn_8039DCF0 = .text:0x8039DCF0; // type:function size:0x1F8
AXRegisterCallback = .text:0x8039DEF0; // type:function size:0x44
fn_8039DF40 = .text:0x8039DF40; // type:function size:0x2C
fn_8039DF70 = .text:0x8039DF70; // type:function size:0xC4
fn_8039E040 = .text:0x8039E040; // type:function size:0x58
AXRmtGetSamplesLeft = .text:0x8039DF40; // type:function size:0x2C
AXRmtGetSamples = .text:0x8039DF70; // type:function size:0xC4
AXRmtAdvancePtr = .text:0x8039E040; // type:function size:0x58
fn_8039E0A0 = .text:0x8039E0A0; // type:function size:0xC
fn_8039E0B0 = .text:0x8039E0B0; // type:function size:0x6C
fn_8039E120 = .text:0x8039E120; // type:function size:0x6C
@@ -40952,7 +40952,7 @@ typeInfo__Q44nw4r3snd6detail10BasicSound = .sbss:0x80576678; // type:object size
lbl_80576690 = .sbss:0x80576690; // type:object size:0x8 data:byte
lbl_80576698 = .sbss:0x80576698; // type:object size:0x4 data:4byte
lbl_8057669C = .sbss:0x8057669C; // type:object size:0x1 data:byte
lbl_805766A0 = .sbss:0x805766A0; // type:object size:0x8 data:byte
@GUARD@GetInstance__Q44nw4r3snd6detail20RemoteSpeakerManagerFv@instance = .sbss:0x805766A0; // type:object size:0x1 data:byte
lbl_805766A8 = .sbss:0x805766A8; // type:object size:0x8 data:4byte
@GUARD@detail_SortPriorityList__Q34nw4r3snd11SoundPlayerFv@listsByPrio = .sbss:0x805766B0; // type:object size:0x1 data:byte
sInitialized__29@unnamed@snd_SoundSystem_cpp@ = .sbss:0x805766B8; // type:object size:0x1 data:byte
@@ -49428,7 +49428,7 @@ lbl_806593C8 = .bss:0x806593C8; // type:object size:0xC
@LOCAL@GetInstance__Q44nw4r3snd6detail14ChannelManagerFv@instance = .bss:0x806593D8; // type:object size:0x20 data:4byte
lbl_806593F8 = .bss:0x806593F8; // type:object size:0xC
@LOCAL@GetInstance__Q44nw4r3snd6detail22DisposeCallbackManagerFv@instance = .bss:0x80659404; // type:object size:0xC data:4byte
lbl_80659410 = .bss:0x80659410; // type:object size:0x2D8 data:byte
@LOCAL@GetInstance__Q44nw4r3snd6detail20RemoteSpeakerManagerFv@instance = .bss:0x80659410; // type:object size:0x2D8 data:byte
mGlobalVariable__Q44nw4r3snd6detail9SeqPlayer = .bss:0x806596E8; // type:object size:0x20 data:2byte
lbl_80659708 = .bss:0x80659708; // type:object size:0x18
lbl_80659720 = .bss:0x80659720; // type:object size:0xC
4 changes: 2 additions & 2 deletions configure.py
Original file line number Diff line number Diff line change
@@ -732,8 +732,8 @@ def nw4rLib(lib_name, objects, extra_cflags=[], mw_version="Wii/1.3"):
Object(Matching, "nw4r/snd/snd_MmlSeqTrackAllocator.cpp"),
Object(NonMatching, "nw4r/snd/snd_NandSoundArchive.cpp"),
Object(Matching, "nw4r/snd/snd_PlayerHeap.cpp"),
Object(NonMatching, "nw4r/snd/snd_RemoteSpeaker.cpp"),
Object(NonMatching, "nw4r/snd/snd_RemoteSpeakerManager.cpp"),
Object(Matching, "nw4r/snd/snd_RemoteSpeaker.cpp"),
Object(Matching, "nw4r/snd/snd_RemoteSpeakerManager.cpp"),
Object(NonMatching, "nw4r/snd/snd_SeqFile.cpp"),
Object(Matching, "nw4r/snd/snd_SeqPlayer.cpp"),
Object(NonMatching, "nw4r/snd/snd_SeqSound.cpp"),
19 changes: 8 additions & 11 deletions include/nw4r/snd/snd_RemoteSpeaker.h
Original file line number Diff line number Diff line change
@@ -76,17 +76,14 @@ class RemoteSpeaker {
bool mFirstEncodeFlag; // at 0x3
bool mValidCallbackFlag; // at 0x4
bool mCommandBusyFlag; // at 0x5
bool mForceResumeFlag; // at 0x6
bool mContinueFlag; // at 0x7
// TODO commenting out a random flag to make eggAudioRmtSpeakerMgr match
// TODO offsets are wrong as a result
// volatile bool mIntervalFlag; // at 0x8
SpeakerState mState; // at 0xC
SpeakerCommand mUserCommand; // at 0x10
SpeakerCommand mInternalCommand; // at 0x14
WENCInfo mEncodeInfo; // at 0x18
int mChannelIndex; // at 0x38
WPADCallback mWpadCallback; // at 0x3C
bool mContinueFlag; // at 0x6
volatile bool mIntervalFlag; // at 0x7
SpeakerState mState; // at 0x8
SpeakerCommand mUserCommand; // at 0xC
SpeakerCommand mInternalCommand; // at 0x10
WENCInfo mEncodeInfo; // at 0x14
int mChannelIndex; // at 0x34
WPADCallback *mWpadCallback; // at 0x38
OSAlarm mContinueAlarm; // at 0x40
OSAlarm mIntervalAlarm; // at 0x70
s64 mContinueBeginTime; // at 0xA0
6 changes: 3 additions & 3 deletions include/rvl/WPAD/WPAD.h
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ enum WPADResult_et {

WPAD_ERR_NO_CONTROLLER = -1, /* name known from asserts */
WPAD_ERR_COMMUNICATION_ERROR = -2, // [RT3P54] has this as WPAD_ERR_BUSY
WPAD_ERR_3 = -3, // [RT3P54] has this as WPAD_ERR_TRANSFER
WPAD_ERR_TRANSFER = -3, // [RT3P54] has this as WPAD_ERR_TRANSFER
WPAD_ERR_INVALID = -4, /* name comes from [R89JEL] */
// WPAD_ERR_5 = -5, /* unknown */
// WPAD_ERR_6 = -6, /* unknown */
@@ -260,8 +260,8 @@ enum WPADMotorCommand_et {
// WPADControlSpeaker
typedef u32 WPADSpeakerCommand;
enum WPADSpeakerCommand_et {
WPAD_SPEAKER_DISABLE = 0,
WPAD_SPEAKER_ENABLE = 1, // might be ON? see HBMRemoteSpk.cpp
WPAD_SPEAKER_OFF = 0,
WPAD_SPEAKER_ON = 1,
WPAD_SPEAKER_MUTE = 2,
WPAD_SPEAKER_UNMUTE = 3,
WPAD_SPEAKER_PLAY = 4, // figured out from HBM usage
372 changes: 372 additions & 0 deletions src/nw4r/snd/snd_RemoteSpeaker.cpp
Original file line number Diff line number Diff line change
@@ -1 +1,373 @@
#include "nw4r/snd/snd_RemoteSpeaker.h"
#include "nw4r/snd/snd_RemoteSpeakerManager.h"
#include "nw4r/ut.h"
#include <string.h>

namespace nw4r {
namespace snd {

RemoteSpeaker::RemoteSpeaker()
: mInitFlag(false),
mPlayFlag(false),
mEnableFlag(false),
mFirstEncodeFlag(false),
mValidCallbackFlag(false),
mCommandBusyFlag(false),
mState(STATE_INVALID),
mUserCommand(COMMAND_NONE),
mInternalCommand(COMMAND_NONE),
mWpadCallback(NULL) {

OSCreateAlarm(&mContinueAlarm);
OSSetAlarmUserData(&mContinueAlarm, this);

OSCreateAlarm(&mIntervalAlarm);
OSSetAlarmUserData(&mIntervalAlarm, this);
}

void RemoteSpeaker::InitParam() {
ClearParam();

mContinueFlag = false;
mPlayFlag = false;
mEnableFlag = true;
mIntervalFlag = false;
}

void RemoteSpeaker::ClearParam() {
mPlayFlag = false;
mEnableFlag = false;

OSCancelAlarm(&mContinueAlarm);
mContinueFlag = false;

OSCancelAlarm(&mIntervalAlarm);
mIntervalFlag = false;
}

bool RemoteSpeaker::Setup(WPADCallback pCallback) {
ut::AutoInterruptLock lock;

InitParam();

if (mWpadCallback != NULL) {
mWpadCallback(mChannelIndex, WPAD_ERR_OK);
mValidCallbackFlag = false;
}

mUserCommand = COMMAND_SPEAKER_ON;
mWpadCallback = pCallback;
mInitFlag = true;

return true;
}

void RemoteSpeaker::Shutdown(WPADCallback pCallback) {
ut::AutoInterruptLock lock;

ClearParam();

if (mWpadCallback != NULL) {
mWpadCallback(mChannelIndex, WPAD_ERR_OK);
mValidCallbackFlag = false;
}

mUserCommand = COMMAND_SPEAKER_OFF;
mWpadCallback = pCallback;
mInitFlag = false;
}

bool RemoteSpeaker::EnableOutput(bool enable) {
if (!mInitFlag) {
return false;
}

mEnableFlag = enable;
return true;
}

bool RemoteSpeaker::IsEnabledOutput() const {
if (!mInitFlag) {
return false;
}

return mEnableFlag;
}

void RemoteSpeaker::Update() {
if (mCommandBusyFlag) {
return;
}

SpeakerCommand command =
mUserCommand != COMMAND_NONE ? mUserCommand : mInternalCommand;

mUserCommand = COMMAND_NONE;
mInternalCommand = COMMAND_NONE;

ExecCommand(command);
}

void RemoteSpeaker::ExecCommand(SpeakerCommand command) {
switch (command) {
case COMMAND_NONE: {
break;
}

case COMMAND_SPEAKER_ON: {
mValidCallbackFlag = true;
mCommandBusyFlag = true;
mState = STATE_EXEC_SPEAKER_ON;
WPADControlSpeaker(mChannelIndex, WPAD_SPEAKER_ON, SpeakerOnCallback);
break;
}

case COMMAND_SPEAKER_PLAY: {
mValidCallbackFlag = true;
mCommandBusyFlag = true;
mState = STATE_EXEC_SPEAKER_PLAY;
WPADControlSpeaker(mChannelIndex, WPAD_SPEAKER_PLAY,
SpeakerPlayCallback);
break;
}

case COMMAND_SPEAKER_OFF: {
mValidCallbackFlag = true;
mCommandBusyFlag = true;
mState = STATE_EXEC_SPEAKER_OFF;
WPADControlSpeaker(mChannelIndex, WPAD_SPEAKER_OFF, SpeakerOffCallback);
break;
}
}
}

void RemoteSpeaker::UpdateStreamData(const s16* pRmtSamples) {
if (!IsAvailable()) {
return;
}

bool playFlag = true;
bool silentFlag = mEnableFlag ? IsAllSampleZero(pRmtSamples) : true;

if (silentFlag /*|| mForceResumeFlag*/) {
playFlag = false;
}

bool firstFlag = !mPlayFlag && playFlag;
bool lastFlag = mPlayFlag && !playFlag;

if (playFlag) {
ut::AutoInterruptLock lock;

if (!WPADCanSendStreamData(mChannelIndex)) {
return;
}

u32 wencMode = !mFirstEncodeFlag ? WENC_FLAG_USER_INFO : 0;
mFirstEncodeFlag = false;

u8 adpcmBuffer[SAMPLES_PER_ENCODED_PACKET];
WENCGetEncodeData(&mEncodeInfo, wencMode, pRmtSamples,
SAMPLES_PER_AUDIO_PACKET, adpcmBuffer);

s32 result = WPADSendStreamData(mChannelIndex, adpcmBuffer,
SAMPLES_PER_ENCODED_PACKET);
if (result != WPAD_ERR_OK) {
mInternalCommand = COMMAND_SPEAKER_ON;
mState = STATE_INVALID;
InitParam();

return;
}
}

if (firstFlag) {
ut::AutoInterruptLock lock;

if (!mContinueFlag) {
OSSetAlarm(&mContinueAlarm,
OS_SEC_TO_TICKS(CONTINUOUS_PLAY_INTERVAL_MINUTES * 60LL),
ContinueAlarmHandler);

mContinueBeginTime = OSGetTime();
mContinueFlag = true;
}

OSCancelAlarm(&mIntervalAlarm);
mIntervalFlag = false;
}

if (lastFlag) {
ut::AutoInterruptLock lock;

mIntervalFlag = true;
OSCancelAlarm(&mIntervalAlarm);
OSSetAlarm(&mIntervalAlarm, OS_SEC_TO_TICKS(1LL), IntervalAlarmHandler);
}

mPlayFlag = playFlag;
}

bool RemoteSpeaker::IsAllSampleZero(const s16* pSample) {
const u32* pBuffer = reinterpret_cast<const u32*>(pSample);
bool zeroFlag = true;

for (int i = 0; i < SAMPLES_PER_ENCODED_PACKET; i++) {
if (pBuffer[i] != 0) {
zeroFlag = false;
break;
}
}

return zeroFlag;
}

void RemoteSpeaker::SpeakerOnCallback(s32 chan, s32 result) {
RemoteSpeaker& r =
detail::RemoteSpeakerManager::GetInstance().GetRemoteSpeaker(chan);

switch (result) {
case WPAD_ERR_OK: {
r.mFirstEncodeFlag = true;
memset(&r.mEncodeInfo, 0, sizeof(WENCInfo));

r.mState = STATE_SPEAKER_ON;
r.mInternalCommand = COMMAND_SPEAKER_PLAY;
break;
}

case WPAD_ERR_COMMUNICATION_ERROR: {
r.mInternalCommand = COMMAND_SPEAKER_ON;
break;
}

case WPAD_ERR_TRANSFER: {
r.mState = STATE_INVALID;
break;
}

case WPAD_ERR_NO_CONTROLLER: {
r.mState = STATE_INVALID;
break;
}

default: {
r.mState = STATE_INVALID;
break;
}
}

if (result != WPAD_ERR_OK && result != WPAD_ERR_COMMUNICATION_ERROR) {
r.NotifyCallback(chan, result);
}

r.mCommandBusyFlag = false;
}

void RemoteSpeaker::SpeakerPlayCallback(s32 chan, s32 result) {
RemoteSpeaker& r =
detail::RemoteSpeakerManager::GetInstance().GetRemoteSpeaker(chan);

switch (result) {
case WPAD_ERR_OK: {
r.mState = STATE_SPEAKER_PLAY;
break;
}

case WPAD_ERR_COMMUNICATION_ERROR: {
r.mInternalCommand = COMMAND_SPEAKER_PLAY;
break;
}

case WPAD_ERR_TRANSFER: {
r.mState = STATE_INVALID;
break;
}

case WPAD_ERR_NO_CONTROLLER: {
r.mState = STATE_INVALID;
break;
}

default: {
r.mState = STATE_INVALID;
break;
}
}

if (result != WPAD_ERR_COMMUNICATION_ERROR) {
r.NotifyCallback(chan, result);
}

r.mCommandBusyFlag = false;
}

void RemoteSpeaker::SpeakerOffCallback(s32 chan, s32 result) {
RemoteSpeaker& r =
detail::RemoteSpeakerManager::GetInstance().GetRemoteSpeaker(chan);

switch (result) {
case WPAD_ERR_OK: {
r.mState = STATE_SPEAKER_OFF;
break;
}

case WPAD_ERR_COMMUNICATION_ERROR: {
r.mInternalCommand = COMMAND_SPEAKER_OFF;
break;
}

case WPAD_ERR_TRANSFER: {
r.mState = STATE_INVALID;
break;
}

case WPAD_ERR_NO_CONTROLLER: {
r.mState = STATE_INVALID;
break;
}

default: {
r.mState = STATE_INVALID;
break;
}
}

if (result != WPAD_ERR_COMMUNICATION_ERROR) {
r.NotifyCallback(chan, result);
}

r.mCommandBusyFlag = false;
}

void RemoteSpeaker::NotifyCallback(s32 chan, s32 result) {
if (mValidCallbackFlag && mWpadCallback != NULL) {
mWpadCallback(chan, result);
mWpadCallback = NULL;
}
}

void RemoteSpeaker::ContinueAlarmHandler(OSAlarm* pAlarm, OSContext* pCtx) {
#pragma unused(pCtx)

ut::AutoInterruptLock lock;
RemoteSpeaker* p = static_cast<RemoteSpeaker*>(OSGetAlarmUserData(pAlarm));
}

void RemoteSpeaker::IntervalAlarmHandler(OSAlarm* pAlarm, OSContext* pCtx) {
#pragma unused(pCtx)

ut::AutoInterruptLock lock;
RemoteSpeaker* p = static_cast<RemoteSpeaker*>(OSGetAlarmUserData(pAlarm));

if (p->mIntervalFlag) {
OSCancelAlarm(&p->mContinueAlarm);
// p->mForceResumeFlag = false;
p->mContinueFlag = false;
}

p->mIntervalFlag = false;
}

} // namespace snd
} // namespace nw4r
73 changes: 73 additions & 0 deletions src/nw4r/snd/snd_RemoteSpeakerManager.cpp
Original file line number Diff line number Diff line change
@@ -1 +1,74 @@
#include "nw4r/snd/snd_RemoteSpeakerManager.h"
#include "rvl/AX.h"

namespace nw4r {
namespace snd {
namespace detail {

RemoteSpeakerManager& RemoteSpeakerManager::GetInstance() {
static RemoteSpeakerManager instance;
return instance;
}

RemoteSpeakerManager::RemoteSpeakerManager() : mInitialized(false) {
for (int i = 0; i < WPAD_MAX_CONTROLLERS; i++) {
mSpeaker[i].SetChannelIndex(i);
}
}

RemoteSpeaker& RemoteSpeakerManager::GetRemoteSpeaker(int i) {
return mSpeaker[i];
}

void RemoteSpeakerManager::Setup() {
if (mInitialized) {
return;
}

OSCreateAlarm(&mRemoteSpeakerAlarm);

OSSetPeriodicAlarm(&mRemoteSpeakerAlarm, OSGetTime(),
OS_NSEC_TO_TICKS(SPEAKER_ALARM_PERIOD_NSEC),
RemoteSpeakerAlarmProc);

mInitialized = true;
}

void RemoteSpeakerManager::Shutdown() {
if (!mInitialized) {
return;
}

OSCancelAlarm(&mRemoteSpeakerAlarm);
mInitialized = false;
}

void RemoteSpeakerManager::RemoteSpeakerAlarmProc(OSAlarm* pAlarm,
OSContext* pCtx) {
#pragma unused(pAlarm)
#pragma unused(pCtx)

RemoteSpeakerManager& r = GetInstance();

s16 samples[RemoteSpeaker::SAMPLES_PER_AUDIO_PACKET];
if (AXRmtGetSamplesLeft() < RemoteSpeaker::SAMPLES_PER_AUDIO_PACKET) {
return;
}

for (int i = 0; i < WPAD_MAX_CONTROLLERS; i++) {
if (r.mSpeaker[i].IsAvailable()) {
AXRmtGetSamples(i, samples,
RemoteSpeaker::SAMPLES_PER_AUDIO_PACKET);

r.mSpeaker[i].UpdateStreamData(samples);
}

r.mSpeaker[i].Update();
}

AXRmtAdvancePtr(RemoteSpeaker::SAMPLES_PER_AUDIO_PACKET);
}

} // namespace detail
} // namespace snd
} // namespace nw4r

0 comments on commit 58fdbe5

Please sign in to comment.