{"id":17087916,"url":"https://github.com/geraintluff/jsfx-pad-synth","last_synced_at":"2025-10-14T17:28:41.936Z","repository":{"id":66040933,"uuid":"67369351","full_name":"geraintluff/jsfx-pad-synth","owner":"geraintluff","description":"Synth written in REAPER's JSFX language","archived":false,"fork":false,"pushed_at":"2018-07-07T17:45:01.000Z","size":6041,"stargazers_count":15,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-08-02T04:02:22.155Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/geraintluff.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2016-09-04T21:31:49.000Z","updated_at":"2025-04-13T18:50:36.000Z","dependencies_parsed_at":null,"dependency_job_id":"cfcdface-773e-4d83-b485-a04c0eff496d","html_url":"https://github.com/geraintluff/jsfx-pad-synth","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/geraintluff/jsfx-pad-synth","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geraintluff%2Fjsfx-pad-synth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geraintluff%2Fjsfx-pad-synth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geraintluff%2Fjsfx-pad-synth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geraintluff%2Fjsfx-pad-synth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/geraintluff","download_url":"https://codeload.github.com/geraintluff/jsfx-pad-synth/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geraintluff%2Fjsfx-pad-synth/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279020076,"owners_count":26086806,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-14T02:00:06.444Z","response_time":60,"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":[],"created_at":"2024-10-14T13:35:24.164Z","updated_at":"2025-10-14T17:28:41.919Z","avatar_url":"https://github.com/geraintluff.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PadSynth\n\nThis is a synth written in REAPER's JSFX language, producing sounds that are thick and smooth.\n\nDemos are available in the `demos/` directory, and some presets are in `padsynth-presets.rpl`.\n\nTo install using ReaPack, add my [JSFX collection](https://geraintluff.github.io/jsfx/).\n\nTo install by hand, copy `pad-synth.jsfx` to REAPER's `Effects/` directory.  You will also need `ui-lib.jsfx-inc` from the [JSFX UI library](https://github.com/geraintluff/jsfx-ui-lib) in the same directory as this synth for it to work.\n\n## Features\n\n### Generates its own samples\n\nA \"model waveform\" is generated, and this is used to generate a set of patches used by a sampling engine.\n\nThe samples are designed in the frequency domain (65536 samples long, 48kHz), and then IFFT'd.  By converting each harmonic into a frequency distribution (with random phase) it generates sounds that are both smooth and \"thick\".\n\nThis thickness can be varied using a process vaguely similar to granular synthesis.\n\n### Intermodulated effects\n\nThis synth has its own effects chain applied separately for each note, including modulators that can alter other effects' parameters (or the note pitch/amplitude/spread).\n\nAvailable effects are:\n\n*\tFilter - 2nd-order lowpass with basic envelope and note/velocity response.  Various parameters (e.g. frequency and Q) are automatable.\n*\tHarmonic Modulator (FM) - a frequency modulator for FM synthesis. FM depth and Hz-offset are modulatable.\n*\tDistortion - a nonlinear filter (currently tanh() only) with optional asymmetry.  Wet/dry is modulatable\n\nAvailable modulators are:\n\n*\tController/Note/Velocity modulator - uses controller values, note number or velocity\n*\tLFO - uses a sinusoid oscillator. Frequency and amplitude of LFO are themselves modulatable.\n*\tEnvelope - uses attack/release\n\nModulatable note parameters are:\n\n*\tPitch\n*\tAmplitude\n*\tDetune/thickness width\n\nWant to make your vibrato dependent on the note velocity?  Want to make your filter frequency dependent on the Expression controller (11)?  Just hook it up.\n\n## Implementation details\n\nAlthough REAPER's built-in FFT has a maximum size of 32768, we can generate larger samples by implementing an extension to this (using Cooley-Tukey factorisation).  This longer FFT code is available [here](https://github.com/geraintluff/jsfx-fft-big).\n\nDetuning width is varied by constantly cross-fading between two points in the sample one wavelength apart.  How often this crossfade is completed and whether we skip forward or backwards determines whether the overall progression rate through the sample is faster or slower than \"natural\" playback.  Progressing faster through the sample increases the detuning amount, and progressing slower decreases it.\n\n## Development\n\nThe code is in `pad-synth.txt`.  This project makes use of a [JSFX preprocessor](https://www.npmjs.com/package/jsfx-preprocessor) to generate `pad-synth.jsfx`.\n\nThis means that to assemble the final code, you'll need Node.js installed.\n\n```\nnode build.js\n```\n\nTo monitor with `nodemon`, use `npm run nodemon` - you can also specify any additional locations to write the result to (e.g. the [JSFX collection](https://github.com/geraintluff/jsfx)):\n\n```\nnpm run nodemon -- ../jsfx-collection/pad-synth.jsfx\n```\n\n## Goals\n\nHere are some things I'd like to work on in future:\n\n### Speed\n\nIt's a little slow at the moment - I don't know how much of this is just because it's written in JSFX, but maybe there are some things that could speed it up.\n\n### Custom waveforms\n\nWe could have custom waveforms by specifying harmonics, or even drawing them (which is then analysed and turned into harmonics).\n\n### More effects\n\nDifferent filter types, multi-stage filters, make more parameters modulatable.\n\nPan/width control, global LFO (so that notes can remain in sync even with different starting times).\n\nOnly per-note effects need to be part of this synth - any \"global\" effect (e.g. reverb) is better implemented as a separate plugin, placed after this one in the chain.\n\n### Waveform width parameters\n\nCurrently, the spread of each harmonic is a Gaussian proportional to frequency (\"natural\" detuning).  However, other detunings would be good.\n\nIt also currently adds harmonics by sampling the density function - this requires a bit of a hack to make sure our width isn't small enough that we completely miss the harmonic.  Instead, we could generate a table of the cumulative density function, and sample the diff (linearly interpolated), which would guarantee coverage (as well as allowing better customisation of the spread).\n\nThis probably means the cumulative table should be power, not amp.\n\n### Pitch bend, other controllers\n\nCurrently ignores pitch bend.\n\n### More compact UI\n\nThe UI is currently spread across more screens than it needs to be - this is largely because the UI library didn't initially have dials or vertical sliders.  However, several of the screens could now be combined using more compact controls\n\n*\tEnvelope could be part of the main screen\n*\tNew \"harmonic spread\" parameters could be part of waveform design screen\n*\tCompact controls on other screens (such as effects) could make room for displays (e.g. small oscillator phase indicator)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeraintluff%2Fjsfx-pad-synth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgeraintluff%2Fjsfx-pad-synth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeraintluff%2Fjsfx-pad-synth/lists"}