{"id":51229160,"url":"https://github.com/olilarkin/libpaulstretch","last_synced_at":"2026-06-28T14:30:37.568Z","repository":{"id":357211617,"uuid":"1207101885","full_name":"olilarkin/libpaulstretch","owner":"olilarkin","description":"Paulstretch for Modern C++/WASM","archived":false,"fork":false,"pushed_at":"2026-06-07T13:16:39.000Z","size":807,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-07T15:10:34.885Z","etag":null,"topics":["audio-processing","extreme","timestretch"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/olilarkin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-10T15:19:56.000Z","updated_at":"2026-06-06T13:16:57.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/olilarkin/libpaulstretch","commit_stats":null,"previous_names":["olilarkin/libpaulstretch"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/olilarkin/libpaulstretch","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olilarkin%2Flibpaulstretch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olilarkin%2Flibpaulstretch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olilarkin%2Flibpaulstretch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olilarkin%2Flibpaulstretch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/olilarkin","download_url":"https://codeload.github.com/olilarkin/libpaulstretch/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olilarkin%2Flibpaulstretch/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34892546,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-28T02:00:05.809Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["audio-processing","extreme","timestretch"],"created_at":"2026-06-28T14:30:35.682Z","updated_at":"2026-06-28T14:30:37.563Z","avatar_url":"https://github.com/olilarkin.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# libpaulstretch\n\nA portable C++20 library implementing the [Paulstretch](http://hypermammut.sourceforge.net/paulstretch/) extreme time-stretching algorithm. Ships an offline renderer, a realtime streaming primitive, optional spectral processing (pitch shift, octave mixer, frequency shift, compressor, filter, harmonics, spread, tonal-noise preservation, arbitrary filter), a binaural-beats post-processor, and an Emscripten/WebAssembly target.\n\n## Native build\n\n```bash\ncmake -S . -B build\ncmake --build build\nctest --test-dir build --output-on-failure\n```\n\n### FFT backends\n\nThe library supports three FFT backends, selected via the `PAULSTRETCH_FFT_BACKEND` CMake option:\n\n| Backend | Value | Description |\n|---|---|---|\n| **PFFFT** | `PFFFT` (default) | Fetched via CMake FetchContent from [marton78/pffft](https://github.com/marton78/pffft). SIMD-capable (SSE, NEON, WASM SIMD). Has specific transform-size constraints — the renderer auto-rounds `fft_size` to the nearest valid size. |\n| **Accelerate** | `ACCELERATE` | Uses Apple's vDSP via the Accelerate framework. macOS/iOS only. Requires power-of-2 FFT sizes (auto-rounded). |\n| **KissFFT** | `KISSFFT` | Bundled in `vendor/kissfft/`. Pure C, no SIMD — useful as a portable fallback when neither PFFFT nor Accelerate is available. |\n\n```bash\n# Default (PFFFT)\ncmake -S . -B build\n\n# macOS Accelerate\ncmake -S . -B build -DPAULSTRETCH_FFT_BACKEND=ACCELERATE\n\n# KissFFT fallback\ncmake -S . -B build -DPAULSTRETCH_FFT_BACKEND=KISSFFT\n```\n\n## WebAssembly build\n\n```bash\nemcmake cmake -S . -B build-wasm\ncmake --build build-wasm\n```\n\nOutput files land directly in `npm/dist/paulstretch.js` and `npm/dist/paulstretch.wasm` so that `cd npm \u0026\u0026 npm pack` produces a publishable tarball with no extra copying.\n\nSIMD is enabled by default (`-msimd128`). Disable with:\n\n```bash\nemcmake cmake -S . -B build-wasm -DPAULSTRETCH_ENABLE_SIMD=OFF\n```\n\n## C++ usage\n\n### Offline rendering\n\n```cpp\n#include \"paulstretch/paulstretch.h\"\n\npaulstretch::OfflineRenderer renderer({\n    .stretch = 8.0f,\n    .fft_size = 4096,\n    .sample_rate = 48000.0f,\n    .window = paulstretch::Window::Hann,\n});\n\nstd::vector\u003cfloat\u003e output = renderer.render_mono(input);\nauto [left, right] = renderer.render_stereo(left_in, right_in);\n```\n\nStereo rendering runs two independent stretchers but synchronizes onset detection across channels so they stay phase-aligned.\n\n### Streaming (realtime) rendering\n\n`StreamingStretcher` is a block-based push/pull primitive for realtime hosts (audio callback, AudioWorklet, Web Worker). The host gathers exactly the number of input frames the stretcher asks for, calls `step()` to produce one output chunk, then advances its input cursor by the additional skip distance:\n\n```cpp\npaulstretch::StreamingStretcher s({\n    .stretch = 8.0f,\n    .fft_size = 4096,\n    .sample_rate = 48000.0f,\n});\n\nstd::vector\u003cfloat\u003e out(s.bufsize());\n\nwhile (rendering) {\n    const int want = s.next_input_size();    // first call: 3 * bufsize() for initial fill\n    std::vector\u003cfloat\u003e in(want);\n    read_from_source(in.data(), want);       // zero-pad if source ran out\n\n    const float position_pct = 100.0f * input_cursor / total_input_frames;\n    s.step(in.data(), position_pct, out.data());\n    write_to_output(out.data(), s.bufsize());\n\n    input_cursor += want + s.skip_after_step();\n}\n```\n\n`set_stretch_factor()` hot-swaps the base stretch ratio without resetting DSP state, and `reset()` clears state for seek/loop while preserving configuration.\n\n### Stretch envelope\n\nApply a time-varying stretch multiplier with breakpoints. Each breakpoint has a `position` (0–1 normalized time) and a `value` (multiplier on the base stretch factor):\n\n```cpp\nrenderer.set_stretch_envelope({\n    {0.0f, 1.0f},   // start: 1× base stretch\n    {0.5f, 4.0f},   // middle: 4× base stretch\n    {1.0f, 1.0f},   // end: 1× base stretch\n});\n\nstd::vector\u003cfloat\u003e output = renderer.render_mono(input);\nrenderer.clear_stretch_envelope(); // revert to uniform\n```\n\n### Spectral processing\n\n`ProcessOptions` enables effects that run on the FFT bins between phase randomization and the inverse transform. All effects default to disabled; set the matching `*_enabled` flag plus its parameters:\n\n```cpp\npaulstretch::ProcessOptions p;\np.pitch_shift_enabled = true;\np.pitch_shift_cents = 700;             // up a perfect fifth\n\np.filter_enabled = true;\np.filter_low_hz = 200.0f;\np.filter_high_hz = 4000.0f;\n\np.harmonics_enabled = true;\np.harmonics_frequency_hz = 110.0f;\np.harmonics_count = 8;\n\nrenderer.set_process_options(p);\n```\n\nAvailable effects: pitch shift, octave mixer (–2/–1/0/+1/+1.5/+2), frequency shift, compressor, bandpass/notch filter, harmonics generator, stereo spread, tonal-noise preservation, and an arbitrary breakpoint-shaped filter (`set_arbitrary_filter` + `arbitrary_filter_enabled`). See `include/paulstretch/paulstretch.h` for the full struct.\n\n### Binaural beats\n\nPost-process the stretched output to add a sub-audio beat between L/R channels:\n\n```cpp\npaulstretch::BinauralBeatsProcessor bb(48000.0f);\nbb.set_options({\n    .enabled = true,\n    .stereo_mode = paulstretch::BinauralStereoMode::LeftRight,\n    .mono = 0.5f,              // mix toward mono before applying the beat\n    .beat_frequency_hz = 8.0f, // alpha range\n});\n\nbb.process(left.data(), right.data(), nframes, position_pct);\n```\n\nThe beat frequency can itself be automated with `set_frequency_envelope()`.\n\n### FFT backend introspection\n\n```cpp\nstd::string backend = paulstretch::fft_backend_name(); // \"PFFFT\"\nstd::string simd = paulstretch::fft_simd_arch();       // \"NEON\", \"SSE\", ...\nint width = paulstretch::fft_simd_size();              // 4\n```\n\n## Node.js / WASM usage\n\nThe Emscripten build is published as [`@olilarkin/paulstretch-wasm`](https://github.com/olilarkin/libpaulstretch/pkgs/npm/paulstretch-wasm). See [`npm/README.md`](npm/README.md) for installation, the full JS API (offline, streaming, envelope, spectral processing, binaural beats), and bundler notes. Type definitions live in [`npm/index.d.ts`](npm/index.d.ts).\n\nThe C++ and JS APIs are 1:1 — JS methods use camelCase versions of the C++ names, and `setProcessOptions` accepts a plain object instead of a `ProcessOptions` struct.\n\n## Notes\n\n- PFFFT only supports specific transform sizes. The renderer rounds `fft_size` to the nearest valid size automatically; read the effective value from `renderer.options().fft_size` (C++) after construction.\n- Sample rate, FFT size, and window are immutable after construction — build a new renderer to change them. Stretch factor, envelopes, and process options are hot-settable.\n- GPLv2-licensed.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Folilarkin%2Flibpaulstretch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Folilarkin%2Flibpaulstretch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Folilarkin%2Flibpaulstretch/lists"}