mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2026-04-27 12:31:47 +00:00
Threaded Audio Support (#176)
* Initial threaded audio. (WIP) * Ready for testing threaded audio. * Remove this, It causes issues on older gcc versions. * Fix Loading Thread not running properly. * Fix Loading Screen & Implementation Updates * Update comment. * Revamp Thread States
This commit is contained in:
parent
bf2d7b629e
commit
507f578dbb
16 changed files with 440 additions and 56 deletions
|
|
@ -2,12 +2,15 @@
|
|||
|
||||
#include "data.h"
|
||||
#include "effects.h"
|
||||
#include "src/pc/thread.h"
|
||||
|
||||
extern struct OSMesgQueue OSMesgQueue0;
|
||||
extern struct OSMesgQueue OSMesgQueue1;
|
||||
extern struct OSMesgQueue OSMesgQueue2;
|
||||
extern struct OSMesgQueue OSMesgQueue3;
|
||||
|
||||
struct ThreadHandle gAudioThread = { 0 };
|
||||
|
||||
#ifdef VERSION_EU
|
||||
struct ReverbSettingsEU sReverbSettings[] = {
|
||||
{ /*Downsample Rate*/ 0x04, /*Window Size*/ 0x0c, /*Gain*/ 0x2fff },
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "internal.h"
|
||||
#include "types.h"
|
||||
#include "src/pc/thread.h"
|
||||
|
||||
#define AUDIO_LOCK_UNINITIALIZED 0
|
||||
#define AUDIO_LOCK_NOT_LOADING 0x76557364
|
||||
|
|
@ -12,6 +13,8 @@
|
|||
|
||||
#define NUMAIBUFFERS 3
|
||||
|
||||
extern struct ThreadHandle gAudioThread;
|
||||
|
||||
// constant .data
|
||||
#if defined(VERSION_EU) || defined(VERSION_SH)
|
||||
extern struct AudioSessionSettingsEU gAudioSessionPresets[];
|
||||
|
|
|
|||
|
|
@ -58,31 +58,35 @@ void sequence_channel_process_sound(struct SequenceChannel *seqChannel, s32 reca
|
|||
}
|
||||
#else
|
||||
static void sequence_channel_process_sound(struct SequenceChannel *seqChannel) {
|
||||
if (seqChannel == NULL) { return; }
|
||||
|
||||
struct SequencePlayer *seqPlayer = seqChannel->seqPlayer;
|
||||
if (seqPlayer == NULL) { return; }
|
||||
|
||||
f32 channelVolume;
|
||||
f32 panLayerWeight;
|
||||
f32 panFromChannel;
|
||||
s32 i;
|
||||
|
||||
// Rom-hacks audio fix
|
||||
// Force the BGM sequence channels to follow the BGM sequence player mute behavior
|
||||
// Make the audio completely silent if MUTE_BEHAVIOR_STOP_SCRIPT or MUTE_BEHAVIOR_STOP_NOTES is set
|
||||
if (seqChannel->seqPlayer == &gSequencePlayers[0]) {
|
||||
seqChannel->muteBehavior = seqChannel->seqPlayer->muteBehavior;
|
||||
if (seqChannel->seqPlayer->muted && (seqChannel->muteBehavior & (MUTE_BEHAVIOR_STOP_SCRIPT | MUTE_BEHAVIOR_STOP_NOTES)) != 0) {
|
||||
seqChannel->seqPlayer->muteVolumeScale = 0.f;
|
||||
if (seqPlayer == &gSequencePlayers[0]) {
|
||||
seqChannel->muteBehavior = seqPlayer->muteBehavior;
|
||||
if (seqPlayer->muted && (seqChannel->muteBehavior & (MUTE_BEHAVIOR_STOP_SCRIPT | MUTE_BEHAVIOR_STOP_NOTES)) != 0) {
|
||||
seqPlayer->muteVolumeScale = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
channelVolume = seqChannel->volume * seqChannel->volumeScale *
|
||||
seqChannel->seqPlayer->fadeVolume * seqChannel->seqPlayer->volumeScale;
|
||||
if (seqChannel->seqPlayer->muted && (seqChannel->muteBehavior & MUTE_BEHAVIOR_SOFTEN) != 0) {
|
||||
channelVolume *= seqChannel->seqPlayer->muteVolumeScale;
|
||||
seqPlayer->fadeVolume * seqPlayer->volumeScale;
|
||||
if (seqPlayer->muted && (seqChannel->muteBehavior & MUTE_BEHAVIOR_SOFTEN) != 0) {
|
||||
channelVolume *= seqPlayer->muteVolumeScale;
|
||||
}
|
||||
|
||||
panFromChannel = seqChannel->pan * seqChannel->panChannelWeight;
|
||||
panLayerWeight = US_FLOAT(1.0) - seqChannel->panChannelWeight;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (s32 i = 0; i < 4; i++) {
|
||||
struct SequenceChannelLayer *layer = seqChannel->layers[i];
|
||||
if (layer != NULL && layer->enabled && layer->note != NULL) {
|
||||
layer->noteFreqScale = layer->freqScale * seqChannel->freqScale;
|
||||
|
|
|
|||
|
|
@ -835,21 +835,29 @@ void create_next_audio_buffer(s16 *samples, u32 num_samples) {
|
|||
extern f32 *smlua_get_vec3f_for_play_sound(f32 *pos);
|
||||
|
||||
void play_sound(s32 soundBits, f32 *pos) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
pos = smlua_get_vec3f_for_play_sound(pos);
|
||||
smlua_call_event_hooks_on_play_sound(HOOK_ON_PLAY_SOUND, soundBits, pos, &soundBits);
|
||||
sSoundRequests[sSoundRequestCount].soundBits = soundBits;
|
||||
sSoundRequests[sSoundRequestCount].position = pos;
|
||||
sSoundRequests[sSoundRequestCount].customFreqScale = 0;
|
||||
sSoundRequestCount++;
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
void play_sound_with_freq_scale(s32 soundBits, f32* pos, f32 freqScale) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
pos = smlua_get_vec3f_for_play_sound(pos);
|
||||
smlua_call_event_hooks_on_play_sound(HOOK_ON_PLAY_SOUND, soundBits, pos, &soundBits);
|
||||
sSoundRequests[sSoundRequestCount].soundBits = soundBits;
|
||||
sSoundRequests[sSoundRequestCount].position = pos;
|
||||
sSoundRequests[sSoundRequestCount].customFreqScale = freqScale;
|
||||
sSoundRequestCount++;
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -986,11 +994,15 @@ static void delete_sound_from_bank(u8 bank, u8 soundIndex) {
|
|||
* Called from threads: thread3_main, thread4_sound, thread5_game_loop
|
||||
*/
|
||||
static void update_background_music_after_sound(u8 bank, u8 soundIndex) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
if (bank >= SOUND_BANK_COUNT || soundIndex >= SOUND_INDEX_COUNT) { return; }
|
||||
if (sSoundBanks[bank][soundIndex].soundBits & SOUND_LOWER_BACKGROUND_MUSIC) {
|
||||
sSoundBanksThatLowerBackgroundMusic &= (1 << bank) ^ 0xffff;
|
||||
begin_background_music_fade(50);
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1761,6 +1773,8 @@ static void update_game_sound(void) {
|
|||
* Called from threads: thread4_sound, thread5_game_loop
|
||||
*/
|
||||
static void seq_player_play_sequence(u8 player, u8 seqId, u16 arg2) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
if (player >= SEQUENCE_PLAYERS) { return; }
|
||||
u8 targetVolume;
|
||||
u8 i;
|
||||
|
|
@ -1801,12 +1815,16 @@ static void seq_player_play_sequence(u8 player, u8 seqId, u16 arg2) {
|
|||
seq_player_fade_from_zero_volume(player, arg2);
|
||||
}
|
||||
#endif
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void seq_player_fade_out(u8 player, u16 fadeDuration) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
if (player >= SEQUENCE_PLAYERS) { return; }
|
||||
#if defined(VERSION_EU) || defined(VERSION_SH)
|
||||
#ifdef VERSION_EU
|
||||
|
|
@ -1824,6 +1842,8 @@ void seq_player_fade_out(u8 player, u16 fadeDuration) {
|
|||
}
|
||||
seq_player_fade_to_zero_volume(player, fadeDuration);
|
||||
#endif
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1840,6 +1860,8 @@ void fade_volume_scale(u8 player, u8 targetScale, u16 fadeDuration) {
|
|||
* Called from threads: thread3_main, thread4_sound, thread5_game_loop
|
||||
*/
|
||||
static void fade_channel_volume_scale(u8 player, u8 channelIndex, u8 targetScale, u16 fadeDuration) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
struct ChannelVolumeScaleFade *temp;
|
||||
if (player >= SEQUENCE_PLAYERS) { return; }
|
||||
if (channelIndex >= CHANNELS_MAX) { return; }
|
||||
|
|
@ -1853,6 +1875,8 @@ static void fade_channel_volume_scale(u8 player, u8 channelIndex, u8 targetScale
|
|||
temp->target = targetScale;
|
||||
temp->current = gSequencePlayers[player].channels[channelIndex]->volumeScale;
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2059,6 +2083,8 @@ void unused_8031FED0(u8 player, u32 bits, s8 arg2) {
|
|||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void seq_player_lower_volume(u8 player, u16 fadeDuration, u8 percentage) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
if (player >= SEQUENCE_PLAYERS) { return; }
|
||||
if (player == SEQ_PLAYER_LEVEL) {
|
||||
sLowerBackgroundMusicVolume = TRUE;
|
||||
|
|
@ -2066,6 +2092,8 @@ void seq_player_lower_volume(u8 player, u16 fadeDuration, u8 percentage) {
|
|||
} else if (gSequencePlayers[player].enabled == TRUE) {
|
||||
seq_player_fade_to_percentage_of_volume(player, fadeDuration, percentage);
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2077,6 +2105,8 @@ void seq_player_lower_volume(u8 player, u16 fadeDuration, u8 percentage) {
|
|||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void seq_player_unlower_volume(u8 player, u16 fadeDuration) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
if (player >= SEQUENCE_PLAYERS) { return; }
|
||||
sLowerBackgroundMusicVolume = FALSE;
|
||||
if (player == SEQ_PLAYER_LEVEL) {
|
||||
|
|
@ -2088,6 +2118,8 @@ void seq_player_unlower_volume(u8 player, u16 fadeDuration) {
|
|||
seq_player_fade_to_normal_volume(player, fadeDuration);
|
||||
}
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2106,6 +2138,8 @@ static u8 begin_background_music_fade(u16 fadeDuration) {
|
|||
|| sCurrentBackgroundMusicSeqId == SEQ_EVENT_CUTSCENE_CREDITS) {
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
if (gSequencePlayers[SEQ_PLAYER_LEVEL].volume == 0.0f && fadeDuration) {
|
||||
gSequencePlayers[SEQ_PLAYER_LEVEL].volume = gSequencePlayers[SEQ_PLAYER_LEVEL].fadeVolume;
|
||||
|
|
@ -2141,6 +2175,8 @@ static u8 begin_background_music_fade(u16 fadeDuration) {
|
|||
seq_player_fade_to_normal_volume(SEQ_PLAYER_LEVEL, fadeDuration);
|
||||
}
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
|
||||
return targetVolume;
|
||||
}
|
||||
|
|
@ -2149,6 +2185,8 @@ static u8 begin_background_music_fade(u16 fadeDuration) {
|
|||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void set_audio_muted(u8 muted) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < SEQUENCE_PLAYERS; i++) {
|
||||
|
|
@ -2161,12 +2199,16 @@ void set_audio_muted(u8 muted) {
|
|||
gSequencePlayers[i].muted = muted;
|
||||
#endif
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from threads: thread4_sound
|
||||
*/
|
||||
void sound_init(void) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
u8 i;
|
||||
u8 j;
|
||||
|
||||
|
|
@ -2225,6 +2267,8 @@ void sound_init(void) {
|
|||
sCurrentSecondaryMusicVolume = 0;
|
||||
sNumProcessedSoundRequests = 0;
|
||||
sSoundRequestCount = 0;
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
// (unused)
|
||||
|
|
@ -2253,6 +2297,8 @@ void get_currently_playing_sound(u8 bank, u8 *numPlayingSounds, u8 *numSoundsInB
|
|||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void stop_sound(u32 soundBits, f32 *pos) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
pos = smlua_get_vec3f_for_play_sound(pos);
|
||||
u8 bank = (soundBits & SOUNDARGS_MASK_BANK) >> SOUNDARGS_SHIFT_BANK;
|
||||
if (bank >= SOUND_BANK_COUNT) { return; }
|
||||
|
|
@ -2275,12 +2321,16 @@ void stop_sound(u32 soundBits, f32 *pos) {
|
|||
soundIndex = sSoundBanks[bank][soundIndex].next;
|
||||
}
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void stop_sounds_from_source(f32 *pos) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
u8 bank;
|
||||
u8 soundIndex;
|
||||
|
||||
|
|
@ -2294,12 +2344,16 @@ void stop_sounds_from_source(f32 *pos) {
|
|||
soundIndex = sSoundBanks[bank][soundIndex].next;
|
||||
}
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from threads: thread3_main, thread5_game_loop
|
||||
*/
|
||||
static void stop_sounds_in_bank(u8 bank) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
if (bank >= SOUND_BANK_COUNT) { return; }
|
||||
u8 soundIndex = sSoundBanks[bank][0].next;
|
||||
|
||||
|
|
@ -2308,6 +2362,8 @@ static void stop_sounds_in_bank(u8 bank) {
|
|||
sSoundBanks[bank][soundIndex].soundBits = NO_SOUND;
|
||||
soundIndex = sSoundBanks[bank][soundIndex].next;
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2327,6 +2383,8 @@ void stop_sounds_in_continuous_banks(void) {
|
|||
* Called from threads: thread3_main, thread5_game_loop
|
||||
*/
|
||||
void sound_banks_disable(UNUSED u8 player, u16 bankMask) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < SOUND_BANK_COUNT; i++) {
|
||||
|
|
@ -2335,23 +2393,31 @@ void sound_banks_disable(UNUSED u8 player, u16 bankMask) {
|
|||
}
|
||||
bankMask = bankMask >> 1;
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
static void disable_all_sequence_players(void) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < SEQUENCE_PLAYERS; i++) {
|
||||
sequence_player_disable(&gSequencePlayers[i]);
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void sound_banks_enable(UNUSED u8 player, u16 bankMask) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < SOUND_BANK_COUNT; i++) {
|
||||
|
|
@ -2360,6 +2426,8 @@ void sound_banks_enable(UNUSED u8 player, u16 bankMask) {
|
|||
}
|
||||
bankMask = bankMask >> 1;
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
u8 unused_803209D8(u8 player, u8 channelIndex, u8 arg2) {
|
||||
|
|
@ -2436,6 +2504,8 @@ void set_sequence_player_volume(s32 player, f32 volume) {
|
|||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void play_music(u8 player, u16 seqArgs, u16 fadeTimer) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
if (player >= SEQUENCE_PLAYERS) { return; }
|
||||
u8 seqId = seqArgs & 0xff;
|
||||
u8 priority = seqArgs >> 8;
|
||||
|
|
@ -2498,12 +2568,16 @@ void play_music(u8 player, u16 seqArgs, u16 fadeTimer) {
|
|||
// Insert item into queue.
|
||||
sBackgroundMusicQueue[foundIndex].priority = priority;
|
||||
sBackgroundMusicQueue[foundIndex].seqId = seqId;
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void stop_background_music(u16 seqId) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
u8 foundIndex;
|
||||
u8 i;
|
||||
|
||||
|
|
@ -2559,6 +2633,8 @@ void stop_background_music(u16 seqId) {
|
|||
// @bug? If the sequence queue is full and we attempt to stop a sequence
|
||||
// that isn't in the queue, this writes out of bounds. Can that happen?
|
||||
sBackgroundMusicQueue[i].priority = 0;
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2642,6 +2718,8 @@ void fade_in_env_music(void) {
|
|||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void play_secondary_music(u8 seqId, u8 bgMusicVolume, u8 volume, u16 fadeTimer) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
UNUSED u32 dummy;
|
||||
|
||||
sUnused80332118 = 0;
|
||||
|
|
@ -2664,6 +2742,8 @@ void play_secondary_music(u8 seqId, u8 bgMusicVolume, u8 volume, u16 fadeTimer)
|
|||
seq_player_fade_to_target_volume(SEQ_PLAYER_ENV, fadeTimer, volume);
|
||||
sCurrentSecondaryMusicVolume = volume;
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2683,6 +2763,8 @@ void stop_secondary_music(u16 fadeTimer) {
|
|||
* Called from threads: thread3_main, thread5_game_loop
|
||||
*/
|
||||
void set_audio_fadeout(u16 fadeDuration) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
if (sHasStartedFadeOut) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -2710,6 +2792,8 @@ void set_audio_fadeout(u16 fadeDuration) {
|
|||
}
|
||||
|
||||
sHasStartedFadeOut = TRUE;
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2807,6 +2891,8 @@ void play_toads_jingle(void) {
|
|||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void sound_reset(u8 presetId) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
#ifndef VERSION_JP
|
||||
if (presetId >= 8) {
|
||||
presetId = 0;
|
||||
|
|
@ -2834,6 +2920,8 @@ void sound_reset(u8 presetId) {
|
|||
D_80332108 = (D_80332108 & 0xf0) + presetId;
|
||||
gSoundMode = D_80332108 >> 4;
|
||||
sHasStartedFadeOut = FALSE;
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -311,6 +311,8 @@ void *sound_alloc_uninitialized(struct SoundAllocPool *pool, u32 size) {
|
|||
#endif
|
||||
|
||||
void sound_alloc_pool_init(struct SoundAllocPool *pool, void *memAddr, u32 size) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
pool->cur = pool->start = (u8 *) ALIGN16((uintptr_t) memAddr);
|
||||
#ifdef VERSION_SH
|
||||
pool->size = size - ((uintptr_t) memAddr & 0xf);
|
||||
|
|
@ -318,15 +320,23 @@ void sound_alloc_pool_init(struct SoundAllocPool *pool, void *memAddr, u32 size)
|
|||
pool->size = size;
|
||||
#endif
|
||||
pool->numAllocatedEntries = 0;
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
void persistent_pool_clear(struct PersistentPool *persistent) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
persistent->pool.numAllocatedEntries = 0;
|
||||
persistent->pool.cur = persistent->pool.start;
|
||||
persistent->numEntries = 0;
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
void temporary_pool_clear(struct TemporaryPool *temporary) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
temporary->pool.numAllocatedEntries = 0;
|
||||
temporary->pool.cur = temporary->pool.start;
|
||||
temporary->nextSide = 0;
|
||||
|
|
@ -338,6 +348,8 @@ void temporary_pool_clear(struct TemporaryPool *temporary) {
|
|||
#endif
|
||||
temporary->entries[0].id = -1; // should be at 1e not 1c
|
||||
temporary->entries[1].id = -1;
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
void unused_803160F8(struct SoundAllocPool *pool) {
|
||||
|
|
@ -347,8 +359,12 @@ void unused_803160F8(struct SoundAllocPool *pool) {
|
|||
|
||||
extern s32 D_SH_80315EE8;
|
||||
void sound_init_main_pools(s32 sizeForAudioInitPool) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
sound_alloc_pool_init(&gAudioInitPool, gAudioHeap, sizeForAudioInitPool);
|
||||
sound_alloc_pool_init(&gAudioSessionPool, gAudioHeap + sizeForAudioInitPool, gAudioHeapSize - sizeForAudioInitPool);
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
#ifdef VERSION_SH
|
||||
|
|
@ -358,37 +374,51 @@ void sound_init_main_pools(s32 sizeForAudioInitPool) {
|
|||
#endif
|
||||
|
||||
void session_pools_init(struct PoolSplit *a) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
gAudioSessionPool.cur = gAudioSessionPool.start;
|
||||
sound_alloc_pool_init(&gNotesAndBuffersPool, SOUND_ALLOC_FUNC(&gAudioSessionPool, a->wantSeq), a->wantSeq);
|
||||
sound_alloc_pool_init(&gSeqAndBankPool, SOUND_ALLOC_FUNC(&gAudioSessionPool, a->wantCustom), a->wantCustom);
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
void seq_and_bank_pool_init(struct PoolSplit2 *a) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
gSeqAndBankPool.cur = gSeqAndBankPool.start;
|
||||
sound_alloc_pool_init(&gPersistentCommonPool, SOUND_ALLOC_FUNC(&gSeqAndBankPool, a->wantPersistent), a->wantPersistent);
|
||||
sound_alloc_pool_init(&gTemporaryCommonPool, SOUND_ALLOC_FUNC(&gSeqAndBankPool, a->wantTemporary), a->wantTemporary);
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
void persistent_pools_init(struct PoolSplit *a) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
gPersistentCommonPool.cur = gPersistentCommonPool.start;
|
||||
sound_alloc_pool_init(&gSeqLoadedPool.persistent.pool, SOUND_ALLOC_FUNC(&gPersistentCommonPool, a->wantSeq), a->wantSeq);
|
||||
sound_alloc_pool_init(&gBankLoadedPool.persistent.pool, SOUND_ALLOC_FUNC(&gPersistentCommonPool, a->wantBank), a->wantBank);
|
||||
sound_alloc_pool_init(&gUnusedLoadedPool.persistent.pool, SOUND_ALLOC_FUNC(&gPersistentCommonPool, a->wantUnused),
|
||||
a->wantUnused);
|
||||
sound_alloc_pool_init(&gUnusedLoadedPool.persistent.pool, SOUND_ALLOC_FUNC(&gPersistentCommonPool, a->wantUnused), a->wantUnused);
|
||||
persistent_pool_clear(&gSeqLoadedPool.persistent);
|
||||
persistent_pool_clear(&gBankLoadedPool.persistent);
|
||||
persistent_pool_clear(&gUnusedLoadedPool.persistent);
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
void temporary_pools_init(struct PoolSplit *a) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
gTemporaryCommonPool.cur = gTemporaryCommonPool.start;
|
||||
sound_alloc_pool_init(&gSeqLoadedPool.temporary.pool, SOUND_ALLOC_FUNC(&gTemporaryCommonPool, a->wantSeq), a->wantSeq);
|
||||
sound_alloc_pool_init(&gBankLoadedPool.temporary.pool, SOUND_ALLOC_FUNC(&gTemporaryCommonPool, a->wantBank), a->wantBank);
|
||||
sound_alloc_pool_init(&gUnusedLoadedPool.temporary.pool, SOUND_ALLOC_FUNC(&gTemporaryCommonPool, a->wantUnused),
|
||||
a->wantUnused);
|
||||
sound_alloc_pool_init(&gUnusedLoadedPool.temporary.pool, SOUND_ALLOC_FUNC(&gTemporaryCommonPool, a->wantUnused), a->wantUnused);
|
||||
temporary_pool_clear(&gSeqLoadedPool.temporary);
|
||||
temporary_pool_clear(&gBankLoadedPool.temporary);
|
||||
temporary_pool_clear(&gUnusedLoadedPool.temporary);
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
#undef SOUND_ALLOC_FUNC
|
||||
|
||||
|
|
|
|||
|
|
@ -1369,10 +1369,13 @@ void reclaim_notes(void) {
|
|||
struct Note *note;
|
||||
s32 i;
|
||||
s32 cond;
|
||||
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
for (i = 0; i < gMaxSimultaneousNotes; i++) {
|
||||
note = &gNotes[i];
|
||||
if (note->parentLayer != NO_LAYER) {
|
||||
if (note == NULL) { continue; }
|
||||
if (note->parentLayer != NULL && note->parentLayer != NO_LAYER) {
|
||||
cond = FALSE;
|
||||
if (!note->parentLayer->enabled && note->priority >= NOTE_PRIORITY_MIN) {
|
||||
cond = TRUE;
|
||||
|
|
@ -1400,6 +1403,8 @@ void reclaim_notes(void) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -350,6 +350,9 @@ void sequence_player_disable_channels_extended(struct SequencePlayer* seqPlayer,
|
|||
|
||||
void sequence_player_disable_all_channels(struct SequencePlayer *seqPlayer) {
|
||||
if (!seqPlayer) { return; }
|
||||
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
eu_stubbed_printf_0("SUBTRACK DIM\n");
|
||||
for (u32 i = 0; i < CHANNELS_MAX; i++) {
|
||||
struct SequenceChannel *seqChannel = seqPlayer->channels[i];
|
||||
|
|
@ -368,11 +371,16 @@ void sequence_player_disable_all_channels(struct SequencePlayer *seqPlayer) {
|
|||
seqPlayer->channels[i] = &gSequenceChannelNone;
|
||||
}
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
void sequence_channel_enable(struct SequencePlayer *seqPlayer, u8 channelIndex, void *script) {
|
||||
if (!seqPlayer) { return; }
|
||||
if (channelIndex >= CHANNELS_MAX) { return; }
|
||||
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
struct SequenceChannel *seqChannel = seqPlayer->channels[channelIndex];
|
||||
s32 i;
|
||||
if (IS_SEQUENCE_CHANNEL_VALID(seqChannel) == FALSE) {
|
||||
|
|
@ -404,10 +412,14 @@ void sequence_channel_enable(struct SequencePlayer *seqPlayer, u8 channelIndex,
|
|||
|
||||
LOG_DEBUG("Enabled sequence channel %d with script entry of %p", channelIndex, script);
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
void sequence_player_disable(struct SequencePlayer *seqPlayer) {
|
||||
if (!seqPlayer) { return; }
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
LOG_DEBUG("Disabling sequence player %p", seqPlayer);
|
||||
|
||||
sequence_player_disable_all_channels(seqPlayer);
|
||||
|
|
@ -451,6 +463,8 @@ void sequence_player_disable(struct SequencePlayer *seqPlayer) {
|
|||
gBankLoadedPool.temporary.nextSide = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1659,7 +1673,7 @@ void sequence_channel_process_script(struct SequenceChannel *seqChannel) {
|
|||
}
|
||||
|
||||
seqPlayer = seqChannel->seqPlayer;
|
||||
if (seqPlayer->muted && (seqChannel->muteBehavior & MUTE_BEHAVIOR_STOP_SCRIPT) != 0) {
|
||||
if (seqPlayer == NULL || (seqPlayer->muted && (seqChannel->muteBehavior & MUTE_BEHAVIOR_STOP_SCRIPT) != 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@
|
|||
#include "buffers.h"
|
||||
#include "audio/data.h"
|
||||
|
||||
ALIGNED8 u8 gDecompressionHeap[0xD000];
|
||||
ALIGNED8 u8 gDecompressionHeap[0xD000] = { 0 };
|
||||
#if defined(VERSION_EU)
|
||||
ALIGNED16 u8 gAudioHeap[DOUBLE_SIZE_ON_64_BIT(AUDIO_HEAP_SIZE) - 0x3800];
|
||||
ALIGNED16 u8 gAudioHeap[DOUBLE_SIZE_ON_64_BIT(AUDIO_HEAP_SIZE) - 0x3800] = { 0 };
|
||||
#elif defined(VERSION_SH)
|
||||
ALIGNED16 u8 gAudioHeap[DOUBLE_SIZE_ON_64_BIT(AUDIO_HEAP_SIZE) - 0x4800];
|
||||
ALIGNED16 u8 gAudioHeap[DOUBLE_SIZE_ON_64_BIT(AUDIO_HEAP_SIZE) - 0x4800] = { 0 };
|
||||
#else
|
||||
ALIGNED16 u8 gAudioHeap[DOUBLE_SIZE_ON_64_BIT(AUDIO_HEAP_SIZE)];
|
||||
ALIGNED16 u8 gAudioHeap[DOUBLE_SIZE_ON_64_BIT(AUDIO_HEAP_SIZE)] = { 0 };
|
||||
#endif
|
||||
|
||||
ALIGNED8 u8 gIdleThreadStack[0x800];
|
||||
|
|
@ -20,23 +20,23 @@ ALIGNED8 u8 gThread5Stack[0x2000];
|
|||
ALIGNED8 u8 gThread6Stack[0x2000];
|
||||
#endif
|
||||
// 0x400 bytes
|
||||
ALIGNED8 u8 gGfxSPTaskStack[SP_DRAM_STACK_SIZE8];
|
||||
ALIGNED8 u8 gGfxSPTaskStack[SP_DRAM_STACK_SIZE8] = { 0 };
|
||||
// 0xc00 bytes for f3dex, 0x900 otherwise
|
||||
ALIGNED8 u8 gGfxSPTaskYieldBuffer[OS_YIELD_DATA_SIZE];
|
||||
ALIGNED8 u8 gGfxSPTaskYieldBuffer[OS_YIELD_DATA_SIZE] = { 0 };
|
||||
// 0x200 bytes
|
||||
ALIGNED8 struct SaveBuffer gSaveBuffer;
|
||||
ALIGNED8 struct SaveBuffer gSaveBuffer = { 0 };
|
||||
// 0x190a0 bytes
|
||||
struct GfxPool gGfxPools[GFX_NUM_POOLS];
|
||||
struct GfxPool gGfxPools[GFX_NUM_POOLS] = { 0 };
|
||||
|
||||
|
||||
// Yield buffer for audio, 0x400 bytes. Stubbed out post-JP since the audio
|
||||
// task never yields.
|
||||
#ifdef VERSION_JP
|
||||
ALIGNED8 u8 gAudioSPTaskYieldBuffer[OS_YIELD_AUDIO_SIZE];
|
||||
ALIGNED8 u8 gAudioSPTaskYieldBuffer[OS_YIELD_AUDIO_SIZE] = { 0 };
|
||||
#endif
|
||||
|
||||
// Probably Thread 2 stack space. Unreferenced, and stubbed out with f3dex to
|
||||
// avoid an overflowing .buffers segment.
|
||||
#if !defined(F3DEX_GBI_SHARED) && !defined(VERSION_EU)
|
||||
ALIGNED8 u8 gUnusedThread2Stack[0x1400];
|
||||
ALIGNED8 u8 gUnusedThread2Stack[0x1400] = { 0 };
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
#ifdef VERSION_EU
|
||||
// 0x17e00 bytes, aligned to a 0x200-byte boundary through sm64.ld. The alignment
|
||||
// wastes 0x100 bytes of space.
|
||||
u64 gGfxSPTaskOutputBuffer[0x2fc0];
|
||||
u64 gGfxSPTaskOutputBuffer[0x2fc0] = { 0 };
|
||||
#else
|
||||
// 0x1f000 bytes, aligned to a 0x1000-byte boundary through sm64.ld. (This results
|
||||
// in a bunch of unused space: ~0x100 in JP, ~0x300 in US.)
|
||||
u64 gGfxSPTaskOutputBuffer[0x3e00];
|
||||
u64 gGfxSPTaskOutputBuffer[0x3e00] = { 0 };
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@
|
|||
#include "config.h"
|
||||
#include "zbuffer.h"
|
||||
|
||||
ALIGNED8 u16 gZBuffer[SCREEN_WIDTH * SCREEN_HEIGHT];
|
||||
ALIGNED8 u16 gZBuffer[SCREEN_WIDTH * SCREEN_HEIGHT] = { 0 };
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include <ultra64.h>
|
||||
|
||||
#include "area.h"
|
||||
#include "audio/data.h"
|
||||
#include "audio/external.h"
|
||||
#include "engine/graph_node.h"
|
||||
#include "engine/math_util.h"
|
||||
|
|
@ -87,6 +88,8 @@ void reset_volume(void) {
|
|||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void lower_background_noise(s32 a) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
switch (a) {
|
||||
case 1:
|
||||
set_audio_muted(TRUE);
|
||||
|
|
@ -96,12 +99,16 @@ void lower_background_noise(s32 a) {
|
|||
break;
|
||||
}
|
||||
sVolumeLoweredState |= a;
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void raise_background_noise(s32 a) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
switch (a) {
|
||||
case 1:
|
||||
set_audio_muted(FALSE);
|
||||
|
|
@ -111,26 +118,36 @@ void raise_background_noise(s32 a) {
|
|||
break;
|
||||
}
|
||||
sVolumeLoweredState &= ~a;
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void disable_background_sound(void) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
if (!sBackgroundMusicDisabled) {
|
||||
sBackgroundMusicDisabled = TRUE;
|
||||
sound_banks_disable(SEQ_PLAYER_SFX, SOUND_BANKS_BACKGROUND);
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void enable_background_sound(void) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
if (sBackgroundMusicDisabled) {
|
||||
sBackgroundMusicDisabled = FALSE;
|
||||
sound_banks_enable(SEQ_PLAYER_SFX, SOUND_BANKS_BACKGROUND);
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -139,9 +156,13 @@ void enable_background_sound(void) {
|
|||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void set_sound_mode(u16 soundMode) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
if (soundMode < 3) {
|
||||
audio_set_sound_mode(sSoundMenuModeToSoundMode[soundMode]);
|
||||
}
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -241,20 +262,28 @@ void set_background_music(u16 a, u16 seqArgs, s16 fadeTimer) {
|
|||
* Called from threads: thread3_main, thread5_game_loop
|
||||
*/
|
||||
void fadeout_music(s16 fadeOutTime) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
set_audio_fadeout(fadeOutTime);
|
||||
sCurrentMusic = MUSIC_NONE;
|
||||
sCurrentShellMusic = MUSIC_NONE;
|
||||
sCurrentCapMusic = MUSIC_NONE;
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from threads: thread5_game_loop
|
||||
*/
|
||||
void fadeout_level_music(s16 fadeTimer) {
|
||||
MUTEX_LOCK(gAudioThread);
|
||||
|
||||
seq_player_fade_out(SEQ_PLAYER_LEVEL, fadeTimer);
|
||||
sCurrentMusic = MUSIC_NONE;
|
||||
sCurrentShellMusic = MUSIC_NONE;
|
||||
sCurrentCapMusic = MUSIC_NONE;
|
||||
|
||||
MUTEX_UNLOCK(gAudioThread);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#ifdef LOADING_SCREEN_SUPPORTED
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "djui/djui.h"
|
||||
#include "pc/djui/djui_unicode.h"
|
||||
|
||||
|
|
@ -24,10 +26,7 @@ struct LoadingScreen {
|
|||
|
||||
static struct LoadingScreen* sLoading = NULL;
|
||||
|
||||
pthread_t gLoadingThreadId;
|
||||
pthread_mutex_t gLoadingThreadMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
bool gIsThreaded = false;
|
||||
struct ThreadHandle gLoadingThread = { 0 };
|
||||
|
||||
void loading_screen_set_segment_text(const char* text) {
|
||||
snprintf(gCurrLoadingSegment.str, 256, text);
|
||||
|
|
@ -46,7 +45,7 @@ static void loading_screen_produce_one_frame(void) {
|
|||
}
|
||||
|
||||
static bool loading_screen_on_render(struct DjuiBase* base) {
|
||||
if (gIsThreaded) { pthread_mutex_lock(&gLoadingThreadMutex); }
|
||||
MUTEX_LOCK(gLoadingThread);
|
||||
|
||||
u32 windowWidth, windowHeight;
|
||||
WAPI.get_dimensions(&windowWidth, &windowHeight);
|
||||
|
|
@ -90,7 +89,7 @@ static bool loading_screen_on_render(struct DjuiBase* base) {
|
|||
|
||||
djui_base_compute(base);
|
||||
|
||||
if (gIsThreaded) { pthread_mutex_unlock(&gLoadingThreadMutex); }
|
||||
MUTEX_UNLOCK(gLoadingThread);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -183,7 +182,8 @@ void render_loading_screen(void) {
|
|||
WAPI.main_loop(loading_screen_produce_one_frame);
|
||||
}
|
||||
|
||||
pthread_join(gLoadingThreadId, NULL);
|
||||
int err = join_thread(&gLoadingThread);
|
||||
assert(err == 0);
|
||||
}
|
||||
|
||||
void render_rom_setup_screen(void) {
|
||||
|
|
@ -196,4 +196,4 @@ void render_rom_setup_screen(void) {
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -7,9 +7,7 @@
|
|||
|
||||
#ifdef LOADING_SCREEN_SUPPORTED
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "cliopts.h"
|
||||
#include "src/pc/thread.h"
|
||||
#include "djui/djui_hud_utils.h"
|
||||
|
||||
struct LoadingSegment {
|
||||
|
|
@ -20,16 +18,13 @@ struct LoadingSegment {
|
|||
extern struct LoadingSegment gCurrLoadingSegment;
|
||||
|
||||
#define LOADING_SCREEN_MUTEX(...) \
|
||||
if (!gCLIOpts.hideLoadingScreen && gIsThreaded) { \
|
||||
pthread_mutex_lock(&gLoadingThreadMutex); \
|
||||
if (!gCLIOpts.hideLoadingScreen && gLoadingThread.state != INVALID) { \
|
||||
pthread_mutex_lock(&gLoadingThread.mutex); \
|
||||
__VA_ARGS__; \
|
||||
pthread_mutex_unlock(&gLoadingThreadMutex); \
|
||||
pthread_mutex_unlock(&gLoadingThread.mutex); \
|
||||
}
|
||||
|
||||
extern pthread_t gLoadingThreadId;
|
||||
extern pthread_mutex_t gLoadingThreadMutex;
|
||||
|
||||
extern bool gIsThreaded;
|
||||
extern struct ThreadHandle gLoadingThread;
|
||||
|
||||
void loading_screen_set_segment_text(const char* text);
|
||||
void loading_screen_reset_progress_bar(void);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "pc/lua/smlua.h"
|
||||
#include "pc/lua/utils/smlua_text_utils.h"
|
||||
#include "game/memory.h"
|
||||
#include "audio/data.h"
|
||||
#include "audio/external.h"
|
||||
|
||||
#include "network/network.h"
|
||||
|
|
@ -25,6 +26,7 @@
|
|||
#include "loading.h"
|
||||
#include "cliopts.h"
|
||||
#include "configfile.h"
|
||||
#include "thread.h"
|
||||
#include "controller/controller_api.h"
|
||||
#include "controller/controller_keyboard.h"
|
||||
#include "fs/fs.h"
|
||||
|
|
@ -230,6 +232,10 @@ void produce_interpolation_frames_and_delay(void) {
|
|||
gRenderingInterpolated = false;
|
||||
}
|
||||
|
||||
// It's just better to have this off the stack, Because the size isn't small.
|
||||
// It also may help static analysis and bug catching.
|
||||
static s16 sAudioBuffer[SAMPLES_HIGH * 2 * 2] = { 0 };
|
||||
|
||||
inline static void buffer_audio(void) {
|
||||
bool shouldMute = configMuteFocusLoss && !WAPI.has_focus();
|
||||
const f32 masterMod = (f32)configMasterVolume / 127.0f * (f32)gLuaVolumeMaster / 127.0f;
|
||||
|
|
@ -239,11 +245,37 @@ inline static void buffer_audio(void) {
|
|||
|
||||
int samplesLeft = audio_api->buffered();
|
||||
u32 numAudioSamples = samplesLeft < audio_api->get_desired_buffered() ? SAMPLES_HIGH : SAMPLES_LOW;
|
||||
s16 audioBuffer[SAMPLES_HIGH * 2 * 2];
|
||||
for (s32 i = 0; i < 2; i++) {
|
||||
create_next_audio_buffer(audioBuffer + i * (numAudioSamples * 2), numAudioSamples);
|
||||
create_next_audio_buffer(sAudioBuffer + i * (numAudioSamples * 2), numAudioSamples);
|
||||
}
|
||||
audio_api->play((u8 *)audioBuffer, 2 * numAudioSamples * 4);
|
||||
audio_api->play((u8 *)sAudioBuffer, 2 * numAudioSamples * 4);
|
||||
}
|
||||
|
||||
void *audio_thread(UNUSED void *arg) {
|
||||
// As long as we have an audio api and that we're threaded, Loop.
|
||||
while (audio_api) {
|
||||
f64 curTime = clock_elapsed_f64();
|
||||
|
||||
// Buffer the audio.
|
||||
lock_mutex(&gAudioThread);
|
||||
buffer_audio();
|
||||
unlock_mutex(&gAudioThread);
|
||||
|
||||
// Delay till the next frame for smooth audio at the correct speed.
|
||||
// delay
|
||||
f64 targetDelta = 1.0 / (f64)FRAMERATE;
|
||||
f64 now = clock_elapsed_f64();
|
||||
f64 actualDelta = now - curTime;
|
||||
if (actualDelta < targetDelta) {
|
||||
f64 delay = ((targetDelta - actualDelta) * 1000.0);
|
||||
WAPI.delay((u32)delay);
|
||||
}
|
||||
}
|
||||
|
||||
// Exit the thread if our loop breaks.
|
||||
exit_thread();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void produce_one_frame(void) {
|
||||
|
|
@ -254,8 +286,11 @@ void produce_one_frame(void) {
|
|||
CTX_EXTENT(CTX_GAME_LOOP, game_loop_one_iteration);
|
||||
|
||||
CTX_EXTENT(CTX_SMLUA, smlua_update);
|
||||
|
||||
CTX_EXTENT(CTX_AUDIO, buffer_audio);
|
||||
|
||||
// If we aren't threaded
|
||||
if (gAudioThread.state == INVALID) {
|
||||
CTX_EXTENT(CTX_AUDIO, buffer_audio);
|
||||
}
|
||||
|
||||
CTX_EXTENT(CTX_RENDER, produce_interpolation_frames_and_delay);
|
||||
}
|
||||
|
|
@ -408,14 +443,12 @@ int main(int argc, char *argv[]) {
|
|||
// start the thread for setting up the game
|
||||
#ifdef LOADING_SCREEN_SUPPORTED
|
||||
bool threadSuccess = false;
|
||||
if (!gCLIOpts.hideLoadingScreen && pthread_mutex_init(&gLoadingThreadMutex, NULL) == 0) {
|
||||
gIsThreaded = true;
|
||||
if (pthread_create(&gLoadingThreadId, NULL, main_game_init, NULL) == 0) {
|
||||
if (!gCLIOpts.hideLoadingScreen) {
|
||||
if (init_thread_handle(&gLoadingThread, main_game_init, NULL, NULL, 0) == 0) {
|
||||
render_loading_screen(); // render the loading screen while the game is setup
|
||||
threadSuccess = true;
|
||||
destroy_mutex(&gLoadingThread);
|
||||
}
|
||||
gIsThreaded = false;
|
||||
pthread_mutex_destroy(&gLoadingThreadMutex);
|
||||
}
|
||||
if (!threadSuccess)
|
||||
#endif
|
||||
|
|
@ -431,6 +464,9 @@ int main(int argc, char *argv[]) {
|
|||
if (!audio_api && audio_sdl.init()) { audio_api = &audio_sdl; }
|
||||
#endif
|
||||
if (!audio_api) { audio_api = &audio_null; }
|
||||
|
||||
// Initialize the audio thread if possible.
|
||||
init_thread_handle(&gAudioThread, audio_thread, NULL, NULL, 0);
|
||||
|
||||
#ifdef LOADING_SCREEN_SUPPORTED
|
||||
loading_screen_reset();
|
||||
|
|
|
|||
132
src/pc/thread.c
Normal file
132
src/pc/thread.c
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
#include "thread.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
int init_thread_handle(struct ThreadHandle *handle, void *(*entry)(void *), void *arg, void *sp, size_t sp_size) {
|
||||
int err1 = init_mutex(handle);
|
||||
int err2 = init_thread(handle, entry, arg, sp, sp_size);
|
||||
|
||||
return (err1 != 0 || err2 != 0);
|
||||
}
|
||||
|
||||
void free_thread_handle(struct ThreadHandle *handle) {
|
||||
assert(handle != NULL);
|
||||
|
||||
//int err = stop_thread(handle);
|
||||
//assert(err == 0);
|
||||
|
||||
int err = destroy_mutex(handle);
|
||||
assert(err == 0);
|
||||
|
||||
// Reset the memory of the thread handle, We no longer need the thread or mutex.
|
||||
memset((void *)handle, 0, sizeof(struct ThreadHandle));
|
||||
}
|
||||
|
||||
// Optimally just call init_thread_handle instead.
|
||||
int init_thread(struct ThreadHandle *handle, void *(*entry)(void *), void *arg, void *sp, size_t sp_size) {
|
||||
assert(handle != NULL);
|
||||
|
||||
// Setup our thread and create it.
|
||||
pthread_attr_t thattr = { 0 };
|
||||
|
||||
// Initialize default attributes for a new thread.
|
||||
int err = pthread_attr_init(&thattr);
|
||||
assert(err == 0);
|
||||
|
||||
// By default, We want the thread to be joinable.
|
||||
err = pthread_attr_setdetachstate(&thattr, PTHREAD_CREATE_JOINABLE);
|
||||
assert(err == 0);
|
||||
|
||||
// Set the stack if we have one specified, Otherwise we don't care.
|
||||
// In truth, This honestly shouldn't be used on PC. But if somebody wants
|
||||
// a really managed stack? This is possible.
|
||||
if (sp != NULL && sp_size > 0) {
|
||||
err = pthread_attr_setstack(&thattr, sp, sp_size);
|
||||
assert(err == 0);
|
||||
}
|
||||
|
||||
// Create our thread.
|
||||
int ret = pthread_create(&handle->thread, &thattr, entry, arg);
|
||||
|
||||
// Destroy the thread attributes, They are no longer needed
|
||||
err = pthread_attr_destroy(&thattr);
|
||||
assert(err == 0);
|
||||
|
||||
handle->state = RUNNING;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int join_thread(struct ThreadHandle *handle) {
|
||||
assert(handle != NULL);
|
||||
|
||||
// Join the thread and wait for it to finish.
|
||||
return pthread_join(handle->thread, NULL);
|
||||
}
|
||||
|
||||
int detach_thread(struct ThreadHandle *handle) {
|
||||
assert(handle != NULL);
|
||||
|
||||
// Detach the thread, it will no longer be joinable afterwards.
|
||||
return pthread_detach(handle->thread);
|
||||
}
|
||||
|
||||
// Call from inside the thread you wish to
|
||||
// terminate.
|
||||
void exit_thread() {
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
int stop_thread(struct ThreadHandle *handle) {
|
||||
assert(handle != NULL);
|
||||
|
||||
handle->state = STOPPED;
|
||||
|
||||
// Stop and or cancel the execution of the thread in question.
|
||||
return pthread_cancel(handle->thread);
|
||||
}
|
||||
|
||||
// Optimally just call init_thread_handle instead.
|
||||
int init_mutex(struct ThreadHandle *handle) {
|
||||
assert(handle != NULL);
|
||||
|
||||
pthread_mutexattr_t mtattr;
|
||||
|
||||
int err = pthread_mutexattr_init(&mtattr);
|
||||
assert(err == 0);
|
||||
|
||||
err = pthread_mutexattr_settype(&mtattr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
assert(err == 0);
|
||||
|
||||
int ret = pthread_mutex_init(&handle->mutex, &mtattr);
|
||||
|
||||
err = pthread_mutexattr_destroy(&mtattr);
|
||||
assert(err == 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int destroy_mutex(struct ThreadHandle *handle) {
|
||||
assert(handle != NULL);
|
||||
|
||||
return pthread_mutex_destroy(&handle->mutex);
|
||||
}
|
||||
|
||||
int lock_mutex(struct ThreadHandle *handle) {
|
||||
assert(handle != NULL);
|
||||
|
||||
return pthread_mutex_lock(&handle->mutex);
|
||||
}
|
||||
|
||||
int trylock_mutex(struct ThreadHandle *handle) {
|
||||
assert(handle != NULL);
|
||||
|
||||
return pthread_mutex_trylock(&handle->mutex);
|
||||
}
|
||||
|
||||
int unlock_mutex(struct ThreadHandle *handle) {
|
||||
assert(handle != NULL);
|
||||
|
||||
return pthread_mutex_unlock(&handle->mutex);
|
||||
}
|
||||
45
src/pc/thread.h
Normal file
45
src/pc/thread.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef THREADING_H
|
||||
#define THREADING_H
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "cliopts.h"
|
||||
#include "types.h"
|
||||
|
||||
// Macros
|
||||
#define MUTEX_LOCK(handle) if (handle.state != INVALID) { lock_mutex(&handle); }
|
||||
#define MUTEX_UNLOCK(handle) if (handle.state != INVALID) { unlock_mutex(&handle); }
|
||||
|
||||
// Types
|
||||
enum ThreadState {
|
||||
INVALID = 0,
|
||||
STOPPED = 1,
|
||||
RUNNING = 2
|
||||
};
|
||||
|
||||
struct ThreadHandle {
|
||||
pthread_t thread;
|
||||
pthread_mutex_t mutex;
|
||||
enum ThreadState state;
|
||||
};
|
||||
|
||||
// Functions
|
||||
//// Thread Handle
|
||||
int init_thread_handle(struct ThreadHandle *handle, void *(*entry)(void *), void *arg, void *sp, size_t sp_size);
|
||||
void cleanup_thread_handle(struct ThreadHandle *handle);
|
||||
|
||||
//// Thread
|
||||
int init_thread(struct ThreadHandle *handle, void *(*entry)(void *), void *arg, void *sp, size_t sp_size);
|
||||
int join_thread(struct ThreadHandle *handle);
|
||||
int detach_thread(struct ThreadHandle *handle);
|
||||
void exit_thread();
|
||||
int stop_thread(struct ThreadHandle *handle);
|
||||
|
||||
//// Mutex
|
||||
int init_mutex(struct ThreadHandle *handle);
|
||||
int destroy_mutex(struct ThreadHandle *handle);
|
||||
int lock_mutex(struct ThreadHandle *handle);
|
||||
int trylock_mutex(struct ThreadHandle *handle);
|
||||
int unlock_mutex(struct ThreadHandle *handle);
|
||||
|
||||
#endif // THREADING_H
|
||||
Loading…
Add table
Reference in a new issue