Alchemy
Loading...
Searching...
No Matches

engine.c

Go to the documentation of this file.
1#include "audio_engine.h"
2#include "types.h"
4
5/// Detaches a note through the command table entry installed by the driver.
6/// Called by the song player (MusicPlayer_Tick, MusicTrack_HandleNote).
8 // Taking the entry address folds its slot into a literal address. Direct
9 // indexing adds an address-adjustment instruction with the library compiler.
10 void (*detachNote)(struct SoundNote *) =
11 SOUND_COMMAND_CAST(void (*)(struct SoundNote *),
13
14 detachNote(note);
15}
16
17/// Clears a 64-byte player or track prefix through the driver command table.
18/// Called by the song player and MusicPlayer_ResetActiveTracks.
19void AudioCommand_InvokeSlot35(void *block) {
20 void (*clearWork)(void *) = SOUND_COMMAND_CAST(
21 void (*)(void *), *(&gSound_CommandTable[SOUND_COMMAND_CLEAR_WORK]));
22
23 clearWork(block);
24}
25
26s32 __divsi3(s32 numerator, s32 denominator);
28void MusicTrack_HandleNote(u32 command, struct SoundPlayer *player,
29 struct SoundTrack *track);
30void Audio_EmptyCallback(void);
34extern const u16 gSound_FrameLengths[];
36
37void MusicPlayer_Tick(struct SoundPlayer *player);
38void MusicTrack_Stop(struct SoundPlayer *player, struct SoundTrack *track);
39void AudioEngine_SetMode(u32 mode);
40
41struct SoundPlayer;
42
43extern const u8 gSound_CgbPitchCodes[];
44extern const s16 gSound_CgbFrequencySteps[];
45extern const u8 gSound_NoisePitchCodes[];
46
47void CgbChannel_Mute(u8 channel);
48
49extern const u8 gSound_Cgb3LevelCodes[];
50
51/// The PCM buffer's size in samples, a multiple of every frame length: the DMA
52/// plays it round and round.
53#define SOUND_PCM_BUFFER_SIZE 0x630
54/// The display's frame rate in ten-thousandths of a hertz: 59.7275 frames a
55/// second.
56#define SOUND_FRAME_RATE_E4 597275
57/// CPU cycles in a frame: 228 lines of 1232 cycles.
58#define SOUND_CYCLES_PER_FRAME (228 * 1232)
59
60/// Resets the sound hardware, clears the whole sound work block and installs
61/// the default PCM driver: stores `work` in SOUND_WORK, points the FIFO DMAs at
62/// its two buffers, fills in the driver callbacks and command table, sets the
63/// default rate and finally sets the work's lock. Called by Audio_Initialize.
65 u32 zero;
66
67 // Stop repeat transfers before configuring the stereo FIFO outputs.
68 work->lock = 0;
69 if (REG_DMA1CNT & (DMA_REPEAT << 16))
71 if (REG_DMA2CNT & (DMA_REPEAT << 16))
79 REG_SOUNDBIAS_H = (REG_SOUNDBIAS_H & 0x3F) | 0x40;
80 REG_DMA1SAD = (u32)work->buffers[0];
82 REG_DMA2SAD = (u32)work->buffers[1];
84 // Clear the complete work block, then install the PCM driver entries.
85 SOUND_WORK = work;
86 zero = 0;
87 Bios_CpuSet(&zero, work, CPU_SET_SRC_FIXED | CPU_SET_32BIT | 0x3EC);
88 work->pcmNoteCount = 8;
89 work->volume = 15;
92 work->cgbMute = (void (*)(u8))Audio_EmptyCallback;
98 work->lock = SOUND_LOCK;
99}
100
101/// Sets the PCM frame length (`mode` bits 16 to 19 pick a gSound_FrameLengths
102/// entry) and the rates derived from it, and Timer 0's reload, starting
103/// playback at scanline 159. Called by AudioEngine_Initialize and
104/// AudioEngine_SetMode, and by songs through the command table.
106 struct SoundWork *work = SOUND_WORK;
108 volatile u16 *timer;
109
110 // Convert the selected frame length into mixer and timer increments.
111 mode = (mode & 0xF0000) >> 16;
112 work->rate = mode;
115 // Frames the DMA plays before the buffer wraps, and the sample rate in hertz
116 // (rounded), and half its reciprocal in 24-bit fixed point
118 work->outputRate = __divsi3(SOUND_FRAME_RATE_E4 * frameSamples + 5000, 10000);
119 work->rateStep = (__divsi3(0x1000000, work->outputRate) + 1) >> 1;
120 // Timer 0 counts the CPU cycles of one sample: it overflows, and the FIFOs
121 // take their next sample, frameSamples times a frame. It starts at scanline
122 // 159 after the FIFO transfers restart.
123 REG_TM0CNT_H = 0;
124 timer = &REG_TM0CNT_L;
127 while (*(volatile u8 *)&REG_VCOUNT == 159)
128 ;
129 while (*(volatile u8 *)&REG_VCOUNT != 159)
130 ;
132}
133
134/// Applies the reverb, channel-count, volume, bias and sample-rate fields of
135/// `mode` to the sound work, under its lock. Called by Audio_Initialize.
137 struct SoundWork *work = SOUND_WORK;
138 u32 modeField;
139 struct SoundNote *note;
140
141 if (work->lock != SOUND_LOCK)
142 return;
143 work->lock++;
144
145 // A zero field leaves the corresponding setting unchanged.
146 modeField = mode & 0xFF;
147 if (modeField != 0)
148 work->reverb = modeField & 0x7F;
149 modeField = mode & 0xF00;
150 if (modeField != 0) {
151 work->pcmNoteCount = modeField >> 8;
152 modeField = SOUND_PCM_NOTE_CAPACITY;
153 note = work->pcmNotes;
154 do {
155 note->state = 0;
156 modeField--;
157 note++;
158 } while (modeField != 0);
159 }
160 modeField = mode & 0xF000;
161 if (modeField != 0)
162 work->volume = modeField >> 12;
163 modeField = mode & 0xB00000;
164 if (modeField != 0) {
165 modeField = (modeField & 0x300000) >> 14;
166 REG_SOUNDBIAS_H = (REG_SOUNDBIAS_H & 0x3F) | modeField;
167 }
168 modeField = mode & 0xF0000;
169 if (modeField != 0) {
171 AudioEngine_SetPcmRate(modeField);
172 }
173 work->lock = SOUND_LOCK;
174}
175
176/// Silences every PCM and CGB note while holding the sound work lock. Nothing
177/// in ☀️ calls it.
179 // Splitting the counter or typed iterators changes the native EN registers.
180 struct SoundWork *work = SOUND_WORK;
181 s32 channelCounter;
182 void *channel;
183
184 if (work->lock != SOUND_LOCK)
185 return;
186 work->lock++;
187
188 // Clear every PCM slot, including slots beyond the active note count.
189 channelCounter = SOUND_PCM_NOTE_CAPACITY;
190 channel = work->pcmNotes;
191 while (channelCounter > 0) {
192 ((struct SoundNote *)channel)->state = 0;
193 channelCounter--;
194 channel = (void *)((s32)channel + sizeof(struct SoundNote));
195 }
196 // Reuse the counter as the hardware channel number for the CGB path.
197 channel = work->cgbNotes;
198 if (channel != NULL) {
199 channelCounter = 1;
200 while (channelCounter <= SOUND_CGB_CHANNEL_COUNT) {
201 work->cgbMute(channelCounter);
202 ((struct CgbNote *)channel)->state = 0;
203 channelCounter++;
204 channel = (void *)((s32)channel + sizeof(struct CgbNote));
205 }
206 }
207 work->lock = SOUND_LOCK;
208}
209
210/// Stops both FIFO transfers and clears their sample buffers, raising the
211/// work's lock until AudioEngine_ResumeDirectSound. Called by
212/// AudioEngine_SetMode around a rate change.
214 struct SoundWork *work = SOUND_WORK;
215 u32 zero;
216
217 if (work->lock - SOUND_LOCK > 1)
218 return;
219 work->lock += 10;
220 if (REG_DMA1CNT & (DMA_REPEAT << 16))
222 if (REG_DMA2CNT & (DMA_REPEAT << 16))
226 zero = 0;
227 Bios_CpuSet(&zero, work->buffers, CPU_SET_SRC_FIXED | CPU_SET_32BIT | 0x318);
228}
229
230/// Restarts both FIFO transfers and releases the suspended-work lock. Called
231/// by AudioEngine_SetPcmRate.
233 struct SoundWork *work = SOUND_WORK;
234 u32 lock = work->lock;
235
236 if (lock == SOUND_LOCK)
237 return;
240 work->transferCountdown = 0;
241 work->lock = lock - 10;
242}
243
244/// Deactivates up to sixteen tracks and links the player into the mixer tick
245/// chain.
247 struct SoundTrack *tracks, u8 trackCount) {
248 struct SoundWork *work;
249
250 if (trackCount == 0)
251 return;
252 if (trackCount > SOUND_PLAYER_TRACK_LIMIT)
253 trackCount = SOUND_PLAYER_TRACK_LIMIT;
254 work = SOUND_WORK;
255 if (work->lock != SOUND_LOCK)
256 return;
257 work->lock++;
258
259 // Clear the player record and deactivate the supplied track slots.
261 player->tracks = tracks;
262 player->trackCount = trackCount;
263 player->status = SOUND_PLAYER_PAUSED;
264 while (trackCount != 0) {
265 tracks->flags = 0;
266 trackCount--;
267 tracks++;
268 }
269 // Prepend this player to the existing mixer tick chain.
270 if (work->tick != NULL) {
271 player->nextTick = work->tick;
272 player->nextTickPlayer = work->tickPlayer;
273 work->tick = NULL;
274 }
275 work->tickPlayer = player;
276 work->tick = MusicPlayer_Tick;
277 work->lock = SOUND_LOCK;
278 player->lock = SOUND_LOCK;
279}
280
281/// Starts a song when its priority permits, resetting its tracks and tempo.
283 const struct SequenceHeader *header) {
284 s32 trackIndex;
285 struct SoundTrack *track;
286
287 if (player->lock != SOUND_LOCK)
288 return;
289
290 // Preserve a higher-priority song unless the player is idle.
291 if (player->checkPriority != 0) {
292 if (player->header == NULL ||
293 !(player->tracks[0].flags & SOUND_TRACK_RESET)) {
294 if ((player->status & 0xFFFF) == 0 ||
295 (player->status & SOUND_PLAYER_PAUSED))
296 goto start;
297 }
298 if (player->priority > header->priority)
299 return;
300 }
301start:
302 player->lock++;
303 // Reset song timing and fade state before assigning track streams.
304 player->status = 0;
305 player->header = header;
306 player->voices = header->voices;
307 player->priority = header->priority;
308 player->ticks = 0;
309 player->tempo = 150;
310 player->tempoStep = 150;
311 player->tempoScale = 256;
312 player->tempoCount = 0;
313 player->fadePeriod = 0;
314
315 trackIndex = 0;
316 track = player->tracks;
317 while (trackIndex < header->trackCount && trackIndex < player->trackCount) {
318 MusicTrack_Stop(player, track);
320 track->notes = NULL;
321 track->cursor = header->tracks[trackIndex];
322 trackIndex++;
323 track++;
324 }
325 // Stop leftover slots that the new song does not use.
326 while (trackIndex < player->trackCount) {
327 MusicTrack_Stop(player, track);
328 track->flags = 0;
329 trackIndex++;
330 track++;
331 }
332 if (header->mode & 0x80)
333 AudioEngine_SetMode(header->mode);
334 player->lock = SOUND_LOCK;
335}
336
337/// Pauses this player and stops all of its tracks, under the player's lock.
338/// Called by Audio_StopSound and Audio_StopAllPlayers.
339void MusicPlayer_Stop(struct SoundPlayer *player) {
340 s32 tracksRemaining;
341 struct SoundTrack *track;
342
343 if (player->lock != SOUND_LOCK)
344 return;
345 player->lock++;
346 player->status |= SOUND_PLAYER_PAUSED;
347 tracksRemaining = player->trackCount;
348 track = player->tracks;
349 while (tracksRemaining > 0) {
350 MusicTrack_Stop(player, track);
351 tracksRemaining--;
352 track++;
353 }
354 player->lock = SOUND_LOCK;
355}
356
357/// Advances a due fade step, updating active track volumes, or at the end of a
358/// fade out stops (or pauses) the player. Called by the song player each tick
359/// through the command table.
360void MusicPlayer_StepFade(struct SoundPlayer *player) {
361 s32 tracksRemaining;
362 struct SoundTrack *track;
363
364 if (player->fadePeriod == 0)
365 return;
366 if (--player->fadeCounter != 0)
367 return;
368 player->fadeCounter = player->fadePeriod;
369
370 // Advance the volume while retaining its low-bit fade flags.
371 if (player->fadeVolume & SOUND_FADE_IN) {
374 player->fadePeriod = 0;
375 }
376 } else {
377 if ((s16)(player->fadeVolume -= SOUND_FADE_STEP) <= 0) {
378 tracksRemaining = player->trackCount;
379 track = player->tracks;
380 while (tracksRemaining > 0) {
381 MusicTrack_Stop(player, track);
382 if (!(player->fadeVolume & SOUND_FADE_PAUSE))
383 track->flags = 0;
384 tracksRemaining--;
385 track++;
386 }
387 if (player->fadeVolume & SOUND_FADE_PAUSE)
388 player->status |= SOUND_PLAYER_PAUSED;
389 else
390 player->status = SOUND_PLAYER_PAUSED;
391 player->fadePeriod = 0;
392 return;
393 }
394 }
395
396 // Propagate the new level to each active track.
397 tracksRemaining = player->trackCount;
398 track = player->tracks;
399 while (tracksRemaining > 0) {
400 if (track->flags & SOUND_TRACK_ACTIVE) {
401 track->volumeScale = player->fadeVolume >> 2;
403 }
404 tracksRemaining--;
405 track++;
406 }
407}
408
409/// Recalculates dirty stereo volumes and pitch from track settings and
410/// modulation.
412 struct SoundTrack *track) {
413 u32 volume;
414 s32 pan;
415 s32 pitch;
416 s32 bend;
417
418 // Mix the volume modulation and clamped stereo pan.
419 if (track->flags & SOUND_TRACK_VOLUME_DIRTY) {
420 volume = (u32)(track->volume * track->volumeScale) >> 5;
422 volume = ((track->modAmount + 128) * volume) >> 7;
423 pan = track->pan * 2 + track->panOffset;
424 if (track->modTarget == SOUND_MODULATION_PAN)
425 pan += track->modAmount;
426 if (pan < -128)
427 pan = -128;
428 else if (pan > 127)
429 pan = 127;
430 track->outVolumeA = ((pan + 128) * volume) >> 8;
431 track->outVolumeB = ((127 - pan) * volume) >> 8;
432 }
433 // Signed semitone offsets are scaled by multiplication, including negatives.
434 if (track->flags & SOUND_TRACK_PITCH_DIRTY) {
435 bend = track->bend * track->bendRange;
436 pitch = (track->tune + bend) * 4 + (track->keyOffsetA * 256) +
437 (track->keyOffsetB * 256) + track->fine;
438 if (track->modTarget == SOUND_MODULATION_PITCH)
439 pitch += track->modAmount * 16;
440 track->pitchHi = pitch >> 8;
441 track->pitchLo = pitch;
442 }
444}
445
446/// Converts a key and fractional pitch to a CGB tone or noise-register value.
447/// Installed as the work's cgbFrequency callback by CgbAudio_Initialize.
449 s32 lowerFrequency;
450 s32 upperFrequency;
451
452 if (kind == 4) {
453 if (key <= 20)
454 key = 0;
455 else {
456 key -= 21;
457 if (key > 59)
458 key = 59;
459 }
460 return gSound_NoisePitchCodes[key];
461 }
462
463 if (key <= 35) {
464 fine = 0;
465 key = 0;
466 } else {
467 key -= 36;
468 if (key > 130) {
469 key = 130;
470 fine = 255;
471 }
472 }
473 lowerFrequency = gSound_CgbPitchCodes[key];
474 lowerFrequency =
475 gSound_CgbFrequencySteps[lowerFrequency & 15] >> (lowerFrequency >> 4);
476 upperFrequency = gSound_CgbPitchCodes[key + 1];
477 upperFrequency =
478 gSound_CgbFrequencySteps[upperFrequency & 15] >> (upperFrequency >> 4);
479 return lowerFrequency + ((fine * (upperFrequency - lowerFrequency)) >> 8) +
480 2048;
481}
482
483/// Disables one CGB channel using its envelope or wave-control register.
484/// Called by Cgb_UpdateChannels, and installed as the work's cgbMute callback.
485void CgbChannel_Mute(u8 channel) {
486 switch (channel) {
487 case 1:
488 REG_NR12 = 8;
489 REG_NR14 = 0x80;
490 break;
491 case 2:
492 REG_NR22 = 8;
493 REG_NR24 = 0x80;
494 break;
495 case 3:
496 REG_NR30 = 0;
497 break;
498 default:
499 REG_NR42 = 8;
500 REG_NR44 = 0x80;
501 break;
502 }
503}
504
505/// Chooses stereo routing and derives peak and sustain levels for a CGB note,
506/// writing them into `note`. Called by Cgb_UpdateChannels. Its separate peak
507/// calculations and jumps are the form the bytes show: shared, tbs-en is four
508/// bytes shorter.
510 u32 right = note->outRight;
511 u32 left = note->outLeft;
512
513 if ((u8)right >= (u8)left) {
514 if ((u8)right / 2 >= (u8)left) {
515 note->panBits = 0x0F;
516 goto one_side;
517 }
518 } else if ((u8)left / 2 >= (u8)right) {
519 note->panBits = 0xF0;
520 goto one_side;
521 }
522 note->panBits = 0xFF;
523 note->peak = (u32)(note->outRight + note->outLeft) >> 4;
524 goto scale;
525one_side:
526 note->peak = (u32)(note->outRight + note->outLeft) >> 4;
527 if (note->peak > 15)
528 note->peak = 15;
529scale:
530 note->sustainLevel = (note->peak * note->sustain + 15) >> 4;
531 note->panBits &= note->channelBits;
532}
533
534/// Steps CGB note envelopes and writes changed pitch, volume and trigger
535/// registers, once a frame. Installed as the work's cgbUpdate callback by
536/// CgbAudio_Initialize; the mixer calls it.
538 s32 channel;
539 s32 extraEnvelopeTick;
540 struct SoundWork *work = SOUND_WORK;
541 struct CgbNote *note;
542 volatile u8 *sweepOrWaveControl;
543 volatile u8 *lengthDutyRegister;
544 volatile u8 *volumeEnvelopeRegister;
545 volatile u8 *frequencyOrNoiseRegister;
546 volatile u8 *triggerRegister;
547 s32 envelopeControl;
548 u32 byteMask = 0xff;
549
550 // Periodically compensate with a second software envelope step.
551 if (work->cgbTick)
552 work->cgbTick--;
553 else
554 work->cgbTick = 14;
555
556 for (channel = 1, note = work->cgbNotes; channel <= SOUND_CGB_CHANNEL_COUNT;
557 channel++, note++) {
558 if (!(note->state & CGB_NOTE_ON))
559 continue;
560
561 // Select this channel's sweep, length, envelope and frequency registers.
562 switch (channel) {
563 case 1:
564 sweepOrWaveControl = &REG_NR10;
565 lengthDutyRegister = &REG_NR11;
566 volumeEnvelopeRegister = &REG_NR12;
567 frequencyOrNoiseRegister = &REG_NR13;
568 triggerRegister = &REG_NR14;
569 break;
570 case 2:
571 sweepOrWaveControl = &REG_NR10 + 1;
572 lengthDutyRegister = &REG_NR21;
573 volumeEnvelopeRegister = &REG_NR22;
574 frequencyOrNoiseRegister = &REG_NR23;
575 triggerRegister = &REG_NR24;
576 break;
577 case 3:
578 sweepOrWaveControl = &REG_NR30;
579 lengthDutyRegister = &REG_NR31;
580 volumeEnvelopeRegister = &REG_NR32;
581 frequencyOrNoiseRegister = &REG_NR33;
582 triggerRegister = &REG_NR34;
583 break;
584 default:
585 sweepOrWaveControl = &REG_NR30 + 1;
586 lengthDutyRegister = &REG_NR41;
587 volumeEnvelopeRegister = &REG_NR42;
588 frequencyOrNoiseRegister = &REG_NR43;
589 triggerRegister = &REG_NR44;
590 break;
591 }
592
593 extraEnvelopeTick = work->cgbTick;
594 envelopeControl = *volumeEnvelopeRegister;
595
596 // A new note initializes its waveform and enters the attack phase.
597 if (note->state & CGB_NOTE_START) {
598 if (!(note->state & CGB_NOTE_STOP)) {
599 note->state = CGB_PHASE_ATTACK;
602 switch (channel) {
603 case 1:
604 *sweepOrWaveControl = note->sweep;
605 // Fall through.
606 case 2:
607 *lengthDutyRegister = ((u32)note->wave << 6) + note->length;
608 goto init_envelope;
609 case 3:
610 // A new wave: NR30 bit 6 selects the bank the CPU writes, then 0
611 // plays it
612 if (note->wave != note->loadedWave) {
613 *sweepOrWaveControl = 0x40;
614 REG_WAVE_RAM[0] = note->wave[0];
615 REG_WAVE_RAM[1] = note->wave[1];
616 REG_WAVE_RAM[2] = note->wave[2];
617 REG_WAVE_RAM[3] = note->wave[3];
618 note->loadedWave = note->wave;
619 }
620 *sweepOrWaveControl = 0;
621 *lengthDutyRegister = note->length;
622 // The trigger byte: 0x80 restarts the channel, 0x40 lets its length
623 // counter stop it
624 if (note->length)
625 note->trigger = 0xc0;
626 else
627 note->trigger = 0x80;
628 break;
629 default:
630 *lengthDutyRegister = note->length;
631 *frequencyOrNoiseRegister = (u32)note->wave << 3;
632 init_envelope:
633 // Envelope bit 3 counts the volume up, at the attack's step time
634 envelopeControl = note->attack + 8;
635 if (note->length)
636 note->trigger = 0x40;
637 else
638 note->trigger = 0;
639 break;
640 }
641 note->counter = note->attack;
642 if ((s8)(note->counter & byteMask)) {
643 note->level = 0;
644 goto count_down;
645 }
646 goto decay;
647 }
648 goto off;
649 // Tail notes expire; stopped notes enter release before their tail.
650 } else if (note->state & CGB_NOTE_ECHO) {
651 note->echoLength--;
652 if ((s8)(note->echoLength & byteMask) > 0)
653 goto write;
654 off:
655 CgbChannel_Mute(channel);
656 note->state = 0;
657 goto done;
658 } else if ((note->state & CGB_NOTE_STOP) &&
659 (note->state & CGB_NOTE_PHASE)) {
660 note->state &= ~CGB_NOTE_PHASE;
661 note->counter = note->release;
662 if ((s8)(note->counter & byteMask)) {
664 if (channel != 3)
665 envelopeControl = note->release;
666 goto count_down;
667 }
668 goto echo;
669 } else {
670 // Attack, decay, sustain and release share this countdown path.
671 step:
672 if (note->counter == 0) {
673 if (channel == 3)
676 if ((note->state & CGB_NOTE_PHASE) == CGB_PHASE_RELEASE) {
677 note->level--;
678 if ((s8)(note->level & byteMask) <= 0) {
679 echo:
680 note->level = ((note->peak * note->echoLevel) + 0xff) >> 8;
681 if (note->level) {
682 note->state |= CGB_NOTE_ECHO;
684 if (channel != 3)
685 envelopeControl = 8;
686 goto write;
687 }
688 goto off;
689 }
690 note->counter = note->release;
691 } else if ((note->state & CGB_NOTE_PHASE) == CGB_PHASE_SUSTAIN) {
692 sustain:
693 note->level = note->sustainLevel;
694 note->counter = 7;
695 } else if ((note->state & CGB_NOTE_PHASE) == CGB_PHASE_DECAY) {
696 note->level--;
697 if ((s8)(note->level & byteMask) <= (s8)note->sustainLevel) {
698 sustain_or_release:
699 if (note->sustain == 0) {
700 note->state &= ~CGB_NOTE_PHASE;
701 goto echo;
702 }
703 note->state--;
705 if (channel != 3)
706 envelopeControl = 8;
707 goto sustain;
708 }
709 note->counter = note->decay;
710 } else {
711 note->level++;
712 if ((u8)(note->level & byteMask) >= note->peak) {
713 decay:
714 note->state--;
715 note->counter = note->decay;
716 if ((s8)(note->counter & byteMask) == 0)
717 goto sustain_or_release;
719 note->level = note->peak;
720 if (channel != 3)
721 envelopeControl = note->decay;
722 } else {
723 note->counter = note->attack;
724 }
725 }
726 }
727 count_down:
728 note->counter--;
729 if (extraEnvelopeTick == 0) {
730 extraEnvelopeTick--;
731 goto step;
732 }
733 }
734
735 // Only changed pitch and volume settings reach the hardware.
736 write:
737 if (note->modified & CGB_NOTE_PITCH_DIRTY) {
738 if (channel < 4 && (note->kind & 8)) {
739 s32 bias = REG_SOUNDBIAS_H;
740
741 // SOUNDBIAS's resolution (bits 6 and 7): at 0 or 1 the frequency
742 // is rounded to a multiple of 4 or 2
743
744 if (bias < 0x40)
745 note->frequency = (note->frequency + 2) & 0x7fc;
746 else if (bias < 0x80)
747 note->frequency = (note->frequency + 1) & 0x7fe;
748 }
749 if (channel != 4)
750 *frequencyOrNoiseRegister = note->frequency;
751 else
752 *frequencyOrNoiseRegister =
753 (*frequencyOrNoiseRegister & 8) | note->frequency;
754 // The frequency's top three bits go in the trigger register's low bits
755 note->trigger = (note->trigger & 0xc0) + *((u8 *)&note->frequency + 1);
756 *triggerRegister = (s8)(note->trigger & byteMask);
757 }
758
759 if (note->modified & CGB_NOTE_VOLUME_DIRTY) {
760 // NR51 routes each channel to the left and right speakers
761 REG_NR51 = (REG_NR51 & ~note->channelBits) | note->panBits;
762 if (channel == 3) {
763 // Channel 3 has no envelope: its level maps to an NR32 volume code
764 *volumeEnvelopeRegister = gSound_Cgb3LevelCodes[note->level];
765 if (note->trigger & 0x80) {
766 *sweepOrWaveControl = 0x80;
767 *triggerRegister = note->trigger;
768 note->trigger &= 0x7f;
769 }
770 } else {
771 // NRx2: the starting volume in the high nibble, the envelope below
772 envelopeControl &= 0xf;
773 *volumeEnvelopeRegister = (note->level << 4) + envelopeControl;
774 *triggerRegister = note->trigger | 0x80;
775 if (channel == 1 && !(*sweepOrWaveControl & 8))
776 *triggerRegister = note->trigger | 0x80;
777 }
778 }
779
780 done:
781 note->modified = 0;
782 }
783}
784
785/// Sets the tempo multiplier and updates the number of ticks advanced per
786/// frame.
788 u16 scale) {
789 if (player->lock == SOUND_LOCK) {
790 player->lock++;
791 player->tempoScale = scale;
792 player->tempoStep = (player->tempo * player->tempoScale) >> 8;
793 player->lock = SOUND_LOCK;
794 }
795}
796
797/// Sets the volume scale of active tracks selected by the bit mask and marks
798/// their output for recalculation. Called by the music layer's volume ramps
799/// and commands (sound.c).
800void MusicPlayer_SetVolume(struct SoundPlayer *player, u16 mask, u16 volume) {
801 s32 tracksRemaining;
802 struct SoundTrack *track;
803 u32 trackBit;
804
805 if (player->lock != SOUND_LOCK)
806 return;
807 player->lock++;
808 tracksRemaining = player->trackCount;
809 track = player->tracks;
810 trackBit = 1;
811 while (tracksRemaining > 0) {
812 if (mask & trackBit) {
813 if (track->flags & SOUND_TRACK_ACTIVE) {
814 track->volumeScale = volume >> 2;
816 }
817 }
818 tracksRemaining--;
819 track++;
820 trackBit <<= 1;
821 }
822 player->lock = SOUND_LOCK;
823}
824
825/// Sets the semitone and fractional pitch offsets of selected active tracks
826/// and marks their pitch for recalculation. Called by the music layer's pitch
827/// ramps and commands (sound.c).
828void MusicPlayer_SetPitch(struct SoundPlayer *player, u16 mask, s16 pitch) {
829 s32 tracksRemaining;
830 struct SoundTrack *track;
831 u32 trackBit;
832
833 if (player->lock != SOUND_LOCK)
834 return;
835 player->lock++;
836 tracksRemaining = player->trackCount;
837 track = player->tracks;
838 trackBit = 1;
839 while (tracksRemaining > 0) {
840 if (mask & trackBit) {
841 if (track->flags & SOUND_TRACK_ACTIVE) {
842 track->keyOffsetB = pitch >> 8;
843 track->fine = pitch;
845 }
846 }
847 tracksRemaining--;
848 track++;
849 trackBit <<= 1;
850 }
851 player->lock = SOUND_LOCK;
852}
853
854/// Sets the stereo pan offset of selected active tracks. Nothing in ☀️ calls
855/// it.
856UNUSED void MusicPlayer_SetPan(struct SoundPlayer *player, u16 mask, s8 pan) {
857 s32 tracksRemaining;
858 struct SoundTrack *track;
859 u32 trackBit;
860
861 if (player->lock != SOUND_LOCK)
862 return;
863 player->lock++;
864 tracksRemaining = player->trackCount;
865 track = player->tracks;
866 trackBit = 1;
867 while (tracksRemaining > 0) {
868 if (mask & trackBit) {
869 if (track->flags & SOUND_TRACK_ACTIVE) {
870 track->panOffset = pan;
872 }
873 }
874 tracksRemaining--;
875 track++;
876 trackBit <<= 1;
877 }
878 player->lock = SOUND_LOCK;
879}
880
881/// Resets the LFO phase and amount, marking the affected output for
882/// recalculation.
884 track->lfoPhase = 0;
885 track->modAmount = 0;
886 if (track->modTarget == SOUND_MODULATION_PITCH)
888 else
890}
891
892/// Sets modulation depth on selected active tracks, resetting zero-depth
893/// modulation.
895 s32 selectedTracks, s32 depthArgument) {
896 u16 mask = selectedTracks;
897 u8 depth = depthArgument;
898 s32 tracksRemaining;
899 struct SoundTrack *track;
900 u32 trackBit;
901
902 if (player->lock != SOUND_LOCK)
903 return;
904
905 player->lock++;
906 tracksRemaining = player->trackCount;
907 track = player->tracks;
908 trackBit = 1;
909 while (tracksRemaining > 0) {
910 if (mask & trackBit) {
911 if (track->flags & SOUND_TRACK_ACTIVE) {
912 track->modDepth = depth;
913 if (!track->modDepth)
915 }
916 }
917 tracksRemaining--;
918 track++;
919 trackBit <<= 1;
920 }
921 player->lock = SOUND_LOCK;
922}
923
924/// Sets LFO speed on selected active tracks, resetting modulation when stopped.
925void MusicPlayer_SetLfoSpeed(struct SoundPlayer *player, u32 selectedTracks,
926 u32 speedArgument) {
927 u16 mask = selectedTracks;
928 u8 speed = speedArgument;
929 s32 tracksRemaining;
930 struct SoundTrack *track;
931 u32 trackBit;
932
933 if (player->lock != SOUND_LOCK)
934 return;
935
936 player->lock++;
937 tracksRemaining = player->trackCount;
938 track = player->tracks;
939 trackBit = 1;
940 while (tracksRemaining > 0) {
941 if (mask & trackBit) {
942 if (track->flags & SOUND_TRACK_ACTIVE) {
943 track->lfoSpeed = speed;
944 if (!track->lfoSpeed)
946 }
947 }
948 tracksRemaining--;
949 track++;
950 trackBit <<= 1;
951 }
952 player->lock = SOUND_LOCK;
953}
954
955/// Executes a work-byte operation and consumes a branch address for
956/// comparisons.
958 struct SoundTrack *track) {
959 u32 operation;
960 u8 *workByte;
961 u8 operand;
962
963 operation = *track->cursor;
964 track->cursor++;
965 workByte = player->workBytes + *track->cursor;
966 track->cursor++;
967 operand = *track->cursor;
968 track->cursor++;
969
970 switch (operation) {
971 case SOUND_WORK_SET:
972 *workByte = operand;
973 return;
974 case SOUND_WORK_ADD:
975 *workByte += operand;
976 return;
978 *workByte -= operand;
979 return;
980 case SOUND_WORK_COPY:
981 *workByte = player->workBytes[operand];
982 return;
984 *workByte += player->workBytes[operand];
985 return;
987 *workByte -= player->workBytes[operand];
988 return;
989 case SOUND_WORK_EQUAL:
990 if (*workByte == operand)
991 goto jump;
992 goto skip;
994 if (*workByte != operand)
995 goto jump;
996 goto skip;
998 if (*workByte > operand)
999 goto jump;
1000 goto skip;
1002 if (*workByte >= operand)
1003 goto jump;
1004 goto skip;
1006 if (*workByte <= operand)
1007 goto jump;
1008 goto skip;
1009 case SOUND_WORK_LESS:
1010 if (*workByte < operand)
1011 goto jump;
1012 goto skip;
1014 if (*workByte == player->workBytes[operand])
1015 goto jump;
1016 goto skip;
1018 if (*workByte != player->workBytes[operand])
1019 goto jump;
1020 goto skip;
1022 if (*workByte > player->workBytes[operand])
1023 goto jump;
1024 goto skip;
1026 if (*workByte >= player->workBytes[operand])
1027 goto jump;
1028 goto skip;
1030 if (*workByte <= player->workBytes[operand])
1031 goto jump;
1032 goto skip;
1034 if (*workByte < player->workBytes[operand])
1035 goto jump;
1036 goto skip;
1037 default:
1038 return;
1039 }
1040
1041jump:
1042 (*(&gSound_CommandTable[SOUND_COMMAND_GOTO]))(player, track);
1043 return;
1044skip:
1045 track->cursor += 4;
1046}
1047
1048/// Reads an extended-command index and invokes its handler.
1050 struct SoundTrack *track) {
1051 s32 command;
1052
1053 command = *track->cursor;
1054 track->cursor++;
1055 gSound_ExtendedCommandTable[command](player, track);
1056}
1057
1058/// A word put together from its four bytes, lowest first.
1061 struct {
1062 u32 byte0 : 8;
1063 u32 byte1 : 8;
1064 u32 byte2 : 8;
1065 u32 byte3 : 8;
1067};
1068
1069/// Finishes a track through the base command table entry.
1071 struct SoundTrack *track) {
1073
1074 finishSequence(player, track);
1075}
1076
1077/// Reads an unaligned little-endian voice target address from the sequence.
1079 struct SoundTrack *track) {
1080 const u8 *source = track->cursor;
1081 union PackedWord targetAddress;
1082
1083 targetAddress.part.byte0 = source[0];
1084 targetAddress.part.byte1 = source[1];
1085 targetAddress.part.byte2 = source[2];
1086 targetAddress.part.byte3 = source[3];
1087 track->voice.target = (const void *)targetAddress.value;
1088 track->cursor = source + 4;
1089}
1090
1091/// Reads the voice kind from the sequence.
1093 struct SoundTrack *track) {
1094 track->voice.kind = *track->cursor;
1095 track->cursor++;
1096}
1097
1098/// Reads the voice attack rate from the sequence.
1100 struct SoundTrack *track) {
1101 track->voice.attack = *track->cursor;
1102 track->cursor++;
1103}
1104
1105/// Reads the voice decay rate from the sequence.
1107 struct SoundTrack *track) {
1108 track->voice.decay = *track->cursor;
1109 track->cursor++;
1110}
1111
1112/// Reads the voice sustain level from the sequence.
1114 struct SoundTrack *track) {
1115 track->voice.sustain = *track->cursor;
1116 track->cursor++;
1117}
1118
1119/// Reads the voice release rate from the sequence.
1121 struct SoundTrack *track) {
1122 track->voice.release = *track->cursor;
1123 track->cursor++;
1124}
1125
1126/// Reads the note tail volume from the sequence.
1128 struct SoundTrack *track) {
1129 track->tailLevel = *track->cursor;
1130 track->cursor++;
1131}
1132
1133/// Reads the note tail duration from the sequence.
1135 struct SoundTrack *track) {
1136 track->tailLength = *track->cursor;
1137 track->cursor++;
1138}
1139
1140/// Reads the hardware note length from the sequence.
1142 struct SoundTrack *track) {
1143 track->voice.length = *track->cursor;
1144 track->cursor++;
1145}
1146
1147/// Reads the voice pan or CGB sweep setting from the sequence.
1149 struct SoundTrack *track) {
1150 track->voice.panOrSweep = *track->cursor;
1151 track->cursor++;
1152}
void MusicPlayer_Initialize(struct SoundPlayer *player, struct SoundTrack *tracks, u8 count)
Deactivates up to sixteen tracks and links the player into the mixer tick chain.
Definition engine.c:246
void AudioEngine_Initialize(struct SoundWork *work)
Resets the sound hardware, clears the whole sound work block and installs the default PCM driver: sto...
Definition engine.c:64
void MusicTrack_OperateWorkByte(struct SoundPlayer *player, struct SoundTrack *track)
Executes a work-byte operation and consumes a branch address for comparisons.
Definition engine.c:957
void AudioEngine_SetPcmRate(u32 mode)
Sets the PCM frame length (mode bits 16 to 19 pick a gSound_FrameLengths entry) and the rates derived...
Definition engine.c:105
void Cgb_UpdateChannels(void)
Steps CGB note envelopes and writes changed pitch, volume and trigger registers, once a frame.
Definition engine.c:537
void MusicTrack_CalcOutput(struct SoundPlayer *player, struct SoundTrack *track)
Recalculates dirty stereo volumes and pitch from track settings and modulation.
Definition engine.c:411
void CgbChannel_Mute(u8 channel)
Disables one CGB channel using its envelope or wave-control register.
Definition engine.c:485
void MusicPlayer_StartSong(struct SoundPlayer *player, const struct SequenceHeader *header)
Starts a song when its priority permits, resetting its tracks and tempo.
Definition engine.c:282
void MusicPlayer_Stop(struct SoundPlayer *player)
Pauses this player and stops all of its tracks, under the player's lock.
Definition engine.c:339
void MusicPlayer_StepFade(struct SoundPlayer *player)
Advances a due fade step, updating active track volumes, or at the end of a fade out stops (or pauses...
Definition engine.c:360
s32 Cgb_KeyToFrequency(u8 kind, u8 key, u8 fine)
Converts a key and fractional pitch to a CGB tone or noise-register value.
Definition engine.c:448
void MusicTrack_Stop(struct SoundPlayer *player, struct SoundTrack *track)
SoundCommand gSound_CommandTable[36]
void AudioEngine_SetMode(u32 mode)
Applies the reverb, channel-count, volume, bias and sample-rate fields of mode to the sound work,...
Definition engine.c:136
Declares nothing of its own: it only includes audio_engine_symbols.h and sound/audio_engine_types....
void Bios_CpuSet(const void *source, void *destination, u32 control)
#define SOUNDCNT_X_ALL_TONES_ON
#define REG_NR12
#define REG_NR41
#define REG_NR43
#define REG_SOUNDCNT_X
#define REG_WAVE_RAM
#define REG_NR32
#define REG_NR31
#define SOUND_COMMAND_FINISH
Entries of gSound_CommandTable, in gSound_CommandTableTemplate's order.
#define SOUND_FADE_FULL_VOLUME
#define REG_NR22
#define SOUND_FADE_STEP
#define REG_NR21
@ SOUND_PLAYER_PAUSED
#define SOUND_COMMAND_GOTO
Byte 0xB2: jumps to the address after it.
#define SOUND_WORK
@ SOUND_WORK_GREATER_BYTE
@ SOUND_WORK_NOT_EQUAL_BYTE
@ SOUND_WORK_LESS_EQUAL_BYTE
@ SOUND_WORK_NOT_EQUAL
@ SOUND_WORK_SET
@ SOUND_WORK_GREATER
@ SOUND_WORK_SUBTRACT
@ SOUND_WORK_ADD
@ SOUND_WORK_SUBTRACT_BYTE
@ SOUND_WORK_LESS
@ SOUND_WORK_ADD_BYTE
@ SOUND_WORK_LESS_BYTE
@ SOUND_WORK_EQUAL
@ SOUND_WORK_GREATER_EQUAL
@ SOUND_WORK_GREATER_EQUAL_BYTE
@ SOUND_WORK_LESS_EQUAL
@ SOUND_WORK_EQUAL_BYTE
@ SOUND_WORK_COPY
#define REG_NR44
#define SOUND_COMMAND_DETACH_NOTE
SoundNote_Detach: unlinks a note from its track's list (AudioCommand_InvokeSlot34).
#define REG_NR42
#define SOUND_COMMAND_CLEAR_WORK
SoundDriver_ClearBuffer: zeroes the first 64 bytes of a player or track (AudioCommand_InvokeSlot35).
@ CGB_PHASE_RELEASE
@ CGB_PHASE_SUSTAIN
@ CGB_PHASE_ATTACK
@ CGB_PHASE_DECAY
#define REG_NR33
#define REG_SOUNDBIAS_H
#define REG_NR34
#define SOUNDCNT_X_ENABLE
@ SOUND_FADE_PAUSE
@ SOUND_FADE_IN
#define REG_NR23
@ SOUND_TRACK_RESET
@ SOUND_TRACK_PITCH_DIRTY
@ SOUND_TRACK_UPDATE_VOLUME
@ SOUND_TRACK_ACTIVE
@ SOUND_TRACK_UPDATE_PITCH
@ SOUND_TRACK_VOLUME_DIRTY
@ SOUND_PLAYER_TRACK_LIMIT
Most tracks a player takes; MusicPlayer_Initialize caps its count here, and the track masks of the Mu...
@ SOUND_CGB_CHANNEL_COUNT
CGB channels, numbered 1 to 4.
@ SOUND_PCM_NOTE_CAPACITY
The PCM notes in SoundWork.pcmNotes; mode changes and AudioEngine_StopAllChannels clear all 12,...
@ SOUND_MODULATION_VOLUME
@ SOUND_MODULATION_PITCH
@ SOUND_MODULATION_PAN
#define SOUND_COMMAND_CAST(type, routine)
Converts between SoundCommand and a table entry that takes other parameters, through the generic func...
#define REG_NR11
#define REG_NR13
#define REG_NR24
#define REG_NR14
@ CGB_NOTE_PITCH_DIRTY
@ CGB_NOTE_VOLUME_DIRTY
@ CGB_NOTE_START
@ CGB_NOTE_ON
@ CGB_NOTE_PHASE
@ CGB_NOTE_STOP
@ CGB_NOTE_ECHO
#define REG_NR30
#define REG_NR51
#define SOUND_LOCK
#define REG_NR10
s32 __divsi3(s32, s32)
void Audio_EmptyCallback(void)
Provides the default empty callback before the sound driver installs its handlers.
void MusicPlayer_SetPitch(struct SoundPlayer *player, u16 mask, s16 pitch)
Sets the semitone and fractional pitch offsets of selected active tracks and marks their pitch for re...
Definition engine.c:828
void MusicPlayer_SetLfoSpeed(struct SoundPlayer *player, u32 selectedTracks, u32 speedArgument)
Sets LFO speed on selected active tracks, resetting modulation when stopped.
Definition engine.c:925
void MusicPlayer_SetModulationDepth(struct SoundPlayer *player, s32 selectedTracks, s32 depthArgument)
Sets modulation depth on selected active tracks, resetting zero-depth modulation.
Definition engine.c:894
const u16 gSound_FrameLengths[]
Samples per frame for each playback frequency setting.
Definition tables.c:131
void MusicTrack_SetVoiceAttack(struct SoundPlayer *player, struct SoundTrack *track)
Reads the voice attack rate from the sequence.
Definition engine.c:1099
#define SOUND_CYCLES_PER_FRAME
CPU cycles in a frame: 228 lines of 1232 cycles.
Definition engine.c:58
void Sound_LoadCommandTable(SoundCommand *table)
void MusicTrack_SetVoiceRelease(struct SoundPlayer *player, struct SoundTrack *track)
Reads the voice release rate from the sequence.
Definition engine.c:1120
void MusicTrack_SetVoiceDecay(struct SoundPlayer *player, struct SoundTrack *track)
Reads the voice decay rate from the sequence.
Definition engine.c:1106
void CgbNote_UpdatePanEnvelope(struct CgbNote *note)
Chooses stereo routing and derives peak and sustain levels for a CGB note, writing them into note.
Definition engine.c:509
const u8 gSound_CgbPitchCodes[]
CGB channel pitches.
Definition tables.c:136
void AudioCommand_InvokeSlot34(struct SoundNote *note)
Detaches a note through the command table entry installed by the driver.
Definition engine.c:7
void MusicTrack_SetVoiceLength(struct SoundPlayer *player, struct SoundTrack *track)
Reads the hardware note length from the sequence.
Definition engine.c:1141
const u8 gSound_Cgb3LevelCodes[]
CGB channel 3 waveform volumes.
Definition tables.c:165
void MusicTrack_DispatchStreamCommand(struct SoundPlayer *player, struct SoundTrack *track)
Reads an extended-command index and invokes its handler.
Definition engine.c:1049
void MusicTrack_SetTailLength(struct SoundPlayer *player, struct SoundTrack *track)
Reads the note tail duration from the sequence.
Definition engine.c:1134
void MusicTrack_SetVoiceSustain(struct SoundPlayer *player, struct SoundTrack *track)
Reads the voice sustain level from the sequence.
Definition engine.c:1113
void MusicPlayer_SetPitchAndUpdateFrequency(struct SoundPlayer *player, u16 scale)
Sets the tempo multiplier and updates the number of ticks advanced per frame.
Definition engine.c:787
void MusicTrack_SetVoiceKind(struct SoundPlayer *player, struct SoundTrack *track)
Reads the voice kind from the sequence.
Definition engine.c:1092
void MusicTrack_HandleNote(u32 command, struct SoundPlayer *player, struct SoundTrack *track)
#define SOUND_FRAME_RATE_E4
The display's frame rate in ten-thousandths of a hertz: 59.7275 frames a second.
Definition engine.c:56
const s16 gSound_CgbFrequencySteps[]
Frequencies by note for CGB channels.
Definition tables.c:151
const u8 gSound_NoisePitchCodes[]
Noise channel pitches.
Definition tables.c:156
void AudioEngine_SuspendDirectSound(void)
Stops both FIFO transfers and clears their sample buffers, raising the work's lock until AudioEngine_...
Definition engine.c:213
UNUSED void MusicPlayer_SetPan(struct SoundPlayer *player, u16 mask, s8 pan)
Sets the stereo pan offset of selected active tracks.
Definition engine.c:856
void MusicTrack_SetVoicePanOrSweep(struct SoundPlayer *player, struct SoundTrack *track)
Reads the voice pan or CGB sweep setting from the sequence.
Definition engine.c:1148
void MusicPlayer_Tick(struct SoundPlayer *player)
void AudioCommand_InvokeSlot35(void *block)
Clears a 64-byte player or track prefix through the driver command table.
Definition engine.c:19
void AudioEngine_ResumeDirectSound(void)
Restarts both FIFO transfers and releases the suspended-work lock.
Definition engine.c:232
#define SOUND_PCM_BUFFER_SIZE
The PCM buffer's size in samples, a multiple of every frame length: the DMA plays it round and round.
Definition engine.c:53
UNUSED void AudioEngine_StopAllChannels(void)
Silences every PCM and CGB note while holding the sound work lock.
Definition engine.c:178
void MusicTrack_ClearModulation(struct SoundTrack *track)
Resets the LFO phase and amount, marking the affected output for recalculation.
Definition engine.c:883
void MusicTrack_SetTailLevel(struct SoundPlayer *player, struct SoundTrack *track)
Reads the note tail volume from the sequence.
Definition engine.c:1127
void MusicTrack_ReadVoiceTarget(struct SoundPlayer *player, struct SoundTrack *track)
Reads an unaligned little-endian voice target address from the sequence.
Definition engine.c:1078
void Runtime_CallWorkEntryWithArgs(struct SoundPlayer *player, struct SoundTrack *track)
Finishes a track through the base command table entry.
Definition engine.c:1070
void MusicPlayer_SetVolume(struct SoundPlayer *player, u16 mask, u16 volume)
Sets the volume scale of active tracks selected by the bit mask and marks their output for recalculat...
Definition engine.c:800
The hardware's I/O registers and their bits, as pret names them.
#define SOUND_A_RIGHT_OUTPUT
Definition io_reg.h:271
#define REG_FIFO_A
Definition io_reg.h:280
#define DMA_START_SPECIAL
Definition io_reg.h:215
#define REG_TM0CNT_L
Definition io_reg.h:298
#define REG_FIFO_B
Definition io_reg.h:281
#define REG_DMA1SAD
Definition io_reg.h:286
#define REG_DMA1CNT_H
Definition io_reg.h:289
#define REG_DMA2DAD
Definition io_reg.h:291
#define REG_TM0CNT_H
Definition io_reg.h:299
#define SOUND_B_TIMER_0
Definition io_reg.h:277
#define CPU_SET_SRC_FIXED
BIOS CpuSet control flags, above its count.
Definition io_reg.h:236
#define REG_DMA2CNT_H
Definition io_reg.h:293
#define DMA_DEST_FIXED
Definition io_reg.h:203
#define REG_VCOUNT
Definition io_reg.h:19
#define DMA_32BIT
Definition io_reg.h:210
#define SOUND_ALL_MIX_FULL
Definition io_reg.h:269
#define REG_DMA2CNT
Definition io_reg.h:292
#define REG_DMA1DAD
Definition io_reg.h:287
#define SOUND_A_TIMER_0
Definition io_reg.h:273
#define CPU_SET_32BIT
Definition io_reg.h:237
#define DMA_REPEAT
Definition io_reg.h:208
#define TIMER_ENABLE
Definition io_reg.h:177
#define REG_SOUNDCNT_H
Definition io_reg.h:263
#define REG_DMA2SAD
Definition io_reg.h:290
#define SOUND_B_FIFO_RESET
Definition io_reg.h:278
#define REG_DMA1CNT
Definition io_reg.h:288
#define SOUND_A_FIFO_RESET
Definition io_reg.h:274
#define SOUND_B_LEFT_OUTPUT
Definition io_reg.h:276
#define DMA_ENABLE
Definition io_reg.h:217
#define NULL
Definition bilibin.h:6
A note on one of the four CGB channels of the hardware: its state and envelope, its levels and pan,...
u8 attack
Frames per attack step.
u8 channelBits
This channel's NR51 bits: 0x11, 0x22, 0x44, 0x88.
u32 frequency
Tone frequency from Cgb_KeyToFrequency (2048 added), or channel 4's NR43 value.
u8 echoLevel
After release, the level held is peak * echoLevel / 256.
u8 outLeft
Velocity and track volume to the left, 0 to 255.
u8 release
Frames per release step.
u8 trigger
Value for NRx4: 7 restart, 6 length on, 2..0 frequency.
u8 echoLength
Frames the echo lasts.
u8 sweep
Channel 1's NR10 sweep; 8 when none.
u8 length
The voice's length.
u8 level
Envelope level 0 to 15 written to the channel.
u8 counter
Frames left in the current envelope step.
u8 peak
Top of the envelope: (outRight + outLeft) / 16, at most 15 when one side plays.
u8 modified
CgbNoteModified: what to write to the channel.
u8 panBits
NR51 bits this note sets: one side or both.
u32 * loadedWave
Channel 3: the pattern last copied into wave RAM.
u8 state
CgbNoteState and CgbNotePhase; 0 when the channel is free.
u8 sustain
Sustain level 0 to 15, scaled by peak.
u8 decay
Frames per decay step.
u8 sustainLevel
(peak * sustain + 15) / 16.
u8 outRight
Velocity and track volume to the right, 0 to 255.
u8 kind
Channel number 1 to 4 at setup, then the voice's kind; bit 3 rounds the frequency to the sound bias's...
u32 * wave
Channel 3: the 16-byte wave pattern.
A song's header: its track count, priority and mode, its voices, and where each track's commands star...
u8 mode
With bit 7 set, passed to AudioEngine_SetMode (bits 6..0 the reverb); ags-music's reverb field.
const u8 * tracks[1]
Each track's first command, trackCount of them.
u8 priority
Becomes the player's priority.
const struct SoundVoice * voices
The voice table its tracks choose from.
A PCM note, one of 12 the mixer renders: its state and envelope, its output levels,...
u8 state
0 when free.
struct SoundTrack * track
The track whose list holds this note; NULL once detached.
A player, which plays one song: its header and status, its tracks, its tempo and fade.
const struct SequenceHeader * header
The song playing or last played.
u8 checkPriority
Nonzero: a song of lower priority does not replace a playing one.
u16 tempoStep
tempo * tempoScale / 256, added to tempoCount each frame.
u16 fadeCounter
Frames left until the next fade step.
u32 ticks
Song ticks played since the song started.
u16 tempoCount
Each 150 in it runs one tick, so a tempoStep of 150 is a tick a frame.
u16 fadeVolume
bits: 8..4 level, 0 to 0x100 in steps of 16 | 1 fade in | 0 pause at the end (SoundFadeFlag).
u32 status
bits: 31 paused | 15..0 tracks active after the last tick.
void(*) nextTick(struct SoundPlayer *player)
The tick routine and player that were first in the chain before this player was added; this player's ...
u8 priority
The song's priority.
u8 trackCount
Tracks this player owns, at most 16.
u16 tempoScale
256 plays at the song's tempo.
u8 * workBytes
gSound_WorkBytes, which the work-byte command uses.
u16 tempo
Twice the tempo command's byte; 150 at start.
const struct SoundVoice * voices
The song's voice table.
u32 lock
SOUND_LOCK when free; raised while the player is changed or ticked.
struct SoundPlayer * nextTickPlayer
Passed to nextTick.
struct SoundTrack * tracks
trackCount tracks.
u16 fadePeriod
Frames between fade steps; 0 when not fading.
A track of a playing song: the song commands it runs, its voice and notes, and the pitch,...
u8 bendRange
Semitones a full bend reaches; 2 at reset.
s8 bend
The bend command's byte - 64: full bend is bendRange.
s8 modAmount
The LFO's output, modDepth * wave / 64: added to the pitch in 1/16 semitone, to the pan,...
u8 pitchHi
Whole semitones of the track's pitch, read as signed and added to each note's key (a sum below 0 play...
u8 pitchLo
The pitch's fraction, 0 to 255 in 1/256 semitone, passed as the fine pitch to the key-to-frequency st...
u8 tailLevel
Each new note's echo level.
u8 lfoSpeed
LFO phase step a tick, 22 at reset; 0 stops the LFO and clears modAmount.
struct SoundNote * notes
The notes this track started, newest first, linked through SoundNote.next; PCM notes from SoundWork....
u8 outVolumeB
Left volume: (127 - pan) * scaled volume / 256.
u8 outVolumeA
Right volume: (pan + 128) * scaled volume / 256.
struct SoundVoice voice
Copied from the player's voice table by the voice command, or set a field at a time by extended comma...
s8 pan
The pan command's byte - 64, -64 to 63; doubled for output.
u8 fine
1/256 semitone, from MusicPlayer_SetPitch.
s8 tune
The tune command's byte - 64: 1/64 semitone.
const u8 * cursor
The next command byte in the song's data, from the header's track pointer; a track's commands end at ...
u8 flags
SoundTrackFlag.
u8 volume
The song's volume command, scaled by volumeScale / 32.
u8 modDepth
0 to 255, from the modulation command or MusicPlayer_SetModulationDepth; 0 stops the LFO and clears m...
u8 modTarget
SoundModulationTarget.
u8 tailLength
Each new note's echo length in frames.
u8 lfoPhase
0 to 255, wrapping; the wave is phase over 0 to 63, 128 - phase over 64 to 191 and phase - 256 over 1...
s8 panOffset
Added to the doubled pan, from MusicPlayer_SetPan.
s8 keyOffsetB
Semitones, from MusicPlayer_SetPitch.
u8 volumeScale
0 to 64 (full, the reset value): a player volume or fade level of 0 to 0x100 divided by 4.
s8 keyOffsetA
Semitones, from the song's key-shift command.
const void * target
The PCM sample, the CGB wave pattern, duty or noise width, or for a rhythm or split voice its voice t...
u8 attack
PCM: added to the envelope each frame until 255.
u8 decay
PCM: envelope * decay / 256 a frame. CGB: frames a step.
u8 panOrSweep
CGB channel 1's sweep (NR10) when bit 7 is clear and bits 6..4 are not; else no sweep.
u8 release
PCM: envelope * release / 256 a frame. CGB: frames a step.
u8 kind
bits: 7 rhythm | 6 key split | 3 fixed rate for PCM, bias rounding for CGB | 2..0 CGB channel (0 PCM)...
u8 length
CGB sound length (NRx1); 0 plays until released.
u8 sustain
Level decay stops at: 0 to 255 for PCM, 0 to 15 for CGB.
The sound driver's work: its lock, the mixer's rate and buffers, the PCM and CGB notes,...
s32(*) cgbFrequency(u8 kind, u8 key, u8 fine)
Cgb_KeyToFrequency.
u8 pcmNoteCount
PCM notes in use, 8 at start (mode bits 11..8).
void(*) unk3c(void)
Set to Audio_EmptyCallback by AudioEngine_Initialize; no TBS code reads it by name.
u8 reverb
0 to 127 (mode bits 6..0); 0 skips the reverb pass.
u8 volume
PCM volume 0 to 15, 15 at start (mode bits 15..12).
s8 buffers[2][0x630]
Right (0, DMA 1 to FIFO A) and left (1, DMA 2 to FIFO B) samples, transferPeriod frames of frameSampl...
struct SoundPlayer * tickPlayer
Passed to tick.
u32 lock
SOUND_LOCK when free; raised while the driver changes it.
u8 rate
1 to 12, indexes gSound_FrameLengths (mode bits 19..16).
u32 frameSamples
Samples mixed a frame, from gSound_FrameLengths.
struct SoundNote pcmNotes[12]
pcmNoteCount of them play.
u32 rateStep
2^23 / outputRate, rounded; a note's frequency times it is its step a sample.
struct CgbNote * cgbNotes
gSound_CgbNotes; NULL before CGB setup.
void(*) noteOn(u32 command, struct SoundPlayer *player, struct SoundTrack *track)
MusicTrack_HandleNote, run for song bytes from 0xCF up with the byte.
void(*) cgbUpdate(void)
Run each mixer frame: Cgb_UpdateChannels.
void(*) cgbMute(u8 channel)
CgbChannel_Mute, channel 1 to 4.
SoundCommand * commands
gSound_CommandTable.
u32 outputRate
Samples a second: frameSamples * 59.7275, rounded.
volatile u8 transferCountdown
Frames until the VBlank DMA restart, which reloads it from transferPeriod; also picks the frame of th...
void(*) tick(struct SoundPlayer *player)
First of the chain of player ticks run each mixer frame; NULL for none.
u8 transferPeriod
Frames the buffers hold: 0x630 / frameSamples.
u8 cgbTick
Counts 14 down to 0 once a CGB update; at 0 the envelopes take an extra step.
void(*) SoundCommand(struct SoundPlayer *player, struct SoundTrack *track)
A command table entry: the driver calls it with the player and the track.
Definition tables.c:11
const SoundCommand gSound_ExtendedCommandTable[]
Extended commands; entries zero and three do nothing.
Definition tables.c:178
The integer types, TRUE, UNUSED and the fixed-address macros.
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
signed char s8
Definition types.h:10
signed short s16
Definition types.h:12
unsigned short u16
Definition types.h:13
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11
A word put together from its four bytes, lowest first.
Definition engine.c:1059
struct PackedWord::@144047150331112312137023105363302267347230057174 part
u32 value
Definition engine.c:1060