Search code examples
javascriptperformanceaudiopitchtone.js

How to change pitch AND playback rate with JavaScript / Tone.js?


I would like to accomplish two things at the same time:

1) change playback rate of a sound file to 1/2 speed

2) lower pitch by a fifth

Lastly, Instead of using a separate button to play the result I would like to hook this up to an audio tag and use the play button there.

Below is the closest I got so far using Tone.js. I am really struggling with the documentation but I understand that Tone.Transport.bpm.value = 60; changes the bpm from 120 to 60 and Tone.PitchShift transposes the song. I just don't see how to combine the two to 'stack' the effects.

Here are some links I followed:

How to change the pitch with JavaScript?

https://tonejs.github.io/docs/r12/PitchShift

https://tonejs.github.io/docs/13.8.25/Transport

Thanks in advance for the help!

<audio id="myAudio" controls preload="none">
      <source src="my_tune.m4a" type="audio/mp4" >
</audio>

<script src="https://unpkg.com/tone@next/build/Tone.js"></script>

<script>

Tone.Transport.bpm.value = 60;  // setting the bpm like this is not working. where to put this?


var player = new Tone.Player("my_tune.m4a").sync().start(0);
// is it possible to use audio tag instead of creating this player?

var pitchShift = new Tone.PitchShift({
    pitch: -5 // this is working and lowers pitch by a fifth
}).toMaster();

player.connect(pitchShift);
window.play = function() {
    Tone.Transport.start();
}

<script>

<button onclick="setPlaySpeed()" type="button">separate button</button><br>


Solution

  • UPDATE: WORKING SOLUTION

    I found a way that works: Set the playback rate first. Then, when setting the pitch you need to calculate how much pitch shift to add/subtract to compensate for the playback rate. In my example I had to compensate +12 pitch shift for 0.5 playback rate.

    player = new Tone.Player("url/to/audio.mp3");
    playback_rate = 0.5 // or 1 (I only implemented these two options)
    transpose_by = 7 // up 7 half steps, -7 would be down 7 half steps
    
    // set playback rate
    player.playbackRate = playback_rate
    player.toDestination();
    
    
    // set pitch shift
    if (playback_rate == 1){
        pitch_shift = new Tone.PitchShift({
        pitch: transpose_by.toString()
        }).toDestination();
    } else { //if playbackrate == 0.5 add +12 to pitch to correct
        trans = transpose_by + 12
        trans = trans.toString()
        pitch_shift = new Tone.PitchShift({
        pitch: trans
      }).toDestination();
    }
    player.disconnect(); // disconnect old player (get overlay of two players otherwise if you repeat this)
    player.connect(pitch_shift);
    
    player.start()
    
    

    See it in action on my website: https://www.lickstack.com

    I still have no idea how to connect a Tone.js player to an audio element though. Any help would be appreciated. See my post here: create html <audio> element from Tone.js object