Vixen
02b45cc4
csharp
public sealed class PitchShiftEffect

Changes the pitch without changing the length.

No guide page documents this yet — the page shows what the code says about itself.

Remarks

Which is the one thing PlaybackSettings.Pitch cannot do. That resamples: a voice played at 2.0 is an octave up and half as long, which is right for a footstep and wrong for anything a player is listening to the words of. A monster whose voice is a human's an octave down, a radio operator two semitones up, a slowed-down explosion that keeps its bass — all of them need the pitch and the duration separated.

Time domain, two taps, crossfaded. A read pointer runs through a delay line at a different rate to the write pointer, which is a pitch change; it eventually catches up with the write pointer, at which point it has to jump, and a jump is a click. So there are two of them half a grain apart, and each is faded in while the other is faded out, so whichever one is jumping is silent while it does.

What it costs, honestly. The crossfade means two copies of the signal are summed at a fixed offset, which is a comb filter that moves — audible as a slight hollowness on broadband material and as warble on a sustained tone. Larger grains reduce the warble and increase the smearing of transients; there is no setting that has neither.

The alternative, and why not yet. A phase vocoder does this in the frequency domain and sounds much better on sustained material — at the cost of an FFT pair per hop, latency of a whole window, and transients that smear into a metallic ring unless it is taught about them. The transform to build it on now exists (Vixen.Audio.Dsp.Fft) and it is owed. For a monster voice, a radio and a slowed-down explosion, this is what every game has always used.

Fields and properties (6)

  • public float Semitones

    How far to shift, in semitones. Twelve is an octave up, −12 an octave down.

  • public float GrainSeconds

    How long each grain is.

  • public float Mix

    How much of the shifted signal to keep, against the untouched one.

  • public bool Enabled

    Whether it does anything. A bypassed effect costs one branch a block.

  • public float Ratio

    The playback-rate ratio the semitone setting works out to.

  • public IReadOnlyList<string> Properties

    The knobs this effect will answer to, by name.

Methods (5)

  • public void Prepare(in AudioFormat format, int maxFrames)

    Sizes and clears every buffer the effect needs.

  • public void Process(Span<float> buffer, int frameCount, int channels)

    Processes a block in place.

  • public void Reset()

    Throws away everything the effect remembers about what came before.

  • public bool TrySetProperty(string name, float value)

    Sets one of the effect's knobs by name, for automation.

  • public bool TryGetProperty(string name, out float value)

    Reads one of the effect's knobs by name.

Used by (4)

  • MixControlTestsVixen.Audio.Tests
  • MixerAssetTestsVixen.Audio.Tests
  • PitchShiftEffectAssetVixen.Audio
  • ShapingEffectTestsVixen.Audio.Tests