1 /*---------------------------------------------------------------------------*
2   Project:  Revolution WPAD AX demo
3   File:     wpad_seqdemo.c
4 
5   Copyright (C)2006 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: wpad_seqdemo.c,v $
14   Revision 1.13.2.1  2007/12/11 01:17:50  tojo
15   Modified to handle the error code of WPADStatus.
16 
17   Revision 1.13  2007/07/10 12:14:46  tojo
18   (none)
19 
20   Revision 1.12  2007/05/10 04:17:34  aka
21   Revised to use AXRmtGetSamplesLeft().
22 
23   Revision 1.11  2007/04/23 09:16:08  tojo
24   (none)
25 
26   Revision 1.10  2007/02/09 06:45:13  tojo
27   Modifed to follow the guideline.
28 
29   Revision 1.9  2006/11/21 08:38:15  aka
30   Removed the zero buffer.
31 
32   Revision 1.8  2006/10/23 02:16:23  aka
33   Changed from AXInit() to AXInitSpecifyMem().
34   Changed from MIXInit() to MIXInitSpecifyMem().
35   Changed from SYNInit() to SYNInitSpecifyMem().
36 
37   Revision 1.7  2006/10/23 01:18:00  tojo
38   Called WPADSetConnectCallback before initialization complete.
39 
40   Revision 1.6  2006/10/11 03:03:50  aka
41   Revised AXInit(), MIXInit() and SYNInit().
42 
43   Revision 1.5  2006/09/19 06:35:07  tojo
44   (none)
45 
46   Revision 1.4  2006/09/18 11:59:38  tojo
47   (none)
48 
49   Revision 1.3  2006/09/15 05:49:02  tojo
50   Fixed to corrupt audio streaming
51 
52   Revision 1.2  2006/08/03 13:32:55  tojo
53   Removed old apis.
54 
55   Revision 1.1  2006/07/26 07:47:32  aka
56   Initial check-in.
57 
58 
59   $NoKeywords: $
60  *---------------------------------------------------------------------------*/
61 
62 #include <string.h>
63 
64 #include <demo.h>
65 #include <revolution/mem.h>
66 #include <revolution/mix.h>
67 #include <revolution/syn.h>
68 #include <revolution/seq.h>
69 #include <revolution/wenc.h>
70 #include <revolution/wpad.h>
71 
72 /*---------------------------------------------------------------------------*
73   SEQ
74  *---------------------------------------------------------------------------*/
75 
76 // data
77 #define GM_WT            "/axdemo/synth/gm16adpcm.wt"
78 #define GM_PCM           "/axdemo/synth/gm16adpcm.pcm"
79 #define MIDI_FILE_MAIN   "/axdemo/midi/2nd_time.mid"
80 #define MIDI_FILE_REMOTE "/axdemo/midi/autumnal.mid"
81 
82 // function prototypes
83 static void *LoadFileIntoRam     ( char *path );
84 static void  AudioFrameCallback  ( void );
85 static void  VoiceInitCallback   ( AXVPB *axvpb, SYNSYNTH *synth, u8 midiChannel );
86 static void  VoiceUpdateCallback ( AXVPB *axvpb, SYNSYNTH *synth, u8 midiChannel );
87 
88 /*---------------------------------------------------------------------------*
89   WPAD
90  *---------------------------------------------------------------------------*/
91 
92 // Audio buffers
93 #define SAMPLES_PER_AUDIO_PACKET  40
94 #define AUDIO_PACKET_LEN          20 // SAMPLES_PER_AUDIO_PACKET / 2
95 
96 // allocator functions for WPAD
97 static void *myAlloc ( u32 size );
98 static u8    myFree  ( void *ptr );
99 
100 // function prototypes
101 static void  UpdateSpeaker     ( OSAlarm *alarm, OSContext *context );
102 static void  SpeakerCallback   ( s32 chan, s32 result );
103 static void  SpeakerOnCallback ( s32 chan, s32 result );
104 static void  SpeakerOffCallback( s32 chan, s32 result );
105 static void  ConnectCallback   ( s32 chan, s32 reason );
106 static void  ExtensionCallback ( s32 chan, s32 result );
107 
108 // Speaker Status
109 typedef struct SpeakerInfo
110 {
111     u8           active;
112     WENCInfo     encInfo;
113     BOOL         first;
114     BOOL         last;
115 
116     s32          status;
117     s16          pcmData[SAMPLES_PER_AUDIO_PACKET];
118     u8           encData[AUDIO_PACKET_LEN];
119 
120     OSTime       pending;
121 } SpeakerInfo;
122 
123 typedef union Status
124 {
125     WPADStatus      cr;
126     WPADFSStatus    fs;
127     WPADCLStatus    cl;
128 } Status;
129 
130 // Controller Status
131 typedef struct ContInfo
132 {
133     u32          type;
134     s32          status;
135     Status      currStat;
136     Status      prevStat;
137     SpeakerInfo  Speakers;
138 
139     SEQSEQUENCE  Sequence;
140     u8           play;
141 
142 } ContInfo;
143 
144 static ContInfo  info[WPAD_MAX_CONTROLLERS];
145 
146 // Periodic Alarms for audio streaming
147 static OSAlarm  SpeakerAlarm;
148 
149 
150 /*---------------------------------------------------------------------------*
151   etc.
152  *---------------------------------------------------------------------------*/
153 
154 // Exp Heap
155 static MEMHeapHandle  hExpHeap;
156 
157 // function prototypes
158 static void  initialize();
159 static void  RenderOperation();
160 static void  RenderControllerStatus();
161 
162 /*---------------------------------------------------------------------------*
163  * Name        : main
164  * Description : main
165  * Arguments   : None.
166  * Returns     : None.
167  *---------------------------------------------------------------------------*/
main(void)168 void main ( void )
169 {
170     s32          i;
171     s32          chan;
172     u16          button;
173 
174     void        *arenaMem2Lo;
175     void        *arenaMem2Hi;
176 
177     SEQSEQUENCE  SequenceMain;
178     u8          *MidiFileMain;
179     u8          *MidiFileRemote;
180     u8          *Wavetable;
181     u8          *Pcm;
182     void        *axBuffer;
183     void        *mixBuffer;
184     void        *synBuffer;
185 
186     // Initialize DEMO
187     initialize();
188 
189     // initialize Exp Heap on MEM2
190     arenaMem2Lo = OSGetMEM2ArenaLo();
191     arenaMem2Hi = OSGetMEM2ArenaHi();
192     hExpHeap    = MEMCreateExpHeap(arenaMem2Lo, (u32)arenaMem2Hi - (u32) arenaMem2Lo);
193     ASSERT(hExpHeap != NULL);
194 
195     //
196     // Initialize Audio
197     //
198 
199     axBuffer  = OSAlloc(AXGetMemorySize(AX_MAX_VOICES));
200     mixBuffer = MEMAllocFromExpHeap(hExpHeap, MIXGetMemorySize(AX_MAX_VOICES));
201     synBuffer = MEMAllocFromExpHeap(hExpHeap, SYNGetMemorySize(AX_MAX_VOICES));
202 
203     AIInit(NULL);
204     AXInitSpecifyMem(AX_MAX_VOICES, axBuffer);
205     MIXInitSpecifyMem(mixBuffer);
206     SYNInitSpecifyMem(synBuffer);
207     SEQInit();
208 
209     // Load Audio Data
210     Wavetable      = LoadFileIntoRam(GM_WT);
211     Pcm            = LoadFileIntoRam(GM_PCM);
212     MidiFileMain   = LoadFileIntoRam(MIDI_FILE_MAIN);
213     MidiFileRemote = LoadFileIntoRam(MIDI_FILE_REMOTE);
214 
215     // Register Callback with AX for audio processing
216     AXRegisterCallback(&AudioFrameCallback);
217 
218     // Prepare Sequence for Main
219     SEQAddSequence(&SequenceMain,
220                    MidiFileMain,
221                    Wavetable,
222                    Pcm,
223                    NULL,
224                    16,
225                    15,
226                    1
227                   );
228 
229     // Play Sequence for Main
230     SEQSetState(&SequenceMain, SEQ_STATE_RUNLOOPED);
231 
232     // Prepare Sequence for Remotes
233     for (i = 0; i < WPAD_MAX_CONTROLLERS; i++)
234     {
235         SEQAddSequence(&info[i].Sequence,
236                        MidiFileRemote,
237                        Wavetable,
238                        Pcm,
239                        NULL,
240                        16,
241                        15,
242                        1
243                       );
244         SYNSetMasterVolume(  &info[i].Sequence.synth, -960);
245         SYNSetInitCallback(  &info[i].Sequence.synth, VoiceInitCallback);
246         SYNSetUpdateCallback(&info[i].Sequence.synth, VoiceUpdateCallback);
247     }
248 
249     //
250     // Initialize WPAD
251     //
252 
253     WPADRegisterAllocator(myAlloc, myFree);
254 
255     WPADInit();
256 
257     for (i = 0; i < WPAD_MAX_CONTROLLERS; i++)
258     {
259         WPADSetConnectCallback((s32)i, ConnectCallback);
260     }
261 
262     while (WPADGetStatus() != WPAD_STATE_SETUP)
263     {
264         ;
265     }
266 
267     OSCreateAlarm(&SpeakerAlarm);
268     OSSetPeriodicAlarm(&SpeakerAlarm, OSGetTime(), WPAD_STRM_INTERVAL, UpdateSpeaker);
269 
270     // Spin
271     while (1)
272     {
273         for (chan = 0; chan < WPAD_MAX_CONTROLLERS; chan++)
274         {
275             info[chan].status = WPADProbe(chan, &info[chan].type);
276 
277             if (info[chan].status != WPAD_ERR_NO_CONTROLLER)
278             {
279                 WPADRead(chan, &info[chan].currStat.cr);
280 
281                 if (info[chan].currStat.cr.err != WPAD_ERR_INVALID)
282                 {
283                     button = WPADButtonDown(info[chan].prevStat.cr.button, info[chan].currStat.cr.button);
284                     info[chan].prevStat.cr = info[chan].currStat.cr;
285                 }
286                 if (button & WPAD_BUTTON_A)
287                 {
288                     switch (info[chan].Speakers.active)
289                     {
290                         case 0: WPADControlSpeaker(chan, WPAD_SPEAKER_ON, SpeakerOnCallback);   break;
291                         case 1: WPADControlSpeaker(chan, WPAD_SPEAKER_OFF, SpeakerOffCallback); break;
292                         default:                                                                break;
293                     }
294                 }
295 
296                 if (SEQGetState(&info[chan].Sequence) == SEQ_STATE_RUN)
297                 {
298                     info[chan].play = 1;
299                 }
300                 else
301                 {
302                     info[chan].play = 0;
303 
304                     if (info[chan].Speakers.active == 1)
305                     {
306                         info[chan].Speakers.active = 2;
307                         WPADControlSpeaker(chan, WPAD_SPEAKER_OFF, SpeakerOffCallback);
308                     }
309                 }
310             }
311         }
312 
313         DEMOBeforeRender();
314 
315         DEMOPrintf( 16, 16, 0, "WPAD Demo -- WPAD Seqdemo");
316         RenderOperation();
317         RenderControllerStatus();
318         DEMODoneRender();
319     }
320 
321     OSCancelAlarm(&SpeakerAlarm);
322 }
323 
324 /*---------------------------------------------------------------------------*
325  * Name        : UpdateSpeaker
326  * Description :
327  * Arguments   :
328  * Returns     : None.
329  *---------------------------------------------------------------------------*/
UpdateSpeaker(OSAlarm * alarm,OSContext * context)330 static void UpdateSpeaker( OSAlarm *alarm, OSContext *context )
331 {
332 #pragma unused(alarm, context)
333 
334     u32   flag;
335     s32   chan;
336     BOOL  intr;
337 
338     if (SAMPLES_PER_AUDIO_PACKET <= AXRmtGetSamplesLeft())
339     {
340 
341         for(chan = 0; chan < WPAD_MAX_CONTROLLERS; chan++)
342         {
343 
344             AXRmtGetSamples(chan, info[chan].Speakers.pcmData, SAMPLES_PER_AUDIO_PACKET);
345 
346             if (info[chan].Speakers.active)
347             {
348                 intr = OSDisableInterrupts();
349 
350                 if (WPADCanSendStreamData(chan))
351                 {
352                     flag = (info[chan].Speakers.first) ? (u32)WENC_FLAG_FIRST : (u32)WENC_FLAG_CONT;
353                     if (info[chan].Speakers.first)
354                     {
355                         info[chan].Speakers.first = FALSE;
356                     }
357 
358                     WENCGetEncodeData(&info[chan].Speakers.encInfo,
359                                       flag,
360                                       info[chan].Speakers.pcmData,
361                                       SAMPLES_PER_AUDIO_PACKET,
362                                       info[chan].Speakers.encData);
363                     info[chan].Speakers.status = WPADSendStreamData(chan, info[chan].Speakers.encData, AUDIO_PACKET_LEN);
364                 }
365 
366                 OSRestoreInterrupts(intr);
367             }
368         }
369 
370         AXRmtAdvancePtr(SAMPLES_PER_AUDIO_PACKET);
371     }
372 }
373 
374 /*---------------------------------------------------------------------------*
375  * Name        : SpeakerCallback
376  * Description :
377  * Arguments   :
378  * Returns     : None.
379  *---------------------------------------------------------------------------*/
SpeakerCallback(s32 chan,s32 result)380 static void SpeakerCallback( s32 chan, s32 result )
381 {
382     if (result == WPAD_ERR_NONE)
383     {
384         info[chan].Speakers.active = 1;
385         info[chan].Speakers.first  = TRUE;
386         info[chan].Speakers.last   = FALSE;
387         memset(&info[chan].Speakers.encInfo, 0, sizeof(WENCInfo));
388 
389         info[chan].Speakers.status = WPAD_ERR_NONE;
390         memset(info[chan].Speakers.pcmData, 0, SAMPLES_PER_AUDIO_PACKET);
391         memset(info[chan].Speakers.encData, 0, AUDIO_PACKET_LEN);
392         SEQSetState(&info[chan].Sequence, SEQ_STATE_RUN);
393 
394         OSReport("Chan[%d] is ready\n", chan);
395     }
396 }
397 
398 /*---------------------------------------------------------------------------*
399  * Name        : SpeakerOffCallback
400  * Description :
401  * Arguments   :
402  * Returns     : None.
403  *---------------------------------------------------------------------------*/
SpeakerOffCallback(s32 chan,s32 result)404 static void SpeakerOffCallback( s32 chan, s32 result )
405 {
406 #pragma unused(result)
407 
408     SEQSetState(&info[chan].Sequence, SEQ_STATE_STOP);
409     info[chan].Speakers.active = 0;
410 
411     OSReport("Chan[%d] is stopped.\n", chan);
412 }
413 
414 /*---------------------------------------------------------------------------*
415  * Name        : SpeakerOnCallback
416  * Description :
417  * Arguments   :
418  * Returns     : None.
419  *---------------------------------------------------------------------------*/
SpeakerOnCallback(s32 chan,s32 result)420 static void SpeakerOnCallback( s32 chan, s32 result )
421 {
422     if (result == WPAD_ERR_NONE)
423     {
424         WPADControlSpeaker(chan, WPAD_SPEAKER_PLAY, SpeakerCallback);
425     }
426 }
427 
428 /*---------------------------------------------------------------------------*
429  * Name        : ExtensionCallback
430  * Description :
431  * Arguments   :
432  * Returns     : None.
433  *---------------------------------------------------------------------------*/
ExtensionCallback(s32 chan,s32 result)434 static void ExtensionCallback( s32 chan, s32 result )
435 {
436     switch(result)
437     {
438         case WPAD_DEV_CORE:
439         case WPAD_DEV_FUTURE:
440         case WPAD_DEV_NOT_SUPPORTED: WPADSetDataFormat(chan, WPAD_FMT_CORE);      break;
441         case WPAD_DEV_FREESTYLE:     WPADSetDataFormat(chan, WPAD_FMT_FREESTYLE); break;
442         case WPAD_DEV_CLASSIC:       WPADSetDataFormat(chan, WPAD_FMT_CLASSIC);   break;
443     }
444 }
445 
446 /*---------------------------------------------------------------------------*
447  * Name        : ConnectCallback
448  * Description :
449  * Arguments   :
450  * Returns     : None.
451  *---------------------------------------------------------------------------*/
ConnectCallback(s32 chan,s32 reason)452 static void ConnectCallback( s32 chan, s32 reason )
453 {
454     OSReport("ConnectCallback(%d) : %s\n", chan, (reason < 0) ? "disconnect" : "connect");
455 
456     info[chan].Speakers.active = 0;
457     if (reason >= 0)
458     {
459         WPADSetDataFormat(chan, WPAD_FMT_CORE);
460         WPADSetExtensionCallback(chan, ExtensionCallback);
461     }
462     else
463     {
464         SEQSetState(&info[chan].Sequence, SEQ_STATE_STOP);
465         info[chan].play = 0;
466     }
467 }
468 
469 /*---------------------------------------------------------------------------*
470  * Name        : myAlloc
471  * Description :
472  * Arguments   : None.
473  * Returns     : None.
474  *---------------------------------------------------------------------------*/
myAlloc(u32 size)475 static void *myAlloc( u32 size )
476 {
477     void *ptr;
478 
479     ptr = MEMAllocFromExpHeap(hExpHeap, size);
480     ASSERTMSG(ptr, "Memory allocation failed\n");
481 
482     return(ptr);
483 }
484 
485 /*---------------------------------------------------------------------------*
486  * Name        : myFree
487  * Description :
488  * Arguments   : None.
489  * Returns     : None.
490  *---------------------------------------------------------------------------*/
myFree(void * ptr)491 static u8 myFree( void *ptr )
492 {
493     MEMFreeToExpHeap(hExpHeap, ptr);
494     return(1);
495 }
496 
497 /*---------------------------------------------------------------------------*
498  * Name        : AudioFrameCallback
499  * Description : Callback that process audio data per 3ms audio frame.
500  * Arguments   : None.
501  * Returns:    : None.
502  *---------------------------------------------------------------------------*/
AudioFrameCallback(void)503 static void AudioFrameCallback( void )
504 {
505     // run the sequencer
506     SEQRunAudioFrame();
507 
508     // run the synth
509     SYNRunAudioFrame();
510 
511     // tell the mixer to update settings
512     MIXUpdateSettings();
513 }
514 
515 /*---------------------------------------------------------------------------*
516  * Name        : LoadFileIntoRam
517  * Description : Loads a file into memory. Memory is allocated.
518  * Arguments   : path    File to load into main memory
519  * Returns:    : pointer to file in main memory or NULL if not opened
520  *---------------------------------------------------------------------------*/
LoadFileIntoRam(char * path)521 static void *LoadFileIntoRam( char *path )
522 {
523     DVDFileInfo  handle;
524     u32          round_length;
525     s32          read_length;
526     void        *buffer;
527 
528     // Open File
529     if (!DVDOpen(path, &handle))
530     {
531         OSReport("WARNING! Failed to open %s\n", path);
532         return NULL;
533     }
534 
535     // Make sure file length is not 0
536     if (DVDGetLength(&handle) == 0)
537     {
538         OSReport("WARNING! File length is 0\n");
539         return NULL;
540     }
541 
542     round_length = OSRoundUp32B(DVDGetLength(&handle));
543     buffer       = MEMAllocFromExpHeapEx(hExpHeap, round_length,  32);
544 
545     // Make sure we got a buffer
546     if (buffer == NULL)
547     {
548         OSReport("WARNING! Unable to allocate buffer\n");
549         return NULL;
550     }
551 
552     // Read Files
553     read_length  = DVDRead(&handle, buffer, (s32)(round_length), 0);
554 
555     // Make sure we read the file correctly
556     if (read_length <= 0)
557     {
558         OSReport("WARNING! File lenght is wrong\n");
559         return NULL;
560     }
561 
562     return buffer;
563 }
564 
565 /*---------------------------------------------------------------------------*
566  * Name        : RenderOperation
567  * Description :
568  * Arguments   : None.
569  * Returns:    : None.
570  *---------------------------------------------------------------------------*/
571 static const s16 HEIGHT = 10;
RenderOperation(void)572 static void RenderOperation( void )
573 {
574     s16 y = 80;
575 
576     DEMOPrintf( 16, y += HEIGHT, 0, "button A : Start/Stop Sequence");
577 }
578 
579 /*---------------------------------------------------------------------------*
580  * Name        : RenderControllerStatus
581  * Description :
582  * Arguments   : None.
583  * Returns:    : None.
584  *---------------------------------------------------------------------------*/
RenderControllerStatus(void)585 static void RenderControllerStatus( void )
586 {
587     s16 y = 32;
588     int chan;
589 
590     DEMOPrintf( 150, y, 0, "speaker");
591     DEMOPrintf( 220, y, 0, "sequence");
592     for( chan = 0; chan < WPAD_MAX_CONTROLLERS; chan++)
593     {
594         y += HEIGHT;
595         DEMOPrintf( 16, y, 0, "CHAN_%d [%s]",
596             chan,
597             (info[chan].status == WPAD_ERR_NO_CONTROLLER) ? "--" :
598             (info[chan].type == 0) ? "CORE"     :
599             (info[chan].type == 1) ? "NUNCHAKU" :
600             (info[chan].type == 2) ? "CLASSIC"  :
601                                      "UNKNOWN"
602         );
603         DEMOPrintf( 150, y, 0, "%s", (info[chan].Speakers.active == 1) ? "ON"   :
604                                      (info[chan].Speakers.active == 2) ? "MUTE" :
605                                                                          "OFF");
606         DEMOPrintf( 220, y, 0, "%s", (info[chan].play == 0) ?            "STOP" :
607                                                                          "PLAY");
608     }
609 }
610 
611 /*---------------------------------------------------------------------------*
612  * Name        : initialize
613  * Description : Initialize GX.
614  * Arguments   : None.
615  * Returns:    : None.
616  *---------------------------------------------------------------------------*/
initialize(void)617 static void initialize( void )
618 {
619     const GXColor DARKBLUE      = { 0, 0, 64, 255 };
620     const int     SCREEN_WIDTH  = 320;
621     const int     SCREEN_HEIGHT = 240;
622 
623     DEMOInit( &GXNtsc480IntDf );
624     GXSetCopyClear( DARKBLUE, GX_MAX_Z24 );
625     GXCopyDisp( DEMOGetCurrentBuffer(), GX_TRUE );
626     DEMOInitCaption( DM_FT_XLU, SCREEN_WIDTH, SCREEN_HEIGHT );
627     GXSetZMode( GX_ENABLE, GX_ALWAYS, GX_ENABLE );                       // Set pixel processing mode
628     GXSetBlendMode( GX_BM_BLEND, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR );    // Translucent mode
629 
630     DEMOPadInit();
631 }
632 
633 /*---------------------------------------------------------------------------*
634  * Name        : VoiceInitCallback
635  * Description :
636  * Arguments   :
637  * Returns:    : None.
638  *---------------------------------------------------------------------------*/
VoiceInitCallback(AXVPB * axvpb,SYNSYNTH * synth,u8 midiChannel)639 static void VoiceInitCallback( AXVPB *axvpb, SYNSYNTH *synth, u8 midiChannel )
640 {
641 #pragma unused(midiChannel)
642 
643     s32 i;
644 
645     for (i = 0; i < WPAD_MAX_CONTROLLERS; i++)
646     {
647         if (synth == &info[i].Sequence.synth)
648         {
649             break;
650         }
651     }
652 
653     switch(i)
654     {
655         case 0:
656             MIXRmtSetVolumes(axvpb, 0, 0, -960, -960, -960, -960, -960, -960, -960);
657             break;
658         case 1:
659             MIXRmtSetVolumes(axvpb, 0, -960, 0, -960, -960, -960, -960, -960, -960);
660             break;
661         case 2:
662             MIXRmtSetVolumes(axvpb, 0, -960, -960, 0, -960, -960, -960, -960, -960);
663             break;
664         default:
665             MIXRmtSetVolumes(axvpb, 0, -960, -960, -960, 0, -960, -960, -960, -960);
666             break;
667     }
668 
669     AXSetVoiceRmtOn(axvpb, AX_PB_REMOTE_ON);
670 }
671 
672 /*---------------------------------------------------------------------------*
673  * Name        : VoiceUpdateCallback
674  * Description :
675  * Arguments   :
676  * Returns:    : None.
677  *---------------------------------------------------------------------------*/
VoiceUpdateCallback(AXVPB * axvpb,SYNSYNTH * synth,u8 midiChannel)678 static void VoiceUpdateCallback( AXVPB *axvpb, SYNSYNTH *synth, u8 midiChannel )
679 {
680 #pragma unused(axvpb)
681 #pragma unused(synth)
682 #pragma unused(midiChannel)
683 }
684