At this point, I didn't know what was slowing down the interval processing, so I tried using Firefox and Chromium to find bottlenecks in the system. I ignored things that didn't look like they were coming from my code. I felt like the libraries and the canvas api call itself were probably already optimized by the browser developers. Nothing really jumped out at me this way, so I started looking for things in my code that were unnecessary or could be written in a faster way. I also asked the AI's what they thought, but since I didn't have anything in particular, they gave me vagure or hallucinatory answers. Nothing I felt worth pursuing.
One of the first things I did was pull the Visible Field filter process out of the interval and ran it once for the whole song. That took a whole loop out of the interval. I know what Big O notation is, but I didn't really use it formally when I was choosing what to optimize, but I know at a high level, I want to process as few loops per interval as possible. If I were to imagine that whatever my current complexity was per interval was, "T(n)", my complexity now would be "T(n) - O(n)". This by itself may have been noticeable, but I was only ever playing the game after making a change. To me it felt a little smoother, but it did not make a big difference over all. Still, lots of tiny optimizations are better than no optimizations!
After some small tweaks like decreasing the number of player synths and trying to change some if's to switches, I decided to try to cut down on the number of iterations the loops were spending going over notes in the song that were outside the current window. Let's say the song was 4 minutes long, with 1000 notes. During a 10 second window into the song, there may only be 30 notes to consider (don't judge my math). So I tried to cut down to just the segment of the song I needed to process for the game at each moment. So my new level of complexity would be something like "T(n) - O(n) - 0(n - n/100)" (don't judge my Big O notation). This again felt a little smoother, and it was definitely more efficient. It still did not move the needle enough for me to hit the 100 frames per second goal, so I needed to figure out where else I could squeeze water from the stone.
Sometimes when the game stuttered, it also made popping noises during play. I found some helpful ToneJS documentation regarding performance and implemented a change to add slight delays to try to keep the popping from occuring.
Nothing much changed with the performance or playability of the game. I felt like I was learning things, and I was getting into a more efficient mindset. So even though it felt like there was very little tangible progress, I was already eager to try new things the next day.