nuaumgr.c
8.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/*======================================================================*/
/* NuSYS */
/* nuaumgr.c */
/* */
/* Copyright (C) 1997, NINTENDO Co,Ltd. */
/* --/--/-- Created by K.Ohki(SLANP) */
/* 98/12/10 Modified by K.Ohki(SLANP) */
/*======================================================================*/
/* $Id: nuaumgr.c,v 1.1.1.1 2002/10/30 02:07:09 blythe Exp $ */
/*======================================================================*/
#include <nusys.h>
#include <nualsgi.h>
static s16* auBuffer_ptr[3]; /* オーディオバッファ */
static void nuAuMgr(void* arg);
static s32 minFrameSampleSize;
static s32 maxFrameSampleSize;
/*----------------------------------------------------------------------*/
/* nuAuMgrInit -オーディオマネージャの初期化 */
/* IN: ヒープバッファの先頭ポインタ */
/* RET: 使用ヒープサイズ */
/*----------------------------------------------------------------------*/
s32 nuAuMgrInit(void* heap_ptr, u32 size, ALSynConfig* synConfig)
{
u32 sampleSize;
u32 frameRate;
nuAuTaskStop = NU_AU_TASK_RUN; /* タスク実行可 */
frameRate = nuScGetFrameRate(); /* フレームレートの取得 */
/* 1フレームに必要なサンプル数の計算。小数点以下切り上げ */
nuAuFrameSampleSize = (nuAuRetraceCount * synConfig->outputRate + frameRate)/frameRate;
nuAuFrameSampleSize += nuAuExtraSampleSize;
sampleSize = nuAuFrameSampleSize + nuAuFrameSampleSize / 4;
#ifdef N_AUDIO
sampleSize = ((sampleSize + NU_AU_AUDIO_SAMPLES - 1) / NU_AU_AUDIO_SAMPLES) * NU_AU_AUDIO_SAMPLES;
minFrameSampleSize = sampleSize;
maxFrameSampleSize = sampleSize + NU_AU_AUDIO_SAMPLES;
#else
sampleSize = (sampleSize + NU_AU_AUDIO_SAMPLES - 1) & ~0x0f;
minFrameSampleSize = nuAuFrameSampleSize & ~0x0f;
maxFrameSampleSize = sampleSize + NU_AU_AUDIO_SAMPLES;
#endif /* N_AUDIO */
/* オーディオヒープの初期化 */
nuAuHeapInit(&nuAuHeap, heap_ptr, size);
/* コマンドリストバッファの確保 */
nuAuCmdListBuf = nuAuHeapAlloc(nuAuAcmdLen * sizeof(Acmd));
/* オーディオバッファの確保 */
auBuffer_ptr[0] = nuAuHeapAlloc(maxFrameSampleSize * sizeof(s32));
auBuffer_ptr[1] = nuAuHeapAlloc(maxFrameSampleSize * sizeof(s32));
auBuffer_ptr[2] = nuAuHeapAlloc(maxFrameSampleSize * sizeof(s32));
/* オーディオマネージャのスタック領域の確保 */
nuAuMgrStack = nuAuHeapAlloc(NU_AU_STACK_SIZE);
/* シンセサイズドライバの初期化 */
synConfig->dmaproc = nuAuDmaNew;
synConfig->heap = &nuAuHeap;
synConfig->outputRate = osAiSetFrequency(synConfig->outputRate);
alInit(&nuAuGlobal, synConfig);
nuAuTask.msg = 0;/* reply with this message */
nuAuTask.list.t.type = M_AUDTASK;
nuAuTask.list.t.ucode_boot = (u64*)rspbootTextStart;
nuAuTask.list.t.ucode_boot_size =
((int) rspbootTextEnd - (int) rspbootTextStart);
#ifdef N_AUDIO
nuAuTask.list.t.ucode = (u64*) n_aspMainTextStart;
nuAuTask.list.t.ucode_data = (u64 *) n_aspMainDataStart;
#else
nuAuTask.list.t.ucode = (u64*) aspMainTextStart;
nuAuTask.list.t.ucode_data = (u64 *) aspMainDataStart;
#endif /* N_AUDIO */
nuAuTask.list.t.ucode_data_size = SP_UCODE_DATA_SIZE;
nuAuTask.list.t.dram_stack = (u64 *) NULL;
nuAuTask.list.t.dram_stack_size = 0;
nuAuTask.list.t.output_buff = (u64 *) NULL;
nuAuTask.list.t.output_buff_size = 0;
nuAuTask.list.t.yield_data_ptr = NULL;
nuAuTask.list.t.yield_data_size = 0;
nuAuSeqPlayer[0].mode = 0;
nuAuSeqPlayer[1].mode = 0;
nuAuSeqPlayer[0].data_ptr = NULL;
nuAuSeqPlayer[1].data_ptr = NULL;
/* オーディオマネージャの起動 */
osCreateThread(&nuAuMgrThread, NU_AU_MGR_THREAD_ID, nuAuMgr, (void*)NULL,
(nuAuMgrStack + NU_AU_STACK_SIZE/sizeof(u64)),
NU_AU_MGR_THREAD_PRI);
osStartThread(&nuAuMgrThread);
/* 使用しているヒープサイズを返す */
return nuAuHeapGetUsed();
}
/*----------------------------------------------------------------------*/
/* nuAuMgr - オーディオマネージャ */
/* IN: 無し */
/* RET: 無し */
/*----------------------------------------------------------------------*/
static void nuAuMgr(void* arg)
{
OSMesgQueue nuAuRtnMesgQ;
OSMesg nuAuRtnMesgBuf;
OSMesg nuAuMsgBuf[NU_AU_MESG_MAX];
s32 sampleSize[3];
NUScMsg* mesg_type;
s32 samplesLeft, Samples=0;
Acmd* cmdListAfter_ptr;
s32 cmdList_len;
u32 status;
s32 frameSampleSize;
u32 bufCnt;
u32 bufPtr;
s32 readCnt;
osCreateMesgQueue(&nuAuMesgQ, nuAuMsgBuf, NU_AU_MESG_MAX);
/* オーディオタスクスレッドからのメッセージ待ちキュー */
osCreateMesgQueue(&nuAuRtnMesgQ, &nuAuRtnMesgBuf, 1);
/* スケジューラにRETRACEクライアント登録 */
nuScAddClient(&nuAuClient, &nuAuMesgQ, NU_SC_RETRACE_MSG | NU_SC_PRENMI_MSG);
frameSampleSize = nuAuFrameSampleSize * 2 + nuAuFrameSampleSize / 2;
cmdList_len = 0;
bufCnt = 0;
readCnt = 0;
bufPtr = 0;
while(1){
(void)osRecvMesg(&nuAuMesgQ, (OSMesg*)&mesg_type, OS_MESG_BLOCK);
#ifdef NU_DEBUG
if((nuAuDebFlag & NU_AU_DEBUG_RETRACEOFF)
&&(*mesg_type == NU_SC_RETRACE_MSG)){
continue;
}
#endif /* NU_DEBUG */
switch(*mesg_type){
#ifdef NU_DEBUG
case NU_AU_AI_DEBUG_MSG:
#endif /* NU_DEBUG */
case NU_SC_RETRACE_MSG:
/* AIのDMAレジスタの状態を取得 */
status = osAiGetStatus();
if(status & AI_STATUS_FIFO_FULL){
continue;
}
/* AIバッファに残存するサンプル数をゲット */
samplesLeft = osAiGetLength() >> 2;
#ifdef NU_DEBUG
if(nuAuDebFlag & NU_AU_DEBUG_NORMAL){
if(!samplesLeft && (nuAuFrameCounter > 4)){
osSyncPrintf("nuAuMgr: no samples left!!\n");
}
}
#endif /* NU_DEBUG */
/* この部分は,ループの1回目は実行されません */
/* というのもループの1回目はまだデータが作成されてないから */
if(bufCnt){
#ifdef NU_DEBUG
if(!(nuAuDebFlag & NU_AU_DEBUG_DISABLEAI)){
#endif /* NU_DEBUG */
/* バッファの切り替え。これによりAIにデータが送られて音が鳴る*/
osAiSetNextBuffer(auBuffer_ptr[readCnt], sampleSize[readCnt]<<2);
#ifdef NU_DEBUG
}
#endif /* NU_DEBUG */
Samples = sampleSize[readCnt];
readCnt = (readCnt + 1) % 3;
bufCnt--;
}
/* タスク起動。コマンドリストが無い場合はタスクを起動しない */
if(cmdList_len && (nuAuTaskStop)) {
#ifdef NU_DEBUG
if(!(nuAuDebFlag & NU_AU_DEBUG_DISABLETASK)){
#endif /* NU_DEBUG */
nuAuTask.list.t.data_ptr = (u64 *)nuAuCmdListBuf;
nuAuTask.list.t.data_size =
(cmdListAfter_ptr - nuAuCmdListBuf) * sizeof(Acmd);
nuAuTask.msgQ = &nuAuRtnMesgQ;
osSendMesg(&nusched.audioRequestMQ, (OSMesg*)&nuAuTask, OS_MESG_BLOCK);
osRecvMesg(&nuAuRtnMesgQ, NULL, OS_MESG_BLOCK);
#ifdef NU_DEBUG
}
#endif /* NU_DEBUG */
/* DMAバッファのクリア。 */
/* 2フレーム未使用のバッファはクリアする */
nuAuCleanDMABuffers();
cmdList_len = 0;
bufPtr = (bufPtr + 1) % 3;
bufCnt++;
}
/* サンプル数の制御方法 */
/* 現在転送中のDMAの残りサンプル数と次に転送されるサンプル数*/
/* からこのフレームで作成するサンプル数を算出する。 */
/* この合計と1.25フレーム分のサンプル数の差をとり, */
/* FIFOバッファに設定されている合計サンプル数が1.25フレーム */
/* 分になるようにサンプル数を制御するように計算。 */
Samples = frameSampleSize - (Samples + samplesLeft);
if(Samples > maxFrameSampleSize){
Samples = maxFrameSampleSize;
} else if(Samples < minFrameSampleSize){
Samples = minFrameSampleSize;
} else {
#ifdef N_AUDIO
Samples = ((Samples + NU_AU_AUDIO_SAMPLES -1)/NU_AU_AUDIO_SAMPLES) * NU_AU_AUDIO_SAMPLES;
#else
Samples = (Samples + NU_AU_AUDIO_SAMPLES - 1) & ~0x0f;
#endif /* N_AUDIO */
}
/* オーディオコマンドリストの作成 */
cmdListAfter_ptr = alAudioFrame(nuAuCmdListBuf, &cmdList_len,
(s16*)osVirtualToPhysical(auBuffer_ptr[bufPtr]),
Samples);
sampleSize[bufPtr] = Samples;
Samples = 0;
/* シーケンスのコントロール */
if(nuAuMgrFunc){
(*nuAuMgrFunc)();
}
#ifdef NU_DEBUG
/* オーディオコマンドリストのサイズの最大値の更新 */
if(cmdList_len >= nuAuDebAcmdLenMax){
nuAuDebAcmdLenMax = cmdList_len;
}
if(cmdList_len >= nuAuAcmdLen){
if(nuAuDebFlag & NU_AU_DEBUG_NORMAL){
osSyncPrintf("nuAuMgr: cmdlist_len %d is too big.\n",
cmdList_len);
}
nuAuDebStatus |= NU_AU_DEBUG_ACMDBUFOVER;
}
#endif /* NU_DEBUG */
/* PRE NMIメッセージが来たら,その後この関数が呼ばれつづける */
if((u32)nuAuPreNMIFunc && nuAuPreNMI){
(*nuAuPreNMIFunc)(NU_SC_RETRACE_MSG, nuAuPreNMI);
nuAuPreNMI++;
}
break;
case NU_SC_PRENMI_MSG:
/* PRE NMIメッセージがきたら関数を呼ぶ */
if(nuAuPreNMIFunc){
(*nuAuPreNMIFunc)(NU_SC_PRENMI_MSG, nuAuPreNMI);
}
nuAuPreNMI++;
break;
default:
#ifdef NU_DEBUG
osSyncPrintf("nuAuMgr: Unknown message %d received \n", *mesg_type);
#endif /* NU_DEBUG */
break;
}
}
}