Jump to content

Developing Utility Functions


Recommended Posts

Kicking off a few topic areas that might be useful for collecting together some related methods for building up these threads. I think it will be helpful to have things in easily searchable form under threads as far as possible. Happy for other suggestions though.

 

One thing that I have found especially helpful for quick working with LISP code so that I can focus on creative ideas rather than technical issues, is to develop a series of utility functions that I can employ for very frequently used tasks when writing scripts.

 

The idea for this comes from Paul Graham's book 'On Lisp' (bit of a classic text - highly recommended!) in which he presents the idea that working in CL effectively it's important to condense longer routines into short functions. I use this a lot. Some ways that I have found this useful:

 

Library indexing - when creating a Library, I always create an index section that I can then pull using a function of form

(index library) - so that I don't have to remember every individual library reference but can just pull them into the Listener when setting up variables with the data from my Libraries

 

Auditioning options - I have a function that changes the port/channel for any snippet auditioning of form (audition port channel) so that when working with my MIDI set up I can easily flip back and forth.

 

Unfold Set and other function condensing - I have a short unfold-set function of form (UF 'method) that is really useful for quickly inserting methods into PS scripts when trying out ideas.  This basically just takes the full version of the unfold function but compresses the other arguments, saving typing everything out. Lazy but effective. Likewise, I have these sort of utility functions for my most used functions that either have long names and/or multiple arguments - and argument order is maintained without having to remember the differences between functions. As I said, I like to keep typing to a minimum!

 

I find this a really efficient way of working.

 

bw

 

Andrew

 

 

Link to comment
Share on other sites

 I use libraries a lot: I got into the habit when working in SuperCollider, as SC dictionaries are so flexible for storing vast amounts of data that you can pull into working code really quickly and so I basically transferred that way of working into developing OM/CL libraries pretty much from the start.  The majority of my OMN content is in some library or other. I have a compulsion to build them over time, ever expanding them -- and I love having archives of different material to draw on -  so this keeps staying on top of what is in them a major task. Indexing is therefore essential to working with them easily without having to keep going into each library to look inside it.

 

Here's a simple example. At the start of any library, I create a named index section. This one's a good example of one that is quite complex, as the library has a lot of sections with varying amounts of data in each section. The index is then pulled using a function.

 

This library is one that I've been building for a while, stores various plainchant resources from the Liber Usualis - so the whole library is preceded by the index section:

(def-library liber-usualis
    (:section index
     n1  '(modes-C m1 m8)
     n2  '(modes-finals m1 m8)
     n3  '(modes-tenors-finals m1 m8)
     n4  '(modes-tenors m1 m8)
     n5  '(schemes s1 s4)
     
     n6  '(kyries 
                 clemens-rector 
                 summe-deus 
                 rector-cosmi-pie 
                 kyrie-altissime 
                 conditur-kyrie-omnium 
                 te-christe-rex-supplices 
                 splendor-aeterne 
                 firmator-sancte 
                 o-pater-excelse 
                 orbis-factor 
                 kyrie-salve
                 lux-et-origo
                 kyrie-fons-bonitatis
                 kyrie-deus-sempiterne
                 cunctipotens-genitor-deus
                 kyrie-magnae-deus-potentiae)

     n7   '(antiphons
                 andreas-christi-famulus
                 salve-regina
                 alma-redemptoris
                 ave-regina
                 regina-caeli
                 o-antiphons)

     n8    '(alleluias
                 alleluia-1
                 modus-cantandi-ad-communionem
                 modus-cantandi-ad-introitum
                 modus-cantandi-ad-offertorium)

     n9    '(misc
                 absolve-domine
                 exitu-israel-de-aegypto
                 domine-jesu-christe
                 haec-dies
                 hodie-christus-natus-est
                 lux-aeterna
                 pange-lingua
                 pascha-nostrum
                 puer-natus
                 te-deum-simplex
                 te-deum-solemnis
                 veni-creator-spiritus
                 victimae-paschal-laudes))

 

My function is:

 

(defun lind (lib)
  (pprint (library lib 'index 'nil :collect :all)))

 

