[linux-audio-dev] Subharmonic synthesizer, is there one?

Paul Winkler pw_lists at slinkp.com
Wed Jun 18 13:10:01 UTC 2003


On Wed, Jun 18, 2003 at 06:52:05PM +0300, Kimmo Sundqvist wrote:
> Hello
> 
> I'd like to know if there is a subharmonic synthesizer for linux.  That is a 
> plugin which adds low frequency content to sound not by boosting, but by 
> synthesizing frequency components that are below what the signal otherwise 
> contains.  I'm thinking about something like Delaydots Phat Pro.  
> 
> If there is no such thing, is anyone thinking about developing one?

I have an old csound instrument i wrote that does this, in a similar way
to the old analog "octave" pedals.

there are more sophisicated techniques, i guess involving analysis of the signal
and generating sine waves based on the analysis...  but mine can be
quite useful.  I would love it if somebody made a LADSPA plugin out
of this algorithm.

my basic technique was this:

 steep lowpass filter (reduces the number of zero crossings)

 count upward-going zero crossings in the sine wave.
   if count % N == 1, set the output to 1.
   if count % N == 0, set the output to -1.

   N determines the frequency of the subharmonic. If N == 2, 
   you get an octave down. If N == 4, you get two octaves down.

 You now have a square wave with no dynamics, whose fundamental frequency
 is a subharmonic of the input signal. It has no dynamics, meaning it's
 likely to produce horrible noise if the input is low with a non-zero noise
 floor :)  We'll fix that later.

 Note that, like its analog counterparts, this algorithm gives somewhat 
 odd results when the input signal is complex, e.g. a dissonant chord.

 Next, apply a steep lowpass filter on the output unless you like the 
 square wave :) 

 Now apply gain balancing so that the output volume tracks the input volume.
 I don't know how you'd do that efficiently in C, i just used a csound 
 opcode that's provided for this purpose.

The csound instrument is attached, if that's useful...

-- 

Paul Winkler
http://www.slinkp.com
Look! Up in the sky! It's OCTO BARON-MAN!
(random hero from isometric.spaceninja.com)
-------------- next part --------------
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;copyright 1998 Paul M. Winkler, zarmzarm at hotmail.com
;****++++
;**** Last modified: Mon May  1 04:23:19 2000
;****----
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


	sr	=	44100
	kr	=	44100
	ksmps	=	1
	nchnls	=	2


instr 1
        ; subharmonic synthesis
        ; version one -- downsampling
        ; Low ksmps (1 or 2) gives best-sounding results.
istraightgain = ampdb(p4)                       ; used as gains,
idown1gain = ampdb(p5)                          ; not amplitudes.
idown2gain =  ampdb(p6)                         ; e.g. if arg is
                                                ; 6, the gain is 2.
                                                ; If arg. is -6, 
                                                ;  gain is 0.5.
; first generate some sound
kcount init 0
ktest init 0
;  kamp expseg .001, 0.5, 1, p3 -1, 1, 0.5, .0001 
kamp expseg .7, p3 -0.2 , 5, 0.2, 0.0005
kpitch init p7
a1, a2 diskin "FX/temp/bore-roar-mix-lopass.aiff", kpitch
;  a1, a2 diskin "FX/temp/bore-mix.aiff", kpitch
;  afilt1 tonex a1, 400, 4     ;  heavy pre-filtering.
amix = (a1 + a2) * .5
afilt1 resonx amix, 150, 200, 2, 1 ; this could use some tweaking
k1 downsamp afilt1

            ; Now process the mix.
            ; This works by counting upward zero crossings in the 
            ;  waveform.
            ;  The count is used to set the output to either 1 or -1
            ; so we get square waves at half (and a quarter) of
            ; the input frequency.
            ; adown1 is down an octave, adown2 is down 2 octaves.
kdetect trigger k1, 0, 0 ; notice only upward zero-crossings
if kdetect == 0 goto next1
kcount = kcount + 1
ktest = kcount % 4
next1:
if ktest != 1 goto next2
    adown1 = 1
    adown2 = 1
    goto output
next2:
    if ktest != 2 goto next3
    adown1 = -1
    adown2 = 1
    goto output
next3:
    if ktest !=3 goto next4
    adown1 = 1
    adown2 = -1
    goto output
