javascript pitch shift with time stretch

2019-01-19 20:38发布

问题:

I'm a beginner learning javascript. I've got various projects in mind with an interactive page on my site related to microtonal frequencies and planetary frequencies. I need to be able to play my audio sample .wav file in a loop but have the audio sample timestretched with a corresponding change in pitch.

I tried myAudio.playbackRate = 0.5; which plays the audio 0.5 slower but keeps pitch same. I researched and found something. But how do i set preservesPitch to false or true? And this only works in 'Google Chrome' I think, so other program i found is here :
https://github.com/janesconference/KievII/blob/master/dsp/pitchshift.js

Can't seem to get it working, i don't know how i am supposed to modify it, where do i paste my Audio .wav file URL in the program ? Any other tips related to this would be much appreciated. Thanks in advance for your time and help.

回答1:

I want to pitch shift audio as well, and after ages I found this.
I also re-formatted the code to make it easier to use for myself (you will need to replace "decode-audio-data/viper.ogg" with your own WAV or OGG filename.):

<script>
function playSound(file, speed=1, pitchShift=1, loop=false, autoplay=true) {
    /*
    Use the play() method to start the audio. if pitchShift is true
    use the stop() method to stop the audio and destroy the object.
    If pitchShift is false use the pause() method to pause and set
    the attribute currentTime to 0 to reset the time.
    */
    if(pitchShift) {
        /*
        After weeks of searching, I have finally found a way to pitch shift audio.
        Thank you Mozilla.
        2018/03/31:
            https://developer.mozilla.org/en-US/docs/Web/API/AudioBufferSourceNode/playbackRate
            https://github.com/mdn/webaudio-examples/tree/master/decode-audio-data
            https://www.w3schools.com/jsref/prop_audio_loop.asp
        Original comments:
            use XHR to load an audio track, and
            decodeAudioData to decode it and stick it in a buffer.
            Then we put the buffer into the source
        */
        audioCtx = new (window.AudioContext || window.webkitAudioContext)();
        source = audioCtx.createBufferSource();
        request = new XMLHttpRequest();

        request.open('GET', file, true);

        request.responseType = 'arraybuffer';


        request.onload = function() {
            var audioData = request.response;

        audioCtx.decodeAudioData(audioData, function(buffer) {
            myBuffer = buffer;
            songLength = buffer.duration;
            source.buffer = myBuffer;
            source.playbackRate.value = speed;
            source.connect(audioCtx.destination);
            source.loop = loop;
        },

        function(e){"Error with decoding audio data" + e.error});

        }

        request.send();
        source.play=source.start
    } else {
        source=new Audio(file)
        source.playbackRate=speed
        source.loop=loop
    }
    if(autoplay) {
        source.play()
    }
    return source
}
var source
function play() {
    source=playSound('decode-audio-data/viper.ogg', pitch=2);
}

function stop() {
    source.stop(0);
    document.getElementById('play').href=''
    document.getElementById('play').innerHTML='Refresh to play again'
}
</script>
<a id="play" href="#" onclick="play()">Play</a> | <a href="#" onclick="stop()">Stop</a>


回答2:

you can set the mozPreservesPitch property to false to change the pitch of an element or soundfile with Firefox. webkitPreservesPitch is supposed to work with webkit browsers but note that "this API is not yet standardized" ...

https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement

This worked for me:

var soundPlayer = new Audio();

function playLowerNote() {
    soundPlayer.src = "piano.mp3";
    soundPlayer.mozPreservesPitch = false;
    soundPlayer.playbackRate = 0.5;
    soundPlayer.play();
}

playLowerNote();

Still looking myself for a better way to loop.



回答3:

Some points, when you said I tried myAudio.playbackRate = 0.5; we are talking about Web Audio API ?

if yes, listen again the pitch as well as the duration of the sample will be affected.

if no, probably that are you using a native html5 function, if you want keep the original speed and change the pitch one way is after change the speed you apply some type of interpolation try linear interpolation with same factor used to stretch your audio. If you need change speed and pitch just apply interpolation without change the speed (in original sound), this can be equivalent to play your audio in a different sample rate Web Audio API can do it.

The code pitchshift.js is a port of the code from Stephan Bernsee to javascript (this change the pitch and keep the speed untouchable), you need call this function at every chunk audio, so first you need do an function that decode your audio file in short int or float.



回答4:

Hey your web audio API seems to work now for sine waves at least , will learn how to use samples too soon https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Using_Web_Audio_API info from here