Contents

Creating the JSAudioKnobs JavaScript library

Background

During my PhD, I created a browser-based music remixing application which I named Remix Portal. It was quite a complex beast, and as is so often the case in research environments, it had to be put together rather quickly. This meant that whilst I was really proud of the robust and effective finished product, I knew the underlying code could do with a thorough refactor, and because of this I was always a little nervous about people poking their head under the bonnet. It was this refactor that gave birth to my JSAudioKnobs library.

I’ll take a step back for a second and explain the need for JSAudioKnobs. Making music in the browser took a big leap forward with the introduction of the Web Audio API in 2012. This gave modern web browsers powerful audio processing capabilities and enabled developers to control this processing via JavaScript. Synthesizers and samplers could be created in just a few lines of code. It was, and still is, a lot of fun. However, the Web Audio API did not ship with any interface components to support interactions. And interacting with audio processing is a pretty big part of the experience. I mean, think of just about any piece of audio playback equipment and I’m pretty sure the picture you conjure up will feature some knobs or sliders for the end user to tailor the sound to their taste: guitar amps, synthesizers, mixing desks, hi-fi’s - they all have them. What’s more, I have no doubt that for many music makers, the look and feel of an interface can have a significant impact upon the fun they derive from the activity and possibly also upon their subjective assessment of the quality of the audio produced. What was needed, I thought, was a range of traditional feeling knobs that could be paired with the sound generating and processing activities performed by the Web Audio API. But when I scouted around at the start of my Remix Portal build, I found very few good options. So I decided to build my own.

How I created the knobs in code

What should a knob interface component do? This was a pretty important question that I had to address at the start of the build. Well, it should look like a knob or dial, obviously, and it should rotate left or right as controlled by the user’s mouse (or touch), and it should store a value corresponding to its rotational position. A developer might want to be able to set the knobs size, give it a low value, high value, current value, and a ‘step’ amount. A developer may or may not want to see an associated label with the exact current value displayed. There’s quite a lot going on already! Furthermore, a developer might want to have several on screen at once, so it was important to ensure that each could function independently.

Having tried a number of software knobs, I was of the opinion that its rotation would best be achieved by clicking on the knob and dragging up to increase the dial’s value, or clicking and dragging down to decrease the value. I thought that the relationship between amount of mouse movement and amount of dial rotation should be configurable, and so I gave each dial a sensitivity property, which is used to scale the mouse movements.

Dial rotation is handled in code by having a long image strip with 50 dial pictures, with gradually increasing rotation represented. A div is used to create a window only large enough to view one knob at a time, and then the image strip is slid up and down to reveal the appropriate portion of the image depending upon the calculated rotation value. The trick is to not slide the image smoothly, but instead step through the image so that each knob picture lines up precisely with the previous, and therefore no movement is perceived beyond the rotation. I.e. If the distance between the centre of the knobs in the image strip is 50px, then the image should be moved in 50px increments. It’s the same technique that can be used to animate characters in an old-school computer game.

Helping people use the library

I have spent too much time looking for libraries, only to be frustrated by unhelpful or inadequate documentation. I was determined that JSAudioKnobs would provide a much better user experience, and my goal was to provide sufficient accompanying resources that newcomers to JavaScript programming could quickly and easily get up and running. I provided three forms of support:

  1. I wrote concise and easy to follow documentation.
  2. I made an interactive knob builder tool that lives on github pages. This provides a form where users can select desired parameters (knob image, size, high and low values, sensitivity etc.) and the resulting knob is displayed on screen. So too is the object code which should be copied and pasted in when the user is creating a knob class instance.
    /images/knobBuilder.jpg
    Interactive knob builder interface
  3. I made a JSFiddle so that people can see the knobs working and can explore the associated code straight away. Should there be any ambiguity in the getting started portion of the documentation, I believe this Fiddle should solve it.

Final thoughts

I’m glad I went to the effort of creating this library. It did a few things for me… Firstly, it forced me to write better code. I knew people would be looking at the code and possibly forking it to build upon, so I worked hard to make all the code clean, concise and readable.

Secondly, it has significantly reduced the barriers to my future projects in this space. As I said above, knobs are everywhere in audio interfaces, so now that I have a good knob interface components library, I can build audio interfaces for Web Audio Applications much more quickly and easily. Essentially, the small extra amount of upfront work should reward me with increased productivity further down the line.

Third, it’s made me feel more confident in my coding abilities. Whilst I have been using JavaScript libraries for many years, up until now I assumed I didn’t have the ability to create the type of low level code I was interacting with - I thought that job was reserved for JavaScript Jedis! But I realised that with a little bit of thought and effort, I could overcome this hurdle and build a useful resource. It’s been an empowering realisation. I am also much better at thinking about how to segment products into worthwhile ‘chunks’ from the outset, and the refactoring process has helped me rethink the way I write code which I am sure will lead to cleaner and more concise code from the outset going forward. It’s also great to receive validation via the positive feedback from happy library users!