Skip to content

Latest commit

 

History

14 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PaulStretch for macOS (Swift)

A native macOS app that stretches audio into long-form ambient drones — a Swift/ AVFoundation + Accelerate port of the in-house PaulStretch engine from the browser project Driftscape. Drop in a WAV, pick a vibe and a length, get back a 15-second-to-60-minute stretched, reverbed drone.

Everything runs on-device. No dependencies beyond Apple frameworks.

Drone · Slow · Freeze — with a source region-looper, live spectrum, Apple stock effects, presets and batch export.

Build & run

  1. Open PaulStretchMac.xcodeproj in Xcode.
  2. Press ⌘R.

⚠️ Run in Release. The bundled shared scheme already defaults Run to Release. Do not run Debug for real use — unoptimised Swift is 20–50× slower for the FFT/DSP loops (a 5-min render goes from ~0.2 s to minutes). If you ever see it crawl, check Product ▸ Scheme ▸ Edit Scheme ▸ Run ▸ Build Configuration = Release.

Signing: the project ad-hoc signs ("Sign to Run Locally"), so it runs on your own Mac with no Apple Developer account. If Xcode nags, pick your team once.

Requirements: macOS 13+, Xcode 15+ (built/tested on Xcode 17 / macOS 26 SDK).

What it does

  • Five sound engines (the Style control):
    • Drone — classic PaulStretch: FFT + phase-randomised STFT wash. Layered (1/3/5 passes incl. octave-shifted Shimmer layerings), pitch, onset preservation, smoothness, wash amount.
    • Slow — tape-style slow-down (varispeed) tiled to length ("slowed + reverb").
    • Freeze — spectral freeze: captures one instant's spectrum and sustains it forever with shimmering phase → a frozen pad. Position + Motion (a slowly scanning capture point) + Blur.
    • Vocoder — phase-vocoder stretch: slows cleanly, keeping the source's structure and pitch — no wash, no tape pitch-drop.
    • Grains — granular cloud: grain size, density, scatter, pitch spread and stereo pan spread.
  • Source region-looper — load audio, drag on the waveform to select a region; it loops that region with a moving playhead. Drag inside to move it, click outside to deselect. The region is what gets stretched.
  • Seekable render transport — play/pause, scrub, stop-to-start, plus a live 56-band spectrum analyser of the output.
  • EffectsReverb (room→cathedral→plate), Tone (3-band EQ), Filter (resonant low-pass), Echo (delay) live on playback and baked into export, plus a Shimmer reverb (pitch-shifted feedback that climbs in octaves; applied to the render itself since feedback loops can't live on the playback graph).
  • Presets — 6 built-ins + save/load your own (persisted in UserDefaults), and a Reset-to-defaults.
  • Export — 24/16-bit WAV, 256k AAC or Apple Lossless (.m4a). Batch exports N random-seed variations to a folder (feeds a "pre-generate loops, host on a CDN" pipeline).
  • Multicore — the stretch and freeze run across all CPU cores (measured ~2000× realtime single-layer, ~280× lush, on a 14-core Mac).

Project layout

The DSP engine lives in the swift-paul-stretch package (github.com/arraypress/swift-paul-stretch), consumed as a local SPM dependency from ../Libraries/swift-paul-stretch. This repo is the GUI host:

swift-paul-stretch-mac/
  Lifecycle/           PaulStretchApp (@main) + StretchEngine (the coordinator)
  Views/               ContentView + one file per Form section
    Components/        SliderRow, WaveShape, WaveformScrubber, SpectrumView
  Utilities/           Panels (NSOpenPanel/NSSavePanel wrappers)
  Models/              Preset + built-ins/store + legacy migration
  Enums/               ExportFormat, ExportLoudness, LaneMotion
  Extensions/          Binding, Double, readout formatting
  genproj.py           regenerates project.pbxproj (file list + package reference)

Notes / known character

  • The fast "grain" you hear on a bare stretch is inherent to PaulStretch (phase randomisation, ~30% amplitude variation — the browser has it too). The intended masker is Reverb — turn it on (Cathedral) and it smooths out.
  • Effects are printed into exports. The dry render is kept in memory for scrubbing; the moment you Export, the current effect settings are baked in.
  • Long renders hold a lot of RAM (~1.3 GB per 60-min stereo buffer, more for Lush). Fine on a Mac; start short while auditioning.

Origin

The engine was ported from Driftscape (Vite + React + Web Audio) — the DSP was translated faithfully (verified bit-for-bit during extraction into the swift-paul-stretch package). The stock effects are Apple units; the shimmer reverb is the package's own DSP.

About

Native macOS app for long-form ambient renders: PaulStretch, tape-slow, spectral freeze, phase-vocoder and granular engines, with a live effects rack and batch export. SwiftUI host for the swift-paul-stretch package.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages