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