test_music.c
8.28 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
281
282
283
284
285
286
287
/*************************************************************
test_music.c : Nintendo 64 Music Tools Library Sample
(c) Copyright 1998, Software Creations (Holdings) Ltd.
Version 3.11
NNSCHED demo main source file. This demo illustrates how to
use a scheduler other than the default OS scheduler.
**************************************************************/
/* include system header files */
#ifndef F3DEX_GBI
#define F3DEX_GBI
#endif
#include <ultra64.h>
#include <libmus.h>
#include <libmus_data.h>
#include "nnsched.h"
/* include current header file */
#include "test_rom.h"
/* internal function prototypes */
static void DmaRomToRam(void *rom, void *ram, int len);
/* music library callback function prototypes these prototypes must match the
typedefs of the callback functions specified in "libmus.h":
typedef void (*LIBMUScb_install) (void);
typedef void (*LIBMUScb_waitframe) (void);
typedef void (*LIBMUScb_dotask) (musTask *);
*/
static void NnSchedInstall(void);
static void NnSchedWaitFrame(void);
static void NnSchedDoTask(musTask *task);
/* music library scheduler callback structure */
static musSched nn_mus_sched =
{
NnSchedInstall, NnSchedWaitFrame, NnSchedDoTask
};
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
[GLOBAL FUNCTION]
InitMusicDriver()
[Explantion]
Download ROM files and initialise the music player.
[Return value]
NONE
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* ROM addresses */
#define WBANK_START _wbankSegmentRomStart
#define PBANK_START _pbankSegmentRomStart
#define PBANK_END _pbankSegmentRomEnd
#define MUSIC1_START _tune1SegmentRomStart
#define MUSIC1_END _tune1SegmentRomEnd
extern char WBANK_START[];
extern char PBANK_START[];
extern char PBANK_END[];
extern char MUSIC1_START[];
extern char MUSIC1_END[];
/* permanent RAM buffers */
#define AUDIO_HEAP_SIZE 300000
#define PBANK_SIZE 5000
#define TUNE_SIZE 8000
unsigned char audio_memory [AUDIO_HEAP_SIZE];
unsigned char pointer_buf [PBANK_SIZE];
/* make sure tune is 32bit aligned */
unsigned int tune_buf1 [TUNE_SIZE/sizeof(int)];
void InitMusicDriver(void)
{
musConfig init;
/* donwload sample .ptr and song .bin file to RAM */
DmaRomToRam(PBANK_START, pointer_buf, PBANK_END-PBANK_START);
DmaRomToRam(MUSIC1_START, (unsigned char *)tune_buf1, MUSIC1_END-MUSIC1_START);
/* setup configuration structure */
init.control_flag = 0;
init.channels = 28; /* lots of channels! */
init.sched = ≻
init.thread_priority = 12;
init.heap = audio_memory;
init.heap_length = AUDIO_HEAP_SIZE;
init.fifo_length = 64;
init.ptr = pointer_buf;
init.wbk = WBANK_START;
init.default_fxbank = NULL;
init.syn_output_rate = 44100;
init.syn_updates = 256;
init.syn_rsp_cmds = 4096;
init.syn_retraceCount= 1;
init.syn_num_dma_bufs= 36;
init.syn_dma_buf_size= 0x800;
/* set for NN scheduler this function must be called before 'musInitialize'
otherwise default scheduler will be initialised and used */
MusSetScheduler(&nn_mus_sched);
MusInitialize(&init);
}
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
[INTERNAL FUNCTION]
DmaRomToRam(rom, ram, len)
[Parameters]
rom address of ROM source
ram address of RAM destination
len number of bytes to transfer
[Explantion]
Download an area of ROM to RAM. Note this function limits the size of any DMA
generated to 16k so as to cause clashes with audio DMAs.
[Return value]
NONE
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* avoid DMA clashes */
#define DMA_LEN 16384
static void DmaRomToRam(void *rom, void *ram, int len)
{
OSIoMesg io_mesg;
OSMesg dummyMesg;
int length;
u32 src;
unsigned char *dest;
src = (u32)rom;
dest = ram;
while (len)
{
if (len>DMA_LEN)
length = DMA_LEN;
else
length = len;
osInvalDCache(dest, length);
osPiStartDma(&io_mesg, OS_MESG_PRI_NORMAL, OS_READ, src, dest, length, &dma_queue);
osRecvMesg(&dma_queue, &dummyMesg, OS_MESG_BLOCK);
src+=length;
dest+=length;
len-=length;
}
}
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
[MUSIC LIBRARY CALLBACK FUNCTION]
NnSchedInstall()
[Explantion]
Initialise the NN scheduler callback functions for the music library. This function
is called once by the audio thread before entering an infinite loop.
[Return value]
NONE
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* scheduler callback functions workspace */
#define QUEUE_SIZE 4
static NNScClient nnclient;
static OSMesgQueue nnframe_queue;
static OSMesgQueue nntask_queue;
static OSMesg nnframe_messages [QUEUE_SIZE];
static OSMesg nntask_messages [QUEUE_SIZE];
static void NnSchedInstall(void)
{
/* create message queues for WaitFrame and DoTask functions */
osCreateMesgQueue(&nnframe_queue, &nnframe_messages[0], QUEUE_SIZE);
osCreateMesgQueue(&nntask_queue, &nntask_messages[0], QUEUE_SIZE);
/* add waitframe client */
nnScAddClient(&sc, &nnclient, &nnframe_queue);
}
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
[MUSIC LIBRARY CALLBACK FUNCTION]
NnSchedWaitFrame()
[Explantion]
Wait for a retrace message for the music library. This function is called by the
audio threads inifinite loop to wait for a retrace message. The 'syn_retraceCount'
parameter of the musConfig structure must contain the number of retraces per
message received.
[Return value]
NONE
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
static void NnSchedWaitFrame(void)
{
NNScMsg *message;
do
{
osRecvMesg(&nnframe_queue, (OSMesg *)&message, OS_MESG_BLOCK);
osRecvMesg(&nnframe_queue, NULL, OS_MESG_NOBLOCK); /* bin any missed syncs! */
} while (*message!=NN_SC_RETRACE_MSG);
}
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
[MUSIC LIBRARY CALLBACK FUNCTION]
NnSchedDoTask()
[Parameters]
task address of the music library task descriptor structure
[Explantion]
Process a audio task for the music library. This function is called by the audio
threads inifinite loop to generate an audio task and wait for its completion.
The structure passed is defined in "libmus.h" and is defined as:
typedef struct
{
u64 *data;
int data_size;
u64 *ucode;
u64 *ucode_data;
} musTask;
The 'data' and 'data_size' components of the structure relate to the command list
to be processed. 'data' is the address of the command list and 'data_size' is the
number of commands it contains.
The 'ucode' and 'ucode_data' components of the structure relate to the microcode
to be used. 'ucode' is the address of the microcode Text section, 'ucode_data' is
the address of the microcode Data section.
[Return value]
NONE
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
static void NnSchedDoTask(musTask *task)
{
NNScTask t;
NNScMsg message;
/* copy settings from musTask structure */
t.list.t.data_ptr = task->data;
t.list.t.data_size = task->data_size;
t.list.t.ucode = (u64 *) task->ucode;
t.list.t.ucode_data = (u64 *) task->ucode_data;
/* fill in the rest of task data */
t.next = 0;
t.msgQ = &nntask_queue;
t.msg = &message;
t.list.t.type = M_AUDTASK;
t.list.t.ucode_boot = (u64 *)rspbootTextStart;
t.list.t.ucode_boot_size = ((int) rspbootTextEnd - (int) rspbootTextStart);
t.list.t.flags = 0;
t.list.t.ucode_size = 4096;
t.list.t.ucode_data_size = SP_UCODE_DATA_SIZE;
t.list.t.dram_stack = (u64 *) NULL;
t.list.t.dram_stack_size = 0;
t.list.t.output_buff = (u64 *) NULL;
t.list.t.output_buff_size = 0;
t.list.t.yield_data_ptr = NULL;
t.list.t.yield_data_size = 0;
/* start task */
osSendMesg(nnScGetAudioMQ(&sc), (OSMesg) &t, OS_MESG_BLOCK);
/* wait for task to finish */
osRecvMesg(&nntask_queue, NULL, OS_MESG_BLOCK);
}
/* end of file */