and I just do the index listing by calling (lind 'library-name) - so it works on any library as long as you have those library names available.

 

It works a treat when building OMN forms in scripts. I can't possibly remember all of the various names of each section and each entry, but this functions just pulls them all into the Listener to drop into calls to Library.

 

bw 

 

Andrew
                           

Link to comment
Share on other sites

Yes, I think this is an illuminating concept.  It seems to me, without working with this idea yet, that one could use this to organize the materials of a given composition - the sketches - and then use the library as a means to try out various combinations and amalgams.  Am I on the right track with this approach?  What I like about coding this way is that it is specific to a methodology.  I find this helpful as a composition can often be the outworking of a specific and unique method - as distinct from a general composers "method" or voice.

Link to comment
Share on other sites

Exactly. I build libraries of existing material as archives to draw on but also build libraries of materials I generate myself so I have libraries of working material, just as you suggest. One use for this is to store results of using specific algorithms, particularly with randomness, where I like the results but not sure initially what to do with the output yet. I store in a library of similar materials to come back to. Adding useful names and indexing to them means I always have a way of easily accessing when I want to use that material at another stage. Great trial-and-error/GAT working.

 

Further, I may use one library of stored material, pull it into algorithms I'm working with, then store the results in another library, categorised, then later do the same with that newer material and so on. Layers of material from different working sessions all stored and accessible via indexing. You could have a library just for a composition in progress or others linked to specific algorithms or others as broader pools of working material. I find this approach congenial to the way I like to work and it also helps to keep code files tidier.

 

Effectively, these libraries are like well organised sketchbooks in different stages of development. 

Link to comment
Share on other sites

Very helpful, Andrew! I am even more curious about this.  Is there a way to look over your shoulder and learn a bit more about how you are doing this organizational work?  It would help me improve my "efficiency quotient."

Perhaps a "use" example?

Link to comment
Share on other sites

  • 2 weeks later...

Difficult to give easy to follow example in single posts but here's a straightforward example that can be applied in multiple ways to working quickly to store results of working sessions. This varies the typical use case of the create-library function, where the results of evaluated functions are stored (and this certainly works well for many cases where I want to store output of various algorithms I'm trying.) However, my usual situation is to get a series of results that I like the sound of and then want to come back to later and move onto another variation with the given function/algorithm. I found that unless being very careful with setting seeds, I'd repeatedly lose the outputs I liked as many of the processes I'm enjoying working with use a lot of randomness.  This means I can file away results I like, move on, then return later to work further with the outputs. It's quick and painless to set up - and I usually have this sort of template code alongside the ps function I'm playing with at the time (below for an example.)

 

A basic way I've found very quick and easy to simply store results into a library for return to later is to do this:

 

