diff options
| author | Max Roncace <me@caseif.net> | 2026-02-20 05:53:27 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-02-20 02:53:27 -0800 |
| commit | 803bc041c7e228e2b7c88afd1121550e51db3f82 (patch) | |
| tree | 5462e8061bc8a8084db8ea2fc677a0fef5bb16d1 /src/Z2AudioCS | |
| parent | 0558bde1e61374f5a1b54453f07fe6cc15525bc1 (diff) | |
Implement Z2AudioCS (#3103)
Diffstat (limited to 'src/Z2AudioCS')
| -rw-r--r-- | src/Z2AudioCS/SpkData.cpp | 37 | ||||
| -rw-r--r-- | src/Z2AudioCS/SpkMixingBuffer.cpp | 51 | ||||
| -rw-r--r-- | src/Z2AudioCS/SpkSound.cpp | 450 | ||||
| -rw-r--r-- | src/Z2AudioCS/SpkSpeakerCtrl.cpp | 314 | ||||
| -rw-r--r-- | src/Z2AudioCS/SpkSystem.cpp | 111 | ||||
| -rw-r--r-- | src/Z2AudioCS/SpkTable.cpp | 44 | ||||
| -rw-r--r-- | src/Z2AudioCS/SpkWave.cpp | 83 | ||||
| -rw-r--r-- | src/Z2AudioCS/Z2AudioCS.cpp | 162 |
8 files changed, 1252 insertions, 0 deletions
diff --git a/src/Z2AudioCS/SpkData.cpp b/src/Z2AudioCS/SpkData.cpp new file mode 100644 index 0000000000..7f426bda78 --- /dev/null +++ b/src/Z2AudioCS/SpkData.cpp @@ -0,0 +1,37 @@ +#include "Z2AudioCS/SpkData.h" + +#include "JSystem/JUtility/JUTAssert.h" + +SpkData::SpkData(JKRArchive* resArc) { + mResArc = resArc; + JUT_ASSERT(21, resArc); +} + +void SpkData::loadTable(u16 chan) { + JUT_ASSERT(32, mResArc); + + void* res = mResArc->getResource(chan); + JUT_ASSERT(35, res); + + mTableMgr.setResource(res); +} + +void SpkData::loadWave(u16 chan) { + JUT_ASSERT(48, mResArc); + + void* res = mResArc->getResource(chan); + JUT_ASSERT(51, res); + + mWaveMgr.setResource(res); +} + +BOOL SpkData::isValid(void) const { + return mTableMgr.isValid() && mWaveMgr.isValid(); +} + +static void dummy(SpkWave* wave, SpkTable* table) { + if (wave->isValid() && table->isValid()) { + table->getParams(0); + table->getNumOfSound(); + } +} diff --git a/src/Z2AudioCS/SpkMixingBuffer.cpp b/src/Z2AudioCS/SpkMixingBuffer.cpp new file mode 100644 index 0000000000..3118f07f94 --- /dev/null +++ b/src/Z2AudioCS/SpkMixingBuffer.cpp @@ -0,0 +1,51 @@ +#include "Z2AudioCS/SpkMixingBuffer.h" + +#include "Z2AudioCS/SpkSound.h" +#include "JSystem/JAudio2/JASCalc.h" +#include "JSystem/JAudio2/JASGadget.h" +#include "JSystem/JAudio2/JASHeapCtrl.h" + +SpkMixingBuffer::SpkMixingBuffer(JKRHeap* heap) { + JUT_ASSERT(25, heap); + for (s32 chan = 0; chan < ARRAY_SIZE(mBuffer); chan++) { + mBuffer[chan] = new (heap, 0) s16[cSamplesPerAudioPacket]; + JUT_ASSERT(29, mBuffer[chan]); + bzeroBuffer(chan); + } +} + +void SpkMixingBuffer::mix(s32 chan, s16* src, s32 len, f32 weight, + s32 offset) { + JUT_ASSERT(61, chan < 4); + JUT_ASSERT(62, mBuffer[chan]); + JUT_ASSERT(63, src); + JUT_ASSERT(64, offset >= 0); + JUT_ASSERT(65, (offset+len) <= cSamplesPerAudioPacket); + + for (s32 i = 0; i < len; i++) { + s32 sample = mBuffer[chan][i + offset]; + s16 srcSample = src[i]; + sample += (s32)(srcSample * weight); + mBuffer[chan][i + offset] = JASCalc::clamp<s16, s32>(sample); + } +} + +s16* SpkMixingBuffer::getSamples(s32 chan) const { + JUT_ASSERT(97, chan < 4); + JUT_ASSERT(98, mBuffer[chan]); + return mBuffer[chan]; +} + +bool SpkMixingBuffer::update(s32 chan) { + bzeroBuffer(chan); + SpkSoundHolder* sound_holder = JASGlobalInstance<SpkSoundHolder>::getInstance(); + JUT_ASSERT(121, sound_holder); + bool result = sound_holder->update(chan); + return result; +} + +void SpkMixingBuffer::bzeroBuffer(s32 chan) { + JUT_ASSERT(143, chan < 4); + JUT_ASSERT(144, mBuffer[chan]); + JASCalc::bzero(mBuffer[chan], cSamplesPerAudioPacket * sizeof(s16)); +} diff --git a/src/Z2AudioCS/SpkSound.cpp b/src/Z2AudioCS/SpkSound.cpp new file mode 100644 index 0000000000..04467f1919 --- /dev/null +++ b/src/Z2AudioCS/SpkSound.cpp @@ -0,0 +1,450 @@ +#include "Z2AudioCS/SpkSound.h" + +#include "Z2AudioCS/SpkSpeakerCtrl.h" +#include "Z2AudioCS/SpkSystem.h" +#include "JSystem/JAudio2/JASCriticalSection.h" +#include "JSystem/JAudio2/JASHeapCtrl.h" + +#define SPK_SOUND_MIX_STEP 40 + +enum SpkSoundState { + SpkSoundState_STARTING_e, + SpkSoundState_LOCKED_e, + SpkSoundState_UNLOCKED_e, + SpkSoundState_STOPPING_e, + SpkSoundState_DEAD_e, +}; + +void SpkSoundHandle::releaseSound() { + if (!mSound) { + return; + } + + mSound->mHandle = NULL; + mSound = NULL; +} + +SpkSoundVolume::SpkSoundVolume() { + field_0x00 = 1.0f; + field_0x04 = 0.0f; + field_0x08 = 1.0f; + field_0x0c = 0.0f; + field_0x10 = 1.0f; + field_0x14 = 1.0f; + field_0x18 = 0.0f; + mTableVolume = 1.0f; +} + +void SpkSoundVolume::setRelease(s32 release) { + if (release > 0) { + field_0x04 = 1.0f / release; + } else { + field_0x04 = 1.0f; + } + + field_0x00 = 1.0f; +} + +void SpkSoundVolume::setFadeOut(s32 fadeOut) { + JASCriticalSection cs; + + if (fadeOut > 0) { + field_0x0c = 1.0f / fadeOut; + } else { + field_0x0c = 1.0f; + } + + field_0x08 = 1.0f; +} + +f32 SpkSoundVolume::calc(bool& param_0) { + param_0 = false; + + if (field_0x04 != 0.0f) { + field_0x00 -= field_0x04; + if (field_0x00 <= 0.0f) { + field_0x00 = 0.0f; + field_0x04 = 0.0f; + param_0 = true; + } + } + + if (field_0x0c != 0.0f) { + field_0x08 -= field_0x0c; + if (field_0x08 <= 0.0f) { + field_0x08 = 0.0f; + field_0x0c = 0.0f; + param_0 = true; + } + } + + if (field_0x18 != 0.0f) { + field_0x10 += field_0x18; + if (field_0x18 >= 0.0f) { + if (field_0x10 >= field_0x14) { + field_0x10 = field_0x14; + field_0x18 = 0.0f; + } + } else if (field_0x10 <= field_0x14) { + field_0x10 = field_0x14; + field_0x18 = 0.0f; + } + } + + f32 result = mTableVolume * (field_0x10 * (field_0x08 * (field_0x00 * field_0x00))); + return result; +} + +void SpkSoundVolume::setTableVolume(f32 vol) { + mTableVolume = vol; +} + +SpkSound::SpkSound() : JSULink<SpkSound>(this), + mHandle(NULL), mSoundNum(-1), mWaveData(0), mCurPos(0), + field_0x20(0), mPriority(100), field_0x28(0), mWaveSize(0), + mWaveLoopStart(-1), mWaveLoopEnd(-1), mState(SpkSoundState_STARTING_e), + mLifeTime(-1) { +} + +SpkSound::~SpkSound() { + releaseHandle(); +} + +void SpkSound::update(f32 param_0) { + if (!((SpkSoundState)mState != SpkSoundState_UNLOCKED_e && + (SpkSoundState)mState != SpkSoundState_STOPPING_e)) { + SpkSystem* system = JASGlobalInstance<SpkSystem>::getInstance(); + JUT_ASSERT(227, system); + + SpkMixingBuffer* mixing_buffer = system->getMixingBuffer(); + JUT_ASSERT(230, mixing_buffer); + + bool calc_flag = false; + f32 weight = mVolume.calc(calc_flag); + if (calc_flag) { + mState = SpkSoundState_DEAD_e; + } + weight *= param_0; + + if (!isLoopWave()) { + s32 len = SPK_SOUND_MIX_STEP; + if (mCurPos + len >= mWaveSize) { + len = mWaveSize - mCurPos; + } + + mixing_buffer->mix(field_0x20, mWaveData + mCurPos, len, weight, 0); + + mCurPos += SPK_SOUND_MIX_STEP; + + if (mCurPos >= mWaveSize) { + mState = SpkSoundState_DEAD_e; + } + return; + } + s32 len = 0; + s32 processedBytes = 0; + s32 remainingBytes = SPK_SOUND_MIX_STEP; + if (mWaveLoopEnd - mCurPos >= SPK_SOUND_MIX_STEP) { + len = SPK_SOUND_MIX_STEP; + mixing_buffer->mix(field_0x20, mWaveData + mCurPos, len, weight, 0); + + mCurPos += SPK_SOUND_MIX_STEP; + + if (mCurPos >= mWaveLoopEnd) { + mCurPos = mWaveLoopStart; + } + } else { + while (remainingBytes > 0) { + len = mWaveLoopEnd - mCurPos; + if (len >= remainingBytes) { + len = remainingBytes; + } + remainingBytes -= len; + + mixing_buffer->mix(field_0x20, mWaveData + mCurPos, len, weight, + processedBytes); + + processedBytes += len; + mCurPos += len; + + if (mCurPos >= mWaveLoopEnd) { + mCurPos = mWaveLoopStart; + } + } + } + } +} + +void SpkSound::stop(s32 msec) { + mState = SpkSoundState_STOPPING_e; + s32 fade = convertMsecToFrames(msec); + + if (fade) { + mVolume.setFadeOut(fade); + } else { + startRelease(); + } +} + +void SpkSound::startRelease(void) { + mVolume.setRelease(field_0x28); +} + +void SpkSound::attachHandle(SpkSoundHandle* handle) { + JUT_ASSERT(338, handle); + if (isHandleAttached()) { + releaseHandle(); + } + + mHandle = handle; + mHandle->mSound = this; +} + +bool SpkSound::isHandleAttached(void) const { + return mHandle != NULL; +} + +void SpkSound::releaseHandle() { + if (!mHandle) { + return; + } + + mHandle->mSound = NULL; + mHandle = NULL; +} + +bool SpkSound::start(s32 param_0, s32 soundNum) { + field_0x20 = param_0; + + bool setResult = setWaveData(soundNum); + if (!setResult) { + return false; + } + + mState = SpkSoundState_LOCKED_e; + return true; +} + +void SpkSound::kill(void) { + mState = SpkSoundState_DEAD_e; +} + +bool SpkSound::isStopping(void) const { + return mState == SpkSoundState_STOPPING_e; +} + +bool SpkSound::isDead(void) const { + return mState == SpkSoundState_DEAD_e; +} + +bool SpkSound::isLocked(void) const { + return mState == SpkSoundState_LOCKED_e; +} + +void SpkSound::unlock() { + if (mState != SpkSoundState_LOCKED_e) { + return; + } + + mState = SpkSoundState_UNLOCKED_e; +} + +s32 SpkSound::getLifeTime(void) { + return mLifeTime; +} + +void SpkSound::setLifeTime(s32 lifeTime) { + mLifeTime = lifeTime; +} + +void SpkSound::updateLifeTime() { + mLifeTime--; +} + +s32 SpkSound::convertMsecToFrames(s32 msec) { + return 6 * msec / 40; +} + +inline bool SpkSound::isLoopWave(void) { + return mWaveLoopStart >= 0 && mWaveLoopEnd > mWaveLoopStart; +} + +bool SpkSound::setWaveData(s32 soundNum) { + SpkSystem* system = JASGlobalInstance<SpkSystem>::getInstance(); + JUT_ASSERT(432, system); + + SpkData* data = system->getData(); + JUT_ASSERT(435, data); + + if (data->isValid() == 0) { + JUT_WARN(438, "%s", "Speaker data is not valid\n"); + return false; + } + + SpkTable& table = data->getTableMgr(); + JUT_ASSERT(444, soundNum < table.getNumOfSound()); + + mSoundNum = soundNum; + s32 waveNum = table.getParams(soundNum)->mWaveNum; + mPriority = table.getParams(soundNum)->field_0x02; + mVolume.setTableVolume(table.getParams(soundNum)->mVolume / 127.0f); + field_0x28 = convertMsecToFrames(table.getParams(soundNum)->mMsec); + + SpkWave& wave = data->getWaveMgr(); + JUT_ASSERT(457, mSoundNum < wave.getNumOfWaves()); + mWaveData = wave.getWave(waveNum); + mCurPos = 0; + mWaveSize = wave.getWaveSize(waveNum) / 2; + mWaveLoopStart = wave.getLoopStartPos(waveNum); + mWaveLoopEnd = wave.getLoopEndPos(waveNum); + + JUT_ASSERT(466, mWaveLoopEnd <= mWaveSize); + + return true; +} + +SpkSoundHolder::SpkSoundHolder() : JASGlobalInstance(true) { + mMasterVolume = 1.0f; + mConfigVolume = 10; + + for (int i = 0; i < ARRAY_SIZE(mSoundVolumes); i++) { + mSoundVolumes[i] = 1.0f; + } +} + +bool SpkSoundHolder::startSound(s32 chan, s32 soundNum, SpkSoundHandle* handle) { + if (!SpkSpeakerCtrl::isEnable(chan)) { + return false; + } + + if (soundNum < 0) { + return false; + } + + if (handle != NULL) { + if (*handle) { + if ((*handle)->isLocked()) { + (*handle)->kill(); + } else { + (*handle)->stop(0); + } + } + } + + SpkSound* new_sound_p = new SpkSound(); + if (new_sound_p == NULL) { + JUT_WARN(520, "%s", "cannot new SpkSound\n"); + return false; + } + + if (handle != NULL) { + new_sound_p->attachHandle(handle); + } + + bool startResult = new_sound_p->start(chan, soundNum); + if (!startResult) { + JUT_WARN(532, "%s", "cannot start SpkSound\n"); + delete new_sound_p; + return false; + } + + { + JASCriticalSection cs; + appendSound(chan, new_sound_p); + } + + return true; +} + +void SpkSoundHolder::appendSound(s32 chan, SpkSound* sound) { + mSoundList[chan].append(sound); +} + +bool SpkSoundHolder::startLevelSound(s32 chan, s32 soundNum, SpkSoundHandle* handle) { + if (handle == NULL) { + JUT_WARN(558, "%s", "Spk : No Handle for Level Sound"); + return false; + } + + if (*handle) { + if (!(*handle)->isStopping() && !(*handle)->isDead()) { + (*handle)->setLifeTime(2); + } + return true; + } else { + bool startResult = startSound(chan, soundNum, handle); + if (!startResult) { + return false; + } + + if (*handle) { + (*handle)->setLifeTime(2); + return true; + } + + return false; + } +} + +void SpkSoundHolder::stopAll(s32 chan, s32 msec) { + JASCriticalSection cs; + + for (JSULink<SpkSound>* it = mSoundList[chan].getFirst(); it != NULL; it = it->getNext()) { + if (it->getObject() != NULL) { + it->getObject()->stop(msec); + } + } +} + +bool SpkSoundHolder::update(s32 chan) { + JASCriticalSection cs; + bool ret = updateEachSound(chan); + return ret; +} + +bool SpkSoundHolder::updateEachSound(s32 chan) { + bool retval = false; + + f32 volume = getMasterVolume() * getConfigVolumeF32(); + + for (JSULink<SpkSound>* it = mSoundList[chan].getFirst(); it != NULL; it = it->getNext()) { + it->getObject()->update(volume * mSoundVolumes[chan]); + retval = true; + } + + return retval; +} + +void SpkSoundHolder::freeDeadSound(s32 chan) { + JSULink<SpkSound>* it = mSoundList[chan].getFirst(); + while (it != NULL) { + JSULink<SpkSound>* next = it->getNext(); + if (it->getObject()->isDead()) { + mSoundList[chan].remove(it); + delete it->getObject(); + } + it = next; + } +} + +void SpkSoundHolder::framework(void) { + JASCriticalSection cs; + + for (int i = 0; i < ARRAY_SIZE(mSoundList); i++) { + for (JSULink<SpkSound>* it = mSoundList[i].getFirst(); it != NULL; it = it->getNext()) { + if (it->getObject() != NULL) { + if (it->getObject()->isLocked()) { + it->getObject()->unlock(); + } else if (it->getObject()->getLifeTime() >= 0) { + it->getObject()->updateLifeTime(); + if (it->getObject()->getLifeTime() <= 0) { + it->getObject()->stop(0); + it->getObject()->setLifeTime(-1); + } + } + } + } + + freeDeadSound(i); + } +} diff --git a/src/Z2AudioCS/SpkSpeakerCtrl.cpp b/src/Z2AudioCS/SpkSpeakerCtrl.cpp new file mode 100644 index 0000000000..112dfd3a2f --- /dev/null +++ b/src/Z2AudioCS/SpkSpeakerCtrl.cpp @@ -0,0 +1,314 @@ +#include "Z2AudioCS/SpkSpeakerCtrl.h" + +#include "Z2AudioCS/SpkMixingBuffer.h" +#include "Z2AudioCS/SpkSound.h" +#include "JSystem/JAudio2/JASCriticalSection.h" +#include <revolution/os.h> +#include <revolution/wpad.h> + +OSAlarm sSpeakerAlarm; +SpeakerInfo sSpeakerInfo[WPAD_MAX_CONTROLLERS]; +SpkSoundHandle sAdjustSoundHandle[WPAD_MAX_CONTROLLERS]; +SpkMixingBuffer* sMixingBuffer; + +#if VERSION == VERSION_WII_USA_R0 +#define SPKSPEAKERCTRL_SET_STATE(s) (void)0 +#else +#define SPKSPEAKERCTRL_SET_STATE(s) mState = s +#endif + +void SpkSpeakerCtrl::setMixingBuffer(SpkMixingBuffer* pMixingBuffer) { + JASCriticalSection cs; + + sMixingBuffer = pMixingBuffer; +} + +void SpkSpeakerCtrl::setup(void) { + for (s32 i = 0; i < WPAD_MAX_CONTROLLERS; i++) { + sSpeakerInfo[i].mIsConnected = false; + sSpeakerInfo[i].mIsPlaying = false; + sSpeakerInfo[i].field_0x22 = true; + sSpeakerInfo[i].mIsMuted = false; +#if VERSION != VERSION_WII_USA_R0 + sSpeakerInfo[i].mState = 0; +#endif + sSpeakerInfo[i].mVolume = 64; + sSpeakerInfo[i].mRadioSensitivityTimer = 0; + sSpeakerInfo[i].mExtensionTimer = 0; + memset(sSpeakerInfo[i].mEncInfo.data, 0, sizeof(sSpeakerInfo[i].mEncInfo)); + } + + OSCreateAlarm(&sSpeakerAlarm); + OSSetPeriodicAlarm(&sSpeakerAlarm, OSGetTime(), OSNanosecondsToTicks(6666667), updateSpeaker); +} + +void SpkSpeakerCtrl::connect(s32 chan) { + JASCriticalSection cs; + + sSpeakerInfo[chan].mIsConnected = true; + sSpeakerInfo[chan].mIsPlaying = false; +#if VERSION != VERSION_WII_USA_R0 + sSpeakerInfo[chan].mState = 0; +#endif + setSpeakerOn(chan); +} + +void SpkSpeakerCtrl::disconnect(s32 chan) { + JASCriticalSection cs; + + sSpeakerInfo[chan].mIsConnected = false; + sSpeakerInfo[chan].mIsPlaying = false; +#if VERSION != VERSION_WII_USA_R0 + sSpeakerInfo[chan].mState = 0; +#endif + setSpeakerOff(chan); +} + +void SpkSpeakerCtrl::setSpeakerOn(s32 chan) { +#if VERSION != VERSION_WII_USA_R0 + JASCriticalSection cs; +#endif + + s32 val = WPADControlSpeaker(chan, 1, setSpeakerOnCallback); + +#if VERSION != VERSION_WII_USA_R0 + if (val == -2) { + sSpeakerInfo[chan].mState = 1; + } else { + sSpeakerInfo[chan].mState = 0; + } +#endif +} + +void SpkSpeakerCtrl::setSpeakerOnCallback(s32 chan, s32 param_1) { +#if VERSION == VERSION_WII_USA_R0 + if (param_1 == 0) { + setSpeakerPlay(chan); + } +#else + JASCriticalSection cs; + + if (param_1 == 0) { + sSpeakerInfo[chan].mState = 0; + setSpeakerPlay(chan); + } else { + if (param_1 == -3) { + sSpeakerInfo[chan].mState = 1; + } + } +#endif +} + +void SpkSpeakerCtrl::setSpeakerPlay(s32 chan) { +#if VERSION != VERSION_WII_USA_R0 + JASCriticalSection cs; +#endif + + s32 val = WPADControlSpeaker(chan, 4, startPlayCallback); + +#if VERSION != VERSION_WII_USA_R0 + if (val == -2) { + sSpeakerInfo[chan].mState = 2; + } else { + sSpeakerInfo[chan].mState = 0; + } +#endif +} + +void SpkSpeakerCtrl::startPlayCallback(s32 chan, s32 param_1) { +#if VERSION != VERSION_WII_USA_R0 + JASCriticalSection cs; +#endif + + if (param_1 == 0) { + sSpeakerInfo[chan].mIsPlaying = true; + sSpeakerInfo[chan].field_0x22 = true; +#if VERSION != VERSION_WII_USA_R0 + sSpeakerInfo[chan].mState = 0; +#endif + memset(&sSpeakerInfo[chan].mEncInfo, 0, 0x20); + } else if (param_1 == -3) { +#if VERSION != VERSION_WII_USA_R0 + sSpeakerInfo[chan].mState = 2; +#endif + } +} + +void SpkSpeakerCtrl::setSpeakerOff(s32 chan) { + sSpeakerInfo[chan].mIsPlaying = false; +#if VERSION != VERSION_WII_USA_R0 + sSpeakerInfo[chan].mState = 0; +#endif + WPADControlSpeaker(chan, 0, 0); +} + +#if VERSION != VERSION_WII_USA_R0 +void SpkSpeakerCtrl::retryConnection(s32 chan) { + switch (sSpeakerInfo[chan].mState) { + case 0: + case 3: + break; + case 1: + setSpeakerOn(chan); + break; + case 2: + setSpeakerPlay(chan); + break; + } +} +#endif + +void SpkSpeakerCtrl::framework() { + for (s32 i = 0; i < WPAD_MAX_CONTROLLERS; i++) { + retryConnection(i); + } +} + +void SpkSpeakerCtrl::updateSpeaker(OSAlarm*, OSContext*) { + for (s32 i = 0; i < WPAD_MAX_CONTROLLERS; i++) { + if (sMixingBuffer != NULL) { + BOOL isBusy = FALSE; + + if (!checkRadioSensitivity(i)) { + isBusy = TRUE; + } + + if (!updateExtensionProcess(i)) { + isBusy = TRUE; + } + + if (sSpeakerInfo[i].mIsMuted) { + continue; + } + + bool updateResult = sMixingBuffer->update(i); + if (isBusy) { + continue; + } + + if (!sSpeakerInfo[i].mIsPlaying) { + continue; + } + + if (updateResult) { + bool var_r28 = true; + + if (sSpeakerInfo[i].mIsPlaying && sMixingBuffer != NULL) { + if (sSpeakerInfo[i].field_0x22) { + var_r28 = false; + sSpeakerInfo[i].field_0x22 = false; + } + u8 data[24]; + WENCGetEncodeData(&sSpeakerInfo[i].mEncInfo, var_r28, + sMixingBuffer->getSamples(i), 0x28, data); + WPADSendStreamData(i, data, 0x14); + } + } else { + sSpeakerInfo[i].field_0x22 = true; + } + } + } +} + +bool SpkSpeakerCtrl::isEnable(s32 chan) { + return WPADIsSpeakerEnabled(chan) && + sSpeakerInfo[chan].mIsPlaying && + !isSubmitPlayByRadioSensitivity(chan) && + !isSubmitPlayByExtensionConnect(chan) && + sMixingBuffer != NULL; +} + +void SpkSpeakerCtrl::extensionProcess(s32 chan, s32 param_1) { + if (!sSpeakerInfo[chan].mIsConnected) { + return; + } + + sSpeakerInfo[chan].mExtensionTimer = 49; + sSpeakerInfo[chan].field_0x22 = true; + if (param_1 == 0xFF) { + sSpeakerInfo[chan].mExtensionTimer = 50; + } + + if (sSpeakerInfo[chan].mIsPlaying == 0) { + return; + } + + setSpeakerOff(chan); +} + +bool SpkSpeakerCtrl::updateExtensionProcess(s32 chan) { + if (sSpeakerInfo[chan].mIsConnected == 0) { + return false; + } + + if (sSpeakerInfo[chan].mExtensionTimer < 50) { + if (sSpeakerInfo[chan].mExtensionTimer > 0) { + if (sSpeakerInfo[chan].mExtensionTimer == 1 && !sSpeakerInfo[chan].mIsPlaying) { + setSpeakerOn(chan); + } + + sSpeakerInfo[chan].mExtensionTimer--; + } else { + sSpeakerInfo[chan].mExtensionTimer = 0; + } + } + + bool retval; + if (sSpeakerInfo[chan].mExtensionTimer == 0) { + retval = true; + } else { + retval = false; + } + return retval; +} + +bool SpkSpeakerCtrl::isSubmitPlayByExtensionConnect(s32 chan) { + if (sSpeakerInfo[chan].mExtensionTimer > 0) { + return true; + } else { + return false; + } +} + +bool SpkSpeakerCtrl::checkRadioSensitivity(s32 chan) { + if (sSpeakerInfo[chan].mIsConnected == 0) { + return false; + } + + if (WPADGetRadioSensitivity(chan) < 60) { + if (sSpeakerInfo[chan].mIsPlaying == 1) { + setSpeakerOff(chan); + } + + sSpeakerInfo[chan].mRadioSensitivityTimer = 200; + sSpeakerInfo[chan].field_0x22 = true; + } else { + if (sSpeakerInfo[chan].mRadioSensitivityTimer > 0) { + if (sSpeakerInfo[chan].mRadioSensitivityTimer == 1) { + if (!sSpeakerInfo[chan].mIsPlaying) { + setSpeakerOn(chan); + } + } + + sSpeakerInfo[chan].mRadioSensitivityTimer--; + } else { + sSpeakerInfo[chan].mRadioSensitivityTimer = 0; + } + } + + bool retval; + if (sSpeakerInfo[chan].mRadioSensitivityTimer == 0) { + retval = true; + } else { + retval = false; + } + return retval; +} + +bool SpkSpeakerCtrl::isSubmitPlayByRadioSensitivity(s32 chan) { + if (sSpeakerInfo[chan].mRadioSensitivityTimer > 0) { + return true; + } else { + return false; + } +} diff --git a/src/Z2AudioCS/SpkSystem.cpp b/src/Z2AudioCS/SpkSystem.cpp new file mode 100644 index 0000000000..9e245f7503 --- /dev/null +++ b/src/Z2AudioCS/SpkSystem.cpp @@ -0,0 +1,111 @@ +#include "Z2AudioCS/SpkSystem.h" + +#include "Z2AudioCS/SpkMixingBuffer.h" +#include "Z2AudioCS/SpkSound.h" +#include "Z2AudioCS/SpkSpeakerCtrl.h" +#include "JSystem/JAudio2/JASGadget.h" +#include "JSystem/JAudio2/JASHeapCtrl.h" +#include "JSystem/JKernel/JKRHeap.h" + +template<> SpkSystem* JASGlobalInstance<SpkSystem>::sInstance; +template<> SpkSoundHolder* JASGlobalInstance<SpkSoundHolder>::sInstance; + +const static s32 cConfigVolumeMax = 15; + +SpkSystem::SpkSystem(JKRHeap* heap) : JASGlobalInstance(true) { + mData = NULL; + + if (!heap) { + heap = JKRGetCurrentHeap(); + } + + mHeap = heap; + mMixingBuffer = new (heap, 0) SpkMixingBuffer(heap); + JUT_ASSERT(35, mMixingBuffer); + mSoundHolder = new (heap, 0) SpkSoundHolder(); + JUT_ASSERT(38, mSoundHolder); + SpkSpeakerCtrl::setup(); + SpkSpeakerCtrl::setMixingBuffer(mMixingBuffer); +} + +void SpkSystem::setResource(JKRArchive* resArc, u16 param_1, u16 param_2) { + JUT_ASSERT(71, mHeap); + JUT_ASSERT(72, resArc); + mData = new (mHeap, 0) SpkData(resArc); + JUT_ASSERT(75, mData); + mData->loadTable(param_1); + mData->loadWave(param_2); +} + +void SpkSystem::framework() { + JUT_ASSERT(89, mSoundHolder); +#if VERSION != VERSION_WII_USA_R0 + SpkSpeakerCtrl::framework(); +#endif + mSoundHolder->framework(); +} + +void SpkSystem::startSound(s32 chan, s32 param_1, SpkSoundHandle* handle) { + JUT_ASSERT(108, chan >= 0); + JUT_ASSERT(109, chan < 4); + JUT_ASSERT(110, mSoundHolder); + mSoundHolder->startSound(chan, param_1, handle); +} + +void SpkSystem::startLevelSound(s32 chan, s32 param_1, SpkSoundHandle* handle) { + JUT_ASSERT(128, chan >= 0); + JUT_ASSERT(129, chan < 4); + JUT_ASSERT(130, mSoundHolder); + JUT_ASSERT(131, handle); + mSoundHolder->startLevelSound(chan, param_1, handle); +} + +void SpkSystem::setMasterVolume(f32 vol) { + JUT_ASSERT(146, mSoundHolder); + JUT_ASSERT(147, vol >= 0.f); + JUT_ASSERT(148, vol <= 1.f); + mSoundHolder->setMasterVolume(vol); +} + +f32 SpkSystem::getMasterVolume(void) { + return mSoundHolder->getMasterVolume(); +} + +void SpkSystem::stopAll(s32 chan, s32 msec) { + JUT_ASSERT(269, mSoundHolder); + JUT_ASSERT(270, chan < 4); + JUT_ASSERT(271, msec >= 0); + + if (chan < 0) { + for (s32 i = 0; i < 4; i++) { + mSoundHolder->stopAll(i, msec); + } + } else { + mSoundHolder->stopAll(chan, msec); + } +} + +void SpkSystem::setConfigVolume(s32 vol) { + JUT_ASSERT(307, mSoundHolder); + JUT_ASSERT(308, vol >= 0); + JUT_ASSERT(309, vol <= cConfigVolumeMax); + + mSoundHolder->setConfigVolume(vol); +} + +void SpkSystem::newSoundMemPool(s32 numOfSound) { + JUT_ASSERT(351, numOfSound >= 0); + JASPoolAllocObject<SpkSound>::newMemPool(numOfSound); +} + +void SpkSystem::connect(s32 chan) { + SpkSpeakerCtrl::connect(chan); +} + +void SpkSystem::disconnect(s32 chan) { + SpkSpeakerCtrl::disconnect(chan); +} + +void SpkSystem::extensionProcess(s32 chan, s32 param_1) { + SpkSpeakerCtrl::extensionProcess(chan, param_1); +} diff --git a/src/Z2AudioCS/SpkTable.cpp b/src/Z2AudioCS/SpkTable.cpp new file mode 100644 index 0000000000..51e4041394 --- /dev/null +++ b/src/Z2AudioCS/SpkTable.cpp @@ -0,0 +1,44 @@ +#include "Z2AudioCS/SpkTable.h" + +SpkTable::SpkTable(void) { + mIsInitialized = false; + mNumOfSound = 0; + mEntryOffset = 0; + mDataOffsets = 0; +} + +struct SpkTableHeader { + s32 resourceCount; + s32 entryOff; + s32 dataOffsetsStartOff; + BOOL isDataOffsetsInitialized; +}; + +void SpkTable::setResource(void* res) { + mIsInitialized = false; + + s32* cursor = (s32*)res; + + s32 resourceCount = *cursor++; + s32 entryOff = *cursor++; + s32 dataOffsetsStartOff = *cursor++; + s32* pIsDataOffsetsInitialized = cursor; + BOOL isDataOffsetsInitialized = *cursor++; + + mNumOfSound = resourceCount; + + s32 entryOffset = (s32)res + entryOff; + mEntryOffset = entryOffset; + s32* dataOffsets = (s32*)((s32)res + dataOffsetsStartOff); + if (!isDataOffsetsInitialized) { + for (s32 i = 0; i < mNumOfSound; i++) { + dataOffsets[i] += (s32)res; + } + } + + s32* dataOffsetsCopy = dataOffsets; + mDataOffsets = dataOffsetsCopy; + *pIsDataOffsetsInitialized = TRUE; + + mIsInitialized = true; +} diff --git a/src/Z2AudioCS/SpkWave.cpp b/src/Z2AudioCS/SpkWave.cpp new file mode 100644 index 0000000000..98c8e81a81 --- /dev/null +++ b/src/Z2AudioCS/SpkWave.cpp @@ -0,0 +1,83 @@ +#include "Z2AudioCS/SpkWave.h" + +#include "JSystem/JAudio2/JASCriticalSection.h" +#include "JSystem/JUtility/JUTAssert.h" +#include <revolution/os.h> +#include <revolution/types.h> + +SpkWave::SpkWave(void) { + mWaveData = NULL; +} + +void SpkWave::setResource(void* res) { + JUT_ASSERT(30, res); + + JASCriticalSection cs; + + mWaveData = res; +} + +s32 SpkWave::getNumOfWaves(void) const { + if (mWaveData == NULL) { + return 0; + } + + return ((s32*)mWaveData)[1]; +} + +s32 SpkWave::getWaveSize(s32 num) const { + JUT_ASSERT(57, num >= 0); + if (!mWaveData) { + return 0; + } + JUT_ASSERT(60, num < getNumOfWaves()); + + WaveData* data = getWaveData(num); + JUT_ASSERT(63, data); + return data->size; +} + +u32 SpkWave::getLoopStartPos(s32 num) const { + JUT_ASSERT(76, num >= 0); + if (!mWaveData) { + return 0; + } + JUT_ASSERT(79, num < getNumOfWaves()); + + WaveData* data = getWaveData(num); + JUT_ASSERT(82, data); + return data->loopStartPos; +} + +u32 SpkWave::getLoopEndPos(s32 num) const { + JUT_ASSERT(95, num >= 0); + if (!mWaveData) { + return 0; + } + JUT_ASSERT(98, num < getNumOfWaves()); + + WaveData* data = getWaveData(num); + JUT_ASSERT(101, data); + return data->loopEndPos; +} + +s16* SpkWave::getWave(s32 num) const { + JUT_ASSERT(114, num >= 0); + if (!mWaveData) { + return 0; + } + JUT_ASSERT(117, num < getNumOfWaves()); + + WaveData* data = getWaveData(num); + JUT_ASSERT(120, data); + return data->wave; +} + +WaveData* SpkWave::getWaveData(s32 num) const { + JUT_ASSERT(138, num >= 0); + JUT_ASSERT(139, mWaveData); + JUT_ASSERT(140, num < getNumOfWaves()); + + WaveData* data = (WaveData*)((u32)mWaveData + *(u32*)((u32)mWaveData + num * 4 + 8)); + return data; +} diff --git a/src/Z2AudioCS/Z2AudioCS.cpp b/src/Z2AudioCS/Z2AudioCS.cpp new file mode 100644 index 0000000000..e619876537 --- /dev/null +++ b/src/Z2AudioCS/Z2AudioCS.cpp @@ -0,0 +1,162 @@ +#include "Z2AudioCS/Z2AudioCS.h" + +#include "Z2AudioCS/SpkSystem.h" +#include "JSystem/JKernel/JKRHeap.h" +#include <revolution/types.h> +#include <revolution/wpad.h> + +#define HANDLES_MAX 0x30 + +static SpkSoundHandle* sSpkHandles; + +static u8 l_spkVolume; + +void Z2AudioCS::newSpkSoundMemPool() { + SpkSystem::newSoundMemPool(HANDLES_MAX); +} + +int Z2AudioCS::init(JKRHeap* heap, JKRArchive* res, s32 param_2, s32 param_3) { + JUT_ASSERT(59, heap); + JUT_ASSERT(60, res); + SpkSystem* spkSys = new(heap, 0) SpkSystem(heap); + JUT_ASSERT(67, spkSys); + + sSpkHandles = new (heap, 0) SpkSoundHandle[HANDLES_MAX]; + JUT_ASSERT(71, sSpkHandles); + + spkSys->setResource(res, 2, 3); + spkSys->setMasterVolume(1.0f); + spkSys->setConfigVolume(15); +} + +void Z2AudioCS::update() { + if (JASGlobalInstance<SpkSystem>::getInstance() != NULL) { + JASGlobalInstance<SpkSystem>::getInstance()->framework(); + } +} + +void Z2AudioCS::connect(s32 chan) { + SpkSystem::connect(chan); + l_spkVolume = WPADGetSpeakerVolume(); +} + +void Z2AudioCS::disconnect(s32 chan) { + SpkSystem::disconnect(chan); +} + +void Z2AudioCS::extensionProcess(s32 chan, s32 param_1) { + SpkSystem::extensionProcess(chan, param_1); +} + +static SpkSoundHandle* getFreeSpkHandle(void) { + JUT_ASSERT(125, JASGlobalInstance<SpkSystem>::getInstance()); + JUT_ASSERT(126, sSpkHandles); + + SpkSoundHandle* highestPriorityHandle = NULL; + s32 highestPriority = 255; + for (s32 i = 0; i < HANDLES_MAX; i++) { + if (!sSpkHandles[i].isSoundAttached()) { + return &sSpkHandles[i]; + } + + if (sSpkHandles[i]->getPriority() < highestPriority) { + highestPriorityHandle = &sSpkHandles[i]; + highestPriority = sSpkHandles[i]->getPriority(); + } + } + + return highestPriorityHandle; +} + +SpkSoundHandle* Z2AudioCS::getHandleSoundID(s32 soundNum) { + JUT_ASSERT(145, JASGlobalInstance<SpkSystem>::getInstance()); + JUT_ASSERT(146, sSpkHandles); + + for (s32 i = 0; i < HANDLES_MAX; i++) { + if (!sSpkHandles[i].isSoundAttached()) { + continue; + } + + if (sSpkHandles[i]->getSoundNum() == soundNum) { + return &sSpkHandles[i]; + } + } + + return NULL; +} + +SpkSoundHandle* Z2AudioCS::start(s32 id, s32 chan) { + if (JASGlobalInstance<SpkSystem>::getInstance() == NULL) { + return NULL; + } + if (sSpkHandles == NULL) { + return NULL; + } + if (l_spkVolume == 0) { + return NULL; + } + + OS_REPORT("[Z2AudioCS::start] id:%d ch:%d\n", id, chan); + SpkSoundHandle* handle = getFreeSpkHandle(); + JUT_ASSERT(172, handle); + + JASGlobalInstance<SpkSystem>::getInstance()->startSound(chan, id, handle); + return handle; +} + +SpkSoundHandle* Z2AudioCS::startLevel(s32 id, s32 chan) { + if (JASGlobalInstance<SpkSystem>::getInstance() == NULL) { + return NULL; + } + if (sSpkHandles == NULL) { + return NULL; + } + if (l_spkVolume == 0) { + return NULL; + } + + OS_REPORT("[Z2AudioCS::startLevel] id:%d ch:%d\n", id, chan); + + SpkSoundHandle* handle = getHandleSoundID(id); + if (handle == NULL) { + handle = getFreeSpkHandle(); + } + JUT_ASSERT(191, handle); + + JASGlobalInstance<SpkSystem>::getInstance()->startLevelSound(chan, id, handle); + return handle; +} + +s32 Z2AudioCS::getName(s32 num) { + if (JASGlobalInstance<SpkSystem>::getInstance() == NULL) { + return 0; + } + if (JASGlobalInstance<SpkSystem>::getInstance()->getData() == NULL) { + return 0; + } + + return JASGlobalInstance<SpkSystem>::getInstance()->getData()->getTableMgr().getName(num); +} + +s32 Z2AudioCS::getNumOfSound(void) { + if (JASGlobalInstance<SpkSystem>::getInstance() == NULL) { + return 0; + } + if (JASGlobalInstance<SpkSystem>::getInstance()->getData() == NULL) { + return 0; + } + + return JASGlobalInstance<SpkSystem>::getInstance()->getData()->getTableMgr().getNumOfSound(); +} + +void Z2AudioCS::stopAll(s32 chan, s32 msec) { + if (JASGlobalInstance<SpkSystem>::getInstance() == NULL) { + return; + } + + JASGlobalInstance<SpkSystem>::getInstance()->stopAll(chan, msec); +} + +void Z2AudioCS::stop(s32 chan) { + stopAll(chan, 0); +} |
