[video output=day526 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Single-Buffer Sound Streaming" vod_platform=youtube id=sU56s8w878Q annotator=Miblo]
[0:05][Note the upgrade to ~remedybg 0.2.2.0 with thanks to @x13pixels][:speech]
[1:18][Set up to get our audio streaming into the game, checking out intro_cutscene.hha in TabView][:admin :"asset system"]
[4:06][Streaming audio into 256KiB fixed-size chunks, with thoughts on audio-visual budgetary considerations][:"asset system" :speech]
[8:46][Streaming audio into a crazy sound buffer][:"asset system" :memory :speech]
[12:32][Crazy Sound Buffer][:"asset system" :blackboard :memory]
[17:45][Crazy sound buffer vs fixed-chunk scheme][:"asset system" :blackboard :memory]
[20:22][Implement our crazy sound buffer in LoadSound()][:"asset system" :memory]
[28:18][Note a subtlety that could cause an incorrect sound to be played back][:"asset system" :memory :speech]
[30:24][Continue to implement our crazy sound buffer in LoadSound(), independent of sample bit-depth][:"asset system" :memory]
[33:56][Introduce Agner Fog's instruction tables[ref
    author="Agner Fog"
    title="Optimization manuals: 4. Instruction tables"
    url=https://www.agner.org/optimize/instruction_tables.pdf]][:isa :performance :research]
[38:19][Consult Agner Fog's Skylake instruction table for the performance of DIV instructions[ref
    author="Agner Fog"
    title="Optimization manuals: 4. Instruction tables"
    url=https://www.agner.org/optimize/instruction_tables.pdf]][:isa :performance :research]
[40:19][Add a SampleBufferMappingMask to the game_assets with which LoadSound() may set the SampleBufferIndex using bitwise AND, rather than the less performant modulus][:"asset system" :mathematics :memory :performance]
[42:23][Check the L2 cache latency of an Intel Skylake CPU[ref
    site="7-Zip LZMA Benchmark"
    page="Intel Skylake"
    url=https://www.7-cpu.com/cpu/Skylake.html]][:hardware :performance :research]
[43:39][Continue to implement our crazy sound buffer in LoadSound()][:"asset system" :memory]
[48:02][Reflect on the simplicity of our crazy sound buffer][:"asset system" :memory :speech]
[48:24][Introduce ReserveSoundMemory() for LoadSound() (and the playback function) to know about the area of the crazy sound buffer that should not get evicted][:"asset system" :memory]
[51:33][Enable GetSoundSamples() to play back from our crazy sound buffer, introducing GetSoundBufferMemory()][:"asset system" :memory]
[1:01:48][Awareness of overlap in a circular buffer][:"asset system" :blackboard :memory]
[1:03:49][Make ReserveSoundMemory() return a more informative sound_buffer_memory for LoadSound() and GetSoundSamples() to use][:"asset system" :memory]
[1:11:39][Implement GetSoundBufferRanges()][:"asset system" :memory]
[1:12:53][Introduce InitSoundMemory() for AllocateGameAssets() to call][:"asset system" :memory]
[1:18:13][Reacquaint ourselves with the audio playing code][:"asset system" :research]
[1:21:33][Enable GameUpdateAndRender() to call ChangeVolume() and PlaySound() on our piano music_test.wav][:"asset system"]
[1:27:39][Listen to our piano music_test.wav in-game, to find that only the first chunk plays][:"asset system" :run]
[1:29:04][Make PrefetchSound() call GetSoundSamples() to pull samples into the non-eviction region of our crazy sound buffer][:"asset system" :memory]
[1:31:44][Continue to reacquaint ourselves with OutputPlayingSounds()][:"asset system" :research]
[1:35:04][Make OutputPlayingSounds() correctly compute the SampleCount and retrieve a full hha_asset * from GetSoundInfo()][:"asset system"]
[1:39:40][Listen to our piano music_test.wav in-game, to find that we get choppy playback when we miss our framerate][:"asset system" :run]
[1:41:43][Reacquaint ourselves with the single-play audio code][:"asset system" :research]
[1:45:02][Make ExecuteBrainHero() call PlaySound() on the Glove][:"asset system" :"entity system"]
[1:46:19][Find that we cannot hear the glove][:"asset system" :"entity system" :run]
[1:47:42][Step through ExecuteBrain() to PlaySound() to find that we passed a bogus SoundID][:"asset system" :"entity system" :run]
[1:48:23][Fix ExecuteBrainHero() to only call PlaySound() on attack, rebuild and crash ~remedybg][:"asset system" :"entity system"]
[1:50:13][Step in to ExecuteBrainHero()][:"asset system" :"entity system" :run]
[1:50:49][Make ExecuteBrainHero() set the Weight for our bloop sound asset, rebuild and crash ~remedybg][:"asset system" :"entity system"]
[1:51:16][Try to figure out the repro case for this ~remedybg crash][:admin]
[1:53:03][Step in to ExecuteBrainHero() to determine that GetBestMatchSoundFrom() fails to find a sound][:"asset system" :"entity system" :run]
[1:53:56][~remedybg feature request: Casting to an enum][:admin :language]
[1:55:20][Step through GetBestMatchAssetFrom() to see how it's handling our request for the bloop asset][:"asset system" :run]
[1:57:56][Check out base_game.hha in TabView to find that our bloop audio assets are absent][:admin :"asset system"]
[2:00:44][Check out our import errors][:"asset system" :run]
[2:01:11][Fix typos in base_game.hht][:admin :"asset system"]
[2:01:30][Reimport our assets, step through ExecuteBrainHero() and successfully hear our glove bloop][:"asset system" :"entity system" :run]
[2:02:29][Investigate why we hear the glove bloop on repeat][:"asset system" :"entity system" :research]
[2:04:00][Listen to the repeated audio][:"asset system" :"entity system" :run]
[2:04:40][Temporarily reduce the Entity->tMovement of our glove swipe in UpdateAndRenderEntities()][:"entity system"]
[2:04:45][Find that the bloop audio continues to repeat][:"asset system" :"entity system" :run]
[2:05:40][Fix ExecuteBrainHero() to correctly perform a single attack][:"entity system"]
[2:07:07][See and hear our non-repeated glove attack bloop][:"asset system" :"entity system" :run]
[2:07:14][Revert the Entity->tMovement of our glove swipe in UpdateAndRenderEntities()][:"entity system"]
[2:07:27][Find that our glove is absent][:"entity system" :run]
[2:07:42][Fix ExecuteBrainHero() to float our glove when we're not attacking, rebuild and crash ~remedybg][:"entity system"]
[2:08:10][See and hear our glove in-game, and hear some clicking][:"entity system" :run]
[2:09:01][Q&A][:speech]
[2:09:40][@mtsmox][Q: In the LRU copy path you might have forgotten to set Result?][:memory]
[2:10:25][Fix GetSoundSamples() to set the correct Result][:memory]
[2:10:55][@guybru5h_vi][Q: Just started at a new job that has a gargantuan codebase (in the millions of lines of code) and it's very hard to follow what's going on. Do you have any general advice or approach to gaining an understanding of what's going on in files that are part of very large codebases? Also thanks! It's in a large part thanks to [~hero Handmade Hero] that I managed to land the job!]
[2:15:05][@nickito97][Is there a name for that type of buffer?][:memory]
[2:16:34][@jkfsda][Q: John Carmack likes Rust, is Rust > C++?][:language]
[2:18:41][@ivereadthesequel][Q: On an interview I was given a debugging task on a new piece of code (it was a web scraper written in Python). This company was actually generous enough to provide feedback on performance and said I would have done better if I had "debugged more systematically". Do you have any tips on better debugging practices?]
[2:19:33][@vtlmks][Q: <joke question> Why can't we use the GF2P8AFFINEINVQB instruction all the time?[ref
    site=Intel
    page="Intel Intrinsics Guide"
    url=https://software.intel.com/sites/landingpage/IntrinsicsGuide/][ref
        site=Wikipedia
        page="Finite field arithmetic"
        url=https://en.wikipedia.org/wiki/Finite_field_arithmetic]][:isa :mathematics]
[2:25:00][@panthalassadigital][Q: After reading your "About" on your website, [@cmuratori Casey], what does it mean to be in gaming research and development? What's your company's bread and butter? Are you basically a consultant for other game companies?]
[2:29:57][@ivereadthesequel][Q: Regarding story engines: what sort of advancements are in yours, if you can mention anything? What does it achieve?]
[2:30:43][Close it down with an exercise for the reader: preventing the sound from skipping when we miss our frame rate][:speech]
[/video]
