echolevel / AmigaPal

Sample prep/converter tool for Protracker
69 stars 3 forks source link

Transpose in preview playback #3

Closed echolevel closed 7 years ago

echolevel commented 7 years ago

This is a frustrating one. Documenting here for my own reference.

Adjusting playback 'speed' when playing audio from a MediaElement performs a timestretching effect, maintaining pitch while altering duration. Maybe that's handy for people who are learning to play Joe Satriani guitar solos, but it's useless for AmigaPal. What I need is the classic, much lower-tech pitch adjustment that commensurately adjusts the duration since all it's doing is adjusting the playback samplerate. You know, like slowing down or speeding up magnetic tape.

This doesn't seem to be possible, even when using a MediaElement as an AudioContext source; you can add some of the Web Audio API's nice effects and set up some interesting routing, but the 'detune' parameter of the BiquadFilter (which performs the desired effect when playing a BufferSource or an oscillator) is either readonly or just isn't hooked up to anything. Maybe it'll change in future. I'd better start asking around on some WAA forums...

Another workaround would be to take the AudioContext buffer that I've already created for each source file on load (in order to draw the waveform) and manipulate that - detune works there, but the problem is that currentTime is a context-wide counter that starts when the source starts playing...which would mean creating a unique AudioContext for every file to have separate control over each one, and eating up a huge amount of memory. I get that MediaElement audio is intended for file playback and AudioContext is intended for synthesis and DSP, but it still seems weird. Also, calling start() on the AudioContext more than once appears to be forbidden! I have no idea why and can't really be bothered to find out at this stage, considering that even if I found a way around it, I'd still have the possibility of a user loading a directory containing hundreds of short samples crashing out the Chrome engine with too many AudioContexts. I don't know what the limit is, or if there is one on desktop, but I know Safari iOS has one.

So that's really annoying. I'm not bothered about preview playback being able to demonstrate how the file will sound when downsampled or reduced to 8bit, but the one thing I'd really like is to be able to preview the target pitch of the sample. That's a much more musically intuitive way of doing things, and likely to allow for happy accidents during the sample prep that could bear fruit during composition!

The closest I can get for now, unless/until Biquad's detune becomes available for MediaElementSources under Chrome, is to load in media elements containing the file that's just been converted - with a separate button, for confidence checks, and a delete button in case it's gone horribly wrong and the user wants to start again. It beats digging through the target directory in the OS filesystem and doing a Preview (Mac) or having to load a media player to check it (Windows).

Here's an example of how I wish it would work:

      var source = audioContext.createMediaElementSource(myPlayerElem);
      var gainNode = audioContext.createGain();
      var gainNode.gain.value = 0.5;
      var biquad = audioContext.createBiquadFilter();
      var biquad.frequency.value = 0; // Lazy filter bypass
      var biquad.type = "lowshelf"; // Lazy filter bypass
      var biquad.detune.value = -1200; // octave down
      var source.connect(biquad);     
      var biquad.connect(gainNode);      
      var gainNode.connect(audioContext.destination);
echolevel commented 7 years ago

Closing this. The problem's not really solved, but I've switched to Wavesurfer.js and it lets me do exactly what I want in terms of on-the-fly transpose. For now, at least - I see some discussion on the Wavesurfer repo about bringing it into line with the Audio Element way of doing things (pitch retention) and that might ruin it. Hopefully both behaviours can coexist peacefully!