next4:
    adown1 = -1
    adown2 = -1
output:
  ; Choose your filter...
;  adown1 tone adown1, kfreq * .04     ; takes out some high end, but
               ; still synth-sounding... looks like a triangle wave.
;  adown1 rezzy adown1, 40, 30      ; pretty smooth but asymmetrical.
;  adown1 tonex adown1, 40, 7         ; distorts with some inputs.
adown1 resonx adown1, 35, 60, 4       ; Very nice, near-sine output.
adown2 resonx adown2, 30, 50, 4
; adown1 butterbp adown1, 30, 10      ; output looks like a triangle wave!
adown1 dcblock adown1
adown2 dcblock adown2
adown1 balance adown1, afilt1   ; Restore dynamics.
adown2 balance adown2, afilt1   ; It's important to use filtered signal!

;   adjust output levels 
asubs = adown1*idown1gain + adown2*idown2gain
;  remove excessive subs.
asubs      atonex     asubs, 22, 5

a1 = (a1*istraightgain + asubs) * kamp
a2 = (a2*istraightgain + asubs) * kamp
outs a1 + asubs,  a2 +asubs
endin



instr 2                                         ; IGNORE THIS ONE.
        ; subharmonic synthesis
        ; version something-or-other... instr1 now is better.
        ; first generate some sound
k2       init 0
kx_count init 0
        ;  test with sine wave input
;  kfreq expseg 70, p3 / 2, 300, p3/2, 70
;  kamp expseg 1, 1, 16000, p3 - 2, 16000, 1, 1
;  a1 oscil kamp, kfreq, 1
kamp expseg .001, 0.5, 1, p3 -1, 1, 0.5, .0001 
kpitch expseg 2, p3, 0.5
a1 diskin "beats+loops/longroove.aiff", kpitch
;  a1filt tone a1, 80 ; doesn't seem to help much... maybe with complex pitches
; Also, low ksmps (1 or 2) gives best-sounding results.
k1 downsamp a1
kdetect trigger k1, 0, 0 ; notices only upward zero-crossings
if kdetect == 0 kgoto skip
kx_count = kx_count + 1   ; kdetect must be 1
skip:
;  I'll keep this next line just as a nice example of using || or && ...
;          if ((kx_count % 4) == 1) || ((kx_count % 4) == 2) kgoto positive
if ((kx_count % 2) == 1) kgoto positive
a2 = -1  ; if we're here, count is odd, so make output negative
kgoto output
positive:
        a2   = 1
output:
;a2 upsamp k2    ; 'interp' doesn't seem to help much here.
;  a2 = a2 * 16000
;  a2 tone a2, kfreq * .04         ; take out some high end, but
; still synth-sounding... looks like a triangle wave.
;  a2  rezzy    a2, 40, 30      ; pretty smooth but asymmetrical.
;  a2 tonex a2, 40, 7              ; distorts with some inputs.
a2 resonx a2, 35, 100           ; VERY nice, near-sine output.
; a2 butterbp a2, 30, 10         ; output looks like a triangle wave!
a2 balance a2, a1, 2            ; balance a2 to a1 to restore dynamics.
outs a1,  a2 
endin








;;; I N S T R U M E N T    3
;;; Dynamic Range Expander???
;;; Keywords: expansion

            instr       3
	;; Description of Arguments:
kpitch expseg 2, p3, 0.5
a1 diskin "beats+loops/longroove.aiff", kpitch
iscale = 1 / 32768
a1 = a1 * iscale                                ; normalize
a2 pow a1, 4                                   ; raise to power
a2 tone a2, 5000                                ; does this help?
a1 balance a1, a2                               ; do the dynamics
outs a1 * 32768, a2 * 32768                     ; re-normalize

            endin


-------------- next part --------------
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;copyright 1998 Paul M. Winkler, zarmzarm at hotmail.com
;****++++
;**** Last modified: Mon May  1 04:20:16 2000
;****----
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

f1 0 32768 10 1                          ; sine
;                       gains:  
;1      at      dur     straight down1  down2  pitch
;  i1      0       16.88   -2      -6      -60     
i1      0.1       4.4    0       4      10      0.6
;  i1      0       .       3       7       13      1       
i1      0       .       0       4       9      1.05       

f0 6



More information about the Linux-audio-dev mailing list