Both sides previous revision
Previous revision
Next revision
|
Previous revision
|
sarah [2017/09/05 22:27] shane [SARAH: FFT-based synthesizer plugin] |
sarah [2017/09/30 15:38] (current) shane |
- 1024 samples of each waveform (one cycle) are generated once, using exactly the same mathematical expressions used in the LFOs, resulting in mathematically "exact" waveforms having 512 harmonics. | - 1024 samples of each waveform (one cycle) are generated once, using exactly the same mathematical expressions used in the LFOs, resulting in mathematically "exact" waveforms having 512 harmonics. |
- Each mathematically-exact waveform is transformed using //juce::dsp::FFT// to produce a frequency-domain representation, which is a new 1024-element array, where each element ("coefficient") represents the relative amplitude and phase of all 512 harmonics. These three "frequency-domain" tables (one each for triangle, square, and sawtooth wave shapes) are kept in memory. | - Each mathematically-exact waveform is transformed using //juce::dsp::FFT// to produce a frequency-domain representation, which is a new 1024-element array, where each element ("coefficient") represents the relative amplitude and phase of all 512 harmonics. These three "frequency-domain" tables (one each for triangle, square, and sawtooth wave shapes) are kept in memory. |
- Each oscillator instance has its own 1024-element array. In preparation to sound a note, it copies the coefficient data out from the appropriate common frequency-domain table to its own array, then performs an //in-place **inverse** FFT// to re-create the appropriate time-domain wave table. To prevent aliasing, only the coefficients for harmonics below the //Nyquist frequency// (one-half the sampling rate) are copied; higher-order coefficients are set to zero. | - Each oscillator instance has its own 1024-element array. In preparation to sound a note, it copies the coefficient data out from the appropriate common frequency-domain table to its own array, then performs an //in-place **inverse FFT**// to reconstruct the appropriate time-domain wave table. To prevent aliasing, only the coefficients for harmonics below the //Nyquist frequency// (one-half the sampling rate) are copied; higher-order coefficients are set to zero. |
- To sound a note, the oscillator resamples its own 1024-element array (wave table). | |
| |
===== Harmonic Shaping ===== | ===== Harmonic Shaping ===== |
| |
Because SARAH is using coefficient adjustments and the inverse FFT to //simulate// filtering, I decided to call this //Harmonic Shaping// rather than "filtering". I'm not at all convinced this is a sensible alternative to conventional (time-domain) digital filtering, but it is certainly interesting, and allowed me to implement simple time-varying timbres (using both an envelope generator and an LFO) with just a few simple changes to the existing anti-aliased oscillator code. | Because SARAH is using coefficient adjustments and the inverse FFT to //simulate// filtering, I decided to call this //Harmonic Shaping// rather than "filtering". I'm not at all convinced this is a sensible alternative to conventional (time-domain) digital filtering, but it is certainly interesting, and allowed me to implement simple time-varying timbres (using both an envelope generator and an LFO) with just a few simple changes to the existing anti-aliased oscillator code. |
| |
| ===== The details ===== |
| See [[sarah_oscillator_details|this page]] for the gritty details of SARAH's oscillator implementation. |
| |
| ===== Skinning ===== |
| As of 29 September, 2017, SARAH uses a single-view GUI instead of the multi-tabbed approach inherited from [[https://github.com/getdunne/VanillaJuce|VanillaJuce]]. See [[sarah_skinning|this page]] for some thoughts on the two approaches. |
| |
| |
| |