DEV Community

loading...

Building a Synth Bass with Tone.js

santispavajeau profile image Santiago Salazar Pavajeau Updated on ・3 min read

As my first main experiment with JavaScript, I built an app to play around with chord progressions which allows the user to add different combinations of chords to a song and experiment with chord progressions to provide a quick and simple 'song-making' experience.

This project has really helped me improve my JS skills and it helps me to keep coding when I need a break from other projects.

So, I have been looking into improving the code and adding more features since the first iteration, and so recently I was able to add a synth bass keyboard with the Tone.js library. Here I explain the process.

Implementing Tone.js

I find this library very interesting because it comes with a synthesizer right out of the box. So all the common properties of sound design like oscillator/wave types, attack, release, frequency, envelope, detune, filter, etc. can be set and played.

It is fairly straightforward to get the 'keyboard' working since a synth can be initialized with:

const synth = new Tone.Synth().toDestination()
Enter fullscreen mode Exit fullscreen mode

And different keys can be played by just by passing a note and duration value:

synth.triggerAttackRelease("A1", "8n")
Enter fullscreen mode Exit fullscreen mode

However, what really excites me about the library is to be able to design the sound of the synthesizer, so I started by adding buttons that can change the wave shape of the oscillator, so it can sound softer(sine) or more robotic(sawtooth). This can be achieved by simply setting:

synth.oscillator.type = "sawtooth"
Enter fullscreen mode Exit fullscreen mode

Checkout the method where the Synth Bass is implemented.

Keydown event listener and switch statement

Now to implement the actual feature of playing the 'synth bass' notes when pressing keyboard keys we can just use event listeners for keydown. This type of event has an event.code property so the switch statement can tell which key has been pressed trigger a different note with each key.

  document.addEventListener("keydown",  (e) => {

            switch (e.code) {
                case "ShiftLeft":
                  return synth.triggerAttackRelease("A1", "16n")
                case "KeyZ":
                  return synth.triggerAttackRelease("A#1", "16n")
                case "KeyX":
                  return synth.triggerAttackRelease("B1", "16n")
                case "KeyC":
                  return synth.triggerAttackRelease("C2", "16n")
                /// ETC...
                default:
                  return
              }
        })

    }
Enter fullscreen mode Exit fullscreen mode

As the code shows, coupling the event listener with a switch statement allows triggering a specific note for each key. Our e.code argument changes with each keypress so for example pressing left shift (ShiftLeft) will play an 'A1' for the duration of an eight note.

So the synth bass currently plays by pressing keys in between the left and right shift to have all lower 12 notes and from A to Enter for the 12 higher octaves which allows to play higher and lower notes easily.

Event listener for oscillator wave type

I implemented a basic on click event listener to change the wave type and sound of the Synth Bass.

So I added some buttons to the synth bass card where the type of the wave can be picked to change the sound of the synth bass. The options are sine, sawtooth, triangle, and square. To acheive this we just add buttons and corresponding event listeners that set the type of wave.

   <button class="waves">Triangle</button>
   <button class="waves">Sawtooth</button>
   <button class="waves">Square</button>
   <button class="waves">Sine</button>
Enter fullscreen mode Exit fullscreen mode
const wavesButtons = document.querySelectorAll("button.waves")

for( let wavesButton of wavesButtons){
   wavesButton.addEventListener("click", (e) => {
      synth.oscillator.type = e.target.innerText.toLowerCase()
   })
}
Enter fullscreen mode Exit fullscreen mode

In this case, I only use the lowercase inner text of the buttons to set the oscillator wave type because these texts correspond to the properties that synth.oscillator.type accepts.

Looking forward

I am looking to improve the UI/UX layout but haven't been able to decide on a specific idea. However, I am thinking of making the app more accessible implementing some type of mini-modals tutorial. Also looking to add some feature that helps the user decide which chord progressions to use either by showing chord progressions of actual songs or by a 'smart' suggestion' of a good next chord depending on the theme wanted for the song. There are many possibilities of where this project can be headed to which will surely keep me busy building for a long time.

Please feel more than welcome to share any thoughts/ideas and reach out!

LinkedIn
Twitter

Discussion (0)

pic
Editor guide