2023-11-30 21:22:30 +00:00
|
|
|
/**
|
|
|
|
* @file audio_thread_manager.c
|
|
|
|
*
|
|
|
|
* This file implements basic thread features for the audio driver. It manages updating the driver on vertical retrace
|
|
|
|
* and sending the audio rsp tasks generated by the driver to the task scheduler.
|
|
|
|
*/
|
|
|
|
|
2020-10-03 15:22:44 +00:00
|
|
|
#include "global.h"
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2023-11-30 21:22:30 +00:00
|
|
|
void AudioMgr_NotifyTaskDone(AudioMgr* audioMgr) {
|
2022-04-09 00:20:23 +00:00
|
|
|
AudioTask* task = audioMgr->rspTask;
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2023-11-30 21:22:30 +00:00
|
|
|
// If the audio rsp task has a message queue to receive task done notifications, post a message to it.
|
2022-04-09 00:20:23 +00:00
|
|
|
if (audioMgr->rspTask->msgQueue != NULL) {
|
|
|
|
osSendMesg(task->msgQueue, NULL, OS_MESG_BLOCK);
|
2020-05-11 00:04:41 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2023-11-30 21:22:30 +00:00
|
|
|
/**
|
|
|
|
* Handle retrace event.
|
|
|
|
* Update the audio driver and schedule audio rsp tasks.
|
|
|
|
*/
|
2020-05-11 00:04:41 +00:00
|
|
|
void AudioMgr_HandleRetrace(AudioMgr* audioMgr) {
|
2021-07-27 23:44:58 +00:00
|
|
|
AudioTask* rspTask;
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2023-11-30 21:22:30 +00:00
|
|
|
if (R_AUDIOMGR_DEBUG_LEVEL > AUDIOMGR_DEBUG_LEVEL_NONE) {
|
|
|
|
// Inhibit audio rsp task processing
|
2021-07-27 23:44:58 +00:00
|
|
|
audioMgr->rspTask = NULL;
|
2020-05-11 00:04:41 +00:00
|
|
|
}
|
2023-11-30 21:22:30 +00:00
|
|
|
|
2021-07-27 23:44:58 +00:00
|
|
|
if (audioMgr->rspTask != NULL) {
|
2023-11-30 21:22:30 +00:00
|
|
|
// Got an rsp task to process, build the OSScTask and forward it to the scheduler to run
|
|
|
|
|
2021-07-27 23:44:58 +00:00
|
|
|
audioMgr->audioTask.next = NULL;
|
2022-04-09 00:20:23 +00:00
|
|
|
audioMgr->audioTask.flags = OS_SC_NEEDS_RSP;
|
2021-07-27 23:44:58 +00:00
|
|
|
audioMgr->audioTask.framebuffer = NULL;
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2021-07-27 23:44:58 +00:00
|
|
|
audioMgr->audioTask.list = audioMgr->rspTask->task;
|
2023-11-30 21:22:30 +00:00
|
|
|
audioMgr->audioTask.msgQueue = &audioMgr->taskDoneQueue;
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2021-07-27 23:44:58 +00:00
|
|
|
audioMgr->audioTask.msg = NULL;
|
2022-04-09 00:20:23 +00:00
|
|
|
osSendMesg(&audioMgr->sched->cmdQueue, (OSMesg)&audioMgr->audioTask, OS_MESG_BLOCK);
|
2022-06-03 19:43:30 +00:00
|
|
|
Sched_Notify(audioMgr->sched);
|
2020-05-11 00:04:41 +00:00
|
|
|
}
|
2021-02-14 00:49:40 +00:00
|
|
|
|
2023-11-30 21:22:30 +00:00
|
|
|
// Update the audio driver
|
|
|
|
|
2022-10-29 20:44:27 +00:00
|
|
|
gAudioThreadUpdateTimeStart = osGetTime();
|
2023-11-30 21:22:30 +00:00
|
|
|
|
|
|
|
if (R_AUDIOMGR_DEBUG_LEVEL >= AUDIOMGR_DEBUG_LEVEL_NO_UPDATE) {
|
|
|
|
// Skip update, no rsp task produced
|
2021-07-27 23:44:58 +00:00
|
|
|
rspTask = NULL;
|
2020-05-11 00:04:41 +00:00
|
|
|
} else {
|
2024-01-31 23:25:23 +00:00
|
|
|
rspTask = AudioThread_Update();
|
2020-05-11 00:04:41 +00:00
|
|
|
}
|
2023-11-30 21:22:30 +00:00
|
|
|
|
2022-10-29 20:44:27 +00:00
|
|
|
gAudioThreadUpdateTimeAcc += osGetTime() - gAudioThreadUpdateTimeStart;
|
|
|
|
gAudioThreadUpdateTimeStart = 0;
|
|
|
|
|
2021-07-27 23:44:58 +00:00
|
|
|
if (audioMgr->rspTask != NULL) {
|
2023-11-30 21:22:30 +00:00
|
|
|
// Wait for the audio rsp task scheduled on the previous retrace to complete. This looks like it should wait
|
|
|
|
// for the task scheduled on the current retrace, earlier in this function, but since the queue is initially
|
|
|
|
// filled in AudioMgr_Init this osRecvMesg call doesn't wait for the task scheduler to post a message for the
|
|
|
|
// most recent task as there is already a message waiting.
|
|
|
|
osRecvMesg(&audioMgr->taskDoneQueue, NULL, OS_MESG_BLOCK);
|
|
|
|
// Report task done
|
|
|
|
//! @bug As the above osRecvMesg is waiting for the previous task to complete rather than the current task,
|
|
|
|
//! the task done notification is sent to the task done queue for the current task as soon as the previous task
|
|
|
|
//! is completed, without waiting for the current task.
|
|
|
|
//! In practice, task done notifications are not used by the audio driver so this is inconsequential.
|
|
|
|
AudioMgr_NotifyTaskDone(audioMgr);
|
2020-05-11 00:04:41 +00:00
|
|
|
}
|
2023-11-30 21:22:30 +00:00
|
|
|
// Update rsp task to be scheduled on next retrace
|
2021-07-27 23:44:58 +00:00
|
|
|
audioMgr->rspTask = rspTask;
|
2020-05-11 00:04:41 +00:00
|
|
|
}
|
2020-03-17 04:31:30 +00:00
|
|
|
|
2023-11-30 21:22:30 +00:00
|
|
|
/**
|
|
|
|
* Handle Pre-NMI event.
|
|
|
|
* Implemented by the audio driver.
|
|
|
|
*
|
|
|
|
* @see Audio_PreNMI
|
|
|
|
*/
|
2022-06-03 19:43:30 +00:00
|
|
|
void AudioMgr_HandlePreNMI(AudioMgr* audioMgr) {
|
2024-08-22 20:33:50 +00:00
|
|
|
PRINTF(
|
|
|
|
T("オーディオマネージャが OS_SC_PRE_NMI_MSG を受け取りました\n", "Audio manager received OS_SC_PRE_NMI_MSG\n"));
|
2021-07-27 23:44:58 +00:00
|
|
|
Audio_PreNMI();
|
2020-05-11 00:04:41 +00:00
|
|
|
}
|
|
|
|
|
2023-11-30 21:22:30 +00:00
|
|
|
void AudioMgr_ThreadEntry(void* arg) {
|
|
|
|
AudioMgr* audioMgr = (AudioMgr*)arg;
|
2020-05-11 00:04:41 +00:00
|
|
|
IrqMgrClient irqClient;
|
2021-02-14 00:49:40 +00:00
|
|
|
s16* msg = NULL;
|
2020-05-11 00:04:41 +00:00
|
|
|
|
2024-08-22 20:33:50 +00:00
|
|
|
PRINTF(T("オーディオマネージャスレッド実行開始\n", "Start running audio manager thread\n"));
|
2023-11-30 21:22:30 +00:00
|
|
|
|
|
|
|
// Initialize audio driver
|
2021-11-07 16:58:50 +00:00
|
|
|
Audio_Init();
|
2022-11-17 02:57:02 +00:00
|
|
|
AudioLoad_SetDmaHandler(DmaMgr_AudioDmaHandler);
|
2021-11-07 16:58:50 +00:00
|
|
|
Audio_InitSound();
|
2023-11-30 21:22:30 +00:00
|
|
|
|
|
|
|
// Fill init queue to signal that the audio driver is initialized
|
|
|
|
osSendMesg(&audioMgr->initQueue, NULL, OS_MESG_BLOCK);
|
|
|
|
|
2022-04-09 00:20:23 +00:00
|
|
|
IrqMgr_AddClient(audioMgr->irqMgr, &irqClient, &audioMgr->interruptQueue);
|
2020-05-11 00:04:41 +00:00
|
|
|
|
2023-11-30 21:22:30 +00:00
|
|
|
// Spin waiting for events
|
2024-02-07 16:03:55 +00:00
|
|
|
for (;;) {
|
2022-04-09 00:20:23 +00:00
|
|
|
osRecvMesg(&audioMgr->interruptQueue, (OSMesg*)&msg, OS_MESG_BLOCK);
|
2023-11-30 21:22:30 +00:00
|
|
|
|
2020-05-11 00:04:41 +00:00
|
|
|
switch (*msg) {
|
|
|
|
case OS_SC_RETRACE_MSG:
|
|
|
|
AudioMgr_HandleRetrace(audioMgr);
|
2023-11-30 21:22:30 +00:00
|
|
|
|
|
|
|
// Empty the interrupt queue
|
2022-04-09 00:20:23 +00:00
|
|
|
while (!MQ_IS_EMPTY(&audioMgr->interruptQueue)) {
|
|
|
|
osRecvMesg(&audioMgr->interruptQueue, (OSMesg*)&msg, OS_MESG_BLOCK);
|
2023-11-30 21:22:30 +00:00
|
|
|
|
2020-05-11 00:04:41 +00:00
|
|
|
switch (*msg) {
|
|
|
|
case OS_SC_RETRACE_MSG:
|
2023-11-30 21:22:30 +00:00
|
|
|
// Don't process a retrace more than once in quick succession
|
2020-05-11 00:04:41 +00:00
|
|
|
break;
|
2023-11-30 21:22:30 +00:00
|
|
|
|
2020-05-11 00:04:41 +00:00
|
|
|
case OS_SC_PRE_NMI_MSG:
|
2023-11-30 21:22:30 +00:00
|
|
|
// Always handle Pre-NMI
|
2022-06-03 19:43:30 +00:00
|
|
|
AudioMgr_HandlePreNMI(audioMgr);
|
2020-05-11 00:04:41 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2023-11-30 21:22:30 +00:00
|
|
|
|
2020-05-11 00:04:41 +00:00
|
|
|
case OS_SC_PRE_NMI_MSG:
|
2022-06-03 19:43:30 +00:00
|
|
|
AudioMgr_HandlePreNMI(audioMgr);
|
2020-05-11 00:04:41 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-30 21:22:30 +00:00
|
|
|
/**
|
|
|
|
* Stalls the current thread until the audio thread is sufficiently initialized.
|
|
|
|
*
|
|
|
|
* Note this function only works once. After the first call the message that the audio thread posted to the init queue
|
|
|
|
* will have been removed, subsequent calls to this function will block indefinitely as the audio thread does not refill
|
|
|
|
* the queue.
|
|
|
|
*/
|
|
|
|
void AudioMgr_WaitForInit(AudioMgr* audioMgr) {
|
|
|
|
osRecvMesg(&audioMgr->initQueue, NULL, OS_MESG_BLOCK);
|
2020-05-11 00:04:41 +00:00
|
|
|
}
|
|
|
|
|
2022-06-03 19:43:30 +00:00
|
|
|
void AudioMgr_Init(AudioMgr* audioMgr, void* stack, OSPri pri, OSId id, Scheduler* sched, IrqMgr* irqMgr) {
|
2020-05-11 00:04:41 +00:00
|
|
|
bzero(audioMgr, sizeof(AudioMgr));
|
|
|
|
|
|
|
|
audioMgr->sched = sched;
|
|
|
|
audioMgr->irqMgr = irqMgr;
|
2021-07-27 23:44:58 +00:00
|
|
|
audioMgr->rspTask = NULL;
|
2020-05-11 00:04:41 +00:00
|
|
|
|
2024-08-27 07:33:20 +00:00
|
|
|
#if PLATFORM_N64
|
|
|
|
R_AUDIOMGR_DEBUG_LEVEL = AUDIOMGR_DEBUG_LEVEL_NO_RSP;
|
|
|
|
#endif
|
|
|
|
|
2023-11-30 21:22:30 +00:00
|
|
|
osCreateMesgQueue(&audioMgr->taskDoneQueue, &audioMgr->taskDoneMsg, 1);
|
2022-04-09 00:20:23 +00:00
|
|
|
osCreateMesgQueue(&audioMgr->interruptQueue, audioMgr->interruptMsgBuf, ARRAY_COUNT(audioMgr->interruptMsgBuf));
|
2023-11-30 21:22:30 +00:00
|
|
|
osCreateMesgQueue(&audioMgr->initQueue, &audioMgr->initMsg, 1);
|
2020-05-11 00:04:41 +00:00
|
|
|
|
2023-11-30 21:22:30 +00:00
|
|
|
// Send a message to the task done queue so it is initially full
|
|
|
|
osSendMesg(&audioMgr->taskDoneQueue, NULL, OS_MESG_BLOCK);
|
2020-05-11 00:04:41 +00:00
|
|
|
|
2022-04-09 00:20:23 +00:00
|
|
|
osCreateThread(&audioMgr->thread, id, AudioMgr_ThreadEntry, audioMgr, stack, pri);
|
|
|
|
osStartThread(&audioMgr->thread);
|
2020-05-11 00:04:41 +00:00
|
|
|
}
|