Writing addon library for MIDI instruments

hi everyone!

i want to ask for help regarding Haskell libraries, since i am writing one to integrate with hardware synths and i am stuck right now :slight_smile:

my motivation is being able to easily retrieve parameters from hardware instruments such as Korg volca beats while live coding.

for example, on the korg volca beats, the kick is note 36, and snare is 38, so i want to be able to retrieve those numbers with notation Korg.volcaBeats.kick which i want to evaluate to 36, so i can use it on Tidal scripts.

another example would be that MIDI instruments tend to have a default MIDI channel for input, and i want to be able to store that on this library, so i can write code such as Korg.volcaBeats.midiChannel, which should evaluate to 10.

i am writing it here, and so far i have played around and been able to create dummy Haskell modules and published the library, but i need help with the Haskell code.

i would like to finish the Korg.hs module with several instruments, and each instrument with several parameters, like these:

Korg has instruments volcaBeats, volcaFM, minilogue, monologue, etc
volcaBeats has noteKick = 36, noteSnare = 38, midiChannel = 10, etc

so that they can be accessed with the notation Korg.volcaBeats.noteKick, and also i would love thoughts about less verbose ways to write the same :slight_smile:

2 Likes

Hi @montoyamoraga,

Here's an example of how you can do this kind of lookup in a pattern. It's a stray bit of code that has made its way into the main tidal library. I think I made this for using the volca beats, coincidentally.

drum :: Pattern String -> ControlPattern
drum = n . (subtract 60 . drumN <$>)

drumN :: Num a => String -> a
drumN "bd" = 36
drumN "sn" = 38
drumN "lt" = 43
drumN "ht" = 50
drumN "ch" = 42
drumN "oh" = 46
drumN "cp" = 39
drumN "cl" = 75
drumN "ag" = 67
drumN "cr" = 49
drumN _ = 0

Then you can do e.g.

d1 $ drum "bd sn ~ ag" # sound "midi"
``
You could make aliases for cc messages too. I'd have to think a little bit about how to do that in a nice way that supports multiple CC messages to be patterned at once.
14 Likes

thank you!

i will play around with this and implement it :slight_smile: !

1 Like

I just implemented @yaxu's drum/drumN approach for my drum synth and it works wonderfully! It's enough of a difference in pattern-coding that it results in some different sequences I wouldn't normally create. Easier to code too!

4 Likes

Interesting! Did you do this for the Rytm? Defining the pads with their own midichan etc? I guess then they could be called in a single sequence by like "pad1 ~~ pad2"? I could see that being really useful.

@ben yes indeed, replaced n with midichan:

let  
  rytm = s "rytm"
  drum :: Pattern String -> ControlPattern
  drum = midichan . (drumN <$>)
  drumN :: Num a => String -> a
  drumN "bd" = 2
  drumN "sd" = 1
  drumN "ch" = 10
  drumN "oh" = 11
  drumN "cp" = 3
  drumN "lt" = 5
  drumN "mt" = 6
  drumN "ht" = 7
  drumN "pad" = 4
  drumN _ = 12
  rytmm x = drum x # rytm # note "c3"

d1 $ rytmm "bd [cp, mt] ch*4 sd"
4 Likes

Very cool. Way more convenient, thanks (to all)!

Thanks for bumping that thread !

I'm trying to set something similar to use with Ableton Live's Drum Rack. Got it all working aside from the "default" routing to its dedicated midichan (that would be s "midi" # midichan 0"). Each drum pad equals a midi note, starting from -24.

  x0x :: Pattern String -> ControlPattern
  x0x = n . (subtract 24 . drumN <$>)
  drumN :: Num a => String -> a
  drumN "1" = 0
  drumN "2" = 1
  drumN "3" = 2
  drumN "4" = 3
  drumN "5" = 4
  drumN "6" = 5
  drumN "7" = 6
  drumN "8" = 7

Currently it'll work with :

d1 $ x0x "[1(3,8) , [~ 3]*2]" # s "midi" # midichan 0

And even though I've tried several tricks as shown above, I've yet to find the right bit of code to get it of the midi routing (just like kindohm did a couple of post ago)

edit : of course, I made it work minutes after my post haha !

Added this : (drm being a previously set alias for s "midi # midichan 0). So obvious I overlooked that, damn ! :smiley:

x0xx x = x0x x # drm

d1 $ x0xx "[1(3,8), [~ 3]*2]"

It just works, thanks again every one ! :slight_smile:

4 Likes

@nilhartman game changer! this is great. assuming i can use the standard note notation here too if i need to..."c1", "d2", etc? thanks everyone!

Could this approach be extended to allow "variant n in a group of MIDI sounds"?

Goal: Send a sequence of numbers like "bd" or "sn" usually allow, picking sounds in MIDI instead of samples from a folder, like this (here):

d1 $ n "0 1 2 3" # s "numbers"

Background: I'm sequencing an Elektron Analog Four, with a set of drum sounds by Kimura Taro (link). There are 128 sounds in the "Sound Pool" available; e.g., 12 different kickdrum sounds.

My current definition was made by imitating the posts in this topic (af for "Analog Four"):

let
  drum :: Pattern String -> ControlPattern
  drum = n . (subtract 60 . drumN <$>)
  drumN :: Num a => String -> a
  drumN "bd1" = 1 -- BD C01 (Kick)
  drumN "bd2" = 2 -- BD C02 (Kick)
  drumN "bd3" = 3 -- BD C03 (Kick)
  drumN "bd4" = 4 -- BD C04 (Kick)
  drumN "bd5" = 5 -- BD C05 (Kick)  .... (etc. etc. up to sound 128)
  drumN _ = 0
  afmidi = s "midi"
  af x = drum x # afmidi

-- usage
d1 $ af "bd1 bd4"

This works really well, but doesn't allow sending a sequence of numbers to select between the kick sounds. Any hints as to how the let could be altered? To allow:

d1 $ n "1 4" # af "bd"

Would it be possible to add velocity controls into a mapping like this? My use case is having some mappings be accented. For instance:

d1 $ drm "~ S ~ [s ~ ~ S]"

Where S is an accented snare and s is at a lower velocity?

S = 2 # amp 1 and s = 2 # amp 0.5?