BFG-Inspired Pitch & Duration Modulation
A procedural control-field modulator for Praat Manipulation. A deterministic two-dimensional field is sampled along time and channel trajectories, then mapped to pitch targets and, optionally, to a shared DurationTier.
What this does
The script creates a control field N(x,y) from one of 12 procedural basis functions. Elapsed source time traverses the field on the X axis, while each audio channel uses its own Y coordinate. The sampled field controls pitch deviation in a Praat Manipulation object. A second, separate field trajectory can control a shared DurationTier.
jit.bfg evaluates procedural basis functions and basis-function graphs over coordinate fields. This Praat script uses custom implementations and analogues of related procedural ideas; it does not reproduce jit.bfg numerically or provide a compatible implementation.
Channel behavior: each input channel is extracted, analyzed, pitch-modulated, and resynthesized separately. The original number and order of channels are restored at the end. Pitch trajectories may differ by channel through Y_offset_per_channel; duration modulation is shared by all channels.
Quick start
- Select exactly one Sound object in Praat.
- Run
BFG_Pitch_Time_Modulation.praat. - Choose one of the 20 named presets, or use Custom.
- For Custom, choose the basis and field controls, then set pitch depth and optional duration depth.
- Set
Pitch_floorandPitch_ceilingfor the source. - Run the script. The result remains selected; it is played automatically only when
Play_resultis enabled.
Parameters
Field and modulation controls
| Control | Default | Behavior |
|---|---|---|
Basis_type | Perlin fBm | Selects one of the 12 field generators described below. |
Field_rate_units_per_s | 4.5 | X-axis traversal rate. For periodic bases it is also the cycle rate; for noise/fractal bases it is a domain-traversal rate rather than one modulation frequency. |
Octaves | 3 | Used by Perlin fBm, ridged multifractal, and turbulence. Values above 8 are limited to 8. |
Persistence | 0.5 | Amplitude multiplier between fractal octaves. Accepted range is > 0 to 1.5. |
Lacunarity | 2.0 | Frequency multiplier between fractal octaves. Must be at least 1. |
Random_seed | 12345 | Offsets the deterministic hash used by the stochastic/noise bases. Periodic bases such as sine, triangle, square, and checker do not use it. |
Pitch_depth_semitones | 0.5 | Peak semitone scale applied to the calibrated pitch field. Magnitude is limited to 48 semitones. |
Quantize_grid_semitones | 0 | 0 disables quantization. Positive values round the field-derived semitone deviation to the nearest grid multiple. |
Time_depth_percent | 0 | 0 disables duration modulation. Otherwise the shared duration factor is 1 + Nt(t) * depth/100. Magnitude is limited to 90%. |
Time_rate_ratio | 0.25 | Multiplies the field traversal rate used by the duration trajectory. |
Y_offset_per_channel | 1.5 | Channel ch uses y = (ch-1) * Y_offset_per_channel. Larger offsets sample more widely separated field trajectories. |
Calibrate_realized_depth | Yes | Centers each realized pitch-channel trajectory independently, then applies one shared gain so the largest centered excursion reaches +/-1. The duration trajectory is centered and scaled separately. |
Analysis and output controls
| Control | Default | Behavior |
|---|---|---|
Pitch_floor | 75 Hz | Lower bound passed to To Manipulation. |
Pitch_ceiling | 600 Hz | Upper analysis bound. It must be below 0.45 * sampling_rate. |
Peak_ceiling | 0.95 | Attenuate-only final peak ceiling. If the output peak is already at or below this value, no gain change is applied. Values above 1 are limited to 1. |
Draw_visualization | Yes | Draws the diagnostic page described below. |
Draw_bfg_map | Yes | Includes the raw 2-D field map when visualization is enabled. |
Map_columns | 180 | Horizontal map resolution; limited to 600. |
Map_rows | 48 | Vertical map resolution; limited to 180. |
Play_result | Yes | Plays the final result after processing. |
Presets
Each named preset overrides exactly these ten controls: Basis_type, Field_rate_units_per_s, Octaves, Persistence, Lacunarity, Pitch_depth_semitones, Quantize_grid_semitones, Time_depth_percent, Time_rate_ratio, and Y_offset_per_channel. The random seed, calibration switch, pitch-analysis bounds, peak ceiling, visualization settings, and playback setting remain user-controlled.
| Preset | Basis | Field: rate / oct / pers / lac | Pitch: depth / grid | Time: depth% / ratio | Y offset |
|---|---|---|---|---|---|
| Subtle Vibrato | Perlin fBm | 5.5 / 2 / 0.50 / 2.0 | 0.30 / off | 0 / 0.25 | 0.7 |
| Organic Vibrato | Perlin fBm | 4.5 / 3 / 0.50 / 2.0 | 0.80 / off | 0 / 0.25 | 1.5 |
| Multiscale Pitch-Time Drift | Perlin fBm | 3.0 / 4 / 0.65 / 2.0 | 0.50 / off | 5 / 0.15 | 1.5 |
| Slow Value-Noise Drift | Value noise | 0.25 / 2 / 0.50 / 2.0 | 0.70 / off | 3 / 0.50 | 2.0 |
| Stereo Chorus Detune | Perlin fBm | 0.9 / 2 / 0.50 / 2.0 | 0.25 / off | 0 / 0.25 | 4.0 |
| Drunken Choir | Perlin fBm | 1.6 / 3 / 0.55 / 2.0 | 2.50 / off | 0 / 0.25 | 6.0 |
| Fast Multiscale Pitch Shiver | Perlin fBm | 10 / 4 / 0.65 / 2.0 | 0.35 / off | 0 / 0.25 | 2.5 |
| Cellular Pitch Jumps | Voronoi cellular | 22 / 3 / 0.50 / 2.0 | 7.00 / off | 0 / 0.25 | 3.0 |
| Chromatic Cellular Steps | Voronoi cellular | 6 / 3 / 0.50 / 2.0 | 12.0 / 1 st | 0 / 0.25 | 1.5 |
| Wide Pitch-Time Warp | Value noise | 1.2 / 2 / 0.50 / 2.0 | 3.0 / off | 35 / 0.60 | 1.5 |
| Quantum Glitch | Voronoi cellular | 30 / 3 / 0.50 / 2.0 | 4.0 / 2 st | 55 / 1.00 | 3.5 |
| Slow Sine Pitch Sweep | Sine LFO | 0.35 / 3 / 0.50 / 2.0 | 6.0 / off | 0 / 0.25 | 2.0 |
| Ridge Snap | Ridged multifractal | 5.0 / 4 / 0.55 / 2.0 | 2.00 / off | 0 / 0.25 | 2.0 |
| Turbulent Warp | Turbulence | 4.0 / 4 / 0.60 / 2.0 | 1.20 / off | 12 / 0.30 | 2.0 |
| Sparse Pitch Excursions | Sparse convolution | 3.0 / 3 / 0.50 / 2.0 | 5.00 / 1 st | 0 / 0.25 | 2.5 |
| Cell-Edge Detune | Cellular edges | 12 / 3 / 0.50 / 2.0 | 1.50 / off | 0 / 0.25 | 3.0 |
| Checker Trill | Checker | 9 / 3 / 0.50 / 2.0 | 3.00 / 1 st | 0 / 0.25 | 1.0 |
| Quasiperiodic Stereo Detune | Sine bank | 2.2 / 3 / 0.50 / 2.0 | 0.60 / off | 0 / 0.25 | 3.0 |
| Triangle Pitch-Time Warp | Triangle LFO | 0.6 / 3 / 0.50 / 2.0 | 8.00 / off | 20 / 1.00 | 1.5 |
| Hard Trill | Square LFO | 7 / 3 / 0.50 / 2.0 | 1.00 / 1 st | 0 / 0.25 | 1.5 |
Basis functions
Perlin fBm fractal
Additive fractal Brownian motion built from the script's 2-D gradient-noise function.
Ridged multifractal fractal
Rectifies and squares octave noise to create narrow high ridges over lower regions.
Turbulence fractal
Uses the absolute value of octave noise before summation, producing rectified multiscale motion.
Value noise noise
Quintic interpolation between deterministic hashed lattice values.
Sparse convolution noise
Sums signed cosine-windowed kernels around hashed feature points.
Voronoi cellular cellular
Assigns the value of the nearest deterministic feature point, creating piecewise-constant regions.
Cellular edges cellular
Maps the difference between the nearest and second-nearest feature-point distances.
Checker periodic
Hard two-state checker field based on integer X/Y cells.
Sine LFO periodic
A single sine field; Y position changes phase.
Sine bank quasiperiodic
Weighted sum of three sine components at 1x, 1.618034x, and 2.718282x.
Triangle LFO periodic
Piecewise-linear triangle field with Y-dependent phase.
Square LFO periodic
Two-state field obtained from the sign of a sine function.
Processing pipeline
1. Coordinate mapping and field detail
x = elapsed_time * Field_rate_units_per_sy = (channel - 1) * Y_offset_per_channelFor Perlin fBm, ridged multifractal, and turbulence, the script estimates the finest field-detail rate as
field_rate * lacunarity^(octaves-1). For the sine bank it uses field_rate * 2.718282. Other bases use the field rate directly.
2. Realized pitch-field calibration
When Calibrate_realized_depth is enabled, the script scans each actual channel trajectory over the full source duration. It subtracts a separate mean from each channel, finds the largest absolute centered excursion across all channels, and uses one common gain equal to its reciprocal. Therefore the largest realized pitch-field excursion reaches +/-1 while relative depth differences between channels are retained.
When calibration is disabled, pitch fields use zero offset and unit gain; values are still clipped to the interval [-1, 1] before mapping to pitch.
3. Pitch mapping
Pitch target
semitone_deviation = Np(t, ch) * Pitch_depth_semitones
If the grid is positive: deviation = round(deviation/grid) * grid
pitch_factor = 2^(deviation/12)
requested_F0 = analyzed_F0 * pitch_factor
Final target F0 values are clipped to 20 Hz through 0.45 x sampling rate. The Info window reports how many targets were clipped.
4. Adaptive Manipulation analysis step
analysis_step = clamp(1 / (8 * field_detail_rate), 0.002, 0.010) seconds.
The script also estimates control samples per field-detail unit and reports a warning when the value falls below 4.
5. Shared duration field
If Time_depth_percent is nonzero, a separate Y plane is used for duration control. The duration trajectory is sampled at field_rate * Time_rate_ratio. With calibration enabled, its piecewise-linear trajectory is centered using a trapezoidal mean and independently scaled to a peak magnitude of 1.
relative_duration = 1 + Nt(t) * Time_depth_percent / 100
These values are written to one DurationTier and the same tier is inserted into every channel's Manipulation object. Values above 1 locally lengthen time; values below 1 locally shorten it. The number of duration control intervals adapts to the estimated time-field detail and is capped at 6000 intervals (6001 points).
6. Per-channel resynthesis
Each channel receives its field-derived PitchTier and the shared DurationTier, then uses Get resynthesis (overlap-add). If no pitch points are detected for a channel, the script does not replace that Manipulation object's existing pitch tier.
Output behavior
| Property | Behavior |
|---|---|
| Name | <source>_bfg_<preset>, with spaces removed from the preset name. |
| Channels | The original channel count and order are preserved. Mono remains mono; multichannel inputs are rebuilt from the separately resynthesized mono channels. |
| Sample rate | Preserved through the Manipulation resynthesis and channel recombination. |
| Time origin | The result is shifted so its start time matches the source start time. |
| Duration | Without duration modulation, the result follows the source duration apart from resynthesis behavior. With a DurationTier, local relative-duration factors can change the final duration. The Info window reports input duration, the integrated tier-model duration, and actual output duration. |
| Peak stage | Peak_ceiling is an attenuate-only ceiling. Signals below the ceiling are not amplified. |
| Reproducibility | The field generator is deterministic. For hash-based noise functions, the same settings and Random_seed reproduce the same field trajectories; the periodic bases do not depend on the seed. |
Visualization
When Draw_visualization is enabled, the script draws a single diagnostic page:
- Raw 2-D procedural field (when
Draw_bfg_mapis enabled), with horizontal channel Y planes overlaid. - Calibrated Np(t) for channel 1 and, for multichannel input, the last channel. A green dotted curve shows the calibrated shared duration field when time modulation is active.
- Pitch tier, channel 1: analyzed F0 in grey and final clipped/modulated F0 targets in red.
- Output waveform: the resynthesized result. Multichannel waveforms are drawn in Praat's stacked-channel representation; the caption reports the final peak.
- Summary strip: basis settings, calibration values, pitch/time controls, analysis step, PSOLA range, duration, peak stage, channel count, and sample rate.