Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,7 @@ set(GAME_FILES
extern/rstl/src/rstl/rstl_strings.cpp
src/Metaforce/ARAMToken.cpp
src/Metaforce/Alloc.cpp
src/Metaforce/Audio.cpp
src/Metaforce/CModelSectionReader.cpp
src/Metaforce/MapData.cpp
src/Metaforce/PathData.cpp
Expand Down
2 changes: 1 addition & 1 deletion extern/musyx
Submodule musyx updated 60 files
+26 −27 CMakeLists.txt
+10 −0 include/musyx/adsr.h
+11 −0 include/musyx/dspvoice.h
+39 −25 include/musyx/hardware.h
+5 −5 include/musyx/musyx.h
+91 −0 include/musyx/pc.h
+10 −1 include/musyx/platform.h
+7 −0 include/musyx/sal.h
+17 −10 include/musyx/seq.h
+11 −0 include/musyx/stream.h
+7 −0 include/musyx/synth.h
+21 −2 include/musyx/synthdata.h
+9 −2 include/musyx/txwin.h
+17 −5 include/musyx/voice.h
+19 −19 src/musyx/runtime/CheapReverb/creverb.c
+10 −10 src/musyx/runtime/CheapReverb/creverb_fx.c
+7 −3 src/musyx/runtime/Chorus/chorus_fx.c
+22 −22 src/musyx/runtime/Delay/delay_fx.c
+23 −23 src/musyx/runtime/StdReverb/reverb.c
+10 −10 src/musyx/runtime/StdReverb/reverb_fx.c
+4 −4 src/musyx/runtime/dsp_import.c
+119 −71 src/musyx/runtime/hardware.c
+123 −82 src/musyx/runtime/hw_aramdma.c
+32 −17 src/musyx/runtime/hw_dolphin.c
+150 −118 src/musyx/runtime/hw_dspctrl.c
+1 −1 src/musyx/runtime/hw_lib_dolphin.c
+20 −3 src/musyx/runtime/hw_memory.c
+555 −694 src/musyx/runtime/hw_pc.c
+665 −0 src/musyx/runtime/hw_pc_assets.c
+47 −0 src/musyx/runtime/hw_pc_assets.h
+107 −0 src/musyx/runtime/hw_pc_decode.c
+21 −0 src/musyx/runtime/hw_pc_decode.h
+41 −0 src/musyx/runtime/hw_pc_internal.h
+18 −0 src/musyx/runtime/hw_pc_null.c
+109 −0 src/musyx/runtime/hw_pc_output.c
+46 −0 src/musyx/runtime/hw_pc_rate.c
+130 −0 src/musyx/runtime/hw_pc_samples.c
+145 −0 src/musyx/runtime/hw_pc_sdl.c
+54 −0 src/musyx/runtime/hw_pc_song.c
+52 −0 src/musyx/runtime/hw_pc_vsample.c
+29 −6 src/musyx/runtime/hw_volconv.c
+35 −36 src/musyx/runtime/profile.c
+442 −79 src/musyx/runtime/s_data.c
+181 −88 src/musyx/runtime/seq.c
+14 −5 src/musyx/runtime/seq_api.c
+89 −89 src/musyx/runtime/snd3d.c
+35 −2 src/musyx/runtime/snd_init.c
+4 −5 src/musyx/runtime/snd_math.c
+38 −26 src/musyx/runtime/snd_midictrl.c
+9 −5 src/musyx/runtime/snd_service.c
+14 −14 src/musyx/runtime/snd_synthapi.c
+223 −121 src/musyx/runtime/stream.c
+110 −50 src/musyx/runtime/synth.c
+36 −36 src/musyx/runtime/synth_adsr.c
+134 −80 src/musyx/runtime/synth_vsamples.c
+104 −57 src/musyx/runtime/synthdata.c
+229 −145 src/musyx/runtime/synthmacros.c
+38 −31 src/musyx/runtime/synthvoice.c
+28 −22 src/musyx/txwin/txwin.c
+16 −13 test/main.c
20 changes: 20 additions & 0 deletions include/Kyoto/Audio/CStaticAudioPlayer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
#include <rstl/vector.hpp>

class CDvdRequest;
#if defined(TARGET_PC)
typedef void (*FAudioCallback)(short* output, size_t frames, u32 rate, u32 channels);
#else
typedef void (*FAudioCallback)();
#endif

class CStaticAudioPlayer {
public:
Expand All @@ -20,12 +24,21 @@ class CStaticAudioPlayer {
void StartMixOut();
void StopMixOut();

#if defined(TARGET_PC)
static void MixCallback(short* output, size_t frames, u32 rate, u32 channels);
void DoMix(short* output, size_t frames, u32 rate, u32 channels);
#else
static void MixCallback();
void DoMix();
#endif
static void RunDMACallback(FAudioCallback);
static void CancelDMACallback(FAudioCallback);
static void InstallAICallback();
#if defined(TARGET_PC)
static void AICallback(short* output, size_t frames, u32 rate, u32 channels);
#else
static void AICallback();
#endif

void Decode(const ushort* bufIn, ushort* bufOut, int numSamples);
void DecodeMonoAndMix(ushort* bufIn, ushort* bufOut, int numSamples,
Expand All @@ -48,6 +61,13 @@ class CStaticAudioPlayer {
g72x_state x58_leftState;
g72x_state x8c_rightState;
ushort xc0_volume;
#if defined(TARGET_PC)
u32 m_audioPhase = 0;
short m_audioHistory[2][2] = {};
short m_audioPair[4] = {};
u32 m_audioPairRead = 2;
bool m_audioPrimed = false;
#endif
};

#endif // _CSTATICAUDIOPLAYER
13 changes: 13 additions & 0 deletions include/Kyoto/Graphics/CMoviePlayer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,23 @@ class CMoviePlayer {
private:
struct SIndexLoad;
static void VerifyCallbackStatus();
#if defined(TARGET_PC)
static void StaticMyAudioCallback(short* output, size_t frames, u32 rate, u32 channels);
#else
static void StaticMyAudioCallback();
#endif
void InitializeTextures();
void ReadCompleted();
void PostDVDReadRequestIfNeeded();
CDvdFile x0_dvdFile;
THPHeader x28_header;
THPFrameCompInfo x58_thpComponents;
THPVideoInfoOld x6c_videoInfo;
#if defined(TARGET_PC)
THPAudioInfoOld x74_audioInfo{};
#else
THPAudioInfoOld x74_audioInfo;
#endif
rstl::vector< CTHPTextureSet > x80_textures;
rstl::auto_ptr< uchar > x90_requestBuffer;
rstl::single_ptr< CDvdRequest > x98_request;
Expand Down Expand Up @@ -168,6 +176,11 @@ class CMoviePlayer {
bool xf4_27_fieldFlip : 1;
uint xf8_cachedBytes;
int xfc_fieldIndex;
#if defined(TARGET_PC)
u32 m_audioPhase = 0;
short m_audioHistory[2][2] = {};
bool m_audioPrimed = false;
#endif
};
CHECK_SIZEOF(CMoviePlayer, 0x100)

Expand Down
34 changes: 34 additions & 0 deletions include/Metaforce/Audio.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

#include <musyx/pc.h>
#include <span>
#include <string_view>

struct dspadpcm_header;

namespace metaforce {
struct AudioGroupView {
std::string_view baseDirectory, name;
SND_PC_GROUP_ASSETS assets{};
};
struct AudioSongHeader {
u32 version, song, group, audioGroup, length;
};

void ConfigureAudio(SND_PC_CONFIG preferred, bool disabled);
void InitializeAudio(u8 voices, u8 music, u8 sfx, u32 flags);
void UpdateAudio();
void LockAudio();
void UnlockAudio();

struct AudioLockGuard {
AudioLockGuard() { LockAudio(); }
~AudioLockGuard() { UnlockAudio(); }
AudioLockGuard(const AudioLockGuard&) = delete;
AudioLockGuard& operator=(const AudioLockGuard&) = delete;
};

bool ReadAudioGroup(std::span< const u8 > bytes, AudioGroupView& result);
bool ReadAudioSongHeader(std::span< const u8 > bytes, AudioSongHeader& result);
bool ReadDSPHeader(std::span< const u8 > bytes, dspadpcm_header& result);
} // namespace metaforce
36 changes: 36 additions & 0 deletions src/Kyoto/Audio/CDSPStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
#include "dolphin/os.h"

#include <string.h>
#if defined(TARGET_PC)
#include "Metaforce/Audio.hpp"
#endif

static struct {
CDSPStream streams[4];
Expand Down Expand Up @@ -109,10 +112,37 @@ void CDSPStream::Initialize() {
}

void CDSPStream::FreeAllStreams() {
#if defined(TARGET_PC)
{
metaforce::AudioLockGuard lock;
for (auto& stream : g_Streams) {
stream.xe8_silenced = 1;
stream.xf0_stopRequested = 1;
if (stream.xc8_streamId != SND_ID_ERROR) sndStreamDeactivate(stream.xc8_streamId);
}
}
// DVD completion takes the same lock. Wait without holding it, and keep
// refill buffers alive until both requests and their callbacks have retired.
for (auto& stream : g_Streams) {
DVDCancel(&stream.x50_fileInfo1.cb);
DVDCancel(&stream.x8c_fileInfo2.cb);
}
metaforce::AudioLockGuard lock;
for (auto& stream : g_Streams) {
if (stream.x0_state != 0) stream.CloseFiles();
if (stream.xc8_streamId != SND_ID_ERROR) sndStreamFree(stream.xc8_streamId);
CMemory::Free(stream.xd4_buffer);
stream.xd4_buffer = nullptr;
stream.xc8_streamId = SND_ID_ERROR;
stream.x0_state = 0;
stream.x8_right = stream.xc_left = nullptr;
}
#else
for (uint i = 0; i < 4; ++i) {
sndStreamFree(g_Streams[i].xc8_streamId);
CMemory::Free(g_Streams[i].xd4_buffer);
}
#endif
}

uint CDSPStream::AllocateStream(const SStreamInfo& info, char vol, char pan) {
Expand Down Expand Up @@ -410,6 +440,9 @@ int CDSPStream::InitializeStream() {
}

void CDSPStream::ReadCompleted(s32, DVDFileInfo* fileInfo) {
#if defined(TARGET_PC)
metaforce::AudioLockGuard lock;
#endif
int idx = 0;
CDSPStream* s = g_Streams;
for (; idx < 4; ++idx, ++s) {
Expand All @@ -418,6 +451,9 @@ void CDSPStream::ReadCompleted(s32, DVDFileInfo* fileInfo) {
}
}

#if defined(TARGET_PC)
if (idx == 4) return;
#endif
CDSPStream& stream = g_Streams[idx];
stream.xec_readsPending--;
if (stream.xec_readsPending != 0) {
Expand Down
47 changes: 46 additions & 1 deletion src/Kyoto/Audio/CDSPStreamManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

#include <string.h>

#if defined(TARGET_PC)
#include "Metaforce/Audio.hpp"
#endif

CDSPStreamManager g_Streams[4] = {CDSPStreamManager(), CDSPStreamManager(), CDSPStreamManager(),
CDSPStreamManager()};
static int sHandleCounter;
Expand Down Expand Up @@ -64,14 +68,36 @@ bool CDSPStreamManager::StartHeaderRead(DVDCallback callback) {
return true;
}

bool CDSPStreamManager::HasSupportedSampleRate() { return x0_header.x8_sampleRate == 32000; }
bool CDSPStreamManager::HasSupportedSampleRate() {
#if defined(TARGET_PC)
return x0_header.x8_sampleRate > 0 && x0_header.x8_sampleRate <= 65535;
#else
return x0_header.x8_sampleRate == 32000;
#endif
}

void CDSPStreamManager::WaitForReadCompletion() {
#if defined(TARGET_PC)
BOOL ints = OSEnableInterrupts();
for (;;) {
bool complete;
{
metaforce::AudioLockGuard lock;
complete = x70_26_headerReadState != kHRS_Reading;
}
if (complete) {
OSRestoreInterrupts(ints);
return;
}
OSYieldThread();
}
#else
BOOL ints = OSEnableInterrupts();
while (x70_26_headerReadState == 1) {
OSYieldThread();
}
OSRestoreInterrupts(ints);
#endif
}

CDSPStreamManager& CDSPStreamManager::operator=(const CDSPStreamManager& other) {
Expand All @@ -88,6 +114,13 @@ void CDSPStreamManager::Initialize() {
}

void CDSPStreamManager::Shutdown() {
#if defined(TARGET_PC)
{
metaforce::AudioLockGuard lock;
for (auto& stream : g_Streams) stream.x70_25_headerReadCancelled = true;
}
for (auto& stream : g_Streams) stream.WaitForReadCompletion();
#endif
CDSPStream::FreeAllStreams();
for (int i = 0; i < 4; ++i) {
g_Streams[i] = CDSPStreamManager();
Expand Down Expand Up @@ -312,12 +345,24 @@ CDSPStreamManager::EState CDSPStreamManager::GetStreamState(int handle) {
}

void CDSPStreamManager::HeaderReadComplete(s32 result, DVDFileInfo* fileInfo) {
#if defined(TARGET_PC)
metaforce::AudioLockGuard lock;
#endif
DVDClose(fileInfo);

for (int idx = 0; idx < 4; ++idx) {
CDSPStreamManager* stream = &g_Streams[idx];
if (&stream->x80_dvdFile == fileInfo && !stream->x70_24_unclaimed) {
CInterruptGuard interrupts;
#if defined(TARGET_PC)
if (result != 0x60 || !metaforce::ReadDSPHeader(
{reinterpret_cast<const u8*>(&stream->x0_header), 0x60}, stream->x0_header) ||
fileInfo->length < 0x60 ||
(u64(stream->x0_header.x4_numNibbles) + 1) / 2 > fileInfo->length - 0x60) {
*stream = CDSPStreamManager();
return;
}
#endif
if (result <= 0 || !stream->HasSupportedSampleRate()) {
*stream = CDSPStreamManager();
return;
Expand Down
51 changes: 48 additions & 3 deletions src/Kyoto/Audio/CMidiManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,24 @@
#include <Kyoto/CFactoryFnReturn.hpp>
#include <Kyoto/Streams/CInputStream.hpp>

#if defined(TARGET_PC)
#include "Metaforce/Audio.hpp"
#include "Metaforce/Common.hpp"

namespace {
constexpr borealis::Log Log{"CMidiManager"};
}
#endif

rstl::reserved_vector< CMidiManager::CMidiWrapper, 3 > CMidiManager::mMidiWrappers;

CMidiManager::CMidiWrapper::CMidiWrapper() : x0_sysHandle(0), xa_available(true) {}
CMidiManager::CMidiWrapper::CMidiWrapper()
: x0_sysHandle(0)
#if defined(TARGET_PC)
, x8_songId(-1)
#endif
, xa_available(true) {
}

const CSfxHandle& CMidiManager::CMidiWrapper::GetManagerHandle() const { return x4_midiHandle; }

Expand Down Expand Up @@ -39,6 +54,11 @@ CSfxHandle CMidiManager::Play(const CMidiData& data, unsigned short fadeTime, bo
wrapper.SetMidiHandle(handle);
if (stopExisting) {
for (int i = 0; i < mMidiWrappers.size(); ++i) {
#if defined(TARGET_PC)
if (&mMidiWrappers[i] == &wrapper) {
continue;
}
#endif
if (mMidiWrappers[i].IsAvailable()) {
continue;
}
Expand All @@ -57,7 +77,14 @@ CSfxHandle CMidiManager::Play(const CMidiData& data, unsigned short fadeTime, bo
wrapper.SetAudioSysHandle(sysHandle);
wrapper.SetSongId(data.GetSongId());
} else {
u32 sysHandle = CAudioSys::SeqPlayEx(data.GetGroupId(), data.GetSongId(), data.GetData(), nullptr, 0);
u32 sysHandle =
CAudioSys::SeqPlayEx(data.GetGroupId(), data.GetSongId(), data.GetData(), nullptr, 0);
#if defined(TARGET_PC)
if (sysHandle == SND_ID_ERROR) {
wrapper.SetAvailable(true);
return {};
}
#endif
if (fadeTime != 0) {
CAudioSys::SeqVolume(0, 0, sysHandle, 0);
}
Expand Down Expand Up @@ -113,15 +140,33 @@ CSfxHandle CMidiManager::LocateHandle() {

CMidiManager::CMidiData::CMidiData(CInputStream& in)
: x0_songId(-1), x2_groupId(-1), x4_agscId(-1) {
#if defined(TARGET_PC)
u8 bytes[20];
metaforce::AudioSongHeader header{};
REQUIRE(in.ReadBytes(bytes, sizeof(bytes)) == sizeof(bytes) &&
metaforce::ReadAudioSongHeader(bytes, header),
"Invalid CSNG header");
x0_songId = header.song;
x2_groupId = header.group;
x4_agscId = header.audioGroup;
x8_data = rs_new uchar[header.length];
REQUIRE(in.ReadBytes(x8_data.get(), header.length) == header.length,
"Truncated CSNG arrangement");
SND_PC_ASSET_ERROR error{};
REQUIRE(sndPCValidateArrangement({x8_data.get(), header.length}, &error),
"Invalid CSNG arrangement at {}: {}", error.offset, error.reason ? error.reason : "");
#else
in.ReadLong();
x0_songId = in.ReadLong();
x2_groupId = in.ReadLong();
x4_agscId = in.ReadLong();
int len = in.ReadInt32();
x8_data = rs_new uchar[len];
in.Get(x8_data.get(), len);
#endif
}

const CFactoryFnReturn FMidiDataFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer&) {
const CFactoryFnReturn FMidiDataFactory(const SObjectTag& tag, CInputStream& in,
const CVParamTransfer&) {
return rs_new CMidiManager::CMidiData(in);
}
Loading
Loading