Open mxmxyz opened 4 years ago
interesting! - just an observation: the notation
-- [3-3-4-2-4]
son = "1 0 0 1 0 0 1 0 0 0 1 0 1 0 0 0"
emphasizes that the comment is more readable than the 0/1 sequence.
Well, then let's write a function f
such that we can define
son = f [3,3,4,2,4]
[EDIT] something like
concatMap (\d -> 1 : replicate (d-1) 0) [3,3,4,2,4]
[1,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0]
For writing long-form sequences, I'd instinctively use spaces to express subdivision
son = "1 0 0 1 0 0 1 0 0 0 1 0 1 0 0 0"
this would bring it nearer to "traditional western notation" - which Toussaint avoids on purpose (see Preface 2nd ed.)
To detect typos in longer sequences, lilypond has the nice safety measure of "bar check" http://lilypond.org/doc/v2.20/Documentation/notation/bars#bar-and-bar-number-checks .
PS: I am interested in rhythms. I am reading Toussaint's book (I just ordered it since you mentioned it in the source). Amazingly, it feels completely disjoint (orthogonal?) to, say, https://hudsonmusic.com/product/the-breakbeat-bible/ . An algebraic approach (describe rhythms with trees) is http://repmus.ircam.fr/jacquemard/publications
I want to have the "break beat elements" available as algebraic operators...
Thanks! Your [Int] -> Pattern Bool
function is very useful even by itself, maybe warrants a PR?
it was of type [Int] -> [Int]
. This has type [Int] -> Pattern Bool
:
fastcat . map pure . concatMap (\d -> True : replicate (d-1) False)
make PR: well, let us include some more ideas from Toussaint's book. You already mentioned hop/jump. Can we do this?
NB: I find the book hard to read (or, too easy to read but too hard to make use of). It looks mathematical but actually it's not. All "definitions" (including "algorithms") are buried in the text, and it's often definition-by-example only, so it's not exactly clear what happens in the general case, what are the actual inputs, and what is the claimed property of the output, and why the claim would be true in general.
For instance, hop/jump (p. 80). The example starts at "5 onsets in a cycle of 12 pulses". Then the "hop width" is 2. Why? Is this width actually the third input of the algorithm? (I would certainly implement it that way.) What are its admissible values? E.g., it probably couldn't be 1 since that would create a cluster (interval of adjacent onsets). But even with hop-width 2, some clusters may appear. Or may they not? Are they allowed in an "odd" pattern? Are we using the def. from p. 75, or p. 77? And so on.
These rhythms are great but I can't help thinking that baking them into a module seems a bit of a shame. I feel if I used such a rhythm I'd always want to edit it. So perhaps this would be better as part of a snippet library, for fast recall into an editor plugin? One problem is that we have a lot of editor plugins and there isn't a standard for snippets as far as I know..
... want to edit
yes but you could also apply Tidal's combinators/transformers.
I thought that some of these algorithms from Toussaint's book could be added, like euclid
is today (as a function, I'm not saying we should invent mini-notation for them).
It can be a first step, and it does not hurt?
On the general question of what to add to a library, cf. https://wiki.haskell.org/Fairbairn_threshold
Perhaps there is a way to get rid of the distinction between library function and user defined function? Something like copy on edit?
Interesting. You mean, when using Tidal, there should be a way to "get the source code for this (library) function" in the editor buffer, to change it?
This would require source code to be available, which normally isn't.
After cabal install tidal
, ghci
uses object (that is, machine code) files.
If ghci
was started in tidals's source directory, then source code is present. But then we need to think about naming (for the copy of the function) and scoping (if it's using other functions that are not exported).
That's certainly possible, but would require a larger effort (design, implementation, installation), and would be worthy of a separate issue.
I thought the original topic (Toussaint's rhythm functions) is a nice student programming exercise. (But I don't have students right now - will have in October.)
Maybe #682 could help with this - an API for expanding code.
Would be nice to be able to expand
rumba
into "1 0 0 1 0 0 0 1 0 0 1 0 1 0 0 0"
"3(3,8)"
into "3 ~ ~ 3 ~ ~ 3 ~"
(or whatever it is)and so on
Just came across this, seems like it's doing something like what's described in this issue:
Hi, Yes. I've been working on these patterns lately basically for the same reason I created the Scales and Chords modules a while back (because I'm lazy and don't want to type the same thing over and over and over again). PS, that's why I created this PR days ago :-)
Re: Technical aspects of how to implement this: Tried to keep this as simple as possible. In the past (circa 2016) it was possible to write patterns as n "1 0 1 0" # s "sample"
, not sure if this is still the case, but found about mask
/ struct
and both seem to do the trick. There are many patterns that can be written as Euclidean rhythms but that would be a bit annoying to parse [0] later.
[0] Sidenote: "t ~ [~ t] ~"
is much more simple to convert to other format (for example: a SuperCollider Dict) than x(6,8)
.
Hi! quite a while since I've posted on here.
Toussaint's book is awesome imo. I think being able to compactly express sparse rhythms like the son and bossa nova timelines would be really powerful.
Following up on @jwaldmann 's function implementing @mxmxyz 's notation, the following works like a charm (highly hacky charm).
let timeline p = parseBP_E (map (\c -> if c==',' then ' '; else c) $ show $ concatMap (\d -> 1 : replicate (d-1) 0) p)
Example:
d1 $ (# sound "sd") $ gain (timeline [3, 4, 3, 2, 3] )
Not patternable though.
@TylerMclaughlin The only downside to that is that you can't use invert
(or functions that are applied to pattern... am i right? it's been a while since i used tidal. there's a high chance i'm wrong), other than that -which i'm sure that in the case of being true, it can be converted to a Pattern Something
(sic) somehow- looks really useful.
@lvm , you can do anything like rev $ timeline [3, 4, 3, 2, 3]
or plyWith 2 (euclid 3 8) $ amp (timeline [3,3, 2, 3, 3])
but what you can't do is pattern the list of integers with something like timeline [3, <4 5>, 3, 2, 3]
. It's got the same syntax as choose
.
I've seen before but haven't used invert
. inv
won't work on what i posted because it's [Int] -> Pattern
, but it definitely does work on @jwaldmann 's [Int] -> Pattern Bool
version.
today learned it's way tidier to use fastcat and map pure instead of the hacky show / parseBP_E combo :D
better 0 and 1s version:
let timeline p = (fastcat . map pure . concatMap (\d -> 1 : replicate (d-1) 0)) p
and @jwaldmann 's
let tlbool p = (fastcat . map pure . concatMap (\d -> True : replicate (d-1) False) p
Since the bool version might be more versatile than the 1s and 0s version, maybe it would make sense to consider a more general As and Bs timeline function:
let tlab a b p = (fastcat . map pure . concatMap (\d -> a : replicate (d-1) b)) p
a and b can be midi note numbers, or instrument/sample names.
you can get really fun linear rhythms:
d1 $ s (tlab "hh" "bd" [3,4,2,3,4])
Just a note, if you get rid of the map pure
you can actually just have A and B as patterns, and Haskell should usually figure out the correct type. For example:
tlab a b = fastcat . concatMap (\d -> a : replicate (d-1) b)
d1 $ s (tlab "hh" "bd" [3,4,2,3,4]
still works fine but now you can do
d1 $ s (tlab "hh*2" "bd" [3,4,2,3,4]
Patternizing the list is a little harder - have to think about what something like tlab "hh" "bd" ["3 4", 3, 4]
should even mean, but I suspect there's probably a way to do it.
There is a Scales module which has been growing in size and scope, with several popular (and some less popular) scales to use as convenient shorthands. It's a nice module, because it's self-documenting and so can double as a reference of sorts . I think it would sometimes be handy to also have similar shorthands for rhythms, expressed as
Pattern Bool
s, usable with functions such asstruct
andwhile
.I've been collecting some rhythms here; there is probably a better and more systematic way to collect them, although I don't really know where to look for myself. Still, even working with such a small library feels very nice.