1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - libraries - snd - common
3 File: snd_bank.c
4
5 Copyright 2004-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 #include <nitro/snd/common/bank.h>
19
20 #ifndef SDK_FROM_TOOL
21
22 #include <nitro/misc.h>
23 #include <nitro/mi.h>
24 #include <nitro/snd/common/main.h>
25
26 #else
27
28 #define SDK_ASSERT(exp) ((void) 0)
29 #define SDK_NULL_ASSERT(exp) ((void) 0)
30 #define SDK_MINMAX_ASSERT(exp, min, max) ((void) 0)
31
32 #define SNDi_LockMutex() ((void) 0)
33 #define SNDi_UnlockMutex() ((void) 0)
34
MI_ReadByte(const void * address)35 static u8 MI_ReadByte(const void *address)
36 {
37 return *(u8 *)address;
38 }
39
40 #define HW_MAIN_MEM 0x02000000
41
42 #ifdef _MSC_VER
43 #pragma warning( disable : 4018 ) // Warning: Signed/unsigned mismatch
44 #pragma warning( disable : 4311 ) // Warning: Pointer truncation from 'type' to 'type'
45 #pragma warning( disable : 4312 ) // Warning: Conversion from 'type' to 'type' of greater size
46 #endif
47
48 #endif /* SDK_FROM_TOOL */
49
50 /******************************************************************************
51 Static function declarations
52 ******************************************************************************/
53 static const SNDWaveData *GetWaveData(const SNDBankData *bank, int waveArcNo, int waveIndex);
54
55 /******************************************************************************
56 Public functions
57 ******************************************************************************/
58
59 /*---------------------------------------------------------------------------*
60 Name: SND_AssignWaveArc
61
62 Description: Assigns a waveform archive to bank (ThreadSafe).
63
64 Arguments: bank - Pointer to SNDBankData structure
65 index - Wave archive index
66 waveArc - Pointer to SNDWaveArc structure
67
68 Returns: None.
69 *---------------------------------------------------------------------------*/
SND_AssignWaveArc(SNDBankData * bank,int index,SNDWaveArc * waveArc)70 void SND_AssignWaveArc(SNDBankData *bank, int index, SNDWaveArc *waveArc)
71 {
72 SNDWaveArcLink *next;
73 SNDWaveArcLink *prev;
74
75 SDK_NULL_ASSERT(bank);
76 SDK_NULL_ASSERT(waveArc);
77 #ifdef SDK_ARM9
78 SDK_ASSERTMSG(((u32)bank & 0x1f) == 0, "bank address must be aligned 32 bytes boundary.");
79 SDK_ASSERTMSG(((u32)waveArc & 0x1f) == 0, "waveArc address must be aligned 32 bytes boundary.");
80 #endif
81 SDK_MINMAX_ASSERT(index, 0, SND_BANK_TO_WAVEARC_MAX - 1);
82
83 SNDi_LockMutex();
84
85 if (bank->waveArcLink[index].waveArc != NULL)
86 {
87 // When already connected
88
89 // If it's the same as the waveform archive to which it is trying to connect, it does nothing
90 if (waveArc == bank->waveArcLink[index].waveArc)
91 {
92 SNDi_UnlockMutex();
93 return;
94 }
95
96 // If a different waveform archive is connected, it disconnects once
97 if (&bank->waveArcLink[index] == bank->waveArcLink[index].waveArc->topLink)
98 {
99 bank->waveArcLink[index].waveArc->topLink = bank->waveArcLink[index].next;
100
101 #ifdef SDK_ARM9
102 DC_StoreRange(bank->waveArcLink[index].waveArc, sizeof(SNDWaveArc));
103 #endif
104 }
105 else
106 {
107 prev = bank->waveArcLink[index].waveArc->topLink;
108 while (prev != NULL)
109 {
110 if (&bank->waveArcLink[index] == prev->next)
111 break;
112 prev = prev->next;
113 }
114 SDK_NULL_ASSERT(prev);
115 prev->next = bank->waveArcLink[index].next;
116
117 #ifdef SDK_ARM9
118 DC_StoreRange(prev, sizeof(SNDWaveArcLink));
119 #endif
120 }
121 }
122
123 next = waveArc->topLink;
124 waveArc->topLink = &bank->waveArcLink[index];
125 bank->waveArcLink[index].next = next;
126 bank->waveArcLink[index].waveArc = waveArc;
127
128 SNDi_UnlockMutex();
129
130 #ifdef SDK_ARM9
131 DC_StoreRange(bank, sizeof(SNDBankData));
132 DC_StoreRange(waveArc, sizeof(SNDWaveArc));
133 #endif
134 }
135
136 /*---------------------------------------------------------------------------*
137 Name: SND_DestroyBank
138
139 Description: Destroys bank (ThreadSafe).
140
141 Arguments: bank - Pointer to SNDBankData structure
142
143 Returns: None.
144 *---------------------------------------------------------------------------*/
SND_DestroyBank(SNDBankData * bank)145 void SND_DestroyBank(SNDBankData *bank)
146 {
147 SNDWaveArc *waveArc;
148 SNDWaveArcLink *prev;
149 int i;
150
151 SDK_NULL_ASSERT(bank);
152 #ifdef SDK_ARM9
153 SDK_ASSERTMSG(((u32)bank & 0x1f) == 0, "bank address must be aligned 32 bytes boundary.");
154 #endif
155
156 SNDi_LockMutex();
157
158 for (i = 0; i < SND_BANK_TO_WAVEARC_MAX; i++)
159 {
160 waveArc = bank->waveArcLink[i].waveArc;
161 if (waveArc == NULL)
162 continue;
163
164 if (&bank->waveArcLink[i] == waveArc->topLink)
165 {
166 waveArc->topLink = bank->waveArcLink[i].next;
167
168 #ifdef SDK_ARM9
169 DC_StoreRange(waveArc, sizeof(SNDWaveArc));
170 #endif
171 }
172 else
173 {
174 prev = waveArc->topLink;
175 while (prev != NULL)
176 {
177 if (&bank->waveArcLink[i] == prev->next)
178 break;
179 prev = prev->next;
180 }
181 SDK_NULL_ASSERT(prev);
182 prev->next = bank->waveArcLink[i].next;
183
184 #ifdef SDK_ARM9
185 DC_StoreRange(prev, sizeof(SNDWaveArcLink));
186 #endif
187 }
188 }
189
190 SNDi_UnlockMutex();
191 }
192
193 /*---------------------------------------------------------------------------*
194 Name: SND_DestroyWaveArc
195
196 Description: Destroys the waveform archive (ThreadSafe).
197
198 Arguments: waveArc - Pointer to SNDWaveArc structure
199
200 Returns: None.
201 *---------------------------------------------------------------------------*/
SND_DestroyWaveArc(SNDWaveArc * waveArc)202 void SND_DestroyWaveArc(SNDWaveArc *waveArc)
203 {
204 SNDWaveArcLink *link;
205 SNDWaveArcLink *next;
206
207 SDK_NULL_ASSERT(waveArc);
208 #ifdef SDK_ARM9
209 SDK_ASSERTMSG(((u32)waveArc & 0x1f) == 0, "waveArc address must be aligned 32 bytes boundary.");
210 #endif
211
212 SNDi_LockMutex();
213
214 link = waveArc->topLink;
215 while (link != NULL)
216 {
217 next = link->next;
218
219 link->waveArc = NULL;
220 link->next = NULL;
221
222 #ifdef SDK_ARM9
223 DC_StoreRange(link, sizeof(SNDWaveArcLink));
224 #endif
225 link = next;
226 }
227
228 SNDi_UnlockMutex();
229 }
230
231
232 /*---------------------------------------------------------------------------*
233 Name: SND_ReadInstData
234
235 Description: Gets instrument parameters from bank (ThreadSafe).
236
237 Arguments: bank - Pointer to SNDBankData structure
238 prgNo - Program number
239 key - Note key
240 inst - Pointer to SNDInstData structure
241
242 Returns: Whether it was successful.
243 *---------------------------------------------------------------------------*/
SND_ReadInstData(const SNDBankData * bank,int prgNo,int key,SNDInstData * inst)244 BOOL SND_ReadInstData(const SNDBankData *bank, int prgNo, int key, SNDInstData *inst)
245 {
246 u32 instOffset;
247
248 SDK_NULL_ASSERT(bank);
249 SDK_NULL_ASSERT(inst);
250
251 if (prgNo < 0)
252 return FALSE;
253
254 #ifdef SDK_FROM_TOOL
255 if (bank->fileHeader.signature[0] == 'S' &&
256 bank->fileHeader.signature[1] == 'B' &&
257 bank->fileHeader.signature[2] == 'C' && bank->fileHeader.signature[3] == 'B')
258 {
259 const SNDBankDataCallback *bankcb = (const SNDBankDataCallback *)bank;
260 return bankcb->readInstDataFunc(bankcb, prgNo, key, inst);
261 }
262 #endif
263
264 SNDi_LockMutex();
265
266 if (prgNo >= bank->instCount)
267 { // Note: Read from MainMemory
268 SNDi_UnlockMutex();
269 return FALSE;
270 }
271
272 instOffset = bank->instOffset[prgNo]; // Note: Read from MainMemory
273 inst->type = (u8)(instOffset & 0xff);
274 instOffset >>= 8;
275
276 // Process for each instrument type
277 switch (inst->type)
278 {
279 case SND_INST_PCM:
280 case SND_INST_PSG:
281 case SND_INST_NOISE:
282 case SND_INST_DIRECTPCM:
283 case SND_INST_NULL:
284 {
285 const SNDInstParam *param = (const SNDInstParam *)((u8 *)bank + instOffset);
286
287 inst->param = *param; // Structure copy
288 break;
289 }
290
291 case SND_INST_DRUM_SET:
292 {
293 const SNDDrumSet *drumSet = (const SNDDrumSet *)((u8 *)bank + instOffset);
294 u8 min = MI_ReadByte(&drumSet->min);
295 u8 max = MI_ReadByte(&drumSet->max);
296
297 if (key < min || key > max)
298 {
299 SNDi_UnlockMutex();
300 return FALSE;
301 }
302
303 *inst = drumSet->instOffset[key - min]; // Structure copy
304 break;
305 }
306
307 case SND_INST_KEY_SPLIT:
308 {
309 int index = 0;
310 const SNDKeySplit *keySplit = (const SNDKeySplit *)((u8 *)bank + instOffset);
311
312 while (key > MI_ReadByte(&keySplit->key[index]))
313 {
314 index++;
315 if (index >= SND_INST_KEYSPLIT_MAX)
316 {
317 SNDi_UnlockMutex();
318 return FALSE;
319 }
320 }
321
322 *inst = keySplit->instOffset[index]; // Structure copy
323 break;
324 }
325
326 case SND_INST_INVALID:
327 default:
328 SNDi_UnlockMutex();
329 return FALSE;
330 }
331
332 SNDi_UnlockMutex();
333
334 return TRUE;
335 }
336
337 /*---------------------------------------------------------------------------*
338 Name: SND_WriteInstData
339
340 Description: Writes instrument data (ThreadSafe).
341
342 Arguments: bank - Pointer to SNDBankData structure
343 prgNo - Program number
344 key - Note key
345 inst - Pointer to SNDInstData structure
346
347 Returns: Whether it was successful.
348 *---------------------------------------------------------------------------*/
SND_WriteInstData(SNDBankData * bank,int prgNo,int key,const struct SNDInstData * inst)349 BOOL SND_WriteInstData(SNDBankData *bank, int prgNo, int key, const struct SNDInstData *inst)
350 {
351 u32 instOffset;
352 u8 type;
353
354 SDK_NULL_ASSERT(bank);
355 SDK_NULL_ASSERT(inst);
356
357 if (prgNo < 0)
358 return FALSE;
359
360 SNDi_LockMutex();
361 if (prgNo >= bank->instCount)
362 { // Note: Read from MainMemory
363 SNDi_UnlockMutex();
364 return FALSE;
365 }
366
367 instOffset = bank->instOffset[prgNo]; // Note: Read from MainMemory
368 type = (u8)(instOffset & 0xff);
369 instOffset >>= 8;
370
371 // Process for each instrument type
372 switch (type)
373 {
374 case SND_INST_PCM:
375 case SND_INST_PSG:
376 case SND_INST_NOISE:
377 case SND_INST_DIRECTPCM:
378 case SND_INST_NULL:
379 {
380 SNDInstParam *param = (SNDInstParam *)((u8 *)bank + instOffset);
381
382 bank->instOffset[prgNo] = (instOffset << 8) | inst->type;
383 *param = inst->param; // Structure copy
384 break;
385 }
386
387 case SND_INST_DRUM_SET:
388 {
389 SNDDrumSet *drumSet = (SNDDrumSet *)((u8 *)bank + instOffset);
390 u8 min = MI_ReadByte(&drumSet->min);
391 u8 max = MI_ReadByte(&drumSet->max);
392
393 if (key < min || key > max)
394 {
395 SNDi_UnlockMutex();
396 return FALSE;
397 }
398
399 drumSet->instOffset[key - min] = *inst; // Structure copy
400 break;
401 }
402
403 case SND_INST_KEY_SPLIT:
404 {
405 int index = 0;
406 SNDKeySplit *keySplit = (SNDKeySplit *)((u8 *)bank + instOffset);
407
408 while (key > MI_ReadByte(&keySplit->key[index]))
409 {
410 index++;
411 if (index >= SND_INST_KEYSPLIT_MAX)
412 {
413 SNDi_UnlockMutex();
414 return FALSE;
415 }
416 }
417
418 keySplit->instOffset[index] = *inst; // Structure copy
419 break;
420 }
421
422 case SND_INST_INVALID:
423 default:
424 SNDi_UnlockMutex();
425 return FALSE;
426 }
427
428 SNDi_UnlockMutex();
429
430 #ifdef SDK_ARM9
431 DC_StoreRange(bank, bank->fileHeader.fileSize);
432 #endif
433
434 return TRUE;
435 }
436
437 /*---------------------------------------------------------------------------*
438 Name: SND_GetFirstInstDataPos
439
440 Description: Gets SNDInstPos for instrument data scanning.
441
442 Arguments: bank - Pointer to bank data
443
444 Returns: SNDInstPos structure.
445 *---------------------------------------------------------------------------*/
SND_GetFirstInstDataPos(const SNDBankData * bank)446 SNDInstPos SND_GetFirstInstDataPos(const SNDBankData *bank)
447 {
448 SNDInstPos pos;
449
450 SDK_NULL_ASSERT(bank);
451
452 (void)bank;
453
454 pos.prgNo = 0;
455 pos.index = 0;
456
457 return pos;
458 }
459
460 /*---------------------------------------------------------------------------*
461 Name: SND_GetNextInstData
462
463 Description: Gets the next instrument data.
464
465 Arguments: bank - Pointer to bank data
466 inst - Pointer that stores the obtained instrument data
467 pos - Pointer to the SNDInstPos structure
468
469 Returns: Whether successfully obtained.
470 *---------------------------------------------------------------------------*/
SND_GetNextInstData(const SNDBankData * bank,SNDInstData * inst,SNDInstPos * pos)471 BOOL SND_GetNextInstData(const SNDBankData *bank, SNDInstData *inst, SNDInstPos *pos)
472 {
473 SDK_NULL_ASSERT(bank);
474 SDK_NULL_ASSERT(inst);
475 SDK_NULL_ASSERT(pos);
476
477 for (; pos->prgNo < bank->instCount; pos->prgNo++, pos->index = 0)
478 {
479 u32 instOffset = bank->instOffset[pos->prgNo];
480 inst->type = (u8)(instOffset & 0xff);
481 instOffset >>= 8;
482
483 switch (inst->type)
484 {
485 case SND_INST_PCM:
486 case SND_INST_PSG:
487 case SND_INST_NOISE:
488 case SND_INST_DIRECTPCM:
489 case SND_INST_NULL:
490 {
491 const SNDInstParam *param = (const SNDInstParam *)((u8 *)bank + instOffset);
492 inst->param = *param;
493 pos->prgNo++;
494 return TRUE;
495 }
496
497 case SND_INST_DRUM_SET:
498 {
499 const SNDDrumSet *drumSet = (const SNDDrumSet *)((u8 *)bank + instOffset);
500 for (; pos->index < drumSet->max - drumSet->min + 1; pos->index++)
501 {
502 *inst = drumSet->instOffset[pos->index];
503 pos->index++;
504 return TRUE;
505 }
506 break;
507 }
508
509 case SND_INST_KEY_SPLIT:
510 {
511 const SNDKeySplit *keySplit = (const SNDKeySplit *)((u8 *)bank + instOffset);
512 for (; pos->index < SND_INST_KEYSPLIT_MAX; pos->index++)
513 {
514 if (keySplit->key[pos->index] == 0)
515 break;
516 *inst = keySplit->instOffset[pos->index];
517 pos->index++;
518 return TRUE;
519 }
520 break;
521 }
522
523 default:
524 break;
525 }
526 }
527
528 return FALSE;
529 }
530
531 /*---------------------------------------------------------------------------*
532 Name: SND_GetWaveDataCount
533
534 Description: Gets the number of waveform data in the waveform archive.
535
536 Arguments: waveArc - Pointer to the waveform archive
537
538 Returns: Number of waveform data.
539 *---------------------------------------------------------------------------*/
SND_GetWaveDataCount(const struct SNDWaveArc * waveArc)540 u32 SND_GetWaveDataCount(const struct SNDWaveArc *waveArc)
541 {
542 SDK_NULL_ASSERT(waveArc);
543
544 return waveArc->waveCount;
545 }
546
547 /*---------------------------------------------------------------------------*
548 Name: SND_SetWaveDataAddress
549
550 Description: Registers waveform data to the waveform archive.
551
552 Arguments: waveArc - Pointer to the waveform archive
553 index - Index number of waveform data
554 address - Address of waveform data
555
556 Returns: None.
557 *---------------------------------------------------------------------------*/
SND_SetWaveDataAddress(SNDWaveArc * waveArc,int index,const SNDWaveData * address)558 void SND_SetWaveDataAddress(SNDWaveArc *waveArc, int index, const SNDWaveData *address)
559 {
560 SDK_NULL_ASSERT(waveArc);
561 SDK_MINMAX_ASSERT(index, 0, waveArc->waveCount);
562 SDK_ASSERT(address == NULL || address >= (void *)HW_MAIN_MEM);
563
564 SNDi_LockMutex();
565
566 waveArc->waveOffset[index] = (u32)address;
567
568 #ifdef SDK_ARM9
569 DC_StoreRange(&waveArc->waveOffset[index], sizeof(u32));
570 #endif
571
572 SNDi_UnlockMutex();
573 }
574
575 /*---------------------------------------------------------------------------*
576 Name: SND_GetWaveDataAddress
577
578 Description: Gets the waveform data registered in the waveform archive.
579
580 Arguments: waveArc - Pointer to the waveform archive
581 index - Index number of waveform data
582
583 Returns: Pointer to the obtained waveform data.
584 *---------------------------------------------------------------------------*/
SND_GetWaveDataAddress(const SNDWaveArc * waveArc,int index)585 const SNDWaveData *SND_GetWaveDataAddress(const SNDWaveArc *waveArc, int index)
586 {
587 const SNDWaveData *wave;
588 u32 offset;
589
590 SDK_NULL_ASSERT(waveArc);
591 SDK_MINMAX_ASSERT(index, 0, waveArc->waveCount);
592
593 SNDi_LockMutex();
594
595 offset = waveArc->waveOffset[index];
596
597 if (offset != 0)
598 {
599 if (offset < HW_MAIN_MEM)
600 wave = (const SNDWaveData *)((u8 *)waveArc + offset);
601 else
602 wave = (const SNDWaveData *)offset;
603 }
604 else
605 {
606 wave = NULL;
607 }
608
609 SNDi_UnlockMutex();
610
611 return wave;
612 }
613
614 //-----------------------------------------------------------------------------
615 // ARM7 only
616
617 #ifdef SDK_ARM7
618
619 /*---------------------------------------------------------------------------*
620 Name: SND_NoteOn
621
622 Description: Performs note-on using the bank.
623
624 Arguments:
625
626 Returns: Pointer to SNDChannel structure.
627 *---------------------------------------------------------------------------*/
SND_NoteOn(SNDExChannel * ch_p,int key,int velocity,s32 length,const SNDBankData * bank,const SNDInstData * inst)628 BOOL SND_NoteOn(SNDExChannel *ch_p,
629 int key, int velocity, s32 length, const SNDBankData *bank, const SNDInstData *inst)
630 {
631 const SNDWaveData *wave_data;
632 int release;
633 BOOL result;
634
635 SDK_NULL_ASSERT(ch_p);
636 SDK_MINMAX_ASSERT(key, 0, 127);
637 SDK_MINMAX_ASSERT(velocity, 0, 127);
638 SDK_NULL_ASSERT(inst);
639
640 release = inst->param.release;
641 if (inst->param.release == SND_BANK_DISABLE_RELEASE)
642 {
643 length = -1;
644 release = 0;
645 }
646
647 switch (inst->type)
648 {
649 case SND_INST_PCM:
650 case SND_INST_DIRECTPCM:
651 if (inst->type == SND_INST_PCM)
652 {
653 wave_data = GetWaveData(bank, inst->param.wave[1], inst->param.wave[0]);
654 }
655 else
656 {
657 wave_data = (const SNDWaveData *)(inst->param.wave[1] << 16 | inst->param.wave[0]);
658 }
659
660 if (wave_data != NULL)
661 {
662 result = SND_StartExChannelPcm(ch_p, &wave_data->param, wave_data->samples, length);
663 }
664 else
665 {
666 result = FALSE;
667 }
668 break;
669
670 case SND_INST_PSG:
671 result = SND_StartExChannelPsg(ch_p, (SNDDuty)inst->param.wave[0], length);
672 break;
673
674 case SND_INST_NOISE:
675 result = SND_StartExChannelNoise(ch_p, length);
676 break;
677
678 default:
679 result = FALSE;
680 break;
681 }
682
683 if (!result)
684 return FALSE;
685
686 ch_p->key = (u8)key;
687 ch_p->original_key = inst->param.original_key;
688 ch_p->velocity = (u8)velocity;
689
690 SND_SetExChannelAttack(ch_p, inst->param.attack);
691 SND_SetExChannelDecay(ch_p, inst->param.decay);
692 SND_SetExChannelSustain(ch_p, inst->param.sustain);
693 SND_SetExChannelRelease(ch_p, release);
694
695 ch_p->init_pan = (s8)(inst->param.pan - 64);
696
697 return TRUE;
698 }
699
700 #endif
701
702 /******************************************************************************
703 Static Functions
704 ******************************************************************************/
705
706 //-----------------------------------------------------------------------------
707 // ARM7 only
708
709 #ifdef SDK_ARM7
710
711 /*---------------------------------------------------------------------------*
712 Name: GetWaveData
713
714 Description: Gets waveform data from the waveform archive.
715
716 Arguments: bank - Pointer to SNDBankData
717 waveArcNo - Wave archive number
718 waveIndex - Wave index
719
720 Returns: Pointer to SNDWaveData structure.
721 *---------------------------------------------------------------------------*/
GetWaveData(const SNDBankData * bank,int waveArcNo,int waveIndex)722 static const SNDWaveData *GetWaveData(const SNDBankData *bank, int waveArcNo, int waveIndex)
723 {
724 const SNDWaveArc *arc;
725
726 SDK_MINMAX_ASSERT(waveArcNo, 0, SND_BANK_TO_WAVEARC_MAX - 1);
727
728 arc = bank->waveArcLink[waveArcNo].waveArc;
729
730 if (arc == NULL)
731 return NULL;
732 if (waveIndex >= arc->waveCount)
733 return NULL;
734
735 return SND_GetWaveDataAddress(arc, waveIndex);
736 }
737
738 #endif
739
740 /*====== End of snd_bank.c ======*/
741