1 /*---------------------------------------------------------------------------*
2   Project:  Revolution PMIC graphic demo
3   File:     pmic_graphic.c
4 
5   Copyright (C)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   $Log: pmic_graphic.c,v $
14   Revision 1.4.2.3  2009/12/14 00:21:52  aka
15   Fixed misspelling.
16 
17   Revision 1.4.2.2  2009/11/19 07:30:49  aka
18   Copied from HEAD.
19 
20   Revision 1.7  2009/11/19 07:28:06  aka
21   Removed WPADShutdown() & WPADDisconnect().
22 
23   Revision 1.6  2009/10/15 07:48:10  aka
24   Changed from tab to spaces.
25 
26   Revision 1.5  2009/10/15 07:45:29  aka
27   Revised error handling of PMICQuit().
28 
29   Revision 1.4  2009/04/17 06:34:21  ozeki_kohei
30   Correct behavior for the case that device is detached while PMICQuit().
31 
32   Revision 1.3  2009/04/02 01:49:07  dante.treglia
33   * Added shutdown code.
34 
35   Revision 1.2  2008/09/10 21:10:36  carlmu
36   Fixed read code to better deal with end-of-buffer wrap-around.
37 
38   Revision 1.1  2008/08/06 01:39:14  carlmu
39   Added graphic demo.
40 
41   $NoKeywords: $
42  *---------------------------------------------------------------------------*/
43 
44 #include <string.h>
45 #include <demo.h>
46 #include <revolution/mem.h>
47 #include <revolution/pmic.h>
48 #include <revolution/wpad.h>
49 
50 #include "audio.h"
51 
52 BOOL  PMICIsUp( void );
53 
54 static MEMHeapHandle  mem2Heap;
55 static u16            button;
56 static u8*            work;
57 
58 
59 static void* myAlloc   ( u32 size );
60 static u8    myFree    ( void* ptr );
61 static BOOL  usePMIC   ( void );
62 static void *procMic   ( void* p );
63 static void  DrawStuff ( void );
64 static void  shutdown  ( void );
65 
66 /*---------------------------------------------------------------------------*
67   Name:         main
68 
69   Description:  main func.
70 
71   Arguments:    none.
72 
73   Returns:      none.
74  *---------------------------------------------------------------------------*/
75 
main(void)76 void main(void)
77 {
78     void*       arenaMem2Lo;
79     void*       arenaMem2Hi;
80     s32         status;
81     u32         type;
82     WPADStatus  currWpad;
83     WPADStatus  prevWpad;
84     BOOL        running = TRUE;
85 
86     // init DEMO lib.
87     DEMOInit(NULL);
88     DEMOPadInit();
89 
90     OSReport ("\n\n");
91     OSReport ("************************************************\n");
92     OSReport ("pmic_graphic: Graphic demo for Party Mic device\n");
93     OSReport ("************************************************\n");
94     OSReport ("This demo requires the Party Mic and a Wii Remote.\n");
95     OSReport ("The audio captured by the Mic is display onscreen.\n");
96     OSReport ("\n");
97 
98     // init MEM lib.
99     arenaMem2Lo = OSGetMEM2ArenaLo();
100     arenaMem2Hi = OSGetMEM2ArenaHi();
101     mem2Heap    = MEMCreateExpHeap(arenaMem2Lo, (u32)arenaMem2Hi - (u32) arenaMem2Lo);
102 
103     // init Audio libs.
104     AUDIOInit(&mem2Heap, procMic); // xxx
105 
106     // init WPAD.
107     WPADRegisterAllocator(myAlloc, myFree);
108     WPADInit();
109 
110     // init PMIC work area.
111     work = MEMAllocFromExpHeapEx(mem2Heap, PMIC_MEM2_WORK, 32);
112 
113     do
114     {
115         status = WPADGetStatus();
116 
117     } while (WPAD_STATE_SETUP != status);
118 
119     memset(&currWpad, 0, sizeof(WPADStatus));
120     memset(&prevWpad, 0, sizeof(WPADStatus));
121 
122     // spin...
123     while (running)
124     {
125         // read Remote.
126         status = WPADProbe(WPAD_CHAN0, &type);
127 
128         if (WPAD_ERR_NONE == status)
129         {
130             WPADRead(WPAD_CHAN0, &currWpad);
131         }
132 
133         button   = WPADButtonDown(prevWpad.button, currWpad.button);
134         prevWpad = currWpad;
135 
136         // operate P-Mic.
137         running = usePMIC();
138 
139         DEMOBeforeRender();
140         DrawStuff();
141         DEMODoneRender();
142     }
143 
144     shutdown();
145 
146     OSHalt("Demo finished!\n");
147 }
148 
149 /*---------------------------------------------------------------------------*
150   Name:         myAlloc
151 
152   Description:  allocate memory.
153 
154   Arguments:    size    bytes to allocate.
155 
156   Returns:      pointer.
157  *---------------------------------------------------------------------------*/
158 
myAlloc(u32 size)159 static void* myAlloc(u32 size)
160 {
161     void *ptr;
162 
163     ptr = MEMAllocFromExpHeap(mem2Heap, size);
164 
165     return ptr;
166 }
167 
168 /*---------------------------------------------------------------------------*
169   Name:         myFree
170 
171   Description:  free memory.
172 
173   Arguments:    ptr    pointer to free.
174 
175   Returns:      always 1.
176  *---------------------------------------------------------------------------*/
177 
myFree(void * ptr)178 static u8 myFree(void* ptr)
179 {
180     MEMFreeToExpHeap(mem2Heap, ptr);
181 
182     return 1;
183 }
184 
185 /*---------------------------------------------------------------------------*
186  *---------------------------------------------------------------------------*
187  *                      very simple P-Mic operation...                       *
188  *---------------------------------------------------------------------------*
189  *---------------------------------------------------------------------------*/
190 
191 enum
192 {
193     STATE_NOT_INITIALIZED=0,
194     STATE_NOT_READY,
195     STATE_PROBE,
196     STATE_OPEN,
197     STATE_WAIT_FOR_OPEN,
198     STATE_STOPPED,
199     STATE_START,
200     STATE_WAIT_FOR_START,
201     STATE_RUN,
202     STATE_DO_STOP,
203     STATE_WAIT_FOR_STOP,
204 
205     STATE_CLOSE,
206     STATE_WAIT_FOR_CLOSE,
207     STATE_WAIT_REOPEN,
208     STATE_QUIT,
209     STATE_WAIT_RESTART,
210     STATE_DIE
211 };
212 
213 static u32 state = STATE_NOT_INITIALIZED;
214 
215 static volatile PMIC_ERR  errCode;
216 
217 static void funcCb ( PMIC_ERR result, void* arg );
218 
219 /*---------------------------------------------------------------------------*
220   Name:         PMICIsUp
221 
222   Description:  Indicates if P-Mic library has been initialized
223 
224   Arguments:    none.
225 
226   Returns:      BOOL indicating whether P-Mic library has been initialized
227  *---------------------------------------------------------------------------*/
228 
PMICIsUp(void)229 BOOL PMICIsUp(void)
230 {
231     if ( state == STATE_NOT_INITIALIZED ||
232          state == STATE_QUIT ||
233          state == STATE_WAIT_RESTART )
234     {
235         return FALSE;
236     }
237 
238     return TRUE;
239 }
240 
241 /*---------------------------------------------------------------------------*
242   Name:         usePMIC
243 
244   Description:  operate P-Mic.
245 
246   Arguments:    none.
247 
248   Returns:      BOOL indicating whether to continue running or not.
249  *---------------------------------------------------------------------------*/
250 
usePMIC(void)251 static BOOL usePMIC(void)
252 {
253     static s32 count = 0;
254 
255     PMIC_ERR  retval;
256 
257     switch (state)
258     {
259 
260         case STATE_NOT_INITIALIZED:
261 
262             OSReport("Starting init lib.\n");
263 
264             retval = PMICInit(work);
265 
266             if (retval == PMIC_ERR_OK)
267             {
268                 OSReport("(%ld) ok to call PMICInit() -> %ld\n", count++, retval);
269                 state = STATE_NOT_READY;
270             }
271             else
272             {
273                 OSReport("(%ld) fail to call PMICInit() -> %ld\n", count++, retval);
274                 state = STATE_DIE; // fatal
275             }
276             break;
277 
278         case STATE_NOT_READY:
279 
280             OSReport("Insert P-Mic, or Push B to quit lib.\n");
281             state = STATE_PROBE;
282             break;
283 
284         case STATE_PROBE:
285 
286             retval = PMICProbe();
287 
288             if (retval == PMIC_ERR_OK)
289             {
290                 OSReport("(%ld) P-Mic is inserted -> %ld\n", count++, retval);
291                 state = STATE_OPEN;
292             }
293             else if (retval != PMIC_ERR_NO_DEVICE)
294             {
295                 OSReport("(%ld) fail to call PMICProbe() -> %ld\n", count++, retval);
296                 state = STATE_DIE;
297             }
298             else if (button & WPAD_BUTTON_B)
299             {
300                 state = STATE_QUIT;
301             }
302             break;
303 
304         case STATE_OPEN:
305 
306             OSReport("Got P-Mic device.  Opening.\n");
307 
308             errCode = (PMIC_ERR)(PMIC_ERR_OK + 1);
309             retval = PMICOpenAsync(funcCb, NULL);
310 
311             if (retval == PMIC_ERR_OK)
312             {
313                 OSReport("(%ld) ok to call PMICOpenAsync() -> %ld\n", count++, retval);
314                 state = STATE_WAIT_FOR_OPEN;
315             }
316             else
317             {
318                 OSReport("(%ld) fail to call PMICOpenAsync() -> %ld\n", count++, retval);
319                 errCode = PMIC_ERR_OK;
320                 state = STATE_NOT_READY; // probe again
321             }
322             break;
323 
324         case STATE_WAIT_FOR_OPEN:
325 
326             // errCode comes from the PMICOpenAsync callback
327             if (errCode > PMIC_ERR_OK) // still waiting?
328             {
329                 break;
330             }
331             else if (errCode == PMIC_ERR_OK)
332             {
333                 OSReport("(%ld) ok to open P-Mic -> %ld.\n", count++, errCode);
334                 state = STATE_STOPPED;
335                 OSReport("Push A to start P-Mic, or B to close P-Mic, or Remove P-Mic.\n");
336             }
337             else
338             {
339                 OSReport("(%ld) fail to open P-Mic -> %ld.\n", count++, errCode);
340                 state = STATE_NOT_READY; // probe again
341             }
342             break;
343 
344         case STATE_STOPPED:
345 
346             retval = PMICProbe();
347 
348             if (retval == PMIC_ERR_NO_DEVICE)
349             {
350                 OSReport("(%ld) P-Mic is removed -> %ld\n", count++, retval);
351                 state = STATE_NOT_READY;
352             }
353             else if (retval != PMIC_ERR_OK)
354             {
355                 OSReport("(%ld) fail to call PMICProbe() -> %ld\n", count++, retval);
356                 state = STATE_DIE;
357             }
358             else
359             {
360                 state = STATE_START;
361             }
362             break;
363 
364         case STATE_START:
365 
366             errCode = (PMIC_ERR)(PMIC_ERR_OK + 1);
367             retval = PMICStartAsync(funcCb, NULL);
368 
369             if (retval == PMIC_ERR_OK)
370             {
371                 OSReport("(%ld) ok to call PMICStartAsync() -> %ld\n", count++, retval);
372                 state = STATE_WAIT_FOR_START;
373             }
374             else
375             {
376                 OSReport("(%ld) fail to call PMICStartAsync() -> %ld\n", count++, retval);
377                 errCode = PMIC_ERR_OK;
378                 state = STATE_NOT_READY;
379             }
380             break;
381 
382         case STATE_WAIT_FOR_START:
383 
384             // errCode is returned by PMICStartAsync callback
385             if (errCode > PMIC_ERR_OK) // still waiting?
386             {
387                 break;
388             }
389             else if (errCode == PMIC_ERR_OK)
390             {
391                 OSReport("(%ld) ok to start P-Mic -> %ld.\n", count++, errCode);
392                 state = STATE_RUN;
393                 OSReport("Push A to stop P-Mic, or B to close P-Mic, or Remove P-Mic.\n");
394             }
395             else
396             {
397                 OSReport("(%ld) fail to start P-Mic -> %ld.\n", count++, errCode);
398                 state = STATE_NOT_READY;
399             }
400             break;
401 
402         case STATE_RUN:
403 
404             retval = PMICProbe();
405 
406             if (retval == PMIC_ERR_NO_DEVICE)
407             {
408                 OSReport("(%ld) P-Mic is removed -> %ld\n", count++, retval);
409                 state = STATE_NOT_READY;
410             }
411             else if (retval != PMIC_ERR_OK)
412             {
413                 OSReport("(%ld) fail to call PMICProbe() -> %ld\n", count++, retval);
414                 state = STATE_DIE;
415             }
416             else if (button & WPAD_BUTTON_A)
417             {
418                 // AUDIOStartPlay(); // start playing p-mic data
419                 state = STATE_DO_STOP;
420             }
421             else if (button & WPAD_BUTTON_B)
422             {
423                 state = STATE_CLOSE;
424             }
425             break;
426 
427         case STATE_DO_STOP:
428 
429             errCode = (PMIC_ERR)(PMIC_ERR_OK + 1);
430             retval = PMICStopAsync(funcCb, NULL);
431 
432             if (retval == PMIC_ERR_OK)
433             {
434                 OSReport("(%ld) ok to call PMICStopAsync() -> %ld\n", count++, retval);
435                 state = STATE_WAIT_FOR_STOP;
436             }
437             else
438             {
439                 OSReport("(%ld) fail to call PMICStopAsync() -> %ld\n", count++, retval);
440                 errCode = PMIC_ERR_OK;
441                 state = STATE_NOT_READY;
442             }
443             break;
444 
445         case STATE_WAIT_FOR_STOP:
446 
447             // errCode comes from the PMICStopAsync callback
448             if (errCode > PMIC_ERR_OK) // still waiting?
449             {
450                 break;
451             }
452             else if (errCode == PMIC_ERR_OK)
453             {
454                 OSReport("(%ld) ok to stop P-Mic -> %ld.\n", count++, errCode);
455                 state = STATE_STOPPED;
456             }
457             else
458             {
459                 OSReport("(%ld) fail to stop P-Mic -> %ld.\n", count++, errCode);
460                 state = STATE_NOT_READY;
461             }
462             break;
463 
464         case STATE_CLOSE:
465 
466             errCode = (PMIC_ERR)(PMIC_ERR_OK + 1);
467             retval = PMICCloseAsync(funcCb, NULL);
468 
469             if (retval == PMIC_ERR_OK)
470             {
471                 OSReport("(%ld) ok to call PMICCloseAsync() -> %ld\n", count++, retval);
472                 state = STATE_WAIT_FOR_CLOSE;
473             }
474             else
475             {
476                 OSReport("(%ld) fail to call PMICCloseAsync() -> %ld\n", count++, retval);
477                 errCode = PMIC_ERR_OK;
478                 state = STATE_NOT_READY;
479             }
480             break;
481 
482         case STATE_WAIT_FOR_CLOSE:
483 
484             // errCode comes from the PMICCloseAsync callback
485             if (errCode > PMIC_ERR_OK) // still waiting?
486             {
487                 break;
488             }
489             else if (errCode == PMIC_ERR_OK)
490             {
491                 OSReport("(%ld) ok to close P-Mic -> %ld.\n", count++, errCode);
492                 state = STATE_WAIT_REOPEN;
493                 OSReport("Push A to open P-Mic, or B to call PMICQuit.\n");
494             }
495             else
496             {
497                 OSReport("(%ld) fail to close P-Mic -> %ld.\n", count++, errCode);
498                 state = STATE_NOT_READY; // or DIE?
499             }
500             break;
501 
502         case STATE_WAIT_REOPEN:
503 
504             if (button & WPAD_BUTTON_A)
505             {
506                 state = STATE_OPEN;
507             }
508             else if (button & WPAD_BUTTON_B)
509             {
510                 state = STATE_QUIT;
511             }
512             break;
513 
514         case STATE_QUIT:
515 
516             retval = PMICQuit();
517 
518             if (retval == PMIC_ERR_OK)
519             {
520                 OSReport("(%ld) ok to call PMICQuit() -> %ld\n", count++, retval);
521                 state = STATE_WAIT_RESTART;
522                 OSReport("Push A to init P-Mic, or B to quit application.\n");
523             }
524             else
525             {
526                 OSReport("(%ld) fail to call PMICQuit() -> %ld\n", count++, retval);
527                 state = STATE_DIE;
528             }
529             break;
530 
531         case STATE_WAIT_RESTART:
532 
533             if (button & WPAD_BUTTON_A)
534             {
535                 state = STATE_NOT_INITIALIZED;
536             }
537             else if (button & WPAD_BUTTON_B)
538             {
539                 state = STATE_DIE;
540             }
541             break;
542 
543         case STATE_DIE:
544 
545             OSReport("Quitting application\n");
546 
547             return FALSE;
548     }
549 
550     return TRUE;
551 }
552 
553 /*---------------------------------------------------------------------------*
554   Name:         funcCb
555 
556   Description:  callback for PMICOpen/Close/Start/StopAsync
557 
558   Arguments:    result    error code.
559                 arg       (not used.)
560 
561   Returns:      none.
562  *---------------------------------------------------------------------------*/
563 
funcCb(PMIC_ERR result,void * arg)564 static void funcCb(PMIC_ERR result, void* arg)
565 {
566 #pragma unused(arg)
567 
568     errCode = result;
569 }
570 
571 /*---------------------------------------------------------------------------*
572   Graphics-related functions
573  *---------------------------------------------------------------------------*/
574 
575 #define FRAMES_TO_DISPLAY        333
576 #define AUDIO_SAMPLES_PER_FRAME  (16 * 3) // 16KHz (mono) x 3msec
577 #define AUDIO_SAMPLES_TOTAL      (AUDIO_SAMPLES_PER_FRAME * FRAMES_TO_DISPLAY)
578 #define AUDIO_BYTES_PER_FRAME    (AUDIO_SAMPLES_PER_FRAME * 2) // 16-bit
579 #define AUDIO_BYTES_TOTAL        (AUDIO_BYTES_PER_FRAME * FRAMES_TO_DISPLAY)
580 
581 #define SCREEN_WIDTH             640
582 #define SCREEN_HEIGHT            480
583 
584 // Don't use parentheses here:
585 #define AUDIO_SCALE              1/4
586 
587 const GXColor LIME     = {   0, 255,   0, 255 };
588 const GXColor AQUA     = {   0, 255, 255, 255 };
589 const GXColor MAGENTA  = { 255,   0, 255, 255 };
590 const GXColor GRAY     = { 128, 128, 128, 255 };
591 const GXColor WHITE    = { 255, 255, 255, 255 };
592 const GXColor TEAL     = {   0, 128, 128, 255 };
593 const GXColor ORANGE   = { 255, 165,   0, 255 };
594 const GXColor PINK     = { 255, 192, 203, 255 };
595 const GXColor GREEN    = {   0, 128,   0, 255 };
596 
597 static s16* srcBuff = 0;
598 static u32 currPos = 0;
599 
600 /*---------------------------------------------------------------------------*
601   Name:         procMic
602 
603   Description:  Thread process that runs to process microphone input.
604                 It is started by AUDIOInit.  It should initialize itself
605                 and then sleep.  It will be woken periodically by the audio
606                 callback.  It just gathers the samples and stores them in a
607                 local buffer.
608 
609   Arguments:    p  (not used.)
610 
611   Returns:      none.
612  *---------------------------------------------------------------------------*/
613 
procMic(void * p)614 static void *procMic(void* p)
615 {
616 #pragma unused(p)
617 
618     s32  reqSamples;
619     s32  gotSamples;
620     s32  space;
621 
622     // Initialize
623 
624     srcBuff = myAlloc(AUDIO_BYTES_TOTAL);
625     memset(srcBuff, 0, AUDIO_BYTES_TOTAL);
626 
627     currPos = 0;
628 
629     while (1)
630     {
631         // Wait for data to arrive
632         AUDIOSleepThread();
633 
634         // get P-Mic's data (16KHz).
635         space = AUDIO_SAMPLES_TOTAL - (s32) currPos;
636         reqSamples = AUDIO_SAMPLES_PER_FRAME < space ? AUDIO_SAMPLES_PER_FRAME : space;
637         gotSamples = PMICRead(&srcBuff[currPos], reqSamples);
638 
639         if (gotSamples > 0)
640         {
641             currPos += gotSamples;
642 
643             if (currPos == AUDIO_SAMPLES_TOTAL)
644             {
645                 currPos = 0;
646                 reqSamples = AUDIO_SAMPLES_PER_FRAME - space;
647 
648                 if (reqSamples > 0)
649                 {
650                     gotSamples = PMICRead(&srcBuff[currPos], reqSamples);
651 
652                     if (gotSamples > 0)
653                     {
654                         currPos += gotSamples;
655                     }
656                 }
657             }
658         }
659     }
660 }
661 
662 /*---------------------------------------------------------------------------*
663   Name:         drawMic
664 
665   Description:  This is called by the main routine.  It draws a graphic
666                 representation of the audio samples using GX.
667 
668   Arguments:    none.
669 
670   Returns:      none.
671  *---------------------------------------------------------------------------*/
672 
DrawStuff(void)673 static void DrawStuff(void)
674 {
675     s32 i;
676     Mtx mv;
677 
678     // Make sure we don't try to draw before buffer is initialized.
679     // This shouldn't happen, but we check to be safe.
680     if (srcBuff == 0)
681     {
682         return;
683     }
684 
685     // Initialize graphics state
686 
687     DEMOInitCaption( DM_FT_XLU, SCREEN_WIDTH, SCREEN_HEIGHT );
688 
689     MTXIdentity(mv);
690     GXLoadPosMtxImm(mv, GX_PNMTX0);
691     GXSetCurrentMtx(GX_PNMTX0);
692 
693     GXSetNumChans(1);
694     GXSetNumTevStages(1);
695     GXSetNumTexGens(0);
696     GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
697     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
698 
699     GXClearVtxDesc();
700     GXSetVtxDesc(GX_VA_POS,  GX_DIRECT);
701     GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
702     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS,  GX_POS_XY,   GX_S16,   0);
703     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
704 
705     // Draw the base line
706 
707 #define LINE_CLR WHITE
708 
709     GXBegin(GX_LINES, GX_VTXFMT0, 2);
710         GXPosition2s16(0, SCREEN_HEIGHT/2);
711         GXColor4u8(LINE_CLR.r, LINE_CLR.g, LINE_CLR.b, LINE_CLR.a);
712         GXPosition2s16(SCREEN_WIDTH, SCREEN_HEIGHT/2);
713         GXColor4u8(LINE_CLR.r, LINE_CLR.g, LINE_CLR.b, LINE_CLR.a);
714     GXEnd();
715 
716     // Draw the graph
717 
718 #define DATA_CLR LIME
719 
720     GXBegin(GX_LINES, GX_VTXFMT0, AUDIO_SAMPLES_TOTAL);
721     for (i = 0; i < AUDIO_SAMPLES_TOTAL; i++)
722     {
723         s16 sample;
724 
725         sample = srcBuff[(i+currPos)%AUDIO_SAMPLES_TOTAL];
726         // If you want the display to wrap instead of scroll, use this:
727         // sample = srcBuff[i];
728 
729         GXPosition2s16((s16)(i*SCREEN_WIDTH/AUDIO_SAMPLES_TOTAL),
730                        (s16)(sample*AUDIO_SCALE+SCREEN_HEIGHT/2));
731 
732         GXColor4u8(DATA_CLR.r, DATA_CLR.g, DATA_CLR.b, DATA_CLR.a);
733     }
734 
735     GXEnd();
736 }
737 
738 /*---------------------------------------------------------------------------*
739   Name:         shutdown
740 
741   Description:  close libraries.
742 
743   Arguments:    none.
744 
745   Returns:      none.
746  *---------------------------------------------------------------------------*/
747 
shutdown(void)748 static void shutdown(void)
749 {
750     PMIC_ERR retval;
751 
752     // Wait for any pending microphone transaction
753     while (errCode > PMIC_ERR_OK)
754     {
755         OSYieldThread();
756     }
757 
758     // Make sure the microphone is stopped
759     errCode = (PMIC_ERR)(PMIC_ERR_OK + 1);
760     retval = PMICStopAsync(funcCb, NULL);
761     if (retval == PMIC_ERR_OK)
762     {
763         while (errCode > PMIC_ERR_OK)
764         {
765             OSYieldThread();
766         }
767     }
768 
769     // Close the microphone
770     errCode = (PMIC_ERR)(PMIC_ERR_OK + 1);
771     retval = PMICCloseAsync(funcCb, NULL);
772     if (retval == PMIC_ERR_OK)
773     {
774         while (errCode > PMIC_ERR_OK)
775         {
776             OSYieldThread();
777         }
778     }
779 
780     // Kill audio
781     AUDIOQuit();
782 
783     // Close PMIC library
784     PMICQuit();
785 
786     // Free the PMIC work area
787     MEMFreeToExpHeap(mem2Heap, work);
788 }
789