TomTolleson Posted January 4, 2023 Share Posted January 4, 2023 Hello! I’m trying to approach a (sort of) contrapuntal composition style many know from Arvo Part as Tintinntabuli. The method is generally a tonal-based approach. I didn't see anything in the forums about it so I'm hoping this post isn't a duplicate. My understanding of it is as follows: 1. In a key, say B minor, we have a melody line that could be: (Setf pitches ‘(cs3 d3 g3 e3 fs3 b3)) This would be the M-line (melody line) Underneath we would have one or more T-lines (tintinntabuli). Each would consist only of the B minor triad. The pitch of the triad in the T-line corresponds to the pitch in the triad determined by the rule established by the composer. This can be inferior or superior. So I could have a T1 line that is comprised of the first inferior diatonic pitch the pitch in the M Line and a T2 line comprised of the second inferior diatonic pitch. So the T1 line would only consist of B, D and F#. To do this manually would be: ;; M1 Line (Setf pitches ‘(cs3 d3 g3 e3 fs3 b3)) ;; T1 Line (Setf pitches ‘(b3 b3 fs3 d3 d3 fs2)) What I’m trying to do is automate the creation of the T1 or T2 lines parametrically. Any advice on the best approach to this? Thanks! Tom Tolleson Quote Link to comment Share on other sites More sharing options...
torstenanders Posted January 4, 2023 Share Posted January 4, 2023 I once implemented a version of this in PWGL with constraint programming (rule based programming) and the help of pwgl-cluster-engine and pwgl-cluster-rules. Unfortunately, I PWGL is meanwhile broken for me, and I cannot open this patch anymore, but just in case you have used PWGL and these libraries before, I attach a patch demonstrating it. If not, then this likely will not really help you. Sorry that I cannot help more. Its about 10 years ago since I did this... Best, Torsten 04-tintinnabuli.pwgl TomTolleson 1 Quote Link to comment Share on other sites More sharing options...
JulioHerrlein Posted January 4, 2023 Share Posted January 4, 2023 Dear Tom, Maybe it would be easier if you specify what kind of "rule" you imagine to implement the sequences. After that you could imagine many different ways to put this in movement, like randomizing the notes of the lines, shuffling the lines in a more specific way. And how would be the rhythmic and texture treatment ? And the instrumentation / voice layers ? Best ! Quote Link to comment Share on other sites More sharing options...
TomTolleson Posted January 4, 2023 Author Share Posted January 4, 2023 "I once implemented a version of this in PWGL " Thanks for finding this! I do not have any of these libraries nor use PWGL but I appreciate you jumping in! 14 minutes ago, JulioHerrlein said: Dear Tom, Maybe it would be easier if you specify what kind of "rule" you imagine to implement the sequences. After that you could imagine many different ways to put this in movement, like randomizing the notes of the lines, shuffling the lines in a more specific way. And how would be the rhythmic and texture treatment ? And the instrumentation / voice layers ? Best ! Thanks, Julio! I'm imagining a melody line of pitches and a "bag" array of the diatonic pitches for that key. Based on the pitch of the m line, the algorithm would select the closest inferior pitch from the diatonic array. Likely there would be a pitch-to-integer conversion to find the smallest difference between the melody line and the pitches in the "bag." I am thinking of this in Machine Learning terms as a K-means "nearest neighbor" approach which likely won't help me in Lisp! Tom Quote Link to comment Share on other sites More sharing options...
TomTolleson Posted January 4, 2023 Author Share Posted January 4, 2023 My direction now is beginning with (setf mline '(d3 e3 d3 a3 f3 g3 c3)) (setf mlinecount (get-count mline :length :note)) (setf tline (rnd-sample mlinecount '(c3 e3 g3))) I just need to figure out how to replace the rnd-sample function with a function that finds the next lowest pitch from (c3 e3 g3), and of course I could also just create a variable out of (c3 e3 and g3) but I hope you get my point. Quote Link to comment Share on other sites More sharing options...
TomTolleson Posted January 4, 2023 Author Share Posted January 4, 2023 The find-closest could do the job but I'm having some difficulty implementing it with variables rather than integers ;; establish mline and tline (in this case just randomizing the tline) (setf mline '(d3 e3 d3 a3 f3 g3 c3)) (setf tline (rnd-sample mlinecount '(c3 e3 g3))) ;; convert pitches to integer. Both of these work properly. I'm just trying to create variables with integers to apply into the "find-closest" function. (setf mlineint (pitch-to-integer mline)) (setf tlineint (pitch-to-integer tline)) ;; The following sample of "find-closest" works properly (find-closest 5 '(6 2 8 3)) ;; the following howevfer does not (find-closest mlineint '(tlineint)) Quote Link to comment Share on other sites More sharing options...
Stephane Boussuge Posted January 5, 2023 Share Posted January 5, 2023 Hi, I've made some Tintinabuli test long time ago in Opusmodus but don't remember if it was correctly implemented or not.... Also all of this tests are broken because using a very old version of Opusmodus. I don't have time to fix them all now but I quick fixed the first one I found with actual Opusmodus correct functions. Don't know if that one is correct regarding the "rules" but may be it could help you a bit. This subject interest me as well and if I find a bit of time, I will explore it deeper this year. Best SB. ;;;--------------------------------------------------------- ;;; Parameters ;;;--------------------------------------------------------- (setf size 8) (setf bars (gen-repeat size '(4/4))) (setf pause (length-span bars '(-q))) (setf ph1.size 8) (setf bars (gen-repeat size '(4/4))) (setf pause (length-span bars '(-q))) (setf mode1 '(dorian :root d4)) (setf ph1.pitch (filter-repeat 1 (tonality-map mode1 (integer-to-pitch (vector-round 0 16 (vector-smooth 0.36 (gen-white-noise 256 :seed 772))))))) (setf ph1.len (euclidean-rhythms (gen-repeat ph1.size '(9)) '(1) '(5) :seed 93 :binary-to-length t :len-val 'e )) ;; Antécédent (setf ph1.omn (make-omn :pitch ph1.pitch :length ph1.len )) ;; Conséquent (setf ph1b.omn (ambitus '(0 16) (tonality-map mode1 (pitch-variant ph1.omn :variant 'i)))) (setf ph1 (assemble-seq ph1.omn ph1b.omn)) ;; Tintinabuli ;; V1 (setf tint1a.pitchlist '(c4 e4 g4)) (setf tint1a.pitch (rnd-sample (* ph1.size 4) tint1a.pitchlist)) (setf tint1a.len (euclidean-rhythms (gen-repeat (length ph1) '(9)) '(1) '(2) :seed 103 :binary-to-length t :len-val 'e )) (setf tint1a.omn (filter-tie (tonality-map mode1 (make-omn :pitch tint1a.pitch :length tint1a.len )))) (setf tint1a tint1a.omn) ;; V2 (setf tint1b.pitchlist '(c3 e3 g3)) (setf tint1b.pitch (rnd-sample (* ph1.size 4) tint1b.pitchlist)) (setf tint1b.len (euclidean-rhythms (gen-repeat (length ph1) '(9)) '(1) '(2) :seed 19 :binary-to-length t :len-val 'e )) (setf tint1b.omn (filter-tie (tonality-map mode1 (make-omn :pitch tint1b.pitch :length tint1b.len )))) (setf tint1b tint1b.omn) ;; V3 (setf tint1c.pitchlist '(c2 e2 g2 c3)) (setf tint1c.pitch (rnd-sample (* ph1.size 4) tint1c.pitchlist)) (setf tint1c.len (euclidean-rhythms (gen-repeat (length ph1) '(9)) '(1) '(2) :seed 17662 :binary-to-length t :len-val 'e )) (setf tint1c.omn (filter-tie (tonality-map mode1 (make-omn :pitch tint1c.pitch :length tint1c.len )))) (setf tint1c tint1c.omn) (setf soprano ph1) (setf alto tint1a) (setf tenor tint1b) (setf bass tint1c) ;;;--------------------------------------------------------- ;;; Score and Layout ;;;--------------------------------------------------------- (def-score choir-satb (:title "Title" :composer "Composer" :copyright "Copyright © " :key-signature 'chromatic :time-signature '((1 1 1 1) 4) :tempo 100 :layout (choir-satb-layout 'soprano 'alto 'tenor 'bass)) (soprano :omn soprano :channel 1 :sound 'gm :program 'choir-aahs :volume 100 :pan 16 :controllers (91 '(48)) ) (alto :omn alto :channel 2 :sound 'gm :program 'choir-aahs :volume 100 :pan 41 :controllers (91 '(48)) ) (tenor :omn tenor :channel 3 :sound 'gm :program 'choir-aahs :volume 100 :pan 86 :controllers (91 '(48)) ) (bass :omn bass :channel 4 :sound 'gm :program 'choir-aahs :volume 100 :pan 111 :controllers (91 '(48)) ) ) TomTolleson 1 Quote Link to comment Share on other sites More sharing options...
Stephane Boussuge Posted January 5, 2023 Share Posted January 5, 2023 On 1/4/2023 at 11:19 AM, torstenanders said: I once implemented a version of this in PWGL with constraint programming (rule based programming) and the help of pwgl-cluster-engine and pwgl-cluster-rules. Unfortunately, I PWGL is meanwhile broken for me, and I cannot open this patch anymore, but just in case you have used PWGL and these libraries before, I attach a patch demonstrating it. If not, then this likely will not really help you. Sorry that I cannot help more. Its about 10 years ago since I did this... Best, Torsten 04-tintinnabuli.pwgl 69.95 kB · 2 downloads Dear Torsten, about Cluster Engine, have you got some plans to implement this wonderful tool into the new Opusmodus V3 ? as well as your great others libraries like Fenv and others ? Best Stéphane Cliff and TomTolleson 1 1 Quote Link to comment Share on other sites More sharing options...
JulioHerrlein Posted January 5, 2023 Share Posted January 5, 2023 Dear Stéphane and Tom I did some edits in the Stéphane´s code. Some functions had names changed. Hope it can help. Best, Julio ;;;--------------------------------------------------------- ;;; Parameters ;;;--------------------------------------------------------- (setf size 8) (setf bars (gen-repeat size '(4/4))) (setf pause (length-span bars '(-q))) (setf ph1.size 8) (setf bars (gen-repeat size '(4/4))) (setf pause (length-span bars '(-q))) (setf mode1 '(dorian :root d4)) (setf ph1.pitch (filter-repeat 1 (tonality-map mode1 (integer-to-pitch (vector-round 0 16 (vector-smooth 0.36 (gen-white-noise 256 :seed 772))))))) (setf ph1.len (euclidean-rhythm (gen-repeat ph1.size '(9)) 1 5 1/8 :seed 93)) ; :binary-to-length t) ; :len-val 'e ; )) ;; Antécédent (setf ph1.omn (make-omn :pitch ph1.pitch :length ph1.len )) ;; Conséquent (setf ph1b.omn (ambitus '(0 16) (tonality-map mode1 (pitch-variant ph1.omn :variant 'i)))) (setf ph1 (assemble-seq ph1.omn ph1b.omn)) ;; Tintinabuli ;; V1 (setf tint1a.pitchlist '(c4 e4 g4)) (setf tint1a.pitch (rnd-sample (* ph1.size 4) tint1a.pitchlist)) (setf tint1a.len (euclidean-rhythm (gen-repeat (length ph1) '(9)) 1 2 1/8 :seed 103)) ; :binary-to-length t ; :len-val 'e ; )) (setf tint1a.omn (filter-tie (tonality-map mode1 (make-omn :pitch tint1a.pitch :length tint1a.len )))) (setf tint1a tint1a.omn) ;; V2 (setf tint1b.pitchlist '(c3 e3 g3)) (setf tint1b.pitch (rnd-sample (* ph1.size 4) tint1b.pitchlist)) (setf tint1b.len (euclidean-rhythm (gen-repeat (length ph1) '(9)) 1 2 1/8 :seed 19)) ; 1/8)) ; :binary-to-length t ; :len-val 'e ; )) (setf tint1b.omn (filter-tie (tonality-map mode1 (make-omn :pitch tint1b.pitch :length tint1b.len )))) (setf tint1b tint1b.omn) ;; V3 (setf tint1c.pitchlist '(c2 e2 g2 c3)) (setf tint1c.pitch (rnd-sample (* ph1.size 4) tint1c.pitchlist)) (setf tint1c.len (euclidean-rhythm (gen-repeat (length ph1) '(9)) 1 2 1/8 :seed 17662)) ; :binary-to-length t ; :len-val 'e ; )) (setf tint1c.omn (filter-tie (tonality-map mode1 (make-omn :pitch tint1c.pitch :length tint1c.len )))) (setf tint1c tint1c.omn) (setf v1 ph1) (setf v2 tint1a) (setf v3 tint1b) (setf v4 tint1c) ;;;--------------------------------------------------------- ;;; Score and Layout ;;;--------------------------------------------------------- (ps 'gm :sq (list (pitch-transpose 0 (ambitus 'violin v1)) (pitch-transpose 0 (ambitus 'violin v2)) (pitch-transpose 0 (ambitus 'viola v3)) (pitch-transpose 0 (ambitus 'cello v4)) ) :key-signature 'atonal :tempo 90 :flexible-clef nil :rewrite-lengths nil :accidentals :cautionary :merge-rests nil ) opmo, TomTolleson and Stephane Boussuge 3 Quote Link to comment Share on other sites More sharing options...
Stephane Boussuge Posted January 6, 2023 Share Posted January 6, 2023 Sorry, the function euclidean-rhythms was one of my personal functions. Attached, you will find the function definition file. SB. euclidean-rhythms.lisp TomTolleson and JulioHerrlein 2 Quote Link to comment Share on other sites More sharing options...
JulioHerrlein Posted January 6, 2023 Share Posted January 6, 2023 Thanks, Stéphane ! Best ! Quote Link to comment Share on other sites More sharing options...
TomTolleson Posted January 24, 2023 Author Share Posted January 24, 2023 On 1/5/2023 at 1:07 PM, JulioHerrlein said: Dear Stéphane and Tom I did some edits in the Stéphane´s code. Some functions had names changed. Hope it can help. Best, Julio This works perfectly Julio. This provides some solid building blocks. Thanks Julio and Stephane! Quote Link to comment Share on other sites More sharing options...
JulioHerrlein Posted January 24, 2023 Share Posted January 24, 2023 Thanks ! The merit goes to Stéphane ! I was just trying to help a little. Best ! Julio Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.