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 != nullptr) {
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 != nullptr && player->mseqReadPos != nullptr) {
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 != nullptr && player->mseqReadPos != nullptr) {
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 != nullptr && player->mseqReadPos != nullptr) {
172 if (player->mode != MSEQ_MODE_PLAYING) {
173 player->mseqReadPos = nullptr;
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 != nullptr && player->mseqReadPos != nullptr) {
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 != nullptr && player->mseqReadPos != nullptr) {
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 != nullptr) {
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 count;
326
327 mseqFile = player->mseqFile;
328 count = mseqFile->trackSettingsCount;
329 if (count != 0 && mseqFile->trackSettingsOffset != 0) {
330 trackData = AU_FILE_RELATIVE(mseqFile->trackSettingsOffset, mseqFile);
331 while (count--) {
332 track = &player->tracks[trackData->trackIndex];
333 if (trackData->type == 0) {
334 track->tuneLerp.time = trackData->time;
335 track->tuneLerp.step = (trackData->delta << 16) / trackData->time;
336 track->tuneLerp.goal = trackData->goal;
337 } else if (trackData->type == 1) {
338 track->volumeLerp.time = trackData->time;
339 track->volumeLerp.step = (trackData->delta << 16) / trackData->time;
340 track->volumeLerp.goal = trackData->goal;
341 }
342 trackData++;
343 }
344 }
345}
346
349 u8 isPitchChanged[16];
350 AuGlobals* globals;
353 AuVoice* voice;
357 s32 i;
358 u16 bankPatch;
359 u32 count;
360 s32 loopID;
361 u8 op, arg1, arg2;
363
364 globals = manager->globals;
365 fadeVolChanged = false;
366 for (i = 0; i < 16U; i++) { // required to use unsigned literal
367 isVolumeChanged[i] = false;
368 isPitchChanged[i] = false;
369 }
370
371 if (player->resetRequired == true) {
373 player->resetRequired = false;
374 }
375
376 if (player->fadeTime != 0) {
377 player->fadeVolume += player->fadeStep;
378 player->fadeTime--;
379 if (player->fadeTime == 0) {
380 player->fadeVolume = player->fadeGoal << 24;
381 if (player->fadeSettingsType == MSEQ_FADE_IN) {
382 // do nothing
383 } else if (player->fadeSettingsType == MSEQ_FADE_OUT) {
384 player->mseqReadPos = BlankMseqData;
385 player->delay = 1;
386 } else if (player->fadeSettingsType == MSEQ_FADE_OUT_PAUSING) {
387 player->mode = MSEQ_MODE_PAUSING;
388 }
389 }
390 fadeVolChanged = true;
391 }
392
393 // update pitch
394 for (trackIdx = 0; trackIdx < ARRAY_COUNT(player->tracks); trackIdx++) {
395 track = &player->tracks[trackIdx];
396 if (track->tuneLerp.time != 0) {
398 if (track->tuneLerp.time != 0) {
399 track->tuneLerp.current += track->tuneLerp.step;
400 } else {
401 track->tuneLerp.current = track->tuneLerp.goal << 16;
402 }
403
404 voiceSelector = player->id.all + (trackIdx << 16);
405 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
406 voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
407 // update all voices belonging to current track
408 if ((voiceState->info.all & 0xFFFF0000) == voiceSelector) {
409 voice = &globals->voices[i];
410 if (voice->priority == manager->priority && trackIdx != TRACK_ID_DRUM) {
411 voice->pitchRatio = au_compute_pitch_ratio(voiceState->pitch + (track->tuneLerp.current >> 16)) * track->instrument->pitchRatio;
412 voice->syncFlags |= AU_VOICE_SYNC_FLAG_PITCH;
413 isPitchChanged[i - player->firstVoiceIdx] = true;
414 }
415 }
416 }
417 }
418 }
419
420 // update volume
421 for (trackIdx = 0; trackIdx < ARRAY_COUNT(player->tracks); trackIdx++) {
422 track = &player->tracks[trackIdx];
423 if (track->volumeLerp.time != 0) {
425 if (track->volumeLerp.time != 0) {
426 track->volumeLerp.current += track->volumeLerp.step;
427 } else {
428 track->volumeLerp.current = track->volumeLerp.goal << 16;
429 }
430
431 voiceSelector = player->id.all + (trackIdx << 16);
432 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
433 voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
434 // update all voices belonging to current track
435 if ((voiceState->info.all & 0xFFFF0000) == voiceSelector) {
436 voice = &globals->voices[i];
437 if (voice->priority == manager->priority) {
438 track = &player->tracks[voiceState->info.trackIndex];
439 voice->clientVolume = VOL_MULT_3(player->fadeVolume >> 24, track->volumeLerp.current >> 16, voiceState->volume);
440 voice->envelopeFlags |= AU_VOICE_ENV_FLAG_VOL_CHANGED;
441 }
442 }
443 }
444 }
445 }
446
447 player->delay--;
448 if (player->delay <= 0) {
449 while (player->delay == 0) {
450 op = au_mseq_read_next(player);
451 if ((s8)op >= 0) {
452 if (op == 0) {
453 // stop
454 player->mseqReadPos = nullptr;
455 player->mseqName = 0;
457 break;
458 }
459 if (op >= 0x78) {
460 // long delay
461 player->delay = ((op & 7) << 8) + au_mseq_read_next(player) + 0x78;
462 } else {
463 //short delay
464 player->delay = op;
465 }
466 continue;
467 }
468
469 // op >= 0x80
470 // op & 0xF0 : command
471 // op & 0xF : track index
472
473 arg1 = au_mseq_read_next(player);
474 trackIdx = op & 0xF;
475 track = &player->tracks[trackIdx];
476
477 switch (op & 0xF0) {
479 // arg1: sound index
480 if (player->playState == MSEQ_PLAYER_PLAYING) {
481 voiceSelector = player->id.all + (trackIdx << 16) + (arg1 << 8);
482 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
483 if (manager->voiceStates[i - player->firstVoiceIdx].info.all == voiceSelector) {
484 manager->voiceStates[i - player->firstVoiceIdx].info.released = true;
485 voice = &globals->voices[i];
486 if (voice->priority == manager->priority) {
488 }
489 }
490 }
491 }
492 break;
494 // arg1: pitch or drum sound id
495 // arg2: volume
496 arg2 = au_mseq_read_next(player);
497 if (player->playState == MSEQ_PLAYER_PLAYING) {
498 // find free voice
499 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
500 voice = &globals->voices[i];
501 if (voice->priority == AU_PRIORITY_FREE) {
502 break;
503 }
504 }
505 if (i >= player->lastVoiceIdx) {
506 // try stealing a voice from the current player (or one with the same priority)
507 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
508 voice = &globals->voices[i];
509 if (voice->priority == manager->priority) {
511 break;
512 }
513 }
514 }
515 if (i >= player->lastVoiceIdx) {
516 // try stealing a voice from a different player with a lower priority
517 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
518 voice = &globals->voices[i];
519 if (voice->priority < manager->priority) {
521 break;
522 }
523 }
524 }
525 if (i < player->lastVoiceIdx) {
526 isVolumeChanged[i - player->firstVoiceIdx] = true;
527 isPitchChanged[i - player->firstVoiceIdx] = true;
528 voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
529 // set playerIndex, trackIndex and tune
530 voiceState->info.all = player->id.all + (trackIdx << 16) + (arg1 << 8);
531 if (track->flags & MSEQ_TRACK_RESUMABLE) {
532 voiceState->isResumable = true;
533 } else {
534 voiceState->isResumable = false;
535 }
536 if (trackIdx != TRACK_ID_DRUM) {
537 if (track->flags & MSEQ_TRACK_RESUMABLE) {
538 voiceState->isResumable = true;
539 } else {
540 voiceState->isResumable = false;
541 }
542
543 voiceState->pitch = (arg1 & 0x7F) * 100 - track->instrument->keyBase;
544 voiceState->volume = arg2 & 0x7F;
545 voice->clientVolume = VOL_MULT_3(player->fadeVolume >> 24, track->volumeLerp.current >> 16, voiceState->volume);
546 voice->pitchRatio = au_compute_pitch_ratio(voiceState->pitch + (track->tuneLerp.current >> 16)) * track->instrument->pitchRatio;
547 voice->pan = track->pan;
548 voice->reverb = track->reverb;
549 voice->instrument = track->instrument;
550 voice->busID = manager->busID;
551 voice->envelope.cmdListPress = track->envelope.cmdListPress;
552 voice->envelope.cmdListRelease = track->envelope.cmdListRelease;
553 } else {
554 voiceState->isResumable = false;
555 drum = &manager->globals->dataPER->drums[arg1 & 0x7F];
556 bankPatch = drum->bankPatch;
557 voice->instrument = au_get_instrument(manager->globals, bankPatch >> 8, bankPatch & 0xFF, &voice->envelope);
558 voiceState->pitch = drum->keyBase - voice->instrument->keyBase;
559 voiceState->volume = VOL_MULT_2(arg2 & 0x7F, drum->volume);
560 voice->clientVolume = VOL_MULT_3(player->fadeVolume >> 24, track->volumeLerp.current >> 16, voiceState->volume);
561 voice->pitchRatio = au_compute_pitch_ratio(voiceState->pitch) * voice->instrument->pitchRatio;
562 voice->pan = drum->pan;
563 voice->reverb = drum->reverb;
564 voice->busID = manager->busID;
565 }
566 voice->syncFlags = AU_VOICE_SYNC_FLAG_ALL;
567 voice->priority = manager->priority;
568 voice->clientPriority = voice->priority;
569 }
570 }
571 break;
573 // higher bit: set pan (1) or volume (0)
574 // lower 7 bits: value
575 if (arg1 & 0x80) {
576 track->pan = arg1 & 0x7F;
577 voiceSelector = player->id.all + (trackIdx << 16);
578 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
579 voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
580 if ((voiceState->info.all & 0xFFFF0000) == voiceSelector) {
581 voice = &globals->voices[i];
582 if (voice->priority == manager->priority && trackIdx != TRACK_ID_DRUM) {
583 voice->pan = track->pan;
585 }
586 }
587 }
588 } else {
589 track->volumeLerp.current = arg1 << 24;
590 if (track->volumeLerp.current != 0) {
591 track->volumeLerp.current |= 0xFFFFFF;
592 }
593 voiceSelector = player->id.all + (trackIdx << 16);
594 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
595 voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
596 if ((voiceState->info.all & 0xFFFF0000) == voiceSelector) {
597 voice = &globals->voices[i];
598 if (voice->priority == manager->priority) {
599 voice->clientVolume = VOL_MULT_3(player->fadeVolume >> 24, track->volumeLerp.current >> 16, voiceState->volume);
600 if (!isVolumeChanged[i - player->firstVoiceIdx]) {
601 voice->envelopeFlags |= AU_VOICE_ENV_FLAG_VOL_CHANGED;
602 isVolumeChanged[i - player->firstVoiceIdx] = true;
603 }
604 }
605 }
606 }
607 }
608 break;
610 // arg1: sub command
611 // arg2: depends on sub command
612 arg2 = au_mseq_read_next(player);
613 switch (arg1) {
615 // arg2: loop id
616 player->loopStartPos[arg2 & 1] = player->mseqReadPos;
617 break;
619 // arg2 lower bit: loop id
620 // (arg2 & 0x7C) >> 2: loop count
621 loopID = arg2 & 1;
622 count = (arg2 & 0x7C) >> 2;
623 if (count != 0) {
624 if (player->loopCount[loopID] != 0) {
625 player->loopCount[loopID]--;
626 // if it's the last iteration then don't jump to the loop start
627 if (player->loopCount[loopID] != 0) {
628 player->mseqReadPos = player->loopStartPos[loopID];
629 }
630 } else {
631 // first iteration, set loop counter
632 player->mseqReadPos = player->loopStartPos[loopID];
633 player->loopCount[loopID] = count;
634 }
635 } else {
636 // infinite loop
637 player->mseqReadPos = player->loopStartPos[loopID];
638 player->loopCount[loopID] = 0;
639 }
640 break;
642 track->reverb = arg2;
643 break;
645 if (arg2 == 1) {
646 track->flags |= MSEQ_TRACK_RESUMABLE;
647 }
648 break;
649 }
650 break;
652 // arg1: bank
653 // arg2: patch
654 arg2 = au_mseq_read_next(player);
655 if (trackIdx != TRACK_ID_DRUM) {
656 track->instrument = au_get_instrument(manager->globals, arg1, arg2, &track->envelope);
657 }
658 break;
660 // arg1: coarse tune
661 // arg2: fine tune
662 track->tuneLerp.current = (arg1 << 24) + (au_mseq_read_next(player) << 16);
663 voiceSelector = player->id.all + (trackIdx << 16);
664 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
665 voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
666 if ((voiceState->info.all & 0xFFFF0000) == voiceSelector) {
667 voice = &globals->voices[i];
668 if (voice->priority == manager->priority && trackIdx != TRACK_ID_DRUM) {
669 voice->pitchRatio = au_compute_pitch_ratio(voiceState->pitch + (track->tuneLerp.current >> 16)) * track->instrument->pitchRatio;
670 voice->syncFlags |= AU_VOICE_SYNC_FLAG_PITCH;
671 isPitchChanged[i - player->firstVoiceIdx] = 1;
672 }
673 }
674 }
675 break;
676 case 0xF0: // required to match
677 break;
678 }
679 }
680 }
681 if (fadeVolChanged) {
682 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
683 voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
684 // update all voices belonging to this player
685 if ((voiceState->info.all & 0xFF000000) == player->id.all) {
686 voice = &globals->voices[i];
687 if (voice->priority == manager->priority && !isVolumeChanged[i - player->firstVoiceIdx]) {
688 track = &player->tracks[voiceState->info.trackIndex];
689 voice->clientVolume = VOL_MULT_3(player->fadeVolume >> 24, track->volumeLerp.current >> 16, voiceState->volume);
690 voice->envelopeFlags |= AU_VOICE_ENV_FLAG_VOL_CHANGED;
691 }
692 }
693 }
694 }
695}
696
698 u8 value = *state->mseqReadPos++;
699 return value;
700}
701
703 AuVoice* voice;
705 s32 i;
706
707 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
708 voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
709 if (voiceState->info.playerIndex == player->id.playerIndex) {
710 voice = &manager->globals->voices[i];
711 if (voice->priority == manager->priority) {
713 }
714 voiceState->info.all = 0;
715 }
716 }
717}
718
721 u32 numSaved = 0;
722 s32 i;
723
724 for (i = player->firstVoiceIdx; i < player->lastVoiceIdx; i++) {
725 AmbienceVoiceState* voiceState = &manager->voiceStates[i - player->firstVoiceIdx];
726
727 if (!voiceState->isResumable) {
728 continue;
729 }
730
731 savedVoice->trackIndex = voiceState->info.trackIndex;
732 savedVoice->tune = voiceState->info.tune;
733 savedVoice->volume = voiceState->volume;
734
735 savedVoice++;
736 numSaved++;
737 if (numSaved >= ARRAY_COUNT(player->savedVoices)) {
738 break;
739 }
740 }
741}
742
744 AuGlobals* globals;
745 AuVoice* voice;
749 u32 i, j;
750
751 globals = manager->globals;
752 if (player->playState == MSEQ_PLAYER_PLAYING) {
753 for (i = 0; i < ARRAY_COUNT(player->savedVoices); i++) {
754 savedVoice = &player->savedVoices[i];
755 if (savedVoice->tune != 0) {
756 track = &player->tracks[savedVoice->trackIndex];
757
758 // find first free voice
759 for (j = player->firstVoiceIdx; j < player->lastVoiceIdx; j++) {
760 voice = &globals->voices[j];
761 if (voice->priority == AU_PRIORITY_FREE) {
762 break;
763 }
764 }
765
766 // try stealing a voice with lower priority
767 if (j >= player->lastVoiceIdx) {
768 for (j = player->firstVoiceIdx; j < player->lastVoiceIdx; j++) {
769 voice = &globals->voices[j];
770 if (voice->priority < manager->priority) {
772 break;
773 }
774 }
775 }
776
777 if (j < player->lastVoiceIdx) {
778 voiceState = &manager->voiceStates[j - player->firstVoiceIdx];
779 voiceState->info.all = player->id.all + (savedVoice->trackIndex << 16) + (savedVoice->tune << 8);
780 voiceState->pitch = (savedVoice->tune & 0x7F) * 100 - track->instrument->keyBase;
781 voiceState->volume = savedVoice->volume & 0x7F;
782 voice->clientVolume = VOL_MULT_3(player->fadeVolume >> 24, track->volumeLerp.current >> 16, voiceState->volume);
783 voice->pitchRatio = au_compute_pitch_ratio(voiceState->pitch + (track->tuneLerp.current >> 16)) * track->instrument->pitchRatio;
784 voice->pan = track->pan;
785 voice->reverb = track->reverb;
786 voice->instrument = track->instrument;
787 voice->busID = manager->busID;
788 voice->envelope.cmdListPress = track->envelope.cmdListPress;
789 voice->envelope.cmdListRelease = track->envelope.cmdListRelease;
790 voice->syncFlags = AU_VOICE_SYNC_FLAG_ALL;
791 voice->priority = manager->priority;
792 voice->clientPriority = voice->priority;
793 }
794 }
795 savedVoice->trackIndex = 0;
796 savedVoice->tune = 0;
797 savedVoice->volume = 0;
798 }
799 }
800}
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:397
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:410
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:506
void au_memset(void *dst, s32 size, u8 value)
Definition engine.c:1224
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:39