diff --git a/config/SZBE69_B8/objects.json b/config/SZBE69_B8/objects.json index b771620a..fca514e9 100644 --- a/config/SZBE69_B8/objects.json +++ b/config/SZBE69_B8/objects.json @@ -223,6 +223,7 @@ "system/math/FileChecksum.cpp": "Matching", "system/math/Geo.cpp": "NonMatching", "system/math/Interp.cpp": "Matching", + "system/math/Key.cpp": { "status": "NonMatching", "extra_cflags": [ "-fp_contract off" ] }, "system/math/Primes.cpp": "Matching", "system/math/Rand.cpp": "Matching", "system/math/Rand2.cpp": "Matching", @@ -406,6 +407,8 @@ "system/rndwii/Rnd.cpp": "NonMatching", "system/synth/ADSR.cpp": "NonMatching", + "system/synth/BinkClip.cpp": "Matching", + "system/synth/BinkReader.cpp": "NonMatching", "system/synth/ByteGrinder.cpp": "NonMatching", "system/synth/Emitter.cpp": "NonMatching", "system/synth/Faders.cpp": "Equivalent", @@ -421,6 +424,7 @@ "system/synth/FxSendPitchShift.cpp": "Matching", "system/synth/FxSendSynapse.cpp": "Matching", "system/synth/FxSendWah.cpp": "Matching", + "system/synth/MetaMusic.cpp": "NonMatching", "system/synth/Mic.cpp": "Matching", "system/synth/MicNull.cpp": "NonMatching", "system/synth/MidiInstrument.cpp": "NonMatching", @@ -480,7 +484,10 @@ "system/ui/UIListWidget.cpp": "NonMatching", "system/ui/UIPanel.cpp": "Matching", "system/ui/UIPicture.cpp": "Matching", - "system/ui/UIProxy.cpp": "NonMatching", + "system/ui/UIProxy.cpp": { + "status": "LinkIssues", + "comment": "SetType ordering in bss" + }, "system/ui/UIResource.cpp": "Matching", "system/ui/UIScreen.cpp": { "status": "LinkIssues", @@ -553,7 +560,7 @@ "system/utl/UTF8.cpp": "NonMatching", "system/utl/VarTimer.cpp": "NonMatching", "system/utl/Wav.cpp": "NonMatching", - "system/utl/WaveFile.cpp": "NonMatching", + "system/utl/WaveFile.cpp": "Matching", "system/world/CameraManager.cpp": "NonMatching", "system/world/CameraShot.cpp": "NonMatching", diff --git a/src/system/char/CharInterest.h b/src/system/char/CharInterest.h index 68ebeee3..ef57f9d1 100644 --- a/src/system/char/CharInterest.h +++ b/src/system/char/CharInterest.h @@ -1,6 +1,5 @@ #ifndef CHAR_CHARINTEREST_H #define CHAR_CHARINTEREST_H -#include "obj/ObjMacros.h" #include "rndobj/Trans.h" #include "obj/ObjPtr_p.h" #include "char/CharEyeDartRuleset.h" diff --git a/src/system/math/Color.h b/src/system/math/Color.h index 095ca13c..012e75d2 100644 --- a/src/system/math/Color.h +++ b/src/system/math/Color.h @@ -23,16 +23,12 @@ namespace Hmx { Color(int i) : alpha(1.0f) { Unpack(i); } // copy ctor uses asm magic - Color(const register Color& color){ - register Color* theCol = this; - register float temp1; - register float temp2; - ASM_BLOCK( - psq_lx temp2,0,color,0,0 - psq_l temp1,8(color),0,0 - psq_stx temp2,0,theCol,0,0 - psq_st temp1,8(theCol),0,0 - ) + Color(const Color& color){ + typedef struct{ + __vec2x32float__ a, b; + } Color_psq; + + *(Color_psq *)this = *(Color_psq *)&color; } void Set(float f1, float f2, float f3, float f4){ @@ -40,13 +36,8 @@ namespace Hmx { } // all weak - // Color() {}; - // Color(int); - // void operator=(const Color &); - // void Unpack(int); // bool operator==(const Color &) const; // bool operator!=(const Color &) const; - // void Set(float, float, float, float); void Set(float f){ red = green = blue = alpha = f; } diff --git a/src/system/math/Key.cpp b/src/system/math/Key.cpp new file mode 100644 index 00000000..60ee3a30 --- /dev/null +++ b/src/system/math/Key.cpp @@ -0,0 +1,49 @@ +#include "math/Key.h" +#include "math/Vec.h" + +// fn_802E33CC - SplineTangent(const Keys&, int, Vector3&) +// https://decomp.me/scratch/uaX0T - retail +// https://decomp.me/scratch/g4W1K - debug (i hate inlining) +void SplineTangent(const Keys& keys, int i, Vector3& vout){ + int size = keys.size(); + MILO_ASSERT(size > 1, 0x17); + if(size == 2){ + Subtract(keys[1].value, keys[0].value, vout); + } + else if(i <= 0){ + Subtract(keys[1].value, keys[0].value, vout); + Scale(vout, 1.5f, vout); + Vector3 vtmp; + Subtract(keys[2].value, keys[0].value, vtmp); + Scale(vtmp, 0.25f, vtmp); + Subtract(vout, vtmp, vout); + } + else if(i >= size - 1){ + Subtract(keys[size - 1].value, keys[size - 2].value, vout); + Scale(vout, 1.5f, vout); + Vector3 vtmp; + Subtract(keys[size - 1].value, keys[size - 3].value, vtmp); + Scale(vtmp, 0.25f, vtmp); + Subtract(vout, vtmp, vout); + } + else { + Subtract(keys[i + 1].value, keys[i - 1].value, vout); + Scale(vout, 0.5f, vout); + } +} + +// fn_802E35A8 - InterpTangent(const Vector3&, const Vector3&, const Vector3&, const Vector3&, float, Vector3&) +// i absolutely hate inlines +void InterpTangent(const Vector3& v1, const Vector3& v2, const Vector3& v3, const Vector3& v4, float f, Vector3& vout){ + float scale = f * f; + Scale(v1, scale * 6.0f - f * 6.0f, vout); + Vector3 vtmp; + Scale(v2, -(f * 4.0f - scale * 3.0f) + 1.0f, vtmp); + Add(vout, vtmp, vout); + Scale(v3, scale * -6.0f + f * 6.0f, vtmp); + Add(vout, vtmp, vout); + Scale(v4, -(f * 2.0f - f * 3.0f), vtmp); + Add(vout, vtmp, vout); +} + +// fn_802E36D4 - InterpVector(const Keys&, const Key*, const Key*, float, bool, Vector3&, Vector3*) \ No newline at end of file diff --git a/src/system/math/Mtx.h b/src/system/math/Mtx.h index 60194fd0..65c3eb56 100644 --- a/src/system/math/Mtx.h +++ b/src/system/math/Mtx.h @@ -39,6 +39,11 @@ namespace Hmx { } Matrix3& operator=(const Matrix3 &); Vector3& operator[](int); + + bool operator==(const Matrix3& mtx) const { + return x == mtx.x && y == mtx.y && z == mtx.z; + } + }; class Quat { @@ -145,6 +150,10 @@ class Transform { m.z.Zero(); v.Zero(); } + + bool operator==(const Transform& tf) const { + return m == tf.m && v == tf.v; + } }; inline BinStream& operator>>(BinStream& bs, Transform& tf){ @@ -212,5 +221,50 @@ void ScaleAddEq(Hmx::Quat&, const Hmx::Quat&, float); void Normalize(const Hmx::Quat&, Hmx::Quat&); void Multiply(const Hmx::Quat&, const Hmx::Quat&, Hmx::Quat&); void FastInterp(const Hmx::Quat&, const Hmx::Quat&, float, Hmx::Quat&); +void Invert(const Hmx::Matrix3&, Hmx::Matrix3&); +void Multiply(const Hmx::Matrix3&, const Vector3&, Vector3&); + +inline void Multiply(const Vector3& vin, const Hmx::Matrix3& mtx, Vector3& vout) { + register __vec2x32float__ i1, i2, m1, m2, o1, o2; + + register const Vector3 *_vin = &vin; + register Vector3 *_vout = &vout; + register const Hmx::Matrix3 *_m = &mtx; + + typedef Hmx::Matrix3 Matrix3; + + ASM_BLOCK( + psq_l i1, Vector3.x(_vin), 0, 0 + psq_l i2, Vector3.y(_vin), 0, 0 + + psq_l m1, Matrix3.z.x(_m), 0, 0 + psq_l m2, Matrix3.z.z(_m), 1, 0 + + ps_muls1 o1, m1, i2 + ps_muls1 o2, m2, i2 + + psq_l m1, Matrix3.y.x(_m), 0, 0 + psq_l m2, Matrix3.y.z(_m), 1, 0 + + ps_madds0 o1, m1, i2, o1 + ps_madds0 o2, m2, i2, o2 + + psq_l m1, Matrix3.x.x(_m), 0, 0 + psq_l m2, Matrix3.x.z(_m), 1, 0 + + ps_madds0 o1, m1, i1, o1 + ps_madds0 o2, m2, i1, o2 + + psq_st o1, Vector3.x(_vout), 0, 0 + psq_st o2, Vector3.z(_vout), 1, 0 + ) +} + +inline void Invert(const Transform& tfin, Transform& tfout){ + Vector3 vtmp; + Negate(tfin.v, vtmp); + Invert(tfin.m, tfout.m); + Multiply(vtmp, tfout.m, tfout.v); +} #endif diff --git a/src/system/math/Rot.h b/src/system/math/Rot.h index 957d7ae3..28e08b7b 100644 --- a/src/system/math/Rot.h +++ b/src/system/math/Rot.h @@ -9,8 +9,6 @@ #define RAD2DEG 57.2957763671875f #define DEG2RAD 0.01745329238474369049f -void Multiply(const Hmx::Matrix3&, const Vector3&, Vector3&); -void Multiply(const Vector3&, const Hmx::Matrix3&, Vector3&); void Multiply(const Vector3&, const Transform&, Vector3&); void Multiply(const Transform&, const Vector3&, Vector3&); void Multiply(const Transform&, const Transform&, Transform&); @@ -21,7 +19,6 @@ void MakeEuler(const Hmx::Matrix3&, Vector3&); void MakeEulerScale(const Hmx::Matrix3&, Vector3&, Vector3&); void Normalize(const Hmx::Matrix3&, Hmx::Matrix3&); void MakeRotMatrix(const Hmx::Quat&, Hmx::Matrix3&); -void Invert(const Transform&, Transform&); void Interp(const Hmx::Quat&, const Hmx::Quat&, float, Hmx::Quat&); void RotateAboutX(const Hmx::Matrix3&, float, Hmx::Matrix3&); void MakeRotQuat(const Vector3&, const Vector3&, Hmx::Quat&); diff --git a/src/system/math/Vec.h b/src/system/math/Vec.h index 4ac4625f..b18b1617 100644 --- a/src/system/math/Vec.h +++ b/src/system/math/Vec.h @@ -80,7 +80,9 @@ class Vector3 { const float& operator[](int i) const { return *(&x + i); } float& operator[](int i){ return *(&x + i); } - // bool operator==(const Vector3 &) const; + bool operator==(const Vector3& v) const { + return x == v.x && y == v.y && z == v.z; + } // bool operator!=(const Vector3 &) const; }; @@ -219,13 +221,7 @@ inline float Distance(const Vector3& v1, const Vector3& v2){ } inline void Subtract(const Vector3 &v1, const Vector3 &v2, Vector3 &dst) { -#ifdef VERSION_SZBE69_B8 - dst.z = v1.z - v2.z; - dst.y = v1.y - v2.y; - dst.x = v1.x - v2.x; -#else dst.Set(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); -#endif } float Length(const Vector3&); @@ -251,6 +247,8 @@ inline float LengthSquared(const Vector3& v){ return x * x + y * y + z * z; } +// https://decomp.me/scratch/TWZ2T +// why oh why does debug behave this way inline float DistanceSquared(const Vector3& v1, const Vector3& v2){ #ifdef VERSION_SZBE69_B8 float zdiff = v1.z - v2.z; @@ -267,13 +265,7 @@ inline float DistanceSquared(const Vector3& v1, const Vector3& v2){ float RecipSqrtAccurate(float); inline void Add(const Vector3& v1, const Vector3& v2, Vector3& dst){ -#ifdef VERSION_SZBE69_B8 - dst.z = v1.z + v2.z; - dst.y = v1.y + v2.y; - dst.x = v1.x + v2.x; -#else dst.Set(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); -#endif } inline void Interp(const Vector2& v1, const Vector2& v2, float f, Vector2& res){ @@ -314,4 +306,8 @@ inline float operator*(const Vector3& v1, const Vector3& v2){ return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; } +inline void Negate(const Vector3& v, Vector3& vres){ + vres.Set(-v.x, -v.y, -v.z); +} + #endif diff --git a/src/system/meta/HeldButtonPanel.h b/src/system/meta/HeldButtonPanel.h index 2d121d0f..32ea9bd0 100644 --- a/src/system/meta/HeldButtonPanel.h +++ b/src/system/meta/HeldButtonPanel.h @@ -1,6 +1,5 @@ #ifndef META_HELDBUTTONPANEL_H #define META_HELDBUTTONPANEL_H -#include "obj/ObjMacros.h" #include "ui/UIPanel.h" #include "meta/ButtonHolder.h" diff --git a/src/system/meta/SongPreview.cpp b/src/system/meta/SongPreview.cpp index 8b306d12..611cd38d 100644 --- a/src/system/meta/SongPreview.cpp +++ b/src/system/meta/SongPreview.cpp @@ -285,10 +285,10 @@ void SongPreview::PrepareSong(Symbol s){ mStream->SetPan(i, pans[i]); } - const TrackChannels& tracks = data->FindTrackChannel(kAudioTypeMulti); - if(&tracks != 0){ - for(int i = 0; i < tracks.mChannels.size(); i++){ - mStream->SetVolume(tracks.mChannels[i], -96.0f); + const TrackChannels* tracks = data->FindTrackChannel(kAudioTypeMulti); + if(tracks != 0){ + for(int i = 0; i < tracks->mChannels.size(); i++){ + mStream->SetVolume(tracks->mChannels[i], -96.0f); } } DetachFaders(); diff --git a/src/system/obj/Dir.h b/src/system/obj/Dir.h index cae4ce5c..a0075ba5 100644 --- a/src/system/obj/Dir.h +++ b/src/system/obj/Dir.h @@ -84,9 +84,10 @@ template class ObjDirPtr : public ObjRef { // IsLoaded__21ObjDirPtr<9ObjectDir>CFv bool IsLoaded() const { + bool b; bool ret = true; if(!mDir){ - bool b = false; + b = false; if(mLoader && mLoader->IsLoaded()) b = true; if(!b) ret = false; } diff --git a/src/system/obj/PropSync_p.h b/src/system/obj/PropSync_p.h index 017697b0..943863eb 100644 --- a/src/system/obj/PropSync_p.h +++ b/src/system/obj/PropSync_p.h @@ -7,8 +7,6 @@ #include "utl/FilePath.h" #include "utl/Symbol.h" #include "os/Debug.h" -#include "obj/ObjVector.h" -#include "obj/ObjList.h" #include "math/Geo.h" #include @@ -220,6 +218,7 @@ template bool PropSync(std::vector& vec, DataNode& } } +#include "obj/ObjVector.h" template bool PropSync(ObjVector& objVec, DataNode& node, DataArray* prop, int i, PropOp op) { if(op == kPropUnknown0x40) return false; else if(i == prop->Size()){ @@ -247,6 +246,7 @@ template bool PropSync(ObjVector& objVec, DataNode } } +#include "obj/ObjList.h" template bool PropSync(ObjList& objList, DataNode& node, DataArray* prop, int i, PropOp op){ if(op == kPropUnknown0x40) return false; else if(i == prop->Size()){ diff --git a/src/system/os/CritSec.h b/src/system/os/CritSec.h index 070c3b05..519b9e58 100644 --- a/src/system/os/CritSec.h +++ b/src/system/os/CritSec.h @@ -14,9 +14,8 @@ class CriticalSection { void Exit(); void Abandon(); - void operator delete(void* v){ - _PoolFree(sizeof(CriticalSection), FastPool, v); - } + NEW_POOL_OVERLOAD(CriticalSection) + DELETE_POOL_OVERLOAD(CriticalSection) }; class CritSecTracker { diff --git a/src/system/os/HDCache.cpp b/src/system/os/HDCache.cpp index 86f526d4..d755ff48 100644 --- a/src/system/os/HDCache.cpp +++ b/src/system/os/HDCache.cpp @@ -1,15 +1,46 @@ #include "HDCache.h" #include "os/Debug.h" #include "os/OSFuncs.h" +#include "os/Archive.h" +#include "utl/Option.h" HDCache TheHDCache; -HDCache::HDCache() : a(0), d(), g(false) {} +HDCache::HDCache() : mBlockState(0), mWriteFileIdx(0), unk18(-1), unk20(0), unk24(0), unk28(-1), unk2c(-1), mLockId(0), + unk34(0), mCritSec(0), mHdrIdx(0), mHdrBuf(0), unk64(0) { + +} HDCache::~HDCache() { } -void HDCache::UnlockCache() { - if (cs.mEntryCount) cs.Enter(); - MILO_ASSERT(mLockID == CurrentThreadID(), 249); - if (cs.mEntryCount) cs.Exit(); +void HDCache::Init(){ + mCritSec = new CriticalSection(); + if(TheArchive){ + OptionBool("no_hdcache", true); + int numarkfiles = TheArchive->mNumArkfiles; + mReadArkFiles.resize(numarkfiles); + mWriteArkFiles.resize(numarkfiles); + FileStream* fs = OpenHeader(); + if(fs){ + if(fs->Tell() == 0){ + + } + } + } +} + +bool HDCache::LockCache(){ + CritSecTracker cst(mCritSec); + if(mLockId == 0 || mLockId == CurrentThreadId()){ + mLockId = CurrentThreadId(); + unk34++; + return true; + } + else return false; +} + +void HDCache::UnlockCache(){ + CritSecTracker cst(mCritSec); + MILO_ASSERT(mLockId == CurrentThreadId(), 0xF9); + if(!unk34--) mLockId = 0; } diff --git a/src/system/os/HDCache.h b/src/system/os/HDCache.h index d4aab388..51dd6c2e 100644 --- a/src/system/os/HDCache.h +++ b/src/system/os/HDCache.h @@ -1,20 +1,33 @@ #ifndef OS_HDCACHE_H #define OS_HDCACHE_H - #include "os/CritSec.h" #include "utl/Str.h" +#include "utl/FileStream.h" +#include "utl/MemStream.h" #include #include class HDCache { - public: - int a; - std::vector b, c; - int d[8]; - OSThread* mLockID; - CriticalSection cs; - String e, f; - bool g; +public: + int** mBlockState; // 0x0 + std::vector mReadArkFiles; // 0x4 + std::vector mWriteArkFiles; // 0xc + int mWriteFileIdx; // 0x14 + int unk18; // 0x18 + int unk1c; + int unk20; // 0x20 + int unk24; + int unk28; + int unk2c; + OSThread* mLockId; // 0x30 + int unk34; + CriticalSection* mCritSec; // 0x38 + int mHdrIdx; // 0x3c + File* mHdr[2]; // 0x40 + MemStream* mHdrBuf; // 0x48 + String mHdrFmt; // 0x4c + String mFileFmt; // 0x58 + bool unk64; // 0x64 HDCache(); ~HDCache(); @@ -27,6 +40,7 @@ class HDCache { bool ReadAsync(int, int, void*); bool ReadFail(); bool ReadDone(); + FileStream* OpenHeader(); }; diff --git a/src/system/os/HolmesClient.cpp b/src/system/os/HolmesClient.cpp index 752333f6..3398cf1c 100644 --- a/src/system/os/HolmesClient.cpp +++ b/src/system/os/HolmesClient.cpp @@ -1,5 +1,4 @@ #include "HolmesClient.h" -#include "obj/ObjMacros.h" #include "os/CritSec.h" #include "os/Debug.h" #include "os/HolmesKeyboard.h" diff --git a/src/system/os/OSFuncs.h b/src/system/os/OSFuncs.h index 510b7b95..71a7b76f 100644 --- a/src/system/os/OSFuncs.h +++ b/src/system/os/OSFuncs.h @@ -11,7 +11,7 @@ inline bool MainThread() { return ret; } -inline OSThread* CurrentThreadID() { return OSGetCurrentThread(); } +inline OSThread* CurrentThreadId() { return OSGetCurrentThread(); } #endif diff --git a/src/system/os/System.cpp b/src/system/os/System.cpp index 20da60a8..fbb54a0e 100644 --- a/src/system/os/System.cpp +++ b/src/system/os/System.cpp @@ -44,13 +44,14 @@ const char* gHostFile; unsigned char* g_pRSOReserveBuf; unsigned char* g_pDefaultRSOBuf; +DECOMP_FORCEACTIVE(System, "_unresolved func.\n", "gen/main_%s.hdr") + namespace { bool gHasPreconfig = true; bool gPreconfigOverride; bool CheckForArchive() { SetUsingCD(true); - FileStat stat; if (FileGetStat(MakeString("gen/main_%s.hdr", PlatformSymbol(TheLoadMgr.GetPlatform())), &stat) < 0) { SetUsingCD(false); @@ -105,6 +106,8 @@ DataNode OnSwitchSystemLanguage(DataArray* da){ return DataNode(1); } +DECOMP_FORCEACTIVE(System, "LanguageInit called, but region has not been initialized", "language", "system") + void LanguageInit() { if (ThePlatformMgr.GetRegion() == kRegionNone) { MILO_WARN("LanguageInit called, but region has not been initialized"); @@ -284,6 +287,11 @@ void SystemTerminate() { TerminateMakeString(); } + +void SystemPreInit(const char* cc){ + CheckForArchive(); +} + int SystemMs() { gSystemTimer.Restart(); float lastMs = gSystemTimer.GetLastMs(); diff --git a/src/system/synth/ADSR.h b/src/system/synth/ADSR.h index 8de37faa..27a37fc9 100644 --- a/src/system/synth/ADSR.h +++ b/src/system/synth/ADSR.h @@ -72,4 +72,7 @@ class ADSR { BinStream& operator>>(BinStream&, ADSR&); static int FindNearestInTable(const float* table, int tableSize, float val); +#include "obj/PropSync_p.h" +bool PropSync(ADSR&, DataNode&, DataArray*, int, PropOp); + #endif diff --git a/src/system/synth/BinkClip.cpp b/src/system/synth/BinkClip.cpp new file mode 100644 index 00000000..0dd1c663 --- /dev/null +++ b/src/system/synth/BinkClip.cpp @@ -0,0 +1,253 @@ +#include "synth/BinkClip.h" +#include "synth/Synth.h" +#include "utl/Symbols.h" + +BinkClip::PanInfo::PanInfo(int i, float f) : chan(i), pan(f) {} + +BinkClip::BinkClip() : mVolume(0), mLoop(0), mPreload(0), mStream(0), mPlaybackVolumeOffset(0), mData(0), mSize(0), mLoader(0), + mFadeOutFader(Hmx::Object::New()), mUnloadWhenFinishedPlaying(0), mPlaying(0), mStreamLoader(0) { + mFaders.push_back(mFadeOutFader); + StartPolling(); +} + +BinkClip::~BinkClip(){ + delete mLoader; + mLoader = 0; + delete mFadeOutFader; + mFadeOutFader = 0; + KillStream(); + UnloadData(); +} + +void BinkClip::SynthPoll(){ + if(mPlaying && mStream){ + if(!mStream->IsPlaying() && mStream->IsReady()){ + mStream->Play(); + } + else { + if(mStream->IsFinished() || mFadeOutFader->mVal == -96.0f){ + Stop(); + } + } + } +} + +SAVE_OBJ(BinkClip, 0x5D) + +BEGIN_COPYS(BinkClip) + COPY_SUPERCLASS(Hmx::Object) + CREATE_COPY(BinkClip) + BEGIN_COPYING_MEMBERS + COPY_MEMBER(mFile) + COPY_MEMBER(mVolume) + COPY_MEMBER(mLoop) + COPY_MEMBER(mPreload) + END_COPYING_MEMBERS +END_COPYS + +BEGIN_LOADS(BinkClip) + PreLoad(bs); + PostLoad(bs); +END_LOADS + +void BinkClip::PreLoad(BinStream& bs){ + int rev; + bs >> rev; + if(rev > 1) MILO_WARN("Can't load new BinkClip"); + else { + LOAD_SUPERCLASS(Hmx::Object); + bs >> mFile >> mVolume >> mLoop >> mPreload; + if(!mFile.empty()){ + LoadFile(rev > 0 ? &bs : 0); + } + } +} + +void BinkClip::PostLoad(BinStream&){ EnsureLoaded(); } + +void BinkClip::Play(){ + if(!mPreload){ + String str(mFile.c_str()); + str = str.substr(0, str.length() - 4); + mStream = dynamic_cast(TheSynth->NewStream(str.c_str(), 0, 0, false)); + mFadeOutFader->SetVal(0); + SetLoop(mLoop); + UpdateVolume(); + UpdateFaders(); + UpdatePanInfo(); + mPlaying = true; + } + else { + if(EnsureLoaded()){ + KillStream(); + mStream = dynamic_cast(TheSynth->NewBufStream(mData, mSize, "bik", 0, true)); + mFadeOutFader->SetVal(0); + SetLoop(mLoop); + UpdateVolume(); + UpdateFaders(); + UpdatePanInfo(); + mPlaying = true; + } + else MILO_WARN("bik file not loaded: '%s'", mFile.c_str()); + } +} + +void BinkClip::Pause(bool b){ + mPlaying = !b; + if(mStream && !mPlaying) mStream->Stop(); +} + +void BinkClip::Stop(){ + KillStream(); + if(mUnloadWhenFinishedPlaying) UnloadData(); +} + +bool BinkClip::IsStreaming() const { + return mStream && mStream->IsPlaying(); +} + +void BinkClip::SetFile(const char* file){ + MILO_ASSERT(file != NULL, 0xFE); + mFile.SetRoot(file); + LoadFile(0); +} + +void BinkClip::SetVolume(float f){ + mVolume = f; + UpdateVolume(); +} + +void BinkClip::SetLoop(bool b){ + mLoop = b; + if(mStream){ + mStream->ClearJump(); + if(mLoop) mStream->SetJump(Stream::kStreamEndMs, 0, 0); + } +} + +void BinkClip::AddFader(Fader* fader){ + if(fader){ + bool found = false; + for(std::vector::iterator it = mFaders.begin(); it != mFaders.end(); ++it){ + if(*it == fader){ + found = true; + break; + } + } + if(!found) mFaders.push_back(fader); + if(mStream) mStream->Faders()->Add(fader); + } +} + +void BinkClip::RemoveFader(Fader* fader){ + if(fader){ + for(std::vector::iterator it = mFaders.begin(); it != mFaders.end(); ++it){ + if(*it == fader){ + mFaders.erase(it); + break; + } + } + if(mStream) mStream->Faders()->Remove(fader); + } +} + +void BinkClip::SetPan(int chan, float pan){ + PanInfo info(chan, pan); + bool found = false; + for(std::vector::iterator it = mPanInfo.begin(); it != mPanInfo.end(); ++it){ + if((*it).chan == chan){ + *it = info; + found = true; + break; + } + } + if(!found) mPanInfo.push_back(info); + if(mStream) mStream->SetPan(info.chan, info.pan); +} + +void BinkClip::FadeOut(float f){ + mFadeOutFader->DoFade(-96.0f, f); +} + +void BinkClip::UnloadWhenFinishedPlaying(bool b){ mUnloadWhenFinishedPlaying = b; } + +void BinkClip::LoadFile(BinStream* bs){ + delete mLoader; + mLoader = 0; + KillStream(); + UnloadData(); + if(mPreload){ + BinStream* toUse = bs && bs->Cached() ? bs : 0; + mLoader = new FileLoader(mFile, FileLocalize(mFile.c_str(), 0), kLoadFront, 0, false, true, toUse); + if(!mLoader) MILO_WARN("Could not load bik file '%s'", mFile.c_str()); + } +} + +bool BinkClip::IsReadyToPlay() const { + if(!mPreload) return true; + if(mLoader) return mLoader->IsLoaded(); + return mData && mSize > 0; +} + +bool BinkClip::EnsureLoaded(){ + if(mLoader){ + if(!mLoader->IsLoaded()){ + MILO_WARN("BinkClip blocked while loading '%s'", mFile.c_str()); + TheLoadMgr.PollUntilLoaded(mLoader, 0); + } + mData = (void*)mLoader->GetBuffer(&mSize); + delete mLoader; + mLoader = 0; + } + return mData && mSize > 0; +} + +void BinkClip::UpdateVolume(){ + if(mStream) mStream->Stream::SetVolume(mVolume + mPlaybackVolumeOffset); +} + +void BinkClip::UpdateFaders(){ + if(mStream){ + for(std::vector::iterator it = mFaders.begin(); it != mFaders.end(); ++it){ + mStream->Faders()->Add(*it); + } + } +} + +void BinkClip::UpdatePanInfo(){ + if(mStream){ + for(std::vector::iterator it = mPanInfo.begin(); it != mPanInfo.end(); ++it){ + mStream->SetPan((*it).chan, (*it).pan); + } + } +} + +void BinkClip::KillStream(){ + mPlaying = false; + delete mStream; + mStream = 0; +} + +void BinkClip::UnloadData(){ + if(mData){ + _MemFree(mData); + mData = 0; + mSize = 0; + } +} + +BEGIN_PROPSYNCS(BinkClip) + SYNC_PROP_SET(file, mFile, SetFile(_val.Str(0))) + SYNC_PROP_SET(volume, mVolume, SetVolume(_val.Float(0))) + SYNC_PROP_SET(loop, mLoop, SetLoop(_val.Int(0))) + SYNC_PROP_SET(preload, mPreload, mPreload = _val.Int(0)) + SYNC_SUPERCLASS(Hmx::Object) +END_PROPSYNCS + +BEGIN_HANDLERS(BinkClip) + HANDLE_ACTION(play, Play()) + HANDLE_ACTION(stop, Stop()) + HANDLE_ACTION(set_pan, SetPan(_msg->Int(2), _msg->Float(3))) + HANDLE_SUPERCLASS(Hmx::Object) + HANDLE_CHECK(0x24A) +END_HANDLERS \ No newline at end of file diff --git a/src/system/synth/BinkClip.h b/src/system/synth/BinkClip.h index d7a1d467..3a9d68e2 100644 --- a/src/system/synth/BinkClip.h +++ b/src/system/synth/BinkClip.h @@ -1,12 +1,72 @@ #ifndef SYNTH_BINKCLIP_H #define SYNTH_BINKCLIP_H - #include "obj/Object.h" #include "synth/Pollable.h" +#include "synth/Faders.h" +#include "synth/StandardStream.h" #include "utl/FilePath.h" class BinkClip : public Hmx::Object, public SynthPollable { - FilePath mFilePath; +public: + struct PanInfo { + PanInfo(int, float); + int chan; + float pan; + }; + + BinkClip(); + virtual ~BinkClip(); + OBJ_CLASSNAME(BinkClip); + OBJ_SET_TYPE(BinkClip); + virtual DataNode Handle(DataArray*, bool); + virtual bool SyncProperty(DataNode&, DataArray*, int, PropOp); + virtual void Save(BinStream&); + virtual void Copy(const Hmx::Object*, Hmx::Object::CopyType); + virtual void Load(BinStream&); + virtual void PreLoad(BinStream&); + virtual void PostLoad(BinStream&); + virtual void SynthPoll(); + + void KillStream(); + void UnloadData(); + void Stop(); + void LoadFile(BinStream*); + bool EnsureLoaded(); + void Play(); + void Pause(bool); + void SetLoop(bool); + void UpdateVolume(); + void UpdateFaders(); + void UpdatePanInfo(); + bool IsStreaming() const; + void SetFile(const char*); + void SetVolume(float); + void AddFader(Fader*); + void RemoveFader(Fader*); + void SetPan(int, float); + void FadeOut(float); + void UnloadWhenFinishedPlaying(bool); + bool IsReadyToPlay() const; + + NEW_OVERLOAD; + DELETE_OVERLOAD; + + FilePath mFile; // 0x28 + float mVolume; // 0x34 + bool mLoop; // 0x38 + bool mPreload; // 0x39 + StandardStream* mStream; // 0x3c + float mPlaybackVolumeOffset; // 0x40 + void* mData; // 0x44 + int mSize; // 0x48 + FileLoader* mLoader; // 0x4c + std::vector mFaders; // 0x50 + std::vector mPanInfo; // 0x58 + Fader* mFadeOutFader; // 0x60 + bool mFadingOut; // 0x64 + bool mUnloadWhenFinishedPlaying; // 0x65 + bool mPlaying; // 0x66 + Loader* mStreamLoader; // 0x68 }; #endif // SYNTH_BINKCLIP_H \ No newline at end of file diff --git a/src/system/synth/BinkReader.cpp b/src/system/synth/BinkReader.cpp new file mode 100644 index 00000000..f22c3c6f --- /dev/null +++ b/src/system/synth/BinkReader.cpp @@ -0,0 +1,5 @@ +#include "synth/BinkReader.h" + +BinkReader::BinkReader(File* f, StandardStream* s){ + +} \ No newline at end of file diff --git a/src/system/synth/BinkReader.h b/src/system/synth/BinkReader.h new file mode 100644 index 00000000..d306822f --- /dev/null +++ b/src/system/synth/BinkReader.h @@ -0,0 +1,45 @@ +#ifndef SYNTH_BINKREADER_H +#define SYNTH_BINKREADER_H +#include "utl/BINK.h" +#include "os/File.h" +#include "synth/StandardStream.h" +#include "synth/StreamReader.h" + +enum BinkReaderState { + kOpenBink = 0, + kOpenTracks = 1, + kInitStream = 2, + kPlay = 3, + kDone = 4, + kFailure = 5, +}; + +class BinkReader : public StreamReader { +public: + BinkReader(File*, StandardStream*); + virtual ~BinkReader(); + virtual void Poll(float); + virtual void Seek(int); + virtual void EnableReads(bool); + virtual bool Done(); + virtual bool Fail(); + virtual void Init(); + + static int sHeap; + static int mPlaying; + + File* mFile; // 0x4 + StandardStream* mStream; // 0x8 + BINK* mBink; // 0xc + BINKTRACK* mBinkTracks[16]; // 0x10 + unsigned char* mPCMBuffers[16]; // 0x50 + unsigned char* mPCMOffsets[16]; // 0x90 + unsigned char mDecodeTrack; // 0xd0 + int mSamplesReady; // 0xd4 + unsigned int mSampleCurrent; // 0xd8 + int mSamplesJump; // 0xdc + BinkReaderState mState; // 0xe0 + int mHeap; // 0xe4 +}; + +#endif \ No newline at end of file diff --git a/src/system/synth/MetaMusic.cpp b/src/system/synth/MetaMusic.cpp new file mode 100644 index 00000000..b513d254 --- /dev/null +++ b/src/system/synth/MetaMusic.cpp @@ -0,0 +1,31 @@ +#include "synth/MetaMusic.h" + +MetaMusic::MetaMusic(const char* cc) : mStream(0), mLoop(0), mFadeTime(1.0f), mVolume(0), mPlayFromBuffer(1), mRndHeap(0), mBufferH(0), + mBuf(0), mFile(0), mBufSize(0), mBytesRead(0), mExtraFaders(this, kObjListNoNull), mLoader(0), unk78(0), unk88(cc), unk8c(1) { + mFader = Hmx::Object::New(); + mFaderMute = Hmx::Object::New(); +} + +MetaMusic::~MetaMusic(){ + delete mStream; + mStream = 0; + UnloadStreamFx(); + delete mFile; + mFile = 0; + delete mLoader; + mLoader = 0; + if(mRndHeap){ + if(mBufferH){ + mBufferH->Unlock(); + MemFreeH(mBufferH); + mBufferH = 0; + } + mBuf = 0; + } + else if(mBuf){ + _MemFree(mBuf); + mBuf = 0; + } + delete mFader; + delete mFaderMute; +} \ No newline at end of file diff --git a/src/system/synth/MetaMusic.h b/src/system/synth/MetaMusic.h new file mode 100644 index 00000000..b425892c --- /dev/null +++ b/src/system/synth/MetaMusic.h @@ -0,0 +1,54 @@ +#ifndef SYNTH_METAMUSIC_H +#define SYNTH_METAMUSIC_H +#include "obj/Object.h" +#include "synth/Faders.h" +#include "synth/Stream.h" +#include "utl/MemMgr.h" +#include "utl/Loader.h" + +class MetaMusicLoader : public Loader { +public: + MetaMusicLoader(File*, int&, unsigned char*, int); + virtual ~MetaMusicLoader(){} + virtual const char* DebugText(){ return "MetaMusicLoader"; } + virtual bool IsLoaded() const; + virtual const char* StateName() const { return "MetaMusicLoader"; } + virtual void PollLoading(); +}; + +class MetaMusic : public Hmx::Object { +public: + MetaMusic(const char*); + virtual ~MetaMusic(); + virtual DataNode Handle(DataArray*, bool); + + void UnloadStreamFx(); + + Stream* mStream; // 0x1c + bool mLoop; // 0x20 + float mFadeTime; // 0x24 + float mVolume; // 0x28 + bool mPlayFromBuffer; // 0x2c + bool mRndHeap; // 0x2d + String mFilename; // 0x30 + MemHandle* mBufferH; // 0x3c + unsigned char* mBuf; // 0x40 + File* mFile; // 0x44 + Symbol mExt; // 0x48 + int mBufSize; // 0x4c + int mBytesRead; // 0x50 + Fader* mFader; // 0x54 + Fader* mFaderMute; // 0x58 + ObjPtrList mExtraFaders; // 0x5c + MetaMusicLoader* mLoader; // 0x6c + std::vector > unk70; + bool unk78; + int unk7c; + int unk80; + int unk84; + const char* unk88; + bool unk8c; + std::vector unk90; +}; + +#endif \ No newline at end of file diff --git a/src/system/synth/MidiInstrument.cpp b/src/system/synth/MidiInstrument.cpp index c20a4ade..34c61e58 100644 --- a/src/system/synth/MidiInstrument.cpp +++ b/src/system/synth/MidiInstrument.cpp @@ -1,5 +1,82 @@ #include "synth/MidiInstrument.h" #include "synth/Synth.h" +#include "synth/SampleInst.h" +#include "math/Decibels.h" +#include "synth/Utl.h" +#include "utl/Symbols.h" + +NoteVoiceInst::NoteVoiceInst(MidiInstrument* minst, SampleZone* zone, unsigned char uc1, unsigned char uc2, int i1, int i2, float f) : + mSample(0), mVolume(0), mStartProgress(0), mTriggerNote(uc1), mCenterNote(zone->mCenterNote), mStarted(0), mStopped(0), mGlideID(i2), mGlideFrames(0), + mGlideToNote(0), mGlideFromNote(0), mGlideFramesLeft(-1), mFineTune(f), mDurationFramesLeft(i1), mOwner(minst) { + if(zone->mSample){ + mSample = zone->mSample->NewInst(); + mSample->SetBankVolume(zone->mVolume + RatioToDb(uc2 / 127.0f)); + mSample->SetBankPan(zone->mPan); + mSample->SetBankSpeed(CalcSpeedFromTranspose(mFineTune / 100.0f + (mTriggerNote - mCenterNote))); + mSample->SetFXCore(zone->mFXCore); + mSample->SetADSR(zone->mADSR); + mSample->SetSend(minst->mSend); + } +} + +NoteVoiceInst::~NoteVoiceInst(){ + delete mSample; + mSample = 0; +} + +void NoteVoiceInst::Start(){ + mStarted = true; + mSample->SetStartProgress(mStartProgress); + mSample->Start(); +} + +void NoteVoiceInst::Stop(){ + mStopped = true; + mSample->Stop(); +} + +bool NoteVoiceInst::IsRunning(){ + return mSample->IsPlaying(); +} + +void NoteVoiceInst::Pause(bool b){ + mSample->Pause(b); +} + +void NoteVoiceInst::SetSend(FxSend* send){ + mSample->SetSend(send); +} + +void NoteVoiceInst::SetReverbMixDb(float f){ + mSample->SetReverbMixDb(f); +} + +void NoteVoiceInst::SetReverbEnable(bool b){ + mSample->SetReverbEnable(b); +} + +void NoteVoiceInst::SetSpeed(float f){ + mSample->SetSpeed(f); +} + +void NoteVoiceInst::SetTranspose(float f){ + SetSpeed(CalcSpeedFromTranspose(f)); +} + +void NoteVoiceInst::SetVolume(float f){ + mVolume = f; + UpdateVolume(); +} + +void NoteVoiceInst::UpdateVolume(){ + mSample->SetVolume(mVolume + mOwner->mFaders.GetVal()); +} + +void NoteVoiceInst::SetPan(float f){ + mSample->SetPan(f); +} + +DECOMP_FORCEFUNC(MidiInstrument, SampleInst, GetProgress()) MidiInstrument::MidiInstrument() : mMultiSampleMap(this), mPatchNumber(0), mSend(this, 0), mReverbMixDb(-96.0f), mReverbEnable(0), mActiveVoices(this, kObjListNoNull), mFaders(this), mFineTuneCents(0.0f) { @@ -24,6 +101,34 @@ void MidiInstrument::Poll(){ } } +BEGIN_HANDLERS(MidiInstrument) + HANDLE_ACTION(add_map, mMultiSampleMap.push_back(SampleZone(this))); + HANDLE_SUPERCLASS(Hmx::Object) + HANDLE_CHECK(0xFE) +END_HANDLERS + +BEGIN_CUSTOM_PROPSYNC(SampleZone) + SYNC_PROP(sample, o.mSample) + SYNC_PROP(volume, o.mVolume) + SYNC_PROP(pan, o.mPan) + SYNC_PROP(centernote, o.mCenterNote) + SYNC_PROP(minnote, o.mMinNote) + SYNC_PROP(maxnote, o.mMaxNote) + SYNC_PROP(minvelo, o.mMinVel) + SYNC_PROP(maxvelo, o.mMaxVel) + SYNC_PROP(fx_core, (int&)o.mFXCore) + SYNC_PROP(adsr, o.mADSR) +END_CUSTOM_PROPSYNC + +BEGIN_PROPSYNCS(MidiInstrument) + SYNC_PROP(multisamplemaps, mMultiSampleMap) + SYNC_PROP_SET(send, mSend, SetSend(_val.Obj(0))) + SYNC_PROP_SET(reverb_mix_db, mReverbMixDb, SetReverbMixDb(_val.Float(0))) + SYNC_PROP_SET(reverb_enable, mReverbEnable, SetReverbEnable(_val.Int(0))) + SYNC_PROP(faders, mFaders) + SYNC_PROP(patchnum, mPatchNumber) +END_PROPSYNCS + SAVE_OBJ(MidiInstrument, 0x125) BEGIN_LOADS(MidiInstrument) @@ -42,4 +147,100 @@ BEGIN_LOADS(MidiInstrument) bs >> mReverbEnable; } } -END_LOADS \ No newline at end of file +END_LOADS + +BEGIN_COPYS(MidiInstrument) + COPY_SUPERCLASS(Hmx::Object) + CREATE_COPY(MidiInstrument) + BEGIN_COPYING_MEMBERS + if(ty != kCopyFromMax) COPY_MEMBER(mMultiSampleMap) + COPY_MEMBER(mSend) + COPY_MEMBER(mPatchNumber) + COPY_MEMBER(mReverbMixDb) + COPY_MEMBER(mReverbEnable) + END_COPYING_MEMBERS +END_COPYS + +void MidiInstrument::PressNote(unsigned char uc1, unsigned char uc2, int i, int j){ + if(i != -1){ + bool b = false; + for(ObjPtrList::iterator it = mActiveVoices.begin(); it != mActiveVoices.end(); ++it){ + if(i == (*it)->mGlideID && !(*it)->Stopped()){ + b = true; + (*it)->GlideToNote(uc1, j); + (*it)->SetFineTune(mFineTuneCents); + } + } + if(b) return; + } + StartSample(uc1, uc2, -1, i); +} + +void MidiInstrument::ReleaseNote(unsigned char uc){ + for(ObjPtrList::iterator it = mActiveVoices.begin(); it != mActiveVoices.end(); ++it){ + if(uc == (*it)->mTriggerNote){ + (*it)->Stop(); + } + } +} + +void MidiInstrument::PlayNote(unsigned char uc1, unsigned char uc2, int i){ + StartSample(uc1, uc2, i, -1); +} + +void MidiInstrument::SetReverbMixDb(float f){ + mReverbMixDb = f; + for(ObjPtrList::iterator it = mActiveVoices.begin(); it != mActiveVoices.end(); ++it){ + (*it)->SetReverbMixDb(mReverbMixDb); + } +} + +void MidiInstrument::SetReverbEnable(bool b){ + mReverbEnable = b; + for(ObjPtrList::iterator it = mActiveVoices.begin(); it != mActiveVoices.end(); ++it){ + (*it)->SetReverbEnable(mReverbEnable); + } +} + +void MidiInstrument::StartSample(unsigned char uc1, unsigned char uc2, int i, int j){ + for(int x = 0; x < mMultiSampleMap.size(); x++){ + SampleZone* thisZone = &mMultiSampleMap[x]; + if(thisZone->Includes(uc1, uc2)){ + NoteVoiceInst* newInst = MakeNoteInst(thisZone, uc1, uc2, i, j); + mActiveVoices.push_back(newInst); + newInst->Start(); + } + } +} + +void MidiInstrument::KillAllVoices(){ + while(!mActiveVoices.empty()){ + NoteVoiceInst* front = mActiveVoices.front(); + mActiveVoices.pop_front(); + delete front; + } +} + +void MidiInstrument::SetSend(FxSend* send){ + mSend = send; + for(ObjPtrList::iterator it = mActiveVoices.begin(); it != mActiveVoices.end(); ++it){ + (*it)->SetSend(mSend); + } +} + +NoteVoiceInst* MidiInstrument::MakeNoteInst(SampleZone* zone, unsigned char uc1, unsigned char uc2, int i, int j){ + NoteVoiceInst* inst = new NoteVoiceInst(this, zone, uc1, uc2, i, j, mFineTuneCents); + inst->UpdateVolume(); + return inst; +} + +void MidiInstrument::Pause(bool b){ + for(ObjPtrList::iterator it = mActiveVoices.begin(); it != mActiveVoices.end(); ++it){ + (*it)->Pause(b); + } +} + +void MidiInstrument::SetFineTune(float cents){ + MILO_ASSERT(( -100.f) <= (cents) && (cents) < ( 100.f), 0x1F9); + mFineTuneCents = cents; +} \ No newline at end of file diff --git a/src/system/synth/MidiInstrument.h b/src/system/synth/MidiInstrument.h index 7a7ae5d7..fef91c19 100644 --- a/src/system/synth/MidiInstrument.h +++ b/src/system/synth/MidiInstrument.h @@ -18,14 +18,22 @@ class NoteVoiceInst : public Hmx::Object { virtual void Start(); virtual void Stop(); virtual bool IsRunning(); - virtual bool Started(); - virtual bool Stopped(); + virtual bool Started(){ return mStarted; } + virtual bool Stopped(){ return mStopped; } virtual void SetTranspose(float); virtual void UpdateVolume(); virtual void SetPan(float); virtual void SetVolume(float); void Poll(); + void Pause(bool); + void SetSend(FxSend*); + void SetReverbMixDb(float); + void SetReverbEnable(bool); + void SetSpeed(float); + void GlideToNote(unsigned char, int); + void SetFineTune(float); + void KillAllVoices(); NEW_POOL_OVERLOAD(NoteVoiceInst) DELETE_POOL_OVERLOAD(NoteVoiceInst) @@ -60,7 +68,20 @@ class MidiInstrument : public Hmx::Object { virtual void Load(BinStream&); void Poll(); + void Pause(bool); + void SetFineTune(float); void KillAllVoices(); + void SetSend(FxSend*); + void SetReverbMixDb(float); + void SetReverbEnable(bool); + void PressNote(unsigned char, unsigned char, int, int); + void StartSample(unsigned char, unsigned char, int, int); + void ReleaseNote(unsigned char); + void PlayNote(unsigned char, unsigned char, int); + NoteVoiceInst* MakeNoteInst(SampleZone*, unsigned char, unsigned char, int, int); + + NEW_OVERLOAD; + DELETE_OVERLOAD; ObjVector mMultiSampleMap; // 0x1c int mPatchNumber; // 0x28 diff --git a/src/system/synth/SampleData.cpp b/src/system/synth/SampleData.cpp index 487fcc88..3dba0504 100644 --- a/src/system/synth/SampleData.cpp +++ b/src/system/synth/SampleData.cpp @@ -1,9 +1,14 @@ #include "synth/SampleData.h" +#include "os/PlatformMgr.h" +#include "utl/ChunkStream.h" +#include "utl/WaveFile.h" SampleDataAllocFunc SampleData::sAlloc = 0; SampleDataFreeFunc SampleData::sFree = 0; BinStream& operator>>(BinStream& bs, SampleMarker& m); +DECOMP_FORCEACTIVE(SampleData, __FILE__, "0") + void SampleData::SetAllocator(SampleDataAllocFunc a, SampleDataFreeFunc f){ sAlloc = a; sFree = f; @@ -21,21 +26,75 @@ void SampleData::Load(BinStream& bs, const FilePath& fp){ Reset(); int rev; bs >> rev; - if(rev < 0xF){ + if(rev > 0xE){ + if(rev - 0x3e9U <= 0x24606){ + MILO_LOG("%s: loading old cached sample\n", fp); + mSampleRate = rev; + bs >> mSizeBytes; + mFormat = kBigEndPCM; + mNumSamples = mSizeBytes / 2; + mData = sAlloc(mSizeBytes, fp.c_str()); + MILO_ASSERT(!((uint)mData & 31), 0x6A); + bs.Read(mData, mSizeBytes); + } + else MILO_WARN("can't load new SampleData: %s", fp); + } + else { int fmt; bs >> fmt >> mNumSamples >> mSampleRate >> mSizeBytes; bool b = true; mFormat = (Format)fmt; - if(rev > 10){ + if(rev >= 0xB){ bs >> b; } if(b){ - // platformmgr + if(ThePlatformMgr.mEnableSFX){ + mData = sAlloc(mSizeBytes, fp.c_str()); + ReadChunks(bs, mData, mSizeBytes, 0x8000); + } + else { + bs.Seek(mSizeBytes, BinStream::kSeekCur); + mNumSamples = 0; + mSizeBytes = 0; + mData = 0; + } } - if(rev > 0xD) bs >> mMarkers; + if(rev >= 0xE) bs >> mMarkers; } } +// https://decomp.me/scratch/XPqxP +void SampleData::LoadWAV(BinStream& bs, const FilePath& fp){ + Reset(); + WaveFile wav(bs); + if(wav.NumChannels() != 1){ + MILO_WARN("Wave file %s has multiple channels", fp); + return; + } + else if(wav.BitsPerSample() != 0x10){ + MILO_WARN("Wave file %s is not 16-bit", fp); + return; + } + else if(wav.Format() != 1){ + MILO_WARN("Wave file %s is compressed", fp); + return; + } + else { + mFormat = kPCM; + mNumSamples = wav.NumSamples(); + mSampleRate = wav.SamplesPerSec(); + mSizeBytes = SizeAs(kPCM); + mData = sAlloc(mSizeBytes, fp.c_str()); + WaveFileData wavdata(wav); + wavdata.Read(mData, mSizeBytes); + for(int i = 0; i < wav.NumMarkers(); i++){ + mMarkers.push_back(SampleMarker(wav.mMarkers[i].mName, wav.mMarkers[i].mFrame)); + } + } +} + +DECOMP_FORCEACTIVE(SampleData, "size % 192 == 0") + void SampleData::Reset(){ sFree(mData); mData = 0; @@ -46,6 +105,33 @@ void SampleData::Reset(){ mMarkers.clear(); } +int SampleData::SizeAs(Format fmt) const { + switch(fmt){ + case kPCM: + return mNumSamples * 2; + case kBigEndPCM: + return mNumSamples * 2; + case kVAG: + int tmp = (mNumSamples + 0x6F) / 0x70 + (mNumSamples + 0x6F >> 0x1F); + return (tmp - (tmp >> 0x1F)) * 0x40; + case kATRAC: + int tmpa = mNumSamples + 0x3FF; + return (tmpa >> 10) + (tmpa < 0 && (tmpa & 0x3FF) != 0) * 0xC0; + case kMP3: + int tmpm = mNumSamples + 0x3FF; + return (tmpm >> 10) + (tmpm < 0 && (tmpm & 0x3FF) != 0) * 0xC0; + case kXMA: + MILO_WARN("don't know size as XMA"); + int tmpx = mNumSamples / 5 + (mNumSamples >> 0x1F); + return tmpx - (tmpx >> 0x1F); + case kNintendoADPCM: + return ((mNumSamples * 2) / 3.4f) + 0x60; + default: + MILO_ASSERT(0, 0x136); + return 0; + } +} + int SampleData::NumMarkers() const { return mMarkers.size(); } const SampleMarker& SampleData::GetMarker(int i) const { return mMarkers[i]; } diff --git a/src/system/synth/SampleData.h b/src/system/synth/SampleData.h index dfbb0c02..9105e409 100644 --- a/src/system/synth/SampleData.h +++ b/src/system/synth/SampleData.h @@ -7,6 +7,7 @@ struct SampleMarker { SampleMarker() : name(""), sample(-1) {} + SampleMarker(const String& str, int i) : name(str), sample(i) {} String name; int sample; diff --git a/src/system/synth/SampleZone.cpp b/src/system/synth/SampleZone.cpp index 0838cc26..cd0a3236 100644 --- a/src/system/synth/SampleZone.cpp +++ b/src/system/synth/SampleZone.cpp @@ -2,7 +2,7 @@ int SampleZone::gRev = 0; -SampleZone::SampleZone(Hmx::Object* obj) : mSynthPtr(obj, 0), unkc(0.0f), unk10(0.0f), unk14(0x24), unk18(0), unk1c(0x7f), unk20(0), unk24(0x7f), unk28(-1) { +SampleZone::SampleZone(Hmx::Object* obj) : mSample(obj, 0), mVolume(0.0f), mPan(0.0f), mCenterNote(0x24), mMinNote(0), mMaxNote(0x7f), mMinVel(0), mMaxVel(0x7f), mFXCore(kFXCoreNone) { } @@ -12,19 +12,19 @@ BinStream& operator>>(BinStream& bs, SampleZone& zone){ } void SampleZone::Load(BinStream& bs){ - bs >> mSynthPtr; - bs >> unkc >> unk10 >> unk14 >> unk18 >> unk1c; + bs >> mSample; + bs >> mVolume >> mPan >> mCenterNote >> mMinNote >> mMaxNote; int num; bs >> num; - unk28 = num; - bs >> adsr; + mFXCore = (FXCore)num; + bs >> mADSR; if(gRev >= 2){ - bs >> unk20 >> unk24; + bs >> mMinVel >> mMaxVel; } } bool SampleZone::Includes(unsigned char uc1, unsigned char uc2){ bool ret = false; - if(unk18 <= uc1 && uc1 <= unk1c && unk20 <= uc2 && uc2 <= unk24) ret = true; + if(mMinNote <= uc1 && uc1 <= mMaxNote && mMinVel <= uc2 && uc2 <= mMaxVel) ret = true; return ret; } \ No newline at end of file diff --git a/src/system/synth/SampleZone.h b/src/system/synth/SampleZone.h index 801f638e..972fb4df 100644 --- a/src/system/synth/SampleZone.h +++ b/src/system/synth/SampleZone.h @@ -4,6 +4,7 @@ #include "synth/SynthSample.h" #include "obj/ObjPtr_p.h" #include "synth/ADSR.h" +#include "synth/SampleInst.h" class SampleZone { public: @@ -13,18 +14,19 @@ class SampleZone { static int gRev; - ObjPtr mSynthPtr; - float unkc; - float unk10; - int unk14; - int unk18; - int unk1c; - int unk20; - int unk24; - int unk28; - ADSR adsr; + ObjPtr mSample; // 0x0 + float mVolume; // 0xc + float mPan; // 0x10 + int mCenterNote; // 0x14 + int mMinNote; // 0x18 + int mMaxNote; // 0x1c + int mMinVel; // 0x20 + int mMaxVel; // 0x24 + FXCore mFXCore; // 0x28 + ADSR mADSR; // 0x2c }; BinStream& operator>>(BinStream&, SampleZone&); +bool PropSync(SampleZone&, DataNode&, DataArray*, int, PropOp); #endif diff --git a/src/system/ui/UIProxy.cpp b/src/system/ui/UIProxy.cpp index 75f99459..0937ab9b 100644 --- a/src/system/ui/UIProxy.cpp +++ b/src/system/ui/UIProxy.cpp @@ -19,10 +19,10 @@ void UIProxy::SetTypeDef(DataArray* da){ if(da){ da->FindData("sync_on_move", mSyncOnMove, false); DataArray* fileArr = da->FindArray("file", false); - if(TheLoadMgr.EditMode() && fileArr->Size() != 3 || fileArr->Int(2) != 0){ + if(TheLoadMgr.EditMode() || fileArr->Size() != 3 || fileArr->Int(2) != 0){ bool shared = true; da->FindData("share", shared, false); - FilePath fp(FileGetPath(da->File(), 0), da->Str(1)); + FilePath fp(FileGetPath(da->File(), 0), fileArr->Str(1)); mDir.LoadFile(fp, Loading(), shared, kLoadFront, false); mPolled = false; if(!Loading()) UpdateDir(); @@ -98,9 +98,7 @@ RndDrawable* UIProxy::CollideShowing(const Segment& seg, float& f, Plane& pl){ if(!mDir.Ptr()) return 0; else { SyncDir(); - RndDrawable* d = mDir->CollideShowing(seg, f, pl); - if(d) return d; - else return 0; + return mDir->CollideShowing(seg, f, pl) ? this : 0; } } @@ -129,8 +127,8 @@ void UIProxy::SetProxyDir(RndDir* dir){ // fn_80575E54 void UIProxy::SyncDir(){ const Transform& world = WorldXfm(); - if(mSyncOnMove){ - // operator==/!= called here + if(mSyncOnMove && !TheLoadMgr.EditMode()){ + if(world == mOldXfm) return; mOldXfm = world; } if(mMainTrans) mMainTrans->SetWorldXfm(world); @@ -143,14 +141,17 @@ void UIProxy::SyncDir(){ // fn_80576014 void UIProxy::UpdateDir(){ - DataArray* transArr = mTypeDef->FindArray("main_trans", false); - if(transArr && mDir.Ptr()){ - mMainTrans = mDir->Find(transArr->Str(1), true); - } - else { - if(!mDir.Ptr()) MILO_WARN("%s Couldn't load main_trans", PathName(this)); - mMainTrans = 0; + DataArray* transArr = TypeDef()->FindArray("main_trans", false); + if(transArr){ + if(mDir.Ptr()){ + mMainTrans = mDir->Find(transArr->Str(1), true); + } + else { + MILO_WARN("%s Couldn't load main_trans", PathName(this)); + mMainTrans = 0; + } } + else mMainTrans = 0; UpdateSphere(); if(mDir.Ptr()){ mDir->Enter(); diff --git a/src/system/utl/BINK.h b/src/system/utl/BINK.h index a33d60ae..907eb9d5 100644 --- a/src/system/utl/BINK.h +++ b/src/system/utl/BINK.h @@ -277,4 +277,15 @@ struct BINKSUMMARY { unsigned int Highest1SecFrame; // offset 0x78, size 0x4 }; +struct BINKTRACK { + // total size: 0x1C + unsigned int Frequency; // offset 0x0, size 0x4 + unsigned int Bits; // offset 0x4, size 0x4 + unsigned int Channels; // offset 0x8, size 0x4 + unsigned int MaxSize; // offset 0xC, size 0x4 + struct BINK * bink; // offset 0x10, size 0x4 + unsigned int sndcomp; // offset 0x14, size 0x4 + int trackindex; // offset 0x18, size 0x4 +}; + #endif diff --git a/src/system/utl/Loader.h b/src/system/utl/Loader.h index b98839e8..8bd8ccf1 100644 --- a/src/system/utl/Loader.h +++ b/src/system/utl/Loader.h @@ -51,8 +51,8 @@ class LoadMgr { void SetEditMode(bool); void Init(); Loader* ForceGetLoader(const FilePath&); - inline bool EditMode() const { return mEditMode; } - inline Platform GetPlatform() const { return (Platform)mPlatform; } + bool EditMode() const { return mEditMode; } + Platform GetPlatform() const { return (Platform)mPlatform; } int AsyncUnload() const { return unk58; } static const char* LoaderPosString(LoaderPos, bool); diff --git a/src/system/utl/MakeString.cpp b/src/system/utl/MakeString.cpp index 3ee57246..dbde72d5 100644 --- a/src/system/utl/MakeString.cpp +++ b/src/system/utl/MakeString.cpp @@ -66,7 +66,7 @@ static char* NextBuf(){ void InitMakeString(){ if(gLock == 0){ - gLock = new (_PoolAlloc(0x1C, 0x1C, FastPool)) CriticalSection(); + gLock = new CriticalSection(); gBuf = (char***)_MemAlloc(0x18, 0); for(int i3 = 0, i5 = 0; i3 < 6; i3++, i5++){ gBuf[i5] = (char**)_MemAlloc(0x28, 0); diff --git a/src/system/utl/MemMgr.h b/src/system/utl/MemMgr.h index fead1ec4..51355d4b 100644 --- a/src/system/utl/MemMgr.h +++ b/src/system/utl/MemMgr.h @@ -9,6 +9,15 @@ class MemDoTempAllocations { ~MemDoTempAllocations(); }; +class MemHandle { +public: + MemHandle(void*); + void Lock(); + void Unlock(); +}; + +void MemFreeH(MemHandle*); + void* operator new(size_t) throw(); void operator delete(void*) throw(); void* operator new[](size_t) throw(); diff --git a/src/system/utl/SongInfoCopy.cpp b/src/system/utl/SongInfoCopy.cpp index 58c1fb9d..89362257 100644 --- a/src/system/utl/SongInfoCopy.cpp +++ b/src/system/utl/SongInfoCopy.cpp @@ -33,10 +33,10 @@ SongInfoCopy::SongInfoCopy(const SongInfo* info) : mName(), mBaseFileName(), mPa mDrumSoloSamples = info->GetDrumSoloSamples(); mDrumFreestyleSamples = info->GetDrumFreestyleSamples(); mTrackChannels = info->GetTracks(); - int midifilenum = NumExtraMidiFiles(); + int midifilenum = info->NumExtraMidiFiles(); mExtraMidiFiles.reserve(midifilenum); for(int i = 0; i < midifilenum; i++){ - mExtraMidiFiles.push_back(String(GetExtraMidiFile(midifilenum))); + mExtraMidiFiles.push_back(info->GetExtraMidiFile(i)); } } @@ -85,18 +85,19 @@ bool SongInfoCopy::IsPlayTrackChannel(int chan) const { return false; } -// this is wrong -const std::vector& SongInfoCopy::FindTrackChannel(SongInfoAudioType ty) const { +const TrackChannels* SongInfoCopy::FindTrackChannel(SongInfoAudioType ty) const { for(int i = 0; i < mTrackChannels.size(); i++){ - if(i == (int)ty){ - return mTrackChannels[i].mChannels; - } + if(mTrackChannels[i].mAudioType == ty){ + return &mTrackChannels[i]; + } } + return 0; } -// also wrong int SongInfoCopy::NumChannelsOfTrack(SongInfoAudioType ty) const { - const std::vector& vec = FindTrackChannel(ty); + const TrackChannels* tc = FindTrackChannel(ty); + if(tc) return tc->mChannels.size(); + else return 0; } int SongInfoCopy::TrackIndex(SongInfoAudioType ty) const { diff --git a/src/system/utl/SongInfoCopy.h b/src/system/utl/SongInfoCopy.h index 0567a488..0096cb8b 100644 --- a/src/system/utl/SongInfoCopy.h +++ b/src/system/utl/SongInfoCopy.h @@ -28,7 +28,7 @@ class SongInfo { // TODO: fix the return types of these methods below as you implement them virtual const std::vector& GetTracks() const = 0; virtual bool IsPlayTrackChannel(int) const = 0; - virtual const TrackChannels& FindTrackChannel(SongInfoAudioType) const = 0; + virtual const TrackChannels* FindTrackChannel(SongInfoAudioType) const = 0; virtual int NumChannelsOfTrack(SongInfoAudioType) const = 0; virtual int TrackIndex(SongInfoAudioType) const = 0; @@ -58,7 +58,7 @@ class SongInfoCopy { // TODO: fix the return types of these methods below as you implement them virtual const std::vector& GetTracks() const; virtual bool IsPlayTrackChannel(int) const; - virtual const std::vector& FindTrackChannel(SongInfoAudioType) const; + virtual const TrackChannels* FindTrackChannel(SongInfoAudioType) const; virtual int NumChannelsOfTrack(SongInfoAudioType) const; virtual int TrackIndex(SongInfoAudioType) const; diff --git a/src/system/utl/WaveFile.cpp b/src/system/utl/WaveFile.cpp index b7b1693d..cd150630 100644 --- a/src/system/utl/WaveFile.cpp +++ b/src/system/utl/WaveFile.cpp @@ -1,5 +1,31 @@ #include "utl/WaveFile.h" +#include "utl/Chunks.h" +#include "os/Debug.h" +#include +namespace { + struct CuePoint { + CuePoint(int frame, int id) : mFrame(frame), mID(id) {} + // total size: 0x8 + int mFrame; // offset 0x0, size 0x4 + int mID; // offset 0x4, size 0x4 + }; + + struct Label { + Label(const String& s, int i) : mName(s), mID(i) {} + // total size: 0x10 + class String mName; // offset 0x0, size 0xC + int mID; // offset 0xC, size 0x4 + }; + + bool CompareCuePoints(const CuePoint& p1, const CuePoint& p2){ + return p1.mFrame < p2.mFrame; + } +} + +#define null 0 + +// fn_8037C29C WaveFile::WaveFile(BinStream& bs) : mMarkers(), mRiffList(bs, true) { ReadFormat(); ReadMarkers(); @@ -10,6 +36,88 @@ WaveFile::~WaveFile(){ } +void WaveFile::ReadFormat(){ + mRiffList.Reset(); + ChunkHeader* chunk = mRiffList.Next(kWaveFormatChunkID); + MILO_ASSERT(chunk != null, 0x6E); + IDataChunk dchunk(mRiffList); + dchunk >> mFormat; + dchunk >> mNumChannels; + dchunk >> mSamplesPerSec; + dchunk >> mAvgBytesPerSec; + dchunk >> mBlockAlign; + dchunk >> mBitsPerSample; + MILO_ASSERT(mAvgBytesPerSec == mSamplesPerSec * mBlockAlign, 0x78); + MILO_ASSERT(mBlockAlign == mNumChannels * mBitsPerSample / 8, 0x79); +} + +// fn_8037C860 - read markers +void WaveFile::ReadMarkers(){ + std::vector cuevec; + std::vector