Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
mseq_player.c
Go to the documentation of this file.
1#include "audio.h"
2#include "audio/core.h"
3
4extern u8 BlankMseqData[];
5
6#define TRACK_ID_DRUM 9
7
14
20
26
30
43
44void au_mseq_manager_init(AmbienceManager* manager, s8 priority, s8 busID, AuGlobals* globals) {
45 AmbiencePlayer* player;
46 s32 i;
47
48 au_memset(manager, sizeof(*manager), 0);
49
50 for (i = 0; i < ARRAY_COUNT(manager->players); i++) {
51 player = &manager->players[i];
52 player->id.playerIndex = i;
53 player->delay = 1;
54 player->fadeVolume = AU_MAX_VOLUME_8 << 24;
55 }
56
57 manager->globals = globals;
58 manager->nextUpdateStep = 1;
59 manager->nextUpdateCounter = 2;
60 manager->nextUpdateInterval = 2;
61 manager->priority = priority;
62 manager->busID = busID;
63}
64
68 } else {
69 return AU_RESULT_OK;
70 }
71}
72
76
79 AmbiencePlayer* player = &manager->players[index];
80
81 if (!disable) {
83 } else {
85 }
86}
87
89 AmbiencePlayer* player = &gAuAmbienceManager->players[index];
91 AuResult status = AU_RESULT_OK;
92
93 if (mseq != NULL) {
94 if (player->mseqName == 0) {
96 if (time != 0) {
97 player->fadeSettingsTime = time;
98 player->fadeSettingsInitial = 0;
101 au_mseq_fade_setup(player);
102 }
103 } else {
105 }
106 } else {
108 }
109 return status;
110}
111
113 u16 time = player->fadeSettingsTime;
114
115 if (player->fadeSettingsInitial == 255) {
116 player->fadeSettingsInitial = player->fadeVolume >> 24;
117 }
118
119 if (time >= SND_MIN_DURATION && time <= SND_MAX_DURATION) {
120 player->fadeVolume = player->fadeSettingsInitial << 24;
121 player->fadeGoal = player->fadeSettingsGoal;
122
123 // converts a fade time in milliseconds to the number of player update ticks needed to complete the fade
124 // the ambience manager updates every other audio frame, so given outputRate = 32000 and frameSize = 184,
125 // update ticks needed = (32000 / 184) / 2, and then we divide by 1000 (since fade time has units of ms).
126 // this reduces to 16/184, which is exactly 1.6 times 10/115
127 // why this odd reduction was chosen unstead of 16/184 is unknown
128 player->fadeTime = (u32)(time * 10) / 115;
129 player->fadeStep = ((player->fadeSettingsGoal - player->fadeSettingsInitial) << 24) / ((s16)player->fadeTime & 0xFFFF);
130 }
131
132 player->fadeSettingsTime = 0;
133 player->fadeSettingsInitial = 0;
134 player->fadeSettingsGoal = 0;
135}
136
137void au_mseq_pause(s32 index, s32 time) {
138 AmbiencePlayer* player = &gAuAmbienceManager->players[index];
139
140 if (player->mseqReadStart != NULL && player->mseqReadPos != NULL) {
141 if (time != 0) {
142 player->fadeSettingsInitial = 255;
143 player->fadeSettingsTime = time;
144 player->fadeSettingsGoal = 0;
146 return;
147 }
148 player->mode = MSEQ_MODE_PAUSING;
149 }
150}
151
152void au_mseq_resume(s32 index, s32 time) {
153 AmbiencePlayer* player = &gAuAmbienceManager->players[index];
154
155 if (player->mseqReadStart != NULL && player->mseqReadPos != NULL) {
156 player->mode = MSEQ_MODE_RESUMING;
157 if (time != 0) {
158 player->fadeSettingsTime = time;
159 } else {
161 }
162 player->fadeSettingsInitial = 0;
165 }
166}
167
169 AmbiencePlayer* player = &gAuAmbienceManager->players[index];
170
171 if (player->mseqReadStart != NULL && player->mseqReadPos != NULL) {
172 if (player->mode != MSEQ_MODE_PLAYING) {
173 player->mseqReadPos = NULL;
174 player->mseqName = 0;
175 player->mode = MSEQ_MODE_PLAYING;
176 return;
177 }
178 player->mseqReadPos = BlankMseqData;
179 player->delay = 1;
180 }
181}
182
183void au_mseq_stop_slow(s32 index, s32 time) {
184 AmbiencePlayer* player = &gAuAmbienceManager->players[index];
185
186 if (player->mseqReadStart != NULL && player->mseqReadPos != NULL) {
187 if (time != 0) {
188 player->fadeSettingsTime = time;
189 } else {
191 }
192 player->fadeSettingsInitial = 255;
193 player->fadeSettingsGoal = 0;
195 }
196}
197
198void au_mseq_set_volume(s32 index, s32 time, s32 volume) {
199 AmbiencePlayer* player = &gAuAmbienceManager->players[index];
200 if ((player->mseqReadStart != 0) && (player->mseqReadPos != 0)) {
201 if (volume <= 0) {
202 volume = 1;
203 } else if (volume > AU_MAX_VOLUME_8) {
204 volume = AU_MAX_VOLUME_8;
205 }
206 if (time != 0) {
207 player->fadeSettingsTime = time;
208 } else {
210 }
211 player->fadeSettingsInitial = 255;
212 player->fadeSettingsGoal = volume;
214 }
215}
216
218 AmbiencePlayer* player = &gAuAmbienceManager->players[index];
219 AuResult status = AU_RESULT_OK;
220
221 if (player->mseqReadStart != NULL && player->mseqReadPos != NULL) {
223 if (player->mode != MSEQ_MODE_PLAYING) {
225 }
226 }
227 return status;
228}
229
231 AmbiencePlayer* player;
233 AuFilePos readPos;
234 s32 i;
235
236 player = &manager->players[index];
237 au_memset(player, sizeof(*player), 0);
238
239 player->mseqFile = mseqFile;
240 readPos = AU_FILE_RELATIVE(mseqFile->dataStart, mseqFile);
241 player->id.playerIndex = index;
242 player->mseqReadPos = readPos;
243 player->loopStartPos[1] = readPos;
244 player->loopStartPos[0] = readPos;
245 player->mseqReadStart = readPos;
246
247 player->delay = 1;
248 player->fadeVolume = AU_MAX_VOLUME_8 << 24;
249 player->fadeGoal = AU_MAX_VOLUME_8;
250
251 player->mseqName = player->mseqFile->name;
252 player->firstVoiceIdx = player->mseqFile->firstVoiceIdx;
253 player->lastVoiceIdx = player->firstVoiceIdx + 16;
254 if (player->lastVoiceIdx > 24) {
255 player->lastVoiceIdx = 24;
256 }
257 for (i = 0; i < ARRAY_COUNT(player->tracks); i++) {
258 track = &player->tracks[i];
259 track->instrument = manager->globals->defaultInstrument;
260 track->volumeLerp.current = AU_MAX_VOLUME_32;
261 track->pan = 64;
262 }
263 player->resetRequired = TRUE;
264}
265
267 u32 i;
268 s32 j;
269
270 for (i = 0; i < ARRAY_COUNT(manager->voiceStates); i++) {
271 AmbienceVoiceState* voiceState = &manager->voiceStates[i];
272
273 // potential @bug, any voice which is not properly released via MSEQ_CMD_80_STOP_SOUND will eventaully
274 // end and set its priority to AU_PRIORITY_FREE, where another client can steal it and begin using it
275 // without it being considered 'free' by this AmbienceManager. this can be fixed by removing the check
276 // for released == TRUE from the conditional
277 if (voiceState->info.released == TRUE && manager->globals->voices[i].priority != manager->priority) {
278 voiceState->info.all = 0;
279 }
280 }
281
282 for (j = 0; j < ARRAY_COUNT(manager->players); j++) {
283 AmbiencePlayer* player = &manager->players[j];
284 s32 mode;
285
286 if (player->mseqReadPos != NULL) {
287 if (manager->loadTracksFadeInfo) {
289 }
290
291 mode = player->mode;
292 if (mode != MSEQ_MODE_PLAYING) {
293 if (mode == MSEQ_MODE_PAUSING) {
294 player->mode = MSEQ_MODE_STOPPED;
297 } else if (player->mode == MSEQ_MODE_RESUMING) {
298 player->mode = MSEQ_MODE_PLAYING;
299 if (player->fadeSettingsTime != 0) {
300 au_mseq_fade_setup(player);
301 }
303 }
304 } else {
305 // case MSEQ_MODE_PLAYING
306 if (player->fadeSettingsTime != 0) {
307 au_mseq_fade_setup(player);
308 }
309 if (player->playState == MSEQ_PLAYER_STOPPING) {
312 }
314 }
315 }
316 }
317
318 manager->loadTracksFadeInfo = FALSE;
319}
320
322 MSEQHeader* mseqFile;
325 s32 offset;
326 s32 count;
327
328 mseqFile = player->mseqFile;
329 count = mseqFile->trackSettingsCount;
330 if (count != 0 && mseqFile->trackSettingsOffset != 0) {
331 trackData = AU_FILE_RELATIVE(mseqFile->trackSettingsOffset, mseqFile);
332 while (count--) {
333 track = &player->tracks[trackData->trackIndex];
334 if (trackData->type == 0) {
335 track->tuneLerp.time = trackData->time;
336 track->tuneLerp.step = (trackData->delta << 16) / trackData->time;
337 track->tuneLerp.goal = trackData->goal;
338 } else if (trackData->type == 1) {
339 track->volumeLerp.time = trackData->time;
340 track->volumeLerp.step = (trackData->delta << 16) / trackData->time;
341 track->volumeLerp.goal = trackData->goal;
342 }
343 trackData++;
344 }
345 }
346}
347
350 u8 isPitchChanged[16];
351 AuGlobals* globals;
354 AuVoice* voice;
358 s32 i;
359 u16 bankPatch;
360 u32 count;
361 s32 loopID;
362 u8 op, arg1, arg2;
364
365 globals = manager->globals;
367 for (i = 0; i < 16U; i++) { // required to use unsigned literal
370 }
371
372 if (player->resetRequired == TRUE) {
374 player->resetRequired = FALSE;
375 }
376
377 if (player->fadeTime != 0) {
378 player->fadeVolume += player->fadeStep;
379 player->fadeTime--;
380 if (player->fadeTime == 0) {
381 player->fadeVolume = player->fadeGoal << 24;
382 if (player->fadeSettingsType == MSEQ_FADE_IN) {
383 // do nothing
384 } else if (player->fadeSettingsType == MSEQ_FADE_OUT) {
385 player->mseqReadPos = BlankMseqData;
386 player->delay = 1;
387 } else if (player->fadeSettingsType == MSEQ_FADE_OUT_PAUSING) {
388 player->mode = MSEQ_MODE_PAUSING;
389 }
390 }
392 }
393
394 // update pitch
395 for (trackIdx = 0; trackIdx < ARRAY_COUNT(player->tracks); trackIdx++) {
396 track = &player->tracks[trackIdx];
397 if (track->tuneLerp.time != 0) {
399 if (track->tuneLerp.time != 0) {
400 track->tuneLerp.current += track->tuneLerp.step;
401 } else {
402 track->tuneLerp.current = track->tuneLerp.goal << 16;
403 }
404
405 voiceSelector = player->id.all + (trackIdx << 16);
406 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
407 voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
408 // update all voices belonging to current track
409 if ((voiceState->info.all & 0xFFFF0000) == voiceSelector) {
410 voice = &globals->voices[i];
411 if (voice->priority == manager->priority && trackIdx != TRACK_ID_DRUM) {
412 voice->pitchRatio = au_compute_pitch_ratio(voiceState->pitch + (track->tuneLerp.current >> 16)) * track->instrument->pitchRatio;
413 voice->syncFlags |= AU_VOICE_SYNC_FLAG_PITCH;
414 isPitchChanged[i - player->firstVoiceIdx] = TRUE;
415 }
416 }
417 }
418 }
419 }
420
421 // update volume
422 for (trackIdx = 0; trackIdx < ARRAY_COUNT(player->tracks); trackIdx++) {
423 track = &player->tracks[trackIdx];
424 if (track->volumeLerp.time != 0) {
426 if (track->volumeLerp.time != 0) {
427 track->volumeLerp.current += track->volumeLerp.step;
428 } else {
429 track->volumeLerp.current = track->volumeLerp.goal << 16;
430 }
431
432 voiceSelector = player->id.all + (trackIdx << 16);
433 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
434 voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
435 // update all voices belonging to current track
436 if ((voiceState->info.all & 0xFFFF0000) == voiceSelector) {
437 voice = &globals->voices[i];
438 if (voice->priority == manager->priority) {
439 track = &player->tracks[voiceState->info.trackIndex];
440 voice->clientVolume = VOL_MULT_3(player->fadeVolume >> 24, track->volumeLerp.current >> 16, voiceState->volume);
441 voice->envelopeFlags |= AU_VOICE_ENV_FLAG_VOL_CHANGED;
442 }
443 }
444 }
445 }
446 }
447
448 player->delay--;
449 if (player->delay <= 0) {
450 while (player->delay == 0) {
451 op = au_mseq_read_next(player);
452 if ((s8)op >= 0) {
453 if (op == 0) {
454 // stop
455 player->mseqReadPos = NULL;
456 player->mseqName = 0;
458 break;
459 }
460 if (op >= 0x78) {
461 // long delay
462 player->delay = ((op & 7) << 8) + au_mseq_read_next(player) + 0x78;
463 } else {
464 //short delay
465 player->delay = op;
466 }
467 continue;
468 }
469
470 // op >= 0x80
471 // op & 0xF0 : command
472 // op & 0xF : track index
473
474 arg1 = au_mseq_read_next(player);
475 trackIdx = op & 0xF;
476 track = &player->tracks[trackIdx];
477
478 switch (op & 0xF0) {
480 // arg1: sound index
481 if (player->playState == MSEQ_PLAYER_PLAYING) {
482 voiceSelector = player->id.all + (trackIdx << 16) + (arg1 << 8);
483 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
484 if (manager->voiceStates[i - player->firstVoiceIdx].info.all == voiceSelector) {
485 manager->voiceStates[i - player->firstVoiceIdx].info.released = TRUE;
486 voice = &globals->voices[i];
487 if (voice->priority == manager->priority) {
489 }
490 }
491 }
492 }
493 break;
495 // arg1: pitch or drum sound id
496 // arg2: volume
497 arg2 = au_mseq_read_next(player);
498 if (player->playState == MSEQ_PLAYER_PLAYING) {
499 // find free voice
500 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
501 voice = &globals->voices[i];
502 if (voice->priority == AU_PRIORITY_FREE) {
503 break;
504 }
505 }
506 if (i >= player->lastVoiceIdx) {
507 // try stealing a voice from the current player (or one with the same priority)
508 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
509 voice = &globals->voices[i];
510 if (voice->priority == manager->priority) {
512 break;
513 }
514 }
515 }
516 if (i >= player->lastVoiceIdx) {
517 // try stealing a voice from a different player with a lower priority
518 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
519 voice = &globals->voices[i];
520 if (voice->priority < manager->priority) {
522 break;
523 }
524 }
525 }
526 if (i < player->lastVoiceIdx) {
527 isVolumeChanged[i - player->firstVoiceIdx] = TRUE;
528 isPitchChanged[i - player->firstVoiceIdx] = TRUE;
529 voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
530 // set playerIndex, trackIndex and tune
531 voiceState->info.all = player->id.all + (trackIdx << 16) + (arg1 << 8);
532 if (track->flags & MSEQ_TRACK_RESUMABLE) {
533 voiceState->isResumable = TRUE;
534 } else {
535 voiceState->isResumable = FALSE;
536 }
537 if (trackIdx != TRACK_ID_DRUM) {
538 if (track->flags & MSEQ_TRACK_RESUMABLE) {
539 voiceState->isResumable = TRUE;
540 } else {
541 voiceState->isResumable = FALSE;
542 }
543
544 voiceState->pitch = (arg1 & 0x7F) * 100 - track->instrument->keyBase;
545 voiceState->volume = arg2 & 0x7F;
546 voice->clientVolume = VOL_MULT_3(player->fadeVolume >> 24, track->volumeLerp.current >> 16, voiceState->volume);
547 voice->pitchRatio = au_compute_pitch_ratio(voiceState->pitch + (track->tuneLerp.current >> 16)) * track->instrument->pitchRatio;
548 voice->pan = track->pan;
549 voice->reverb = track->reverb;
550 voice->instrument = track->instrument;
551 voice->busID = manager->busID;
552 voice->envelope.cmdListPress = track->envelope.cmdListPress;
553 voice->envelope.cmdListRelease = track->envelope.cmdListRelease;
554 } else {
555 voiceState->isResumable = FALSE;
556 drum = &manager->globals->dataPER->drums[arg1 & 0x7F];
557 bankPatch = drum->bankPatch;
558 voice->instrument = au_get_instrument(manager->globals, bankPatch >> 8, bankPatch & 0xFF, &voice->envelope);
559 voiceState->pitch = drum->keyBase - voice->instrument->keyBase;
560 voiceState->volume = VOL_MULT_2(arg2 & 0x7F, drum->volume);
561 voice->clientVolume = VOL_MULT_3(player->fadeVolume >> 24, track->volumeLerp.current >> 16, voiceState->volume);
562 voice->pitchRatio = au_compute_pitch_ratio(voiceState->pitch) * voice->instrument->pitchRatio;
563 voice->pan = drum->pan;
564 voice->reverb = drum->reverb;
565 voice->busID = manager->busID;
566 }
567 voice->syncFlags = AU_VOICE_SYNC_FLAG_ALL;
568 voice->priority = manager->priority;
569 voice->clientPriority = voice->priority;
570 }
571 }
572 break;
574 // higher bit: set pan (1) or volume (0)
575 // lower 7 bits: value
576 if (arg1 & 0x80) {
577 track->pan = arg1 & 0x7F;
578 voiceSelector = player->id.all + (trackIdx << 16);
579 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
580 voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
581 if ((voiceState->info.all & 0xFFFF0000) == voiceSelector) {
582 voice = &globals->voices[i];
583 if (voice->priority == manager->priority && trackIdx != TRACK_ID_DRUM) {
584 voice->pan = track->pan;
586 }
587 }
588 }
589 } else {
590 track->volumeLerp.current = arg1 << 24;
591 if (track->volumeLerp.current != 0) {
592 track->volumeLerp.current |= 0xFFFFFF;
593 }
594 voiceSelector = player->id.all + (trackIdx << 16);
595 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
596 voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
597 if ((voiceState->info.all & 0xFFFF0000) == voiceSelector) {
598 voice = &globals->voices[i];
599 if (voice->priority == manager->priority) {
600 voice->clientVolume = VOL_MULT_3(player->fadeVolume >> 24, track->volumeLerp.current >> 16, voiceState->volume);
601 if (!isVolumeChanged[i - player->firstVoiceIdx]) {
602 voice->envelopeFlags |= AU_VOICE_ENV_FLAG_VOL_CHANGED;
603 isVolumeChanged[i - player->firstVoiceIdx] = TRUE;
604 }
605 }
606 }
607 }
608 }
609 break;
611 // arg1: sub command
612 // arg2: depends on sub command
613 arg2 = au_mseq_read_next(player);
614 switch (arg1) {
616 // arg2: loop id
617 player->loopStartPos[arg2 & 1] = player->mseqReadPos;
618 break;
620 // arg2 lower bit: loop id
621 // (arg2 & 0x7C) >> 2: loop count
622 loopID = arg2 & 1;
623 count = (arg2 & 0x7C) >> 2;
624 if (count != 0) {
625 if (player->loopCount[loopID] != 0) {
626 player->loopCount[loopID]--;
627 // if it's the last iteration then don't jump to the loop start
628 if (player->loopCount[loopID] != 0) {
629 player->mseqReadPos = player->loopStartPos[loopID];
630 }
631 } else {
632 // first iteration, set loop counter
633 player->mseqReadPos = player->loopStartPos[loopID];
634 player->loopCount[loopID] = count;
635 }
636 } else {
637 // infinite loop
638 player->mseqReadPos = player->loopStartPos[loopID];
639 player->loopCount[loopID] = 0;
640 }
641 break;
643 track->reverb = arg2;
644 break;
646 if (arg2 == 1) {
647 track->flags |= MSEQ_TRACK_RESUMABLE;
648 }
649 break;
650 }
651 break;
653 // arg1: bank
654 // arg2: patch
655 arg2 = au_mseq_read_next(player);
656 if (trackIdx != TRACK_ID_DRUM) {
657 track->instrument = au_get_instrument(manager->globals, arg1, arg2, &track->envelope);
658 }
659 break;
661 // arg1: coarse tune
662 // arg2: fine tune
663 track->tuneLerp.current = (arg1 << 24) + (au_mseq_read_next(player) << 16);
664 voiceSelector = player->id.all + (trackIdx << 16);
665 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
666 voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
667 if ((voiceState->info.all & 0xFFFF0000) == voiceSelector) {
668 voice = &globals->voices[i];
669 if (voice->priority == manager->priority && trackIdx != TRACK_ID_DRUM) {
670 voice->pitchRatio = au_compute_pitch_ratio(voiceState->pitch + (track->tuneLerp.current >> 16)) * track->instrument->pitchRatio;
671 voice->syncFlags |= AU_VOICE_SYNC_FLAG_PITCH;
672 isPitchChanged[i - player->firstVoiceIdx] = 1;
673 }
674 }
675 }
676 break;
677 case 0xF0: // required to match
678 break;
679 }
680 }
681 }
682 if (fadeVolChanged) {
683 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
684 voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
685 // update all voices belonging to this player
686 if ((voiceState->info.all & 0xFF000000) == player->id.all) {
687 voice = &globals->voices[i];
688 if (voice->priority == manager->priority && !isVolumeChanged[i - player->firstVoiceIdx]) {
689 track = &player->tracks[voiceState->info.trackIndex];
690 voice->clientVolume = VOL_MULT_3(player->fadeVolume >> 24, track->volumeLerp.current >> 16, voiceState->volume);
691 voice->envelopeFlags |= AU_VOICE_ENV_FLAG_VOL_CHANGED;
692 }
693 }
694 }
695 }
696}
697
699 u8 value = *state->mseqReadPos++;
700 return value;
701}
702
704 AuVoice* voice;
706 s32 i;
707
708 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
709 voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
710 if (voiceState->info.playerIndex == player->id.playerIndex) {
711 voice = &manager->globals->voices[i];
712 if (voice->priority == manager->priority) {
714 }
715 voiceState->info.all = 0;
716 }
717 }
718}
719
722 u32 numSaved = 0;
723 s32 i;
724
725 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
726 AmbienceVoiceState* voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
727
728 if (!voiceState->isResumable) {
729 continue;
730 }
731
732 savedVoice->trackIndex = voiceState->info.trackIndex;
733 savedVoice->tune = voiceState->info.tune;
734 savedVoice->volume = voiceState->volume;
735
736 savedVoice++;
737 numSaved++;
738 if (numSaved >= ARRAY_COUNT(player->savedVoices)) {
739 break;
740 }
741 }
742}
743
745 AuGlobals* globals;
746 AuVoice* voice;
750 u32 i, j;
751
752 globals = manager->globals;
753 if (player->playState == MSEQ_PLAYER_PLAYING) {
754 for (i = 0; i < ARRAY_COUNT(player->savedVoices); i++) {
755 savedVoice = &player->savedVoices[i];
756 if (savedVoice->tune != 0) {
757 track = &player->tracks[savedVoice->trackIndex];
758
759 // find first free voice
760 for (j = player->firstVoiceIdx; j < player->lastVoiceIdx; j++) {
761 voice = &globals->voices[j];
762 if (voice->priority == AU_PRIORITY_FREE) {
763 break;
764 }
765 }
766
767 // try stealing a voice with lower priority
768 if (j >= player->lastVoiceIdx) {
769 for (j = player->firstVoiceIdx; j < player->lastVoiceIdx; j++) {
770 voice = &globals->voices[j];
771 if (voice->priority < manager->priority) {
773 break;
774 }
775 }
776 }
777
778 if (j < player->lastVoiceIdx) {
779 voiceState = &manager->voiceStates[j - player->firstVoiceIdx];
780 voiceState->info.all = player->id.all + (savedVoice->trackIndex << 16) + (savedVoice->tune << 8);
781 voiceState->pitch = (savedVoice->tune & 0x7F) * 100 - track->instrument->keyBase;
782 voiceState->volume = savedVoice->volume & 0x7F;
783 voice->clientVolume = VOL_MULT_3(player->fadeVolume >> 24, track->volumeLerp.current >> 16, voiceState->volume);
784 voice->pitchRatio = au_compute_pitch_ratio(voiceState->pitch + (track->tuneLerp.current >> 16)) * track->instrument->pitchRatio;
785 voice->pan = track->pan;
786 voice->reverb = track->reverb;
787 voice->instrument = track->instrument;
788 voice->busID = manager->busID;
789 voice->envelope.cmdListPress = track->envelope.cmdListPress;
790 voice->envelope.cmdListRelease = track->envelope.cmdListRelease;
791 voice->syncFlags = AU_VOICE_SYNC_FLAG_ALL;
792 voice->priority = manager->priority;
793 voice->clientPriority = voice->priority;
794 }
795 }
796 savedVoice->trackIndex = 0;
797 savedVoice->tune = 0;
798 savedVoice->volume = 0;
799 }
800 }
801}
BSS s32 PopupMenu_SelectedIndex
MSEQHeader * mseqFiles[4]
Definition audio.h:1371
s8_24 fadeStep
Definition audio.h:1358
u32 firstVoiceIdx
Definition audio.h:1355
AmbVoiceStateInfo info
Definition audio.h:1331
MSEQHeader * mseqFile
Definition audio.h:1338
u8 fadeSettingsType
Definition audio.h:1348
u8 trackSettingsCount
Definition audio.h:1286
AuVoice voices[24]
Definition audio.h:1075
AuFilePos mseqReadPos
Definition audio.h:1340
u8 fadeSettingsGoal
Definition audio.h:1352
Instrument * instrument
Definition audio.h:1293
u16 fadeSettingsTime
Definition audio.h:1350
#define VOL_MULT_3(a, b, c)
Definition audio.h:125
u16 dataStart
Definition audio.h:1288
AmbienceTrack tracks[10]
Definition audio.h:1362
u8 loopCount[2]
Definition audio.h:1353
#define VOL_MULT_2(a, b)
Definition audio.h:122
#define AU_FILE_RELATIVE(base, offset)
Definition audio.h:43
SoundLerp tuneLerp
Definition audio.h:1295
AmbVoiceStateInfo id
Definition audio.h:1342
f32 pitchRatio
Definition audio.h:838
#define AU_MAX_VOLUME_8
Definition audio.h:61
u8 numActivePlayers
Definition audio.h:1372
AuFilePos mseqReadStart
Definition audio.h:1339
SoundLerp volumeLerp
Definition audio.h:1296
u8 loadTracksFadeInfo
Definition audio.h:1373
@ AU_VOICE_SYNC_FLAG_PAN_FXMIX
Definition audio.h:151
@ AU_VOICE_SYNC_FLAG_PITCH
Definition audio.h:150
@ AU_VOICE_SYNC_FLAG_ALL
Definition audio.h:148
s16 clientVolume
Definition audio.h:861
s32 name
Definition audio.h:1284
u8 pan
Definition audio.h:841
s16 time
Definition audio.h:704
u16 trackSettingsOffset
Definition audio.h:1287
#define SND_MIN_DURATION
Definition audio.h:102
AmbienceSavedVoice savedVoices[4]
Definition audio.h:1363
AuFilePos loopStartPos[2]
Definition audio.h:1341
AmbiencePlayer players[4]
Definition audio.h:1376
s8_24 fadeVolume
Definition audio.h:1357
u8 envelopeFlags
Definition audio.h:858
#define SND_MAX_DURATION
Definition audio.h:103
u8 firstVoiceIdx
Definition audio.h:1285
u8 fadeSettingsInitial
Definition audio.h:1351
#define AU_MAX_VOLUME_32
Definition audio.h:63
@ AU_PRIORITY_FREE
Definition audio.h:133
u32 lastVoiceIdx
Definition audio.h:1356
u8 * AuFilePos
Definition audio.h:11
@ AU_VOICE_ENV_FLAG_KEY_RELEASED
Definition audio.h:143
@ AU_VOICE_ENV_FLAG_VOL_CHANGED
Definition audio.h:144
AmbienceManager * gAuAmbienceManager
Definition engine.c:11
void au_reset_voice(AuVoice *voice, u8 voiceIdx)
Definition engine.c:393
f32 au_compute_pitch_ratio(s32 tuning)
Converts a linear pitch value (in cents) into a frequency ratio suitable for adjusting playback speed...
Definition engine.c:406
Instrument * au_get_instrument(AuGlobals *globals, BankSetIndex bank, s32 patch, EnvelopeData *arg3)
Note that bank is supplied as BankSetIndex and not BankSet, which means it will be used to perform a ...
Definition engine.c:502
void au_memset(void *dst, s32 size, u8 value)
Definition engine.c:1226
AuResult
Definition enums.h:1758
@ AU_RESULT_OK
Definition enums.h:1759
@ AU_AMBIENCE_STOP_ERROR_1
Definition enums.h:1761
@ AU_AMBIENCE_STOP_ERROR_2
Definition enums.h:1762
@ AU_AMBIENCE_ERROR_3
Definition enums.h:1767
@ AU_AMBIENCE_ERROR_MSEQ_NOT_FOUND
Definition enums.h:1765
@ AU_AMBIENCE_ERROR_PLAYER_BUSY
Definition enums.h:1763
AuResult au_mseq_start(s32 index, s32 time)
Definition mseq_player.c:88
void au_mseq_restore_voices(AmbienceManager *manager, AmbiencePlayer *player)
void au_mseq_set_disabled(s32 index, s32 disable)
Definition mseq_player.c:77
void au_mseq_player_update(AmbienceManager *manager, AmbiencePlayer *player)
void au_mseq_stop_slow(s32 index, s32 time)
MseqPlayState
Definition mseq_player.c:21
@ MSEQ_PLAYER_PLAYING
Definition mseq_player.c:22
@ MSEQ_PLAYER_STOPPED
Definition mseq_player.c:23
@ MSEQ_PLAYER_STOPPING
Definition mseq_player.c:24
#define TRACK_ID_DRUM
Definition mseq_player.c:6
MseqMode
Definition mseq_player.c:8
@ MSEQ_MODE_PAUSING
Definition mseq_player.c:12
@ MSEQ_MODE_STOPPED
Definition mseq_player.c:11
@ MSEQ_MODE_RESUMING
Definition mseq_player.c:10
@ MSEQ_MODE_PLAYING
Definition mseq_player.c:9
AuResult au_mseq_check_player_index(u32 index)
Definition mseq_player.c:65
void au_mseq_manager_init(AmbienceManager *manager, s8 priority, s8 busID, AuGlobals *globals)
Definition mseq_player.c:44
void au_mseq_fade_setup(AmbiencePlayer *player)
void au_mseq_load_tracks_fade(s32 arg0, s32 arg1)
Definition mseq_player.c:73
void au_mseq_save_voices(AmbienceManager *manager, AmbiencePlayer *player)
MseqTrackFlags
Definition mseq_player.c:27
@ MSEQ_TRACK_RESUMABLE
Definition mseq_player.c:28
MseqFadeState
Definition mseq_player.c:15
@ MSEQ_FADE_OUT
Definition mseq_player.c:17
@ MSEQ_FADE_IN
Definition mseq_player.c:16
@ MSEQ_FADE_OUT_PAUSING
Definition mseq_player.c:18
void au_mseq_stop_quick(s32 index)
MseqCommand
Definition mseq_player.c:31
@ MSEQ_CMD_C0_SET_INSTRUMENT
Definition mseq_player.c:36
@ MSEQ_CMD_SUB_68_SET_REVERB
Definition mseq_player.c:40
@ MSEQ_CMD_SUB_67_END_LOOP
Definition mseq_player.c:39
@ MSEQ_CMD_SUB_69_SET_RESUMABLE
Definition mseq_player.c:41
@ MSEQ_CMD_90_PLAY_SOUND
Definition mseq_player.c:33
@ MSEQ_CMD_B0_MULTI
Definition mseq_player.c:35
@ MSEQ_CMD_SUB_66_START_LOOP
Definition mseq_player.c:38
@ MSEQ_CMD_A0_SET_VOLUME_PAN
Definition mseq_player.c:34
@ MSEQ_CMD_80_STOP_SOUND
Definition mseq_player.c:32
@ MSEQ_CMD_E0_TUNING
Definition mseq_player.c:37
void au_mseq_resume(s32 index, s32 time)
AuResult au_mseq_check_stopped(s32 index)
u8 au_mseq_read_next(AmbiencePlayer *state)
u8 BlankMseqData[]
Definition sfx_player.c:287
void au_mseq_load_track_fade_info(AmbienceManager *manager, AmbiencePlayer *player)
void au_mseq_set_volume(s32 index, s32 time, s32 volume)
void au_mseq_pause(s32 index, s32 time)
void au_mseq_player_stop(AmbienceManager *manager, AmbiencePlayer *player)
void au_mseq_manager_audio_frame_update(AmbienceManager *manager)
void au_mseq_play_sequence(AmbienceManager *manager, MSEQHeader *mseqFile, s32 index)
#define ARRAY_COUNT(arr)
Definition macros.h:40