-- | Representing rhythms as rose trees. module Boopadoop.Rhythm where import Data.Numbers.Primes import Data.List.Split -- | A rhythm is represented as a rose tree where each subtree is given equal amounts of time. -- Leaves are either a Beat of type @a@ or empty (a rest). data Beat a = RoseBeat [Beat a] | Beat a | Rest -- | Class for things that can be summarized in a single character, for use in printing out rhythms. class SummaryChar a where sumUp :: a -> Char -- | Show the rhythm by printing the summary characters, or @'.'@ for rests. instance SummaryChar a => Show (Beat a) where show (RoseBeat bs) = "[" ++ (bs >>= show) ++ "]" show (Beat x) = [sumUp x] show Rest = "." -- | A rack of drums. Simple enumeration of the different possible drum types. data DrumRack = Kick | Snare instance SummaryChar DrumRack where sumUp Kick = 'O' sumUp Snare = 'x' -- | The standard rock beat (or half of it) played on the 'DrumRack' rockBeat :: Beat DrumRack rockBeat = RoseBeat [Beat Kick, Rest, Beat Snare, Rest] -- | Force there to be only prime divisions of time in the rhythm. -- This is done without affecting the actual rhythm. -- This operation is not uniquely valued in any way, and this algorithm prefers small primes first. primeBeat :: Beat a -> Beat a primeBeat (RoseBeat bs) | isPrime (length bs) = RoseBeat $ map primeBeat bs | otherwise = let (pf:_) = reverse $ primeFactors (length bs) in primeBeat . RoseBeat . map RoseBeat $ chunksOf pf bs primeBeat x = x