-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
“Robottle fight” voice sample cuts out halfway on real GBA hardware #183
Comments
Verified the issue doesn't occur on 0.1.0 |
The whole voiceover setup is super timing dependent... Will probably spend some time disassembling it and maybe reimplementing it. |
0A:44AF is what actually does the robattle stuff, including setting up the text and calling the function 3779 calls the playback and sets things up |
2023-06-13_20-45-19.mp42023-06-13_20-47-17.mp4Depending on how you affect the timing it, it actually happens in both the original and our patch. Note the volume differences too... |
It's been mentioned that the Japanese version also has this issue, but I looked at part of a YouTube playlist of Medarot 3 (see here: https://www.youtube.com/playlist?list=PLNL-hT-h2KcRnB1E7ZkP8Lokv14Nm1B79), in Japanese, on the Game Boy Player (which is affected by the "Robattle fight" issue in the English patch). This issue doesn't seem to be present in Japanese on real hardware so it might be an emulation issue. Below is a list of timestamps through the end of Chapter 2. This will be updated over time with more timestamps. Unless otherwise noted, a timestamp has "Robattle fight" as its voice clip.
|
The root cause of this issue is that GBC audio on GBA is very different internally from GBC audio on GBC, which causes a problem with the playback method that this and some other games use. The playback method works by playing ultrasonic tone and varying the volume of the sound channel. The ultrasonic tone is inaudible or filtered out, and what's left is a varying DC offset that's used to play one sample at a time. For example a square wave at volume On GBC, the audio mixing is analog. The combined signal is happily output from the SoC, and the ultrasonic tone is (hopefully) filtered out by various components on the GBC meant for suppressing interference. (For example the C14 filter capacitor connected in parallel with the internal speaker, or the EM1-EM5 EMI filters connected in series with the headphone jack.) On GBA, the audio mixing is digital, and what's worse, more or less using the nearest neighbor sampling method. It's sampling periodically at a rate specified by the GBA BIOS during the boot process. This means that in the example above it might only pick every 2nd or 4th sample and happen to always pick the active signal level, in which case the sample is heard. Or it might align so that it always reads zeros. It essentially works or not based on dumb luck. Except that's not what happens at all, because of what is probably a bug in the code. First look at the initialization code in ld a, $FF
ldh [H_RegNR13], a
ldh [H_RegNR23], a
ld a, $78
ldh [H_RegNR12], a
ldh [H_RegNR22], a ;Envelope 0xFF, sweep disabled
ld a, $87
ldh [H_RegNR14], a
ldh [H_RegNR24], a ;Frequency 0x2FF, consecutive mode The comment is actually wrong. The pitch value is initialized to For contrast, this is what's done later in ld a, $FF ; 0 in Telefang.
ldh [H_RegNR13], a
ldh [H_RegNR23], a
ld a, $81 ; $80 in Telefang.
ldh [H_RegNR14], a
ldh [H_RegNR24], a This sets the pitch value to But the phase position can be reset partially, to the start of the closest step. (Unless you turn the APU off and on again.) So if you let the channel run freely for a while without resetting it or keeping precise track of the time that has elapsed, you can get a similar effect as above where you only get zeros as output. In the first playback method described the issue is that a ultrasonic square wave doesn't align with the sampling if the GBA's audio mixer and only samples zeros. But this method accidentally isn't used. In the second playback described, the issue is that we might wait the wrong amount of time and lock the channel in a phase position where it only outputs zeros. So we've basically gone from one playback method that might've worked by dumb luck, through a bug, to another playback method that works by dumb luck but in a different way. So, what's actually happening, exactly? We can reset the APU by turning it off and then on again to reset the phase position of CH1 and CH2. The game does this... kind of: xor a
ldh [H_RegNR52], a ;Disable sound hardware, resetting all state
call Sound_OpenSampleData
.fragmentLoop
call Sound_ExitSampleMode ; In Telefang this call is missing.
call Sound_PrepareSampleFragment
di ; In Telefang this is before the call to the Sound_PlaySample wrapper function instead.
call Sound_PlaySampleFragment
ei ; In Telefang this is after the call to the Sound_PlaySample wrapper function instead.
; Later loop back to .fragmentLoop. The problems more specifically are this:
The quick fix would be to rearrange the code a little bit: Sound_PlaySample::
push af
push bc
push de
push hl
call Sound_OpenSampleData
.fragmentLoop
call Sound_PrepareSampleFragment
di ; In Telefang this is before the call to the Sound_PlaySample wrapper function instead.
xor a
ldh [H_RegNR52], a ;Disable sound hardware, resetting all state
call Sound_PlaySampleFragment
call Sound_ExitSampleMode ; In Telefang this call is missing.
ei ; In Telefang this is after the call to the Sound_PlaySample wrapper function instead.
ld a, [W_Sound_SampleFragmentCount]
dec a
ld [W_Sound_SampleFragmentCount], a
jr nz, .fragmentLoop
call Sound_ExitSampleMode
pop hl
pop de
pop bc
pop af
rst $18 ; Absent from Telefang (since Telefang uses a wrapper function instead).
ret What we're doing here is putting all timing critical code inside the |
Thanks for the detailed explanation @nitro2k01 . Also CC: @andwhyisit
If you're interested, a PR is always welcome :). We're also fairly active in the development discord https://discord.gg/VqqGXzXE (#medarot-3-translation) |
Hardware used
Flashcarts used
Versions
Has been present since the very first English patch (0.1.0) and remains as of 0.4.1+EN+nightly.20230611, and occurs consistently. Consistently does not occur in the retail Japanese game. Occurs in both Kabuto and Kuwagata versions.
Description
The “Robottle fight” voice sample, which is heard at the start of a Robattle, cuts out halfway on real GBA hardware: Only the “Robottle” part is heard, but the “fight” part is not. This issue happens consistently in all English patches tested. No other voice sample in the game is known to have this issue.
This issue does not occur in BGB in GBC mode, but a different issue occurs when played in GBC on GBA mode. (This can be done by right-clicking BGB -> Options -> System tab -> Check "detect GBA".) Instead of being silent, the "fight" part has a buzzing sound overlapping the normal "fight" voice. Due to the different behavior between BGB and real GBA hardware, this issue appears to be a strange corner case. (Making this even stranger is that Medarot 3 doesn't even check the b register on boot, which is normally done to detect if the game is run on a GBA.)
It is possible that the issue is timing or lag related, as if you hack the game to disable double speed mode (this can be done by unchecking the "double speed" box in the bgb IO map), even more severe buzzing occurs with all voice samples.
This issue has been untested on other flashcarts. It was also untested on an original GBA as I do not have a working one to test with.
Audio files
Various audio (MP3) files are attached.
Robottle Fight.zip
The text was updated successfully, but these errors were encountered: