GENpadsynth

"padsynth" — Generate a sample table using the padsynth algorithm.

Description

Paul Octavian Nasca's "padsynth algorithm" adds bandwidth to each partial of a periodic weaveform. This bandwidth is heard as color, movement, and additional richness of sound.

First, the waveform is defined by the user as a series of harmonic partials. Then, bandwidth is added by independently spreading each partial of the original waveform from a single frequency across neighboring frequencies, according to a "profile" function: a Gaussian curve, a square, or a rising and then falling expontential.

The partials of the original waveform may be considered to be samples in a discrete Fourier transform of the waveform. Normally there is not an exact one-to-one correspondence between the frequencies of the samples (frequency bins) of the discrete Fourier transform with the frequencies of the partials of the original waveform, because any frequency in the inverse of the discrete Fourier transform might be synthesized by interference between any number of bins. However, the padsynth algorithm uses a simple trick to create this correspondence. The discrete Fourier transform is simply made so large that the frequency of any partial of the original waveform will be very close to the frequency of the corresponding bin in the Fourier transform. Once this correspondence has been created, the bandwidth profile can be applied by centering it over the frequency bin of the original partial, scaling the profile by the bandwidth, and simply multiplying the original partial by each sample of the profile and adding the product to the corresponding bin of the Fourier transform.

As the frequencies of the partials increase, their bandwidth may optionally become wider or (less often) narrower.

Once each partial has been spread out in this way, the discrete Fourier transform may be given random phases, and is then simply inverted to synthesize the desired waveform, which may be used as the wavetable for a digital oscillator.

N.B.: The size of the function table does NOT necessarily reflect one periodic cycle of the waveform that it contains. The fundamental frequency must be used to generate the desired pitch from an oscillator using the function table, e.g.

oscillator_hz = desired_hz * (sr / padsynth_size / fundamental_hz)

Syntax

f # score_time table_size "padsynth" fundamental_frequency
    partial_bandwidth partial_scale harmonic_stretch profile_shape profile_shape_parameter
    partial1_amplitude [partial2_amplitude ...]

Initialization

table_size -- Function table size. Should be large, e.g. 2^18 == 262144. Must be a power of 2 or power-of-2 plus 1 (see f statement).

fundamental_frequency -- Fundamental frequency for the generated table.

partial_bandwidth -- Bandwidth of each partial in cents.

partial_scale -- Scaling factor for bandwidth of each partial (log of increase/decrease with partial frequency, 0 is no stretch or shrink).

harmonic_stretch -- Harmonic stretch/shrink for all partials (1 is harmonic).

profile_shape -- Number specifying the shape of the bandwidth profile: 1 = Gaussian, 2 = square, and 3 = exponential

profile_shape_parameter -- Parameter passed to the function generating the profile shape, e.g. exponent.

partial1_amplitude, partial2_amplitude, ... -- Amplitudes for each partial (may be zero).

Examples

Here is an example of the GENpadsynth routine. It uses the files padsynth_gen.csd.

Example 1222. An example of the GENpadsynth routine.

<CsoundSynthesizer>
<CsOptions>
-odac
</CsOptions>
<CsInstruments>
sr=44100
ksmps=1
nchnls=2
0dbfs=2000

	gispec_len init 2^18

	instr 1
    prints "Plain sine for frequency/amplitude/distortion comparison.\n"
	gi_padsynth_1 ftgenonce 0, 0, gispec_len, 10, 1
    iattack = 0.08
    idecay = 0.1
    isustain = 0.25
    irelease = 0.2
    aenv madsr iattack, idecay, isustain, irelease
    ifreq cpsmidinn p4
    iamp ampdb p5
    ibasefreq = 440 ; can be lower or higher frequency; close to played frequency is said to be best
    ibw_cents = 56.96943 ; width of the peaks, 100 is semitone
	asig poscil iamp, ifreq, gi_padsynth_1
    asig = aenv * asig
	aleft, aright pan2 asig, 0.5
	outs aleft, aright
	endin

	instr 2
    prints "PadSynth with sine tone.\n"
    ibasehz = 261.625565
    ;                       p1 p2 p3          p4           p5       p6  p7    p8 p9  p10  p11
	gi_padsynth_1 ftgenonce 0, 0, gispec_len, "padsynth", ibasehz, p6, 0.0,  1, 1,  1.0, 1
    iattack = 0.08
    idecay = 0.1
    isustain = 0.25
    irelease = 0.2
    aenv madsr iattack, idecay, isustain, irelease
    ifreq cpsmidinn p4
    iamp ampdb p5
	asig poscil iamp, ifreq*(sr/gispec_len/ibasehz), gi_padsynth_1
    asig = aenv * asig
	aleft, aright pan2 asig, 0.5
	outs aleft, aright
	endin

	instr 3
    prints "PadSynth with harmonics.\n"
    ibasehz = 261.625565
    ;                       p1 p2 p3          p4           p5       p6  p7 p8 p9  p10  p11
	gi_padsynth_1 ftgenonce 0, 0, gispec_len, "padsynth", ibasehz, p6, 1, 1, 1,  1, 0.7600046992, 0.6199994683, 0.9399998784, 0.4400023818, 0.0600003302, 0.8499968648, 0.0899999291, 0.8199964762, 0.3199984133, 0.9400014281, 0.3000001907, 0.120003365, 0.1799997687, 0.5200006366, 0.9300042987
    iattack = 0.08
    idecay = 0.1
    isustain = 0.25
    irelease = 0.2
    aenv madsr iattack, idecay, isustain, irelease
    ifreq cpsmidinn p4
    iamp ampdb p5
	asig poscil iamp, ifreq*(sr/gispec_len/ibasehz), gi_padsynth_1
    asig = aenv * asig
	aleft, aright pan2 asig, 0.5
	outs aleft, aright
	endin

	instr 4
    prints "PadSynth with inharmonic partials.\n"
    ibasehz = 261.625565
    ;                       p1 p2 p3          p4           p5       p6  p7 p8 p9  p10  p11
	gi_padsynth_1 ftgenonce 0, 0, gispec_len, "padsynth", ibasehz, p6, 1, 2, 3,  1, 0.7600046992, 0.6199994683, 0.9399998784, 0.4400023818, 0.0600003302, 0.8499968648, 0.0899999291, 0.8199964762, 0.3199984133, 0.9400014281, 0.3000001907, 0.120003365, 0.1799997687, 0.5200006366, 0.9300042987
    iattack = 0.08
    idecay = 0.1
    isustain = 0.25
    irelease = 0.2
    aenv madsr iattack, idecay, isustain, irelease
    ifreq cpsmidinn p4
    iamp ampdb p5
	asig poscil iamp, ifreq*(sr/gispec_len/ibasehz), gi_padsynth_1
    asig = aenv * asig
	aleft, aright pan2 asig, 0.5
	outs aleft, aright
	endin


</CsInstruments>

<CsScore>



i1  0 2 60.00 60
i1  + 2 72.00 60
i1  + 2 84.00 60

i2  7 2 60.00 60 0.3
i2  + 2 72.00 60 0.3
i2  + 2 84.00 60 0.3
i2  + 2 60.00 60 25
i2  + 2 72.00 60 25
i2  + 2 84.00 60 25
i2  + 2 60.00 60 55
i2  + 2 72.00 60 55
i2  + 2 84.00 60 55

i3 26 2 60.00 60 0.3
i3  + 2 72.00 60 0.3
i3  + 2 84.00 60 0.3
i3  + 2 60.00 60 25
i3  + 2 72.00 60 25
i3  + 2 84.00 60 25
i3  + 2 60.00 60 55
i3  + 2 72.00 60 55
i3  + 2 84.00 60 55

i4 45 2 60.00 60 0.3
i4  + 2 72.00 60 0.3
i4  + 2 84.00 60 0.3
i4  + 2 60.00 60 25
i4  + 2 72.00 60 25
i4  + 2 84.00 60 25
i4  + 2 60.00 60 55
i4  + 2 72.00 60 55
i4  + 2 84.00 60 55

e
</CsScore>
</CsoundSynthesizer>


See Also

More information on Padsynth: www.paulnasca.com/algorithms-created-by-me

Credits

Written by Michael Gogins

New in version 6.05