summaryrefslogtreecommitdiffstats
path: root/2020/info
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--2020/info/27.md218
1 files changed, 216 insertions, 2 deletions
diff --git a/2020/info/27.md b/2020/info/27.md
index bc19e6c2..f2df923a 100644
--- a/2020/info/27.md
+++ b/2020/info/27.md
@@ -1,8 +1,9 @@
# State of Retro Gaming in Emacs
Vasilij "wasamasa" Schneidermann
-[[!template id=vid src="https://mirror.csclub.uwaterloo.ca/emacsconf/2020/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann.webm"]]
-[Download compressed .webm video (7.2M)](https://mirror.csclub.uwaterloo.ca/emacsconf/2020/smaller/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann--vp9-q56-video-original-audio.webm)
+[[!template vidid=mainVideo id=vid src="https://mirror.csclub.uwaterloo.ca/emacsconf/2020/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann.webm"subtitles="/2020/subtitles/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann.vtt"]]
+[Download compressed .webm video (7.2M)](https://mirror.csclub.uwaterloo.ca/emacsconf/2020/smaller/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8--vasilij-wasamasa-schneidermann--vp9-q56-video-original-audio.webm)
+[View transcript](#transcript)
- [chip8 demo - alien, .webm video, 720p, 2M](https://mirror.csclub.uwaterloo.ca/emacsconf/2020/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8-demo-alien--vasilij-wasamasa-schneidermann.webm)
- [chip8 demo - brix, .webm video, 720p, 1M](https://mirror.csclub.uwaterloo.ca/emacsconf/2020/emacsconf-2020--27-state-of-retro-gaming-in-emacs-chip8-demo-brix--vasilij-wasamasa-schneidermann.webm)
@@ -71,3 +72,216 @@ constraints.
- Repository available at <https://depp.brause.cc/chip8.el/>.
- Blog post available at
<https://emacsninja.com/posts/smooth-video-game-emulation-in-emacs.html>.
+
+<a name="transcript"></a>
+# Transcript
+
+[[!template new="1" text="Hello everyone and welcome to my talk, &quot;The State of Retro Gaming and Emacs.&quot;" start="00:00:00.880" video="mainVideo" id=subtitle]]
+[[!template text="First of all, a little bit about myself." start="00:00:06.960" video="mainVideo" id=subtitle]]
+[[!template text="My name is Vasilij Schneidermann. I'm 28 years old." start="00:00:08.639" video="mainVideo" id=subtitle]]
+[[!template text="I work as a cyber security consultant at msg systems," start="00:00:12.000" video="mainVideo" id=subtitle]]
+[[!template text="and test other people's web applications" start="00:00:14.719" video="mainVideo" id=subtitle]]
+[[!template text="and review the source code for security problems." start="00:00:17.359" video="mainVideo" id=subtitle]]
+[[!template text="You can reach me by email." start="00:00:20.160" video="mainVideo" id=subtitle]]
+[[!template text="I have my own self-hosted git repositories," start="00:00:22.080" video="mainVideo" id=subtitle]]
+[[!template text="and I have a blog where you can occasionally find new posts by me" start="00:00:25.039" video="mainVideo" id=subtitle]]
+[[!template text="on all kinds of things, not just Emacs things." start="00:00:28.160" video="mainVideo" id=subtitle]]
+[[!template new="1" text="The motivation about this one..." start="00:00:32.160" video="mainVideo" id=subtitle]]
+[[!template text="I found that Emacs is the ultimate procrastination machine," start="00:00:34.559" video="mainVideo" id=subtitle]]
+[[!template text="and there are lots of fun demonstrations." start="00:00:37.600" video="mainVideo" id=subtitle]]
+[[!template text="I'll go over a few of them." start="00:00:39.600" video="mainVideo" id=subtitle]]
+[[!template text="For example, someone made a thing to order salad for himself online," start="00:00:41.200" video="mainVideo" id=subtitle]]
+[[!template text="so he doesn't have to walk over to the shop." start="00:00:45.840" video="mainVideo" id=subtitle]]
+[[!template text="There's plenty of IRC bots. There's some game things." start="00:00:48.239" video="mainVideo" id=subtitle]]
+[[!template text="There's an emulator for the Z-machine which you can use to play zork." start="00:00:51.760" video="mainVideo" id=subtitle]]
+[[!template new="1" text="And so I asked myself, at this point," start="00:00:55.600" video="mainVideo" id=subtitle]]
+[[!template text="can you actually emulate retro games at 60fps?" start="00:00:57.440" video="mainVideo" id=subtitle]]
+[[!template text="I looked around a bit and found some projects," start="00:00:59.920" video="mainVideo" id=subtitle]]
+[[!template text="but none that were actually able to do it at 60fps." start="00:01:02.079" video="mainVideo" id=subtitle]]
+[[!template text="So I set out to do my own one," start="00:01:06.159" video="mainVideo" id=subtitle]]
+[[!template text="and looked out for a console" start="00:01:08.000" video="mainVideo" id=subtitle]]
+[[!template text="that you can actually emulate at that speed," start="00:01:09.200" video="mainVideo" id=subtitle]]
+[[!template text="using Emacs with its very, very limited rendering." start="00:01:11.119" video="mainVideo" id=subtitle]]
+[[!template new="1" text="And here's the project, chip8.el." start="00:01:16.320" video="mainVideo" id=subtitle]]
+[[!template text="It's pretty much finished." start="00:01:19.200" video="mainVideo" id=subtitle]]
+[[!template text="It clocks into under 1000 source lines of code." start="00:01:20.560" video="mainVideo" id=subtitle]]
+[[!template text="It supports the superchip 8 extensions." start="00:01:24.000" video="mainVideo" id=subtitle]]
+[[!template text="It runs at full speed." start="00:01:26.159" video="mainVideo" id=subtitle]]
+[[!template text="All games behave okay, as far as I'm concerned," start="00:01:27.280" video="mainVideo" id=subtitle]]
+[[!template text="and yeah, I'm pretty happy with it." start="00:01:29.600" video="mainVideo" id=subtitle]]
+[[!template text="It's very much the hello world of emulation," start="00:01:31.680" video="mainVideo" id=subtitle]]
+[[!template text="and I might, maybe, do some other emulation projects in the future." start="00:01:34.479" video="mainVideo" id=subtitle]]
+[[!template new="1" text="Now, for the section which is the longest:" start="00:01:40.880" video="mainVideo" id=subtitle]]
+[[!template text="bunch of fun facts about chip8.el" start="00:01:43.360" video="mainVideo" id=subtitle]]
+[[!template text="which I've learned during this project." start="00:01:45.439" video="mainVideo" id=subtitle]]
+[[!template text="So what the hell is chip8 anyway?" start="00:01:49.200" video="mainVideo" id=subtitle]]
+[[!template text="First of all, unlike many other emulation game things," start="00:01:51.759" video="mainVideo" id=subtitle]]
+[[!template text="it's not a console, but a VM." start="00:01:54.960" video="mainVideo" id=subtitle]]
+[[!template text="It was designed for easy porting of home computer games." start="00:01:56.799" video="mainVideo" id=subtitle]]
+[[!template text="It wasn't terribly successful," start="00:02:00.000" video="mainVideo" id=subtitle]]
+[[!template text="but there's still a small community of enthusiasts writing games for it," start="00:02:02.320" video="mainVideo" id=subtitle]]
+[[!template text="and there are even a few demos." start="00:02:05.439" video="mainVideo" id=subtitle]]
+[[!template text="This VM has system specs." start="00:02:09.119" video="mainVideo" id=subtitle]]
+[[!template text="It has a very, very simple 8-bit cpu with 16 registers," start="00:02:11.039" video="mainVideo" id=subtitle]]
+[[!template text="and 36 fixed-size instructions." start="00:02:14.720" video="mainVideo" id=subtitle]]
+[[!template text="You have a whole 4 kilobyte of RAM." start="00:02:17.280" video="mainVideo" id=subtitle]]
+[[!template text="You have a stack with 16 return addresses." start="00:02:19.680" video="mainVideo" id=subtitle]]
+[[!template text="The resolution is 64 by 32 black/white pixels." start="00:02:22.080" video="mainVideo" id=subtitle]]
+[[!template new="1" text="Rendering is done by drawing sprites." start="00:02:25.760" video="mainVideo" id=subtitle]]
+[[!template text="These are drawn in XOR mode," start="00:02:28.000" video="mainVideo" id=subtitle]]
+[[!template text="meaning that if you draw a sprite and set a bit," start="00:02:29.200" video="mainVideo" id=subtitle]]
+[[!template text="it just flips over from black to white or white to black." start="00:02:31.840" video="mainVideo" id=subtitle]]
+[[!template text="For sound, you have a monotone buzzer that can just beep at one frequency." start="00:02:35.040" video="mainVideo" id=subtitle]]
+[[!template text="Most unusually, there's a hexadecimal keypad as input," start="00:02:39.360" video="mainVideo" id=subtitle]]
+[[!template text="so the keys are basically zero to nine and a to f." start="00:02:43.120" video="mainVideo" id=subtitle]]
+[[!template text="So how does this whole thing work?" start="00:02:48.480" video="mainVideo" id=subtitle]]
+[[!template text="It runs at an unspecified speed." start="00:02:50.720" video="mainVideo" id=subtitle]]
+[[!template text="You'll probably have to do some fine-tuning" start="00:02:52.400" video="mainVideo" id=subtitle]]
+[[!template text="to find the speed you're happy with." start="00:02:53.040" video="mainVideo" id=subtitle]]
+[[!template new="1" text="Sound and delay timers exist." start="00:02:56.080" video="mainVideo" id=subtitle]]
+[[!template text="They count down at 60fps down to 0." start="00:02:58.080" video="mainVideo" id=subtitle]]
+[[!template text="This is done so that you can play a sound at some specific time." start="00:03:01.120" video="mainVideo" id=subtitle]]
+[[!template text="The game itself is loaded with a fixed offset into RAM." start="00:03:05.120" video="mainVideo" id=subtitle]]
+[[!template text="The program counter is set to exactly that offset," start="00:03:07.840" video="mainVideo" id=subtitle]]
+[[!template text="and from there it enters the game loop" start="00:03:10.480" video="mainVideo" id=subtitle]]
+[[!template text="where it decodes an instruction," start="00:03:11.920" video="mainVideo" id=subtitle]]
+[[!template text="executes it for the side effects," start="00:03:13.280" video="mainVideo" id=subtitle]]
+[[!template text="and just loops and does this ad infinitum." start="00:03:14.800" video="mainVideo" id=subtitle]]
+[[!template new="1" text="So the game loop was the first thing where we ran into problems." start="00:03:19.599" video="mainVideo" id=subtitle]]
+[[!template text="The usual game approach is to do stuff," start="00:03:22.720" video="mainVideo" id=subtitle]]
+[[!template text="figure out how long to wait," start="00:03:25.120" video="mainVideo" id=subtitle]]
+[[!template text="wait for exactly that much, and repeat." start="00:03:26.640" video="mainVideo" id=subtitle]]
+[[!template text="This doesn't work well in Emacs at all, because, well," start="00:03:29.280" video="mainVideo" id=subtitle]]
+[[!template text="user input, basically." start="00:03:31.680" video="mainVideo" id=subtitle]]
+[[!template text="Emacs is designed to just do whatever it needs to do" start="00:03:34.959" video="mainVideo" id=subtitle]]
+[[!template text="whenever you enter user input" start="00:03:37.760" video="mainVideo" id=subtitle]]
+[[!template text="instead of doing things at one specific time." start="00:03:39.040" video="mainVideo" id=subtitle]]
+[[!template text="If you try to do interruptable sleep, well, you get unpredictable behavior." start="00:03:42.319" video="mainVideo" id=subtitle]]
+[[!template text="For example, it can be the timer doesn't run at all at the next time" start="00:03:46.640" video="mainVideo" id=subtitle]]
+[[!template text="because you've accidentally cancelled it." start="00:03:50.480" video="mainVideo" id=subtitle]]
+[[!template text="If you do uninterruptable sleep, it freezes instead ," start="00:03:52.560" video="mainVideo" id=subtitle]]
+[[!template text="which isn't what we want either." start="00:03:55.120" video="mainVideo" id=subtitle]]
+[[!template new="1" text="So I went for timers, which forced me to do inversion of control," start="00:03:56.720" video="mainVideo" id=subtitle]]
+[[!template text="meaning that I have to write code in the style" start="00:04:00.560" video="mainVideo" id=subtitle]]
+[[!template text="where it just calls timer," start="00:04:02.560" video="mainVideo" id=subtitle]]
+[[!template text="and this allows this input to happen" start="00:04:04.879" video="mainVideo" id=subtitle]]
+[[!template text="and for things to progress at roughly the speed I want to." start="00:04:06.560" video="mainVideo" id=subtitle]]
+[[!template text="So there's the timer function which is called at 60fps" start="00:04:11.040" video="mainVideo" id=subtitle]]
+[[!template text="and I have to be very careful to not do too much in it." start="00:04:14.159" video="mainVideo" id=subtitle]]
+[[!template text="And, say, this function executes CPU cycles," start="00:04:17.359" video="mainVideo" id=subtitle]]
+[[!template text="decrement the sound/delay registers, and redraw the screen." start="00:04:21.305" video="mainVideo" id=subtitle]]
+[[!template new="1" text="So to map this whole system to Emacs Lisp," start="00:04:26.479" video="mainVideo" id=subtitle]]
+[[!template text="I've used just integers and vectors" start="00:04:28.800" video="mainVideo" id=subtitle]]
+[[!template text="which contain even more integers." start="00:04:31.199" video="mainVideo" id=subtitle]]
+[[!template text="This is used for the RAM, registers," start="00:04:33.120" video="mainVideo" id=subtitle]]
+[[!template text="return stack, key state, screen," start="00:04:35.040" video="mainVideo" id=subtitle]]
+[[!template text="and so on and so forth." start="00:04:37.040" video="mainVideo" id=subtitle]]
+[[!template text="Basically, what you would do if you were writing C." start="00:04:38.508" video="mainVideo" id=subtitle]]
+[[!template text="All of this is stored in global variables." start="00:04:41.520" video="mainVideo" id=subtitle]]
+[[!template text="I'm not using any lists at all." start="00:04:43.360" video="mainVideo" id=subtitle]]
+[[!template text="As a side effect, there's no consing going on at all." start="00:04:45.600" video="mainVideo" id=subtitle]]
+[[!template text="There are no extra objects created" start="00:04:48.400" video="mainVideo" id=subtitle]]
+[[!template text="which would trigger garbage collection processes." start="00:04:50.080" video="mainVideo" id=subtitle]]
+[[!template text="Getting this right was rather tricky, actually," start="00:04:53.199" video="mainVideo" id=subtitle]]
+[[!template text="and there were some hidden garbage collection problems" start="00:04:55.600" video="mainVideo" id=subtitle]]
+[[!template text="which I had to resolve over time." start="00:04:58.240" video="mainVideo" id=subtitle]]
+[[!template new="1" text="So, decoding instructions." start="00:05:01.759" video="mainVideo" id=subtitle]]
+[[!template text="For this, you have to know that all instructions are two bytes long," start="00:05:03.759" video="mainVideo" id=subtitle]]
+[[!template text="and the arguments are encoded inside them." start="00:05:06.800" video="mainVideo" id=subtitle]]
+[[!template text="For example, the jump to address instruction" start="00:05:08.880" video="mainVideo" id=subtitle]]
+[[!template text="is encoded as one and three hex digits." start="00:05:11.440" video="mainVideo" id=subtitle]]
+[[!template text="The type is extracted masking with #xF000" start="00:05:15.120" video="mainVideo" id=subtitle]]
+[[!template text="and then shifting it by 12 bits." start="00:05:18.400" video="mainVideo" id=subtitle]]
+[[!template text="Mask means you perform the binary AND." start="00:05:20.400" video="mainVideo" id=subtitle]]
+[[!template text="You can do the same with the argument by masking with #0xFFF and no shift." start="00:05:23.520" video="mainVideo" id=subtitle]]
+[[!template text="If you do this long enough, you'll find common patterns." start="00:05:28.400" video="mainVideo" id=subtitle]]
+[[!template text="For example, addresses are always encoded like this" start="00:05:30.560" video="mainVideo" id=subtitle]]
+[[!template text="using the last three nibbles." start="00:05:32.639" video="mainVideo" id=subtitle]]
+[[!template text="In the code, you'll find a big cond" start="00:05:34.880" video="mainVideo" id=subtitle]]
+[[!template text="which dispatches on the type and executes it for the side effects." start="00:05:36.160" video="mainVideo" id=subtitle]]
+[[!template new="1" text="For testing, I've initially just executed the ROM until I've hit C-g," start="00:05:41.440" video="mainVideo" id=subtitle]]
+[[!template text="and then use the debug command to render the screen to a buffer." start="00:05:45.919" video="mainVideo" id=subtitle]]
+[[!template text="Later on, I found tiny ROMs that just display a static test screen," start="00:05:49.039" video="mainVideo" id=subtitle]]
+[[!template text="for example, logo, and looked whether it looked right." start="00:05:53.199" video="mainVideo" id=subtitle]]
+[[!template text="I added instructions as needed" start="00:05:57.280" video="mainVideo" id=subtitle]]
+[[!template text="and went through more and more and more ROMs." start="00:05:58.800" video="mainVideo" id=subtitle]]
+[[!template text="And later I wrote a unit test suite as a safety net." start="00:06:00.720" video="mainVideo" id=subtitle]]
+[[!template text="This unit test suite, it just sets up an empty emulator state," start="00:06:04.000" video="mainVideo" id=subtitle]]
+[[!template text="executes some instructions," start="00:06:07.840" video="mainVideo" id=subtitle]]
+[[!template text="and then looks whether the expected side effects have happened." start="00:06:09.199" video="mainVideo" id=subtitle]]
+[[!template new="1" text="For debugging, I usually use edebug, but this was super ineffective," start="00:06:14.880" video="mainVideo" id=subtitle]]
+[[!template text="because, well, you don't really want to step through big cons" start="00:06:18.319" video="mainVideo" id=subtitle]]
+[[!template text="doing side effects for every single cycle," start="00:06:21.600" video="mainVideo" id=subtitle]]
+[[!template text="when it can take like 100 cycles for things to happen." start="00:06:23.680" video="mainVideo" id=subtitle]]
+[[!template text="Therefore I've set up logging." start="00:06:26.880" video="mainVideo" id=subtitle]]
+[[!template text="Whenever I logged something and couldn't figure out the error," start="00:06:29.680" video="mainVideo" id=subtitle]]
+[[!template text="I compared my log output with the instrumented version of another emulator," start="00:06:32.639" video="mainVideo" id=subtitle]]
+[[!template text="and if the logs diverge, then I have figured out where the bug lies" start="00:06:37.039" video="mainVideo" id=subtitle]]
+[[!template text="and could look deeper into it." start="00:06:40.479" video="mainVideo" id=subtitle]]
+[[!template text="Future project idea might be a chip 8 debugger," start="00:06:42.720" video="mainVideo" id=subtitle]]
+[[!template text="but I doubt I'll ever go into it." start="00:06:44.960" video="mainVideo" id=subtitle]]
+[[!template new="1" text="For analysis, I initially wrote a disassembler," start="00:06:49.440" video="mainVideo" id=subtitle]]
+[[!template text="which is a very simple thing but super tedious," start="00:06:51.759" video="mainVideo" id=subtitle]]
+[[!template text="especially if you wanted to add advanced functionality," start="00:06:54.400" video="mainVideo" id=subtitle]]
+[[!template text="for example, analysis or thinking of what part is data," start="00:06:56.639" video="mainVideo" id=subtitle]]
+[[!template text="what part is code." start="00:06:58.720" video="mainVideo" id=subtitle]]
+[[!template text="I had this great idea for using the radare 2 framework" start="00:07:00.000" video="mainVideo" id=subtitle]]
+[[!template text="and adding analysis and disassembly plug-in for it." start="00:07:03.360" video="mainVideo" id=subtitle]]
+[[!template text="So I looked into this. Found, okay," start="00:07:06.479" video="mainVideo" id=subtitle]]
+[[!template text="you can write plugins in C" start="00:07:08.400" video="mainVideo" id=subtitle]]
+[[!template text="but also in Python, so I wrote one in Python," start="00:07:10.319" video="mainVideo" id=subtitle]]
+[[!template text="and then discovered there's actually an existing one in core," start="00:07:12.639" video="mainVideo" id=subtitle]]
+[[!template text="which you have to enable explicitly by passing an extra argument." start="00:07:14.720" video="mainVideo" id=subtitle]]
+[[!template text="I've tried it and found it's not exactly as good as my own one," start="00:07:18.400" video="mainVideo" id=subtitle]]
+[[!template text="so I improved this one and submitted pull requests" start="00:07:21.680" video="mainVideo" id=subtitle]]
+[[!template text="until it was at the same level." start="00:07:24.160" video="mainVideo" id=subtitle]]
+[[!template new="1" text="Rendering was the trickiest part of this whole thing," start="00:07:28.080" video="mainVideo" id=subtitle]]
+[[!template text="because, well, I decided against using a library." start="00:07:30.720" video="mainVideo" id=subtitle]]
+[[!template text="Not like there would have been any usable library for this." start="00:07:34.319" video="mainVideo" id=subtitle]]
+[[!template text="My usual approach of creating SVG files was too expensive." start="00:07:37.120" video="mainVideo" id=subtitle]]
+[[!template text="It just created too much garbage and took too long time." start="00:07:40.880" video="mainVideo" id=subtitle]]
+[[!template text="I then tried creating mutating strings." start="00:07:45.120" video="mainVideo" id=subtitle]]
+[[!template text="This was either too expensive, just like SVGs, or too complicated." start="00:07:47.360" video="mainVideo" id=subtitle]]
+[[!template text="I tried changing SVG tiles, which created gaps between the lines." start="00:07:52.479" video="mainVideo" id=subtitle]]
+[[!template text="Then I tried to create an xpm file which was backed by a bool vector" start="00:07:57.280" video="mainVideo" id=subtitle]]
+[[!template text="and mutating this bool vector," start="00:08:00.720" video="mainVideo" id=subtitle]]
+[[!template text="but the image caching effect" start="00:08:02.400" video="mainVideo" id=subtitle]]
+[[!template text="made it just every nth frame to appear," start="00:08:04.000" video="mainVideo" id=subtitle]]
+[[!template text="which wasn't good either." start="00:08:06.479" video="mainVideo" id=subtitle]]
+[[!template text="Then I had the idea to just use plain text" start="00:08:08.879" video="mainVideo" id=subtitle]]
+[[!template text="and paint the individual characters" start="00:08:11.440" video="mainVideo" id=subtitle]]
+[[!template text="with a different background color." start="00:08:13.120" video="mainVideo" id=subtitle]]
+[[!template text="This had perfect, perfect performance." start="00:08:14.800" video="mainVideo" id=subtitle]]
+[[!template text="There were many optimization attempts until I got there," start="00:08:17.120" video="mainVideo" id=subtitle]]
+[[!template text="and it was very, very stressful." start="00:08:19.280" video="mainVideo" id=subtitle]]
+[[!template text="I wasn't sure whether I would ever get to accept the performance at all." start="00:08:21.199" video="mainVideo" id=subtitle]]
+[[!template new="1" text="For sound, you only need to do a single beep," start="00:08:26.160" video="mainVideo" id=subtitle]]
+[[!template text="so technically, it shouldn't be difficult to emulate it." start="00:08:28.560" video="mainVideo" id=subtitle]]
+[[!template text="However, doing this is hard because" start="00:08:31.280" video="mainVideo" id=subtitle]]
+[[!template text="Emacs officially only supports synchronous playback of sounds." start="00:08:33.039" video="mainVideo" id=subtitle]]
+[[!template text="But there's also Emacs process, which you can launch in asynchronous way." start="00:08:37.200" video="mainVideo" id=subtitle]]
+[[!template text="So I looked into it and found that mplayer has a slave mode" start="00:08:41.360" video="mainVideo" id=subtitle]]
+[[!template text="and mpv supports listing on the fifo for commands." start="00:08:44.720" video="mainVideo" id=subtitle]]
+[[!template text="So I've created a pipe, started a paused MPV in loop mode," start="00:08:48.640" video="mainVideo" id=subtitle]]
+[[!template text="and always send in pause and unpause command to the FIFO," start="00:08:53.760" video="mainVideo" id=subtitle]]
+[[!template text="and that way I could control" start="00:08:56.560" video="mainVideo" id=subtitle]]
+[[!template text="when to start beeping and stop beeping." start="00:08:58.000" video="mainVideo" id=subtitle]]
+[[!template new="1" text="So yeah, that's it so far." start="00:09:02.640" video="mainVideo" id=subtitle]]
+[[!template text="It was a very educational experience." start="00:09:04.160" video="mainVideo" id=subtitle]]
+[[!template text="I have tried out a bunch of games which were," start="00:09:07.200" video="mainVideo" id=subtitle]]
+[[!template text="well, I almost say the worst ports of classic games I've ever tried." start="00:09:10.320" video="mainVideo" id=subtitle]]
+[[!template text="It wasn't terribly fun to play them," start="00:09:14.320" video="mainVideo" id=subtitle]]
+[[!template text="but was fun to improve the emulator" start="00:09:15.680" video="mainVideo" id=subtitle]]
+[[!template text="until, well, things worked good enough." start="00:09:18.555" video="mainVideo" id=subtitle]]
+[[!template text="I've learned a lot about how computers work at this level," start="00:09:21.760" video="mainVideo" id=subtitle]]
+[[!template text="so, maybe, maybe I'll in the future make another emulator," start="00:09:25.120" video="mainVideo" id=subtitle]]
+[[!template text="but I'm not sure whether anything more advanced, like an Intel 8080 emulator," start="00:09:28.880" video="mainVideo" id=subtitle]]
+[[!template text="will actually run in Emacs fast enough," start="00:09:34.000" video="mainVideo" id=subtitle]]
+[[!template text="but it's still an interesting idea," start="00:09:36.560" video="mainVideo" id=subtitle]]
+[[!template text="because then you could actually have an OS inside Emacs" start="00:09:37.839" video="mainVideo" id=subtitle]]
+[[!template text="and fulfill that one specific meme." start="00:09:40.800" video="mainVideo" id=subtitle]]
+[[!template text="But if I try to do most serious stuff," start="00:09:43.120" video="mainVideo" id=subtitle]]
+[[!template text="I'll probably use Chicken Scheme," start="00:09:45.440" video="mainVideo" id=subtitle]]
+[[!template text="which is my preferred language for serious projects," start="00:09:47.040" video="mainVideo" id=subtitle]]
+[[!template text="and write a NES game emulator." start="00:09:49.920" video="mainVideo" id=subtitle]]
+[[!template text="And that's it. Thank you." start="00:09:53.279" video="mainVideo" id=subtitle]]