1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - SND - demos - synth
3 File: main.c
4
5 Copyright 2007-2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: 2008-09-18#$
14 $Rev: 8573 $
15 $Author: okubata_ryoma $
16 *---------------------------------------------------------------------------*/
17
18 //---------------------------------------------------------------------------
19 // USAGE:
20 // Touch panel: play
21 //---------------------------------------------------------------------------
22
23 #ifdef SDK_TWL
24 #include <twl.h>
25 #else
26 #include <nitro.h>
27 #endif
28
29 #define CHANNEL_NUM 4
30 #define ALARM_NUM 0
31 #define STREAM_THREAD_PRIO 12
32 #define THREAD_STACK_SIZE 1024
33 #define STRM_BUF_PAGESIZE 64*32
34 #define STRM_BUF_SIZE STRM_BUF_PAGESIZE*2
35 #define STRM_SAMPLE_RATE 44100
36 #define OSC_MAX_VOLUME 18767
37
38 // Derive the frequency from the key number
39 #define GetFreq(pitch) (SND_TIMER_CLOCK / SND_CalcTimer((SND_TIMER_CLOCK / 440), (pitch - 69 * 64)))
40
41 // Stream object
42 typedef struct StreamInfo
43 {
44 u32 bufPage;
45 }
46 StreamInfo;
47
48 // Touch panel
49 typedef struct TpData
50 {
51 int touch:1;
52 int trg:1;
53 int rls:1;
54 u16 x;
55 u16 y;
56 }
57 TpData;
58
59 // Oscillator
60 typedef struct Oscillator
61 {
62 fx16 index;
63 fx16 step;
64 fx32 rate; // Output sampling rate
65 u16 gain;
66 u16 dummy;
67 }
68 Oscillator;
69
70
71 static void SoundAlarmHandler(void *arg);
72 static void StrmThread(void *arg);
73 static void Play(StreamInfo * strm);
74 static void Stop();
75 static void MakeStreamData(StreamInfo * strm);
76
77 static void VBlankIntr(void);
78 static void TpRead(void);
79
80 static u16 Cont;
81 static u16 Trg;
82 static TpData tp;
83 static u64 strmThreadStack[THREAD_STACK_SIZE / sizeof(u64)];
84 static OSThread strmThread;
85 static OSMessageQueue msgQ;
86 static OSMessage msgBuf[1];
87
88 static u8 strmBuf[STRM_BUF_SIZE] ATTRIBUTE_ALIGN(32);
89
90 static Oscillator osc;
91 static TPCalibrateParam calibrate;
92
93 /*---------------------------------------------------------------------------*
94 Name: NitroMain
95
96 Description: Main.
97
98 Arguments: None.
99
100 Returns: None.
101 *---------------------------------------------------------------------------*/
NitroMain()102 void NitroMain()
103 {
104 StreamInfo strm;
105
106 // Initialization
107 OS_Init();
108 OS_InitThread();
109 GX_Init();
110 FX_Init();
111 SND_Init();
112 TP_Init();
113
114 // Initializes touch panel read
115 (void)TP_GetUserInfo(&calibrate);
116 TP_SetCalibrateParam(&calibrate);
117 tp.touch = 0;
118 tp.trg = 0;
119 tp.rls = 0;
120
121 // Oscillator settings
122 osc.rate = STRM_SAMPLE_RATE << FX32_SHIFT;
123
124 // V-Blank interrupt settings
125 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
126 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
127 (void)OS_EnableIrq();
128 (void)GX_VBlankIntr(TRUE);
129
130 // Print usage
131 OS_Printf("=================================\n");
132 OS_Printf("USAGE:\n");
133 OS_Printf(" Touch panel : play\n");
134 OS_Printf(" Release panel: stop\n");
135 OS_Printf("=================================\n");
136
137 // Lock the channel
138 SND_LockChannel(1 << CHANNEL_NUM, 0);
139
140 /* Startup stream thread */
141 OS_InitMessageQueue(&msgQ, msgBuf, 1);
142 OS_CreateThread(&strmThread,
143 StrmThread,
144 NULL,
145 strmThreadStack + THREAD_STACK_SIZE / sizeof(u64),
146 THREAD_STACK_SIZE, STREAM_THREAD_PRIO);
147 OS_WakeupThreadDirect(&strmThread);
148
149 //================ Main loop
150 while (1)
151 {
152 u16 ReadData;
153
154 OS_WaitVBlankIntr();
155
156 // Receive ARM7 command reply
157 while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL)
158 {
159 }
160
161 ReadData = PAD_Read();
162 TpRead();
163 Trg = (u16)(ReadData & (ReadData ^ Cont));
164 Cont = ReadData;
165
166 if (tp.touch)
167 {
168 osc.step = (fx16)FX_Div(GetFreq(tp.x * 4 + 60 * 64) << FX32_SHIFT, osc.rate);
169 osc.gain = (u16)(tp.y * OSC_MAX_VOLUME / 192);
170 }
171
172 // Plays the PSG square wave
173 if (tp.trg)
174 {
175 Play(&strm);
176 }
177
178 if (tp.rls)
179 {
180 Stop();
181 }
182
183 // Command flush
184 (void)SND_FlushCommand(SND_COMMAND_NOBLOCK);
185 }
186 }
187
188 /*---------------------------------------------------------------------------*
189 Name: Play
190
191 Description: Plays streaming playback.
192
193 Arguments: strm: Stream object
194 filename: Name of the streaming playback file
195
196 Returns: None.
197 *---------------------------------------------------------------------------*/
Play(StreamInfo * strm)198 static void Play(StreamInfo * strm)
199 {
200 s32 timerValue;
201 u32 alarmPeriod;
202
203 osc.index = 0;
204
205 /* Set parameters */
206 timerValue = SND_TIMER_CLOCK / STRM_SAMPLE_RATE;
207 alarmPeriod = timerValue * (STRM_BUF_PAGESIZE / sizeof(s16)) / 32;
208
209 // Read initial stream data
210 strm->bufPage = 0;
211 MakeStreamData(strm);
212 MakeStreamData(strm);
213
214 // Set up the channel and alarm
215 SND_SetupChannelPcm(CHANNEL_NUM,
216 SND_WAVE_FORMAT_PCM16,
217 strmBuf,
218 SND_CHANNEL_LOOP_REPEAT,
219 0,
220 STRM_BUF_SIZE / sizeof(u32),
221 127, SND_CHANNEL_DATASHIFT_NONE, timerValue, 64);
222 SND_SetupAlarm(ALARM_NUM, alarmPeriod, alarmPeriod, SoundAlarmHandler, strm);
223 SND_StartTimer(1 << CHANNEL_NUM, 0, 1 << ALARM_NUM, 0);
224 }
225
226 /*---------------------------------------------------------------------------*
227 Name: StopStream
228
229 Description: Stops streaming playback.
230
231 Arguments: strm: Stream object
232
233 Returns: None.
234 *---------------------------------------------------------------------------*/
Stop()235 static void Stop()
236 {
237 SND_StopTimer(1 << CHANNEL_NUM, 0, 1 << ALARM_NUM, 0);
238 }
239
240 /*---------------------------------------------------------------------------*
241 Name: StrmThread
242
243 Description: The stream thread.
244
245 Arguments: arg: User data (unused)
246
247 Returns: None.
248 *---------------------------------------------------------------------------*/
StrmThread(void *)249 static void StrmThread(void * /*arg */ )
250 {
251 OSMessage message;
252
253 while (1)
254 {
255 (void)OS_ReceiveMessage(&msgQ, &message, OS_MESSAGE_BLOCK);
256 (void)MakeStreamData((StreamInfo *) message);
257 }
258 }
259
260 /*---------------------------------------------------------------------------*
261 Name: SoundAlarmHandler
262
263 Description: Alarm callback function.
264
265 Arguments: arg: Stream object
266
267 Returns: None.
268 *---------------------------------------------------------------------------*/
SoundAlarmHandler(void * arg)269 static void SoundAlarmHandler(void *arg)
270 {
271 (void)OS_SendMessage(&msgQ, (OSMessage)arg, OS_MESSAGE_NOBLOCK);
272 }
273
274 /*---------------------------------------------------------------------------*
275 Name: MakeStreamData
276
277 Description: Generates stream data.
278
279 Arguments: strm: Stream object
280
281 Returns: None.
282 *---------------------------------------------------------------------------*/
MakeStreamData(StreamInfo * strm)283 static void MakeStreamData(StreamInfo * strm)
284 {
285 u8 *buf;
286 int i;
287
288 // Buffer page settings
289 if (strm->bufPage == 0)
290 {
291 buf = strmBuf;
292 strm->bufPage = 1;
293 }
294 else
295 {
296 buf = strmBuf + STRM_BUF_PAGESIZE;
297 strm->bufPage = 0;
298 }
299
300 // Generates data
301 for (i = 0; i < STRM_BUF_PAGESIZE / sizeof(s16); i++)
302 {
303 ((s16 *)buf)[i] = (s16)FX_Whole(FX_Mul32x64c(osc.gain << FX32_SHIFT,
304 FX_SinFx64c(FX_Mul32x64c(osc.index,
305 FX64C_TWOPI))));
306 osc.index += osc.step;
307 osc.index &= FX32_DEC_MASK;
308 }
309
310 DC_StoreRange( strmBuf, sizeof(strmBuf) );
311 }
312
313 //--------------------------------------------------------------------------------
314 // V-Blank interrupt process
315 //
VBlankIntr(void)316 static void VBlankIntr(void)
317 {
318 // Interrupt check flag
319 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
320 }
321
322 /*---------------------------------------------------------------------------*
323 Name: TpRead
324
325 Description: Reads the touch panel.
326
327 Arguments: None.
328
329 Returns: None.
330 *---------------------------------------------------------------------------*/
TpRead(void)331 void TpRead(void)
332 {
333 TPData tp_data;
334 TPData tp_raw;
335 int old;
336
337 old = tp.touch;
338 while (TP_RequestRawSampling(&tp_raw) != 0)
339 {
340 };
341 TP_GetCalibratedPoint(&tp_data, &tp_raw);
342
343 tp.touch = tp_data.touch;
344 tp.trg = tp.touch & (tp.touch ^ old);
345 tp.rls = old & (old ^ tp.touch);
346
347 switch (tp_data.validity)
348 {
349 case TP_VALIDITY_VALID:
350 tp.x = tp_data.x;
351 tp.y = tp_data.y;
352 break;
353 case TP_VALIDITY_INVALID_X:
354 tp.y = tp_data.y;
355 break;
356 case TP_VALIDITY_INVALID_Y:
357 tp.x = tp_data.x;
358 break;
359 case TP_VALIDITY_INVALID_XY:
360 break;
361 default:
362 break;
363 }
364 }
365