[HN Gopher] Modder re-creates Game Boy Advance games using the a...
___________________________________________________________________
Modder re-creates Game Boy Advance games using the audio from crash
sounds
Author : dagenix
Score : 551 points
Date : 2024-01-22 17:39 UTC (1 days ago)
(HTM) web link (arstechnica.com)
(TXT) w3m dump (arstechnica.com)
| 2024throwaway wrote:
| This is insanely impressive. I'm sure many of the techniques used
| like the "majority vote" algorithm cited are underutilized across
| many industries.
| epcoa wrote:
| If one is interested there is nearly 100 years now of
| sophisticated noisy signal recovery techniques.
|
| Magnetic storage media operates on the principal of this hack
| at baseline! https://en.wikipedia.org/wiki/Partial-
| response_maximum-likel...
|
| The same idea can apply here as GBA ROM material would be
| highly biased. Majority vote wastes a lot of information.
| rob74 wrote:
| The problem with this signal is that it was never designed to
| be recovered in the first place (it only came about by
| chance), that's why it has the issue with long sequences of 0
| bytes described in the article.
| mikepurvis wrote:
| I wondered about it for film scanning, specifically with a fan
| project like 4K77 where they're dealing with potentially
| damaged theatre prints rather than pristine masters-- having
| multiple of them and being able to use that to eliminate
| scratches and so on would potentially save a ton of time on
| manual fixing in post.
| guyomes wrote:
| One interesting application of taking the value appearing in
| majority, or more generally taking the median, is to remove
| noise or people from a sequence of several photos taken from
| the same point of view. This idea is to superimpose all the
| photos, and for each pixel, you simply keep the median [1].
|
| [1]: https://patdavid.net/2013/05/noise-removal-in-photos-with-
| me...
| astrange wrote:
| This will have the effect of smoothing the image even if you
| didn't want to do that, which is part of the reason people
| are convinced phone cameras "overprocess" images or try to
| beautify you even when they aren't.
|
| You have to counteract this by actually putting the noise
| back when you're done.
| jacquesm wrote:
| It's fairly common in data recovery though, just keep on
| reading disk images and running quora until something passes
| the checksum and see if it works out. Better still if there are
| higher level checksums (for instance across a file that has a
| signature) for further verification. Also used in some
| aerospace applications.
| brokensegue wrote:
| Zzazz (the subject of the article) runs a yearly April fools
| competition/event that usually involves some amount of retro
| hacking/reverse engineering. I recommend participating. Previous
| years competitions are on their GitHub
| reactordev wrote:
| It's stories like these that remind me I'm stupid and have a lot
| still to learn. My goodness this is amazing. Up there with audio
| key logging and things I read about but could never dream would
| be a real thing.
|
| I tip my hat sir. Reminded that I'm a mere mortal in the presence
| of greatness. The absurdity of recreating a game based on audio
| crashes sounds like something a mental patient would say but no,
| here we are in 2024.
| sunnybeetroot wrote:
| You're not stupid because you don't know how to reverse
| engineer a GBA game, unless you work for Nintendo and it's part
| of your job description.
| da768 wrote:
| I imagine the 0xFF might be converted to 0x00 due to DC blocking
| capacitors/high-pass filtering, audio circuits aren't really
| suited for non-audible content.
|
| He might get better capture accuracy with a digital oscilloscope
| hooked directly at the chip's audio outputs if he's lucky, but
| it's still pretty impressive he got a bootable image out of that.
| Frenchgeek wrote:
| From what I remember reading in the comments of his youtube
| video, the point of the exercise was to do it with as basic
| equipment as possible.Hence the hours of multiples passes to
| average the error out instead of a proper data-logging
| oscilloscope.
| arcticbull wrote:
| > I imagine the 0xFF might be converted to 0x00 due to DC
| blocking capacitors/high-pass filtering, audio circuits aren't
| really suited for non-audible content.
|
| Yeah, you want to generate a signal with no DC bias, something
| as simple as Manchester encoding will go a long way. If that's
| not good enough, there's NRZ or even a convolutional encoding.
| You also want to make sure you either send a sin wave, or if
| you can't do that, at least make sure your square wave
| frequency is high enough that it doesn't get eaten by the AC
| coupling capacitors.
| freeqaz wrote:
| Would it be possible to get a higher quality read from using
| something like an Arduino's I/O pins and some bit-banged C
| code? I'd be curious to see what would be possible using
| cheap, off-the-shelf tools since a lot of people don't
| necessarily have an oscilloscope laying around. :P
| fodkodrasz wrote:
| Without looking up datasheets, just form the top of my
| head: the Arduino DAC most likely has 12 bits resolution
| (as common for cheap uCs), and maybe even slower sampling
| than a soundcard. A sound card was probably better than
| that even in the 1990s (say a Sound Blaster).
| aidenn0 wrote:
| The original Sound Blaster could only record at 8-bit
| resolution at up to 12 kHz. The 2.0 could record at up to
| 15kHz, still 8-bit.
|
| The second generation of Sound Blaster was the first that
| could record at 44kHz (mono) sampling rate, but was still
| only 8-bits of resolution.
|
| It wasn't until the 3rd generation Sound Blaster 16 that
| 16-bit audio could be recorded.
| fodkodrasz wrote:
| Hmm, I had (false) memories of better capabilities.
| Though my first soundcard was an SB Pro clone, later an
| SB16, both almost capable :)
| skeaker wrote:
| Glad to see this getting more attention here, it was posted a few
| days ago but drowned
| (https://news.ycombinator.com/item?id=39037104). The original
| video has a lot not mentioned in this brief article, including a
| custom adapter that the hacker had to cut together manually to
| get the right audio quality out of the DS.
| taftster wrote:
| Link to "original video":
|
| https://www.youtube.com/watch?v=0-7PSmYYHF0
| hifikuno wrote:
| The video was great. I think my favourite part is where he
| dumps the Chinese knock off version and finds the random ARM
| code and reverse engineers it. So much cool stuff in there.
| taftster wrote:
| Right? This kind of stuff just makes me look silly in what
| I'm able to achieve. I can only accomplish watching a video
| of some guy doing bad ass stuff and maybe holding onto a
| few notional details. People are just super smart
| sometimes.
| runnr_az wrote:
| It's especially fun watching super smart people work on
| somewhat ridiculous projects.
| peddling-brink wrote:
| Why would this happen in the first place? Is it common for these
| games to dump state to audio? Is it a deliberate debugging tool
| for the game devs?
| 0xC0ncord wrote:
| The author's previous video[1] explains the technical details
| regarding this behavior.
|
| Basically the way GBA sound works is there is a buffer in RAM
| that the audio is streamed from, and an interrupt is supposed
| to signal the hardware to begin reading data from the beginning
| of the buffer again. However, if the interrupt is never fired
| (such as when the game crashes), the audio stream will go
| beyond the buffer and read other parts of memory.
|
| [1] https://www.youtube.com/watch?v=wSWNkpqjtQY&t=361s
| jboy55 wrote:
| Would this be dependent on the audio file that was being
| played during the crash to start at address 0 of the ROM? It
| seems like it'd be highly unlikely you'd be able to get 100%
| of the ROM.
|
| Now if this was a hack where the thought was, "What if we
| dumped the whole ROM to the audio buffer, could we recover
| the complete ROM through audio analysis?"
| ordu wrote:
| I think hardware starts from 0 after reaching 0xfff..ffff
| address. The article mentions that you need to wait before
| starting to record, I assume it is a pause needed for
| hardware to overflow address.
| lelandbatey wrote:
| That video seems to imply that the audio hardware
| automatically wraps back to address 0 when it reaches the
| end of RAM. That may not be true, but it's implied by the
| animation in that video. And since they were apparently
| able to dump the entire ROM via audio, I suppose there's
| _some_ way to get the entire memory contents.
| shadowgovt wrote:
| The ROM on the GBA is mapped into memory at high memory
| addresses (0x08000000 and above). The audio "working"
| buffer is in low memory (I think somewhere near
| 0x02000000?). An interrupt fires when the audio chip reads
| to the end of the working buffer that looks something like
| this:
|
| - run the function to fetch the next batch of audio to
| audio working RAM
|
| - reset the audio read pointer to the beginning of audio
| working RAM
|
| When interrupts are disabled (because the game has
| crashed), that "reset pointer" code never runs and the
| audio circuit keeps reading way past the end of its buffer,
| incrementing forever. Eventually it would increment into
| the 0x08000000 range in which case the sounds it's emitting
| map directly to the bits in the ROM.
| aprilnya wrote:
| the sounds aren't read directly from the rom - the buffer
| is in a fixed place in ram, and sounds from the rom get
| copied into there
|
| remember that it's not like the music is just there as raw
| audio, the raw audio is just the sounds of the different
| instruments
| jboy55 wrote:
| That makes more sense, I thought they would just be
| pointers to ROM addresses for the samples.
| shadowgovt wrote:
| No, they're read directly from the ROM.
|
| Here's what's going on:
|
| - reading from ROM is slow, relative to working RAM; the
| ROM is mapped to the same memory address space as the
| RAM, but reading a ROM address takes (I think 8?) clock
| ticks.
|
| - so to do audio playback, the GBA "stripes" a chunk of
| data into RAM, sets a pointer to the beginning of that
| stripe, and then lets the audio chip pull data and update
| that pointer. When the pointer reaches the end of the
| stripe, an interrupt triggers that is _supposed_ to pull
| in the next chunk of audio into the stripe (overwriting
| the current stripe contents) and reset the pointer.
|
| ... but if interrupts are disabled, then that doesn 't
| happen, and the simpler logic in the audio chip just
| keeps incrementing the pointer forever and reading more
| data. It'll eventually get to the ROM addresses and pull
| directly from those (it's slow, but fast enough that it
| doesn't starve the chip; you just wouldn't run your audio
| this way in the game normally because you'd have 1/8th
| the amount of time to do _everything else_ every frame of
| animation if the audio system were reading directly from
| ROM all the time. Also, reading from RAM lets you edit
| the samples to do audio effects).
| Dwedit wrote:
| GBA Memory Map: 02000000-0203FFFF EWRAM
| (256 KBytes) 03000000-03007FFF IWRAM (32 KBytes)
| 06000000-06017FFF VRAM - Video RAM (96 KBytes)
| 08000000-09FFFFFF Game Cartridge ROM (max 32MB)
|
| The audio buffer will usually live in EWRAM, then you have
| to wait until about 100,000,000 audio samples have played
| before it proceeds from EWRAM to Game Cartridge ROM.
| shadowgovt wrote:
| It's pretty uncommon and it's not a deliberate debugging tool.
| In this case, the GBA could, hypothetically, have had a way to
| "park" the architecture on a game crash, or "watchdog" the
| system (by tying state update somewhere that should run
| periodically to a non-maskable interrupt that reboots the
| machine if that state update stops happening).
|
| Simply because it costs more to do those things, the GBA
| doesn't (Nintendo instead opting for the time-worn approach of
| the great game cart manufacturers of old, "if our games don't
| have bugs we don't have to worry about the behavior of the
| hardware in undefined state!"). So when a GBA game gets into
| some crash states (infinite loop with interrupts disabled, for
| example), the audio chip doesn't know the system is crashed and
| keeps doing its very simple job: reading sequential bits in RAM
| and converting them to sounds. Without the housekeeping that
| normally runs when the game is in good working order
| shepherding that read operation, it just keeps reading and
| eventually gets to the bits representing values in the
| cartridge ROM.
| Dwedit wrote:
| The GBA does have an interrupt that occurs when cartridge is
| removed.
| krallja wrote:
| WOW how did I never know about this?
|
| https://gbadev.net/gbadoc/interrupts.html
|
| > It is possible to switch cartridges and have the routine
| resume execution on a completely different ROM.
|
| That would have been a heck of a game mechanic back in the
| early 2000s! Maybe I never saw it because game developers
| were tired of the "please insert disk 2" of the Playstation
| era. But it feels like a gimmick a Metal Gear Solid game
| could have used.
| thewakalix wrote:
| The issue with long runs of 0x00 is related to "clock recovery".
|
| > Some digital data streams, especially high-speed serial data
| streams (such as the raw stream of data from the magnetic head of
| a disk drive and serial communication networks such as Ethernet)
| are sent without an accompanying clock signal. The receiver
| generates a clock from an approximate frequency reference, and
| then phase-aligns the clock to the transitions in the data stream
| with a phase-locked loop (PLL).
|
| > In order for this scheme to work, a data stream must transition
| frequently enough to correct for any drift in the PLL's
| oscillator. The limit for how long a clock-recovery unit can
| operate without a transition is known as its maximum consecutive
| identical digits (CID) specification.
|
| https://en.wikipedia.org/wiki/Clock_recovery
| akira2501 wrote:
| I love how we used to use a bunch of very clever "code book"
| systems like 8b/10b which did a lot of careful work with small
| runs of bits to ensure the clock was recoverable and to avoid
| line capacitance issues.
|
| Then we just moved to things like 64/66b which takes a giant
| chunk of bits, adds a short header to guarantee a clock
| transition, then runs everything through a pseudorandom
| scrambler.
| dwattttt wrote:
| A sprinkle of entropy improves everything
| jacquesm wrote:
| They do a similar thing for GPS data recovery. It is so far
| below the noise floor that normally speaking the signal is
| not recoverable. But then you inject some (known) noise and
| suddenly the noise modulated by the (unknown) signal starts
| to drown out the noise in the rest of the system and that
| in turn allows you to recover bits from the signal.
| akira2501 wrote:
| It's not only below the noise floor, but all satellites
| transmit the code on the same frequencies, so it's
| several signals all at once below the noise floor. Which
| makes the known noise unique to each satellite, and you
| dredge out the same frequency repeatedly with different
| sets of known noise to recover multiple signals.
|
| Gold sequences are really neat, which is precisely the
| same pseudorandom scrambling technique, but where each
| sequence is selected to have low correlation with all
| other sequences in use, which is what enables the
| frequency sharing property of the system.
| farhanhubble wrote:
| This thread brings back fond memories from electronics
| and digital signal processing.
| rollcat wrote:
| https://ciechanow.ski/gps/
| jacquesm wrote:
| That's a great article, you should post it separately.
| rollcat wrote:
| https://news.ycombinator.com/from?site=ciechanow.ski ;)
| physicles wrote:
| QR codes do this too, as explained by yesterday's front
| page post about decoding QR codes by hand.
| userbinator wrote:
| Against adversaries, scrambling schemes can produce some very
| perplexing behaviour. See the "weak sectors" used for CD copy
| protection for one infamous example.
| tux3 wrote:
| The PCIe standards kept moving to longer codes, and nowadays
| they're able to do "1b/1b" (no header at all)
| phire wrote:
| Not really accurate. The switch from NRZ to PAM4 actually
| massively increased the bit error rate. They switched away
| from the 8b/10b style line code and replaced it with
| forwards error correction.
|
| PCIe 6.0 uses 256 Byte frames, with 242 Bytes of data, 8
| Bytes or CRC and 3 Bytes of error correction.
|
| So it actually has way more overhead than the older
| versions and their 128b/130b line coding, It's just at a
| slightly different layer.
| mlyle wrote:
| Another concern is if the waveform is AC coupled somewhere and
| DC can't pass.
|
| Even if you have a perfectly synchronized clock, all-or-
| mostly-1's will be the same as all-or-mostly-0's in the long
| run.
| andai wrote:
| From this page I found a very interesting article: Wireless Set
| Number 10
|
| https://en.wikipedia.org/wiki/Wireless_Set_Number_10
| hun3 wrote:
| This is probably irrelevant. The audio is analog (requires DAC
| to decode into bitstream) and is transmitted with some fixed
| frequency (44.1kHz or 48kHz), without any particular
| synchronization.
| dtgriscom wrote:
| Nope. If you're trying to recover bits from a signal which is
| either high or low, and the signal stays high for a long
| time, unless your clocks are perfect (they won't be) you
| won't be able to tell just how many bits were in that long
| period of "high"s.
| Y_Y wrote:
| This reminds me of the original iPodLinux hack almost twenty
| years ago where the fourth-gen firmware was dumped via the piezo
| speaker -
| https://web.archive.org/web/20140810083116/http://www.newsci...
|
| Coincidentally one of the things this facilitated was playing GBA
| games on the iPod, though I was happy enough just to play Doom a
| with the click wheel and watch monochrome videos.
| nathancahill wrote:
| Good memories. I still have my iPod Classic, I upgraded the
| battery and added 4 256GB MicroSD cards. I saw a mod recently
| for adding Bluetooth but it involves swapping the rear case and
| I don't think I'll go that far. There's something timeless
| about the design (and about owning copies of music files).
| KennyBlanken wrote:
| Every music file I have in iTunes and on my iPhone is a DRM-
| less MP3 or AAC file.
| xyzzy_plugh wrote:
| Funny to see this mentioned. I was recently out skiing and
| was using my phone to listen to music, as I used to do with
| my 3rd generation iPod. Moments ago I was lamenting to my
| colleague that while my phone's battery rapidly plummeted in
| the cold despite being insulated and close to my body (no way
| even remotely approaching freezing temperatures) my iPod
| never struggled to play tunes all day. In fact I never recall
| any noticeable difference in battery performance in cold
| temperatures despite daily use for years.
|
| And yet my phone gets a bit chilly and gives up the ghost.
|
| I use Bluetooth otherwise I'd have dug out the 3rd gen for
| the next ski day.
| wegfawefgawefg wrote:
| Was it a difference in battery chemistry?
| speedgoose wrote:
| Sample size N=1 too but I remember warming up my iPod to
| get more battery while my iPhone survives pretty well while
| streaming my GPS coordinates when I go skiing.
| ace2358 wrote:
| Given the 'super compute in your pocket' thing we say...
| super computers turned out to be terrible at playing music
| files without stopping.
|
| My iPhone will regularly forgot what I was listening to
| moments ago after I press pause. Insane.
| tomduncalf wrote:
| Yeah this is so annoying! It especially seems to happen
| with 3rd party music player apps.
| ace2358 wrote:
| Also apps and or websites pausing my music but play no
| sound... ugh. I want an iPod.app to come along.
|
| Tiny player does nice but the os level issues are getting
| insane.
|
| Also apps that have their data deleted (Apple tv infuse
| app, play:sub iOS) because the os said so. I have plenty
| of space but things get deleted. I want to FILL my 256
| phone please.
| mensetmanusman wrote:
| I thought everyone enjoyed being forced to watch an Apple
| Music advert when they just want to play a song stored on
| device!
| seabass-labrax wrote:
| Does anyone know what's going on when the TheZZAZZGlitch's
| emulator reports that the game tries to jump to an invalid
| address? I'm not so familiar with the ARM7 processor used in the
| GameBoy Advance, but I can't imagine how it would be possible to
| construct a jump call with an invalid value. Additionally, what
| would happen if one of TheZZAZZGlitch's incorrectly reconstructed
| ROMs was run on a real GameBoy?
| cosarara wrote:
| > I can't imagine how it would be possible to construct a jump
| call with an invalid value
|
| You can use the bx instruction to jump to any address stored in
| a register.
|
| > Additionally, what would happen if one of TheZZAZZGlitch's
| incorrectly reconstructed ROMs was run on a real GameBoy?
|
| It would crash, and eventually start playing the ROM on the
| speaker, the whole point of the video :)
| seabass-labrax wrote:
| Thanks for the explanation! So it sounds like the emulator is
| detecting the error 'out of band' with the emulated execution
| flow, and choosing to throw an error message rather than
| letting the execution continue. If it didn't catch the error,
| it sounds like it would glitch out in much the same way as
| the real GameBoy would. Is that right?
| immibis wrote:
| That's right. This sort of thing is more likely to indicate
| a discrepancy between the emulator and the real hardware,
| than actual game behaviour, so emulator developers choose
| to treat it like a crash. Some emulators have "continue
| anyway" buttons and some don't.
| ehaliewicz2 wrote:
| It is likely that the emulator only emulates accessing valid
| parts of the GBA's memory map, and throws that error if invalid
| parts are accessed. As to what happens on real hardware.. who
| knows? :)
| Trekker666 wrote:
| I've done this using GoldWave opening game files to extract their
| audio because I like the menu song or something, but nothing this
| sophisticated and cool.
| jacquesm wrote:
| That is extremely clever. The persistence alone is impressive but
| to get it to the point where it works well enough that you can
| actually extract the ROM contents with high fidelity is next
| level.
| maxlin wrote:
| The diffing of the real-world cartridge was the most interesting
| part. Requires a goofy amount of unnecessary knowledge to just
| jump in to reversing that and figuring out what its meaning is
| lol
| DerCommodore wrote:
| Crazy
| scarecrw wrote:
| This reminds me of an attempt made by RGMechEx to retrieve game
| code for an Atari game where the code itself was used to generate
| a visual effect similar to TV static on the screen [1].
|
| [1] https://www.youtube.com/watch?v=5HSjJU562e8
| Rapzid wrote:
| The most impressive part of all this is, IMHO, how the code was
| modified by the bootleggers to run the game off writable flash vs
| ROM plus volatile save memory haha.
| mmaniac wrote:
| This is a very common technique on bootleg Game Boy and Game
| Boy Advance games which bootleggers use to save a few cents on
| batteries. And in truth, it's not too difficult to make such a
| patch.
|
| Bootleggers will write per-game patches which flush the save
| contents to writeable flash depending on a small amount of
| reverse engineering work to discover where in the code the game
| saves. However, since all official GBA games always save data
| using functions from the Nintendo SDK, it's fairly
| straightforward to hook those functions and make a generic
| patch for any GBA game to save on a batteryless bootleg
| cartridge.
|
| I have written a patcher to do this which you can find here.
| https://github.com/metroid-maniac/gba-auto-batteryless-patch...
| goodboyjojo wrote:
| this is a good article. very interesting stuff
| shadowgovt wrote:
| I've always found Nintendo's audio architectures to be
| fascinating.
|
| The original NES had a sample generator that could do arbitrary
| waveforms and could be driven in two modes: one mode is you gave
| it a memory address and it'd start reading the bits in and treat
| them as an incredibly simple waveform (1 means 'go up one value',
| 0 means 'go down one value'... So to do a flat wave you'd do a
| run of 10101010etc.).
|
| But you could also direct-drive the chip by continuously feeding
| it an "initial value" directly from the CPU, which was actually
| faster than the audio driver would read the bits from RAM
| itself... Problem is that doing so ate up all your CPU cycles, so
| you could only do it if you weren't doing anything else.
|
| There were some games that took advantage of that: Battletoads
| had higher-fidelity drum-hits that they could play when action
| was paused, and they used it for the title screen, the
| extra-"crunchy" final hits on enemies (where all the action
| paused for a moment for dramatic effect), and the memorable pause
| music.
|
| Here's a demo of the game switching between direct-drive and let-
| chip-read-samples mode to demonstrate (credit to Retro Game Audio
| for uploading the emulator-doctored video to show when the game
| is in the direct-drive subroutine).
| https://www.youtube.com/watch?v=JGT0FM3yh-w
___________________________________________________________________
(page generated 2024-01-23 23:02 UTC)