title
Learn Modern C++ by Building an Audio Plugin (w/ JUCE Framework) - Full Course

description
In this tutorial you will learn modern C++ by building an audio plugin with the JUCE Framework. ✏️ This course was developed by Matkat Music. Check him out on YouTube and Instagram: 🔗 https://www.youtube.com/matkatmusic 🔗 https://www.instagram.com/matkatmusic 💻 Code: https://github.com/matkatmusic/SimpleEQ 💻 Download the completed plugin: https://www.programmingformusicians.com/simpleeq/ 🎉 Check out the PFM::C++ for musicians course: https://www.programmingformusicians.com/pfmcpp/ ⭐️ Extra Resources ⭐️ 🔗 Starting from scratch on MacOS: https://youtu.be/fpYp4nz7CsQ 🔗 Starting from scratch on Windows: https://youtu.be/JHTcLVOcnQ4 🔗 Configuring VisualStudio to run AudioPluginHost automatically on Windows: https://youtu.be/R1KgcfgVGQA ⭐️ Course Contents ⭐️ ⌨️ (0:00:00) Part 1 - Intro ⌨️ (0:02:29) Part 2 - Setting up the Project ⌨️ (0:16:51) Part 3 - Creating Audio Parameters ⌨️ (0:30:32) Part 4 - Setting up the DSP ⌨️ (0:38:55) Part 5 - Setting up Audio Plugin Host ⌨️ (0:44:28) Part 6 - Connecting the Peak Params ⌨️ (0:55:50) Part 7 - Connecting the LowCut Params ⌨️ (1:06:27) Part 8 - Refactoring the DSP ⌨️ (1:26:46) Part 9 - Adding Sliders to GUI ⌨️ (1:40:12) Part 10 - Draw the Response Curve ⌨️ (2:05:02) Part 11 - Build the Response Curve Component ⌨️ (2:10:44) Part 12 - Customize Slider Visuals ⌨️ (3:03:05) Part 13 - Response Curve Grid ⌨️ (3:27:03) Part 14 - Spectrum Analyzer ⌨️ (4:16:55) Part 15 - Bypass Buttons -- Learn to code for free and get a developer job: https://www.freecodecamp.org Read hundreds of articles on programming: https://freecodecamp.org/news

