# Superfm

**URL:** <https://uzu.lurk.org/t/superfm/1761>\
**Category:** TidalCycles\
**Tags:** questions\
**Created:** [28 July 2020 13:07 UTC](https://uzu.lurk.org/t/superfm/1761 "2020-07-28T13:07:36Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![earthlydelight](https://uzu.lurk.org/letter_avatar_proxy/v4/letter/e/ecc23a/32.png) [@earthlydelight](https://uzu.lurk.org/u/earthlydelight)\
**Post date:** [28 July 2020 13:07 UTC](https://uzu.lurk.org/t/superfm/1761/1 "2020-07-28T13:07:37Z")

</div>

Hi! I'd like to play with the SuperDirt superfm synth, but can't understand the syntax. Can anyone give a quick example of how to set the parameters on the six operators?

I've read the docs here but I keep getting "variable out of scope" when I try to use e.g.:

```haskell
d1 $ sound "superfm" # ratio2 2.3

```

---

<div class="post-metadata">

**Author:** ![ndr\_brt](https://uzu.lurk.org/user_avatar/uzu.lurk.org/ndr_brt/32/396_2.png) [@ndr\_brt](https://uzu.lurk.org/u/ndr_brt)\
**Post date:** [28 July 2020 20:56 UTC](https://uzu.lurk.org/t/superfm/1761/2 "2020-07-28T20:56:02Z")

</div>

You need to define the parameters before, e.g.  
`let ratio2 = pF "ratio2"`

---

<div class="post-metadata">

**Author:** ![earthlydelight](https://uzu.lurk.org/letter_avatar_proxy/v4/letter/e/ecc23a/32.png) [@earthlydelight](https://uzu.lurk.org/u/earthlydelight)\
**Post date:** [28 July 2020 21:49 UTC](https://uzu.lurk.org/t/superfm/1761/3 "2020-07-28T21:49:48Z")

</div>

Ok that works, thank you! (Grazie mille 😉)

---

<div class="post-metadata">

**Author:** ![gamar3is](https://uzu.lurk.org/user_avatar/uzu.lurk.org/gamar3is/32/3020_2.png) [@gamar3is](https://uzu.lurk.org/u/gamar3is)\
**Post date:** [14 August 2020 21:22 UTC](https://uzu.lurk.org/t/superfm/1761/4 "2020-08-14T21:22:51Z")

</div>

You can also place the parameters in your `BootTidal.hs` file, I put this in mine, based on the [docs](https://tidalcycles.org/index.php/All_effects_and_synths#superfm):

```haskell
-- additions for superfm support
:{
let ratio1 = pF "ratio1"
    ratio2 = pF "ratio2"
    amp1 = pF "amp1"
    amp2 = pF "amp2"
    detune1 = pF "detune1"
    detune2 = pF "detune2"
    mod11 = pF "mod11"
    mod12 = pF "mod12"
    mod21 = pF "mod21"
    mod22 = pF "mod22"
    eglevel11 = pF "eglevel11"
    eglevel12 = pF "eglevel12"
    eglevel21 = pF "eglevel21"
    eglevel22 = pF "eglevel22"
    eglevel31 = pF "eglevel31"
    eglevel32 = pF "eglevel32"
    eglevel41 = pF "eglevel41"
    eglevel42 = pF "eglevel42"
    egrate11 = pF "egrate11"
    egrate12 = pF "egrate12"
    egrate21 = pF "egrate21"
    egrate22 = pF "egrate22"
    egrate31 = pF "egrate31"
    egrate32 = pF "egrate32"
    egrate41 = pF "egrate41"
    egrate42 = pF "egrate42"
:}

```

I only tried a couple of these; you'll notice that it's only using 2 operators out of the available 6, but for that you'd need to type every operator combination into this list, if I understand it correctly.

I suppose it'd be easier to declare each necessary parameter in your script instead of placing hundreds of them in your boot file. I hope someone more knowledgeable on the Tidal innards can tell about the "proper" way to do things!

---

<div class="post-metadata">

**Author:** ![ndr\_brt](https://uzu.lurk.org/user_avatar/uzu.lurk.org/ndr_brt/32/396_2.png) [@ndr\_brt](https://uzu.lurk.org/u/ndr_brt)\
**Post date:** [15 August 2020 18:32 UTC](https://uzu.lurk.org/t/superfm/1761/5 "2020-08-15T18:32:25Z")

</div>

I use a secondary `Parameters.hs` file called from the BootTidal (and another one called `Functions.hs`).

That's neat 🙂

---

<div class="post-metadata">

**Author:** ![yaxu](https://uzu.lurk.org/user_avatar/uzu.lurk.org/yaxu/32/2_2.png) [@yaxu](https://uzu.lurk.org/u/yaxu)\
**Post date:** [16 August 2020 13:18 UTC](https://uzu.lurk.org/t/superfm/1761/6 "2020-08-16T13:18:11Z")

</div>

We should add these to the stock tidal parameters.. So what would the full list be like?

---

<div class="post-metadata">

**Author:** ![yaxu](https://uzu.lurk.org/user_avatar/uzu.lurk.org/yaxu/32/2_2.png) [@yaxu](https://uzu.lurk.org/u/yaxu)\
**Post date:** [16 August 2020 13:22 UTC](https://uzu.lurk.org/t/superfm/1761/7 "2020-08-16T13:22:12Z")

</div>

It'd also be nice to have some 'presets' to add to superfm, anyone have some interesting ones?

I can ask my friend Dave about evolving some using this [https://fo.am/activities/midimutant/](https://fo.am/activities/midimutant/)

---

<div class="post-metadata">

**Author:** ![paul1](https://uzu.lurk.org/letter_avatar_proxy/v4/letter/p/3d9bf3/32.png) [@paul1](https://uzu.lurk.org/u/paul1)\
**Post date:** [16 August 2020 21:21 UTC](https://uzu.lurk.org/t/superfm/1761/8 "2020-08-16T21:21:54Z")

</div>

Rather than define all 81 parameters individually, I tried to add functions with parameters for the operator numbers:

```haskell
-- sets the amount of operator 'op' in the superfm output mix
-- (1 <= op <= 6)
fmamp :: Int -> Pattern Double -> ControlPattern
fmamp op = pF ("amp" ++ show op)

-- sets the ratio for operator 'op'.
-- the frequency is note * ratio + detune Hz
-- (1 <= op <= 6)
fmratio :: Int -> Pattern Double -> ControlPattern
fmratio op = pF ("ratio" ++ show op)

-- set the detune for operator 'op'
fmdetune :: Int -> Pattern Double -> ControlPattern
fmdetune op = pF ("detune" ++ show op)

-- set the modulation of oerator opa by operator opb
-- if opa == opb, then the modulation amount is multiplied by the
-- 'feedback' parameter
fmmod :: Int -> Int -> Pattern Double -> ControlPattern
fmmod opa opb = pF ("mod" ++ show opa ++ show opb)

-- feedback
fmfeedback :: Pattern Double -> ControlPattern
fmfeedback = pF "feedback"

-- Envelope definition: each operator has an envelop with 4 steps
fmeglevel :: Int -> Int -> Pattern Double -> ControlPattern
fmeglevel op step = pF ("eglevel" ++ show op ++ show step)

-- Envelope definition: sets the rate at which the envelope moves
-- between steps. Low numbers are slow, high numbers are fast.
fmegrate :: Int -> Int -> Pattern Double -> ControlPattern
fmegrate op step = pF ("egrate" ++ show op ++ show step)

```

Then you can use them like this:

```haskell
d1 $ stut 2 0.7 0.125 $ slow 3 $ s "superfm" 
  |+| note (arp "pinkyup" "[0,4,7,12] [0,5,7,9]" )
  # fmfeedback 1 -- global multiplier for 'fmod x x' feedback parameters.
  # fmamp 1 1 -- amplitudes default to '1', so probably need to set all 6 of them...
  # fmamp 2 0
  # fmamp 3 1
  # fmamp 4 0
  # fmamp 5 0
  # fmamp 6 0
  # fmratio 1 1 -- oscillator frequency is note * ratio + detune Hz.
  # fmratio 2 0.5 -- (range 0.25 20 (slow 3 $ sine))
  # fmdetune 2 1
  # fmratio 3 0.26
  # fmmod 1 1 "0"   
  # fmmod 1 2 (range 0 4 (slow 4 $ sine)) -- fmod a b Pattern = modulate op a with op b..
  # fmmod 1 3 (range 0 4 (slow 3 $ sine))
  # fmmod 3 2 (range 0 3 (slow 2 $ sine))
  # fmeglevel 1 1 "1" -- envelope generator has 4 rates and 4 steps for each operator...
  # fmeglevel 1 2 "0.5"
  # fmeglevel 1 3 "0"
  # fmeglevel 1 4 "0"
  # fmegrate 1 1 "10"  
  # fmegrate 1 2 "0.1"
  # fmegrate 1 3 "0.1"
  # fmegrate 1 4 "1"
  # fmeglevel 2 1 "1" -- envelope generator has 4 rates and 4 steps for each operator...
  # fmeglevel 2 2 "0"
  # fmeglevel 2 3 "0"
  # fmeglevel 2 4 "0"
  # fmegrate 2 1 "1"  
  # fmegrate 2 2 "0.3"
  # fmegrate 2 3 "0.7"
  # fmegrate 2 4 "1"
  # fmeglevel 3 1 "1" -- envelope generator has 4 rates and 4 steps for each operator...
  # fmeglevel 3 2 "0.2"
  # fmeglevel 3 3 "0"
  # fmeglevel 3 4 "1"
  # fmegrate 3 1 "10"  
  # fmegrate 3 2 "0.5"
  # fmegrate 3 3 "0.4"
  # fmegrate 3 4 "1"
  # room 0.3

```

The end result is pretty verbose though.

It makes some nice noises! (I have no idea what I'm doing, so I just put in numbers until something interesting came out...)

---

<div class="post-metadata">

**Author:** ![gamar3is](https://uzu.lurk.org/user_avatar/uzu.lurk.org/gamar3is/32/3020_2.png) [@gamar3is](https://uzu.lurk.org/u/gamar3is)\
**Post date:** [19 August 2020 21:18 UTC](https://uzu.lurk.org/t/superfm/1761/9 "2020-08-19T21:18:27Z")

</div>

Oh boy, this is a lot saner! The syntax looks more straightforward this way -- using the envelope numbers as parameters instead of part of the function name seems to make much more sense. Thank you so much \<3

---

<div class="post-metadata">

**Author:** ![ghales](https://uzu.lurk.org/user_avatar/uzu.lurk.org/ghales/32/2171_2.png) [@ghales](https://uzu.lurk.org/u/ghales)\
**Post date:** [5 September 2020 01:41 UTC](https://uzu.lurk.org/t/superfm/1761/10 "2020-09-05T01:41:38Z")

</div>

This is beaufitul, thank you so much ✨

---

<div class="post-metadata">

**Author:** ![earthlydelight](https://uzu.lurk.org/letter_avatar_proxy/v4/letter/e/ecc23a/32.png) [@earthlydelight](https://uzu.lurk.org/u/earthlydelight)\
**Post date:** [6 September 2020 09:29 UTC](https://uzu.lurk.org/t/superfm/1761/11 "2020-09-06T09:29:05Z")

</div>

When I try to evaluate the functions it gives me the following error:

```haskell
Warning: GHCi | mytidalfuncs.tidal:76:1: error:
Warning: GHCi | • No instance for (Show (Int -> Pattern Double -> ControlPattern))
Warning: GHCi | arising from a use of ‘print’
Warning: GHCi | (maybe you haven't applied a function to enough arguments?)
Warning: GHCi | • In a stmt of an interactive GHCi command: print it

```

Any idea why?

---

<div class="post-metadata">

**Author:** ![paul1](https://uzu.lurk.org/letter_avatar_proxy/v4/letter/p/3d9bf3/32.png) [@paul1](https://uzu.lurk.org/u/paul1)\
**Post date:** [6 September 2020 14:48 UTC](https://uzu.lurk.org/t/superfm/1761/12 "2020-09-06T14:48:02Z")

</div>

Could you post the code that is going wrong?

I can only guess at what you are doing otherwise, but one way to get that error message is to execute one of the functions on its own with no parameters.

e.g.

```haskell

fmamp

```

will produce:

```haskell
Warning: GHCi | <interactive>:247:1: error:
Warning: GHCi | • No instance for (Show (Int -> Pattern Double -> ControlPattern))
Warning: GHCi | arising from a use of ‘print’
Warning: GHCi | (maybe you haven't applied a function to enough arguments?)
Warning: GHCi | • In a stmt of an interactive GHCi command: print it

```

That is just Haskell telling you it doesn't know how to print a value of that type (in GHCi 'it' is the result of the last expression executed, and 'print it' is trying to print the result).

---

<div class="post-metadata">

**Author:** ![earthlydelight](https://uzu.lurk.org/letter_avatar_proxy/v4/letter/e/ecc23a/32.png) [@earthlydelight](https://uzu.lurk.org/u/earthlydelight)\
**Post date:** [6 September 2020 14:53 UTC](https://uzu.lurk.org/t/superfm/1761/13 "2020-09-06T14:53:28Z")

</div>

I just pasted your code in a new file called mytidalfuncs.tidal and then evaluated it from another file with:

```haskell
:script mytidalfuncs.tidal

```

---

<div class="post-metadata">

**Author:** ![paul1](https://uzu.lurk.org/letter_avatar_proxy/v4/letter/p/3d9bf3/32.png) [@paul1](https://uzu.lurk.org/u/paul1)\
**Post date:** [6 September 2020 16:15 UTC](https://uzu.lurk.org/t/superfm/1761/14 "2020-09-06T16:15:54Z")

</div>

You need to make the loaded script into a multiline command by wrapping it in :{ :} like this:

```haskell
:{
    -- sets the amount of operator 'op' in the superfm output mix
    -- (1 <= op <= 6)
    fmamp :: Int -> Pattern Double -> ControlPattern
    fmamp op = pF ("amp" ++ show op)

    -- sets the ratio for operator 'op'.
    -- the frequency is note * ratio + detune Hz
    -- (1 <= op <= 6)
    fmratio :: Int -> Pattern Double -> ControlPattern
    fmratio op = pF ("ratio" ++ show op)

    -- set the detune for operator 'op'
    fmdetune :: Int -> Pattern Double -> ControlPattern
    fmdetune op = pF ("detune" ++ show op)

    -- set the modulation of oerator opa by operator opb
    -- if opa == opb, then the modulation amount is multiplied by the
    -- 'feedback' parameter
    fmmod :: Int -> Int -> Pattern Double -> ControlPattern
    fmmod opa opb = pF ("mod" ++ show opa ++ show opb)

    -- feedback
    fmfeedback :: Pattern Double -> ControlPattern
    fmfeedback = pF "feedback"

    -- Envelope definition: each operator has an envelop with 4 steps
    fmeglevel :: Int -> Int -> Pattern Double -> ControlPattern
    fmeglevel op step = pF ("eglevel" ++ show op ++ show step)

    -- Envelope definition: sets the rate at which the envelope moves
    -- between steps. Low numbers are slow, high numbers are fast.
    fmegrate :: Int -> Int -> Pattern Double -> ControlPattern
    fmegrate op step = pF ("egrate" ++ show op ++ show step)
:}

```

If I save that as fm.tidal and load it using :script fm.tidal it seems to work (no errors at least). I can't check if it _actually_ works because my SuperCollider install is currently broken due to updating my mac to Big Sur beta....

---

<div class="post-metadata">

**Author:** ![earthlydelight](https://uzu.lurk.org/letter_avatar_proxy/v4/letter/e/ecc23a/32.png) [@earthlydelight](https://uzu.lurk.org/u/earthlydelight)\
**Post date:** [7 September 2020 11:37 UTC](https://uzu.lurk.org/t/superfm/1761/15 "2020-09-07T11:37:00Z")

</div>

That was definitely the problem, thank you 🙂

---

<div class="post-metadata">

**Author:** ![loopier](https://uzu.lurk.org/user_avatar/uzu.lurk.org/loopier/32/1152_2.png) [@loopier](https://uzu.lurk.org/u/loopier)\
**Post date:** [7 September 2020 19:38 UTC](https://uzu.lurk.org/t/superfm/1761/16 "2020-09-07T19:38:36Z")

</div>

Hi all,

I'm the developer of the Superfm synth for SuperDirt. I am very happy and touched to see other people using it. This is very exciting.

Sorry for the late reply, I've been more into Supercollider than Tidal lately. I wasn't aware of this thread. A friend pointed it to me just now.

I see there's quite a bit of confusion on this synth, so I'm planning on setting up an online workshop, or tutorial, or stream, or whatever, to give some guidelines on how this synth works. I have a busy month ahead, but I'll try to do it sometime during October. I don't think it's possible to do it before. Would you be up for it? Maybe a YouTube stream? What do you people think?

I'll try to give some answers to the different questions.

> [@yaxu](#):
>
> We should add these to the stock tidal parameters.. So what would the full list be like?

That would be absolutely awsome! This is the full list:

```haskell
-- modulators
mod11 = pF "mod11"
mod12 = pF "mod12"
mod13 = pF "mod13"
mod14 = pF "mod14"
mod15 = pF "mod15"
mod16 = pF "mod16"
mod21 = pF "mod21"
mod22 = pF "mod22"
mod23 = pF "mod23"
mod24 = pF "mod24"
mod25 = pF "mod25"
mod26 = pF "mod26"
mod31 = pF "mod31"
mod32 = pF "mod32"
mod33 = pF "mod33"
mod34 = pF "mod34"
mod35 = pF "mod35"
mod36 = pF "mod36"
mod41 = pF "mod41"
mod42 = pF "mod42"
mod43 = pF "mod43"
mod44 = pF "mod44"
mod45 = pF "mod45"
mod46 = pF "mod46"
mod51 = pF "mod51"
mod52 = pF "mod52"
mod53 = pF "mod53"
mod54 = pF "mod54"
mod55 = pF "mod55"
mod56 = pF "mod56"
mod61 = pF "mod61"
mod62 = pF "mod62"
mod63 = pF "mod63"
mod64 = pF "mod64"
mod65 = pF "mod65"
mod66 = pF "mod66"
-- operator envelope generator levels
eglevel11 = pF "eglevel11"
eglevel12 = pF "eglevel12"
eglevel13 = pF "eglevel13"
eglevel14 = pF "eglevel14"
eglevel21 = pF "eglevel21"
eglevel22 = pF "eglevel22"
eglevel23 = pF "eglevel23"
eglevel24 = pF "eglevel24"
eglevel31 = pF "eglevel31"
eglevel32 = pF "eglevel32"
eglevel33 = pF "eglevel33"
eglevel34 = pF "eglevel34"
eglevel41 = pF "eglevel41"
eglevel42 = pF "eglevel42"
eglevel43 = pF "eglevel43"
eglevel44 = pF "eglevel44"
eglevel51 = pF "eglevel51"
eglevel52 = pF "eglevel52"
eglevel53 = pF "eglevel53"
eglevel54 = pF "eglevel54"
eglevel61 = pF "eglevel61"
eglevel62 = pF "eglevel62"
eglevel63 = pF "eglevel63"
eglevel64 = pF "eglevel64" 
-- operator envelope generator rates
egrate11 = pF "egrate11"
egrate12 = pF "egrate12"
egrate13 = pF "egrate13"
egrate14 = pF "egrate14"
egrate21 = pF "egrate21"
egrate22 = pF "egrate22"
egrate23 = pF "egrate23"
egrate24 = pF "egrate24"
egrate31 = pF "egrate31"
egrate32 = pF "egrate32"
egrate33 = pF "egrate33"
egrate34 = pF "egrate34"
egrate41 = pF "egrate41"
egrate42 = pF "egrate42"
egrate43 = pF "egrate43"
egrate44 = pF "egrate44"
egrate51 = pF "egrate51"
egrate52 = pF "egrate52"
egrate53 = pF "egrate53"
egrate54 = pF "egrate54"
egrate61 = pF "egrate61"
egrate62 = pF "egrate62"
egrate63 = pF "egrate63"
egrate64 = pF "egrate64"
-- operator output levels
amp1 = pF "amp1"
amp2 = pF "amp2"
amp3 = pF "amp3"
amp4 = pF "amp4"
amp5 = pF "amp5"
amp6 = pF "amp6"
-- operator frequency ratios
ratio1 = pF "ratio1"
ratio2 = pF "ratio2"
ratio3 = pF "ratio3"
ratio4 = pF "ratio4"
ratio5 = pF "ratio5"
ratio6 = pF "ratio6"
-- operator frequency detuners
detune1 = pF "detune1"
detune2 = pF "detune2"
detune3 = pF "detune3"
detune4 = pF "detune4"
detune5 = pF "detune5"
detune6 = pF "detune6"
-- other
feedback = pF "feedback"
lfofreq = pF "lfofreq"
lfodepth = pF "lfodepth"

```

> [@yaxu](#):
>
> It'd also be nice to have some 'presets' to add to superfm, anyone have some interesting ones?

Yes, it'd be great! There are 6 presets already in the `# voice` parameter, but since I didn't really know what to put in them at first I let them be random for the time being. `0` is the default customizable one; [1-5] are random presets that are consistent for one boot - they are generated every time you boot SuperDirt and cleared when quitting the server, so you never get the same. Anyhow, by playing with it I came across a couple of nice presets that I will store in the `# voice` at some point, but will share here for now.

Double saw:

```haskell
d1 $ s "superfm"
# n 0
# amp1 1
# amp2 0
# amp3 1
# amp4 0
# amp5 0
# amp6 0
# ratio2 1.01
# mod12 0.75
# mod34 0.7
# mod45 0.6

```

Double pulse:

```haskell
d1 $ s "superfm"
# n 0
# amp1 1
# amp2 0
# amp3 1
# amp4 0
# amp5 0
# amp6 0
# ratio2 2.01
# ratio4 2
# ratio5 2
# mod12 0.75
# mod34 0.7
# mod45 0.6

```

FM bass:

```haskell

d1 $ s "superfm"
# octave 4
# n 0
# amp1 1
# amp2 1
# amp3 0
# amp4 0
# amp5 0
# amp6 1
# ratio2 2
# ratio3 3
# ratio4 4
# ratio5 0.5
# ratio6 0.25
# feedback 1
# mod11 1
# mod16 1
# mod23 1
# mod34 1
# mod45 1
# mod66 1
# egrate61 1
# egrate62 10
# egrate63 1
# eglevel62 0.13
# eglevel63 1.5
# room 0.5

```

> [@yaxu](#):
>
> I can ask my friend Dave about evolving some using this [https://fo.am/activities/midimutant/](https://fo.am/activities/midimutant/)

Wow! That's very very interesting. I love it. It would be so cool to have these.

> [@paul1](#):
>
> Rather than define all 81 parameters individually, I tried to add functions with parameters for the operator numbers:

This is absolutely brilliant. Thank you so much for posting it. I like it much better than the original function syntax, too. I'm not a Haskell person, so I very much appreciate this.

I think that's it for now. I'm open to further suggestions and improvements. I'll do my best on keeping track of any input. And would definitely love to see what interesting presets come out and may add them as voices, too. I myself discovered FM not long ago and am still in dipers, so any help will be very much appreciated.

Cheers!

---

<div class="post-metadata">

**Author:** ![gamar3is](https://uzu.lurk.org/user_avatar/uzu.lurk.org/gamar3is/32/3020_2.png) [@gamar3is](https://uzu.lurk.org/u/gamar3is)\
**Post date:** [8 September 2020 09:38 UTC](https://uzu.lurk.org/t/superfm/1761/17 "2020-09-08T09:38:07Z")

</div>

This is fantastic, thank you for posting this!!

I've been in love with superfm even though I have no idea what I'm doing by fiddling with the parameters. I'd love to get a better notion of what's going on, and finally try to get FM theory by having a practical application.

+1 for a Youtube workshop, I'll definitely be there if it happens.

(as an aside, I found the random preset feature really interesting, in that you cannot keep the same sound over work sessions. There were a couple of times that I stumbled into some really interesting presets, but since I don't know how to analyse their parameters, they were bound to be lost on reboot. I'm sure there's a life analogy in this.)

---

<div class="post-metadata">

**Author:** ![loopier](https://uzu.lurk.org/user_avatar/uzu.lurk.org/loopier/32/1152_2.png) [@loopier](https://uzu.lurk.org/u/loopier)\
**Post date:** [8 September 2020 10:24 UTC](https://uzu.lurk.org/t/superfm/1761/18 "2020-09-08T10:24:05Z")

</div>

> [@gamar3is](#):
>
> I'm sure there's a life analogy in this

haha yes, probably. When I add the other presets I will keep at least one random. I like the suprises it give, as well as the unpredictability of it.

> [@gamar3is](#):
>
> +1 for a Youtube workshop, I'll definitely be there if it happens.

Great! There are some people interested in it in the community here in Barcelona, so I'll start working on it. Will let you know when it happens.

> [@gamar3is](#):
>
> I've been in love with superfm even though I have no idea what I'm doing by fiddling with the parameters. I'd love to get a better notion of what's going on, and finally try to get FM theory by having a practical application.

This is wonderful! I actually built the synth to be able to learn and practice FM myself in a fast and fun way.

---

<div class="post-metadata">

**Author:** ![ghales](https://uzu.lurk.org/user_avatar/uzu.lurk.org/ghales/32/2171_2.png) [@ghales](https://uzu.lurk.org/u/ghales)\
**Post date:** [8 September 2020 11:39 UTC](https://uzu.lurk.org/t/superfm/1761/19 "2020-09-08T11:39:23Z")

</div>

Hey all! I was trying another approach, based on @paul1's code. Since everything uses numerical indices, the parameters work nicely with arrays.

These are the necessary definitions

```haskell
-- Parameters
let fmamp op = pF ("amp" ++ show op)
    fmratio op = pF ("ratio" ++ show op)
    fmdetune op = pF ("detune" ++ show op)
    fmmod opa opb = pF ("mod" ++ show opa ++ show opb)
    fmegrate op step = pF ("egrate" ++ show op ++ show step)
    fmeglevel op step = pF ("eglevel" ++ show op ++ show step)
    fmfeedback = pF "feedback"

-- Array functions
let fmparam function = foldr (#) (gain 1) . zipWith function [1..]
    lfma = fmparam fmamp
    lfmr = fmparam fmratio
    lfmd = fmparam fmdetune
    lfmer op = fmparam (fmegrate op)
    lfmel op = fmparam (fmeglevel op)
    lfmm opa = fmparam (fmmod opa) -- didn't test, should work

```

And this is how you use it:

```haskell
d1 $ stut 2 0.7 0.125 $ s "superfm"
  |+| note (arp "pinkyup" "[0,4,8,12] [0,3,7,11]" )
  # fmfeedback 1
  # fmdetune 2 1
  # lfmel 1 [1, 0.5, 0, 0] -- EG Level (Operator 1)
  # lfmer 1 [10, 0.1, 0.1, 1] -- EG Rate (Operator 1)
  # lfmel 2 [1, 0, 0, 0] -- EG Level (Operator 2)
  # lfmer 2 [1, 0.3, 0.7, 1] -- EG Rate (Operator 2)
  # lfmel 3 [1,0.2,0,1] -- EG Level (Operator 3)
  # lfmer 3 [10,0.5,0.4,1] -- EG Rate (Operator 3)
  # lfma [1, 1, 0, 0, 0, 1] -- Amps (Operators 1..6)
  # lfmr [1, 0.26, 0.5] -- Ratios (Operators 1..3)

```

Sorry about the names, they're very confusing right now. Also, big shoutout @loopier , great job with this SynthDef 🙂

edit: the `(gain 1)` on `fmparam` is a placeholder - I couldn't find a neutral `ControlMap` function (like `id`)  
edit2: adding `lfmm` for the `fmmod` function

---

<div class="post-metadata">

**Author:** ![loopier](https://uzu.lurk.org/user_avatar/uzu.lurk.org/loopier/32/1152_2.png) [@loopier](https://uzu.lurk.org/u/loopier)\
**Post date:** [8 September 2020 11:47 UTC](https://uzu.lurk.org/t/superfm/1761/20 "2020-09-08T11:47:56Z")

</div>

This is superb. That was my initial thought but didn't find a way to implement it. Looks beautiful. Thanks!

[Next page](https://uzu.lurk.org/t/superfm/1761.md?page=2)
