-- Leo's gemini proxy

-- Connecting to thrig.me:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini

Tarai


The 「tarai function」 recently came to my attention; the context was music composition, or the art of creating hopefully neither boring nor terrible sounds from the emissions of some algorithm.


    (defun tarai (x y z)
      (if (<= x y)
        y
        (tarai (tarai (- x 1) y z)
               (tarai (- y 1) z x)
               (tarai (- z 1) x y))))

Outputs


A first step may be to study the outputs for given inputs; x > y will avoid the obvious filter, and who knows what z will do. Given the subtractions we probably want positive values, and probably not values that are too large given all the recursion. Some experimentation yielded the following, which gets slow, and does not appear to produce anything interesting.


    (dotimes (n 5)
      (dotimes (m 5)
        (let* ((y 4) (x (+ y n 1)) (z (+ y x m 1)))
               (format t "~&~d,~d,~d -> ~d" x y z (tarai x y z)))))

Tools to convert streams of numbers into Lilypond or MIDI might be good to have. Some of these come from my App::MusicTools module: transpose the numbers up by 54 pitches, convert to lilypond, convert lilypond to sheet music and a MIDI file. Other translations would be possible (to chords, a particular scale, a rhythm, etc).


    $ sbcl --script tarai.lisp |
      perl -lane 'print $F[-1] + 54' |
      atonal-util pitch2ly --mode=absolute - |
      ly-fu --absolute --open -

ly-fu.K8p8TsAAz1.midi


Yeah... if something uses glorious amounts of CPU for not much if any gain, we are probably on the wrong track. Some functions work when fed sequences of integers (see Music::Voss for example) but probably not this one. Maybe you might find something to use here?


Internals


The author of the tarai function posting does not use the output of the function, but rather uses the internal x y z of each of the many recursive function calls.


    (defun tarai (x y z)
      (format t "~d ~d ~d~&" x y z) ; log what we were called with
      (if (<= x y)
        y
        (tarai (tarai (- x 1) y z)
               (tarai (- y 1) z x)
               (tarai (- z 1) x y))))
    (tarai 10 5 0)

This gives us 343,073 lines to work with. We might use the numbers as pitch values in some scale, or maybe the first number is the pitch, the second the note velocity, and the third duration? Plenty of things to experiment with here, as all sorts of mappings and modulus are possible.


A statistical look at the numbers may be worthwhile; this shows the numbers mostly stay around one though rarely will get up to 10. They could be mapped directlyl to a 12-note scale, or perhaps extreme values could be ignored, put into the next octave, or modulated into some smaller base scale. The columns have different values, which perhaps points to using only one of the columns, or to utilize a unique mapping for each column.


    $ r-fu summary < tarai.10.5.0.txt
    elements 1029219 mean 1.330 range 11.000 min -1.000 max 10.000 sd 1.553

      0%  25%  50%  75% 100%
      -1    0    1    2   10

    $ r-fu colsumm - x y z < tarai.10.5.0.txt
                         x             y             z
    Count   343073.0000000 343073.000000 343073.000000
    Range       11.0000000     10.000000     10.000000
    Mean         0.6855363      1.628414      1.675594
    Sdev         1.5179802      1.533457      1.399214
    Min.        -1.0000000      0.000000      0.000000
    1st Qu.      0.0000000      0.000000      0.000000
    Median       0.0000000      1.000000      2.000000
    3rd Qu.      2.0000000      3.000000      3.000000
    Max.        10.0000000     10.000000     10.000000

Converting the first column (x) pitches to Dorian mostly results in a stepwise descent and some leaps. Nothing really too interesting. More experimentation here might turn up something usable. The original post used arpeggio which probably adds interest and may hide a weaker harmonic or melodic line.


    (define-condition list-full (error) ())
    (defconstant +maxn+ 64)
    (defparameter *nn* nil)
    (defparameter *mm* '((-1 . "b") (0 . "c'") (1 . "d'") (2 . "e'")
                         (3 . "f'") (4 . "g'") (5 . "a'") (6 . "b'")
                         (7 . "c''") (8 . "d''") (9 . "e''") (10 . "f''")))
    (defun tarai (x y z)
      (push x *nn*) ; (push y *nn*) (push z *nn*)
      (when (>= (length *nn*) +maxn+) (error 'list-full))
      (if (<= x y) y (tarai (tarai (- x 1) y z) (tarai (- y 1) z x)
                            (tarai (- z 1) x y))))
    (handler-case
        (tarai 10 5 0)
      (list-full ()
        (dolist (n (nreverse *nn*))
          (format t "~d~&" (cdr (assoc n *mm*))))))

ly-fu.M38JMsBAiD.midi


By way of:


    $ sbcl --script tarai.lisp | ly-fu --absolute --open -

See Also


Random code I've thrown together to wrangle music or numbers with. Probably needs a rewrite. Proably will not be rewritten.


https://metacpan.org/pod/App::MusicTools

https://metacpan.org/pod/Music::Voss

https://thrig.me/src/r-fu.git


tags #lisp #music

-- Response ended

-- Page fetched on Tue May 21 12:19:16 2024