detail
{'title': 'Learn Modern C++ by Building an Audio Plugin (w/ JUCE Framework) - Full Course', 'heatmap': [{'end': 1277.238, 'start': 730.219, 'weight': 0.753}, {'end': 1826.936, 'start': 1638.554, 'weight': 0.963}, {'end': 2925.951, 'start': 1999.927, 'weight': 0.745}, {'end': 4377.716, 'start': 4009.38, 'weight': 0.826}, {'end': 7838.223, 'start': 7654.496, 'weight': 0.802}], 'summary': 'Learn modern c++ by building an audio plugin with juce framework, covering 3-band equalizer creation, audio dsp controls, plugin development, host functionality, customizing plugins, troubleshooting code, drawing shapes, fft analysis, and power button implementation, providing hands-on mentorship and practical guidance.', 'chapters': [{'end': 81.815, 'segs': [{'end': 81.815, 'src': 'embed', 'start': 24.003, 'weight': 0, 'content': [{'end': 30.026, 'text': 'this other plugin is also where you can learn modern C++ and the JUICE framework from scratch,', 'start': 24.003, 'duration': 6.023}, {'end': 33.888, 'text': 'taught from the context of writing audio software in a mentored environment.', 'start': 30.026, 'duration': 3.862}, {'end': 37.949, 'text': "You're not following videos, you're not watching someone else code, and you're not copying them.", 'start': 34.208, 'duration': 3.741}, {'end': 40.951, 'text': "You're coding it yourself, and I'm reviewing your work.", 'start': 38.39, 'duration': 2.561}, {'end': 42.491, 'text': 'Alright, enough about those.', 'start': 41.571, 'duration': 0.92}, {'end': 45.273, 'text': "Let's learn about what we are going to build today.", 'start': 43.012, 'duration': 2.261}, {'end': 49.815, 'text': 'This is a 3-band equalizer with a spectrum analyzer at the top.', 'start': 46.113, 'duration': 3.702}, {'end': 54.836, 'text': 'It has a low cut band, it has a high cut band, and it has a parametric band in the middle.', 'start': 50.715, 'duration': 4.121}, {'end': 58.897, 'text': 'The low cut band lets you cut out all of the low end of the signal.', 'start': 55.576, 'duration': 3.321}, {'end': 61.318, 'text': 'You can also control the steepness of the cut.', 'start': 59.657, 'duration': 1.661}, {'end': 68.4, 'text': 'The high cut band lets you remove all of the high frequencies, and you can also control how steep that cut is.', 'start': 63.559, 'duration': 4.841}, {'end': 78.472, 'text': 'The parametric band lets you add notches or boosts and we can also control how wide or how narrow those boosts are and we can control the frequency.', 'start': 69.844, 'duration': 8.628}, {'end': 81.815, 'text': "Everybody's familiar with this type of swept frequency sound.", 'start': 79.633, 'duration': 2.182}], 'summary': 'Learn modern c++ and juice framework for audio software, mentored coding with 3-band equalizer and spectrum analyzer.', 'duration': 57.812, 'max_score': 24.003, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc24003.jpg'}], 'start': 1.94, 'title': 'Building 3-band equalizer', 'summary': 'Focuses on building a 3-band equalizer with a spectrum analyzer using modern c++ and the juice framework, emphasizing hands-on learning and mentorship in writing audio software.', 'chapters': [{'end': 81.815, 'start': 1.94, 'title': 'Building 3-band equalizer with juice framework', 'summary': 'Focuses on building a 3-band equalizer with a spectrum analyzer using modern c++ and the juice framework, emphasizing hands-on learning and mentorship in writing audio software.', 'duration': 79.875, 'highlights': ['Building a 3-band equalizer with a spectrum analyzer using Modern C++ and the Juice Framework', 'Emphasis on hands-on learning and mentorship in writing audio software', 'Features include low cut, high cut, and parametric bands with adjustable parameters']}], 'duration': 79.875, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc1940.jpg', 'highlights': ['Features include low cut, high cut, and parametric bands with adjustable parameters', 'Emphasis on hands-on learning and mentorship in writing audio software', 'Building a 3-band equalizer with a spectrum analyzer using Modern C++ and the Juice Framework']}, {'end': 745.191, 'segs': [{'end': 118.357, 'src': 'embed', 'start': 83.796, 'weight': 0, 'content': [{'end': 89.501, 'text': "Above that there are bypass buttons which allow you to disable individual bands which is always helpful when you're working on audio.", 'start': 83.796, 'duration': 5.705}, {'end': 95.346, 'text': 'Then above that is the response curve which gives us a visual representation of what the filters are doing.', 'start': 90.142, 'duration': 5.204}, {'end': 100.527, 'text': 'Then behind that is the spectrum analyzer, and this shows us what we are hearing.', 'start': 96.345, 'duration': 4.182}, {'end': 104.349, 'text': "And these always use a bunch of CPUs, so there's a bypass button for that as well.", 'start': 101.228, 'duration': 3.121}, {'end': 107.611, 'text': "We're gonna learn all the DSP that's going on in the background.", 'start': 105.05, 'duration': 2.561}, {'end': 109.032, 'text': 'That makes this thing work.', 'start': 108.091, 'duration': 0.941}, {'end': 112.514, 'text': "We're gonna learn how to draw everything, how to draw the sliders, the bypass buttons,", 'start': 109.192, 'duration': 3.322}, {'end': 118.357, 'text': 'how to draw the response curve and make it respond whenever we adjust the sliders, and how to draw the spectrum analyzer.', 'start': 112.514, 'duration': 5.843}], 'summary': 'Transcript discusses bypass buttons, response curve, and spectrum analyzer for audio processing.', 'duration': 34.561, 'max_score': 83.796, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc83796.jpg'}, {'end': 178.687, 'src': 'embed', 'start': 151.693, 'weight': 1, 'content': [{'end': 155.155, 'text': 'All right, the first thing we need to do is get set up with the JUICE framework.', 'start': 151.693, 'duration': 3.462}, {'end': 159.417, 'text': "Now, if you've never done any audio programming before, fear not.", 'start': 156.155, 'duration': 3.262}, {'end': 164.119, 'text': 'The only things you need are two tools, the JUICE framework and then an IDE to write code in.', 'start': 159.577, 'duration': 4.542}, {'end': 167.26, 'text': 'That could be Xcode or it could be Visual Studio.', 'start': 164.619, 'duration': 2.641}, {'end': 169.381, 'text': "It depends on what operating system you're running.", 'start': 167.28, 'duration': 2.101}, {'end': 172.543, 'text': "I'm on Mac, so I'm going to be using Xcode for this video.", 'start': 169.941, 'duration': 2.602}, {'end': 178.687, 'text': "If you've never set yourself up with an IDE before, I have two videos linked in the description.", 'start': 173.383, 'duration': 5.304}], 'summary': 'Setup juice framework with ide, like xcode or visual studio.', 'duration': 26.994, 'max_score': 151.693, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc151693.jpg'}, {'end': 267.816, 'src': 'embed', 'start': 239.583, 'weight': 7, 'content': [{'end': 241.464, 'text': 'Features are being added, that sort of thing.', 'start': 239.583, 'duration': 1.881}, {'end': 246.248, 'text': "So if I have the repository cloned, I'm able to pull in those changes.", 'start': 241.885, 'duration': 4.363}, {'end': 251.61, 'text': "This is different from if I had just downloaded a zip file, so that's why I'm going to do that.", 'start': 247.268, 'duration': 4.342}, {'end': 253.951, 'text': "Okay, I'm going to go to terminal.", 'start': 252.15, 'duration': 1.801}, {'end': 256.492, 'text': "If you don't have terminal open, just, you know, terminal.", 'start': 254.231, 'duration': 2.261}, {'end': 259.753, 'text': 'Open it like that, or open some kind of command prompt shell.', 'start': 257.031, 'duration': 2.722}, {'end': 267.816, 'text': "Okay, then I'm going to, let's see, I've got my users folder right here, and I'm just going to clone the repository right into that.", 'start': 259.773, 'duration': 8.043}], 'summary': 'Adding features and cloning repository with terminal.', 'duration': 28.233, 'max_score': 239.583, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc239583.jpg'}, {'end': 317.518, 'src': 'embed', 'start': 284.434, 'weight': 8, 'content': [{'end': 285.155, 'text': 'All right, there it goes.', 'start': 284.434, 'duration': 0.721}, {'end': 286.236, 'text': "There's the juice framework.", 'start': 285.355, 'duration': 0.881}, {'end': 297.726, 'text': 'Now, what we want to do is switch to the develop branch because, as I had shown, it contains more recent changes than the other branch.', 'start': 286.896, 'duration': 10.83}, {'end': 301.53, 'text': 'You can see that the develop branch is 19 commits ahead of the master branch.', 'start': 297.806, 'duration': 3.724}, {'end': 304.553, 'text': 'So to do that, we need to type in terminal.', 'start': 302.371, 'duration': 2.182}, {'end': 306.955, 'text': 'First, we need to go into the juice folder.', 'start': 305.253, 'duration': 1.702}, {'end': 309.077, 'text': "So let's do that right now.", 'start': 308.176, 'duration': 0.901}, {'end': 317.518, 'text': 'And now we need to do git checkout develop, like that.', 'start': 312.504, 'duration': 5.014}], 'summary': 'Switch to develop branch with 19 commits ahead of master.', 'duration': 33.084, 'max_score': 284.434, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc284434.jpg'}, {'end': 452.304, 'src': 'embed', 'start': 424.716, 'weight': 4, 'content': [{'end': 429.578, 'text': "Now it's going to run it, and then we will be able to configure this stuff.", 'start': 424.716, 'duration': 4.862}, {'end': 431.138, 'text': "All right, so let's get this set up.", 'start': 429.618, 'duration': 1.52}, {'end': 435.6, 'text': 'Okay, we are presented with the new project wizard.', 'start': 432.439, 'duration': 3.161}, {'end': 440.561, 'text': 'Before we do that, we want to go to Projuicer and we want to configure our global paths.', 'start': 436.52, 'duration': 4.041}, {'end': 445.062, 'text': 'And these need to point to the juice folder and the modules folder.', 'start': 441.101, 'duration': 3.961}, {'end': 452.304, 'text': 'Now the juice folder, by default, if you clone the repository to your users folder, this stuff is going to be set automatically.', 'start': 445.383, 'duration': 6.921}], 'summary': 'Configuring global paths in projuicer to point to juice and modules folders for repository cloned to users folder.', 'duration': 27.588, 'max_score': 424.716, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc424716.jpg'}, {'end': 524.222, 'src': 'embed', 'start': 481.637, 'weight': 5, 'content': [{'end': 490.061, 'text': "Once that is done, now you can go to the plugin right here, basic, and we're going to create a project called Simple EQ.", 'start': 481.637, 'duration': 8.424}, {'end': 494.628, 'text': "And then we can do create project and it's going to ask me where do I want to save this.", 'start': 491.161, 'duration': 3.467}, {'end': 496.211, 'text': 'Create project.', 'start': 495.25, 'duration': 0.961}, {'end': 498.376, 'text': 'I want to save it to this programming folder.', 'start': 496.652, 'duration': 1.724}, {'end': 501.127, 'text': 'And there it goes.', 'start': 500.487, 'duration': 0.64}, {'end': 501.807, 'text': "It's going to save it.", 'start': 501.167, 'duration': 0.64}, {'end': 502.428, 'text': "It's going to make it.", 'start': 501.867, 'duration': 0.561}, {'end': 507.289, 'text': 'And now if I reveal in Finder, here is my project.', 'start': 503.048, 'duration': 4.241}, {'end': 513.791, 'text': 'So I am going to make a Git repository next before I actually take a look around at the code,', 'start': 507.789, 'duration': 6.002}, {'end': 521.134, 'text': "because it's always important to set yourself up with the Git repository in case you have to backtrack and undo some stuff or whatnot.", 'start': 513.791, 'duration': 7.343}, {'end': 522.433, 'text': "So I'm going to do that next.", 'start': 521.494, 'duration': 0.939}, {'end': 524.222, 'text': 'All right.', 'start': 523.683, 'duration': 0.539}], 'summary': "Created project 'simple eq' in programming folder and set up git repository.", 'duration': 42.585, 'max_score': 481.637, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc481637.jpg'}], 'start': 83.796, 'title': 'Audio dsp controls and juice framework setup', 'summary': 'Covers audio dsp controls like bypass buttons and response curve, and the significance of spectrum analyzer, consuming cpu. it also provides a guide for setting up juice framework for audio software using modern c++, including repository cloning, branch switching, and projuicer for project creation.', 'chapters': [{'end': 118.357, 'start': 83.796, 'title': 'Audio dsp controls and visualization', 'summary': 'Covers audio dsp controls including bypass buttons and response curve, and the significance of the spectrum analyzer in visualizing audio, all of which require cpu usage.', 'duration': 34.561, 'highlights': ['The chapter covers audio DSP controls including bypass buttons and response curve.', 'Significance of the spectrum analyzer in visualizing audio.', 'CPU usage required for these DSP controls.']}, {'end': 424.216, 'start': 119.611, 'title': 'Setting up audio software with juice framework', 'summary': 'Guides on setting up the juice framework for audio software development using modern c++, including cloning the repository, switching to the develop branch, and using projuicer to make a project.', 'duration': 304.605, 'highlights': ['The chapter covers the process of setting up the JUICE framework for audio software development using modern C++ and the JUICE framework from scratch.', 'It emphasizes the importance of cloning the repository rather than downloading a zip file to ensure access to the latest changes and additions.', 'The chapter provides detailed steps on switching to the develop branch and using Projuicer to make a project for audio software development.']}, {'end': 745.191, 'start': 424.716, 'title': 'Setting up project and git repository', 'summary': 'Details the process of setting up a new project in projuicer, configuring global paths to the juice and modules folders, creating a project called simple eq, and then setting up a git repository using terminal, while explaining the gitignore file and initial commit.', 'duration': 320.475, 'highlights': ['The process of setting up a new project in Projuicer and configuring global paths to the juice and modules folders is explained, including the option to rescan for any issues (relevance score: 5)', 'The detailed steps for creating a project called Simple EQ in the plugin and saving it to a specific folder are outlined (relevance score: 4)', 'The detailed process of setting up a Git repository using terminal, including creating a gitignore file to exclude specific folders, doing an initial commit, and tracking the files, is explained (relevance score: 3)']}], 'duration': 661.395, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc83796.jpg', 'highlights': ['The chapter covers audio DSP controls including bypass buttons and response curve.', 'The chapter covers the process of setting up the JUICE framework for audio software development using modern C++ and the JUICE framework from scratch.', 'Significance of the spectrum analyzer in visualizing audio.', 'CPU usage required for these DSP controls.', 'The process of setting up a new project in Projuicer and configuring global paths to the juice and modules folders is explained, including the option to rescan for any issues.', 'The detailed steps for creating a project called Simple EQ in the plugin and saving it to a specific folder are outlined.', 'The detailed process of setting up a Git repository using terminal, including creating a gitignore file to exclude specific folders, doing an initial commit, and tracking the files, is explained.', 'It emphasizes the importance of cloning the repository rather than downloading a zip file to ensure access to the latest changes and additions.', 'The chapter provides detailed steps on switching to the develop branch and using Projuicer to make a project for audio software development.']}, {'end': 2312.01, 'segs': [{'end': 851.888, 'src': 'embed', 'start': 820.692, 'weight': 0, 'content': [{'end': 825.956, 'text': 'you cannot interrupt that chain of events If you add latency or whatever.', 'start': 820.692, 'duration': 5.264}, {'end': 832.499, 'text': 'it can cause clicks and pops in your speakers, and that has the potential to damage speakers as well as explode eardrums.', 'start': 825.956, 'duration': 6.543}, {'end': 844.724, 'text': "Just imagine this scenario that you're at a club and the sound system is super loud and your plugin causes a pop or a glitch, and the sound engineer,", 'start': 833.439, 'duration': 11.285}, {'end': 851.888, 'text': "or the DJ or whatever has their thing totally cranked and there's just this huge pop and everybody's ears just go.", 'start': 844.724, 'duration': 7.164}], 'summary': 'Latency can cause clicks and pops, damaging speakers and eardrums, risking hearing damage.', 'duration': 31.196, 'max_score': 820.692, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc820692.jpg'}, {'end': 1165.965, 'src': 'embed', 'start': 1141.408, 'weight': 1, 'content': [{'end': 1147.892, 'text': 'For the low cut and high cut bands, we will be able to control the frequency cutoff as well as the slope of the cutoff.', 'start': 1141.408, 'duration': 6.484}, {'end': 1155.237, 'text': 'For the peak or parametric band, we will be able to control the center frequency, the gain and the quality,', 'start': 1148.773, 'duration': 6.464}, {'end': 1158.099, 'text': 'meaning how narrow or how wide the peak is.', 'start': 1155.237, 'duration': 2.862}, {'end': 1162.542, 'text': 'All right, so we will start with the low cut and high cut frequency parameters.', 'start': 1158.119, 'duration': 4.423}, {'end': 1165.965, 'text': 'And JUIC has an audio processor parameter class.', 'start': 1163.283, 'duration': 2.682}], 'summary': 'Control frequency cutoff and slope for low and high cut bands, and center frequency, gain, and quality for peak band in audio processor parameter class.', 'duration': 24.557, 'max_score': 1141.408, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc1141408.jpg'}, {'end': 1626.447, 'src': 'embed', 'start': 1598.267, 'weight': 2, 'content': [{'end': 1604.992, 'text': '1.F Alright, for the low cut and high cut filters, I want to have the ability to change the steepness of the filter cut.', 'start': 1598.267, 'duration': 6.725}, {'end': 1609.035, 'text': 'So I will give myself four different options.', 'start': 1605.893, 'duration': 3.142}, {'end': 1618.503, 'text': 'Our cut filters are normally expressed in decibels per octave, or their responses are normally expressed in decibels per octave.', 'start': 1609.676, 'duration': 8.827}, {'end': 1626.447, 'text': 'sorry the way the math behind the filter equations works ends up expressing these choices in multiples of 6 or 12.', 'start': 1618.943, 'duration': 7.504}], 'summary': 'Adjust filter steepness with 4 options, expressed in multiples of 6 or 12.', 'duration': 28.18, 'max_score': 1598.267, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc1598267.jpg'}, {'end': 1826.936, 'src': 'heatmap', 'start': 1638.554, 'weight': 0.963, 'content': [{'end': 1647.02, 'text': 'So because we are using specific choices and not a range of values like with these sliders This means we get to use the audio parameter choice object.', 'start': 1638.554, 'duration': 8.466}, {'end': 1651.943, 'text': "So I'll show you what that's like Audio parameter choice.", 'start': 1647.34, 'duration': 4.603}, {'end': 1655.664, 'text': "So that's this thing right here, This thing.", 'start': 1651.943, 'duration': 3.721}, {'end': 1658.586, 'text': 'it needs a string array that represents the choices.', 'start': 1655.664, 'duration': 2.922}, {'end': 1666.148, 'text': 'And because both the low cut and high cut will use the same set of choices, I only need to create this string array once.', 'start': 1659.126, 'duration': 7.022}, {'end': 1668.029, 'text': "So we're going to do that first.", 'start': 1666.408, 'duration': 1.621}, {'end': 1669.129, 'text': 'Let me get rid of this line.', 'start': 1668.049, 'duration': 1.08}, {'end': 1671.15, 'text': 'Let me scroll up.', 'start': 1670.27, 'duration': 0.88}, {'end': 1673.751, 'text': "Okay, so let's make our string array.", 'start': 1671.91, 'duration': 1.841}, {'end': 1676.352, 'text': "And now we're going to do four choices.", 'start': 1674.771, 'duration': 1.581}, {'end': 1684.874, 'text': 'And now we are going to construct something that says 12 dB per oct, or 24, and we can do that like this.', 'start': 1677.672, 'duration': 7.202}, {'end': 1689.555, 'text': 'All right, that should make a lot of sense.', 'start': 1687.775, 'duration': 1.78}, {'end': 1692.416, 'text': "Default. value is zero, so we've got.", 'start': 1689.795, 'duration': 2.621}, {'end': 1697.538, 'text': "I'm sorry, i's first value is zero, so we've got 12 plus zero, then 12 plus 12, 12 plus 24, 12 plus 36, that gives us 12, 24, 36, 48..", 'start': 1692.416, 'duration': 5.122}, {'end': 1699.798, 'text': "And then we're just sticking dB per octave on the end of that string.", 'start': 1697.538, 'duration': 2.26}, {'end': 1714.598, 'text': 'All right now we just need to create the audio parameter choice and give it the string array of choices and use the default value of zero,', 'start': 1707.452, 'duration': 7.146}, {'end': 1718.961, 'text': 'meaning the filter will have a default slope of 12 dB per octave.', 'start': 1714.598, 'duration': 4.363}, {'end': 1719.862, 'text': "Let's create that now.", 'start': 1719.121, 'duration': 0.741}, {'end': 1724.045, 'text': 'This is going to be called low cut slope.', 'start': 1720.803, 'duration': 3.242}, {'end': 1726.888, 'text': 'Choice is going to be our string array.', 'start': 1725.226, 'duration': 1.662}, {'end': 1729.55, 'text': 'And our default index will be zero.', 'start': 1728.189, 'duration': 1.361}, {'end': 1734.914, 'text': 'And we just need to duplicate this line for the high cut as well.', 'start': 1731.411, 'duration': 3.503}, {'end': 1740.546, 'text': 'All right now we have got our parameters set up in our parameter layout,', 'start': 1736.664, 'duration': 3.882}, {'end': 1746.95, 'text': 'so we can just return it and pass it to the audio processor tree value state constructor, which we have already done.', 'start': 1740.546, 'duration': 6.404}, {'end': 1750.813, 'text': 'We already did that right here.', 'start': 1748.912, 'duration': 1.901}, {'end': 1758.457, 'text': 'All right, now if we run the app as it is right now, we are not going to see anything other than that hello world.', 'start': 1750.833, 'duration': 7.624}, {'end': 1761.259, 'text': "And that's because we haven't added anything to our GUI.", 'start': 1759.018, 'duration': 2.241}, {'end': 1773.538, 'text': 'But if I go up to the create editor function, we can use the generic audio processor editor to see what our parameters look like.', 'start': 1761.92, 'duration': 11.618}, {'end': 1774.358, 'text': "So let's do that.", 'start': 1773.718, 'duration': 0.64}, {'end': 1775.379, 'text': "We're going to comment that line out.", 'start': 1774.378, 'duration': 1.001}, {'end': 1785.302, 'text': "We're going to write return new generic audio processor editor, and it's going to be this.", 'start': 1775.839, 'duration': 9.463}, {'end': 1791.084, 'text': 'Okay, so if we run it and take a look, first of all, make sure you are in standalone mode.', 'start': 1786.282, 'duration': 4.802}, {'end': 1795.625, 'text': 'If we run it, we are going to see some good stuff.', 'start': 1791.964, 'duration': 3.661}, {'end': 1802.015, 'text': 'Okay, if we look at our combo boxes, we can see that our slope controls show up this way.', 'start': 1797.532, 'duration': 4.483}, {'end': 1804.777, 'text': "Here's our 12, 24, 36, and 48.", 'start': 1802.055, 'duration': 2.722}, {'end': 1813.223, 'text': 'Peak control, default value of 1, we can see it goes 0.1, 1.5, 2.5, all the way up to 10.', 'start': 1804.777, 'duration': 8.446}, {'end': 1817.746, 'text': "And then for our gain, we've got 24.", 'start': 1813.223, 'duration': 4.523}, {'end': 1821.308, 'text': "We can see that it's stepping by half of a decibel every time.", 'start': 1817.746, 'duration': 3.562}, {'end': 1826.936, 'text': 'Okay, so next we will work on the signal processing side of things.', 'start': 1822.532, 'duration': 4.404}], 'summary': 'Creating audio parameter choices for low and high cut filters, default slope of 12 db per octave, shown in gui editor.', 'duration': 188.382, 'max_score': 1638.554, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc1638554.jpg'}, {'end': 2137.33, 'src': 'embed', 'start': 2106.906, 'weight': 3, 'content': [{'end': 2118.054, 'text': 'Now we need two instances of this mono chain if we want to do stereo processing and to have access to the filter instances in order to adjust their cutoff,', 'start': 2106.906, 'duration': 11.148}, {'end': 2119.535, 'text': 'gain quality or slope.', 'start': 2118.054, 'duration': 1.481}, {'end': 2120.916, 'text': "So let's declare that now.", 'start': 2119.855, 'duration': 1.061}, {'end': 2122.978, 'text': 'Mono chain.', 'start': 2122.057, 'duration': 0.921}, {'end': 2126.16, 'text': 'We got the left channel and the right.', 'start': 2123.738, 'duration': 2.422}, {'end': 2133.489, 'text': 'Cool Now before we can use our our filter chains, we need to prepare them.', 'start': 2128.246, 'duration': 5.243}, {'end': 2137.33, 'text': "So let's go over to our prepare to play and do that.", 'start': 2133.749, 'duration': 3.581}], 'summary': 'Two instances of mono chain needed for stereo processing and filter adjustment.', 'duration': 30.424, 'max_score': 2106.906, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc2106906.jpg'}], 'start': 745.891, 'title': 'Audio plugin development', 'summary': 'Provides an overview of key source code files and functions, emphasizes managing audio processing within a fixed time, discusses audio processor parameter setup, implementation of filter slope options, and integration of dsp modules using juice dsp framework and c++17 language.', 'chapters': [{'end': 1119.438, 'start': 745.891, 'title': 'Audio plugin source code overview', 'summary': 'Provides a brief overview of key source code files and functions, focusing on pluginprocessor.cpp, pluginprocessor.h, plugineditor.cpp, and plugineditor.h. it explains the crucial functions preparetoplay and process block, emphasizing the importance of managing audio processing within a fixed time, and it highlights the setup of visual elements in the plugin editor.', 'duration': 373.547, 'highlights': ['The chapter emphasizes the crucial functions prepareToPlay and process block, which are the main focus of the source code, and explains the importance of managing audio processing within a fixed time to prevent issues like clicks, pops, and potential damage to speakers and eardrums.', 'It highlights the setup of visual elements in the plugin editor, explaining the use of constructors, paint function, and resized function to create and lay out visual components like knobs, sliders, buttons, spectrum analyzer, and response curve based on audio parameters.', 'The chapter mentions the need to declare the AudioProcessorValueTreeState object in the audio processor as it coordinates syncing parameters with GUI elements, and it explains the function of providing a parameter layout in the form of an APVTS parameter layout for APVTS creation.']}, {'end': 1596.646, 'start': 1120.838, 'title': 'Audio processor parameter setup', 'summary': 'Discusses setting up audio processor parameters for a project, including defining the ranges and defaults for low cut, high cut, and peak frequency bands, as well as gain and quality control.', 'duration': 475.808, 'highlights': ['The chapter discusses setting up audio processor parameters for a project, including defining the ranges and defaults for low cut, high cut, and peak frequency bands, as well as gain and quality control.', "The human ear's frequency range of 20 Hz to 20,000 Hz is used to define the parameter range for the low cut and high cut frequency bands, with a step size of 1 for adjusting the frequency values.", 'For the peak frequency band, the default value is set to 750 Hz within the same frequency range of 20 Hz to 20,000 Hz, and the peak gain is expressed in decibels with a range of -24 to +24, a step size of 0.5, and a default value of 0.', 'The quality control for the peak band is set with a low value of 0.1 and a high value of 10, using a step size of 0.05 to allow for precise adjustments and a default value of 1.']}, {'end': 1836.027, 'start': 1598.267, 'title': 'Filter slope options and audio parameters', 'summary': 'Discusses the implementation of filter slope options, offering 12, 24, 36, and 48 decibels per octave, using the audio parameter choice object to represent the choices, and demonstrating the parameter layout in the gui.', 'duration': 237.76, 'highlights': ['The chapter introduces four different options for filter cut steepness: 12, 24, 36, and 48 decibels per octave, expressed using the audio parameter choice object.', 'It explains the construction of a string array representing the filter slope choices and their default values.', 'The chapter demonstrates the parameter layout in the GUI and the appearance of slope controls (12, 24, 36, 48) in the combo boxes.']}, {'end': 2312.01, 'start': 1836.447, 'title': 'Audio processing and dsp module integration', 'summary': 'Covers the process of adding parameters, integrating dsp modules, and setting up filter chains for stereo processing in an audio plugin development, with a focus on juice dsp framework and c++17 language, providing step-by-step instructions and concepts on mono audio processing, filter aliasing, and preparing and using filter chains for stereo processing.', 'duration': 475.563, 'highlights': ['The chapter emphasizes the importance of making a commit to revert back if the next step gets messed up, adding parameters, and creating a generic audio processor editor, with a focus on the Juice DSP framework and C++17 language.', 'It instructs on adding the DSP module in ProJuicer, enabling access to Juice DSP modules for audio processing, and highlights the significance of understanding stereo and mono audio processing in the context of signal processing classes in the DSP namespace.', 'It details the process of creating type aliases for processing floats, setting the slope of cut filters, and defining a chain to represent the whole mono signal path in the DSP namespace, providing insights into the template metaprogramming and nested namespaces used in the Juice DSP framework.', 'The chapter provides a step-by-step guide on preparing and using filter chains for stereo processing, emphasizing the importance of preparing filters before use, creating a processing context, and passing it to each link in the chain, ensuring the readiness of the chains for processing.', 'It explains the requirement of passing a processing context to the processor chain, extracting the left and right channels from the buffer, creating audio blocks and processing contexts for individual channels, and passing these contexts to mono filter chains for stereo processing, ensuring the correct setup and processing of the filters.']}], 'duration': 1566.119, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc745891.jpg', 'highlights': ['The chapter emphasizes managing audio processing within a fixed time to prevent issues like clicks, pops, and potential damage to speakers and eardrums.', 'The chapter discusses setting up audio processor parameters for a project, including defining the ranges and defaults for low cut, high cut, and peak frequency bands, as well as gain and quality control.', 'The chapter introduces four different options for filter cut steepness: 12, 24, 36, and 48 decibels per octave, expressed using the audio parameter choice object.', 'The chapter provides a step-by-step guide on preparing and using filter chains for stereo processing, emphasizing the importance of preparing filters before use, creating a processing context, and passing it to each link in the chain, ensuring the readiness of the chains for processing.']}, {'end': 4087.308, 'segs': [{'end': 2463.801, 'src': 'embed', 'start': 2435.083, 'weight': 1, 'content': [{'end': 2437.384, 'text': "It's going to find our simple EQ because we built it that way.", 'start': 2435.083, 'duration': 2.301}, {'end': 2440.827, 'text': 'And then for Audio Unit, do the same thing.', 'start': 2438.005, 'duration': 2.822}, {'end': 2444.57, 'text': "In my case, I have a bunch of UAD stuff, so it's going to find all of that.", 'start': 2440.847, 'duration': 3.723}, {'end': 2453.413, 'text': 'Okay, so now that we have all of our audio units that are built into the computer and our VST3, close this Available Plugins list window.', 'start': 2445.788, 'duration': 7.625}, {'end': 2462.36, 'text': 'Now we can right-click right here, go to the Your Company, unless you put something else in, and pick VST3 for right now.', 'start': 2453.834, 'duration': 8.526}, {'end': 2463.801, 'text': "Here's our plugin.", 'start': 2463.18, 'duration': 0.621}], 'summary': 'Finding all built-in audio units and vst3 plugins for your company.', 'duration': 28.718, 'max_score': 2435.083, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc2435083.jpg'}, {'end': 2570.333, 'src': 'embed', 'start': 2541.067, 'weight': 0, 'content': [{'end': 2549.716, 'text': "Okay, I've got my AU Audio File Player set up with a file that is not going to trigger a copyright flag with YouTube.", 'start': 2541.067, 'duration': 8.649}, {'end': 2555.823, 'text': "I've got it wired up to this simple EQ that we've been working on, and it's connected to the audio output.", 'start': 2550.317, 'duration': 5.506}, {'end': 2560.067, 'text': "So if I push play, I'm going to hear it through the speakers, and you guys are going to hear it through this video.", 'start': 2555.903, 'duration': 4.164}, {'end': 2560.648, 'text': 'So check it out.', 'start': 2560.167, 'duration': 0.481}, {'end': 2570.333, 'text': 'All right, cool.', 'start': 2569.813, 'duration': 0.52}], 'summary': 'Au audio file player set up without copyright flag, connected to eq and audio output for playback.', 'duration': 29.266, 'max_score': 2541.067, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc2541067.jpg'}, {'end': 3395.521, 'src': 'embed', 'start': 3367.326, 'weight': 2, 'content': [{'end': 3371.55, 'text': 'and that instance has four filters within it.', 'start': 3367.326, 'duration': 4.224}, {'end': 3379.954, 'text': 'As I said before, each of these filters has a 12 dB per octave response if it is configured as a low-pass or high-pass filter.', 'start': 3372.191, 'duration': 7.763}, {'end': 3387.718, 'text': 'We are going to use a helper function from the JUICE framework that allows us to define IIR filters with custom orders.', 'start': 3380.675, 'duration': 7.043}, {'end': 3395.521, 'text': "And we've been describing the slope in terms of decibels per octave, but the slope of cut filters is also known as its order.", 'start': 3388.398, 'duration': 7.123}], 'summary': 'Using juice framework to create iir filters with custom orders.', 'duration': 28.195, 'max_score': 3367.326, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc3367326.jpg'}, {'end': 3487.584, 'src': 'embed', 'start': 3460.648, 'weight': 3, 'content': [{'end': 3464.231, 'text': "That's what I mean how, like, This gives us a 12 dB per octave cut.", 'start': 3460.648, 'duration': 3.583}, {'end': 3469.517, 'text': "If it's 4, if our order is 4, we're going to get 2 sets of coefficients.", 'start': 3465.112, 'duration': 4.405}, {'end': 3471.919, 'text': 'If our order is 6, we will get 3, etc.', 'start': 3469.637, 'duration': 2.282}, {'end': 3480.608, 'text': ', etc So what we need to do is produce the required number of coefficient objects that are needed based on what our slope parameter is set to.', 'start': 3471.919, 'duration': 8.689}, {'end': 3484.924, 'text': 'Now remember this parameter had four choices.', 'start': 3482.042, 'duration': 2.882}, {'end': 3487.584, 'text': 'It was 12, 24, 36, 48.', 'start': 3484.984, 'duration': 2.6}], 'summary': '12 db per octave cut, order 4 gets 2 sets of coefficients, order 6 gets 3, slope parameter choices: 12, 24, 36, 48', 'duration': 26.936, 'max_score': 3460.648, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc3460648.jpg'}], 'start': 2312.591, 'title': 'Audio plugin host functionality', 'summary': 'Covers setting up audiopluginhost to demonstrate audio plugin functionality, including building and configuring an audio plugin host, setting up filter coefficients, and implementing low-cut filters with custom orders, resulting in successful functionality and parameter extraction.', 'chapters': [{'end': 2393.238, 'start': 2312.591, 'title': 'Setting up audiopluginhost', 'summary': 'Covers setting up audiopluginhost to demonstrate audio plugin functionality, including navigating to the juice folder, opening audiopluginhost, building it, and running it outside of the project, resulting in a successful build.', 'duration': 80.647, 'highlights': ['Navigating to Juice folder and opening AudioPluginHost', 'Building AudioPluginHost', 'Running AudioPluginHost outside of the project']}, {'end': 2841.016, 'start': 2393.759, 'title': 'Audio plugin host configuration', 'summary': 'Covers the process of building and configuring an audio plugin host, including scanning for and adding vst3 and audio unit plugins, setting up an audio file player, configuring audio device settings, and debugging code. the chapter concludes with the initialization and extraction of parameter values from the audio processor value tree state.', 'duration': 447.257, 'highlights': ['The process of scanning for and adding VST3 and Audio Unit plugins to the audio plugin host is detailed, including finding and adding the simple EQ plugin and configuring the audio output. (relevance score: 5)', 'Setting up an AU audio file player to load and play audio files, wiring it to the audio output, and configuring audio device settings for the project is explained. (relevance score: 4)', 'The steps for configuring the audio plugin host to run when the project is executed, saving filter graph settings, and debugging code within the plugin host are outlined. (relevance score: 3)', 'The process of initializing and extracting parameter values from the audio processor value tree state for the filter chain configuration is described. (relevance score: 2)']}, {'end': 3332.748, 'start': 2841.537, 'title': 'Audio development: setting up filters', 'summary': 'Covers setting up filter coefficients and accessing links in the processor chain, with an emphasis on peak filter coefficients, as well as adjusting the skew parameter for frequency sliders to enable audible changes in audio production.', 'duration': 491.211, 'highlights': ['Setting up filter coefficients for peak filter using static helper functions and converting decibel values to gain units.', 'Accessing links in the processor chain via enum-defined positions and assigning coefficients to the peak filter link.', 'Adjusting the skew parameter for frequency sliders to control the filter response and maximize the usable range of frequency values.']}, {'end': 4087.308, 'start': 3333.849, 'title': 'Implementing low-cut filters with custom orders', 'summary': 'Discusses implementing low-cut filters with custom orders, using a helper function to define iir filters with custom orders, adjusting the slope in terms of decibels per octave, and adding a helper function to update coefficients for the dsp iir filter class.', 'duration': 753.459, 'highlights': ["The helper function from the JUICE framework allows defining IIR filters with custom orders, aiding in adapting the slope in terms of decibels per octave and adjusting the low-cut filters' slope parameter (4 filters within it) with a 12 dB per octave response.", 'The implementation involves producing the required number of coefficient objects based on the slope parameter set to 12, 24, 36, or 48, resulting in orders of 2, 4, 6, or 8, and using a helper function to obtain the array of coefficients and configuring the filter properly.', 'The code is later optimized by adding a helper function to update the coefficients for the DSP IIR filter class, aiming to facilitate the process of updating coefficients across different parts of the code.', 'Refactoring work includes cleaning up the configuration of the peak filter, implementing a helper function to update coefficients across multiple instances, and encapsulating the update peak code within a separate function for easier management and maintenance.']}], 'duration': 1774.717, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc2312591.jpg', 'highlights': ['Setting up an AU audio file player to load and play audio files, wiring it to the audio output, and configuring audio device settings for the project is explained. (relevance score: 4)', 'The process of scanning for and adding VST3 and Audio Unit plugins to the audio plugin host is detailed, including finding and adding the simple EQ plugin and configuring the audio output. (relevance score: 5)', "The helper function from the JUICE framework allows defining IIR filters with custom orders, aiding in adapting the slope in terms of decibels per octave and adjusting the low-cut filters' slope parameter (4 filters within it) with a 12 dB per octave response.", 'The implementation involves producing the required number of coefficient objects based on the slope parameter set to 12, 24, 36, or 48, resulting in orders of 2, 4, 6, or 8, and using a helper function to obtain the array of coefficients and configuring the filter properly.']}, {'end': 5307.672, 'segs': [{'end': 4181.508, 'src': 'embed', 'start': 4153.055, 'weight': 1, 'content': [{'end': 4156.197, 'text': 'All right, here we go.', 'start': 4153.055, 'duration': 3.142}, {'end': 4157.837, 'text': 'Commit that, stage all this stuff.', 'start': 4156.377, 'duration': 1.46}, {'end': 4167.102, 'text': 'Boom Okay, we can refactor how the low cut filter gets configured next, and then we can use that same code to configure the high cut filter.', 'start': 4159.209, 'duration': 7.893}, {'end': 4170.308, 'text': "Let's refactor how the low cut filter is updated.", 'start': 4167.764, 'duration': 2.544}, {'end': 4176.707, 'text': "So we'll be able to use this later for the high cut filter, Now I'm not sure what type names to use for the parameters here.", 'start': 4170.868, 'duration': 5.839}, {'end': 4178.346, 'text': "So I'm going to use a templated function.", 'start': 4176.727, 'duration': 1.619}, {'end': 4179.807, 'text': "So let's go to our header file.", 'start': 4178.546, 'duration': 1.261}, {'end': 4181.508, 'text': 'Put this down here.', 'start': 4180.528, 'duration': 0.98}], 'summary': 'Refactoring low cut filter configuration for high cut filter using templated function.', 'duration': 28.453, 'max_score': 4153.055, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc4153055.jpg'}, {'end': 4436.909, 'src': 'embed', 'start': 4403.347, 'weight': 0, 'content': [{'end': 4404.847, 'text': 'This is where we need our chain settings.', 'start': 4403.347, 'duration': 1.5}, {'end': 4407.648, 'text': 'Low cut slope.', 'start': 4406.648, 'duration': 1}, {'end': 4410.049, 'text': 'And then do the same thing for the right low cut.', 'start': 4408.248, 'duration': 1.801}, {'end': 4419.26, 'text': 'Our slider and combo box for the low cut filter should configure the DSP filter properly.', 'start': 4412.737, 'duration': 6.523}, {'end': 4421.321, 'text': "All right, let's test out our refactor.", 'start': 4419.28, 'duration': 2.041}, {'end': 4425.283, 'text': "And if it's cool, we will delete all this code and do a commit.", 'start': 4421.761, 'duration': 3.522}, {'end': 4426.944, 'text': "Okay, let's run it and see what we get.", 'start': 4425.803, 'duration': 1.141}, {'end': 4431.206, 'text': 'Okay, so we are gonna mess with the low cut now and the slope.', 'start': 4427.824, 'duration': 3.382}, {'end': 4436.909, 'text': "That's working.", 'start': 4436.329, 'duration': 0.58}], 'summary': 'Configured low cut settings, tested, and confirmed functionality.', 'duration': 33.562, 'max_score': 4403.347, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc4403347.jpg'}, {'end': 4564.419, 'src': 'embed', 'start': 4539.215, 'weight': 2, 'content': [{'end': 4544.84, 'text': "We can also write a templated helper function to eliminate even more duplicated code because we're doing this thing.", 'start': 4539.215, 'duration': 5.625}, {'end': 4546.041, 'text': 'And yeah.', 'start': 4545.801, 'duration': 0.24}, {'end': 4546.962, 'text': 'All right.', 'start': 4546.342, 'duration': 0.62}, {'end': 4549.285, 'text': "So let's write that next right above this guy.", 'start': 4547.002, 'duration': 2.283}, {'end': 4550.326, 'text': 'All right.', 'start': 4550.145, 'duration': 0.181}, {'end': 4551.306, 'text': "So we're going to do template.", 'start': 4550.346, 'duration': 0.96}, {'end': 4554.95, 'text': "We'll add these parameters next void update.", 'start': 4551.326, 'duration': 3.624}, {'end': 4556.531, 'text': "So we're going to need our chain.", 'start': 4555.27, 'duration': 1.261}, {'end': 4559.314, 'text': "We're going to need the coefficients.", 'start': 4557.873, 'duration': 1.441}, {'end': 4564.419, 'text': "And then so we're going to need our chain type and our coefficients.", 'start': 4561.256, 'duration': 3.163}], 'summary': 'Creating a templated helper function to eliminate duplicated code.', 'duration': 25.204, 'max_score': 4539.215, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc4539215.jpg'}, {'end': 5223.881, 'src': 'embed', 'start': 5195.168, 'weight': 3, 'content': [{'end': 5203.111, 'text': 'We get to design a custom interface and knobs and get the response curve showing up and the FFT analysis showing up in the background as well.', 'start': 5195.168, 'duration': 7.943}, {'end': 5205.312, 'text': 'Okay, see you in the next one.', 'start': 5203.651, 'duration': 1.661}, {'end': 5216.173, 'text': "Okay, before we start on the GUI, let's implement saving and loading of our plugin's parameter state.", 'start': 5209.306, 'duration': 6.867}, {'end': 5223.881, 'text': "It's very easy to do because the plugin state is stored in the APVTS's member called state.", 'start': 5216.653, 'duration': 7.228}], 'summary': "Custom interface design with response curve and fft analysis, implementing saving and loading of plugin's parameter state.", 'duration': 28.713, 'max_score': 5195.168, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc5195168.jpg'}], 'start': 4087.328, 'title': 'Dsp filter implementation', 'summary': "Covers refactoring low cut filter configuration, using templated functions for code reuse, and implementing dsp filters for low cut, peak, and high cut with a focus on updating coefficients and chain settings, while also addressing saving and loading of plugin state using apvts's member called state.", 'chapters': [{'end': 4302.866, 'start': 4087.328, 'title': 'Refactoring and configuring filters', 'summary': 'Discusses refactoring the low cut filter, configuring the high cut filter, and using templated functions for parameter naming and code reuse, with a focus on updating cut filter coefficients and chain settings while resolving associated errors.', 'duration': 215.538, 'highlights': ['Refactoring and configuring filters, including low cut and high cut filters, is discussed, with an emphasis on using the same names in refactored code and resolving errors during the process.', 'Using templated functions and explicitly declaring them as templated is highlighted as a strategy for parameter naming and code reuse.', 'The process of updating cut filter coefficients and chain settings is detailed, along with the resolution of errors encountered during the update.']}, {'end': 4539.215, 'start': 4302.886, 'title': 'Refactoring low cut filter configuration', 'summary': 'Demonstrates refactoring the low cut filter configuration in c++ with a focus on using helper functions, updating switch statements, and leveraging case pass-through to eliminate code duplication.', 'duration': 236.329, 'highlights': ['Refactoring the low cut filter configuration by using a helper function and updating the switch statement.', 'Leveraging case pass-through to eliminate code duplication and improve efficiency.', 'Testing and confirming the success of the refactor by building and running the program.']}, {'end': 4713.266, 'start': 4539.215, 'title': 'Templated helper function', 'summary': "Discusses writing a templated helper function to eliminate duplicated code, showcasing the use of template arguments and demonstrating the compiler's ability to deduce arguments automatically. it also includes specific examples of using the update coefficients function for different index values.", 'duration': 174.051, 'highlights': ["The chapter emphasizes the use of template arguments, showcasing the compiler's ability to deduce arguments automatically, reducing the need for manual input.", 'Specific examples of utilizing the update coefficients function for different index values, such as 3, 2, 1, and 0, are provided to demonstrate its functionality and effectiveness.', 'The chapter discusses the use of a templated helper function to eliminate duplicated code, showcasing the efficiency and practicality it offers in code implementation.']}, {'end': 5307.672, 'start': 4713.266, 'title': 'Implementing dsp filters and saving plugin state', 'summary': "Discusses implementing dsp filters and cleaning up the code for low cut, peak, and high cut filters, with a focus on updating coefficients and chain settings. additionally, it covers implementing saving and loading of the plugin's parameter state using apvts's member called state.", 'duration': 594.406, 'highlights': ['The chapter covers implementing DSP filters and cleaning up the code for low cut, peak, and high cut filters, including updating coefficients and chain settings.', "It discusses implementing saving and loading of the plugin's parameter state using APVTS's member called state.", 'The process involves renaming core coefficients, configuring the high cut chain, using helper functions to get and update coefficients, and testing the high cut frequency and slope.', 'The implementation also includes using a memory output stream to write the APBTS state to a memory block and restoring the plugin state from memory.']}], 'duration': 1220.344, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc4087328.jpg', 'highlights': ['Implementing DSP filters for low cut, peak, and high cut with updating coefficients and chain settings', 'Refactoring low cut filter configuration using a helper function and updating the switch statement', 'Using templated functions for code reuse and resolving errors during the update', "Implementing saving and loading of plugin state using APVTS's member called state"]}, {'end': 6122.199, 'segs': [{'end': 5333.463, 'src': 'embed', 'start': 5308.512, 'weight': 1, 'content': [{'end': 5317.776, 'text': 'Okay, once we know the tree is valid, then we can replace our plugin state and also update our filters with the saved parameter values.', 'start': 5308.512, 'duration': 9.264}, {'end': 5323.919, 'text': 'So apvts.replaceState with the new one, and then updateFilters.', 'start': 5318.277, 'duration': 5.642}, {'end': 5333.463, 'text': 'How simple is that? So now if we run this in AudioPluginHost, we should be able to tweak the parameters, and then it will be restored.', 'start': 5324.719, 'duration': 8.744}], 'summary': 'Validating the tree allows for state replacement and filter updates, ensuring parameter restoration in audiopluginhost.', 'duration': 24.951, 'max_score': 5308.512, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc5308512.jpg'}, {'end': 5449.71, 'src': 'embed', 'start': 5404.798, 'weight': 0, 'content': [{'end': 5406.819, 'text': "Now let's go to plugin editor.h.", 'start': 5404.798, 'duration': 2.021}, {'end': 5412.58, 'text': "Now I don't want to have to type this base class initialization for every slider that I'm going to make,", 'start': 5407.319, 'duration': 5.261}, {'end': 5415.861, 'text': "because they're all going to be rotary sliders and they're not going to have a text box.", 'start': 5412.58, 'duration': 3.281}, {'end': 5422.202, 'text': "So I'm going to create a class that does this automatically in the constructor and just use that for every slider in the GUI.", 'start': 5416.121, 'duration': 6.081}, {'end': 5424.223, 'text': "So I'm going to put that right here.", 'start': 5422.282, 'duration': 1.941}, {'end': 5437.723, 'text': "We're inheriting from slider and then we're going to set it so that it's using the rotary horizontal vertical drag style and then a no text box position.", 'start': 5428.598, 'duration': 9.125}, {'end': 5440.905, 'text': 'Now we need to add some sliders.', 'start': 5439.064, 'duration': 1.841}, {'end': 5442.646, 'text': "So let's add them right here.", 'start': 5441.105, 'duration': 1.541}, {'end': 5445.467, 'text': "Okay We're going to deal with these slope controls later.", 'start': 5442.666, 'duration': 2.801}, {'end': 5449.71, 'text': "For right now, we're just going to show the frequency and gain and quality sliders.", 'start': 5445.867, 'duration': 3.843}], 'summary': 'Creating a base class for rotary sliders to automate initialization and usage in gui.', 'duration': 44.912, 'max_score': 5404.798, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc5404798.jpg'}, {'end': 5573.49, 'src': 'embed', 'start': 5532.452, 'weight': 3, 'content': [{'end': 5540.218, 'text': "I will use juice live constant because it's basically lets me adjust positions of things while the editor is visible, which is very handy.", 'start': 5532.452, 'duration': 7.766}, {'end': 5548.105, 'text': "But for right now what I'm going to do is reserve the top third of display third of the display for showing the frequency response of the filter chain.", 'start': 5540.499, 'duration': 7.606}, {'end': 5553.45, 'text': "And then the bottom two thirds is going to go, it's going to be dedicated to the placement of all the sliders.", 'start': 5548.145, 'duration': 5.305}, {'end': 5554.651, 'text': "So I'm going to do that next.", 'start': 5553.87, 'duration': 0.781}, {'end': 5558.622, 'text': 'All right.', 'start': 5558.342, 'duration': 0.28}, {'end': 5562.624, 'text': "So the way this works is I've got my bounding box for the component.", 'start': 5558.902, 'duration': 3.722}, {'end': 5567.367, 'text': "I'm dedicating an area for the top, basically like I'm chopping off a rectangle.", 'start': 5563.305, 'duration': 4.062}, {'end': 5573.49, 'text': "I'm top chopping off, uh, 33% of the height that's going to get stored in this response area.", 'start': 5567.487, 'duration': 6.003}], 'summary': 'Using juice live constant to adjust positions. reserving top third for frequency response and bottom two thirds for slider placement.', 'duration': 41.038, 'max_score': 5532.452, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc5532452.jpg'}, {'end': 6010.136, 'src': 'embed', 'start': 5984.132, 'weight': 2, 'content': [{'end': 5993.879, 'text': 'Cool So we have successfully connected our default sliders to their parameters, and they save and load whenever we open and close the GUI.', 'start': 5984.132, 'duration': 9.747}, {'end': 5996.841, 'text': "Cool Let's make a commit of that.", 'start': 5994.319, 'duration': 2.522}, {'end': 6000.944, 'text': 'Connected sliders to parameter.', 'start': 5998.342, 'duration': 2.602}, {'end': 6004.067, 'text': "That's where we added the attachments.", 'start': 6002.805, 'duration': 1.262}, {'end': 6006.851, 'text': "Here's where we resaved something in the filter graph.", 'start': 6004.628, 'duration': 2.223}, {'end': 6010.136, 'text': 'Here is where we initialized all those attachments.', 'start': 6007.452, 'duration': 2.684}], 'summary': 'Successfully connected default sliders to parameters, saved and loaded gui settings.', 'duration': 26.004, 'max_score': 5984.132, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc5984132.jpg'}], 'start': 5308.512, 'title': 'Customizing plugins and connecting sliders', 'summary': 'Discusses updating plugin state and filters, enabling parameter tweaking and restoration, customizing the gui with rotary sliders, positioning components using juice live constant, and successful testing to preserve slider values when reopening the gui.', 'chapters': [{'end': 5508.682, 'start': 5308.512, 'title': 'Plugin state update and gui customization', 'summary': 'Discusses updating the plugin state and filters with saved parameter values, enabling parameter tweaking and restoration, and customizing the gui with rotary sliders and automatic initialization for each slider.', 'duration': 200.17, 'highlights': ['The plugin state is updated and filters are replaced with saved parameter values, allowing for parameter tweaking and restoration in AudioPluginHost.', 'The GUI is customized by resizing the window to 600 by 400, switching to the standalone plugin, and creating a class for automatic initialization of rotary sliders to streamline the GUI creation process.', 'Rotary sliders for frequency, gain, and quality control are added to the GUI, along with the implementation of a function to retrieve all GUI components in a vector for easy iteration before setting the size.']}, {'end': 6122.199, 'start': 5508.802, 'title': 'Positioning and connecting sliders', 'summary': 'Involves positioning components using juice live constant, dividing display into sections for sliders, and connecting sliders to audio parameters, with a successful test to preserve slider values when reopening the gui.', 'duration': 613.397, 'highlights': ['Juice Live Constant is used to adjust positions of components while the editor is visible, facilitating the positioning of components on the screen.', 'Components are positioned on the screen by dividing the display into sections for different sliders, with each slider having a specific portion of the screen, such as 33% or half, based on the bounding box calculations.', 'Sliders are successfully connected to audio parameters, and their values are preserved when closing and reopening the GUI, ensuring the proper functionality of the sliders.']}], 'duration': 813.687, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc5308512.jpg', 'highlights': ['Rotary sliders for frequency, gain, and quality control are added to the GUI, along with the implementation of a function to retrieve all GUI components in a vector for easy iteration before setting the size.', 'The plugin state is updated and filters are replaced with saved parameter values, allowing for parameter tweaking and restoration in AudioPluginHost.', 'Sliders are successfully connected to audio parameters, and their values are preserved when closing and reopening the GUI, ensuring the proper functionality of the sliders.', 'Juice Live Constant is used to adjust positions of components while the editor is visible, facilitating the positioning of components on the screen.', 'The GUI is customized by resizing the window to 600 by 400, switching to the standalone plugin, and creating a class for automatic initialization of rotary sliders to streamline the GUI creation process.', 'Components are positioned on the screen by dividing the display into sections for different sliders, with each slider having a specific portion of the screen, such as 33% or half, based on the bounding box calculations.']}, {'end': 7747.217, 'segs': [{'end': 6171.321, 'src': 'embed', 'start': 6146.466, 'weight': 0, 'content': [{'end': 6152.289, 'text': 'And then we will call the function get magnitude for frequency for each filter in the chain.', 'start': 6146.466, 'duration': 5.823}, {'end': 6155.15, 'text': "So let's get our get our chain elements.", 'start': 6152.489, 'duration': 2.661}, {'end': 6162.478, 'text': 'So to use that function, we are going to need the sample rate.', 'start': 6159.437, 'duration': 3.041}, {'end': 6167.96, 'text': 'We can get that from the audio processor to use that get magnitude for frequency function.', 'start': 6162.658, 'duration': 5.302}, {'end': 6171.321, 'text': 'So this is where we can do audio processor to get sample rate.', 'start': 6169.041, 'duration': 2.28}], 'summary': 'Get magnitude for frequency for each filter in the chain using sample rate from audio processor.', 'duration': 24.855, 'max_score': 6146.466, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc6146466.jpg'}, {'end': 6246.516, 'src': 'embed', 'start': 6216.105, 'weight': 1, 'content': [{'end': 6220.509, 'text': "We're mapping the normalized pixel number to its frequency within the human hearing range.", 'start': 6216.105, 'duration': 4.404}, {'end': 6221.61, 'text': 'That looks like this.', 'start': 6220.909, 'duration': 0.701}, {'end': 6224.392, 'text': 'Our normalized value.', 'start': 6223.351, 'duration': 1.041}, {'end': 6227.775, 'text': "Oops, let me be consistent with how I'm doing my casting.", 'start': 6224.392, 'duration': 3.383}, {'end': 6231.928, 'text': 'And our minimum range is 20, and our max range is 20, 000.', 'start': 6228.686, 'duration': 3.242}, {'end': 6239.392, 'text': 'All right, now we just need to call the magnitude function with this frequency.', 'start': 6231.928, 'duration': 7.464}, {'end': 6246.516, 'text': "What's it called? GetMagnitudeForFrequency function, and multiply the results with our magnitude right here.", 'start': 6239.412, 'duration': 7.104}], 'summary': 'Mapping pixel number to frequency within human hearing range, with a range of 20 to 20,000.', 'duration': 30.411, 'max_score': 6216.105, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc6216105.jpg'}, {'end': 6422.442, 'src': 'embed', 'start': 6387.702, 'weight': 2, 'content': [{'end': 6391.345, 'text': "We're going to start it at our response area dot get x.", 'start': 6387.702, 'duration': 3.643}, {'end': 6393.707, 'text': 'This is the left edge of the component.', 'start': 6391.345, 'duration': 2.362}, {'end': 6399.192, 'text': 'And the first value is going to be map mags dot front.', 'start': 6395.008, 'duration': 4.184}, {'end': 6404.588, 'text': "So we're going to run the first value in our magnitudes vector through this map function.", 'start': 6400.305, 'duration': 4.283}, {'end': 6408.171, 'text': "We're mapping our decibels to screen coordinates.", 'start': 6405.149, 'duration': 3.022}, {'end': 6413.555, 'text': 'Now we just need to create line twos for every other magnitude.', 'start': 6408.852, 'duration': 4.703}, {'end': 6422.442, 'text': 'All right, response curve, line two, and we want to go to response curve, response area.', 'start': 6415.096, 'duration': 7.346}], 'summary': 'Mapping magnitudes to screen coordinates for response curve.', 'duration': 34.74, 'max_score': 6387.702, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc6387702.jpg'}, {'end': 6909.807, 'src': 'embed', 'start': 6883.039, 'weight': 4, 'content': [{'end': 6888.302, 'text': "Let's do a little commit since this is kind of getting into, you know, micro code surgery, that sort of thing.", 'start': 6883.039, 'duration': 5.263}, {'end': 6888.962, 'text': "Let's get rid of that.", 'start': 6888.362, 'duration': 0.6}, {'end': 6889.882, 'text': 'Save this.', 'start': 6889.502, 'duration': 0.38}, {'end': 6890.583, 'text': "Let's go over here.", 'start': 6889.922, 'duration': 0.661}, {'end': 6896.285, 'text': 'We will say refactored peak coefficient generation.', 'start': 6890.603, 'duration': 5.682}, {'end': 6898.306, 'text': "All right, that's where we did that.", 'start': 6896.305, 'duration': 2.001}, {'end': 6902.488, 'text': 'Okay, we migrated this stuff up to there and made this make peak filter helper function.', 'start': 6898.326, 'duration': 4.162}, {'end': 6909.807, 'text': 'Yes Then we implemented that stuff and started using it.', 'start': 6905.444, 'duration': 4.363}], 'summary': 'Refactored peak coefficient generation, migrated and implemented new peak filter helper function.', 'duration': 26.768, 'max_score': 6883.039, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc6883039.jpg'}, {'end': 7076.327, 'src': 'embed', 'start': 7046.618, 'weight': 3, 'content': [{'end': 7050.901, 'text': "Let's make new coefficients and then let's update our mono chain and then repaint.", 'start': 7046.618, 'duration': 4.283}, {'end': 7052.422, 'text': 'Okay, very simple.', 'start': 7050.921, 'duration': 1.501}, {'end': 7054.403, 'text': 'Auto chain settings.', 'start': 7052.762, 'duration': 1.641}, {'end': 7058.725, 'text': "Let's make our coefficients for the peak band.", 'start': 7056.024, 'duration': 2.701}, {'end': 7063.128, 'text': 'All right, our chain settings, our sample rate.', 'start': 7060.226, 'duration': 2.902}, {'end': 7066.89, 'text': 'And now we can update our chains coefficients.', 'start': 7064.368, 'duration': 2.522}, {'end': 7071.827, 'text': 'Our old ones are the mono chain dot get, and we want the peak.', 'start': 7068.246, 'duration': 3.581}, {'end': 7076.327, 'text': 'And then our replacements are going to be these peak coefficients.', 'start': 7073.547, 'duration': 2.78}], 'summary': 'Updating coefficients for peak band in mono chain', 'duration': 29.709, 'max_score': 7046.618, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc7046618.jpg'}, {'end': 7163.985, 'src': 'embed', 'start': 7135.444, 'weight': 5, 'content': [{'end': 7137.208, 'text': "All right, so I'm just going to adjust the gain.", 'start': 7135.444, 'duration': 1.764}, {'end': 7139.172, 'text': 'Hey, look at that.', 'start': 7138.631, 'duration': 0.541}, {'end': 7149.534, 'text': 'All right, so now we need to get the cut filters, the cut filter functions usable by the editor.', 'start': 7143.089, 'duration': 6.445}, {'end': 7156.66, 'text': 'So head on over to your plugin processor.h and we need to jump down to all of these update functions.', 'start': 7149.674, 'duration': 6.986}, {'end': 7159.422, 'text': 'Okay, we need to make all of these public.', 'start': 7156.68, 'duration': 2.742}, {'end': 7163.985, 'text': 'So just grab these template functions.', 'start': 7159.882, 'duration': 4.103}], 'summary': 'Adjusting gain, making cut filter functions usable by the editor', 'duration': 28.541, 'max_score': 7135.444, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc7135444.jpg'}, {'end': 7402.727, 'src': 'embed', 'start': 7379.642, 'weight': 8, 'content': [{'end': 7387.103, 'text': 'So auto low cut coefficients equals make low cut filter, change settings, sample rate.', 'start': 7379.642, 'duration': 7.461}, {'end': 7389.464, 'text': "Let's cache that sample right now.", 'start': 7387.984, 'duration': 1.48}, {'end': 7391.204, 'text': "I'm just feeling a little lazy.", 'start': 7389.504, 'duration': 1.7}, {'end': 7392.125, 'text': "I'm just going to copy that.", 'start': 7391.244, 'duration': 0.881}, {'end': 7393.505, 'text': 'This can all be refactored later.', 'start': 7392.205, 'duration': 1.3}, {'end': 7394.885, 'text': "So we don't DRY.", 'start': 7393.825, 'duration': 1.06}, {'end': 7396.686, 'text': "So we don't repeat ourselves.", 'start': 7395.665, 'duration': 1.021}, {'end': 7398.426, 'text': 'We always want to not repeat ourselves.', 'start': 7396.846, 'duration': 1.58}, {'end': 7400.166, 'text': "DRY, don't repeat yourself.", 'start': 7398.726, 'duration': 1.44}, {'end': 7400.847, 'text': 'Okay, here we go.', 'start': 7400.406, 'duration': 0.441}, {'end': 7402.727, 'text': 'Auto high cut.', 'start': 7401.187, 'duration': 1.54}], 'summary': 'Adjusting low cut coefficients, discussing code refactoring and avoiding repetitions.', 'duration': 23.085, 'max_score': 7379.642, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc7379642.jpg'}, {'end': 7521.733, 'src': 'embed', 'start': 7475.756, 'weight': 6, 'content': [{'end': 7490.852, 'text': "Okay Cool, all right, let's commit that.", 'start': 7475.756, 'duration': 15.096}, {'end': 7500.708, 'text': 'Response curve now shows cut filter response, cool.', 'start': 7492.575, 'duration': 8.133}, {'end': 7509.505, 'text': 'Migrating this code from the editor to a separate component is relatively easy.', 'start': 7504.542, 'duration': 4.963}, {'end': 7512.767, 'text': 'We need to inherit from the things the editor is inheriting.', 'start': 7509.765, 'duration': 3.002}, {'end': 7517.31, 'text': "And yeah, we're really not writing any new code, really.", 'start': 7513.888, 'duration': 3.422}, {'end': 7519.672, 'text': "We're just refactoring what we already have.", 'start': 7517.35, 'duration': 2.322}, {'end': 7521.733, 'text': "Let's go to our header file, first of all.", 'start': 7519.952, 'duration': 1.781}], 'summary': 'Code migration and refactoring process, inheriting from editor, no new code written.', 'duration': 45.977, 'max_score': 7475.756, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc7475756.jpg'}, {'end': 7753.118, 'src': 'embed', 'start': 7726.952, 'weight': 9, 'content': [{'end': 7731.373, 'text': "Um, we don't need this atomic, we don't need, uh, the chain.", 'start': 7726.952, 'duration': 4.421}, {'end': 7735.994, 'text': 'So that means we can get rid of these, uh, get rid of those functions as well.', 'start': 7731.393, 'duration': 4.601}, {'end': 7736.854, 'text': 'All right.', 'start': 7736.014, 'duration': 0.84}, {'end': 7739.495, 'text': "So let's go to our plugin editor dot CPP.", 'start': 7736.934, 'duration': 2.561}, {'end': 7743.496, 'text': "Uh, we are no longer listening for those and we're not a timer anymore.", 'start': 7740.315, 'duration': 3.181}, {'end': 7745.076, 'text': 'So those go away.', 'start': 7744.196, 'duration': 0.88}, {'end': 7747.217, 'text': 'Same for the destructor stuff.', 'start': 7745.937, 'duration': 1.28}, {'end': 7753.118, 'text': "And then we're not doing any of this, so we can just continue filling it entirely with a black.", 'start': 7747.917, 'duration': 5.201}], 'summary': 'Removing atomic and chain, no longer listening for timer, and filling with black.', 'duration': 26.166, 'max_score': 7726.952, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc7726952.jpg'}], 'start': 6122.219, 'title': 'Audio response curve generation', 'summary': 'Covers the generation of audio response curves by obtaining frequency magnitudes, mapping pixel space to frequency space, converting magnitudes to decibels, and updating cut filters and coefficients, resulting in successful testing and refactoring of the response curve component.', 'chapters': [{'end': 6306.882, 'start': 6122.219, 'title': 'Audio response curve generation', 'summary': 'Discusses the generation of an audio response curve, including obtaining frequency magnitudes for each filter in the chain and mapping pixel space to frequency space, aiming to compute one magnitude per pixel.', 'duration': 184.663, 'highlights': ['Obtaining frequency magnitudes for each filter in the chain, using the function getMagnitudeForFrequency, to compute one magnitude per pixel.', 'Mapping normalized pixel number to its frequency within the human hearing range using the helper function mapToLogBase10, with a minimum range of 20 and a maximum range of 20,000.', 'Iterating through each pixel and computing the magnitude at that frequency, expressed as gain units, with a starting gain of one and multiplicative gain units.']}, {'end': 7134.101, 'start': 6310.384, 'title': 'Converting magnitudes to decibels and drawing path', 'summary': 'Discusses converting magnitudes into decibels and drawing a path based on the decibel values, utilizing a range of -24 to +24 and a refresh rate of 60hz for updating the filter chain in the audio processor.', 'duration': 823.717, 'highlights': ['Converting magnitudes into decibels and mapping them to screen coordinates using a range of -24 to +24 to draw a response curve.', 'Setting up the filter chain in the editor to respond to parameter changes and updating the chain coefficients with a 60Hz refresh rate for smooth curve rendering.', 'Refactoring the peak coefficient generation by turning the update coefficients function into a free function for efficient processing.']}, {'end': 7379.182, 'start': 7135.444, 'title': 'Updating cut filters and coefficients', 'summary': "Involves updating the plugin processor to make cut filter functions usable by the editor, adding helper functions for producing coefficients, and updating call sites, resulting in successful testing of the editor's functionality and a refactor of cut filters creation.", 'duration': 243.738, 'highlights': ['Updating the plugin processor to make cut filter functions usable by the editor and adding helper functions for producing coefficients.', "Updating call sites for the low cut and high cut filters to use the new functions, resulting in successful testing of the editor's functionality.", 'Refactoring the creation of cut filters and updating the response curve in the plugin editor, ensuring the GUI listens to parameter changes and displaying the successful testing of the editor.']}, {'end': 7747.217, 'start': 7379.642, 'title': 'Refactoring response curve component', 'summary': 'Discusses the process of refactoring the response curve component by migrating code from the editor to a separate component, inheriting from existing structures, and updating callbacks and functions, ensuring the response area draws within its bounds and accurately represents the audio processing.', 'duration': 367.575, 'highlights': ['The chapter demonstrates the process of refactoring the response curve component by migrating code from the editor to a separate component, ensuring the response area draws within its bounds and accurately represents the audio processing.', "It emphasizes the importance of not repeating code and the concept of DRY (Don't Repeat Yourself).", 'The process involves inheriting from existing structures, updating callbacks and functions, and initializing the response area to accurately represent the audio processing.', 'The chapter also highlights the need to update the plugin editor by removing unnecessary callbacks and functions, reflecting the changes made in the response curve component.']}], 'duration': 1624.998, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc6122219.jpg', 'highlights': ['Obtaining frequency magnitudes for each filter using getMagnitudeForFrequency', 'Mapping pixel number to frequency within human hearing range using mapToLogBase10', 'Converting magnitudes to decibels and mapping to screen coordinates', 'Updating filter chain coefficients with a 60Hz refresh rate for smooth rendering', 'Refactoring peak coefficient generation for efficient processing', 'Updating plugin processor to make cut filter functions usable by the editor', 'Refactoring creation of cut filters and updating response curve in plugin editor', 'Demonstrating refactoring of response curve component by migrating code', 'Emphasizing importance of not repeating code and concept of DRY', 'Updating plugin editor by removing unnecessary callbacks and functions']}, {'end': 8844.063, 'segs': [{'end': 7860.936, 'src': 'embed', 'start': 7747.917, 'weight': 0, 'content': [{'end': 7753.118, 'text': "And then we're not doing any of this, so we can just continue filling it entirely with a black.", 'start': 7747.917, 'duration': 5.201}, {'end': 7756.299, 'text': 'So we can get rid of all of this stuff.', 'start': 7754.038, 'duration': 2.261}, {'end': 7762.305, 'text': "And then we don't need our, this callback that disappears.", 'start': 7757.483, 'duration': 4.822}, {'end': 7763.625, 'text': 'All right.', 'start': 7763.245, 'duration': 0.38}, {'end': 7765.826, 'text': "And I believe that's most of the errors.", 'start': 7764.365, 'duration': 1.461}, {'end': 7767.546, 'text': "Let's build it and see what it tells us.", 'start': 7765.846, 'duration': 1.7}, {'end': 7769.727, 'text': 'That may have been it.', 'start': 7769.167, 'duration': 0.56}, {'end': 7770.867, 'text': 'All right.', 'start': 7769.747, 'duration': 1.12}, {'end': 7771.627, 'text': 'Yep Okay.', 'start': 7771.067, 'duration': 0.56}, {'end': 7772.088, 'text': 'All right.', 'start': 7771.828, 'duration': 0.26}, {'end': 7773.208, 'text': "So let's run and test it.", 'start': 7772.168, 'duration': 1.04}, {'end': 7776.354, 'text': 'All right, so this is tiny for some reason.', 'start': 7774.394, 'duration': 1.96}, {'end': 7777.755, 'text': "That's way smaller than we wanted.", 'start': 7776.394, 'duration': 1.361}, {'end': 7779.695, 'text': "Let's go to our resized function.", 'start': 7778.275, 'duration': 1.42}, {'end': 7782.216, 'text': 'Bounds removed from top.', 'start': 7780.956, 'duration': 1.26}, {'end': 7783.416, 'text': 'Bounds dot get height.', 'start': 7782.336, 'duration': 1.08}, {'end': 7795.599, 'text': "Oh, you know why? It's because our response area here in this, our response area should not be 33% of the actual component.", 'start': 7784.336, 'duration': 11.263}, {'end': 7797.039, 'text': 'It should just be the get local bounds.', 'start': 7795.619, 'duration': 1.42}, {'end': 7800.28, 'text': "So I'm just going to do that and then get rid of this line.", 'start': 7797.079, 'duration': 3.201}, {'end': 7804.081, 'text': 'All right, now if we run it, we should be good to go.', 'start': 7801.52, 'duration': 2.561}, {'end': 7807.742, 'text': 'Okay, cool.', 'start': 7807.242, 'duration': 0.5}, {'end': 7811.124, 'text': "So let's check if we are drawing outside of our bounds anymore.", 'start': 7808.062, 'duration': 3.062}, {'end': 7812.344, 'text': 'And no, we are not.', 'start': 7811.364, 'duration': 0.98}, {'end': 7813.705, 'text': "So that's fantastic.", 'start': 7812.404, 'duration': 1.301}, {'end': 7816.406, 'text': 'I told you that would be easy.', 'start': 7815.265, 'duration': 1.141}, {'end': 7818.887, 'text': "Okay, let's commit that change.", 'start': 7817.226, 'duration': 1.661}, {'end': 7823.389, 'text': 'And created response curve component.', 'start': 7820.308, 'duration': 3.081}, {'end': 7828.799, 'text': 'That was a fairly aggressive amount of code surgery.', 'start': 7824.878, 'duration': 3.921}, {'end': 7831.84, 'text': "Here's our response curve component with all the good stuff in it.", 'start': 7828.899, 'duration': 2.941}, {'end': 7836.002, 'text': "Here's where we gutted the editor.", 'start': 7832.941, 'duration': 3.061}, {'end': 7838.223, 'text': 'Same for right here.', 'start': 7837.562, 'duration': 0.661}, {'end': 7841.124, 'text': "Alright We've come a long way.", 'start': 7839.303, 'duration': 1.821}, {'end': 7842.084, 'text': "We've done a lot of stuff.", 'start': 7841.144, 'duration': 0.94}, {'end': 7849.829, 'text': 'Okay, we are going to customize the slider visuals now.', 'start': 7846.167, 'duration': 3.662}, {'end': 7853.011, 'text': 'For this slider class, I want it to show the following.', 'start': 7850.57, 'duration': 2.441}, {'end': 7860.936, 'text': 'Okay, I want to see the min and max range at either end of the slider, and I want to see the parameters value in the center of the slider.', 'start': 7853.031, 'duration': 7.905}], 'summary': 'Code review and optimization of a response curve component, with visual adjustments made to the slider class.', 'duration': 113.019, 'max_score': 7747.917, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc7747917.jpg'}, {'end': 8178.201, 'src': 'embed', 'start': 8148.987, 'weight': 4, 'content': [{'end': 8153.81, 'text': "we're gonna call this rotary slider with labels Okay.", 'start': 8148.987, 'duration': 4.823}, {'end': 8159.274, 'text': 'so the next thing we need is we need to give ourselves a parameter and a suffix, like I had said.', 'start': 8153.81, 'duration': 5.464}, {'end': 8162.936, 'text': 'so juice ranged audio parameter.', 'start': 8159.274, 'duration': 3.662}, {'end': 8175.3, 'text': "we're gonna do pointer to it, and The reason I'm using this thing is because this is the base class for all of these guys.", 'start': 8162.936, 'duration': 12.364}, {'end': 8178.201, 'text': 'And it derives from audio processor parameter.', 'start': 8175.32, 'duration': 2.881}], 'summary': 'Creating a rotary slider with labels using a parameter and suffix derived from audio processor parameter.', 'duration': 29.214, 'max_score': 8148.987, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc8148987.jpg'}, {'end': 8250.844, 'src': 'embed', 'start': 8221.188, 'weight': 5, 'content': [{'end': 8233.334, 'text': 'Okay, now we actually need a look and feel class, okay? We need an actual look and feel class that we can provide our drawRotarySlider function.', 'start': 8221.188, 'duration': 12.146}, {'end': 8242.94, 'text': 'All right, if we jump back over to this thing, this is where I can go to that slider class.', 'start': 8233.353, 'duration': 9.587}, {'end': 8245.04, 'text': "Here's the look and feel methods.", 'start': 8243.86, 'duration': 1.18}, {'end': 8249.144, 'text': 'So we want to implement a rotary slider function.', 'start': 8245.341, 'duration': 3.803}, {'end': 8250.844, 'text': "Okay, so that's what we need to provide here.", 'start': 8249.164, 'duration': 1.68}], 'summary': 'Creating a look and feel class for implementing a rotary slider function.', 'duration': 29.656, 'max_score': 8221.188, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc8221188.jpg'}], 'start': 7747.917, 'title': 'Troubleshooting code, component resizing, and customizing slider visuals', 'summary': 'Provides guidance on troubleshooting errors in code, resolving component resizing issues, and creating a response curve component, along with customizing slider visuals such as min and max range display, parameter value, and practical implementation of a custom look and feel class for a rotary slider.', 'chapters': [{'end': 7831.84, 'start': 7747.917, 'title': 'Troubleshooting code and component resizing', 'summary': 'Details troubleshooting errors in the code, resolving component resizing issues, and successfully testing the changes, ultimately creating a response curve component with significant code modifications.', 'duration': 83.923, 'highlights': ['Successfully resolved component resizing issue by adjusting the response area to be the get local bounds, resulting in no drawing outside of the bounds.', 'Troubleshooting errors in the code, resulting in the removal of unnecessary callbacks and fixing size discrepancies, leading to a successful build and test of the code.', 'Created a response curve component with significant code modifications, marking a successful completion of the troubleshooting process.']}, {'end': 8220.307, 'start': 7832.941, 'title': 'Customizing slider visuals', 'summary': 'Details the process of customizing slider visuals, including displaying min and max range, parameter value, and customizing text and suffix, with a focus on implementation and practical application in the code.', 'duration': 387.366, 'highlights': ['The chapter discusses customizing the slider visuals, including displaying the min and max range at either end of the slider and the parameter value in the center, with a focus on the implementation in the code.', 'It explains the look and feel methods for the slider class, detailing the organization and inheritance of look and feel member functions, and provides insights into the practical application through code examples.', "The speaker emphasizes the need for uniform text type and customized suffix for parameters, with specific examples such as '2.85 kilohertz' and '12 dB per octave', highlighting the attention to detail in the customization process.", "The discussion involves implementing a custom class 'rotary slider with labels' and utilizing the 'juice ranged audio parameter' to handle parameter values and member functions, showcasing practical coding and implementation strategies."]}, {'end': 8844.063, 'start': 8221.188, 'title': 'Implementing custom slider visuals', 'summary': "Discusses the implementation of a custom look and feel class for a rotary slider, including the creation of a paint function, setting up the rotary slider range, and mapping the slider's value to a normalized value, with details on setting the start and end angles, and drawing the rotary slider.", 'duration': 622.875, 'highlights': ["The chapter discusses the implementation of a custom look and feel class for a rotary slider, including the creation of a paint function, setting up the rotary slider range, and mapping the slider's value to a normalized value, with details on setting the start and end angles, and drawing the rotary slider.", "The transcript also covers the process of setting up the rotary slider to visually have a range of 7 o'clock to 5 o'clock, including the calculation of start and end angles, and the utilization of radians for angle representation.", "Additionally, the chapter provides details on the creation of a look and feel class to draw the rotary slider, involving the filling of a circle to act as the slider background, drawing a border around the circle, converting the slider's normalized value to an angle in radians, and creating and rotating a small vertical rectangle to the angle in radians.", "The implementation of the drawRotarySlider function is also highlighted, emphasizing the creation of circles to represent the rotary nature of the slider, and the utilization of specific colors for the slider's visual representation."]}], 'duration': 1096.146, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc7747917.jpg', 'highlights': ['Successfully resolved component resizing issue by adjusting the response area to be the get local bounds, resulting in no drawing outside of the bounds.', 'Created a response curve component with significant code modifications, marking a successful completion of the troubleshooting process.', 'Troubleshooting errors in the code, resulting in the removal of unnecessary callbacks and fixing size discrepancies, leading to a successful build and test of the code.', 'The chapter discusses customizing the slider visuals, including displaying the min and max range at either end of the slider and the parameter value in the center, with a focus on the implementation in the code.', "The discussion involves implementing a custom class 'rotary slider with labels' and utilizing the 'juice ranged audio parameter' to handle parameter values and member functions, showcasing practical coding and implementation strategies.", "The chapter discusses the implementation of a custom look and feel class for a rotary slider, including the creation of a paint function, setting up the rotary slider range, and mapping the slider's value to a normalized value, with details on setting the start and end angles, and drawing the rotary slider."]}, {'end': 9995.733, 'segs': [{'end': 8888.932, 'src': 'embed', 'start': 8844.083, 'weight': 3, 'content': [{'end': 8848.904, 'text': "I don't know what that looks like right now.", 'start': 8844.083, 'duration': 4.821}, {'end': 8855.005, 'text': 'I just know that when I first sketched this project out, I liked that after I found it somewhere.', 'start': 8848.984, 'duration': 6.021}, {'end': 8860.337, 'text': 'Okay, so g.fillEllipse, and this is where we want to fill the bounding box.', 'start': 8855.393, 'duration': 4.944}, {'end': 8862.98, 'text': "Let's do the same thing again with a different color,", 'start': 8860.357, 'duration': 2.623}, {'end': 8867.163, 'text': "and we're going to draw the ellipse which is going to give us the border we said we were going to create.", 'start': 8862.98, 'duration': 4.183}, {'end': 8869.305, 'text': "Let's take a look at that.", 'start': 8868.585, 'duration': 0.72}, {'end': 8870.526, 'text': "We'll just see some circles.", 'start': 8869.445, 'duration': 1.081}, {'end': 8872.748, 'text': 'Cool, circles.', 'start': 8871.827, 'duration': 0.921}, {'end': 8880.035, 'text': "Let's make a narrow rectangle that goes from the center of the bounding box up to the 12 o'clock position.", 'start': 8874.069, 'duration': 5.966}, {'end': 8887.431, 'text': "Now if we want to rotate something that's going to be drawn, we have to define it inside of a path.", 'start': 8880.987, 'duration': 6.444}, {'end': 8888.932, 'text': "So let's create a path now.", 'start': 8887.611, 'duration': 1.321}], 'summary': 'Sketching project with circles, ellipses, and rectangles for drawing and rotation.', 'duration': 44.849, 'max_score': 8844.083, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc8844083.jpg'}, {'end': 9054.34, 'src': 'embed', 'start': 9030.387, 'weight': 1, 'content': [{'end': 9038.111, 'text': 'Okay, so we are mapping our normalized slider value to be between these two rotary positions, which we defined here.', 'start': 9030.387, 'duration': 7.724}, {'end': 9049.237, 'text': 'We can rotate the narrow rectangle to this radian angle using an affine transform, and we have to do it around the center of our component.', 'start': 9039.292, 'duration': 9.945}, {'end': 9052.059, 'text': 'All right, so p.applyTransform.', 'start': 9049.618, 'duration': 2.441}, {'end': 9054.34, 'text': 'Here is we want an affine transform.', 'start': 9052.619, 'duration': 1.721}], 'summary': 'Mapping slider value to rotary positions, applying affine transform around component center.', 'duration': 23.953, 'max_score': 9030.387, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc9030387.jpg'}, {'end': 9135.832, 'src': 'embed', 'start': 9109.377, 'weight': 0, 'content': [{'end': 9114.88, 'text': 'The next thing I would like to do is add the center label showing the parameters value next.', 'start': 9109.377, 'duration': 5.503}, {'end': 9118.943, 'text': "Okay, we'll figure out that bounding issue in a minute as well.", 'start': 9114.9, 'duration': 4.043}, {'end': 9120.684, 'text': "Let's make a commit of that.", 'start': 9119.604, 'duration': 1.08}, {'end': 9124.807, 'text': 'Added basic slider visuals.', 'start': 9121.405, 'duration': 3.402}, {'end': 9126.128, 'text': "Here's where we.", 'start': 9125.668, 'duration': 0.46}, {'end': 9129.824, 'text': 'made these implementations into declarations.', 'start': 9126.86, 'duration': 2.964}, {'end': 9135.832, 'text': "And then here's where we implemented our first basic paint function, which calls the rotary slider.", 'start': 9129.844, 'duration': 5.988}], 'summary': 'Implemented basic slider visuals and first paint function', 'duration': 26.455, 'max_score': 9109.377, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc9109377.jpg'}, {'end': 9793.872, 'src': 'embed', 'start': 9771.128, 'weight': 5, 'content': [{'end': 9779.418, 'text': 'If you recall the values that our parameter ranges had, you know that the hertz parameter is the only one that can possibly get over 1, 000.', 'start': 9771.128, 'duration': 8.29}, {'end': 9785.446, 'text': 'So that means we can just check if our value is over that and then divide by 1, 000 to get a kilohertz value.', 'start': 9779.419, 'duration': 6.027}, {'end': 9791.131, 'text': 'Once we have that, then we can say, yes, please add a K to the suffix.', 'start': 9786.949, 'duration': 4.182}, {'end': 9793.872, 'text': 'And we can convey that with that Boolean flag we used earlier.', 'start': 9791.371, 'duration': 2.501}], 'summary': 'Hertz parameter can go over 1,000, then add k to the suffix using a boolean flag.', 'duration': 22.744, 'max_score': 9771.128, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc9771128.jpg'}], 'start': 8844.083, 'title': 'Drawing shapes and customized display in java', 'summary': 'Covers drawing ellipses, rectangles, and paths in java, using g.fillellipse method, rotating drawings, implementing customized look and feel for a rotary slider, and displaying parameters with transformations and numeric values.', 'chapters': [{'end': 8951.316, 'start': 8844.083, 'title': 'Drawing ellipses and rectangles in java', 'summary': 'Demonstrates drawing ellipses, rectangles, and paths in java, including using the g.fillellipse method, rotating drawings inside a path, and visualizing rectangles using member functions.', 'duration': 107.233, 'highlights': ['The g.fillEllipse method is used to fill the bounding box with a color.', 'The process of rotating drawings inside a path is explained, emphasizing the need to define it inside the path.', 'The advantage of using rectangle member functions over the rectangle class constructor is highlighted for easier visualization of the position of rectangles.']}, {'end': 9288.466, 'start': 8951.316, 'title': 'Implementing customized look and feel', 'summary': 'Discusses the implementation of a customized look and feel for a rotary slider, including mapping slider values to radian angles, rotating the slider, and drawing the slider bounds.', 'duration': 337.15, 'highlights': ['The chapter discusses mapping slider values to radian angles using J map, which maps from a slider position proportional from a value of 0.0 to 0.1, and then rotates the narrow rectangle to this radian angle using an affine transform around the center of the component.', 'It explains the process of drawing the slider bounds, including shrinking the size, moving it towards the top of the component, and setting its position based on the center of the component.', 'The implementation of a customized look and feel for a rotary slider is discussed, addressing issues such as weird explosions, slider bounding problems, and ensuring the slider is functioning correctly.', 'The chapter includes code implementation details such as adding rectangles, ensuring proper rotation to avoid weird explosions, and implementing a basic paint function for the rotary slider.']}, {'end': 9995.733, 'start': 9289.758, 'title': 'Implementing display of parameters', 'summary': 'Details the process of implementing the display of parameters, including transforming sliders into circles, adjusting bounding boxes, casting, setting font and text, handling suffixes for parameter values, and displaying numeric values for sliders, with a commitment to display basic param values.', 'duration': 705.975, 'highlights': ['Process of implementing display of parameters, including transforming sliders into circles and adjusting bounding boxes, is detailed, with a commitment to display basic param values.', 'Explanation of casting and setting font and text for parameter display is provided.', 'Handling suffixes for parameter values, such as truncating hertz value if over 1000 and displaying as kilohertz, is discussed.', 'Details about displaying numeric values for sliders, including the need to adjust suffixes and handle quality property without any units, are outlined.']}], 'duration': 1151.65, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc8844083.jpg', 'highlights': ['The process of implementing display of parameters, including transforming sliders into circles and adjusting bounding boxes, is detailed, with a commitment to display basic param values.', 'The chapter discusses mapping slider values to radian angles using J map, which maps from a slider position proportional from a value of 0.0 to 0.1, and then rotates the narrow rectangle to this radian angle using an affine transform around the center of the component.', 'The implementation of a customized look and feel for a rotary slider is discussed, addressing issues such as weird explosions, slider bounding problems, and ensuring the slider is functioning correctly.', 'The g.fillEllipse method is used to fill the bounding box with a color.', 'The process of rotating drawings inside a path is explained, emphasizing the need to define it inside the path.', 'Handling suffixes for parameter values, such as truncating hertz value if over 1000 and displaying as kilohertz, is discussed.']}, {'end': 10915.103, 'segs': [{'end': 10079.005, 'src': 'embed', 'start': 10033.995, 'weight': 0, 'content': [{'end': 10036.677, 'text': 'And now this is displaying the correct slope values.', 'start': 10033.995, 'duration': 2.682}, {'end': 10037.738, 'text': "So that's cool.", 'start': 10037.037, 'duration': 0.701}, {'end': 10039.88, 'text': 'All right.', 'start': 10039.599, 'duration': 0.281}, {'end': 10042.942, 'text': "Let's ditch those bounding boxes that were showing the rectangles.", 'start': 10040.04, 'duration': 2.902}, {'end': 10044.443, 'text': "It's these guys right here.", 'start': 10043.603, 'duration': 0.84}, {'end': 10046.565, 'text': "I'm going to leave them in as comments though.", 'start': 10044.463, 'duration': 2.102}, {'end': 10054.591, 'text': "Um, because you know, if we ever need to debug this some more, it's good to just, you know, it makes it easy to uncomment them and display them later.", 'start': 10047.466, 'duration': 7.125}, {'end': 10057.033, 'text': "Let's take a look one more time and see what we've got.", 'start': 10055.112, 'duration': 1.921}, {'end': 10058.094, 'text': 'All right.', 'start': 10057.794, 'duration': 0.3}, {'end': 10058.995, 'text': "That's nice and clean.", 'start': 10058.134, 'duration': 0.861}, {'end': 10062.699, 'text': "Cool Let's make a commit of that.", 'start': 10060.393, 'duration': 2.306}, {'end': 10069.435, 'text': 'So implemented displaying the parameter value with suffix.', 'start': 10063.882, 'duration': 5.553}, {'end': 10079.005, 'text': "Cool Let's add the labels next that will show the minimum and maximum values that our parameters can have.", 'start': 10072.321, 'duration': 6.684}], 'summary': 'Implemented displaying parameter values with suffix and adding labels for minimum and maximum values.', 'duration': 45.01, 'max_score': 10033.995, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc10033995.jpg'}, {'end': 10168.375, 'src': 'embed', 'start': 10142.682, 'weight': 7, 'content': [{'end': 10149.144, 'text': "at whatever normalized position we have decided on, around our slider's circumference.", 'start': 10142.682, 'duration': 6.462}, {'end': 10156.608, 'text': 'Once we have that bounding box, we can just use the graphics function draw fitted text like we did right here.', 'start': 10150.104, 'duration': 6.504}, {'end': 10158.069, 'text': 'We can do the same thing.', 'start': 10156.628, 'duration': 1.441}, {'end': 10163.092, 'text': 'We can do that to draw our label inside the bounding box.', 'start': 10159.93, 'duration': 3.162}, {'end': 10168.375, 'text': "So first things first, let's get the center and radius of our slider bounds.", 'start': 10163.332, 'duration': 5.043}], 'summary': 'Graphics function draws fitted text inside slider bounding box', 'duration': 25.693, 'max_score': 10142.682, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc10142682.jpg'}, {'end': 10255.423, 'src': 'embed', 'start': 10223.688, 'weight': 5, 'content': [{'end': 10225.309, 'text': "okay, we're going to use the default font.", 'start': 10223.688, 'duration': 1.621}, {'end': 10230.13, 'text': 'with this text height we need to iterate through our labels.', 'start': 10225.309, 'duration': 4.821}, {'end': 10240.112, 'text': 'so auto num choices equals labels dot size, and here we go for int i equals zero.', 'start': 10230.13, 'duration': 9.982}, {'end': 10242.773, 'text': 'i is less than num choices plus i.', 'start': 10240.112, 'duration': 2.661}, {'end': 10247.501, 'text': "Alright, now let's convert that normalized position into a radian angle.", 'start': 10243.84, 'duration': 3.661}, {'end': 10251.482, 'text': 'Auto position equals labels.', 'start': 10248.501, 'duration': 2.981}, {'end': 10255.423, 'text': "We want to make sure that it's between 0 and 1, just in case.", 'start': 10252.882, 'duration': 2.541}], 'summary': 'Using default font, iterating through labels to convert position to radian angle.', 'duration': 31.735, 'max_score': 10223.688, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc10223688.jpg'}, {'end': 10321.266, 'src': 'embed', 'start': 10288.842, 'weight': 6, 'content': [{'end': 10290.103, 'text': 'get point on circumference.', 'start': 10288.842, 'duration': 1.261}, {'end': 10297.707, 'text': 'We can use this member function to find the center point we will use for this bounding box with this particular radian angle.', 'start': 10290.123, 'duration': 7.584}, {'end': 10300.549, 'text': 'We have our center that we will use.', 'start': 10298.487, 'duration': 2.062}, {'end': 10303.872, 'text': 'So center dot get point on circumference.', 'start': 10300.769, 'duration': 3.103}, {'end': 10310.237, 'text': 'Our radius is going to be radius plus get text height.', 'start': 10304.372, 'duration': 5.865}, {'end': 10315.141, 'text': 'Yeah, we want it to be a little bit further out from our rectangle.', 'start': 10310.938, 'duration': 4.203}, {'end': 10321.266, 'text': "So we'll do like half the text height, maybe a little bit of another cushion.", 'start': 10315.682, 'duration': 5.584}], 'summary': 'Using member function to find center point on circumference for bounding box with a specific radian angle, adjusting radius and text height.', 'duration': 32.424, 'max_score': 10288.842, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc10288842.jpg'}, {'end': 10546.972, 'src': 'embed', 'start': 10515.333, 'weight': 4, 'content': [{'end': 10518.015, 'text': "Let's add our min and max ranges.", 'start': 10515.333, 'duration': 2.682}, {'end': 10521.898, 'text': "So we'll start with the peak freak slider.", 'start': 10518.235, 'duration': 3.663}, {'end': 10527.662, 'text': "Okay, and this is where we'll go to our labels and we'll just add one of these label positions.", 'start': 10521.918, 'duration': 5.744}, {'end': 10532.346, 'text': 'So at position zero, I want to display 20 hertz.', 'start': 10527.862, 'duration': 4.484}, {'end': 10538.01, 'text': 'And then at position 1.0, we will display 20 kilohertz.', 'start': 10533.006, 'duration': 5.004}, {'end': 10542.133, 'text': "And then we'll do KHC like that.", 'start': 10539.951, 'duration': 2.182}, {'end': 10543.674, 'text': "Let's see if that looks like anything.", 'start': 10542.213, 'duration': 1.461}, {'end': 10545.751, 'text': 'Okay, cool.', 'start': 10545.231, 'duration': 0.52}, {'end': 10546.972, 'text': '20 Hz, 20 kHz.', 'start': 10545.771, 'duration': 1.201}], 'summary': 'Adding min and max ranges for peak freak slider, displaying 20 hz and 20 khz.', 'duration': 31.639, 'max_score': 10515.333, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc10515333.jpg'}, {'end': 10825.849, 'src': 'embed', 'start': 10796.051, 'weight': 3, 'content': [{'end': 10797.532, 'text': 'Okay, so this is caused.', 'start': 10796.051, 'duration': 1.481}, {'end': 10802.195, 'text': "Let's go look at our timer callback code.", 'start': 10798.773, 'duration': 3.422}, {'end': 10803.756, 'text': 'Response curve component.', 'start': 10802.875, 'duration': 0.881}, {'end': 10812.201, 'text': 'Okay, the chain is only updated whenever the timer callback determines that this parameter is true.', 'start': 10804.216, 'duration': 7.985}, {'end': 10815.724, 'text': 'And this parameter is only set to true whenever the parameter values change.', 'start': 10812.241, 'duration': 3.483}, {'end': 10825.849, 'text': 'So if our GUI is displayed, have the parameters changed since they were initially loaded? No, they have not.', 'start': 10816.284, 'duration': 9.565}], 'summary': 'Timer callback updates chain when parameter values change.', 'duration': 29.798, 'max_score': 10796.051, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc10796051.jpg'}, {'end': 10898.779, 'src': 'embed', 'start': 10869.428, 'weight': 8, 'content': [{'end': 10872.23, 'text': "Okay, we're just going to move that code out of timer callback.", 'start': 10869.428, 'duration': 2.802}, {'end': 10876.553, 'text': 'Void response curve component, update chain.', 'start': 10872.81, 'duration': 3.743}, {'end': 10878.714, 'text': 'We can just grab all this stuff.', 'start': 10876.573, 'duration': 2.141}, {'end': 10880.556, 'text': "We're not going to repaint though.", 'start': 10879.415, 'duration': 1.141}, {'end': 10883.778, 'text': "Okay, now we're just going to call it update chain.", 'start': 10880.576, 'duration': 3.202}, {'end': 10886.82, 'text': 'Now we can call it in our constructor as well.', 'start': 10884.839, 'duration': 1.981}, {'end': 10890.403, 'text': "Let's call it before we do our timer.", 'start': 10887.661, 'duration': 2.742}, {'end': 10898.779, 'text': "All right, let's run it and we should see the chain get updated automatically whenever we close and reopen the GUI.", 'start': 10892.065, 'duration': 6.714}], 'summary': 'Moved code out of timer callback to update chain automatically.', 'duration': 29.351, 'max_score': 10869.428, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc10869428.jpg'}], 'start': 9995.733, 'title': 'Enhancing parameter display and gui visuals', 'summary': 'Covers implementing parameter display with suffix, displaying correct slope values, and adding labels, as well as drawing fitted text with a defined center and bounds. it also involves adjusting gui visuals, fixing a bug in the response curve component, adding min and max ranges for sliders, setting label positions, and updating the chain during construction.', 'chapters': [{'end': 10223.688, 'start': 9995.733, 'title': 'Implementing parameter display and labels', 'summary': 'Focuses on implementing parameter display with suffix, displaying correct slope values, and adding labels to show minimum and maximum values for parameters, using a data structure and drawing them in the paint function.', 'duration': 227.955, 'highlights': ['Implemented displaying the parameter value with suffix, showing 1.01 as an example.', 'Displaying the correct slope values, ensuring the correct display of the slope values.', 'Adding labels to show the minimum and maximum values for parameters using a data structure and drawing them in the paint function.']}, {'end': 10486.832, 'start': 10223.688, 'title': 'Drawing fitted text', 'summary': 'Explains the process of iterating through labels, converting normalized position into a radian angle, and drawing fitted text with a defined center and bounds.', 'duration': 263.144, 'highlights': ['Iterating through labels to set the number of choices and convert normalized position into a radian angle for drawing fitted text.', "Using the 'get point on circumference' member function to find the center point and define the bounding box for the text, ensuring it doesn't collide with the circle.", 'Defining the width and height of the text to create a rectangle with the specified bounds and then drawing the fitted text with the defined center and bounds.']}, {'end': 10915.103, 'start': 10486.832, 'title': 'Adjusting gui visuals and fixing bug', 'summary': 'Involves adjusting gui visuals and fixing a bug in the response curve component, including adding min and max ranges for sliders, setting label positions, and updating the chain during construction to solve a bug.', 'duration': 428.271, 'highlights': ['Adjusting GUI visuals and fixing bug in response curve component by adding min and max ranges for sliders, setting label positions, and updating the chain during construction to solve a bug', 'Setting label positions for the peak freak slider to display 20 Hz and 20 kHz, gain slider to show -24 and +24, quality slider to show 0.1 and 10.0, low cut and high cut sliders to show 20 Hz and 20 kHz, and slope sliders to show 12 and 48', 'Updating the chain during construction to solve a bug in the response curve component by refactoring how parameter values are set and adding an update chain function']}], 'duration': 919.37, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc9995733.jpg', 'highlights': ['Implemented displaying the parameter value with suffix, showing 1.01 as an example.', 'Displaying the correct slope values, ensuring the correct display of the slope values.', 'Adding labels to show the minimum and maximum values for parameters using a data structure and drawing them in the paint function.', 'Adjusting GUI visuals and fixing bug in response curve component by adding min and max ranges for sliders, setting label positions, and updating the chain during construction to solve a bug', 'Setting label positions for the peak freak slider to display 20 Hz and 20 kHz, gain slider to show -24 and +24, quality slider to show 0.1 and 10.0, low cut and high cut sliders to show 20 Hz and 20 kHz, and slope sliders to show 12 and 48', 'Iterating through labels to set the number of choices and convert normalized position into a radian angle for drawing fitted text.', "Using the 'get point on circumference' member function to find the center point and define the bounding box for the text, ensuring it doesn't collide with the circle.", 'Defining the width and height of the text to create a rectangle with the specified bounds and then drawing the fitted text with the defined center and bounds.', 'Updating the chain during construction to solve a bug in the response curve component by refactoring how parameter values are set and adding an update chain function']}, {'end': 12369.293, 'segs': [{'end': 10968.276, 'src': 'embed', 'start': 10943.595, 'weight': 0, 'content': [{'end': 10951.081, 'text': "And then here's where we fixed the response curve issue by refactoring what happens in timer callback into its own function that we can call from our constructor.", 'start': 10943.595, 'duration': 7.486}, {'end': 10953.071, 'text': 'Okay, cool.', 'start': 10952.631, 'duration': 0.44}, {'end': 10959.373, 'text': 'That wraps up the response curve and customizing the knob visuals.', 'start': 10953.571, 'duration': 5.802}, {'end': 10964.095, 'text': 'Okay, the next thing to do is to put a grid behind the response curve.', 'start': 10959.873, 'duration': 4.222}, {'end': 10968.276, 'text': 'And then after we do that, we can add the spectrum analyzer.', 'start': 10964.695, 'duration': 3.581}], 'summary': 'Fixed response curve issue, customized knob visuals, added grid and spectrum analyzer.', 'duration': 24.681, 'max_score': 10943.595, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc10943595.jpg'}, {'end': 11044.434, 'src': 'embed', 'start': 11015.451, 'weight': 1, 'content': [{'end': 11022.035, 'text': 'because it is called whenever the component bounds change and it is called before the first time that paint is called.', 'start': 11015.451, 'duration': 6.584}, {'end': 11024.216, 'text': "So let's declare that guy here.", 'start': 11022.776, 'duration': 1.44}, {'end': 11027.378, 'text': "All right, let's go to our CPP file.", 'start': 11024.237, 'duration': 3.141}, {'end': 11029.66, 'text': "Let's put this after our paint function.", 'start': 11028.199, 'duration': 1.461}, {'end': 11038.456, 'text': 'The first thing we will do in this resized function is make a new background image based on the width and height of our component.', 'start': 11030.953, 'duration': 7.503}, {'end': 11044.434, 'text': "Okay, so first let's declare this void response curve component resized.", 'start': 11039.451, 'duration': 4.983}], 'summary': "The resized function is called when component bounds change to create a new background image based on the component's width and height.", 'duration': 28.983, 'max_score': 11015.451, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc11015451.jpg'}, {'end': 11442.978, 'src': 'embed', 'start': 11406.374, 'weight': 2, 'content': [{'end': 11409.556, 'text': "And then height-wise, I don't think I need that much.", 'start': 11406.374, 'duration': 3.182}, {'end': 11413.118, 'text': "I'm going to go with 8.", 'start': 11409.576, 'duration': 3.542}, {'end': 11419.882, 'text': 'So 10 for the width reduction and then 8 for the height reduction.', 'start': 11413.118, 'duration': 6.764}, {'end': 11422.803, 'text': '10 and 8.', 'start': 11419.902, 'duration': 2.901}, {'end': 11423.984, 'text': 'So let me just make that change here.', 'start': 11422.803, 'duration': 1.181}, {'end': 11432.11, 'text': '10, 8.', 'start': 11424.004, 'duration': 8.106}, {'end': 11433.791, 'text': 'put this on its own line for right now.', 'start': 11432.11, 'duration': 1.681}, {'end': 11439.915, 'text': "Okay, I'm happy with that, so let's make the response curve sit within this rectangle now.", 'start': 11435.312, 'duration': 4.603}, {'end': 11442.978, 'text': "Let's go to our paint function.", 'start': 11441.937, 'duration': 1.041}], 'summary': 'Reducing width by 10 and height by 8 for the response curve rectangle.', 'duration': 36.604, 'max_score': 11406.374, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc11406374.jpg'}, {'end': 11618.719, 'src': 'embed', 'start': 11590.374, 'weight': 3, 'content': [{'end': 11596.66, 'text': "So that's what I mean when I say our analysis area is going to be a little bit smaller than our render area.", 'start': 11590.374, 'duration': 6.286}, {'end': 11601.264, 'text': "So let's implement this back to our CPP file.", 'start': 11598.602, 'duration': 2.662}, {'end': 11602.045, 'text': 'Put this right here.', 'start': 11601.304, 'duration': 0.741}, {'end': 11605.728, 'text': "We're going to start with our render area.", 'start': 11604.227, 'duration': 1.501}, {'end': 11610.572, 'text': "And then we're going to trim some off the top and trim off the bottom.", 'start': 11607.309, 'duration': 3.263}, {'end': 11618.719, 'text': 'So that way we can see the top and bottom line of our grid as I had explained a moment ago.', 'start': 11610.852, 'duration': 7.867}], 'summary': 'The analysis area will be smaller than the render area for the grid display.', 'duration': 28.345, 'max_score': 11590.374, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc11590374.jpg'}, {'end': 12070.046, 'src': 'embed', 'start': 12041.288, 'weight': 4, 'content': [{'end': 12042.888, 'text': "All right, let's run it and take a look.", 'start': 12041.288, 'duration': 1.6}, {'end': 12044.949, 'text': 'All right, cool.', 'start': 12044.349, 'duration': 0.6}, {'end': 12047.51, 'text': 'Uh, we got some collision of texts going on here.', 'start': 12045.329, 'duration': 2.181}, {'end': 12049.79, 'text': "That's okay though.", 'start': 12049.09, 'duration': 0.7}, {'end': 12051.751, 'text': "We'll figure that out next.", 'start': 12050.691, 'duration': 1.06}, {'end': 12053.472, 'text': 'All right.', 'start': 12053.251, 'duration': 0.221}, {'end': 12059.653, 'text': 'So it looks like the 40 and, um, the 30 and the 40 are getting pretty close.', 'start': 12053.512, 'duration': 6.141}, {'end': 12061.874, 'text': '300 and 400 collide a lot.', 'start': 12060.113, 'duration': 1.761}, {'end': 12063.334, 'text': '3k and 4k collide a lot.', 'start': 12062.134, 'duration': 1.2}, {'end': 12064.795, 'text': "So let's get rid of those.", 'start': 12063.735, 'duration': 1.06}, {'end': 12067.645, 'text': "And let's try that again.", 'start': 12066.785, 'duration': 0.86}, {'end': 12070.046, 'text': 'Ah, much cleaner.', 'start': 12069.106, 'duration': 0.94}], 'summary': 'Identified text collisions, resolved 300 and 400 collisions, achieving a much cleaner result.', 'duration': 28.758, 'max_score': 12041.288, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc12041288.jpg'}], 'start': 10915.643, 'title': 'Plugin editor enhancements', 'summary': 'Covers fixing response curve bug, adding star values and labels, finalizing component positions, pre-rendering background image, adjusting bounding box and render area, and adding frequency and gain labels, showcasing quick project progression and addressing specific examples such as 300 and 400 collisions and gain range for the peak band being 48.', 'chapters': [{'end': 10993.752, 'start': 10915.643, 'title': 'Response curve bug fix and component progress', 'summary': 'Details the process of fixing the response curve bug, adding star values and labels, finalizing component positions, and planning the addition of a grid, spectrum analyzer, and bypass buttons, showcasing a quick project progression.', 'duration': 78.109, 'highlights': ['The response curve bug was fixed by refactoring the timer callback into a separate function, resulting in improved GUI functionality.', 'The process involved displaying star values and adding labels, finalizing component positions, and planning the addition of a grid, spectrum analyzer, and bypass buttons.', 'Project progress is described as quick, at a pretty good clip, with three major tasks remaining before completion.']}, {'end': 11261.315, 'start': 10994.172, 'title': 'Pre-rendering component background image', 'summary': 'Discusses the pre-rendering of a background image in a plugin editor, utilizing the resized function to create a new background image based on component dimensions, drawing frequency and gain lines, and addressing collision issues.', 'duration': 267.143, 'highlights': ["Utilizing the resized function to create a background image based on the component's dimensions, ensuring it is called before the first paint operation.", 'Drawing frequency lines using standard values in multiples of 10 and mapping them to a normalized position, with the top frequency being the top of the human hearing range.', 'Drawing gain lines every 12 decibels, mapping the gain slider ranges to the component, and addressing collision issues in the graphic rendering.']}, {'end': 11486.512, 'start': 11262.076, 'title': 'Adjusting bounding box and render area', 'summary': 'Discusses adjusting the bounding box and render area for drawing the background grid and response curve, reducing the bounding box by 10 for width and 8 for height, and updating the paint function to reflect the changes.', 'duration': 224.436, 'highlights': ['Reducing the bounding box by 10 for the width and 8 for the height results in a more refined render area for drawing the background grid and response curve.', 'Updating the paint function to reflect the changes by setting the response area to the render area results in progress in the drawing process.', 'Utilizing the juiceLiveConstant and reduce function to calculate the adjusted bounding box and render area contributes to the accuracy and precision of the drawing process.']}, {'end': 12037.715, 'start': 11487.915, 'title': 'Adjusting render area and analysis area', 'summary': 'Discusses adjusting the render area and analysis area by removing space from the top, bottom, and sides, implementing functions to separate the render and analysis areas, caching information about the analysis area, drawing grid lines, gain lines, and frequency labels, and pre-rendering grid into a background image.', 'duration': 549.8, 'highlights': ['The render area and analysis area are adjusted by removing space from the top, bottom, and sides, with 12 pixels gap at the top, 20 pixels gap on the sides, and grid lines being drawn within the analysis area.', 'Functions are implemented to separate the render and analysis areas, and information about the analysis area is cached, including left, right, top, bottom, and width.', 'Grid lines, gain lines, and frequency labels are drawn within the analysis area, with a font height of 10 and light gray color for the labels to pop out.', 'The chapter also involves pre-rendering grid into a background image, and making adjustments for a visually appealing display.']}, {'end': 12369.293, 'start': 12041.288, 'title': 'Adding frequency and gain labels', 'summary': 'Details the process of adding frequency labels, thinning out number of frequencies, and adding gain labels to a grid, with specific examples such as 300 and 400 collisions and gain range for the peak band being 48.', 'duration': 328.005, 'highlights': ['The chapter discusses the collision of texts, such as the 40 and 30, and the 300 and 400, as well as 3k and 4k, providing insight into the process of thinning out the number of frequencies.', 'It details the addition of gain labels to a grid, with examples of gain values such as plus 24, plus 12, zero, minus 24, and minus 12, and the process of aligning the text and setting the color accordingly.', 'The process of adding frequency labels and thinning out the number of frequencies is outlined, along with specific examples of collision between values like 300 and 400, and 3k and 4k.']}], 'duration': 1453.65, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc10915643.jpg', 'highlights': ['The response curve bug was fixed by refactoring the timer callback into a separate function, resulting in improved GUI functionality.', "Utilizing the resized function to create a background image based on the component's dimensions, ensuring it is called before the first paint operation.", 'Reducing the bounding box by 10 for the width and 8 for the height results in a more refined render area for drawing the background grid and response curve.', 'The render area and analysis area are adjusted by removing space from the top, bottom, and sides, with 12 pixels gap at the top, 20 pixels gap on the sides, and grid lines being drawn within the analysis area.', 'The chapter discusses the collision of texts, such as the 40 and 30, and the 300 and 400, as well as 3k and 4k, providing insight into the process of thinning out the number of frequencies.']}, {'end': 13684.084, 'segs': [{'end': 12442.838, 'src': 'embed', 'start': 12404.124, 'weight': 0, 'content': [{'end': 12405.984, 'text': 'What we added here, this was a code cleanup.', 'start': 12404.124, 'duration': 1.86}, {'end': 12410.655, 'text': 'And then we also added analyzer decibel marks.', 'start': 12407.153, 'duration': 3.502}, {'end': 12415.098, 'text': 'Added analyzer decibel marks.', 'start': 12411.256, 'duration': 3.842}, {'end': 12417.42, 'text': 'Cleaned up code.', 'start': 12415.979, 'duration': 1.441}, {'end': 12429.108, 'text': "Awesome All right, let's head on over to pluginprocessor.h.", 'start': 12420.102, 'duration': 9.006}, {'end': 12431.61, 'text': 'Okay, go up to the top.', 'start': 12429.208, 'duration': 2.402}, {'end': 12438.115, 'text': 'Now our analyzer will display two FFT curves, one for each audio channel.', 'start': 12432.492, 'duration': 5.623}, {'end': 12442.838, 'text': "That's because the FFT algorithm operates on a single channel of audio.", 'start': 12438.716, 'duration': 4.122}], 'summary': 'Code cleanup and addition of analyzer decibel marks for dual fft curves.', 'duration': 38.714, 'max_score': 12404.124, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc12404124.jpg'}, {'end': 12727.668, 'src': 'embed', 'start': 12699.295, 'weight': 1, 'content': [{'end': 12702.997, 'text': 'And finally, the GUI consumes those and renders the paths.', 'start': 12699.295, 'duration': 3.702}, {'end': 12709.5, 'text': 'OK? So buffers of random size are fed into the single channel sample FIFO right here.', 'start': 12703.477, 'duration': 6.023}, {'end': 12711.44, 'text': 'This thing spits out fixed size blocks.', 'start': 12709.56, 'duration': 1.88}, {'end': 12714.182, 'text': 'Then those go into an FFT data generator.', 'start': 12712.061, 'duration': 2.121}, {'end': 12717.683, 'text': 'The FFT data generator spits out FFT data blocks.', 'start': 12714.802, 'duration': 2.881}, {'end': 12721.885, 'text': 'Then those get run through a path producer, which produces juice paths.', 'start': 12718.204, 'duration': 3.681}, {'end': 12725.507, 'text': 'And those get rendered and consumed by the GUI.', 'start': 12722.505, 'duration': 3.002}, {'end': 12727.668, 'text': "OK? That's what we are going to build.", 'start': 12725.527, 'duration': 2.141}], 'summary': 'Random size buffers fed into fifo, fft data generated, paths rendered by gui.', 'duration': 28.373, 'max_score': 12699.295, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc12699295.jpg'}, {'end': 13065.656, 'src': 'embed', 'start': 13040.841, 'weight': 3, 'content': [{'end': 13050.308, 'text': "So that's what I meant about how we have to append the blocks to the end of it and shift everything towards the front of the vector.", 'start': 13040.841, 'duration': 9.467}, {'end': 13052.609, 'text': "So we're going to implement that now.", 'start': 13051.088, 'duration': 1.521}, {'end': 13060.872, 'text': 'Okay, so we are going to need a mono buffer, because remember these are mono channels of audio.', 'start': 13053.587, 'duration': 7.285}, {'end': 13065.656, 'text': 'Newest blocks are going to get stuck at the end and the oldest blocks are going to go at the front,', 'start': 13062.213, 'duration': 3.443}], 'summary': 'Implementing appending of blocks to mono buffer for audio channels.', 'duration': 24.815, 'max_score': 13040.841, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc13040841.jpg'}, {'end': 13454.752, 'src': 'embed', 'start': 13430.462, 'weight': 2, 'content': [{'end': 13439.066, 'text': 'if our sample rate is 48 000 and then we have 2048 bins, each bin roughly accounts for 23 hertz.', 'start': 13430.462, 'duration': 8.604}, {'end': 13441.527, 'text': "so that means we're going to get a lot of.", 'start': 13439.066, 'duration': 2.461}, {'end': 13446.989, 'text': "this means we're going to get a lot of resolution at the upper end and not a lot of resolution at the bottom end.", 'start': 13441.527, 'duration': 5.462}, {'end': 13451.771, 'text': "so let's just take a look at our plot So you can see what I'm talking about.", 'start': 13446.989, 'duration': 4.782}, {'end': 13454.752, 'text': 'Okay, you can see that like whoops.', 'start': 13452.011, 'duration': 2.741}], 'summary': 'At a sample rate of 48,000 and 2048 bins, each bin represents roughly 23 hz, resulting in varying resolution across frequencies.', 'duration': 24.29, 'max_score': 13430.462, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc13430462.jpg'}], 'start': 12369.293, 'title': 'Audio processing and fft analysis', 'summary': 'Covers code cleanup and fft analyzer implementation, audio processing system design, fft generation, and audio spectrum analysis, providing a detailed explanation of the processes and their impacts on system performance and functionality.', 'chapters': [{'end': 12580.921, 'start': 12369.293, 'title': 'Audio processing code cleanup and fft analyzer implementation', 'summary': 'Covers the process of cleaning up the code by removing unnecessary lines and implementing an fft analyzer that displays two fft curves, one for each audio channel, along with the explanation of the classes involved in the process and references to related courses.', 'duration': 211.628, 'highlights': ['The FFT analyzer will display two FFT curves, one for each audio channel.', 'The process involves cleaning up the code and adding analyzer decibel marks.', 'Explanation of classes involved in the process and references to related courses is provided.', 'Creation of instances of single channel FIFO per audio channel is demonstrated, with the use of type alias to simplify code.']}, {'end': 13022.971, 'start': 12581.261, 'title': 'Audio processing system design', 'summary': 'Discusses the design and coordination of an audio processing system, including the preparation and utilization of single channel fifos and the process of generating fft data blocks and rendering juice paths for the gui.', 'duration': 441.71, 'highlights': ['The system involves preparing single channel FIFOs, pushing buffers into them, and converting audio samples into FFT data, resulting in the generation of juice path instances for GUI rendering.', 'The process involves coordinating the single channel sample FIFO, pulling buffers, and sending them to the FFT data generator to maintain order and size consistency of the blocks.', 'The design includes the creation of mono buffers to ferry audio blocks from right to left and ensure continuity and seamless transition of data for processing and consumption.']}, {'end': 13372.598, 'start': 13023.031, 'title': 'Audio data processing and fft generation', 'summary': 'Explains the process of shifting and appending audio blocks in a mono buffer, initializing the fft data generator, configuring it, and ensuring the mono buffer has the required size for fft processing.', 'duration': 349.567, 'highlights': ['The process involves shifting and appending audio blocks in a mono buffer to ensure the newest blocks are placed at the end and the oldest at the front, thus preparing the buffer for FFT data generation.', 'The FFT data generator, which operates on vectors of floats, must be initialized and configured to handle the incoming audio blocks and provide the necessary FFT data for further processing.', 'The mono buffer needs to have a specific size to match the requirements of the FFT data generator, ensuring that it can effectively handle the audio data for FFT processing.']}, {'end': 13684.084, 'start': 13372.598, 'title': 'Audio spectrum analysis', 'summary': 'Explains the concept of splitting the audio spectrum into 2048 equally sized frequency bins, where each bin representing roughly 23 hertz, resulting in a lot of resolution at the upper end and not much at the bottom end, with the option to increase fft order for more resolution in the lower end at the expense of more cpu.', 'duration': 311.486, 'highlights': ['Splitting the audio spectrum into 2048 equally sized frequency bins, with each bin representing roughly 23 hertz, resulting in a lot of resolution at the upper end and not much at the bottom end.', 'Increasing the FFT order provides more resolution in the lower end at the expense of more CPU.', 'Configuring the FFT with 2048 frequency bins to avoid major performance impacts during usage.']}], 'duration': 1314.791, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc12369293.jpg', 'highlights': ['The FFT analyzer will display two FFT curves, one for each audio channel.', 'The system involves preparing single channel FIFOs, pushing buffers into them, and converting audio samples into FFT data, resulting in the generation of juice path instances for GUI rendering.', 'Splitting the audio spectrum into 2048 equally sized frequency bins, with each bin representing roughly 23 hertz, resulting in a lot of resolution at the upper end and not much at the bottom end.', 'The process involves shifting and appending audio blocks in a mono buffer to ensure the newest blocks are placed at the end and the oldest at the front, thus preparing the buffer for FFT data generation.']}, {'end': 14812.526, 'segs': [{'end': 13720.776, 'src': 'embed', 'start': 13685.134, 'weight': 0, 'content': [{'end': 13687.235, 'text': "Okay, so let's build it and see what happens.", 'start': 13685.134, 'duration': 2.101}, {'end': 13688.736, 'text': 'All right, build failed.', 'start': 13687.735, 'duration': 1.001}, {'end': 13692.237, 'text': 'Why are we failing? Too few arguments, expect a call.', 'start': 13688.896, 'duration': 3.341}, {'end': 13699.741, 'text': 'Aha, this is because our FIFO class needs a second prepare function to handle when the type is vector, not audio buffer.', 'start': 13692.397, 'duration': 7.344}, {'end': 13702.022, 'text': "That's over here in our plugin processor.", 'start': 13700.141, 'duration': 1.881}, {'end': 13703.843, 'text': 'All right, it wants this.', 'start': 13702.822, 'duration': 1.021}, {'end': 13706.165, 'text': 'We are currently using this.', 'start': 13704.443, 'duration': 1.722}, {'end': 13707.366, 'text': "Let's see what's going on.", 'start': 13706.505, 'duration': 0.861}, {'end': 13708.347, 'text': 'Prepare is declared here.', 'start': 13707.426, 'duration': 0.921}, {'end': 13710.268, 'text': 'We are instantiating it.', 'start': 13709.087, 'duration': 1.181}, {'end': 13712.69, 'text': 'Where is this being called from?', 'start': 13711.489, 'duration': 1.201}, {'end': 13720.776, 'text': "It's being called right here, where we've got a FIFO with our block type of.", 'start': 13713.611, 'duration': 7.165}], 'summary': 'Debugging plugin processor for fifo class, resolving too few arguments issue.', 'duration': 35.642, 'max_score': 13685.134, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc13685134.jpg'}, {'end': 13880.797, 'src': 'embed', 'start': 13857.01, 'weight': 1, 'content': [{'end': 13863.712, 'text': "So now we need to turn those blocks into a path instance, okay? So let's write a path generator class.", 'start': 13857.01, 'duration': 6.702}, {'end': 13865.832, 'text': "Alright, let's go up to our header file.", 'start': 13864.332, 'duration': 1.5}, {'end': 13871.754, 'text': "We'll go after the FFT data generator, before the look and feel guy.", 'start': 13866.473, 'duration': 5.281}, {'end': 13880.797, 'text': "Now this class is going to take in this FFT data abounding box, info about the FFT size and the bin width, and it's going to spit out a path.", 'start': 13872.194, 'duration': 8.603}], 'summary': 'Create a path generator class to process fft data for a path instance.', 'duration': 23.787, 'max_score': 13857.01, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc13857010.jpg'}, {'end': 14024.43, 'src': 'embed', 'start': 13996.131, 'weight': 3, 'content': [{'end': 14003.356, 'text': "It's going to want a bounding box and it wants to know the FFT size, the bin width and where negative infinity is,", 'start': 13996.131, 'duration': 7.225}, {'end': 14005.498, 'text': 'or what value is being considered negative infinity.', 'start': 14003.356, 'duration': 2.142}, {'end': 14008.913, 'text': "Okay So let's provide those things.", 'start': 14006.431, 'duration': 2.482}, {'end': 14024.43, 'text': 'So our bounding box is going to be our FFT bounds get analysis area and it wants it to be float all right and it needs to know the fft size and the bandwidth and frequencies.', 'start': 14010.374, 'duration': 14.056}], 'summary': 'Provide a float fft bounding box with fft size and bin width.', 'duration': 28.299, 'max_score': 13996.131, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc13996131.jpg'}, {'end': 14779.72, 'src': 'embed', 'start': 14747.839, 'weight': 4, 'content': [{'end': 14756.222, 'text': 'stereo context from the block, and then now we can just do osc.process stereo context.', 'start': 14747.839, 'duration': 8.383}, {'end': 14757.843, 'text': "All right, that's it.", 'start': 14757.183, 'duration': 0.66}, {'end': 14760.044, 'text': 'Okay, and we can now check the accuracy.', 'start': 14758.223, 'duration': 1.821}, {'end': 14763.725, 'text': "So apologies in advance for the annoying sine waves we're going to hear.", 'start': 14760.624, 'duration': 3.101}, {'end': 14770.948, 'text': 'Okay, so our frequency was 200.', 'start': 14768.507, 'duration': 2.441}, {'end': 14773.309, 'text': "So let's try 500 and 1, 000 and 50 and 5k and see what it looks like.", 'start': 14770.948, 'duration': 2.361}, {'end': 14779.72, 'text': "So I'm going to change this to a thousand.", 'start': 14777.259, 'duration': 2.461}], 'summary': 'Testing accuracy of frequency at 200, 500, 1000, 5000 hz.', 'duration': 31.881, 'max_score': 14747.839, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc14747839.jpg'}], 'start': 13685.134, 'title': 'Fft path generation and data analysis', 'summary': 'Covers creating a prepare function for the fifo class to handle vector type, developing an fft path generator class, implementing the fft path generator, addressing bugs, and analyzing fft data and positioning with test frequencies of 200, 500, 1000, 5000, and 50, along with their corresponding observations.', 'chapters': [{'end': 13943.486, 'start': 13685.134, 'title': 'Fifo preparation and path generation', 'summary': 'Discusses the process of creating a second prepare function for the fifo class to handle vector type, incorporating static asserts to ensure the correct prepare function is utilized, and developing a path generator class to convert fft data blocks into a path instance.', 'duration': 258.352, 'highlights': ['Creation of a second prepare function for FIFO class to handle vector type, incorporating static asserts to ensure the correct prepare function is utilized, leading to successful build', 'Development of a path generator class to convert FFT data blocks into a path instance, providing a simplified version of the path producer in Project 11 and emphasizing the importance of learning to create advanced versions']}, {'end': 14512.528, 'start': 13944.787, 'title': 'Implementing fft path generator', 'summary': 'Explains the process of implementing the fft path generator, including generating paths from fft data, retrieving and drawing the paths, and addressing bugs in the code, leading to the successful implementation of a basic fft design.', 'duration': 567.741, 'highlights': ['The chapter explains the process of implementing the FFT path generator, including generating paths from FFT data, retrieving and drawing the paths, and addressing bugs in the code (relevance score: 5)', 'The FFT path generator requires rendered data, a bounding box, FFT size, bin width, and a value considered as negative infinity, providing a comprehensive overview of the necessary parameters (relevance score: 4)', 'The process involves retrieving FFT data buffers, generating paths, and addressing potential issues related to the speed of path production and consumption, demonstrating the practical application of the path generation process (relevance score: 3)', 'The chapter highlights the successful implementation of a basic FFT design, showcasing the functional outcome of the discussed implementation process (relevance score: 2)']}, {'end': 14812.526, 'start': 14512.548, 'title': 'Fft data analysis and positioning', 'summary': 'Involves fixing the fft path position, preparing and using an oscillator to verify the accuracy of the analyzer, with test frequencies of 200, 500, 1000, 5000, and 50, along with their corresponding observations.', 'duration': 299.978, 'highlights': ["Using an oscillator to verify the accuracy of the analyzer with test frequencies of 200, 1000, 5000, and 50, observing the corresponding blips in the data (e.g., 'Yikes, that's painful' at 5k).", 'Fixing the FFT path position and making a commit to show the fix, as some bugs take a long time to diagnose and solve.', 'Preparing the oscillator, setting its frequency, and using it in the process block to fill the buffer, checking the accuracy with apologies for the annoying sine waves.']}], 'duration': 1127.392, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc13685134.jpg', 'highlights': ['Creation of a second prepare function for FIFO class to handle vector type, ensuring successful build', 'Development of a path generator class to convert FFT data blocks into a path instance', 'The chapter explains the process of implementing the FFT path generator, including generating paths from FFT data, retrieving and drawing the paths, and addressing bugs', 'The FFT path generator requires rendered data, a bounding box, FFT size, bin width, and a value considered as negative infinity', 'Using an oscillator to verify the accuracy of the analyzer with test frequencies of 200, 1000, 5000, and 50, observing the corresponding blips in the data']}, {'end': 16199.115, 'segs': [{'end': 14888.224, 'src': 'embed', 'start': 14858.768, 'weight': 4, 'content': [{'end': 14861.97, 'text': "we're going to turn that off, because who wants to listen to those sine waves again?", 'start': 14858.768, 'duration': 3.202}, {'end': 14871.138, 'text': "Okay, let's grab everything we used in the single channel version of the FFT and put it into its own class.", 'start': 14863.655, 'duration': 7.483}, {'end': 14880.221, 'text': 'This is going to be the single channel FIFO buffer, the mono buffer, FFT generator, analyzer path generator, and the path itself.', 'start': 14871.878, 'duration': 8.343}, {'end': 14882.002, 'text': "So let's make a new class.", 'start': 14881.001, 'duration': 1.001}, {'end': 14884.723, 'text': "We're just going to migrate these things over there first.", 'start': 14882.022, 'duration': 2.701}, {'end': 14888.224, 'text': "Okay, so I'm just going to cut these.", 'start': 14884.743, 'duration': 3.481}], 'summary': 'Migrating components into a new class for fft analysis.', 'duration': 29.456, 'max_score': 14858.768, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc14858768.jpg'}, {'end': 15125.664, 'src': 'embed', 'start': 15096.356, 'weight': 2, 'content': [{'end': 15102.257, 'text': 'Do the same thing with the FFT bounds and through the path producer loops.', 'start': 15096.356, 'duration': 5.901}, {'end': 15108.359, 'text': 'And now instead of doing auto FFT equals get analysis area, this is a function argument.', 'start': 15103.657, 'duration': 4.702}, {'end': 15109.819, 'text': "So let's get rid of that.", 'start': 15108.979, 'duration': 0.84}, {'end': 15114.82, 'text': 'And then our bandwidth is using the sample rate.', 'start': 15111.62, 'duration': 3.2}, {'end': 15117.181, 'text': 'Very convenient.', 'start': 15116.321, 'duration': 0.86}, {'end': 15119.06, 'text': 'All right.', 'start': 15118.86, 'duration': 0.2}, {'end': 15125.664, 'text': 'So we took all of that code away, and now we are going to call our process function instead.', 'start': 15119.861, 'duration': 5.803}], 'summary': 'Updated code to use function argument for auto fft and bandwidth derived from sample rate.', 'duration': 29.308, 'max_score': 15096.356, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc15096356.jpg'}, {'end': 15419.984, 'src': 'embed', 'start': 15391.116, 'weight': 0, 'content': [{'end': 15397.48, 'text': 'Implemented FFT spectrum analyzer.', 'start': 15391.116, 'duration': 6.364}, {'end': 15399.861, 'text': "Okay, let's just stage all this stuff.", 'start': 15397.5, 'duration': 2.361}, {'end': 15401.562, 'text': 'And commit.', 'start': 15401.182, 'duration': 0.38}, {'end': 15406.225, 'text': 'Okay, so the next thing that I want to add is some bypass buttons for each band.', 'start': 15402.383, 'duration': 3.842}, {'end': 15411.988, 'text': 'And then a bypass button for the analyzer because those analyzers always use a ton of CPU.', 'start': 15406.905, 'duration': 5.083}, {'end': 15413.509, 'text': 'Okay, cool.', 'start': 15413.129, 'duration': 0.38}, {'end': 15419.984, 'text': 'All right, time for the bypass buttons.', 'start': 15418.123, 'duration': 1.861}], 'summary': 'Implemented fft spectrum analyzer, added bypass buttons for each band and analyzer to save cpu usage.', 'duration': 28.868, 'max_score': 15391.116, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc15391116.jpg'}, {'end': 15754.128, 'src': 'embed', 'start': 15722.206, 'weight': 1, 'content': [{'end': 15729.651, 'text': 'You should see three buttons right in the middle, centered among the three columns of sliders.', 'start': 15722.206, 'duration': 7.445}, {'end': 15731.852, 'text': 'And there we go.', 'start': 15731.332, 'duration': 0.52}, {'end': 15732.753, 'text': "Here's our toggle button.", 'start': 15731.892, 'duration': 0.861}, {'end': 15734.154, 'text': 'All right, cool.', 'start': 15733.734, 'duration': 0.42}, {'end': 15736.976, 'text': "Let's connect them to parameters next.", 'start': 15734.774, 'duration': 2.202}, {'end': 15743.604, 'text': 'Alright, go back to plugin-editor.h, and we need to declare some button attachments.', 'start': 15738.922, 'duration': 4.682}, {'end': 15751.827, 'text': 'So using button-attachment equals APVTS button-attachment.', 'start': 15743.964, 'duration': 7.863}, {'end': 15754.128, 'text': 'And now we can declare four of them.', 'start': 15752.867, 'duration': 1.261}], 'summary': 'Three buttons and four button attachments were declared in the plugin-editor.h file.', 'duration': 31.922, 'max_score': 15722.206, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc15722206.jpg'}, {'end': 15866.498, 'src': 'embed', 'start': 15838.137, 'weight': 3, 'content': [{'end': 15846.446, 'text': 'All right, so the bypass control definitely works, but the response curve is not updating.', 'start': 15838.137, 'duration': 8.309}, {'end': 15851.946, 'text': "Let's take care of that next.", 'start': 15850.765, 'duration': 1.181}, {'end': 15853.387, 'text': 'All right.', 'start': 15853.147, 'duration': 0.24}, {'end': 15859.232, 'text': "Let's head on up to our update chain function for the, uh, response curve component.", 'start': 15853.507, 'duration': 5.725}, {'end': 15863.155, 'text': "Now we've got our chain settings right here.", 'start': 15860.733, 'duration': 2.422}, {'end': 15866.498, 'text': "So we're going to do the same thing we did with the process block.", 'start': 15863.775, 'duration': 2.723}], 'summary': 'Bypass control works, response curve not updating. troubleshooting in progress.', 'duration': 28.361, 'max_score': 15838.137, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc15838137.jpg'}], 'start': 14813.226, 'title': 'Audio plugin development and implementation', 'summary': 'Covers the process of adding generators for audio channels, implementing response curves and path producers, and implementing an fft spectrum analyzer, with a focus on understanding audio plugin development and debugging. it also involves adding bypass buttons, updating bypass control components, and implementing toggle button functions in the plugin editor.', 'chapters': [{'end': 14902.09, 'start': 14813.226, 'title': 'Audio plugin development', 'summary': 'Discusses the process of adding a second set of generators for the right audio channel and migrating components to a new class, aiming to understand audio plugin development.', 'duration': 88.864, 'highlights': ['Adding a second set of generators for the right audio channel.', 'Migrating components to a new class for the single channel FIFO buffer, the mono buffer, FFT generator, analyzer path generator, and the path itself.', 'Noting the potential errors that may arise during the build process.']}, {'end': 15361.002, 'start': 14906.732, 'title': 'Implementing response curve and path producers', 'summary': "Discusses implementing a response curve and path producers for both channels, initializing the fft data generator and monobuffer, and debugging the code to display the left and right channels' paths in the audio plugin host.", 'duration': 454.27, 'highlights': ['Implemented a process function to handle temp buffer, FFT bounds, and sample rate, enabling the initialization of path producers for both channels.', 'Debugged the code to resolve the issue of displaying only the left path by identifying the error of drawing the left path twice and verifying the proper audio input through a test oscillator.', 'Added constructors and path retrieval methods to enable the initialization and retrieval of path producers for both channels.']}, {'end': 15838.117, 'start': 15361.182, 'title': 'Fft spectrum analyzer implementation', 'summary': 'Outlines the implementation of an fft spectrum analyzer, including adding bypass buttons for each band and the analyzer, creating boolean parameters for bypassing each band and enabling/disabling the analyzer, and connecting toggle buttons to parameters.', 'duration': 476.935, 'highlights': ['Implemented FFT spectrum analyzer and added bypass buttons for each band and the analyzer, reducing CPU usage. (3 bands, 1 analyzer)', 'Created 3 boolean parameters for bypassing each individual band and 1 for enabling/disabling the analyzer, enhancing flexibility. (3 bands, 1 analyzer)', 'Connected toggle buttons to parameters, facilitating user control and customization. (4 buttons)']}, {'end': 16199.115, 'start': 15838.137, 'title': 'Update and implement bypass control', 'summary': 'Discusses updating the bypass control response curve component, adding bypass buttons, and implementing the toggle button look and feel function in the plugin editor.', 'duration': 360.978, 'highlights': ['The chapter discusses updating the bypass control and response curve component, including setting bypass states for different chain positions and checking if individual bands are bypassed.', 'It covers the addition of bypass buttons and the ability to bypass DSP bands, with a commitment to make a dial-in graphics next.', 'The implementation of the toggle button look and feel function in the plugin editor is detailed, including adding a power button type of graphic using the path function.']}], 'duration': 1385.889, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc14813226.jpg', 'highlights': ['Implemented FFT spectrum analyzer and added bypass buttons for each band and the analyzer, reducing CPU usage. (3 bands, 1 analyzer)', 'Connected toggle buttons to parameters, facilitating user control and customization. (4 buttons)', 'Implemented a process function to handle temp buffer, FFT bounds, and sample rate, enabling the initialization of path producers for both channels.', 'The chapter discusses updating the bypass control and response curve component, including setting bypass states for different chain positions and checking if individual bands are bypassed.', 'Migrating components to a new class for the single channel FIFO buffer, the mono buffer, FFT generator, analyzer path generator, and the path itself.']}, {'end': 18200.732, 'segs': [{'end': 16231.91, 'src': 'embed', 'start': 16199.215, 'weight': 4, 'content': [{'end': 16199.615, 'text': 'Enough of that.', 'start': 16199.215, 'duration': 0.4}, {'end': 16200.995, 'text': "Let's see.", 'start': 16200.475, 'duration': 0.52}, {'end': 16202.456, 'text': 'Path power button.', 'start': 16201.135, 'duration': 1.321}, {'end': 16206.437, 'text': 'Okay First thing first is we are going to create a rectangle.', 'start': 16202.476, 'duration': 3.961}, {'end': 16209.337, 'text': 'This rectangle is going to have equal length sides.', 'start': 16206.917, 'duration': 2.42}, {'end': 16217.548, 'text': "And in the center of that will be our Yeah, this rectangle is going to be center in our component's bounding box.", 'start': 16209.457, 'duration': 8.091}, {'end': 16218.851, 'text': "So let's do that first.", 'start': 16218.109, 'duration': 0.742}, {'end': 16226.606, 'text': "Where's our top? We're going to do that same Jmin thing that we were talking about.", 'start': 16221.419, 'duration': 5.187}, {'end': 16231.91, 'text': 'We did that up for the, we did that somewhere.', 'start': 16227.687, 'duration': 4.223}], 'summary': "Creating a rectangle with equal length sides in a component's bounding box.", 'duration': 32.695, 'max_score': 16199.215, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc16199215.jpg'}, {'end': 16524.647, 'src': 'embed', 'start': 16488.769, 'weight': 0, 'content': [{'end': 16492.312, 'text': "Okay, so I'm going to use a stroke thickness of, we'll try two.", 'start': 16488.769, 'duration': 3.543}, {'end': 16500.487, 'text': "And then for the joint style, if I use a curved joint style, it'll give me rounded edges at the gap and then around that rectangle.", 'start': 16494.183, 'duration': 6.304}, {'end': 16501.386, 'text': "So I'm going to use that.", 'start': 16500.507, 'duration': 0.879}, {'end': 16504.889, 'text': "So I'll do curved.", 'start': 16502.226, 'duration': 2.663}, {'end': 16508.751, 'text': 'All right, now this just needs a name, PST.', 'start': 16504.909, 'duration': 3.842}, {'end': 16510.912, 'text': 'And now I can use that here, PST.', 'start': 16509.35, 'duration': 1.562}, {'end': 16514.054, 'text': 'And then the path is going to be the power button.', 'start': 16512.213, 'duration': 1.841}, {'end': 16524.647, 'text': 'And then what is wrong with this? Why is this complaining? Oh, is that because that needs to be to float? Yes, this should be a float rectangle.', 'start': 16516.455, 'duration': 8.192}], 'summary': 'Using stroke thickness of 2 and curved joint style for rectangle pst, adjusting to float rectangle.', 'duration': 35.878, 'max_score': 16488.769, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc16488769.jpg'}, {'end': 16725.366, 'src': 'embed', 'start': 16696.811, 'weight': 1, 'content': [{'end': 16699.132, 'text': "It's a little bit beyond the scope of this tutorial.", 'start': 16696.811, 'duration': 2.321}, {'end': 16701.293, 'text': "So I'm just going to get rid of that.", 'start': 16700.392, 'duration': 0.901}, {'end': 16705.355, 'text': "Okay, let's add a commit for that.", 'start': 16702.393, 'duration': 2.962}, {'end': 16711.598, 'text': 'So customized the graphics.', 'start': 16705.695, 'duration': 5.903}, {'end': 16715.619, 'text': 'All right, before I do that, actually, I wanted to show the juice live constant thing.', 'start': 16712.698, 'duration': 2.921}, {'end': 16720.581, 'text': 'So if we do this here, juice live constant, this was six.', 'start': 16715.64, 'duration': 4.941}, {'end': 16721.742, 'text': 'Same for this one.', 'start': 16720.902, 'duration': 0.84}, {'end': 16723.926, 'text': 'This was also 6.', 'start': 16723.045, 'duration': 0.881}, {'end': 16725.366, 'text': 'And we can mess with this angle too.', 'start': 16723.926, 'duration': 1.44}], 'summary': 'Customized graphics and adjusted constants for juice live, setting them to 6.', 'duration': 28.555, 'max_score': 16696.811, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc16696811.jpg'}, {'end': 17213.23, 'src': 'embed', 'start': 17182.983, 'weight': 2, 'content': [{'end': 17188.2, 'text': "Okay, now I'm going to do analyzer enabled area.", 'start': 17182.983, 'duration': 5.217}, {'end': 17193.262, 'text': 'Give me a width of 100.', 'start': 17188.701, 'duration': 4.561}, {'end': 17196.684, 'text': "Give me an x of 5 so it's not right along that edge.", 'start': 17193.262, 'duration': 3.422}, {'end': 17202.566, 'text': 'And then just remove a little bit from the top of this analyzer enabled area,', 'start': 17198.164, 'duration': 4.402}, {'end': 17205.787, 'text': "so there's a gap between the top of the GUI and the top of this rectangle.", 'start': 17202.566, 'duration': 3.221}, {'end': 17213.23, 'text': "Now I'm just going to set that to be my analyzer enabled buttons bounds.", 'start': 17208.628, 'duration': 4.602}], 'summary': 'Creating an analyzer enabled area with a width of 100 and an x value of 5, with a gap between gui and the rectangle.', 'duration': 30.247, 'max_score': 17182.983, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc17182983.jpg'}, {'end': 17585.467, 'src': 'embed', 'start': 17557.946, 'weight': 3, 'content': [{'end': 17565.89, 'text': 'we need to use a safe pointer to make sure that our class in this case the editor is still in existence when we try to use this particular onClick lambda.', 'start': 17557.946, 'duration': 7.944}, {'end': 17568.591, 'text': "All right, so let's get started with that.", 'start': 17567.131, 'duration': 1.46}, {'end': 17579.637, 'text': 'Auto safe pointer equals juice component safe pointer, simple EQ audio processor editor, this.', 'start': 17568.831, 'duration': 10.806}, {'end': 17582.805, 'text': 'Alright, now we can start declaring these guys.', 'start': 17580.643, 'duration': 2.162}, {'end': 17585.467, 'text': "So we'll start with the peak bypass button.", 'start': 17582.825, 'duration': 2.642}], 'summary': 'Using a safe pointer to ensure class existence in onclick lambda.', 'duration': 27.521, 'max_score': 17557.946, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc17557946.jpg'}], 'start': 16199.215, 'title': 'Custom power button implementation', 'summary': 'Discusses creating a centered arc and a custom power button with adjustable visuals, stroke thickness of 2, and toggle state color change. it also covers graphics customization, button functionality, analyzer button control implementation, and safe pointers and lambda functions for toggle states of sliders.', 'chapters': [{'end': 16396.774, 'start': 16199.215, 'title': 'Creating centered arc for power button', 'summary': 'Discusses creating a centered arc for a power button, specifying angles and dimensions to achieve the desired appearance, using juicer live constant for adjustments, and converting degrees to radians for calculations.', 'duration': 197.559, 'highlights': ["Creating a rectangle with equal length sides and centering it in the component's bounding box.", 'Using Juicer Live Constant to adjust the dimensions of the rectangle and specifying angles to create the gap at the top of the arc.', 'Centering an arc at a specified radius, not rotating the ellipse, and converting degrees to radians for calculations.']}, {'end': 16696.31, 'start': 16397.474, 'title': 'Creating custom power button', 'summary': 'Explains the process of creating a custom power button with adjustable visuals, stroke thickness of 2, and toggle state color change, providing a clear understanding of the code structure and functionality.', 'duration': 298.836, 'highlights': ['The process of creating a custom power button with adjustable visuals and stroke thickness of 2.', "Explanation of toggle state color change based on the button's status.", "Demonstration of the hit test region for toggling the button's status."]}, {'end': 17117.888, 'start': 16696.811, 'title': 'Graphics customization and button functionality', 'summary': 'Covers graphics customization using sliders to adjust angles and sizes, and reusing toggle button functionality for analyzer buttons, including creating classes, implementing draw toggle button function, and adding randomized path drawing inside the analyzer button.', 'duration': 421.077, 'highlights': ['The chapter covers graphics customization using sliders to adjust angles and sizes, including the ability to adjust placement and positioning of elements.', 'Reusing toggle button functionality for analyzer buttons involves creating classes, implementing draw toggle button function, and adding randomized path drawing inside the analyzer button.', 'The randomized path drawing inside the analyzer button includes using color settings to reflect the button state and randomly generating a path inside a smaller rectangle.', 'The step-by-step process of creating classes, implementing draw toggle button function, and adding randomized path drawing inside the analyzer button is explained in detail.']}, {'end': 17557.946, 'start': 17117.888, 'title': 'Analyzer button control implementation', 'summary': 'Details the implementation of the analyzer button control, including setting up the button on the gui, creating a path, and enabling/disabling gui parameters, with a focus on using on-click lambdas for control and the resizing function to compute the random path.', 'duration': 440.058, 'highlights': ['The implementation involves setting up the analyzer button on the GUI, creating a path, and enabling/disabling GUI parameters using on-click lambdas for control and the resizing function to compute the random path.', 'The resizing function is utilized to compute the random path that the toggle button will draw, ensuring the path is created only once whenever the instance is resized.', 'The on-click lambdas are used to change the enablement of the sliders and control the drawing of the analyzer, providing an efficient way for components to communicate with each other.']}, {'end': 18200.732, 'start': 17557.946, 'title': 'Implementing safe pointers and lambda functions', 'summary': 'Details the implementation of safe pointers and lambda functions to ensure the existence of the editor class, enabling toggle states of sliders based on bypass conditions, setting colors for enabled and disabled states, and implementing an fft analyzer button with toggle functionality.', 'duration': 642.786, 'highlights': ['The implementation of safe pointers and lambda functions ensures the existence of the editor class, facilitating the execution of onClick lambdas and toggle states of sliders based on bypass conditions.', 'The process involves setting colors for enabled and disabled states, ensuring visual cues for the functionality of sliders based on bypass conditions.', 'The detailed process of implementing an FFT analyzer button with toggle functionality, enabling the spectrum analysis and drawing paths based on the enabled state.']}], 'duration': 2001.517, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/i_Iq4_Kd7Rc/pics/i_Iq4_Kd7Rc16199215.jpg', 'highlights': ['The process of creating a custom power button with adjustable visuals and stroke thickness of 2.', 'The chapter covers graphics customization using sliders to adjust angles and sizes.', 'The implementation involves setting up the analyzer button on the GUI and enabling/disabling GUI parameters using on-click lambdas for control.', 'The implementation of safe pointers and lambda functions ensures the existence of the editor class, facilitating the execution of onClick lambdas and toggle states of sliders based on bypass conditions.', "Creating a rectangle with equal length sides and centering it in the component's bounding box."]}], 'highlights': ['The chapter covers the process of setting up the JUICE framework for audio software development using modern C++ and the JUICE framework from scratch.', 'The process of scanning for and adding VST3 and Audio Unit plugins to the audio plugin host is detailed, including finding and adding the simple EQ plugin and configuring the audio output.', 'Implemented FFT spectrum analyzer and added bypass buttons for each band and the analyzer, reducing CPU usage. (3 bands, 1 analyzer)', 'The process of setting up an AU audio file player to load and play audio files, wiring it to the audio output, and configuring audio device settings for the project is explained.', 'Rotary sliders for frequency, gain, and quality control are added to the GUI, along with the implementation of a function to retrieve all GUI components in a vector for easy iteration before setting the size.']}