1 /*---------------------------------------------------------------------------*
2   Project:  Audio visualization tools
3   File:     DEMOAVX.c
4 
5   Copyright 2001 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   $Log: DEMOAVX.c,v $
14   Revision 2.0  2006/02/20 04:37:44  ceb
15   Ported from revolution to cafe.
16 
17   Revision 1.2  2006/02/20 04:37:44  mitu
18   Changed include path from dolphin/ to revolution/.
19 
20   Revision 1.1.1.1  2005/05/12 02:15:48  yasuh-to
21   Ported from dolphin sheath tree.
22 
23 
24     1     2002/01/11 4:55p Eugene
25     Cheesy method for snooping output from DSP/input to AI-FIFO. It is
26     audio-system agnostic, however.
27 
28 
29   $NoKeywords: $
30  *---------------------------------------------------------------------------*/
31 
32 /*---------------------------------------------------------------------------*
33  * Includes
34  *---------------------------------------------------------------------------*/
35 
36 #include <stdlib.h>
37 #include <stddef.h>
38 #include <string.h>
39 #include <math.h>
40 
41 #include <cafe/demo.h>
42 #include <cafe/ai.h>
43 
44 #define AVX_INTERNAL_NUM_FRAMES  10     // Buffer for up to 10 frames (in case the frame rate drops to around 20 fps).
45 
46 ALIGNED_VAR(static s16, 32, __AVX_internal_buffer[AVX_FRAME_SIZE_WORDS*AVX_INTERNAL_NUM_FRAMES]);
47 
48 
49 static void (*__AVX_save_isr)(void);    // AVX callback for the AI-FIFO DMA interrupt.
50 
51 static u32  __AVX_num_frames;           // Number of audio frames to buffer.
52 static u32  __AVX_num_filled;           // Number of frames filled since the last user refresh.
53 static u32  __AVX_curr_frame;
54 
55 static u16 *__AVX_buffer;               // Internal AI-FIFO buffer.
56 static s16 *__AVX_left_buffer;          // Pointer to the caller's left-channel sample buffer.
57 static s16 *__AVX_right_buffer;         // Pointer to the caller's right-channel sample buffer.
58 
59 static u32  __AVX_write_ptr    = 0;
60 static u32  __AVX_buffer_size  = 0;
61 
62 static OSMutex __AVX_mutex;
63 
64 /*---------------------------------------------------------------------------*
65  * Name        :
66  * Description :
67  * Arguments   : None.
68  * Returns     : None.
69  *---------------------------------------------------------------------------*/
70 
71 static BOOL flag = FALSE;
72 
__DEMOAVX_isr(void)73 static void __DEMOAVX_isr(void)
74 {
75     u32 frame_address;
76 
77     if (__AVX_save_isr)
78     {
79         (*__AVX_save_isr)();
80 
81 
82         // Get the current address of the current AI-FIFO DMA transaction.
83         frame_address = AIGetDMAStartAddr();
84 
85         // Freak out if the address is NULL
86         ASSERTMSG(frame_address, "AVX: frame address is NULL!\n");
87 
88         // Invalidate source (DSP output/AI-FIFO input)
89         //DCInvalidateRange((void *)(frame_address), AVX_FRAME_SIZE_BYTES);
90 
91         // Copy output from DSP into the AVX buffer.
92         memcpy((void *)(&__AVX_buffer[__AVX_curr_frame * AVX_FRAME_SIZE_WORDS]), (void *)(frame_address), AVX_FRAME_SIZE_BYTES);
93 
94         // Flush newly copied data from the cache.
95         //DCFlushRange((void *)(&__AVX_buffer[__AVX_curr_frame * AVX_FRAME_SIZE_WORDS]), AVX_FRAME_SIZE_BYTES);
96 
97         // Increment the frame pointer.
98         __AVX_curr_frame = (__AVX_curr_frame + 1) % __AVX_num_frames;
99 
100         // Increment the frame counter.
101         __AVX_num_filled = (__AVX_num_filled + 1) % AVX_INTERNAL_NUM_FRAMES;
102 
103         if (__AVX_curr_frame > 4)
104             flag = TRUE;
105     }
106 } // end __DEMOAVX_isr
107 
108 /*---------------------------------------------------------------------------*
109  * Name        :
110  * Description :
111  * Arguments   : None.
112  * Returns     : None.
113  *---------------------------------------------------------------------------*/
114 
115 
DEMOAVXGetNumFilled(void)116 u32 DEMOAVXGetNumFilled(void)
117 {
118     u32  tmp;
119 
120     OSLockMutex(&__AVX_mutex);
121 
122     tmp = __AVX_num_filled;
123     __AVX_num_filled = 0;
124 
125     OSUnlockMutex(&__AVX_mutex);
126 
127     return(tmp);
128 } // end DEMOAVXGetNumFilled()
129 
130 /*---------------------------------------------------------------------------*
131  * Name        :
132  * Description :
133  * Arguments   : None.
134  * Returns     : None.
135  *---------------------------------------------------------------------------*/
136 
DEMOAVXGetFrameCounter(void)137 u32 DEMOAVXGetFrameCounter(void)
138 {
139     return(__AVX_curr_frame);
140 } // end DEMOAVXGetFrameCounter()
141 
142 /*---------------------------------------------------------------------------*
143  * Name        :
144  * Description :
145  * Arguments   : None.
146  * Returns     : None.
147  *---------------------------------------------------------------------------*/
148 
DEMOAVXRefreshBuffer(u32 * start_index,u32 * end_index)149 u32 DEMOAVXRefreshBuffer(u32 *start_index, u32 *end_index)
150 {
151     u32  num_filled;
152     u32  curr_frame;
153 
154     u32 i;
155     u32 j;
156 
157     if (flag)
158     {
159         OSLockMutex(&__AVX_mutex);
160         //
161         num_filled = DEMOAVXGetNumFilled();
162 
163         // Rewind back through the AI buffer
164         curr_frame = (__AVX_num_frames + DEMOAVXGetFrameCounter() - num_filled) % __AVX_num_frames;
165 
166         OSUnlockMutex(&__AVX_mutex);
167 
168         // Save the starting position in the final sample buffer.
169         *start_index = __AVX_write_ptr;
170 
171         for (i=0; i<num_filled; i++)
172         {
173             // Invalidate the AI buffer range
174             //DCInvalidateRange( (void *)(&__AVX_buffer[curr_frame * AVX_FRAME_SIZE_WORDS]), AVX_FRAME_SIZE_BYTES);
175 
176             for (j=0; j<AVX_FRAME_SIZE_WORDS; j+=2)
177             {
178                 __AVX_left_buffer [__AVX_write_ptr] = (s16)(__AVX_buffer[curr_frame * AVX_FRAME_SIZE_WORDS + j]);
179                 __AVX_right_buffer[__AVX_write_ptr] = (s16)(__AVX_buffer[curr_frame * AVX_FRAME_SIZE_WORDS + j + 1]);
180 
181                 __AVX_write_ptr = (__AVX_write_ptr + 1) % __AVX_buffer_size;
182             }
183 
184             curr_frame = (curr_frame + 1) % __AVX_num_frames;
185         }
186 
187         *end_index = __AVX_write_ptr;
188 
189         return(num_filled*AVX_FRAME_SIZE_SAMPLES);
190     }
191 
192     return(0);
193 } // end DEMOAudioRefreshBuffer()
194 
195 /*---------------------------------------------------------------------------*
196  * Name        :
197  * Description :
198  * Arguments   : None.
199  * Returns     : None.
200  *---------------------------------------------------------------------------*/
201 
DEMOAVXInit(s16 * left,s16 * right,u32 size)202 void DEMOAVXInit(s16 *left, s16 *right, u32 size)
203 {
204 
205     __AVX_left_buffer  = left;
206     __AVX_right_buffer = right;
207 
208     __AVX_write_ptr = 0;
209 
210     __AVX_buffer_size = size;
211 
212     OSInitMutex(&__AVX_mutex);
213 
214     DEMOAVXAttach((void *)__AVX_internal_buffer, AVX_INTERNAL_NUM_FRAMES);
215 } // end DEMOAVXInit()
216 
217 /*---------------------------------------------------------------------------*
218  * Name        :
219  * Description :
220  * Arguments   : None.
221  * Returns     : None.
222  *---------------------------------------------------------------------------*/
223 
224 
DEMOAVXAttach(void * buffer,u32 num_frames)225 void DEMOAVXAttach(void *buffer, u32 num_frames)
226 {
227     u32  i;
228 
229     __AVX_buffer     = (u16 *)buffer;
230     __AVX_num_frames = num_frames;
231     __AVX_num_filled = 0;
232     __AVX_curr_frame = 0;
233 
234     // Clear the buffer.
235     for (i=0; i<(num_frames*AVX_FRAME_SIZE_WORDS); i++)
236         *(__AVX_buffer + i) = 0;
237 
238     // Attach the AVX interrupt handler.
239     __AVX_save_isr = AIRegisterDMACallback(__DEMOAVX_isr);
240 } // end DEMOAVXAttach()
241