1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
Many thanks to ipatix and Kurausukun. Without them, none of this would be possible.
Anyway, these changes will allow the game to have reduced noise and output sound at a higher base frequency.
In [src/m4a_1.s](https://github.com/pret/pokeemerald/blob/master/src/m4a_1.s), replace everything in that file with the code in the link below:
[Mixer code](https://gist.github.com/Xhyzi/2a3eafac546788c1c158295d5b3d3526)
This is the code for the mixer.
In [src/m4a.c](https://github.com/pret/pokeemerald/blob/master/src/m4a.c), change the size of SoundMainRAM_Buffer to
```c
0xC00
```
Again in [src/m4a.c](https://github.com/pret/pokeemerald/blob/master/src/m4a.c), add this line right below the line mentioned above:
```c
BSS_CODE ALIGNED(4) u32 hq_buffer_ptr[size] = {0};
```
With the aforementioned changes, it should look like this:
```c
BSS_CODE ALIGNED(4) char SoundMainRAM_Buffer[0xC00] = {0};
BSS_CODE ALIGNED(4) u32 hq_buffer_ptr[size] = {0};
```
Here, `[size]` is the length of one frame of audio, which varies by the sample rate you use. Here is a list of the possible sample rates and their corresponding frame sizes:
```
5734Hz: 0x60
7884Hz: 0x84 (This mode is not aligned to the buffer length and is not supported by the mixer)
10512Hz: 0xB0
13379Hz: 0xE0 (This is the default engine rate; without any modifications, this is what the GBA Pokemon games use)
15768Hz: 0x108
18157Hz: 0x130
21024Hz: 0x160
26758Hz: 0x1C0
31536Hz: 0x210
36314Hz: 0x260
40137Hz: 0x2A0
42048Hz: 0x2C0
```
Just find the sample rate you're using and use its corresponding frame size as the size of the array. For example, for the default sample rate, the size of the array is 0xE0 (note that the size of the array actually needs to be the frame size x 4; this is why this array is of type `u32` rather than `char` or `u8`).
Additionally, if you are planning on building the `modern` target, you will need to change
```c
struct SoundInfo gSoundInfo = {0};
```
to
```c
EWRAM_DATA struct SoundInfo gSoundInfo = {0};
```
In the vanilla build, we rely on `sym_ewram.txt` to put that symbol in the EWRAM section, but the `modern` target does not use `sym_ewram.txt`, which means that if we do not add this macro, the linker will attempt to put it into IWRAM, which will overflow the section and cause it not to build.
Next, remove the following from [common_syms/m4a.txt](https://github.com/pret/pokeemerald/blob/master/common_syms/m4a.txt):
```
gSoundInfo
```
Add then add the following to the end of [sym_ewram.txt](https://github.com/pret/pokeemerald/blob/master/sym_ewram.txt):
```
gSoundInfo:
.space 0xFB0
```
That's the mixer stuff out of the way, and if it was done correctly, the game shouldn't be producing as much quantization noise.
Optionally, you can also change the audio engine's sample rate if you're using higher-quality samples. However, be warned; this means that any fixed-frequency samples (most percussion samples) will be played at this frequency; if you keep these samples at a lower sample rate, they will get pitched up and not sound right. Resample your samples to the rate you're making the engine use, or use higher quality samples and downsample them to the proper rate.
In [src/m4a.c](https://github.com/pret/pokeemerald/blob/master/src/m4a.c), look for:
```c
SoundInit(&gSoundInfo);
MPlayExtender(gCgbChans);
m4aSoundMode(SOUND_MODE_DA_BIT_8
| SOUND_MODE_FREQ_13379
| (12 << SOUND_MODE_MASVOL_SHIFT)
| (5 << SOUND_MODE_MAXCHN_SHIFT));
```
For the sake of this tutorial, we'll be changing it to 36314Hz. So in that file, it would look like this:
```c
SoundInit(&gSoundInfo);
MPlayExtender(gCgbChans);
m4aSoundMode(SOUND_MODE_DA_BIT_8
| SOUND_MODE_FREQ_36314
| (12 << SOUND_MODE_MASVOL_SHIFT)
| (5 << SOUND_MODE_MAXCHN_SHIFT));
```
There's another call to set the sound frequency on [line 375](https://github.com/pret/pokeemerald/blob/master/src/m4a.c#L375); while it appears this code never actually affects anything since it gets overridden by the above change, for fool-proofing and if you're paranoid like me, you can change that one to match as well.
Now all that's left, and this is optional as well, is fixing the reverb for your new sample rate. At rates other than the default rate of 13379Hz, the game's reverb sounds much less pronounced, and if you go high enough, it gets to the point that you can't even really tell it's there. This is honestly a matter of preference--some people think reverb sounds good, some people prefer not to have it--but for the sake of completeness and those who like reverb, I will explain how to get the reverb to sound like it does at the default sample rate.
I talked about it like it's a huge deal, but there's actually not too much we need to change--in fact, the only thing that needs changing is the size of the direct sound buffer the game uses. This is defined in two different files--[constants/m4a_constants.inc](https://github.com/pret/pokeemerald/blob/master/constants/m4a_constants.inc#L3) and [include/gba/m4a_internal.h](https://github.com/pret/pokeemerald/blob/master/include/gba/m4a_internal.h#L152). Opening these files, you will see that the buffer's default size is 1584, or 0x630 in hex. Where does this number come from, you may ask--well it comes from the frame size I mentioned up above. The buffer is designed to last 7 frames in the game, plus some extra space at the end, so multiply your frame size to get the value you need. If we recall that the frame size of the default sample rate is 0xE0, we can do 0xE0 x 7, and we will find that it equals 0x620--which is 0x10 less than the original value (this is the extra space I mentioned). So find your sample rate in the table again, multiply it by 7, and replace the value in those two files with your new value. But we're not quite done yet!
The last thing we need to do is update the mixer code to use this new value. By default, it uses a hardcoded 0x630 value to match the default buffer. Changing that is actually going to be harder than expected due to the way immediate values work in ARM. The statement in question can be found on [line 890](https://gist.github.com/ShinyDragonHunter/6571250991f4b0f560206e2201e27e55#file-m4a_1-s-L890) of our new `src/m4a_1.s` file. If you're using anything under 36314Hz, you should be fine to just replace the value. However, for rates 36314Hz and above, the size of the buffer is too large to fit into the immediate field of a `mov` instruction. Generally, the solution to this is finding values that can be bit-shifted to equal your new size. This works nicely for 36314Hz's buffer size of 0x10A0--you'll find that 0x85 << 5 = 0x10A0. And luckily, ARM lets us bit-shift right in the operand, so we can do:
```asm
mov r0, #0x85
str r6, [r9, r0, lsl#5]
```
In place of the original `str` command. For 40137Hz, 0x93 << 5 works. And for 42048Hz, you can do 0x134 << 4. Replace them just like the statement above, and you'll be good.
And I believe that's that. If everything was done correctly (or I didn't screw something up), you will have much less noise in your sound.
|