8-Channel Spectral Shift — User Guide

Creates eight parallel whole-file spectral translations of one source. Each channel receives a constant additive frequency offset by translating FFT bins; components shifted below DC or above Nyquist are discarded rather than wrapped.

Author: Shai Cohen Affiliation: Department of Music, Bar-Ilan University, Israel Version: 0.9 (2026) License: MIT License Repo: Praat AudioTools
Contents:

What this does

The script converts the selected Sound to a mono working source, computes one whole-file FFT, and creates eight translated spectra from that common source spectrum. Each requested shift is converted to an integer FFT-bin offset, the complex bins are translated without wraparound, and each translated spectrum is inverse-transformed back to audio. All eight channels start together and retain the source duration.

Frequency shift, not pitch shift: spectral translation adds a constant frequency offset. A component at f becomes approximately f + Δf. This does not preserve harmonic ratios. The eight outputs are parallel spectral variations, not a canon: there are no staggered entries, delays, or temporal imitation between channels.

Quick start

  1. Select exactly one Sound.
  2. Run 8-Channel_Spectral_Shift.praat.
  3. Choose a Preset, or leave Custom and enter eight shifts.
  4. For Custom, choose Hertz for file-independent values or FFT bins for direct bin offsets.
  5. Choose the required Output_format.
  6. Set Scale_peak, and leave visualization/playback enabled if desired.
  7. Click OK. The Info window reports requested and achieved shifts, bin quantization, retained spectral energy, and output routing.
Recommended interpretation: small offsets can create close inharmonic beating or spectral thickening; larger offsets produce stronger spectral displacement. The audible result depends strongly on the source spectrum because translated components that leave the representable 0–Nyquist range are removed.

Spectral translation

One FFT for the complete source

The script does not use an STFT, frames, windows, or a time-varying shift. It computes one Spectrum for the complete mono source and translates that spectrum by a fixed amount for each of the eight channels.

source Sound ↓ To Spectrum ↓ source complex spectrum X[k] ↓ copy to destination Matrix ↓ translate columns by integer binOffset ↓ restore legal DC / Nyquist imaginary values ↓ To Spectrum → To Sound ↓ trim to original duration

Hertz to bins

FFT-bin width depends on sample rate and FFT length. In Hertz mode the script measures that width and converts each requested shift to the nearest integer bin:

binWidth = measured Spectrum bin width binOffset = round(requested_Hz / binWidth) achieved_Hz = binOffset × binWidth quantization error = achieved_Hz - requested_Hz

This is why Hertz is the default user unit. A value such as “100 bins” represents different Hz shifts for files whose FFT lengths differ, while “100 Hz” retains the same musical/spectral meaning and is merely quantized to the available bin grid.

Positive and negative translation

Positive shift: destination[k] = source[k - offset] Negative shift: destination[k] = source[k + |offset|] Bins with no valid source index are set to zero. There is no wraparound.

DC and Nyquist

After translation, the imaginary component of the DC bin and of the Nyquist bin is explicitly set to zero. These bins must be purely real for a valid spectrum representing a real-valued time-domain signal.

Shift limits

After the FFT size is known, each bin offset is constrained to the range -(nBins-1) through +(nBins-1). The Info report notes when a requested shift had to be clamped.

Presets

All named presets use Hertz, regardless of the Shift_units menu. FFT-bin mode is available only for Custom.

PresetCh1–Ch8 shifts (Hz)Structure
CustomUser valuesHz or FFT bins, including positive, zero, and negative values.
Gentle Up20, 30, 40, 50, 65, 80, 100, 120Eight small upward translations.
Moderate Up100, 150, 200, 250, 300, 400, 500, 600Increasing upward offsets.
Extreme Up500, 700, 900, 1200, 1500, 1800, 2200, 2600Large upward translations with increasing high-frequency truncation risk.
Symmetrical+400, +300, +200, +100, -100, -200, -300, -400Upward spectral bank against downward spectral bank.
All Down-50, -100, -150, -200, -250, -300, -350, -400Eight downward translations.
Spread-400, -250, -100, 0, 0, +100, +250, +400Negative bank through two unshifted centre channels to positive bank.
Cluster Up100, 110, 120, 130, 140, 150, 160, 170Tightly spaced upward translations.
Doubling offsets+50, +100, +200, +400, -50, -100, -200, -400Geometrically increasing additive offsets.
“Doubling offsets” does not mean octave shifting. The offset values double, but the processing is additive in Hertz. A fixed +100 Hz translation represents a different musical interval at every source frequency.

