sc/utilities [ Modules ]

[ Top ] [ Modules ]

NAME

 utilities

 File:             utilities.lsp

 Class Hierarchy:  none: no classes defined

 Version:          1.0.7

 Project:          slippery chicken (algorithmic composition)

 Purpose:          Various helper functions of a general nature.

 Author:           Michael Edwards: m@michael-edwards.org

 Creation date:    June 24th 2002

 $$ Last modified: 16:32:39 Sun Jun 19 2016 WEST

 SVN ID: $Id: utilities.lsp 5891 2016-07-02 09:11:42Z medward2 $

utilities/a-weighting [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Implementation of A-weighting loudness compensation.  Formula taken from
 http://en.wikipedia.org/wiki/A-weighting.  This doesn't take 1000Hz
 loudness into account, rather it implements the 40-phon Fletcher-Munson
 curve only.

ARGUMENTS

 The frequency in Hertz for which to find the loudness weighting.

OPTIONAL ARGUMENTS

 keyword aguments:
 - :expt. A power (exponent) to raise the result to in order to
    tame/exaggerate the curve (make the db weightings less/more
    extreme). This only really makes sense if :linear t though will work
    with db values also of course.  Values < 1 result in linear values
    closer to 1 (less extreme).  Values > 1 are further from 1. Default = NIL
    i.e. no exponential function.
 - :linear.  If T return amplitude values as linear scalers rather than
    logarithmic decibel values.  NB If this is NIL then returned values are
    likely to be negative (db) values.  Default = T.  
 - :invert.  As the weighting routine tries to tell us what relative
    loudness we'll perceive given constant amplitudes, low and high
    frequencies will return negative values as we perceive them Xdb less
    than our most sensitive frequency area.  If :invert t, just flip this
    negatives to positives so that if :linear T you get a scaler to make
    lower/higher frequences equally loud as the most sensitive frequencies.

RETURN VALUE

 The linear or db weighting value for the given frequency.

EXAMPLE

;;; Decibels:
(a-weighting 50 :invert nil :linear nil) => -30.274979
(a-weighting 50 :invert t :linear nil) => 30.274979
;;; Linear amplitude scalers:
(a-weighting 50) => 32.639904
(a-weighting 50 :invert nil) => 0.030637344
;;; Exaggeration:
(a-weighting 50 :expt 1.1) => 46.251286
;;; Smoothing:
(a-weighting 50 :expt .5) => 5.7131343

;;; Looping through the MIDI note range by tritones returning decibel values:
(loop for midi from 0 to 127 by 6
     for freq = (midi-to-freq midi)
     collect (list (midi-to-note midi)
                   (a-weighting freq :linear nil :invert nil)))
=>
((C-1 -76.85258) (FS-1 -65.94491) (C0 -55.819363) (FS0 -46.71565)
 (C1 -38.714867) (FS1 -31.724197) (C2 -25.598646) (FS2 -20.247103)
 (C3 -15.622625) (FS3 -11.657975) (C4 -8.258142) (FS4 -5.358156)
 (C5 -2.9644737) (FS5 -1.1277018) (C6 0.13445985) (FS6 0.8842882) (C7 1.226917)
 (FS7 1.2351798) (C8 0.89729404) (FS8 0.09495151) (C9 -1.3861179)
 (FS9 -3.7814288))

;;; Similar but returning linear amplitude scalers:
(loop for midi from 0 to 127 by 6
     for freq = (midi-to-freq midi)
     collect (list (midi-to-note midi) (a-weighting freq)))
=>
((C-1 6960.316) (FS-1 1982.6475) (C0 617.9711) (FS0 216.6619) (C1 86.246864)
 (FS1 38.56647) (C2 19.051636) (FS2 10.288571) (C3 6.041312) (FS3 3.827355)
 (C4 2.5876594) (FS4 1.8531382) (C5 1.4067719) (FS5 1.1386365) (C6 0.9846389)
 (FS6 0.9032034) (C7 0.8682687) (FS7 0.86744314) (C8 0.9018521) (FS8 0.9891278)
 (C9 1.1730213) (FS9 1.5455086))

SYNOPSIS

(defun a-weighting (f &key expt (linear t) (invert t))

utilities/all-members [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Find out whether the members of the list given as the second argument are
 all present in the list given as the first argument.

ARGUMENTS

 - A list in which the members of the second argument will be sought. 
 - A list whose members will be sought in the first argument.
 
 OPTIONAL ARGUMENT
 - A comparison function.

RETURN VALUE

 T or NIL.

EXAMPLE

(all-members '(1 2 3 4 5 6 7) '(1 2 3 7))

=> T

SYNOPSIS

(defun all-members (list test-list &optional (test #'equal))

utilities/almost-flatten [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DATE

 September 4th 2013

DESCRIPTION

 Similar to flatten but allows one level of nesting

ARGUMENTS

 A list with an arbitrary level of nesting.

RETURN VALUE

 A list with a maximum of one level of nesting

EXAMPLE

(almost-flatten '((1 (2 3 4) (5 (6 7) (8 9 10 (11) 12)) 13) 14 15 (16 17)))

SYNOPSIS

(defun almost-flatten (nested-list)

utilities/almost-zero [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Return T if a given decimal is within 0.000001 of 0.0.

ARGUMENTS

 - A number.

OPTIONAL ARGUMENTS

 - A number that is a user-specified difference for the comparison test. 

RETURN VALUE

 T if the number is within the tolerance difference to zero, otherwise NIL. 

EXAMPLE

(almost-zero 0.0000007)

=> T

SYNOPSIS

(defun almost-zero (num &optional (tolerance 0.000001))

utilities/amp2db [ Methods ]

[ Top ] [ utilities ] [ Methods ]

DESCRIPTION

 Convert a standard digital amplitude value (>0.0 to 1.0) to a corresponding
 decibel value.

ARGUMENTS

 - A decimal number between >0.0 and 1.0.

RETURN VALUE

 A decimal number that is a value in decibel.

EXAMPLE

(amp2db 0.3)

=> -10.457575

SYNOPSIS

(defmacro amp2db (amp)

utilities/amplitude-to-dynamic [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Convert a specified digital amplitude between 0.0 and 1.0 to a
 corresponding dynamic between niente and ffff.

ARGUMENTS

 - A decimal number between 0.0 and 1.0.

OPTIONAL ARGUMENTS

 - T or NIL to indicate whether to print a warning if the specified
   amplitude is <0.0 or >1.0. T = warn. Default = T.

RETURN VALUE

 A symbol that is a dynamic level.

EXAMPLE

(amplitude-to-dynamic 0.3)

=> PP

SYNOPSIS

(defun amplitude-to-dynamic (amp &optional (warn t))

utilities/auto-scale-env [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DATE

 August 29th 2013

DESCRIPTION

 Automatically scale both the x and y values of an envelope to fit within
 the given ranges. Normally we'll assume that the minimum and maximum Y
 values are present in the original envelope and so the automatically scaled
 envelope will represent these with the new minimum and maximum
 values. However sometimes an envelope doesn't range over the possible
 extremes, for example (0 .3 100 .6) where the y range is from 0 to 1. If
 this is the case and you need a scaled envelope to take this into account,
 then how is the original envelopes minimum and maximum values to the
 keyword argument :orig-y-range.

ARGUMENTS

 - The envelope: a list of x y pairs

OPTIONAL ARGUMENTS

 keyword arguments:
 - :x-min: The new minimum (starting) x value
 - :x-max: The new maximum (last) x value
 - :y-min: The new minimum (not necessarily starting!) y value
 - :y-max: The new maximum (not necessarily starting!) y value
 - :orig-y-range: a two-element list specifying the original envelope's
   minimum and maximum values (see above).

RETURN VALUE

 The new envelope (list).

EXAMPLE

(auto-scale-env '(0 0 10 1))
=>
(0.0 0.0 100.0 10.0)

(auto-scale-env '(-1 0 .3 -3 1 1) :y-min 5 :y-max 6 :x-min 2)
=>
(2.0 5.75 65.7 5.0 100.0 6.0))

(auto-scale-env '(0 1 5 1.5 7 0 10 1) :y-min -15 :y-max -4)
=>
(0.0 -7.6666665 50.0 -4.0 70.0 -15.0 100.0 -7.6666665))

(auto-scale-env '(0 .5 100 .5) :y-min 1 :y-max 2)
=> (0.0 1.0 100.0 1.0)

(auto-scale-env '(0 .5 100 .5) :y-min 1 :y-max 2 :orig-y-range '(0 1))
=> (0.0 1.5 100.0 1.5)

SYNOPSIS

(defun auto-scale-env (env &key
                             (x-min 0.0) (x-max 100.0)
                             (y-min 0.0) (y-max 10.0)
                             orig-y-range)

utilities/between [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Return a random number between two specified numbers. If the two numbers
 are integers, the random selection is inclusive. If either are floating-point
 (decimal) numbers, the result will be a float between the first (inclusive)
 and just less than the second (i.e. exclusive).

ARGUMENTS

 - A first, lower, number.
 - A second, higher, number. 

 NB: The first number must always be lower than the second.

OPTIONAL ARGUMENTS

 - T or NIL to indicate whether the random seed should be fixed.
 - T or NIL to indicate whether, when fixed-random is set to T, we should
   reset the random number generator (to guarantee the same random
   sequences). This would generally only be called once, perhaps at the
   start of a generation procedure.

RETURN VALUE

 An integer if both numbers are integers, or a float if one or both are
 decimal numbers.

EXAMPLE

;;; Using the defaults. This will produce a different result each time.
(loop repeat 10 collect (between 1 100))

=> (43 63 26 47 28 2 99 93 66 23)

;;; Setting fixed-random to T and using zerop to reset the random when i is 0 
(loop repeat 5 
   collect (loop for i from 0 to 9 collect (between 1 100 t (zerop i))))

=> ((93 2 38 81 43 19 70 18 44 26) (93 2 38 81 43 19 70 18 44 26)
    (93 2 38 81 43 19 70 18 44 26) (93 2 38 81 43 19 70 18 44 26)
    (93 2 38 81 43 19 70 18 44 26))

SYNOPSIS

(defun between (low high &optional fixed-random restart)

utilities/between-extremes [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DATE

 April 23rd 2016, Edinburgh

DESCRIPTION

 Given a <progress> value of between 0 and 1, we'll return whatever that
 proportion is of the difference between <min> and <max> added to min. NB No
 randomness here.

ARGUMENTS

 - the minimum value (returned when <progress> is 0.0)
 - the maximum value (returned when <progress> is 1.0)
 - a value between 

RETURN VALUE

 a number between min and max

EXAMPLE

(BETWEEN-EXTREMES 0.5 1 .5)
==> 0.75
(BETWEEN-EXTREMES 0.5 1 .9)
==> 0.95

SYNOPSIS

(defun between-extremes (min max progress)

utilities/combine-into-symbol [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Combine a sequence of elements of any combination of type string, number,
 or symbol into a symbol.

ARGUMENTS

 - A sequence of elements.

RETURN VALUE

 A symbol as the primary value, with the length of that symbol as a
 secondary value.

EXAMPLE

(combine-into-symbol "test" 1 'a)

=> TEST1A, 6

SYNOPSIS

(defun combine-into-symbol (&rest params)

utilities/db2amp [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Convert a decibel value to a standard digital amplitude value (>0.0 to 1.0),
 whereby 0dB = 1.0.

ARGUMENTS

 - A number that is a value in decibel.

RETURN VALUE

 A decimal number between >0.0 and 1.0.

EXAMPLE

(db2amp -3)

=> 0.70794576

SYNOPSIS

(defmacro db2amp (db)

utilities/decimal-places [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DATE

 19-Mar-2012

DESCRIPTION

 Round the given number to the specified number of decimal places.

ARGUMENTS

 - A number.
 - An integer that is the number of decimal places to which to round the
   given number.

RETURN VALUE

 A decimal number.

EXAMPLE

(decimal-places 1.1478349092347 2)

=> 1.15

SYNOPSIS

(defun decimal-places (num places)

utilities/decimate-env [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Reduce the number of x,y pairs in an envelope.  In every case the envelope
 is first stretched along the x-axis to fit the new number of points
 required.  Then we proceed by one of three methods:
 
 1) average: for every new output x value, interpolate 100 times from -0.5
 to +0.5 around the point, then average the y value.  This will catch
 clustering but round out spikes caused by them
 
 2) points: also an averaging method but only using the existing points in
 the original envelope (unless none is present for a new x value, whereupon
 interpolation is used): Take an average of the (several) points nearest the
 new output point. This might not recreate the extremes of the original
 envelope but clustering is captured, albeit averaged.
 
 3) interpolate: for each new output point, interpolate the new y value from
 the original envelope.  This will leave out details in the case of
 clustering, but accurately catch peaks if there are enough output points.
 
 In each case we create an even spread of x values, rather than clustering
 where clusters exist in the original.

ARGUMENTS

 - the original envelope (list of x,y values on any scales).
 - the number of points required in the output list.

OPTIONAL ARGUMENTS

 - the method to be applied (symbol): 'points, 'average, 'interpolate.
   Default = 'points.

RETURN VALUE

 A list representing the x,y values of the new envelope

EXAMPLE

(decimate-env '(0 0 4 4 5 5 5.1 5.1 5.3 1 5.6 5.6 6 6 10 10) 6)
=>
(0.0 0.0 1 2.0 2 4.5 3 4.425 4 8.0 5.0 10.0)

SYNOPSIS

(defun decimate-env (env num-points &optional (method 'points))

utilities/down-up [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DATE

DESCRIPTION

ARGUMENTS

OPTIONAL ARGUMENTS

RETURN VALUE

EXAMPLE

SYNOPSIS

(defun down-up (steps &key (down t) (up t) (start 1.0d0) (target 0.0d0)
                        (cons nil) (butlast t))

utilities/dynamic-to-amplitude [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Convert a symbol that is a dynamic level between niente and ffff to a
 corresponding digital amplitude value between 0.0 and 1.0.

ARGUMENTS

 - A symbol that is a dynamic level between niente and fff.

OPTIONAL ARGUMENTS

 - T or NIL to indicate whether to print a warning when the symbol specified
   is not recognized as a dynamic. T = warn. Default = T.

RETURN VALUE

 A decimal number between 0.0 and 1.0.

EXAMPLE

(dynamic-to-amplitude 'fff)

=> 0.9

SYNOPSIS

(defun dynamic-to-amplitude (dynamic &optional (warn t))

utilities/econs [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Add a specified element to the end of an existing list.

ARGUMENTS

 - A list.
 - An element to add to the end of the list.

RETURN VALUE

 A new list.

EXAMPLE

(econs '(1 2 3 4) 5)

=>  '(1 2 3 4 5)

SYNOPSIS

(defun econs (list new-back)

utilities/env-plus [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Increase all y values of a given list of break-point pairs by a specified
 amount.

ARGUMENTS

 - An envelope in the form of a list of break-point pairs.
 - A number that is the amount by which all y values of the given envelope
   are to be increased.

RETURN VALUE

 A list of break-point pairs.

EXAMPLE

(env-plus '(0 0 25 11 50 13 75 19 100 23) 7.1)

=> (0 7.1 25 18.1 50 20.1 75 26.1 100 30.1)

SYNOPSIS

(defun env-plus (env add)

utilities/env-symmetrical [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Create a new list of break-point pairs that is symmetrical to the original
 around a specified center. If no center is specified, the center value
 defaults to 0.5

ARGUMENTS

 - An envelope in the form of a list of break-point pairs.

OPTIONAL ARGUMENTS

 - A number that is the center value around which the values of the
   new list are to be symmetrical.
 - A number that is to be the minimum value for the y values returned.
 - A number that is to be the maximum value for the y values returned.

RETURN VALUE

 An envelope in the form of a list of break-point pairs.

EXAMPLE

;;; Default center is 0.5
(env-symmetrical '(0 0 25 11 50 13 75 19 100 23))

=> (0 1.0 25 -10.0 50 -12.0 75 -18.0 100 -22.0)

;; Specifying a center of 0
(env-symmetrical '(0 0 25 11 50 13 75 19 100 23) 0)

=> (0 0.0 25 -11.0 50 -13.0 75 -19.0 100 -23.0)

;;; Specifying minimum and maximum y values for the envelope returned
(env-symmetrical '(0 0 25 11 50 13 75 19 100 23) 0 -20 -7)

=> (0 -7 25 -11.0 50 -13.0 75 -19.0 100 -20)

SYNOPSIS

(defun env-symmetrical (env &optional (centre .5) 
                        (min most-negative-double-float)
                        (max most-positive-double-float))

utilities/env2gnuplot [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DATE

 24th December 2013

DESCRIPTION

 Write a data file of x,y envelope values for use with gnuplit.  Once called
 start gnuplot and issue commands such as:
 gnuplot> set terminal postscript default
 gnuplot> set output '/tmp/env.ps'
 gnuplot> plot '/tmp/env.txt' with lines.

ARGUMENTS

 - The envelope as the usual list of x y pairs

OPTIONAL ARGUMENTS

 - The pathname of the data file to write.  Default = "/tmp/env.txt".

RETURN VALUE

 Always T

SYNOPSIS

(defun env2gnuplot (env &optional (file "/tmp/env.txt"))

utilities/envelope-boundaries [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Find sharp changes in envelope values. These are defined as when a y value
 rises or falls over 30% (by default) of it's overall range within 5%
 (again, by default) of its overall x axis range.

ARGUMENTS

 The envelope (a list of x y pairs).

OPTIONAL ARGUMENTS

 - jump-threshold: the minimum percentage change in y value that is deemed a
   sharp change. 
 - steepness-min: the maximum percentage of the overall x axis that
   constitutes a 'quick' change.

RETURN VALUE

 A list of x values at which boundaries are deemed to lie.

EXAMPLE

(ENVELOPE-BOUNDARIES '(0 10 20 10 21 3 25 4 26 9 50 7 51 1 55 2 56 7 70 10
                     100 10))
--> (21 26 51 56)

SYNOPSIS

(defun envelope-boundaries (envelope &optional (jump-threshold 30)
                            (steepness-min 5))

utilities/equal-within-tolerance [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Test whether the difference between two decimal numbers falls within a
 specified tolerance.

 This test is designed to compensate for calculation discrepancies caused by
 floating-point errors (such as 2.0 vs. 1.9999997), in which the equations
 should yield equal numbers. It is intended to be used in place of = in such
 circumstances.

ARGUMENTS

 - A first number.
 - A second number.

OPTIONAL ARGUMENTS

 - A decimal value that is the maximum difference allowed between the two
   numbers that will still return T. Default = 0.000001d0.

RETURN VALUE

 T if the two tested numbers are equal within the specified tolerance,
 otherwise NIL.

EXAMPLE

;; An example of floating-point error
(loop for i from 0.0 below 1.1 by 0.1 collect i)

=> (0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.70000005 0.8000001 0.9000001 1.0000001) 

;; Using =
(loop for i from 0.0 below 1.1 by 0.1 
   for j in '(0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0)
   collect (= i j))

=> (T T T T T T T NIL NIL NIL NIL)

;; Using equal-within-tolerance
(loop for i from 0.0 below 1.1 by 0.1 
   for j in '(0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0)
   collect (equal-within-tolerance i j))

=> (T T T T T T T T T T T)

SYNOPSIS

(defun equal-within-tolerance (a b &optional (tolerance 0.000001d0))

utilities/exaggerate-env [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Makes the y values in an envelope more radically pushed towards its
 extremes. Y values below the mid-point will be pushed downwards; those
 above will be pushed upwards. The opposite can be accomplished by making
 the exponent argument > 1 (see below).

ARGUMENTS

 - the envelope: a list of numbers representing an envelope: x y pairs
 - the exponent: this determines the amount of
   exaggeration. Counterintuitively perhaps, the lower values are than 1 the
   more exaggeration takes place. Values > 1 will mean the opposite:
   understated y values, if you will.

OPTIONAL ARGUMENTS

 - easy-expt: because of the counterintuitive nature of the exponent, you
   can pass values between -10 and +10 if this third argument is T. This
   will be scaled to useful though not over-extreme exponents of 1.9 (-10)
   to .1 (+10) with 0 equating to an exponent of 1, i.e. no change.

RETURN VALUE

 The new exaggerated envelope (a list).

EXAMPLE

(exaggerate-env '(0 0 50 .8 100 1) 1.9)
--> (0 0.0 50 0.6894338 100 1.0)
(exaggerate-env '(0 0 50 .8 100 1) .1)
--> (0 0.0 50 0.9751001 100 1.0)
(exaggerate-env '(0 0 50 .8 100 1) -10)
--> (0 0.0 50 83.19083 100 1.0)
(exaggerate-env '(0 0 50 .8 100 1) -10 t)
--> (0 0.0 50 0.6894338 100 1.0)
(exaggerate-env '(0 0 50 .8 100 1) 0 t)
--> (0 0.0 50 0.8 100 1.0)
(exaggerate-env '(0 0 50 .8 100 1) 10 t)
--> (0 0.0 50 0.9751001 100 1.0)

SYNOPSIS

(defun exaggerate-env (env expt &optional easy-expt)

utilities/factor [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Boolean test to check if a specified number is a multiple of a second
 specified number.

ARGUMENTS

 - A number that will be tested to see if it is a multiple of the second
   number. 
 - A second number that is the base number for the factor test.

RETURN VALUE

 T if the first number is a multiple of the second number, otherwise NIL.

EXAMPLE

(factor 14 7)

=> T

SYNOPSIS

(defun factor (num fac)

utilities/flatten [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Return a list of nested lists of any depth as a flat list.

ARGUMENTS

 - A list of nested lists.

RETURN VALUE

 A flat list.

EXAMPLE

(flatten '((1 (2 3 4) (5 (6 7) (8 9 10 (11) 12)) 13) 14 15 (16 17)))

=> (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17)

SYNOPSIS

(defun flatten (nested-list)

utilities/force-length [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DATE

 03-FEB-2011

DESCRIPTION

 Create a new a list of a specified new length by adding or removing items
 at regular intervals from the original list. If adding items and the list
 contains numbers, linear interpolation will be used, but only between two
 adjacent items; i.e. not with a partial increment.

 NB: The function can only create new lists that have a length between 1 and
     1 less than double the length of the original list.

ARGUMENTS

 - A flat list.
 - A number that is the new length of the new list to be derived from the
   original list. This number must be a value between 1 and 1 less than
   double the length of the original list.

RETURN VALUE

EXAMPLE

;;; Shortening a list
(force-length (loop for i from 1 to 100 collect i) 17)

=> (1 7 13 20 26 32 39 45 51 57 63 70 76 82 89 95 100)

;;; Lengthening a list
(force-length (loop for i from 1 to 100 collect i) 199)

=> (1 1.5 2 2.5 3 3.5 4 4.5 5 5.5 6 6.5 7 7.5 8 8.5 9 9.5 10 10.5 11 11.5 12
    12.5 13 13.5 14 14.5 15 15.5 16 16.5 17 17.5 18 18.5 19 19.5 20 20.5 21
    21.5 22 22.5 23 23.5 24 24.5 25 25.5 26 26.5 27 27.5 28 28.5 29 29.5 30
    30.5 31 31.5 32 32.5 33 33.5 34 34.5 35 35.5 36 36.5 37 37.5 38 38.5 39
    39.5 40 40.5 41 41.5 42 42.5 43 43.5 44 44.5 45 45.5 46 46.5 47 47.5 48
    48.5 49 49.5 50 50.5 51 51.5 52 52.5 53 53.5 54 54.5 55 55.5 56 56.5 57
    57.5 58 58.5 59 59.5 60 60.5 61 61.5 62 62.5 63 63.5 64 64.5 65 65.5 66
    66.5 67 67.5 68 68.5 69 69.5 70 70.5 71 71.5 72 72.5 73 73.5 74 74.5 75
    75.5 76 76.5 77 77.5 78 78.5 79 79.5 80 80.5 81 81.5 82 82.5 83 83.5 84
    84.5 85 85.5 86 86.5 87 87.5 88 88.5 89 89.5 90 90.5 91 91.5 92 92.5 93
    93.5 94 94.5 95 95.5 96 96.5 97 97.5 98 98.5 99 99.5 100)

SYNOPSIS

(defun force-length (list new-len)

utilities/get-clusters [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Takes a list with (ascending) numbers and creates sublists of those numbers
 within <threshold> of each other. 

ARGUMENTS

 A list of (ascending) numbers. NB Though the numbers don't have to be in
 ascending order, the design application of the function makes most sense if
 they are.

OPTIONAL ARGUMENTS

 The maximum distance between two numbers in order for them to be considered
 as part of the same cluster.

RETURN VALUE

 A list with clusters in sublists.

EXAMPLE

(get-clusters '(24 55 58 59 60 81 97 102 106 116 118 119 145 149 151 200 210
                211 214 217 226 233 235 236 237 238 239 383 411 415 419))
--> (24 (55 58 59 60) 81 (97 102 106) (116 118 119) (145 149 151) 200
        (210 211 214 217) 226 (233 235 236 237 238 239) 383 (411 415 419))

(get-clusters '(0 .1 .3 .7 1.5 1.55 2 4.3 6.3 6.4) 1)
--> ((0 0.1 0.3 0.7 1.5 1.55 2) 4.3 (6.3 6.4))

(get-clusters '(0 .1 .3 .7 1.5 1.55 2 4.3 6.3 6.4) 0.5)
--> ((0 0.1 0.3 0.7) (1.5 1.55 2) 4.3 (6.3 6.4))

SYNOPSIS

(defun get-clusters (list &optional (threshold 5))

utilities/get-harmonics [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Return a list of the harmonic partial frequencies in Hertz from a
 specified (usually fundamental) frequency.

ARGUMENTS

 - A number that is the fundamental or starting frequency in Hertz.

OPTIONAL ARGUMENTS

 keyword arguments
 - :start-partial. An integer that is the number of the first harmonic
    partial to return. Default = 1.
 - :min-freq. A number that is the lowest frequency in Hertz to
   return. Default = 20.
 - :max-freq. A number that is the highest frequency in Hertz to
   return. Default = 20000.
 - :start-freq-is-partial.  Rather than treating the first argument as the
   fundamental, treat it as the partial number indicated by this argument.
   Default = 1.
 - :max-results.  The maximum number of harmonics to return.  Default =
    most-positive-fixnum  
 - :skip. The increment for the harmonics.  If 1, then we ascend the
    harmonics series one partial at a time; 2 would mean skipping every other
    Default = 1. 

RETURN VALUE

 A list of numbers that are the frequencies in Hertz of harmonic partials
 above the same fundamental frequency.

EXAMPLE

;;; Get the first 15 harmonic partials above a fundamental pitch of 64 Hertz,
;;; starting with partial 2, and specifying an upper cut-off of 1010 Hz.

(get-harmonics 63 :start-partial 2 :max-freq 1010)

=> (126 189 252 315 378 441 504 567 630 693 756 819 882 945 1008)

SYNOPSIS

(defun get-harmonics (start-freq &key (start-partial 1) (min-freq 20)
                      (start-freq-is-partial 1) (max-freq 20000) (skip 1)
                      (max-results most-positive-fixnum))

utilities/get-sublist-indices [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Get the starting position of sublists within a list as though the complete
 set of items were a flat list.

ARGUMENTS

 - A list of lists.

RETURN VALUE

 A list of integers that are the indices of the sublists.

EXAMPLE

(get-sublist-indices '((1 2) (3 4 5 6) (7 8 9) (10 11 12 13 14) (15)))

=> (0 2 6 9 14)

SYNOPSIS

(defun get-sublist-indices (list)

utilities/get-sublist-lengths [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Get the lengths of all sublists in a given list.

ARGUMENTS

 - A list of lists.

OPTIONAL ARGUMENTS

 - T or NIL to indicate whether to first remove zeros caused by empty
   sublists from the result.

RETURN VALUE

 A list of integers.

EXAMPLE

;; Straightforward usage allows zeros in the result
(get-sublist-lengths '((1 2) (3 4 5 6) (7 8 9) (10 11 12 13 14) ()))

=> (2 4 3 5 0)

;; Setting the optional argument to T removes zeros from the result

(get-sublist-lengths '((1 2) (3 4 5 6) (7 8 9) (10 11 12 13 14) ()) t)

=> (2 4 3 5)

SYNOPSIS

(defun get-sublist-lengths (list &optional (remove-zeros nil))

utilities/hailstone [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Implementation of the Collatz conjecture (see
 http://en.wikipedia.org/wiki/Collatz_conjecture )

 The Collatz conjecture suggests that by starting with a given number, and
 if it is even dividing it by two or if it is odd multiplying it by three
 and adding one, then repeating with the new result, the process will
 eventually always result in one.

ARGUMENTS

 - A number to start with.

RETURN VALUE

 A list of the results collected from each iteration starting with the
 specified number and ending with one.

EXAMPLE

(hailstone 11)

=> (11 34 17 52 26 13 40 20 10 5 16 8 4 2 1)

SYNOPSIS

(defun hailstone (n)

utilities/hz2ms [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Convert a frequency in Hertz to the equivalent number of milliseconds. 

ARGUMENTS

 - A number that is a Hertz frequency.

RETURN VALUE

 A number that is the millisecond equivalent of the specified Hertz
 frequency. 

EXAMPLE

(hz2ms 261.63)

=> 3.8221915

SYNOPSIS

(defun hz2ms (hertz)

utilities/interleave [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Interleave the elements of an aribitrary number of lists. Should the lists
 not be of the same length, this function will only use up as many elements
 as in the shortest list.

ARGUMENTS

 As many lists as need to be interleaved.

RETURN VALUE

 A new list of interleaved elements.

EXAMPLE

(INTERLEAVE '(1 2 3 4 5) '(a b c d) '(x y z))
--> (1 A X 2 B Y 3 C Z)

(INTERLEAVE '(1 2 3 4 5) '(a b c d e) '(v w x y z))
--> (1 A V 2 B W 3 C X 4 D Y 5 E Z)

SYNOPSIS

(defun interleave (&rest lists)

utilities/interpolate [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Get the interpolated value at a specified point within an envelope. The
 envelope must be specified in the form of a list of break-point pairs.

ARGUMENTS

 - A number that is the point within the specified envelope for which to
   return the interpolated value.
 - A list of break-point pairs.

OPTIONAL ARGUMENTS

 keyword arguments:
 - :scaler. A number that is the factor by which to scale the values of
   the break-point pairs in the given envelope before retrieving the
   interpolated value. Default = 1.
 - :exp. A number that is the exponent to which the result should be
   raised. Default = 1.
 - :warn. T or NIL to indicate whether the method should print a warning if
   the specified point is outside of the bounds of the x-axis specified in
   the list of break-point pairs. T = warn. Default = T.

RETURN VALUE

EXAMPLE

;;; Using the defaults
(interpolate 50 '(0 0 100 1))

=> 0.5

;;; Specifying a different scaler
(interpolate 50 '(0 0 100 1) :scaler 2)

=> 1.0

;;; Specifying a different exponent by which the result is to be raised
(interpolate 50 '(0 0 100 1) :exp 2)

=> 0.25

SYNOPSIS

(defun interpolate (point env &key (scaler 1) (exp 1) (warn t))

utilities/list-to-string [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Convert a list to a string.

ARGUMENTS

 - A list.

OPTIONAL ARGUMENTS

 - A string that will serve as a separator between the elements. 
   Default = " ".
 - T or NIL to indicate whether a list value of NIL is to be returned as
   "NIL" or NIL. T = "NIL" as a string. Default = T.

RETURN VALUE

EXAMPLE

;;; Using defaults
(list-to-string '(1 2 3 4 5))

=> "1 2 3 4 5"

;;; Specifying a different separator
(list-to-string '(1 2 3 4 5) "-")

=> "1-2-3-4-5"

;;; A NIL list returns "NIL" as a string by default
(list-to-string NIL)

=> "nil"

;;; Setting the second optional argument to NIL returns a NIL list as NIL
;;; rather than as "NIL" as a string
(list-to-string NIL "" nil)

=> NIL

SYNOPSIS

(defun list-to-string (list &optional (separator " ") (nil-as-string t))

utilities/logarithmic-steps [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Create a list of numbers progressing from the first specified argument to
 the second specified argument over the specified number of steps using an
 exponential curve rather than linear interpolation.

ARGUMENTS

 - A number that is the starting value in the resulting list.
 - A number that is the ending value in the resulting list.
 - An integer that will be the length of the resulting list - 1.

OPTIONAL ARGUMENTS

 - A number that will be used as the exponent when determining the
   exponential interpolation between values. Default = 2.

RETURN VALUE

 A list of numbers.

EXAMPLE

(logarithmic-steps 1 100 19)

=> (1.0 1.3055556 2.2222223 3.75 5.888889 8.638889 12.0 15.972222 20.555555
    25.75 31.555555 37.97222 45.0 52.63889 60.88889 69.75 79.22222 89.30556
    100.0)

SYNOPSIS

(defun logarithmic-steps (low high num-steps &optional (exponent 2))

utilities/middle [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Get the number value that is middle of two number values.

ARGUMENTS

 - A first number.
 - A second number.

RETURN VALUE

 A number.

EXAMPLE

(middle 7 92)

=> 49.5

SYNOPSIS

(defun middle (lower upper)

utilities/mins-secs-to-secs [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Derive the number of seconds from a minutes-seconds value that is indicated
 as a two-item list in the form '(minutes seconds).

ARGUMENTS

 - A two-item list of integers in the form '(minutes seconds).

RETURN VALUE

 A decimal number that is a number in seconds.

EXAMPLE

(mins-secs-to-secs '(2 1))

=> 121.0

SYNOPSIS

(defun mins-secs-to-secs (list)

utilities/move-elements [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DATE

 02-Mar-2011

DESCRIPTION

 Move the specified elements from one list (if they are present in that
 list) to another, deleting them from the first.

ARGUMENTS

 - A list of elements that are the elements to be moved.
 - A list from which the specified elements are to be moved and deleted.
 - A list to which the specified elements are to be moved.

OPTIONAL ARGUMENTS

 - A predicate by which to test that the specified elements are equal to
   elements of the source list. Default = #'eq.

RETURN VALUE

 Two values: A first list that is the source list after the items have been
 moved; a second list that is the target list after the items have been
 moved. 

EXAMPLE

(move-elements '(3 5 8) '(1 2 3 4 5 6 7 8 9) '(a b c d e))

=> (1 2 4 6 7 9), (8 5 3 A B C D E)

SYNOPSIS

(defun move-elements (what from to &optional (test #'eq))

utilities/move-to-end [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DATE

 22-May-2011

DESCRIPTION

 Move a specified element of a given list to the end of the list, returning
 the new list. 

 NB: If the element exists more than once in the given list, all but one of
     the occurrences will be removed and only one of them will be placed at
     the end.

ARGUMENTS

 - An item that is an element of the list that is the second argument.
 - A list.

RETURN VALUE

 A list.

EXAMPLE

;;; All unique items
(move-to-end 2 '(1 2 3 4 5))

=> (1 3 4 5 2)

;;; Duplicate items
(move-to-end 2 '(1 2 3 2 4 2 5))

=> (1 3 4 5 2)

SYNOPSIS

(defun move-to-end (what list &optional (test #'eql))

utilities/nconc-sublists [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Concatenate corresponding sublists of a given list. Each sublist in the
 argument should have the same length and number of sublists etc.

ARGUMENTS

 A list of lists.

RETURN VALUE

 A list of lists.

EXAMPLE

(nconc-sublists '(((1 2) (a b) (cat dog)) 
                  ((3 4) (c d) (bird fish)) 
                  ((5 6) (e f) (pig cow))))

=> ((1 2 3 4 5 6) (A B C D E F) (CAT DOG BIRD FISH PIG COW))

SYNOPSIS

(defun nconc-sublists (lists)

utilities/nearest-power-of-2 [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Return the closest number to the specified value that is a power of two but
 not greater than the specified value (unless the optional argument is T:
 see below).

ARGUMENTS

 - A number.

OPTIONAL ARGUMENTS

 - T or NIL to indicate whether we can return a power of 2 greater than the
   argument, if that is nearer to the argument than the lower power or 2.

RETURN VALUE

 An integer that is a power of two.

EXAMPLE

(nearest-power-of-2 31)

=> 16

(nearest-power-of-2 31 t)

=> 32

(nearest-power-of-2 32)

=> 32

(nearest-power-of-2 33)

=> 32

SYNOPSIS

(defun nearest-power-of-2 (num &optional allow>)

utilities/octave-freqs [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 A boolean test to determine whether two specified frequencies are octave
 transpositions of the same pitch class. 

ARGUMENTS

 - A first number that is a frequency in Hertz.
 - A second number that is a frequency in Hertz.

OPTIONAL ARGUMENTS

 - T or NIL to indicate whether identical frequencies ("unison") are also
   to be considered octave transpositions of the same pitch class. 
   T = unisons are also octaves. Default = T.

RETURN VALUE

 T or NIL.

EXAMPLE

(octave-freqs 261.63 2093.04)

=> T

(octave-freqs 261.63 3000.00)

=> NIL

(octave-freqs 261.63 261.63)

=> T

(octave-freqs 261.63 261.63 nil)

=> NIL

SYNOPSIS

(defun octave-freqs (freq1 freq2 &optional (unison-also t))

utilities/parse-audacity-label-file-for-loops [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Read an audacity label file and return its loop points as groups.

 NB: If this fails it's probably because there's a tab between time and
     label instead of spaces: save in emacs to detab.

 NB: Beware that marker files created on different operating systems from
     the one on which this function is called might trigger errors due to
     newline character mismatches.

ARGUMENTS

 - A string that is the name of the label file to be parsed, including
   directory path and extension.

RETURN VALUE

 Returns a list of lists which are the grouped time points. 

 Also prints separate feedback to the listener.

EXAMPLE

(parse-audacity-label-file-for-loops  "/path/to/24-7loops1.txt")

=>
313 markers, 50 loops read

((25.674559 25.829296 26.116327 26.649048 27.038843)
 (32.211884 32.33669 32.481815 32.618233 32.716915 32.902676 33.227757
  33.61959)
 (36.893604 37.059048 37.160633 37.27383 37.439274 37.4683 37.627937)
 (39.52907 39.81932 39.999275 40.2634 40.338867 40.605896)
 (45.612698 45.818775 46.050976 46.145306 46.275192)
 (46.4566 46.644535 46.76934 46.886894 46.971066 47.16553)
 (84.15927 84.260864 84.292786 84.355194 84.47274 84.52789 84.556915
  84.65415)
 ...
 (676.1075 676.79114 677.1503 677.57904 678.12366)
 (799.29205 799.8019 800.58984 800.96063 801.13446 801.45886)
 (804.98145 805.2016 805.5724 805.83887 806.31396))

SYNOPSIS

(defun parse-audacity-label-file-for-loops (label-file)

utilities/parse-wavelab-marker-file-for-loops [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Read a wavelab marker file and return its loop points as groups.

 The marker file must contain markers with the word "loop". A marker with
 that name will start a new set of loop points, and nameless markers will
 belong to the group until the next "loop" marker.

ARGUMENTS

 - A string that is the name of the marker file to be parsed, including
   directory path and extension.

OPTIONAL ARGUMENTS

 keyword arguments:
 - :sampling-rate. An integer that is the sampling rate of the sound file to
   which the marker file refers. This value will affect the resulting time
   points. Default = 44100.
 - :max-length. The maximum duration in seconds between two points: anything
   greater than this will result in a warning being printed.

RETURN VALUE

 Returns a list of lists which are the grouped time points. 

 Also prints separate feedback to the listener.

EXAMPLE

(parse-wavelab-marker-file-for-loops "/path/to/24-7loops1.mrk")

=>
WARNING:
   utilities::parse-wavelab-marker-file-for-loops 
   loop points 10:13.213 to 10:14.475 are too long (1.2620239)
WARNING:
   utilities::parse-wavelab-marker-file-for-loops 
   loop points 10:33.223 to 10:34.486 are too long (1.2630615)
WARNING:
   utilities::parse-wavelab-marker-file-for-loops 
   loop points 10:36.456 to 10:37.522 are too long (1.06604)


312 markers, 50 loops read

((25.674559 25.829296 26.116327 26.649048 27.038843)
 (32.211884 32.33669 32.481815 32.618233 32.716915 32.902676 33.227757
  33.61959)
 (36.893604 37.059048 37.160633 37.27383 37.439274 37.4683 37.627937)
 (39.52907 39.81932 39.999275 40.2634 40.338867 40.605896)
 (45.612698 45.818775 46.050976 46.145306 46.275192)
 (46.4566 46.644535 46.76934 46.886894 46.971066 47.16553)
 (84.15927 84.260864 84.292786 84.355194 84.47274 84.52789 84.556915
  84.65415)
 ...
 (655.91077 656.4554 656.80304 657.4519 658.04285 658.8192)
 (676.1075 676.79114 677.1503 677.57904 678.12366)
 (799.29205 799.8019 800.58984 800.96063 801.13446 801.45886)
 (804.98145 805.2016 805.5724 805.83887 806.31396))

SYNOPSIS

(defun parse-wavelab-marker-file-for-loops
    (marker-file &key (sampling-rate 44100) (max-length 1.0))

utilities/partial-freqs [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DATE

 13-Dec-2011

DESCRIPTION

 A Boolean test to determine whether either of two specified frequencies
 can be considered a harmonic partial of the other.

ARGUMENTS

 - A first frequency in Hertz.
 - A second frequency in Hertz.

OPTIONAL ARGUMENTS

 - T or NIL to indicate whether identical frequencies ("unison") are also to
   be considered partials of each other. T = unison are partials. 
   Default = T.

RETURN VALUE

 T if one of the frequencies has the ratio of a harmonic partial to the
 other, otherwise NIL.

EXAMPLE

(partial-freqs 300 900)

=> T

(partial-freqs 300 700)

=> NIL

(partial-freqs 300 300)

=> T

(partial-freqs 300 300 nil)

=> NIL

SYNOPSIS

(defun partial-freqs (freq1 freq2 &optional (unison-also t))

utilities/pdivide [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Creates a list of proportionally related times, dividing a starting
 duration into a number of smaller durations a specified number of times.
 We start with a proportion as a ratio (e.g. 3/2) and divide the given
 duration into two parts according to that ratio.  Then those two parts will
 be divided into the same ratios.  This will iterate the number of times
 indicated by the second argument.

 The following are some classical proportions:
         Latin        (Greek)
 (3 : 2) Sesquialtera (Diapente)
 (4 : 3) Sesquitertia (Diatessaron)
 (5 : 4) Sesquiquarta (Diatonus Semitonus)
 (8 : 3) Duplasuperbipartiens (Diapson Diatesseron)
 (9 : 8) Sesquioctava (Tonus)

ARGUMENTS

 - an integer or ratio (in Lisp terms, a rational) e.g. 3/2
 - an integer >=1 specifying the number of times to iterate the process of
   dividing the duration into proportions.

OPTIONAL ARGUMENTS

 keyword arguments:
 - :duration. The overall duration to apply the proportional divisions to.
   Units are arbitrary of course as this is just a number. Default 1.0.
 - :print. If T, print each level of division as we proceed. Default NIL.
 - :reverse. If T reverse the proportion (so 3/2 becomes 2/3). Default NIL.
 - :alternate. If T, reverse the proportion every other division (not
   iteration) so that if we have a proportion of 3/2 on the second iteration
   we divide into 3/2 then 2/3.  Default NIL.
 - :increment. If T, then each time we divide we increment both sides of the
   proportion,  so 3:2 becomes 4:3 which becomes 5:4 etc.  Default NIL.
 - :halves. This will only make a difference if :increment is T: As results
   tend overall towards increasing (when numerator < denominator e.g. 2/3) or
   decreasing (numerator > denominator e.g. 3/2) numbers, we can mix things
   up by dividing the resultant list into two halves and splicing their
   elements one after the other.  Default NIL.
 - :shuffle. Mix things up by shuffling the resultant list.  As this uses
   the shuffle algorithm we have fixed-seed randomness so results will be
   the same upon each call within the same Lisp implementation/version.
   Default NIL. 

RETURN VALUE

 Three values: the list of ascending timings from the last generation of the
 calculated proportions; the durations of each part for the last generation;
 the list of ascending timings for _each_ generation of the calculated
 proportions (a list of lists).

EXAMPLE

Notice here that each generation prints the proportions along with the
durations these correspond to and the start time of each (cumulative durations).

(pdivide 3/2 4 :duration 35 :print t)

PRINTS:
Generation 1: 3 (21.00=21.00), 2 (14.00=35.00), 

Generation 2: 3 (12.60=12.60), 2 (8.40=21.00), 3 (8.40=29.40), 2 (5.60=35.00), 

Generation 3: 3 (7.56=7.56), 2 (5.04=12.60), 3 (5.04=17.64), 2 (3.36=21.00), 
3 (5.04=26.04), 2 (3.36=29.40), 3 (3.36=32.76), 2 (2.24=35.00), 

Generation 4: 3 (4.54=4.54), 2 (3.02=7.56), 3 (3.02=10.58), 2 (2.02=12.60), 
3 (3.02=15.62), 2 (2.02=17.64), 3 (2.02=19.66), 2 (1.34=21.00), 3 (3.02=24.02),
2 (2.02=26.04), 3 (2.02=28.06), 2 (1.34=29.40), 3 (2.02=31.42), 2 (1.34=32.76),
3 (1.34=34.10), 2 (0.90=35.00), 

RETURNS: 
(0.0 4.5360003 7.5600004 10.584001 12.6 15.624001 17.640001 19.656002 21.000002
 24.024002 26.040003 28.056004 29.400003 31.416004 32.760006 34.104008
 35.000008)
(4.5360003 3.0240002 3.0240004 2.0160003 3.0240004 2.0160003 2.0160003
 1.3440002 3.0240004 2.0160003 2.0160003 1.3440002 2.0160003 1.3440001
 1.3440001 0.896)
((0.0 4.5360003 7.5600004 10.584001 12.6 15.624001 17.640001 19.656002
  21.000002 24.024002 26.040003 28.056004 29.400003 31.416004 32.760006
  34.104008 35.000008)
 (0.0 7.5600004 12.6 17.640001 21.000002 26.040003 29.400003 32.760002
  35.000004)
 (0.0 12.6 21.0 29.400002 35.0) (0.0 21.0 35.0))


(pdivide 3/2 4 :duration 35 :print t :increment t :halves t)

PRINTS:
Generation 1: 3 (21.00=21.00), 2 (14.00=35.00), 

Generation 2: 4 (12.00=12.00), 3 (9.00=21.00), 5 (7.78=28.78), 4 (6.22=35.00), 

Generation 3: 6 (6.55=6.55), 5 (5.45=12.00), 7 (4.85=16.85), 6 (4.15=21.00), 
8 (4.15=25.15), 7 (3.63=28.78), 9 (3.29=32.07), 8 (2.93=35.00), 

Generation 4: 10 (3.44=3.44), 9 (3.10=6.55), 11 (2.86=9.40), 10 (2.60=12.00), 
12 (2.53=14.53), 11 (2.32=16.85), 13 (2.16=19.01), 12 (1.99=21.00), 
14 (2.15=23.15), 13 (2.00=25.15), 15 (1.88=27.03), 14 (1.75=28.78), 
16 (1.70=30.48), 15 (1.59=32.07), 17 (1.51=33.58), 16 (1.42=35.00), 

RETURNS:
(0.0 3.4449766 5.595868 8.696347 10.6936035 13.550747 15.428142 18.025545
 19.77778 22.30621 24.0064 26.324125 27.918053 30.078053 31.58647 33.580315
 35.0)
(3.4449766 2.1508918 3.100479 1.9972568 2.8571434 1.8773947 2.5974028 1.752235
 2.5284283 1.7001898 2.317726 1.593928 2.16 1.5084175 1.9938462 1.4196872)
((0.0 3.4449766 6.5454555 9.402599 12.000002 14.52843 16.846155 19.006155
  21.000002 23.150894 25.148151 27.025547 28.777782 30.477972 32.0719 33.58032
  35.000004)
 (0.0 6.5454555 12.000002 16.846157 21.000004 25.148151 28.77778 32.0719
  35.000004)
 (0.0 12.000001 21.0 28.777779 35.0) (0.0 21.0 35.0))

SYNOPSIS

(defun pdivide (start levels &key (duration 1.0) print reverse alternate
                    halves shuffle increment)

utilities/pexpand [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Instead of dividing an overall duration (pdivide) we start with a
 proportion and expand outwards from there, keeping each newly created part
 in the same proportion.  This is repeated the number of times specified in
 the first argument.  Useful for generating maps (section structure).

ARGUMENTS

 The number of times to expand proportionally.

OPTIONAL ARGUMENTS

 As many integer proportions as required.  If the last argument here is t,
 then instead of using letters to denote sections we use numbers instead. 

RETURN VALUE

 3 values: 
 1) a list showing the cumulative count (e.g. bar numbers) of where major
 and minor sections occur.  Topmost sections will have the labels A, B, C,
 etc. with subsections such as A.A, A.B, ... C.C.C.C.  Of course, wherever a
 major section starts, an arbitrary number of subsections also begin, but
 only the most major section is present in the list.
 2) the structure of the sections and subsections in the form of a list of
 sublists for each, and containing the section labels paired with their
 length.  The bottommost subsection will have a length of the sum of the
 proportions, with higher subsection groupings showing multiples of this.
 3) the overall length of the structure produced (also the first element of
 the second returned value).

EXAMPLE

;;; 2 generations:
(pexpand 2 3 2) =>
(1 (A) 6 (A A A B) 11 (A A A C) 16 (A A B) 21 (A A B B) 26 (A B) 31 (A B A B)
 36 (A B A C) 41 (A B B) 46 (A B B B) 51 (A C) 56 (A C A B) 61 (A C A C) 66
 (A C B) 71 (A C B B) 76 (B) 81 (B A A B) 86 (B A A C) 91 (B A B) 96 (B A B B)
 101 (B B) 106 (B B A B) 111 (B B A C) 116 (B B B) 121 (B B B B))
(125
 (((A) 75)
  (((A A) 25) (((A A A) 15) ((A A A A) 5) ((A A A B) 5) ((A A A C) 5))
   (((A A B) 10) ((A A B A) 5) ((A A B B) 5)))
  (((A B) 25) (((A B A) 15) ((A B A A) 5) ((A B A B) 5) ((A B A C) 5))
   (((A B B) 10) ((A B B A) 5) ((A B B B) 5)))
  (((A C) 25) (((A C A) 15) ((A C A A) 5) ((A C A B) 5) ((A C A C) 5))
   (((A C B) 10) ((A C B A) 5) ((A C B B) 5))))
 (((B) 50)
  (((B A) 25) (((B A A) 15) ((B A A A) 5) ((B A A B) 5) ((B A A C) 5))
   (((B A B) 10) ((B A B A) 5) ((B A B B) 5)))
  (((B B) 25) (((B B A) 15) ((B B A A) 5) ((B B A B) 5) ((B B A C) 5))
   (((B B B) 10) ((B B B A) 5) ((B B B B) 5)))))
125

;;; 3 generations:
(pexpand 3 3 2) =>
(1 (A) 6 (A A A A A B) 11 (A A A A A C) 16 (A A A A B) 21 (A A A A B B) 26
 (A A A B) 31 (A A A B A B) 36 (A A A B A C) 41 (A A A B B) 46 (A A A B B B) 51
 (A A A C) 56 (A A A C A B) 61 (A A A C A C) 66 (A A A C B) 71 (A A A C B B) 76
...
 581 (B B B A A B) 586 (B B B A A C) 591 (B B B A B) 596 (B B B A B B) 601
 (B B B B) 606 (B B B B A B) 611 (B B B B A C) 616 (B B B B B) 621
 (B B B B B B))
(625
 (((A) 375)
  (((A A) 125)
   (((A A A) 75)
    (((A A A A) 25)
     (((A A A A A) 15) ((A A A A A A) 5) ((A A A A A B) 5) ((A A A A A C) 5))
     (((A A A A B) 10) ((A A A A B A) 5) ((A A A A B B) 5)))
...
   (((B B B) 50)
    (((B B B A) 25)
     (((B B B A A) 15) ((B B B A A A) 5) ((B B B A A B) 5) ((B B B A A C) 5))
     (((B B B A B) 10) ((B B B A B A) 5) ((B B B A B B) 5)))
    (((B B B B) 25)
     (((B B B B A) 15) ((B B B B A A) 5) ((B B B B A B) 5) ((B B B B A C) 5))
     (((B B B B B) 10) ((B B B B B A) 5) ((B B B B B B) 5)))))))
625

;;; 2 generations of 3 proportional values, returning numbers for labels
(pexpand 2 3 2 4 t) =>
(1 (1) 10 (1 1 1 2) 19 (1 1 1 3) 28 (1 1 2) 37 (1 1 2 2) 46 (1 1 3) 55
 (1 1 3 2) 64 (1 1 3 3) 73 (1 1 3 4) 82 (1 2) 91 (1 2 1 2) 100 (1 2 1 3) 109
 (1 2 2) 118 (1 2 2 2) 127 (1 2 3) 136 (1 2 3 2) 145 (1 2 3 3) 154 (1 2 3 4)
... (3 4 2 2) 694 (3 4 3) 703 (3 4 3 2) 712 (3 4 3 3) 721 (3 4 3 4))

(729
 (((1) 243)
  (((1 1) 81) (((1 1 1) 27) ((1 1 1 1) 9) ((1 1 1 2) 9) ((1 1 1 3) 9))
   (((1 1 2) 18) ((1 1 2 1) 9) ((1 1 2 2) 9))
   (((1 1 3) 36) ((1 1 3 1) 9) ((1 1 3 2) 9) ((1 1 3 3) 9) ((1 1 3 4) 9)))
...
   (((3 2 2) 18) ((3 2 2 1) 9) ((3 2 2 2) 9))
   (((3 2 3) 36) ((3 2 3 1) 9) ((3 2 3 2) 9) ((3 2 3 3) 9) ((3 2 3 4) 9)))
  (((3 3) 81) (((3 3 1) 27) ((3 3 1 1) 9) ((3 3 1 2) 9) ((3 3 1 3) 9))
   (((3 3 2) 18) ((3 3 2 1) 9) ((3 3 2 2) 9))
   (((3 3 3) 36) ((3 3 3 1) 9) ((3 3 3 2) 9) ((3 3 3 3) 9) ((3 3 3 4) 9)))
  (((3 4) 81) (((3 4 1) 27) ((3 4 1 1) 9) ((3 4 1 2) 9) ((3 4 1 3) 9))
   (((3 4 2) 18) ((3 4 2 1) 9) ((3 4 2 2) 9))
   (((3 4 3) 36) ((3 4 3 1) 9) ((3 4 3 2) 9) ((3 4 3 3) 9) ((3 4 3 4) 9)))))
729

SYNOPSIS

(defun pexpand (generations &rest proportions)

utilities/pexpand-find [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Find the cumulative number of where a label occurs in a list returned by
 pexpand.

ARGUMENTS

 - the label we're looking for
 - a list of the type returned by pexpand (first returned value).

OPTIONAL ARGUMENTS

 - a function to be called when the label cannot be found.  Default =
 #'error but could also be #'warn or NIL.

RETURN VALUE

 An integer.

SYNOPSIS

(defun pexpand-find (label list &optional (on-error #'error))

utilities/pexpand-reaper-markers [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DATE

 September 4th 2015, Edinburgh

DESCRIPTION

 Using the pexpand function, we write marker information in a format which
 can be read by the Reaper (version 4/5+) DAW software. Though we can think
 of the outputs of pexpand to be in beats, seconds, bars, or any arbitrary
 scale, the timings of Reaper markers are in seconds, hence the need here
 for an initial tempo. In other words, we treat the output of pexpand to be
 beat counts; if you would prefer to interpret these as bars, simply divide
 the tempo by the number of beats per bar. If there are to be tempo changes
 in the mix/piece Reaper itself will update the markers' positions when the
 new tempo is inserted in the project window--this is fine when you are
 thinking in beats/bars but beware of changing tempo in Reaper if you are
 thinking of markers with fixed timings (seconds).

 Copy the output of this into the Reaper file verbatim (no enclosing < >
 marks) before the <PROJBAY tag.

ARGUMENTS

 - the tempo in BPM
 - the number of generations: see the pexpand function
 - (&rest) the proportions: see the pexpand function

RETURN VALUE

 Always T

EXAMPLE

(pexpand-reaper-markers 144 2 6 3 5 4)
->
  MARKER 1 7.5 "level 4" 0 0 1
  MARKER 2 15.0 "level 4" 0 0 1
  MARKER 3 22.5 "level 4" 0 0 1
  MARKER 4 30.0 "level 4" 0 0 1
  MARKER 5 37.5 "level 4" 0 0 1
...
  MARKER 108 810.0 "level 1" 0 0 1
  MARKER 109 817.5 "level 4" 0 0 1
  MARKER 110 825.0 "level 4" 0 0 1
  MARKER 111 832.5 "level 4" 0 0 1
  MARKER 112 840.0 "level 4" 0 0 1
  MARKER 113 847.5 "level 4" 0 0 1
  MARKER 114 855.0 "level 3" 0 0 1
...
  MARKER 319 2392.5 "level 4" 0 0 1
  MARKER 320 2400.0 "level 3" 0 0 1
  MARKER 321 2407.5 "level 4" 0 0 1
  MARKER 322 2415.0 "level 4" 0 0 1
  MARKER 323 2422.5 "level 4" 0 0 1


Here's where I pasted the data into the .RPP Reaper file:

  <TEMPOENVEX
    ACT 0
    VIS 1 0 1
    LANEHEIGHT 0 0
    ARM 0
    DEFSHAPE 1 -1 -1
  >
  MARKER 1 7.5 "level 4" 0 0 1
  MARKER 2 15 "level 4" 0 0 1
  MARKER 3 22.5 "level 4" 0 0 1
  MARKER 4 30 "level 4" 0 0 1
...
  MARKER 320 2400 "level 3" 0 0 1
  MARKER 321 2407.5 "level 4" 0 0 1
  MARKER 322 2415 "level 4" 0 0 1
  MARKER 323 2422.5 "level 4" 0 0 1
  <PROJBAY
  >
  <TRACK {EBF9837F-BE25-9542-B720-A1862C0DF380}

SYNOPSIS

(defun pexpand-reaper-markers (tempo generations &rest proportions)

utilities/pexpand-section-length [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Return the length (integer) of any arbitrary section in the data returned
 by pexpand. 

ARGUMENTS

 - The (rest of) the kind of list returned as the second value of a call to
   pexpand.
 - The section ID we want the length of, either as a list or single symbol.

RETURN VALUE

 An integer or NIL if the section can't be found.

EXAMPLE

(pexpand-section-length (rest (nth-value 1 (pexpand 2 3 6 4 5))) '(c a b))
=> 108

(pexpand-section-length (rest (nth-value 1 (pexpand 2 3 6 4 5))) 'c)
=> 1296

SYNOPSIS

(defun pexpand-section-length (pexpand-list section)

utilities/power-of-2 [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Test whether the specified number is a power of two and return the
 logarithm of the specified number to base 2.

 This method returns two values: T or NIL for the test and a decimal that is
 the logarithm of the specified number to base 2.

ARGUMENTS

 - A number.

RETURN VALUE

 Two values: T or NIL for the test and a decimal number that is the
 logarithm of the specified number to base 2.

EXAMPLE

(power-of-2 16)

=> T, 4.0

(power-of-2 17.3)

=> NIL, 4.1127

SYNOPSIS

(defun power-of-2 (float)

utilities/pts2cm [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Convert a specified number of points to a length in centimeters at a
 resolution of 72ppi.

ARGUMENTS

 - A number.

RETURN VALUE

 A number.

EXAMPLE

(pts2cm 150)

=> 5.2916665

SYNOPSIS

(defun pts2cm (points)

utilities/random-amount [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Return a random number from within a total range of <percent> of the given
 number, centering around zero. Thus, if the <number> is 100, and the
 <percent> is 5, the results will be a random number between -2.5 and +2.5.

ARGUMENTS

 A number.

OPTIONAL ARGUMENTS

 A number that will be a percent of the given number.

RETURN VALUE

 A random positive or negative number.

EXAMPLE

;;; Using the default will return numbers within a 5% span of the given number, 
;;; centering around zero. With 100 that means between -2.5 and +2.5.
(loop repeat 10 collect (random-amount 100))

=> (0.7424975 -1.4954442 -1.7126495 1.5918689 -0.43478793 -1.7916341 -1.9115914
    0.8541988 0.057197176 2.0713913)

;;; Specifying 10% of 80 will return random numbers between -4.0 and +4.0
(loop repeat 10 collect (random-amount 80 10))

=> (-0.66686153 3.0387697 3.4737322 -2.3753185 -0.8495751 -0.47580242
    -0.25743783 -1.1395472 1.3560238 -0.5958566)

SYNOPSIS

(defun random-amount (number &optional (percent 5))

utilities/random-from-list [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Return a random element from a specified list of elements. 

ARGUMENTS

 - A list.

OPTIONAL ARGUMENTS

 - An integer can be passed stating the length of the list, for more
   efficient processing. NB: There is no check to ensure this number is
   indeed the length of the list. If the number is less than the length of
   the list, only elements from the first part of the list will be
   returned. If it is greater than the length of the list, the method may
   return NIL.

RETURN VALUE

 An element from the specified list.

EXAMPLE

(random-from-list '(3 5 7 11 13 17 19 23 29))

=> 13

SYNOPSIS

(defun random-from-list (list &optional list-length) ; for efficiency

utilities/randomise [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Return a random decimal number close to the number specified (within a
 certain percentage of that number's value).

ARGUMENTS

 - A number.

OPTIONAL ARGUMENTS

 - A number that is a percentage value, such that any random number returned
   will be within that percentage of the original number's value. 
   Default = 5.

RETURN VALUE

 A decimal number.

EXAMPLE

(loop repeat 10 collect (randomise 100))

=> (99.413795 99.15346 98.682014 100.76199 97.74929 99.05693 100.59494 97.96452
    100.42091 100.01329)

SYNOPSIS

(defun randomise (number &optional (percent 5))

utilities/read-from-file [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Read a Lisp expression from a file. This is determined by the Lisp
 parenthetical syntax.

ARGUMENTS

 - A string that is a file name including directory path and extension. 

RETURN VALUE

 The Lisp expression contained in the file.

EXAMPLE

(read-from-file "/path/to/lisp-lorem-ipsum.txt")

=> (LOREM IPSUM DOLOR SIT AMET CONSECTETUR ADIPISCING ELIT CRAS CONSEQUAT
    CONVALLIS JUSTO VITAE CONSECTETUR MAURIS IN NIBH VEL EST TEMPUS LOBORTIS
    SUSPENDISSE POTENTI SED MAURIS MASSA ADIPISCING VITAE DIGNISSIM CONDIMENTUM
    VOLUTPAT VEL FELIS FUSCE AUGUE DUI PULVINAR ULTRICIES IMPERDIET SED
    PHARETRA EU QUAM INTEGER IN VULPUTATE VELIT ALIQUAM ERAT VOLUTPAT VIVAMUS
    SIT AMET ORCI EGET EROS CONSEQUAT TINCIDUNT NUNC ELEMENTUM ADIPISCING
    LOBORTIS MORBI AT LOREM EST EGET MATTIS ERAT DONEC AC RISUS A DUI MALESUADA
    LOBORTIS AC AT EST INTEGER AT INTERDUM TORTOR VIVAMUS HENDRERIT CONSEQUAT
    AUGUE QUISQUE ALIQUAM TELLUS NEC VESTIBULUM LOBORTIS RISUS TURPIS LUCTUS
    LIGULA IN BIBENDUM FELIS SEM PULVINAR DOLOR VIVAMUS RHONCUS NISI GRAVIDA
    PORTA VULPUTATE IPSUM LACUS PORTA RISUS A VULPUTATE MAGNA JUSTO A EST)

SYNOPSIS

(defun read-from-file (file)

utilities/reflect-list [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Order a list of numbers from least to greatest, then transpose the list so
 that if an element is the second lowest, it will be replaced by the second
 highest etc.

ARGUMENTS

 - A list or numbers.

RETURN VALUE

 A list of numbers.

EXAMPLE

(reflect-list '(1 4 3 5 9 6 2 7 8 8 9))

=> (9 6 7 5 1 4 8 3 2 2 1)

SYNOPSIS

(defun reflect-list (list)

utilities/remove-all [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Remove all of the specified elements from a list, returning a list
 containing only those elements that are not in the first argument list.

ARGUMENTS

 - A first list that is the list of items to remove.
 - A second list that is the original list.

OPTIONAL ARGUMENTS

 - A predicate for testing equality between the elements of the two lists. 
   Default = #'eq.

RETURN VALUE

 A list.

EXAMPLE

(remove-all '(3 5 8 13) '(1 2 3 4 5 6 7 8 9 10 11 12 13))

=> (1 2 4 6 7 9 10 11 12)

SYNOPSIS

(defun remove-all (rm-list list &optional (test #' eq))

utilities/remove-elements [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Remove a specified number of elements from a given list starting at a
 specified position (0-based) within the list.

ARGUMENTS

 - A list.
 - An integer that is the 0-based position within that list that will be the
   first element to be removed.
 - An integer that is the number of elements to remove.

RETURN VALUE

 A list.

EXAMPLE

(remove-elements '(1 2 3 4 5 6 7) 2 4)

=> (1 2 7)

SYNOPSIS

(defun remove-elements (list start how-many)

utilities/remove-more [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Remove all instances of a list of specified elements from an original
 list. The predicate used to test the presence of the specified elements in
 the original list must be specified by the user (such as #'eq, #'equalp,
 #'= etc.)

ARGUMENTS

 - A list.
 - A predicate with which to test the presence of the specified elements.
 - A sequence of elements to be removed from the given list.

RETURN VALUE

 A list.

EXAMPLE

(remove-more '(1 2 3 4 5 5 5 6 7 7 8) #'= 5 7 2)

=> (1 3 4 6 8)

SYNOPSIS

(defun remove-more (list test &rest remove)

utilities/replace-elements [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Replace the elements in list between start and end (inclusive) with the new
 list.

ARGUMENTS

 - A list.
 - An integer that is first position of the segment of the original list to
   be replaced.
 - An integer that is the last position of the segment of the original list
   to be replaced.
 - A list that is to replace the specified segment of the original
   list. This list can be of a different length than that of the segment
   of the original specified by the start and end positions.

RETURN VALUE

 A list.

EXAMPLE

(replace-elements '(1 2 3 4 5 6 7 8 9) 3 7 '(dog cat goldfish))

=> (1 2 3 DOG CAT GOLDFISH 9)

SYNOPSIS

(defun replace-elements (list start end new)

utilities/rescale [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DATE

 June 8th 2016, Edinburgh

DESCRIPTION

 Given a value within an original range, return its value withing a new range

ARGUMENTS

 - the value we want to rescale
 - the original minimum
 - the original maximum
 - the new minimum
 - the new maximum

RETURN VALUE

 The value within the new range (a number)

EXAMPLE

(rescale .5 0 1 0 100)
==> 50.0

SYNOPSIS

(defun rescale (val min max new-min new-max)

utilities/round-if-close [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Round a decimal number if it is within a given tolerance to the next whole
 number. 

ARGUMENTS

 - A decimal number.

OPTIONAL ARGUMENTS

 - If the given number is this amount or less than the nearest whole number,
   round the given number to the nearest whole number.

RETURN VALUE

 If the given number is within the tolerance, return the number, otherwise
 return the nearest whole number.

EXAMPLE

(round-if-close 1.999998)

=> 1.999998

(round-if-close 1.999999)

=> 2

SYNOPSIS

(defun round-if-close (num &optional (tolerance 0.000001))

utilities/scale-env [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Scale either the x-axis values, the data values, or both of a list of
 break-point pairs by specified factors.

ARGUMENTS

 - An envelope in the form of a list of break-point pairs.
 - A number that is the factor by which the y values (data segment of the
   break-point pairs) are to be scaled.

OPTIONAL ARGUMENTS

 keyword arguments:
 - :y-min. A number that is the minimum value for all y values after
   scaling.  NB The -min/-max arguments are hard-limits only; they do not
   factor into the arithmetic.
 - :y-max. A number that is the maximum value for all y values after
   scaling.
 - :x-scaler. A number that is the factor by which to scale the x-axis
   values of the break-point pairs.
 - :x-min. A number that is the minimum value for all x values after
   scaling. NB: This optional argument can only be used if a value has been
   specified for the :x-scaler. 
 - :x-max. A number that is the maximum value for all x values after
   scaling. NB: This optional argument can only be used if a value has been
   specified for the :x-scaler.

RETURN VALUE

 An envelope in the form of a list of break-point pairs.

EXAMPLE

;;; Scaling only the y values.
(scale-env '(0 53 25 189 50 7 75 200 100 3) 0.5)

=> (0 26.5 25 94.5 50 3.5 75 100.0 100 1.5)

;;; Scaling the y values and setting a min and max for those values
(scale-env '(0 53 25 189 50 7 75 200 100 3) 0.5 :y-min 20 :y-max 100)

=> (0 26.5 25 94.5 50 20 75 100 100 20)

;;; Scaling only the x-axis values
(scale-env '(0 53 25 189 50 7 75 200 100 3) 1.0 :x-scaler 2)

=> (0 53.0 50 189.0 100 7.0 150 200.0 200 3.0)

;;; Scaling the x values and setting a min and max for those values
(scale-env '(0 53 25 189 50 7 75 200 100 3) 1.0 :x-scaler 2 :x-min 9 :x-max 90)

=> (9 53.0 50 189.0 90 7.0 90 200.0 90 3.0)

SYNOPSIS

(defun scale-env (env y-scaler &key x-scaler 
                                    (x-min most-negative-double-float)
                                    (y-min most-negative-double-float)
                                    (x-max most-positive-double-float)
                                    (y-max most-positive-double-float))

utilities/secs-to-mins-secs [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Convert a number of seconds into a string of the form "24:41.723" where
 seconds are always rounded to three decimal places (i.e. milliseconds).

ARGUMENTS

 - the number of seconds

OPTIONAL ARGUMENTS

 keyword arguments:
 - :post-mins. The string used to separate minutes and seconds. Default ":"
 - :post-secs. The string used to separate seconds and milliseconds.
    Default "." 
 - :post-msecs. The string used to follow milliseconds. Default "" 
 - :same-width. Ensure minutes values are always two characters wide, like
   seconds, i.e with a leading 0.
 - :round. Round to the nearest second and don't print milliseconds. Default
   NIL. 

RETURN VALUE

 A string

EXAMPLE

(secs-to-mins-secs 77.1232145)
"1:17.123"
(secs-to-mins-secs 67.1)
"1:07.100"
(secs-to-mins-secs 67.1 :same-width t)
"01:07.100"
(secs-to-mins-secs 67.1 :same-width t :post-secs "s")
"01:07s100"
(secs-to-mins-secs 67.1 :post-secs "secs" :post-mins "min" :post-msecs "msecs")
"1min07secs100msecs"
(secs-to-mins-secs 67.7 :same-width t :round t)
"01:08"

SYNOPSIS

(defun secs-to-mins-secs (seconds &key
                                    round
                                    (post-mins ":")
                                    (post-secs ".")
                                    (post-msecs "")
                                    (same-width nil))

utilities/semitones [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Return the sample-rate conversion factor required for transposing an audio
 file by a specific number of semitones. The number of semitones can be
 given as a decimal number, and may be positive or negative.

ARGUMENTS

 - A number of semitones.

OPTIONAL ARGUMENTS

 - A number that is the factor required to transpose by an octave. 
   Default = 2.0.
 - A number that is the number of semitones per octave. Default = 12. 

RETURN VALUE

 A number.

EXAMPLE

;;; Usage with default values
(semitones 3)

=> 1.1892071

;;; Specifying a different number of semitones per octave
(semitones 3 2.0 13)

=> 1.1734605

;;; Specifying a different factor for transposing by an octave 
(semitones 3 4.0)

=> 1.4142135

;;; Fractional semitones are allowed
(semitones 3.72)

=> 1.2397077

;;; Negative semitones are also allowed
(semitones -3.72)

=> 0.80664176

SYNOPSIS

(defun semitones (st &optional (octave-size 2.0) (divisions-per-octave 12))

utilities/setf-last [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Change the last element in a given list to a specified new element.

ARGUMENTS

 - A list.
 - The new last element of that list.

RETURN VALUE

 Returns the new last element.

EXAMPLE

(let ((l '(1 2 3 4 5)))
  (setf-last l 'dog)
  l)

=> (1 2 3 4 DOG)

SYNOPSIS

(defmacro setf-last (list new-last)

utilities/sort-symbol-list [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Sort a list of symbols alphabetically ascending, case-insensitive. 

ARGUMENTS

 A list of symbols.

RETURN VALUE

 The same list of symbols sorted alphabetically ascending, case-insensitive.

EXAMPLE

(sort-symbol-list '(Lorem ipsum dolor sit amet consectetur adipiscing))

=> (ADIPISCING AMET CONSECTETUR DOLOR IPSUM LOREM SIT)

SYNOPSIS

(defun sort-symbol-list (list)

utilities/splice [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Insert the elements of a first list into a second list beginning at a
 specified index (0-based).

ARGUMENTS

 - A list that contains the elements to be inserted into the second list.
 - A list into which the elements of the first argument are to be inserted. 
 - An integer that is the index within the second list where the elements
   are to be inserted.

RETURN VALUE

 - A list.

EXAMPLE

(splice '(dog cat goldfish) '(1 2 3 4 5 6 7 8 9) 3)

=> (1 2 3 DOG CAT GOLDFISH 4 5 6 7 8 9)

SYNOPSIS

(defun splice (elements into-list where)

utilities/split-groups [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Create a list consisting of as many repetitions of a specified number as
 will fit into a given greater number, with the last item in the new list
 being the value of any remainder.

ARGUMENTS

 - A number that is to be split into repetitions of a specified smaller
   number (the second argument).
 - The number that is to be the repeating item in the new list. This number
   must be smaller than the first number.

RETURN VALUE

 A list consisting of repetitions of the specified number, with the last
 element being any possible remainder.

EXAMPLE

(split-groups 101 17)

=> (17 17 17 17 17 16)

SYNOPSIS

(defun split-groups (num divider)

utilities/split-into-sub-groups [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Create a new list consisting of sublists made from the elements of the
 original flat list, whose lengths are determined by the second argument to
 the function.

 NB: The lengths given in the second argument are not required to add up to
     the length of the original list. If their sum is less than the original
     list, the resulting list of sublists will only contain a segment of the
     original elements. If their sum is greater than the length of the
     original list, the last sublist in the new list will be shorter than
     the corresponding group value.

ARGUMENTS

 - A flat list.
 - A list of integers that are the lengths of the consecutive subgroups
   into which the original list is to be divided. 

RETURN VALUE

 A list of lists.

EXAMPLE

;; Used with a list of subgroup lengths whose sum is equal to the length of the
;; original list
(split-into-sub-groups '(1 2 3 4 5 6 7 8 9 10) '(2 2 3 2 1))

=> ((1 2) (3 4) (5 6 7) (8 9) (10))

;; Used with a list of subgroup lengths whose sum is less than the length of the
;; original list 
(split-into-sub-groups '(1 2 3 4 5 6 7 8 9 10) '(2 1))

=> ((1 2) (3))

;; Used with a list of subgroup lengths whose sum is greater than the length of
;; the original list
(split-into-sub-groups '(1 2 3 4 5 6 7 8 9 10) '(2 3 17))

=> ((1 2) (3 4 5) (6 7 8 9 10))

SYNOPSIS

(defun split-into-sub-groups (list groups)

utilities/split-into-sub-groups2 [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Create a new list of lists by splitting the original flat list into
 sublists of the specified length.

 NB: The length given as the second argument is not required to be fit
     evenly into the length of the original flat list. If the original list
     is not evenly divisible by the specified length, the resulting list of
     sublists will contain a final sublist of a different length.

ARGUMENTS

 - A flat list.
 - An integer that is the length of each of the sublists to be created.

RETURN VALUE

 A list of lists.

EXAMPLE

;; The second argument fits evenly into the length of the original list. 
(split-into-sub-groups2 '(1 2 3 4 5 6 7 8 9 10 11 12) 3)

=> ((1 2 3) (4 5 6) (7 8 9) (10 11 12))

;; The second argument does not fit evenly into the length of the original
;; list. 

(split-into-sub-groups2 '(1 2 3 4 5 6 7 8 9 10 11 12) 5)

=> ((1 2 3 4 5) (6 7 8 9 10) (11 12))

SYNOPSIS

(defun split-into-sub-groups2 (list length)

utilities/split-into-sub-groups3 [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Split a given flat list into sublists of the specified length, putting any
 remaining elements, if there are any, into the last sublist.

ARGUMENTS

 - A flat list.
 - An integer that is the length of the new sublists.

RETURN VALUE

 A list of lists.

EXAMPLE

(split-into-sub-groups3 '(1 2 3 4 5 6 7 8 9 10 11 12) 3)

=> ((1 2 3) (4 5 6) (7 8 9) (10 11 12))

(split-into-sub-groups3 '(1 2 3 4 5 6 7 8 9 10 11 12) 5)

=> ((1 2 3 4 5) (6 7 8 9 10 11 12))

SYNOPSIS

(defun split-into-sub-groups3 (list length)

utilities/srt [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Return the semitone transposition for a given sampling rate conversion
 factor.

ARGUMENTS

 - A number that is a sample-rate conversion factor.

OPTIONAL ARGUMENTS

 - A number that is the factor required for transposing one octave. 
 - A number that is the number of scale degrees in an octave.

RETURN VALUE

 A number.

EXAMPLE

;;; Using the defaults
(srt 1.73)

=> 9.4893

;;; Using a sample-rate conversion factor of 4.0 for the octave and specifying
;;; 13 divisions of the octave
(srt 1.73 4.0 13)

=> 5.14

SYNOPSIS

(let ((last8vesize 0)
      (log8ve 0.0)) ;; so we don't have to recalculate each time
  (defun srt (srt &optional (octave-size 2.0) (divisions-per-octave 12)
              ;; MDE Tue Feb  7 16:59:45 2012 -- round so we don't get tiny
              ;; fractions of semitones due to float inaccuracies?
              (round-to 0.0001))

utilities/string-replace [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Replace specified segments of a string with a new specified string.

ARGUMENTS

 - A string that is the string segment to be replaced.
 - A string that is the string with which the specified string segment is to
   be replaced.
 - The string in which the specified segment is to be sought and replaced.

RETURN VALUE

 A string.

EXAMPLE

(string-replace "flat" "\\flat" "bflat clarinet")

=> "b\\flat clarinet"

SYNOPSIS

(defun string-replace (what with string)

utilities/swap-elements [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Swap the order of each consecutive pair of elements in a list.

ARGUMENTS

 - A list.

RETURN VALUE

 A list.

EXAMPLE

(swap-elements '(1 2 3 4 5 6 7 8 9 10))

=> (2 1 4 3 6 5 8 7 10 9)

(swap-elements '(1 2 3 4 5 6 7 8 9))

=> (2 1 4 3 6 5 8 7 9)

SYNOPSIS

(defun swap-elements (list)

utilities/update-app-src [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DATE

 June 1st 2013

DESCRIPTION

 NB This function currently works in SBCL and CCL on UNIX systems only.
 
 For users of the slippery chicken app, this function will update the source
 code of the app to the latest in the online subversion (svn) repository.
 An internet connection is therefore necessary.  

 The first time it is run it will delete the current source code and
 download all the new source code, so make sure to back up if you've
 modified the source code yourself (not recommended).  When it is run from
 then on, it will only update the source code that is out of date.

 Once the source code is updated, you'll need to restart the app or just
 Lisp for the changes to be recompiled. 
 
 **NB** The first time you call this function, you might get a "certificate
 error".  In order to accept the certificate, start the terminal application
 and type the following:
 
 cd /tmp/
 svn co https://svn.ecdf.ed.ac.uk/repo/user/medward2/sc-tags/sc-latest/src
 
 That should give you a prompt in the terminal from which you can accept the
 certificate.  Then the next time you try it from Lisp the certificate
 should not cause a problem.
 
 Users without the app can always download the latest source code in a
 terminal by issuing the following command.
 svn co https://svn.ecdf.ed.ac.uk/repo/user/medward2/sc-tags/sc-latest/src

ARGUMENTS

 The full path to the slippery-chicken application, minus the last slash.
 Remember that this can't include any spaces in file/folder names 

OPTIONAL ARGUMENTS

 keyword arguments:
 - :rm.  The path to the shell 'rm' command.  Default = "/bin/rm"
 - :svn.  The path to the shell 'svn' command.  Default = "/usr/bin/svn"

RETURN VALUE

 The shell return value of the call to SVN, usually 0 on success.

EXAMPLE

Running for the first time:
(update-app-src "/tmp/sc-app/slippery-chicken.app")
A    /tmp/sc-app/slippery-chicken.app/Contents/Resources/sc/src/sndfile.lsp
A    /tmp/sc-app/slippery-chicken.app/Contents/Resources/sc/src/osc.lsp
A    /tmp/sc-app/slippery-chicken.app/Contents/Resources/sc/src/osc-sc.lsp
[...]
Checked out revision 3608.
0

or after successfully updating a previously updated version:
...
At revision 3608.
0

SYNOPSIS

(defun update-app-src (path-to-app &key (rm "/bin/rm") (svn "/usr/bin/svn"))

utilities/wavelab-to-audacity-marker-file [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Write a .txt file suitable for import to audacity with the same name and in
 the same directory as the file argument.

ARGUMENTS

 - A string that is the name of a wavelab marker file, including directory
   path and extension.

OPTIONAL ARGUMENTS

 - An integer that is the sampling rate of the sound file to which the
   wavelab marker file refers. This value will affect the times of the
   output. 

RETURN VALUE

 Returns T and prints the number of markers read to the listener. 

EXAMPLE

(wavelab-to-audacity-marker-file "/path/to/24-7.mrk"  44100)

=> 51 markers read

SYNOPSIS

(defun wavelab-to-audacity-marker-file (file &optional (sampling-rate 44100))

utilities/wrap-list [ Functions ]

[ Top ] [ utilities ] [ Functions ]

DESCRIPTION

 Shift the elements of a list to start at a specified position and wrap to
 the beginning of the list to the list's tail.

ARGUMENTS

 - A list.
 - An integer which is the 0-based position in the original list where the
   new list is to begin.

RETURN VALUE

 A list.

EXAMPLE

(wrap-list '(1 2 3 4 5 6 7 8 9) 4)

=> (5 6 7 8 9 1 2 3 4)

SYNOPSIS

(defun wrap-list (list start)