mirror of
https://github.com/zeldaret/ss
synced 2026-05-25 15:25:13 -04:00
363 lines
8.2 KiB
C++
363 lines
8.2 KiB
C++
#include "nw4r/snd/snd_SeqSound.h"
|
|
|
|
/* Original source:
|
|
* kiwi515/ogws
|
|
* src/nw4r/snd/snd_SeqSound.cpp
|
|
*/
|
|
|
|
/*******************************************************************************
|
|
* headers
|
|
*/
|
|
|
|
#include <decomp.h>
|
|
#include "common.h"
|
|
|
|
#include "nw4r/snd/snd_BasicSound.h"
|
|
#include "nw4r/snd/snd_PlayerHeap.h"
|
|
#include "nw4r/snd/snd_SeqFile.h"
|
|
#include "nw4r/snd/snd_SeqPlayer.h"
|
|
#include "nw4r/snd/snd_SeqSoundHandle.h"
|
|
#include "nw4r/snd/snd_SeqTrack.h"
|
|
#include "nw4r/snd/snd_SoundInstanceManager.h"
|
|
#include "nw4r/snd/snd_TaskManager.h"
|
|
|
|
#include "nw4r/ut/ut_FileStream.h"
|
|
#include "nw4r/ut/ut_RuntimeTypeInfo.h"
|
|
|
|
#include <rvl/DVD/dvd.h> // DVD_ECANCELED
|
|
|
|
#include "nw4r/NW4RAssert.hpp"
|
|
|
|
/*******************************************************************************
|
|
* types
|
|
*/
|
|
|
|
// forward declarations
|
|
namespace nw4r { namespace snd { namespace detail { class NoteOnCallback; }}}
|
|
namespace nw4r { namespace snd { namespace detail { class SeqTrackAllocator; }}}
|
|
|
|
/*******************************************************************************
|
|
* variables
|
|
*/
|
|
|
|
namespace nw4r { namespace snd { namespace detail
|
|
{
|
|
ut::detail::RuntimeTypeInfo const SeqSound::typeInfo(&BasicSound::typeInfo);
|
|
}}} // namespace nw4r::snd::detail
|
|
|
|
/*******************************************************************************
|
|
* functions
|
|
*/
|
|
|
|
namespace nw4r { namespace snd { namespace detail {
|
|
|
|
#pragma push
|
|
|
|
// TODO: fake
|
|
|
|
SeqSound::SeqSound(SoundInstanceManager<SeqSound> *manager, int priority,
|
|
int ambientPriority) :
|
|
#if 1
|
|
BasicSound (priority, ambientPriority),
|
|
mTempSpecialHandle (
|
|
reinterpret_cast<SeqSoundHandle *>(mPreparedFlag = mLoadingFlag = 0)),
|
|
mManager (manager),
|
|
mStartOffset (0),
|
|
mFileStream (nullptr)
|
|
#else
|
|
BasicSound (priority, ambientPriority),
|
|
mTempSpecialHandle (nullptr),
|
|
mManager (manager),
|
|
mStartOffset (0),
|
|
mLoadingFlag (false),
|
|
mPreparedFlag (false),
|
|
mFileStream (nullptr)
|
|
#endif
|
|
{
|
|
}
|
|
|
|
#pragma pop
|
|
|
|
void SeqSound::InitParam()
|
|
{
|
|
BasicSound::InitParam();
|
|
|
|
mStartOffset = 0;
|
|
}
|
|
|
|
SeqPlayer::SetupResult SeqSound::Setup(SeqTrackAllocator *trackAllocator,
|
|
u32 allocTracks,
|
|
NoteOnCallback *callback)
|
|
{
|
|
NW4RAssertPointerNonnull_Line(95, callback);
|
|
|
|
InitParam();
|
|
|
|
return mSeqPlayer.Setup(trackAllocator, allocTracks, GetVoiceOutCount(),
|
|
callback);
|
|
}
|
|
|
|
void SeqSound::Prepare(void const *seqBase, s32 seqOffset,
|
|
SeqPlayer::OffsetType startOffsetType, int startOffset)
|
|
{
|
|
NW4RAssertPointerNonnull_Line(124, seqBase);
|
|
|
|
mSeqPlayer.SetSeqData(seqBase, seqOffset);
|
|
|
|
if (startOffset > 0)
|
|
Skip(startOffsetType, startOffset);
|
|
|
|
mPreparedFlag = true;
|
|
}
|
|
|
|
void SeqSound::Prepare(ut::FileStream *fileStream, s32 seqOffset,
|
|
SeqPlayer::OffsetType startOffsetType, int startOffset)
|
|
{
|
|
mFileStream = fileStream;
|
|
mSeqOffset = seqOffset;
|
|
mStartOffsetType = startOffsetType;
|
|
mStartOffset = startOffset;
|
|
|
|
mLoadingFlag = true;
|
|
|
|
if (!LoadData(&NotifyLoadAsyncEndSeqData, this))
|
|
Shutdown();
|
|
}
|
|
|
|
void SeqSound::NotifyLoadAsyncEndSeqData(bool result, void const *seqBase,
|
|
void *userData)
|
|
{
|
|
SeqSound *sound = static_cast<SeqSound *>(userData);
|
|
NW4RAssertPointerNonnull_Line(178, sound);
|
|
|
|
sound->mLoadingFlag = false;
|
|
|
|
if (result == false)
|
|
{
|
|
sound->Stop(0);
|
|
return;
|
|
}
|
|
|
|
NW4RAssertPointerNonnull_Line(189, seqBase);
|
|
sound->mSeqPlayer.SetSeqData(seqBase, sound->mSeqOffset);
|
|
|
|
if (sound->mStartOffset > 0)
|
|
sound->mSeqPlayer.Skip(sound->mStartOffsetType, sound->mStartOffset);
|
|
|
|
sound->mPreparedFlag = true;
|
|
}
|
|
|
|
void SeqSound::Skip(SeqPlayer::OffsetType offsetType, int offset)
|
|
{
|
|
mSeqPlayer.Skip(offsetType, offset);
|
|
}
|
|
|
|
void SeqSound::Shutdown()
|
|
{
|
|
if (mLoadingFlag)
|
|
TaskManager::GetInstance().CancelTask(&mSeqLoadTask);
|
|
|
|
if (mFileStream)
|
|
{
|
|
mFileStream->Close();
|
|
mFileStream = nullptr;
|
|
}
|
|
|
|
BasicSound::Shutdown();
|
|
mManager->Free(this);
|
|
}
|
|
#if 0
|
|
// SeqSound::SetTempoRatio ([R89JEL]:/bin/RVL/Debug/mainD.MAP:13849)
|
|
DECOMP_FORCE(NW4RAssert_String(tempoRatio >= 0.0f));
|
|
#endif
|
|
|
|
void SeqSound::SetTempoRatio(f32 tempo) {
|
|
mSeqPlayer.SetTempoRatio(tempo);
|
|
}
|
|
|
|
void SeqSound::SetChannelPriority(int priority)
|
|
{
|
|
// specifically not the source variant
|
|
NW4RAssertHeaderClampedLRValue_Line(266, priority, 0, 127);
|
|
|
|
mSeqPlayer.SetChannelPriority(priority);
|
|
}
|
|
|
|
void SeqSound::SetReleasePriorityFix(bool fix)
|
|
{
|
|
mSeqPlayer.SetReleasePriorityFix(fix);
|
|
}
|
|
|
|
void SeqSound::SetSeqUserprocCallback(SeqPlayer::SeqUserprocCallback *callback,
|
|
void *arg)
|
|
{
|
|
mSeqPlayer.SetSeqUserprocCallback(callback, arg);
|
|
}
|
|
|
|
void SeqSound::OnUpdatePlayerPriority()
|
|
{
|
|
mManager->UpdatePriority(this, CalcCurrentPlayerPriority());
|
|
}
|
|
|
|
void SeqSound::SetTrackMute(u32 trackFlags, SeqMute mute)
|
|
{
|
|
mSeqPlayer.SetTrackMute(trackFlags, mute);
|
|
}
|
|
|
|
void SeqSound::SetTrackSilence(u32 trackFlags, bool silence, int fadeFrames)
|
|
{
|
|
mSeqPlayer.SetTrackSilence(trackFlags, silence, fadeFrames);
|
|
}
|
|
|
|
void SeqSound::SetTrackVolume(u32 trackFlags, f32 volume)
|
|
{
|
|
mSeqPlayer.SetTrackVolume(trackFlags, volume);
|
|
}
|
|
|
|
bool SeqSound::ReadVariable(int varNo, s16 *value) const
|
|
{
|
|
if (!GetStartedFlag()) {
|
|
*value = -1;
|
|
} else {
|
|
*value = mSeqPlayer.GetLocalVariable(varNo);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SeqSound::WriteVariable(int varNo, s16 value)
|
|
{
|
|
mSeqPlayer.SetLocalVariable(varNo, value);
|
|
return true;
|
|
}
|
|
|
|
bool SeqSound::WriteGlobalVariable(int varNo, s16 value)
|
|
{
|
|
SeqPlayer::SetGlobalVariable(varNo, value);
|
|
return true;
|
|
}
|
|
|
|
bool SeqSound::WriteTrackVariable(int trackNo, int varNo, s16 value)
|
|
{
|
|
SeqTrack *track = mSeqPlayer.GetPlayerTrack(trackNo);
|
|
if (track == NULL)
|
|
return false;
|
|
|
|
track->SetTrackVariable(varNo, value);
|
|
return true;
|
|
}
|
|
|
|
u32 SeqSound::GetTick() const
|
|
{
|
|
return !GetStartedFlag() ? 0 : mSeqPlayer.GetTickCounter();
|
|
}
|
|
|
|
|
|
#if 0
|
|
// SeqSound::SetTrackVolume ([R89JEL]:/bin/RVL/Debug/mainD.MAP:13857)
|
|
DECOMP_FORCE(NW4RAssert_String(volume >= 0.0f));
|
|
|
|
// SeqSound::SetTrackPitch ([R89JEL]:/bin/RVL/Debug/mainD.MAP:13858)
|
|
DECOMP_FORCE(NW4RAssert_String(pitch >= 0.0f));
|
|
|
|
// SeqSound::ReadVariable? maybe all of them?
|
|
DECOMP_FORCE(NW4RAssertPointerNonnull_String(var));
|
|
|
|
// SeqSound::ReadGlobalVariable? maybe both of them?
|
|
DECOMP_FORCE(NW4RAssertHeaderClampedLValue_String(varNo));
|
|
|
|
// SeqSound::ReadTrackVariable? maybe both of them?
|
|
DECOMP_FORCE(NW4RAssertHeaderClampedLValue_String(trackNo));
|
|
#endif
|
|
bool SeqSound::IsAttachedTempSpecialHandle()
|
|
{
|
|
return mTempSpecialHandle != nullptr;
|
|
}
|
|
|
|
void SeqSound::DetachTempSpecialHandle()
|
|
{
|
|
mTempSpecialHandle->DetachSound();
|
|
}
|
|
|
|
bool SeqSound::LoadData(SeqLoadTask::Callback *callback, void *callbackArg)
|
|
{
|
|
PlayerHeap *heap = static_cast<BasicSound *>(callbackArg)->GetPlayerHeap();
|
|
if (!heap)
|
|
return false;
|
|
|
|
int fileSize = mFileStream->GetSize();
|
|
void *buffer = heap->Alloc(fileSize);
|
|
if (!buffer)
|
|
return false;
|
|
|
|
mSeqLoadTask.mFileStream = mFileStream;
|
|
mSeqLoadTask.mBuffer = buffer;
|
|
mSeqLoadTask.mBufferSize = fileSize;
|
|
mSeqLoadTask.mCallback = callback;
|
|
mSeqLoadTask.mCallbackData = this;
|
|
|
|
TaskManager::GetInstance().AppendTask(&mSeqLoadTask,
|
|
TaskManager::PRIORITY_MIDDLE);
|
|
|
|
return true;
|
|
}
|
|
|
|
SeqSound::SeqLoadTask::SeqLoadTask() :
|
|
mFileStream (nullptr),
|
|
mBuffer (nullptr),
|
|
mCallback (nullptr),
|
|
mCallbackData (nullptr)
|
|
{
|
|
}
|
|
|
|
void SeqSound::SeqLoadTask::Execute()
|
|
{
|
|
mFileStream->Seek(0, ut::FileStream::SEEK_ORIGIN_SET);
|
|
|
|
s32 readSize = mFileStream->Read(mBuffer, mBufferSize);
|
|
|
|
mFileStream = nullptr;
|
|
|
|
if (readSize == DVD_ECANCELED)
|
|
{
|
|
if (mCallback)
|
|
(*mCallback)(false, nullptr, mCallbackData);
|
|
|
|
return;
|
|
}
|
|
|
|
if (readSize != mBufferSize)
|
|
{
|
|
NW4RCheckMessage_Line(716, readSize != 0,
|
|
"failed to load sequence data\n");
|
|
|
|
if (mCallback)
|
|
(*mCallback)(false, nullptr, mCallbackData);
|
|
|
|
return;
|
|
}
|
|
|
|
SeqFile const *seq = static_cast<SeqFile const *>(mBuffer); // What
|
|
SeqFileReader reader(seq);
|
|
void const *seqBase = reader.GetBaseAddress();
|
|
|
|
if (mCallback)
|
|
(*mCallback)(true, seqBase, mCallbackData);
|
|
}
|
|
|
|
void SeqSound::SeqLoadTask::Cancel()
|
|
{
|
|
if (mCallback)
|
|
(*mCallback)(false, nullptr, mCallbackData);
|
|
}
|
|
|
|
void SeqSound::SeqLoadTask::OnCancel()
|
|
{
|
|
mCallback = nullptr;
|
|
|
|
ut::FileStream *fileStream = mFileStream;
|
|
if (fileStream)
|
|
fileStream->Cancel();
|
|
}
|
|
|
|
}}} // namespace nw4r::snd::detail
|