I ran into a situation with my midi drum machine where I wanted to be able to set up a grp but have the first parameter set a few different "default" parameters.
I made a function grpWith that works like grp but allows one to combine repeated values
with a specified combination function.
-- Might have some missing imports
import Text.Read (readMaybe)
import qualified Data.Map.Strict as Map
import Data.Maybe (fromMaybe)
import Sound.Tidal.Pattern (Value, Pattern, ControlPattern, ValueMap)
import Sound.Tidal.Utils (wordsBy)
-- | Like @grp@, but allows each part to create multiple control values
-- Combined with the union function `u`
grpWith :: (Value -> Value -> Value) -> [String -> ValueMap] -> Pattern String -> ControlPattern
grpWith u fs p = splitby <$> p
where
splitby :: String -> ValueMap
splitby s = Map.unionsWith u $ map (\(v, f) -> f v) $ zip (split s) fs
split :: String -> [String]
split = wordsBy (== ':')
type ParamList = [(String, Value)]
drumMachine :: [(String, ParamList)] -> Pattern String -> ControlPattern
drumMachine voices = grpWith (fNum2 (*) (*)) [ base , mF "legato" , mF "gain" ]
where
-- Create base ValueMap from the voice table
base :: String -> ValueMap
base voice = fromMaybe Map.empty $ do
baseParams <- lookup voice voices
return $ Map.fromList baseParams
-- | Control the drumkit with patterns like `"bd hh hh:0.5 sd . bd sd"`
drums :: Pattern String -> ControlPattern
drums pat = drumMachine voices pat # sound "midi" # release 0 # n "0"
where
params c l g =
[("midichan", (VI c)), ("gain", (VF (g*2.0))), ("legato", (VF l))]
voices =
[ ("bd", params 0 0.4 1)
, ("sd", params 1 0.1 1)
, ("hh", params 2 0.1 1)
]
What's really cool is I can have a default gain and legato that are tuned to work well with the quirks of my drum machine, and be able to multiply the values after : against the defaults!
This way I still have the flexibility to combine and override as usual, but gotta be mindful to use
|* if I want to preserve the behavior when composing patterns.
This should be flexible enough to work with notes instead of midi channels for each voice, but you'd have to update both drumMachine and drums
Shared under terms of AGPLv3.0.