Parameters

ParameterDefaultActual role
PresetCustomSelects Custom or one of eight fixed Hz shift patterns.
Shift_unitsHertzHertz or direct FFT-bin offsets. Named presets always force Hertz.
Shift_1 … Shift_8100, 200, 300, 400, -100, -200, -300, -400Custom additive spectral offsets. Positive = up, negative = down.
Output_format8-channel octophonicSelects the returned routing layout.
Scale_peak0.99Target used by the shared eight-channel gain stage; values ≤0 revert to 0.99 and values above 1 are clamped to 1.
Draw_visualizationonDraws the v0.9 process/analysis figure.
Play_resultonPlays the single returned object, or a temporary stereo spectral-bank monitor for stem formats.

Level handling & energy retention

No per-channel peak equalization

Each translated channel is measured but is not independently peak-normalized. This matters because upward and downward translation can discard different amounts of spectral energy. Equalizing every channel separately would hide those differences.

peakAll = maximum absolute peak among Ch1 ... Ch8 sharedGain = Scale_peak / peakAll Ch1 ... Ch8 are all multiplied by the same sharedGain

The shared gain may attenuate or boost the bank as a whole. Relative channel levels produced by the spectral translations remain intact.

Energy retained

Before the shared gain is applied, the script measures each translated channel's whole-file energy relative to the mono source:

retained[%] = 100 × translated_channel_energy / source_energy

The display and Info window use this as a practical indicator of how much energy survived the DC/Nyquist truncation. If the weakest channel falls below 50%, the report calls attention to the loss.

Interpret correctly: a low retained-energy value is not a processing failure. It means a substantial part of the source spectrum was translated outside the representable frequency range and intentionally discarded.

Output formats

FormatReturned objectsRoutingAdditional normalization
8 channels — octophonic1 × 8-channelout1–out8 = Ch1–Ch8None after shared gain
4 stereo pairs4 × stereoCh1|Ch2, Ch3|Ch4, Ch5|Ch6, Ch7|Ch8None after shared gain
2 quad groups2 × 4-channelCh1–Ch4 and Ch5–Ch8None after shared gain
4-channel fold-down1 × 4-channel1=Ch1+Ch5, 2=Ch2+Ch6, 3=Ch3+Ch7, 4=Ch4+Ch8Final peak scaling to Scale_peak
Stereo mix1 × stereoL = Ch1+Ch2+Ch3+Ch4; R = Ch5+Ch6+Ch7+Ch8Final peak scaling to Scale_peak

Why the stereo fold uses two banks

The stereo mapping is deliberately positional rather than odd/even. Channels 1–4 form the left spectral bank and channels 5–8 the right bank. This makes presets such as Symmetrical, Spread, and All Up/Down readable as two opposing spectral groups.

Stem-format preview

For 4 stereo pairs and 2 quad groups, Play_result creates a temporary stereo monitor using the same bank mapping — Ch1–4 left, Ch5–8 right — peak-scales that monitor, plays it, and removes it. The monitor is not one of the returned stem objects.

Visualization

The v0.9 figure uses an 8 × 8 canvas and reads the eight working translated channels directly, so its core analysis is the same for all five output formats.

TITLE • source, preset, duration, sample rate • measured Hz/bin • selected output format PANEL A — Bin offset • one bar per channel • blue = upward translation • orange/red = downward translation • zero reference line • numerical bin offsets shown in sufficiently tall bars PANEL B — Achieved shift in Hz • horizontal channel bars • zero reference • displays the actual bin-quantized spectral offset PANEL C — Spectral energy retained • retained whole-file energy before shared gain • 100% and 50% references • directly shows losses caused by DC/Nyquist truncation PANEL D — Channel examples • blue = working Ch1 • orange = working Ch8 • one common amplitude scale • shared normalization makes their displayed levels directly comparable • these are two spectral variations, not an “8-channel mix” PANEL E — Summary • preset/source/FFT information • achieved Ch1–Ch8 shifts • output format, object count, channel count and routing

Implementation notes & limitations