Function summary | |
---|---|
copy-time-signature | music-with-time-signature music-to-rebar |
count-notes | notes |
edit-omn | type notation fun &key (flat nil) (swallow nil) (section nil) (additional-args nil) |
ensure-double-list | x |
flattened-length-adjust | duration sequence |
fn-unfold | fns sequence |
length-add | &rest length-values |
length-subtract | &rest length-values |
map-events | fn sequence &key (test #'(lambda (&rest args) (declare (ignore args)) t)) flat section exclude |
map-omn | fn omn-expr |
map-position-in-bar | position type sequence fun &key (section nil) |
map-section | function sequence &key section exclude section-args shared-args |
mk-seed | &optional seed |
phrase-lengths | lengths |
process-element | fn element args |
process-omn2 | type function sequence &key flatten flat (span :length) swallow section exclude |
rnd-section | section-range probability &key seed |
swap-args | fn &optional (pos 1) |
total-duration | sequence &optional float? |
*< | sequence &key (transpose nil) (section nil) (exclude nil) (omn t) |
*<> | sequence &key (transpose nil) (section nil) (exclude nil) (omn t) |
*> | sequence &key (transpose nil) (section nil) (exclude nil) (omn t) |
*>< | sequence &key (transpose nil) (section nil) (exclude nil) (omn t) |
*a | sequence range &key (type :transpose) (section nil) (exclude nil) (omn nil) |
*ac | sequence size &key (unique t) (section nil) (exclude nil) |
*frag | sequence count range &key (encode t) (lists nil) (section nil) (exclude nil) (seed nil) |
*i | sequence &key (transpose nil) (section nil) (exclude nil) (omn t) |
*ld | sequence values &key set ignore (seed nil) (section nil) (exclude nil) (omn nil) |
*mute | sequence &key (section nil) (exclude nil) |
*r | sequence &key (transpose nil) (section nil) (exclude nil) (omn t) |
*rest | sequence value &key (type nil) (swallow t) (section nil) (exclude nil) (omn nil) (flat nil) (span :length) |
*ri | sequence &key (transpose nil) (section nil) (exclude nil) (omn t) |
*t | sequence transpose &key (section nil) (exclude nil) (ambitus 'piano) (omn nil) |
map-events | fn sequence &key (test #'(lambda (&rest args) (declare (ignore args)) t)) flat section exclude | [Function] |
Every event for which the function `test' returns true is transformed by the function `fn'. In the background, sequence is transformed into a list of events, where each note is represented by a list of the parameters length, pitch, velocity, and articulation.
Rests are skipped unprocessed.
fn: function expecting and returning a single event, i.e. the function expects the arguments length, pitch, velocity and articulation of individual elements.
sequence: an OMN sequence
test: Boolean function expecting a single event. By default, all elements are processed.
flat (Boolean): whether or not to flatten sequence before processing.
section (list of ints): 0-based positions of bars (sublists) in nested `sequence' to which `fn' is applied.
exclude (list of ints): 0-based positions of bars (sublists) in nested `sequence' to which `fn' is *not* applied. Only either `section' or `exclude' should be specified, otherwise `exclude' is ignored.
Reduce all events with velocity p to velocity pp
(map-events #'(lambda (l p v a) (list l p 'pp a)) '((-e s bb3 f marc a3 leg g3 p leg gs3 leg g3 leg a3 leg) (q fs3 f ten -q)) :test #'(lambda (l p v a) (eql v 'p)))
Many Opusmodus functions are defined to work only with lists. This function is intended to help when you want to instead process a single element with such a function.
Transpose a single element with pitch-transpose
(process-element #'pitch-transpose 'c4 '(2 _))
Without this function, the call above would look as follows.
(first (pitch-transpose 2 (list 'c4)))
It is a matter of taste/style, which approach you prefer :)
Of course, it might be better if instead Opusmodus functions would simply support single OMN notation elements as well.
Variant of mapcar for omn expressions, intended for creating variations of omn-expr. Applies function fn to every note in omn-expr (a flat OMN list). fn must exect four arguments (a length, pitch, velocity and articution) and returns a list of four values (a length, pitch, velocity and articution).
NOTE: This was one of my first Opusmodus function definitions, and while it works it is not as refined as some later functions :)
fn: a function expecting four arguments (a length, pitch, velocity and articulation) and returning a list of four values (a length, pitch, velocity and articulation).
omn-expr: an OMN expression
(map-omn #'(lambda (length pitch velocity articulation) (list length pitch ;; replace tasto dynamics by fff (if (equal articulation 'tasto) 'fff velocity) articulation)) '(e. c4 pppp tasto d4 ponte e4)) => (e. c4 fff tasto d4 pppp ponte e4)
(map-omn #'(lambda (length pitch velocity articulation) (list length (if (member 'slap (disassemble-articulations articulation)) 'c4 pitch) velocity articulation)) '((q b4 f slap+stacc -h q bb4 slap+stacc -h) (q gs4 slap+stacc -h) (q bb4 slap+stacc c5 mp ord d5 q. f5 e eb5 q d5) (-q c5 g4 h fs4 q eb5 stacc) (q c5 f slap+stacc -h q. g4 mp ord e f5 q e5) (q f5 cs5 f4 h d5 -q)))
Does not work if omn-expr contains rest.
Problem: omn does not provide any values for rests. Possible solution: couple note durations with their respective params, but leave rests without. Then skip rests in the processing unchanged. BTW: This process looses articulations on rests, like fermata.
See also the Opusmodus built-in function `single-events': looping (or mapping) over its result has similar effect.
Rebars `music-to-rebar' so that it fits the meter of `music-with-time-signature'. If music-with-time-signature is a flat list, no rebarring happens.
Apply a function to only selected bars (sublists) in an OMN sequence.
function: function to apply to sublists in `sequence'
sequence: nested list of OMN parameters or full OMN expressions
section (list of ints): 0-based positions of bars (sublists) in `sequence' to which `function' is applied.
exclude (list of ints): 0-based positions of bars (sublists) in `sequence' to which `function' is *not* applied. Only either `section' or `exclude' should be specified, otherwise `exclude' is ignored.
section-args (list or list of lists): Further arguments to `function' added behind the current sublist of `sequence'. If not a nested list, then only a single additional argument is specified for each bar (sublist) to which `function' is applied.
shared-args (list): Further arguments to `function' added behind the current sublist of `sequence' and potentially `section-args'.
(map-section #'(lambda (seq) (pitch-transpose 7 seq)) '((c4 c4 c4) (c4 c4 c4) (c4 c4 c4)) :section '(1 2))
(map-section #'(lambda (seq) (pitch-transpose 7 seq)) '((c4 c4 c4) (c4 c4 c4) (c4 c4 c4)) :exclude '(0))
(map-section #'(lambda (seq interval) (pitch-transpose interval seq)) '((c4 c4 c4) (c4 c4 c4) (c4 c4 c4)) :section '(1 2) :shared-args '(7))
(map-section #'(lambda (seq interval) (pitch-transpose interval seq)) '((c4 c4 c4) (c4 c4 c4) (c4 c4 c4)) :section '(1 2) :section-args '(7 12))
(map-section #'(lambda (seq count divide) (length-divide count divide seq)) '((q q q) (q q q) (q q q) (q q q)) :section '(1 2 3) :section-args '((1 2) (2 3)))
(map-section #'(lambda (seq count divide &rest args) (apply #'length-divide count divide seq args)) '((q q q) (q q q) (q q q) (h.)) :section '(1 2 3) :section-args '((1 2) (2 3)) :shared-args '(:ignore h.))
This function is a generalised and somewhat more clean variant of the Opusmodus builtin `do-section'.
edit-omn | type notation fun &key (flat nil) (swallow nil) (section nil) (additional-args nil) | [Function] |
Use function `fun', defined for transforming lists of individual OMN parameters of `type' (e.g., :length, or :velocity) to transform omn expression `notation'. This function is intended as a convenient way to generalise your functions to support omn notation as input.
type: a keyword like :length, :pitch, :velocity, :duration, or :articulation (any keyword supported by function omn or make-omn).
notation: a omn sequence or a plain parameter list (can be nested).
fun: a function expecting a parameter sequence of given type. It is sufficient to support only a flat input list, support for nested lists is added implicitly.
flat: whether or not `fun' expects a flat input list.
swallow: if `type' is :length, and `fun' turns notes into rests, the argument `swallow' sets whether the pitches of these notes should be shifted to the next note or omitted (swallowed). `swallow' is ignored if notation is a plain parameter list (e.g., a
section: only process the sublists (bars) at the positions given to this argument. Arg is ignored if `flat' is T.
additional-args (list of args): `additional-args' allows implementing 'dynamic' arguments, i.e., transformations that change over the sublists of `notation' depending on a list of arguments instead of a plain value. If `additional-args' is nil, then `fun' expects parameter values directly. However, if it is a list, then `fun' expects a list where the parameter values are the first element, and `additional-args' (if `flat' is T) or an element thereof (if `flat' is NIL) the second element in the list expected by `fun'.
Roll your own transposition function.
First define an aux def supporting only a flat list of pitches.
(defun my-transposition-aux (interval pitches) (midi-to-pitch (loop for p in (pitch-to-midi pitches) collect (+ p interval))))
Test that function.
(my-transposition-aux 7 '(c4 e4 g4)) => (g4 b4 d5)
Now, based on that aux function, define a function that supports also full OMN sequences. You can later expand this new function further with edit-omn to also support arguments like section and flat (see below).
(defun my-transposition (interval omn) (edit-omn :pitch omn #'(lambda (ps) (my-transposition-aux interval ps))))
Test the new function with nested OMN including rests.
(my-transposition 7 '((q c4 mp -q q e4 q f4) (h g4 tr2))) => ((q g4 mp - b4 c5) (h d5 mp tr2))
Another example: expand the built-in function `length-rest-series' to support arbitrary OMN expressions (not just length lists), and additionally the arguments `swallow' and `section'.
(defun note-rest-series (positions sequence &key (flat nil) (swallow nil) (section nil)) (edit-omn :length sequence #'(lambda (ls) (length-rest-series positions ls)) :swallow swallow :section section :flat flat)) (setf melody '((s eb6 < leg f5 < leg c5 < leg f5 < leg) (e e6 f - -q))) (note-rest-series '(1 1) melody :swallow T :section '(0))
The next example demonstrates how 'dynamic' arguments can be implemented, i.e. arguments that support different values for subsections. Below is a simplified definition of the function rotate-omn. Note how the function argument `n' is handed to the argument `additional-args' of `edit-omn' if `n' is a list. The function given to `edit-omn' also tests whether `n' is a list, and in that case extracts the OMN sublist to rotate as first element of the function argument `xs' and the amount of the rotation of this sublist as second element of `xs'. Further 'dynamic' arguments could be implemented by handing `additional-args' a list of argument lists to use, and by then extracting the relevant elements of such sublists within the function given to `edit-omn'.
(defun rotate-omn (n sequence &key (parameter :pitch) (flat T) (section nil)) (let ((n-list-arg? (listp n))) (edit-omn parameter sequence #'(lambda (xs) (if n-list-arg? (gen-rotate (second xs) (first xs)) (gen-rotate n xs))) :section section :flat flat :additional-args (when n-list-arg? n))))
The function rotate-omn can now be called with either giving a single number or a list of numbers to its argument `n'.
(setf melody '((-h e c4 e4) (q. f4 e g4 q a4) (q g4 f4 e e4 d4))) (rotate-omn 1 melody) ; default parameter pitch (rotate-omn '(0 1 2) melody :flat nil) (rotate-omn '(2 1) melody :section '(1 2) :flat nil :parameter :length)
process-omn2 | type function sequence &key flatten flat (span :length) swallow section exclude | [Function] |
Function similar to edit-omn that will soon be built-in in Opusmodus.
Transforms in the bars of `sequence' the parameter of `type' (e.g., :length) at `position' with `fun'.
Apply the articulation tenuto to every first note in all bars except the last bar.
(map-position-in-bar 0 :articulation '((-q c4 c4) (q c4 c4 c4) (q c4 c4 c4)) #'(lambda (ignore) 'ten) :section '(0 1))
Currently, rests are simply not counted when estimating the position of a parameter other then :length. Potential workaround: use argument `section'.
Returns the total duration (length) of `sequence', i.e. the sum of the length of all its notes and rests.
If `float?' is true the result is a float.
(total-duration '((h c4 q) (q h tie) (h.))) => 9/4
Currently, the built-in function length-adjust has no :flatten argument. This function offers a workaround.
Returns number of notes (ignoring rests) in length list or other OMN expression.
(count-notes '((q c4 c4 c4) (q g4 g4 g4)))
* BUG:
Counts tied notes as multiple notes.
Returns the number of notes between rests in the given lengths.
length: lengths or OMN (list or list of list).
Subtraction for OMN length values.
(length-subtract 'w 'q) => h.
Addition of OMN length values.
(length-add 'w 'q) => wq
The function returns a list of random section numbers intended for the argument section of many Opusmodus functions. The list of returned sections is unsorted.
section-range (pair of ints): the range of 0-based section positions (including boundaries) within which sections are returned.
probability (float in interval 0-1): the likelyhood by which sections are return, where 0 means the result is nil, 1 means that the result contains all sections within the given range, and, e.g., 0.5 means a 50 percent probability that any section is selected.
(rnd-section '(0 9) 0.5 :seed 1)
Generates a random seed value, prints and returns it. Useful for exploring different results of random processes, but then keeping a found solution.
This function is now rather redundant, as Opusmodus automatically prints seed values of all function calls.
seed (int): optionally fixes generated seed.
(rnd-sample 3 '(c4 d4 e4) :seed (mk-seed)) ; 405621 rnd-sample => (c4 e4 d4)
(rnd-sample 3 '(c4 d4 e4) :seed (mk-seed 13)) ; 13 rnd-sample => (e4 d4 e4)
Ensures that `x' is a duble-wrapped list. If not, a list (or two) are wrapped around it. As a precaution, if `x' is inconsistently nested, then the result is a flattened version of it with a double list wrapped around.
Much like the buildin Opusmodus `unfold`, but instead works with functions and additional arguments can be given to the functions. Apply to `sequence` all fns in order.
fns (list of lists): Each sublist has the form (<omn-fn> &rest <args>), where <omn-fn> is a function expecting an OMN sequence as first argument and arbitrary further argments, and <args> are the further arguments beyond the OMN sequence given to the function.
sequence: OMN sequence
Some material to use
(setf mat '((q c4 d4 e4) (h f4 q b3)))
Remember: all functions used must expect a OMN sequence as *first* argument.
(fn-unfold '((gen-retrograde :flatten T) (quantum :fraction -0.2)) mat)
Some short-hand versions of common functions are defined for conciseness. These short-hand functions commonly start with an asterisk (*) to stand out and to reduce namespace pollution.
(fn-unfold '((*t 12) (*ld (2 3) :section 1)) mat)
Return a function where the argument at `pos` is moved forward to become the first positional argument. Intended for making arbitrary OMN functions usable for `fn-unfold` (so that their OMN argument becomes the first positional argument).
Like pitch-transpose, but sequence as first param.
Like ambitus, but sequence as first param.
Like ambitus-chord, but sequence as first param.
Simplification of pitch-variant: return retrograde.
Simplification of pitch-variant: return inverse.
Simplification of pitch-variant: return retrograde inverse.
Simplification of pitch-variant: return descending.
Simplification of pitch-variant: return ascending.
Simplification of pitch-variant: return descending-ascending.
Simplification of pitch-variant: return ascending-descending.
Like length-divide, but sequence as first param.