On the continuing quest to find the most effective way to build this most critical aspect of the user interface, the pattern editor, I’ve been trying out something a little different. Having looked closely at the audio engine code that a1k0n created for his jsxm FasttrackerII player, I turned my attention to his decision to use canvas for rendering the user interface. This is much more low level, not relying (or taking advantage of if you like) the DOM that the browsers use, but instead drawing each element individually. This approach appeals to me on many levels, not least, that it harks back to my early days, developing games and softeare on Amiga and DOS machines, where the norm was to attack the bitmapped screens directly. Ok, perhaps not quite that far back, it does have a reasonably feature-rich drawin API, but all the same, it’s far more manual than the equivalent DOM hackery I’d been using up to now.
As with the DOM based approach, the general scrolling of a pattern during playback and editing is quite a simple problem to solve. Although with the canvas I found it a lot easier to solve, implementing the fixed header row and timeline column in a matter of 30 minutes or so, as opposed to a couple of days hacking with the DOM. The problem comes when switching patterns. Redrawing an entire pattern during playback is costly. With the DOM based pattern editor, I found myself doing all sorts of trick to reduce the amount of events that were updated during a pattern render, and to cache pointers to the DOM elements that needed update. Turns out there are similar, although again simpler, approaches with the canvas. One such, trick, as a large portion of the ‘events’ in a pattern, espeicially one with many tracks, are empty, drawing the empty note, instrument, volume, and effects items individually seems silly. Much better to render an empty event offscreen separately to another canvas, then just draw that image to the empty event when needed. This trick alone resulted in enough speed increase to make the pattern transition almost undetectable on my machine during playback. There are others I’ll be trying over time, but for now, this is a good sign.
I’ve also taken, with permission, the basic monitor scopes code from a1k0n’s
jsxm code and integrated them into the codebase as a module. All this is
currently on a separate branch, ‘pattern_change_tests’, as of the writing of
this post, however, it is very likely to be merged into the master very soon as
the way forward for this element of the interface. Anyone wanting to try it out,
checkout that branch, run with
npm run start and view it in your browser
(preferably Chrome), clicking the play button will play a preloaded XM file and
show the moving pattern editor and scopes.