audio thread now runs at 60hz

also now using the built-in sys_sleep() upon sleeping. also implemented mutex locks.
This commit is contained in:
KingOfSpadesJFK 2024-04-11 22:09:29 -07:00
parent ac7d9303f4
commit ed5c01021e
1 changed files with 35 additions and 25 deletions

View File

@ -66,6 +66,8 @@ pthread_t audio_thread_id;
bool audio_thread_running = false;
sem_t audio_sem;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
extern void gfx_run(Gfx *commands);
extern void thread5_game_loop(void *arg);
extern void audio_game_loop_tick(void);
@ -107,43 +109,46 @@ void produce_one_frame(void) {
// Seperate the audio thread from the main thread so that your ears won't bleed at a low framerate
// FIXME: Low but comman chance of a segfault when teleporting to a new level
// After implementing mutexes and semaphores, idk how common it is now since it's hard to reproduce
void* audio_thread() {
const long framerateNano = 33333333L; // 33.333333 ms = 30 fps; run this thread 30 times a second like the original game
int napResult = 0;
const double frametime_micro = 16666.666; // 16.666666 ms = 60Hz; run this thread 60 times a second like the original game
struct timespec start_time;
struct timespec end_time;
while(audio_thread_running) {
clock_gettime(CLOCK_MONOTONIC, &start_time);
while(1) {
// Check if the audio thread should be stopped
pthread_mutex_lock(&mutex);
if (!audio_thread_running) {
pthread_mutex_unlock(&mutex);
break;
}
pthread_mutex_unlock(&mutex);
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start_time);
const f32 master_mod = (f32)configMasterVolume / 127.0f;
set_sequence_player_volume(SEQ_PLAYER_LEVEL, (f32)configMusicVolume / 127.0f * master_mod);
set_sequence_player_volume(SEQ_PLAYER_SFX, (f32)configSfxVolume / 127.0f * master_mod);
set_sequence_player_volume(SEQ_PLAYER_ENV, (f32)configEnvVolume / 127.0f * master_mod);
// audio_game_loop_tick();
int samples_left = audio_api->buffered();
u32 num_audio_samples = samples_left < audio_api->get_desired_buffered() ? SAMPLES_HIGH : SAMPLES_LOW;
// printf("Audio samples: %d %u\n", samples_left, num_audio_samples);
s16 audio_buffer[SAMPLES_HIGH * 2 * 2];
for (int i = 0; i < 2; i++) {
/*if (audio_cnt-- == 0) {
audio_cnt = 2;
}
u32 num_audio_samples = audio_cnt < 2 ? 528 : 544;*/
if (!audio_thread_running) break;
create_next_audio_buffer(audio_buffer + i * (num_audio_samples * 2), num_audio_samples);
s16 audio_buffer[SAMPLES_HIGH * 2];
/*if (audio_cnt-- == 0) {
audio_cnt = 2;
}
u32 num_audio_samples = audio_cnt < 2 ? 528 : 544;*/
create_next_audio_buffer(audio_buffer, num_audio_samples);
// printf("Audio samples before submitting: %d\n", audio_api->buffered());
if (!audio_thread_running) break;
audio_api->play((u8 *)audio_buffer, 2 * num_audio_samples * 4);
audio_api->play((u8 *)audio_buffer, num_audio_samples * 4);
clock_gettime(CLOCK_MONOTONIC, &end_time);
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end_time);
long napTime = framerateNano - (end_time.tv_nsec - start_time.tv_nsec);
napResult = nanosleep((const struct timespec[]){{0, napTime}}, NULL);
if (napResult == -1) {
printf("interrupted by a signal handler\n");
}
// Sleep for the remaining time
uint64_t second_passed = end_time.tv_nsec < start_time.tv_nsec ? 1000000000L : 0; // Take account for if the end time is in the next second
double nap_time = frametime_micro - (double)(end_time.tv_nsec + second_passed - start_time.tv_nsec) / 1000.0;
// printf("Audio thread nap time: %f\n", nap_time);
sys_sleep(nap_time);
sem_post(&audio_sem);
}
return NULL;
@ -156,13 +161,18 @@ void audio_thread_init() {
}
void audio_shutdown(void) {
// Tell the audio thread to stop
pthread_mutex_lock(&mutex);
audio_thread_running = false;
pthread_mutex_unlock(&mutex);
sem_wait(&audio_sem); // Wait for the audio thread to finish rendering audio, then destroy it all
pthread_join(audio_thread_id, NULL);
sem_destroy(&audio_sem);
if (audio_api) {
if (audio_api->shutdown) audio_api->shutdown();
audio_api = NULL;
}
audio_thread_running = false;
pthread_join(audio_thread_id, NULL);
sem_destroy(&audio_sem);
}
void game_deinit(void) {