(create-library 'library-name 'section-name 'entry-identifier
                (list 
                (eval 'variable)
                (eval 'variable)
                (eval 'variable)
                (eval 'variable)
                (eval 'variable)
                (eval 'variable)
                (eval 'variable))
                :file "library file name"

                :note "session 3 information and reminders"

)

 

where 'variable is a given OMN form output from an algorithm. This just dumps the content of each variable - usually an OMN form - into a library entry with everything labelled and set up to then pull out again later. I usually use the variable name as the entry-identifier so that I can more easily pull the library entries back into any code I'm working on. Obviously, with particular large libraries, useful to set up an index too.

 

I usually do this by throwing them into a ps function to tease out various combinations of them, for example - here's one that I've recently been playing around with. FYI, the (uf 'method variable) function is one of my utility functions to condense the unfold function to use more easily - so it's basically just (unfold 'unfold-set 'method 'variable) in short form:

 

(ps 'r-ens

 

:sf-fl (list (uf 'fl (assemble-seq 
9-pause 9-pause (uf 'r gendyn1) (uf 'i gendyn3) (uf 'ri gendyn2) s-pause (subseq gendyn1 0 18) 9-pause))
:cc '(1 (gen-dynamic-controller gendyn1) 21 (gen-dynamic-controller gendyn1)))

 

:sf-cl (list (uf 'cl (uf 't-12 (assemble-seq 
3-pause (uf 't-12 (subseq gendyn1 0 18)) (uf 'r gendyn4) 9-pause (uf 'rop gendyn3) s-pause (subseq gendyn1 0 18) gendyn1)))
:cc '(1 (gen-dynamic-controller gendyn4) 21 (gen-dynamic-controller gendyn4)))

 

:sf-ob (list (uf 'ob (uf 't-24 (assemble-seq 
9-pause gendyn3 (uf 'r gendyn2) 9-pause (uf 'rop gendyn4) s-pause (subseq gendyn3 0 18) gendyn2))) 
:cc '(1 (gen-dynamic-controller gendyn3) 21 (gen-dynamic-controller gendyn3)))

 

:sf-bn (list (uf 'bn (uf 't-24 (assemble-seq 
(uf 'r gendyn2) gendyn2 (uf 'r gendyn3) (uf 'i gendyn1) (uf 'rop gendyn1) s-pause (subseq gendyn2 0 18) gendyn3))) 
:cc '(1 (gen-dynamic-controller gendyn2) 21 (gen-dynamic-controller gendyn2)))

 

:plate-bells (list (ambitus '(bb2 d5) (assemble-seq 
9-pause 9-pause 9-pause (uf 't12 gen-1a) (uf 't12 (uf 'r (uf 'rop gen-1a))))))

 

:crotales (list (ambitus '(b4 f7) (assemble-seq
9-pause 9-pause 9-pause 9-pause (uf '(t12 rop) gen-1a))))

 

:time-signature '(3 2)
:tempo 80)

 

Basically, each of those 'gendyn' variables and all the various transformations can just be dumped into a library via the list evaluations sent to create-library and then recalled later by pulling them back into another ps or def-score using calls to library.  I probably do most of this in a non-standard OM way as I know that def-score is usual approach but prefer sketching like this using ps rather than having to set up def-scores which require more faffing to make even small changes on the fly. Once I have results I want to keep, I use :output :score in the ps to create the def-score I want to develop further.

 

I have some other examples of working with algorithms directly and storing in libraries but these are more tricky to summarise in a post but closely mirror the use of create-library given in the function help document. Will look to find some examples. I'm off for a few days away in Scotland and Northumberland and the laptop is not coming (!) but will see what I can put together when I get back.

 

bw 

 

Andrew

 

 

Link to comment
Share on other sites

Further to this - here's the specific code from that ps function then dumped to a library using that create-library template:

 

(create-library 'genner-iso-winds-whole 'melodic 'line


                (list 

                (eval 'gen-1a)
                (eval 'gendyn1)
                (eval 'gendyn2)
                (eval 'gendyn3)
                (eval 'gendyn4)
                (eval '9-pause)
                (eval '8-pause)
                (eval '3-pause)

 

                (eval '(uf 'fl (assemble-seq  9-pause 9-pause (uf 'r gendyn1) (uf 'i gendyn3) (uf 'ri gendyn2) 3-pause 
                                             (subseq gendyn1 0 18) 9-pause)))

 

                (eval '(uf 'cl (uf 't-12 (assemble-seq 3-pause (uf 't-12 (subseq gendyn1 0 18)) (uf 'r gendyn4) 9-pause 
                                             (uf 'rop gendyn3) 3-pause (subseq gendyn1 0 18) gendyn1))))
            
                (eval '(uf 'ob (uf 't-24 (assemble-seq  9-pause gendyn3 (uf 'r gendyn2) 9-pause (uf 'rop gendyn4) 3-pause 
                                             (subseq gendyn3 0 18) gendyn2))))

 

                (eval '(uf 'bn (uf 't-24 (assemble-seq  (uf 'r gendyn2) gendyn2 (uf 'r gendyn3) (uf 'i gendyn1) 
                                              (uf 'rop gendyn1) 3-pause (subseq gendyn2 0 18) gendyn3))))

 

                (eval '(ambitus '(bb2 d5) (assemble-seq 9-pause 9-pause 9-pause (uf 't12 gen-1a) 
                                              (uf 't12 (uf 'r (uf 'rop gen-1a)))))))

 

                :file "genner-iso-winds-whole"
                :note "all transformed sequences")

 

This library then holds all the individual OMN forms as initial variables and the specific transformations applied in the ps using assemble-seq and various unfold set calls. This works surprisingly well: it's quick and doesn't get in the way when working iteratively with material. Using the :note to give precise information can help with indexing later.

 

Andrew

Link to comment
Share on other sites

  • 2 weeks later...

Without knowing the values:

  (eval 'gen-1a)
                (eval 'gendyn1)
                (eval 'gendyn2)
                (eval 'gendyn3)
                (eval 'gendyn4)
                (eval '9-pause)
                (eval '8-pause)
                (eval '3-pause)

etc...

I can't comment.

Link to comment
Share on other sites

The content of those variables are just lists of standard OMN forms, of type:

 

'((e c4 mp stacc d4 mf marc g4 f stacc)(w c5 p ten)) etc...

 

To drop LISP forms into a Library using create-library, reference in the documentation shows evaluation of functions being used to easily set-up a library with the results of evaluation of those functions. To do this with quoted lists, it appears that one needs to evaluate them in the same way so they populate the new library because the lists are not the output of a function used within create-library as in the documentation but they are results of various transformations done iteratively previously. This create-library stage comes at the end of a series of transformations of material. I do use this function-driven method as well as in the standard use shown in the documentation, but also want to be able to simply store lists of OMN forms into libraries for future use without having to do it all manually each time. create-library is a really useful function!

 

I'm aware that direct use of eval is not very efficient in CL and that in other similar situations 'apply' might be better, but it doesn't work in this use case and as it's only a one-off use of eval used only when setting up the library initially and not used again for that set of data, I can live with it if it does what I need to do. There may be a better way of doing this though, but I can't see other options, as create-library looks like it needs the evaluation to correctly populate, hence my use of eval.

 

I think that it would be useful to have some extended Library functions in the OM system along the lines of what is available for unfold-sets and instrument-sets but not sure how complex this is to do, but what I love about OM is how easy it is to design and build things for one's own purposes. 

 

bw

 

Andrew

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

Terms of Use Privacy Policy