August 15Aug 15 I'd like to take a simple vector like(setf test '(q c4 d4 e4 f4 g4 a4 b4 c5))and broadcast it across 2+ instruments, so that one instrument plays the first note, the second plays the second note, and then the first instrument plays the third note, etc. I thought the length-invert command would work(length-invert '(q c4 d4 e4 f4 g4 a4 b4 c5) :exclude '(1 3))but this produces (-q c4 - d4 - - - -)as opposed to the desired(q c4 - e4 - - - - -)Any ideas on what I'm doing wrong?
August 15Aug 15 :exclude refers to sections meaning sublists (bars).My first idea was this:(setf test '(q c4 d4 e4 f4 g4 a4 b4 c5)) (length-rest-series (rp '(200 1)) test) (length-rest-series (rp '((1 0) (200 1))) test)Instead of 200 use just any number bigger than the length of the list.
August 15Aug 15 ;;; more flexible is this approach: (setf test '(q c4 stacc d4 leg e4 f4 g4 stacc a4 b4 c5)) ;; call this function or add it to the "User attributes.lisp" under extensions. Call the attribute ch(x) or voice(x) (add-program-attributes '(ch1) '(ch2) '(ch3) '(ch4) '(ch5) '(ch6) '(ch7) '(ch8) '(ch9) '(ch10) '(ch11) '(ch12) '(ch13) '(ch14) '(ch15) '(ch16) ) ;; then add to the omn-sequence the nubmber of voices as attributes ;;best is to create this attributes when you create the omn. ;;if there are no other attributes this will do (setf channels (omn-replace :articulation '(ch1 ch2 ch3) test)) ;or any number of channels ;; if there are other attributes, first get the attributes and then merge and then omn-replace (setf add_chx (merge-attributes (get-articulation test) (gen-repeat 500 '(ch1 ch2 ch3)))) (setf channels (omn-replace :articulation add_chx test)) ;; then use filter-events to get the part you want. This works to anny number of voices(channels) you defined (setf t_ch1 (filter-events 'ch1 channels :joined-attributes t)) (setf t_ch2 (filter-events 'ch2 channels :joined-attributes t)) (setf t_ch3 (filter-events 'ch3 channels :joined-attributes t)) If there is a better way to do that I would like to know.
August 15Aug 15 a (very simple) more lispian version (setf l1 '(1 0 1 1 0 0 0 1 0 1 0 0 0 1 0 1 0 1 1 1 0 1 0 1)) ; an eventlist (setf l2 '(0 1 0 0 0 1 0 0 1 1 0 1 0 0 1 0 1 0 0 0 1 1 1 0)) ; another eventlist (setf plist (gen-repeat 2 (rnd-air :type :pitch))) ;; a rnd-pitch-seq (setf rlist (rnd-sample 50 '(1/16 2/16 3/16 5/16))) ;; a rnd-length-seq ;; voice 1 (setf instr1 (loop repeat (length l1) for cnt = 0 then (incf cnt) when (= (nth cnt l1) 1) collect (list (nth cnt rlist) (nth cnt plist) 'f) else collect (* -1 (nth cnt rlist)))) ;; voice 2 (setf instr2 (loop repeat (length l2) for cnt = 0 then (incf cnt) when (= (nth cnt l2) 1) collect (list (nth cnt rlist) (nth cnt plist) 'p) else collect (* -1 (nth cnt rlist )))) ;; check by MERGE (merge-voices instr1 instr2)
August 15Aug 15 packed in a function ... as many voices you want...;; packed in a function (defun gen-omn-by-events (elist plist rlist &key (vel 'p)) (loop repeat (length elist) for cnt = 0 then (incf cnt) when (= (nth cnt elist) 1) collect (list (nth cnt rlist) (nth cnt plist) vel) else collect (* -1 (nth cnt rlist )))) (setf events1 '(1 0 1 1 0 0 0 1 0 1 0 0 0 1 0 1 0 1 1 1 0 1 0 1)) ; an eventlist (setf events2 '(0 1 0 0 0 1 0 0 1 1 0 1 0 0 1 0 1 0 0 0 1 1 1 0)) ; another eventlist (setf events3 '(1 1 1 0 1 1 0 0 0 0 1 1 0 0 1 1 0 0 1 0 1 0 0 0)) ; another eventlist (setf instr1 (gen-omn-by-events events1 plist rlist :vel 'p)) (setf instr2 (gen-omn-by-events events2 plist rlist :vel 'f)) (setf instr3 (gen-omn-by-events events3 plist rlist :vel 'ppp)) ;; ........ ;; check it (merge-voices instr1 instr2 instr3)
August 16Aug 16 I understood that jacobcvt12 is looking for a hocketing-function that can be applied to any existing omn.I improved my idea above to work over any omn-seq with or without attributes and with or without bars. (setf test '(q c4 d4 e4 f4 g4 a4 b4 c5)) (setf test '(q c4 stacc d4 leg e4 f4 g4 stacc a4 b4 c5)) (setf test '((q c4 stacc d4 leg e4 f4 g4 stacc a4 b4 c5)(e c4 stacc d4 leg e4 f4 g4 stacc a4 b4 c5))) (setf test '((q c4 d4 e4 f4 g4 a4 b4 c5)(e c4 d4 e4 f4 g4 a4 b4 c5))) ;; call this function or add it to the "User attributes.lisp" under extensions. Add any number of chx or what you want to call it. (add-program-attributes '(ch1) '(ch2) '(ch3) '(ch4) ) ;; function to define number of voices and setting the attributes. starts each bar from ch1 when :bars is t (defun rk_hocket (omnl ch_list &key (bars nil)) (if (some 'listp omnl) (if (not bars) (omn-replace :articulation (merge-attributes (get-articulation omnl) (gen-divide (mclength (omn :articulation omnl)) (flatten (gen-repeat (length (flatten seq)) ch_list)))) omnl) (omn-replace :articulation (loop for bar in omnl collect (merge-attributes (get-articulation bar) (gen-repeat (length bar) ch_list))) omnl)) (omn-replace :articulation (merge-attributes (get-articulation omnl) (gen-repeat (length omnl) ch_list)) omnl) ) ) ;; call function with attribute-list (setf channels (rk_hocket test '(ch1 ch2 ch3) :bars t)) ;; could also be like this (setf channels (rk_hocket test '(ch1 ch3 ch3 ch2))) ;; then use filter-events to get the part you want. This works for any number of voices(channels) you defined (setf t_ch1 (filter-events 'ch1 channels :joined-attributes t)) (setf t_ch2 (filter-events 'ch2 channels :joined-attributes t)) (setf t_ch3 (filter-events 'ch3 channels :joined-attributes t)) ;; you can also do that on creation of the omn (setf test (make-omn :pitch '(c4 d4 e4 f4 g4 a4 b4 c5) :length '(q) :articulation '(ch1 ch2 ch3) :span :pitch)) ;; and than use the filter-events ;; test on a more complicated omn (setf seq '((5h fs6 mp stacc 5q f6 ten - fs6 fermata) (3h bb6 p stacc -3q) (5q gs6 f stacc a6 ten - gs6 fs6 fermata) (5e gs6 mf stacc fs6 stacc 5q g6 ten - gs6 fermata g6) (s bb6 mp stacc b6 ten bb6 -) (5q f6 p stacc 5h fs6 ten 5q f6 -) (5q eb6 f stacc - 5h e6 ten 5q eb6))) (setf channels (rk_hocket seq '(ch1 ch2 ch3))) (setf channels (rk_hocket seq '(ch1 ch2 ch3) :bars t)) (setf t_ch1 (filter-events 'ch1 channels :joined-attributes t))As hocket is a defined musical technique maybe Opusmodus could offer a library-function for this?This one is good enough for me. So far no problems.I could not find a function to just add attributes to an own-seq. So I had to get-articulation, merge the ones I want to add and then replace-articulation.Is there a way to just add a list of attributes directly without deleting the old ones? I mean the merging is done in the function if there is something to merge.
August 16Aug 16 An example of hocketing can be found in the documentation of the find-complement function.
August 16Aug 16 Yes, but how could that be used to hocket over an existing omn like this:(setf test '((q c4 stacc d4 leg e4 f4 g4 stacc a4 b4 c5) (e c4 stacc d4 leg e4 f4 g4 stacc a4 b4 c5)))
August 16Aug 16 Will this work?Jesper(setf test '((q c4 stacc d4 leg e4 f4 g4 stacc a4 b4 c5) (e c4 stacc d4 leg e4 f4 g4 stacc a4 b4 c5))) (setf test2 (single-events (flatten-omn test))) (lake-everyother 16 0 2 test2) (lake-everyother 16 1 2 test2)
August 16Aug 16 Yes it works. The bars are gone but can be added later. You have to do some calculations for 3 or 4 voices. A good idea. I have not yet used the lake-functions. I like Per Nørgård's music. Will have a closer look at it. When there are rests in the omn then there will be no real hocketing because the rest is an event and the same voice plays the next pitch, too. As far as I see the rk_hocket takes care of the rests.@AM: Thanks. Will have a look at it tomorrow.
August 17Aug 17 The idea with add-program-attributes and '(ch1) etc. I got from Stephane and used it quite often for splitting voices. Wouldn't have thought of that myself. Thanks. Different problem, but...https://opusmodus.com/forums/topic/3801-playing-a-multi-channel-guitar-instrument-on-midi-channels-1-6/?&do=getNewComment&comment=12962
August 17Aug 17 a simple hocket-function - starting with an OMN-sequence(defun gen-hocket-voice (elist omnlist) (let ((omnevents (single-events omnlist))) (loop repeat (length (single-events omnlist)) for cnt = 0 then (incf cnt) when (= (nth cnt elist) 1) collect (nth cnt omnevents) else collect (if (length-restp (car (nth cnt omnevents))) (nth cnt omnevents) (* -1 (car (flatten (omn :length (nth cnt omnevents))))))))) ;; eveluate this (progn ;(setf omnseq '(s c4 mf cs4 d4 ds4 -q s e4 f4 -1 s fs4 g4 gs4 a4)) ; simple ;(setf omnseq (flatten (gen-rnd-omn 3 8 1 3 '(c4 cs4 d4 ds4 e4 f4 fs4 g4 gs4 a4) 's nil) )) ; more complex (setf omnseq (flatten (filter-first 5 (gen-rnd-omn 8 '(8 8 12 4) 2 4 '(c4 cs4 d4 ds4 e4 f4 fs4 g4 gs4 a4) 's '(p mp f) :rotate '(-1 2 0 1) :type 2)))) (setf events1 '(0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1)) ; an eventlist (setf events2 '(1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0)) ; another eventlist (setf events3 '(1 1 1 0 1 1 0 0 1 1 1 0 1 1 1 1 1 0 1 1 0 0 1 1 1 0 1 1)) ; another eventlist (setf instr1 (gen-hocket-voice events1 omnseq)) (setf instr2 (gen-hocket-voice events2 omnseq)) (setf instr3 (gen-hocket-voice events3 omnseq)) ;; check it -> if one voice then everything okay (merge-voices instr1 instr2 instr3))
August 21Aug 21 GEN-HOCKET part of OM 4.0.30098 with a stochastic approach :-);; Few bars from Webern Op.5 (setf mat '(-q -e. s f5 e e6 -s e6 - e6 e6 - - fs6 leg ds6 leg g5 gs6 leg e6 a6 leg bb5 g6 leg fs6 leg ds6 leg g5 gs6 leg e6 a6 leg bb5 g6 leg fs6 leg ds6 leg g5 leg gs6 - e6 a6 bb5 - - b5 b5 g5 - gs4d4)) ;; cmd-1 (gen-hocket 1 mat :seed 12) ;; cmd-2 (gen-hocket 4 mat :index 'v :seed 12) (gen-hocket 4 mat :density .16 :prob .7 :index 'v :seed 12) (gen-hocket 4 mat :density .25 :prob 1.0 :seed 12) (gen-hocket 4 mat :density '(.1 .8 .5 .2) :prob '(.3 .2 .5 .4) :index 'v :seed 12)
August 21Aug 21 If it weren’t exclusively stochastic, but if it were also possible to ‘filter’ the events through binary lists, then one could build interesting instrumentation matrices/trajectories (for example, using vector-envelopes that would then be mapped voice by voice into binary lists). Would that be an option?
August 21Aug 21 Yes, we could do that, let me see.What about rnd-hocket and binary-hocket function.I will see if I can make all this in one function.Or(gen-hocket 3 mat :density '((0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1) (1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0) (1 1 1 0 1 1 0 0 1 1 1 0 1 1 1 1 1 0 1 1 0 0 1 1 1 0 1 1)) :prob '(.3 .2 .5 .4))If density values are binary lists then they will be used. Without the prob you will get exactly the result you are looking for.
August 21Aug 21 Done in 4.0.30101, I had to do a few more changes then I thought, I hope you like it now.We have now two denisty modes: stochastic thinning using floating-point densities or deterministic thinning using binary masks.In stochastic mode, the number of voices equals the length of the density list (or 1 for a scalar). In binary mode, it equals the number of masks supplied. prob may be scalar or per-voice.;; stochastic (gen-hocket mat :seed 12) (gen-hocket mat :density '(.16 .5 .23 .4) :prob .7 :index 'v) (gen-hocket mat :density '(.1 .8 .5 .2) :prob '(.3 .2 .5 .4) :index 'v) ;; deterministic (gen-hocket mat :density '((0 0 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1) (1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0) (1 1 1 0 1 1 0 0 1 1 1 0 1 1 1 1 1 0 1 1 0 0 1 1 1 0 1 1)))
August 22Aug 22 Thanks. I tried some but I don't get how I would do a simple alternating hocket with 3 or more voices without complicated binary-lists that make sure that voices don't sound the same time.Would it be possible to have an option to just set the number of voices and get alternating hocketing with any number of voices ? No binary-lists for each voice needed. Possibly as a pattern list that repeats like '( 1 2) or '( 1 2 3 4 ) or '( 1 1 2 2) or '( 1 2 3 4 5 6 7 8) the numbers are the voices. Could be any symbol.Maybe I missed some in the document and it is already easily possible.
August 22Aug 22 Voice count equal the density count:(gen-hocket omn :density '(.16 .5 .23 .4)) ; 4 voices (gen-hocket omn :density '(.16 .23 .4)) ; 3 voices
August 22Aug 22 Okay, but there is no alternating. How would I use this function to alternately hocket through a omn. v1,v2,v3,v4,v1,v2,v3,v4,...... or with 8 voices or any other number. Just straight alternating.
August 23Aug 23 @erka Creating a set of binary masks for a straight-ahead circulation can be done algorithmically. For example, ChatGPT came up with this function:(defun make-voice-pattern (voices total-length) (loop for n from 0 below voices collect (let* ((padding (make-list n :initial-element 0)) (remaining (- total-length n)) (pattern (loop repeat remaining for i from 0 collect (if (= (mod i voices) 0) 1 0)))) (subseq (append padding pattern) 0 total-length))))Here's a couple different runs:(make-voice-pattern 2 5) => ((1 0 1 0 1) (0 1 0 1 0)) (make-voice-pattern 4 7) => ((1 0 0 0 1 0 0) (0 1 0 0 0 1 0) (0 0 1 0 0 0 1) (0 0 0 1 0 0 0))I haven't upgraded yet, but I'm looking forward to the new gen-hocket function.Cheers,Jon
August 23Aug 23 Thank you for your research.I didn't expect to have to use another non-library-function to achieve the simplest case of hocketing with gen-hocket, which is single note alternating over a number of voices.What about a pattern of 2 notes each. Another function to be written to generate the binaries?I can't imagine that the medieval singers thought about density or binary patterns. I am sure say agreed on ideas like: We alternate every note or each of use sings 2 notes or the first person sings 1 note , the second 2 notes the third 3 notes and the fourth person again 1 note and so on.I cannot see how that is possible with this gen-hocket function. It looks like not without other functions.That is way I suggested to add another option like :alternate or what ever it is called to specify the alternation pattern that makes really sure that no voices sound together but the whole melody is played. Maybe like '(v1 v2) or '(v1 v1 v2 v2) or '(v1 v2 v2 v3 v3 v3) or '(v 1 v2 v3). Still don't get what density has to do with hocketing. To me this was the simple idea of hocketing:(Wikipedia on hocket):In music, hocket is the rhythmic linear technique using the alternation of notes, pitches, or chords. In medieval practice of hocket, a single melody is shared between two (or occasionally more) voices such that alternately one voice sounds while the other rests. Sure, we are not in the medievals anymore.Just my ideas on it. I have a working non-library-function for this kind of simple hocketing. See above.
August 23Aug 23 density is taken from the given material which equal 100%.Material: '(q c4 d4 e4 f4 g4 a4 b4 c5)stochastic method:density 0.5 ; probable result: (-q - e4 f4 - a4 - c5)deterministic (binary) method:map (0 1 1 0 0 1 0 1) ; fixed map result: (-q d4 e4 - - a4 - c5)If you have other posibile transformation which could be usful for composition work, please make an example with the input and the output.
August 24Aug 24 Hi Janusz,that was not my question. My question was what density has to do with hocketing.Wikipedia: ".... a single melody is shared between two (or occasionally more) voices such that alternately one voice sounds while the other rests."Doc of gen-hocket: ".... a single melodic line isdivided across two or more parts so that only one part sounds at a time; the melody “jumps”between voices...."Two example what I mean:(progn (setf mat '(q c4 d4 e4 f4 g4 a4 b4 c5)) (gen-hocket mat :density '(.16 .23 .4) :index 'v :seed 601331) (setf mv (merge-voices v1 v2 v3)) (list v1 v2 v3 mv) ) ; v1 v2 v3 mv ; => ((-q - - - - - - -) (-q - - - - - - -) (q c4 mf d4 - - - - - -) (q c4 d4 -w.)) ;6 pitches missing. Voice 1 and 2 are probably sleeping (progn (setf mat '(-q -e. s f5 e e6 -s e6 - e6 e6 - - fs6 leg ds6 leg g5 gs6 leg e6 a6 leg bb5 g6 leg fs6 leg ds6 leg g5 gs6 leg e6 a6 leg bb5 g6 leg fs6 leg ds6 leg g5 leg gs6 - e6 a6 bb5 - - b5 b5 g5 - gs4d4)) (gen-hocket mat :density '(.16 .23 .4) :index 'v :seed 601331) (setf mv (merge-voices v1 v2 v3)) (setf lmat (length (omn :pitch mat))) (setf lmv (length (omn :pitch mv))) (list v1 v2 v3 mv lmv lmat) ) #| v1 (-q -e. -s -e -s - - - - - - - - - - - a6 mf leg - - - - - - - - - - - - - - - - - - - - b5 - - - -) v2 (-q -e. -s -e -s - - - - - - - ds6 mf leg g5 - - - - g6 leg - - - - - - - - - - - - - - a6 - - - - - - - -) v3 (-q -e. s f5 mf -e -s - - - - - - - - - - - - bb5 g6 leg - ds6 leg g5 - e6 a6 leg bb5 - - - - - - e6 - bb5 - - b5 b5 g5 - -) mv (-q.. s f5 -h -e s ds6 g5 -e s a6 bb5 g6 - ds6 g5 - e6 a6 bb5 -q. s e6 a6 bb5 -e s b5 b5 g5 -e) lmv 17 lmat 32 15 pitches are missing and voice 1 is probably drunk. |#My idea of hocketing is that the whole melody is performed in the end but alternating by the players.I once watched Fret Frith with 3 or 4 other guitarists hocket very fast thru a known rock song melody. So it was clear that it was not random notes. The melody was very obvious. No note missing and none added. Each player having another tone for the guitar. This was very impressive. And incredible fast. As part of the concert was quite random and noisy here it became very obvious that this guys know what they are doing. That was my idea of hocketing.When you look at the beginning of this thread the original poster asked for a sequential hocketing through a sequence. Alternating voices.As the gen-hocket was created during this discussions, my question still is how to solve this simple task at the OP asked for with gen-hocket and 3 or 4 voices.Thats all I was asking for.Hope you get the idea.Have a nice sunny Sunday.
Create an account or sign in to comment