./../../src/player.lsp

## linked-named-object/player [ Classes ]

[ Top ] [ linked-named-object ] [ Classes ]

NAME

     player

     File:             player.lsp

     Class Hierarchy:  named-object -> linked-named-object -> player

     Version:          1.0.3

     Project:          slippery chicken (algorithmic composition)

     Purpose:          Implementation of the player class which holds an
                       instrument or a assoc-list of instruments in it's data
                       slot.

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

     Creation date:    7th September 2001

     $$ Last modified: 16:26:58 Tue Jul  3 2012 BST

     SVN ID: $Id: player.lsp 3940 2013-06-19 10:04:04Z medward2 $

## player/make-player [ Functions ]

[ Top ] [ player ] [ Functions ]

DESCRIPTION

     Create a player object from a specified instrument-palette object and a
     specified instrument or list of instruments which that player plays.

     The player object is separate from the instrument object as on player in an
     ensemble may perform more than one instrument ("double"), such as flute and
     piccolo, clarinet and bass clarinet, or sax, flute and clarinet.

ARGUMENTS

     - A symbol which will be the ID of the resulting player object.
     - An instrument-palette object.
     - A symbol or a list of symbols that are the instruments from the
       specified instrument-palette object that the given player will play, as
       spelled and defined within the instrument-palette object. NB: If only one
       instrument is to be assigned to the given player, it should be stated as
       symbol rather than a list, to avoid errors in the DOUBLES slot.

OPTIONAL ARGUMENTS

     keyword arguments:
     - :midi-channel. An integer that indicates the MIDI channel on which any
       non-microtonal pitch material for this player is to be played
       back. Default = 1.
     - :microtones-midi-channel. An integer that indicates the MIDI channel on
       which any microtonal pitch material for this player is to be played
       back. slippery chicken uses this channel to add MIDI pitch-bends via CM
       so that microtonal chords are possible, but due to a current glitch these
       tracks contain no pitch-bend data. A work-around for this is to simply
       open the MIDI file in a sequencer and shift the entire channel by the
       desired pitch-bend value. Default = -1.
     - :cmn-staff-args. A list of pairs that indicate any additional arguments
       to the call to cmn::staff for this player, such as staff size, number of
       lines etc. Instead of being real cmn function calls, as they would be in
       normal cmn, this is a simple list of pairs; e.g. '(staff-size .8
       staff-lines 3). Defaults = NIL.

RETURN VALUE

     Returns a player object.

EXAMPLE

    ;; Create a player object with just one instrument object
    (let ((ip (make-instrument-palette
                'inst-pal
                '((picc (:transposition-semitones 12 :lowest-written d4
                         :highest-written c6))
                  (flute (:lowest-written c4 :highest-written d7))
                  (clar (:transposition-semitones -2 :lowest-written e3
                         :highest-written c6))
                  (horn (:transposition f :transposition-semitones -7
                         :lowest-written f2 :highest-written c5))
                  (vln (:lowest-written g3 :highest-written c7 :chords t))
                  (vla (:lowest-written c3 :highest-written f6 :chords t))))))
      (make-player 'player-one ip 'flute))

    =>
    PLAYER: (id instrument-palette): INST-PAL
    doubles: NIL, cmn-staff-args: NIL
    LINKED-NAMED-OBJECT: previous: NIL, this: NIL, next: NIL
    NAMED-OBJECT: id: PLAYER-ONE, tag: NIL,
    data:
    INSTRUMENT: lowest-written:
    [...]
    NAMED-OBJECT: id: FLUTE, tag: NIL,
    data: NIL

    ;; Create a player object with two instruments, setting the midi channels using
    ;; the keyword arguments, then print the corresponding slots to see the changes
    (let* ((ip (make-instrument-palette
                'inst-pal
                '((picc (:transposition-semitones 12 :lowest-written d4
                         :highest-written c6))
                  (flute (:lowest-written c4 :highest-written d7))
                  (clar (:transposition-semitones -2 :lowest-written e3
                         :highest-written c6))
                  (horn (:transposition f :transposition-semitones -7
                         :lowest-written f2 :highest-written c5))
                  (vln (:lowest-written g3 :highest-written c7 :chords t))
                  (vla (:lowest-written c3 :highest-written f6 :chords t)))))
           (plr (make-player 'player-one ip '(flute picc)
                             :midi-channel 1
                             :microtones-midi-channel 2)))
      (print (loop for i in (data (data plr)) collect (id i)))
      (print (midi-channel plr))
      (print (microtones-midi-channel plr)))

    =>
    (FLUTE PICC)
    1
    2

    ;;; With specified cmn-staff-args
    (let ((ip (make-instrument-palette
               'inst-pal
               '((picc (:transposition-semitones 12 :lowest-written d4
                        :highest-written c6))
                 (flute (:lowest-written c4 :highest-written d7))
                 (clar (:transposition-semitones -2 :lowest-written e3
                        :highest-written c6))
                 (horn (:transposition f :transposition-semitones -7
                        :lowest-written f2 :highest-written c5))
                 (vln (:lowest-written g3 :highest-written c7 :chords t))
                 (vla (:lowest-written c3 :highest-written f6 :chords t))))))
      (make-player 'player-one ip '(flute picc)
                   :midi-channel 1
                   :microtones-midi-channel 2
                   :cmn-staff-args '(staff-size .8 staff-lines 3)))

    =>
    PLAYER: (id instrument-palette): INST-PAL
    doubles: T, cmn-staff-args: (#<SELF-ACTING {10097B6E73}>
                                 #<SELF-ACTING {10097B6EE3}>), total-notes: 0, total-degrees: 0,
    total-duration: 0.000, total-bars: 0, tessitura: NIL
    LINKED-NAMED-OBJECT: previous: NIL, this: NIL, next: NIL
    NAMED-OBJECT: id: PLAYER-ONE, tag: NIL,
    data:
    [...]

SYNOPSIS

    (defun make-player (id instrument-palette instruments
                        &key (cmn-staff-args nil)
                             (microtones-midi-channel -1) (midi-channel 1))

## player/microtonal-chords-p [ Methods ]

[ Top ] [ player ] [ Methods ]

DESCRIPTION

     Determines whether the MICROTONES-MIDI-CHANNEL slot of the given player
     object is set to a value greater than 0, indicating that the player and its
     instrument are capable of performing microtonal chords.

ARGUMENTS

     - A player object.

RETURN VALUE

     Returns T if the value stored in the MICROTONES-MIDI-CHANNEL slot of the
     given player object is greater than 0, otherwise returns NIL.

EXAMPLE

    ;; Returns T
    (let* ((ip +slippery-chicken-standard-instrument-palette+)
           (plr (make-player 'vln ip 'violin :microtones-midi-channel 2)))
      (microtonal-chords-p plr))

    => T

    ;; Returns NIL
    (let* ((ip +slippery-chicken-standard-instrument-palette+)
           (plr (make-player 'pno ip 'piano)))
      (microtonal-chords-p plr))

    => NIL

SYNOPSIS

    (defmethod microtonal-chords-p ((p player))
      (> (microtones-midi-channel p) 0))

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    (defmethod score-write-bar-line ((p player))
      (let* ((data (data p))
             (ins (if (typep data 'assoc-list)
                      (first (data data))
                    data)))
        (score-write-bar-line ins)))

## player/player-get-instrument [ Methods ]

[ Top ] [ player ] [ Methods ]

DESCRIPTION

     Get the instrument object assigned to a single-instrument player object or
     get the specified instrument object assigned to a multiple-instrument
     player object.

     NB: This method will drop into the debugger with an error if no optional
         argument is supplied when applying the method to a multiple-instrument
         player object. It will also print a warning when supplying an optional
         argument to a player object that contains only one instrument object.

ARGUMENTS

     - A player object.

OPTIONAL ARGUMENTS

     - Actually a required object for multiple-instrument player objects: The
       symbol that is the ID of the sought-after instrument object, as it
       appears in the instrument-palette with which the player object which
       made. If the given player object consists of only one instrument object,
       this argument is disregarded and a warning is printed.

RETURN VALUE

     Returns an instrument object.

EXAMPLE

    ;; Returns an instrument object. Needs no optional argument when applied to a
    ;; player object that contains only one instrument object
    (let* ((ip +slippery-chicken-standard-instrument-palette+)
           (plr (make-player 'pno ip 'piano)))
       (player-get-instrument plr))

    =>
    INSTRUMENT:
    [...]
    NAMED-OBJECT: id: PIANO, tag: NIL,
    data: NIL

    ;; Returns the only existing instrument object and prints a warning if using
    ;; the optional argument when applying to a single-instrument player object
    (let* ((ip +slippery-chicken-standard-instrument-palette+)
           (plr (make-player 'pno ip 'piano)))
      (id (player-get-instrument plr 'piano)))

    => PIANO
    WARNING:
       player::player-get-instrument: player PNO has only 1 instrument so optional
    argument PIANO is being ignored

    ;; Asking for a non-existent instrument obect from a single-instrument player
    ;; object returns the only existing instrument object instead
    (let* ((ip +slippery-chicken-standard-instrument-palette+)
           (plr (make-player 'pno ip 'piano)))
      (id (player-get-instrument plr 'marimba)))

    => PIANO
    WARNING:
       player::player-get-instrument: player PNO has only 1 instrument so optional
    argument PIANO is being ignored

    ;; The ID desired instrument object must be specified when applying the method
    ;; to a multiple-instrument player object
    (let* ((ip +slippery-chicken-standard-instrument-palette+)
           (plr (make-player 'percussion ip '(marimba vibraphone))))
      (id (player-get-instrument plr 'marimba)))

    => MARIMBA

    ;; Interrupts and drops into the debugger when the optional argument is omitted
    ;; in applying the method to a multiple-instrument player object
    (let* ((ip +slippery-chicken-standard-instrument-palette+)
           (plr (make-player 'percussion ip '(marimba vibraphone))))
       (player-get-instrument plr))

    =>
    player::player-get-instrument: PERCUSSION doubles so you need to pass the ID of
    the instrument you want.
       [Condition of type SIMPLE-ERROR]

SYNOPSIS

    (defmethod player-get-instrument ((p player) &optional ins (warn t))

## player/plays-transposing-instrument [ Methods ]

[ Top ] [ player ] [ Methods ]

DESCRIPTION

     Determine whether a given player object has one or more transposing
     instrument objects assigned to it.

ARGUMENTS

     - A player object.

OPTIONAL ARGUMENTS

     - T or NIL to indicate whether instruments that transpose at the octave are
       to be considered transposing instruments.  T = instruments that transpose
       at the octave are not considered transposing instruments. Default = T.

RETURN VALUE

     Returns T if one or more of the instrument objects assigned to the given
     player object has a transposition value other than C or a
     transposition-semitones value other than 0.

EXAMPLE

    ;; Create a player object using the 'b-flat-clarinet instrument object
    ;; definition from the default +slippery-chicken-standard-instrument-palette+,
    ;; then apply the method.
    (let* ((ip +slippery-chicken-standard-instrument-palette+)
           (plr (make-player 'cl ip 'b-flat-clarinet)))
      (plays-transposing-instrument plr))

    => T

    ;; Create a player object using the 'flute instrument object definition from
    ;; the default +slippery-chicken-standard-instrument-palette+, then apply the
    ;; method.
    (let* ((ip +slippery-chicken-standard-instrument-palette+)
           (plr (make-player 'fl ip 'flute)))
      (plays-transposing-instrument plr))

    => NIL

    ;; Although the intended procedure is to list single instruments as once-off
    ;; symbols (as in the previous example), single instruments can also be added
    ;; as a one-item list
    (let* ((ip +slippery-chicken-standard-instrument-palette+)
           (plr (make-player 'fl ip '(flute))))
      (doubles plr))

    => NIL

    ;; Create a player object using a list that consists of the 'flute and
    ;; 'alto-sax instrument object definitions from the default
    ;; +slippery-chicken-standard-instrument-palette+, then apply the method to see
    ;; that it returns T even when only one of the instruments is transposing.
    (let* ((ip +slippery-chicken-standard-instrument-palette+)
           (plr (make-player 'fl ip '(flute alto-sax))))
      (plays-transposing-instrument plr))

    => T

    ;; Setting the optional argument to NIL causes instruments that transpose at
    ;; the octave to return T.
    (let* ((ip +slippery-chicken-standard-instrument-palette+)
           (plr (make-player 'db ip 'double-bass)))
      (plays-transposing-instrument plr))

    => NIL

    (let* ((ip +slippery-chicken-standard-instrument-palette+)
           (plr (make-player 'db ip 'double-bass)))
      (plays-transposing-instrument plr nil))

    => T

SYNOPSIS

    (defmethod plays-transposing-instrument ((p player)
                                             &optional (ignore-octaves t) ignore)

## player/tessitura-degree [ Methods ]

[ Top ] [ player ] [ Methods ]

DESCRIPTION

     Return a number that represents the average pitch for a specified
     instrument over the course of a piece. The number returned will be degrees
     in the current scale.

ARGUMENTS

     - A player object.

RETURN VALUE

     A number that is the tessitura-degree; i.e., average pitch of the given
     instrument for the entirety of the given musical data.

EXAMPLE

    (let ((mini
           (make-slippery-chicken
            '+mini+
            :ensemble '(((vn (violin :midi-channel 1))
                         (va (violin :midi-channel 2))
                         (vc (cello :midi-channel 3))))
            :set-palette '((1 ((gs3 as3 b3 cs4 ds4 e4 fs4 gs4 as4 b4 cs5))))
            :set-map '((1 (1 1 1 1 1)))
            :rthm-seq-palette '((1 ((((2 4) q (e) s (32) 32))
                                    :pitch-seq-palette ((1 2 3)))))
            :rthm-seq-map '((1 ((vn (1 1 1 1 1))
                                (va (1 1 1 1 1))
                                (vc (1 1 1 1 1))))))))
      (tessitura-degree (get-data 'vc (ensemble mini))))

    => 136

SYNOPSIS

    (defmethod tessitura-degree ((p player))

## player/tessitura-note [ Methods ]

[ Top ] [ player ] [ Methods ]

DESCRIPTION

     Return the value of the TESSITURA-DEGREE slot of a specified player object
     as a note-name symbol.

ARGUMENTS

     - A player object.

RETURN VALUE

     - A note-name symbol.

EXAMPLE

    (in-scale :chromatic)

    (let ((mini
           (make-slippery-chicken
            '+mini+
            :ensemble '(((vn (violin :midi-channel 1))
                         (va (violin :midi-channel 2))
                         (vc (cello :midi-channel 3))))
            :set-palette '((1 ((gs3 as3 b3 cs4 ds4 e4 fs4 gs4 as4 b4 cs5))))
            :set-map '((1 (1 1 1 1 1)))
            :rthm-seq-palette '((1 ((((2 4) q (e) s (32) 32))
                                    :pitch-seq-palette ((1 2 3)))))
            :rthm-seq-map '((1 ((vn (1 1 1 1 1))
                                (va (1 1 1 1 1))
                                (vc (1 1 1 1 1))))))))
      (tessitura-note (first (data (ensemble mini)))))

    => BF3

SYNOPSIS

    (defmethod tessitura-note ((p player))

## player/total-bars [ Methods ]

[ Top ] [ player ] [ Methods ]

DESCRIPTION

     Return the number of bars in a specified player object.

ARGUMENTS

     - A player object.

RETURN VALUE

     - An integer.

EXAMPLE

    (let ((mini
           (make-slippery-chicken
            '+mini+
            :ensemble '(((vn (violin :midi-channel 1))
                         (va (violin :midi-channel 2))
                         (vc (cello :midi-channel 3))))
            :set-palette '((1 ((gs3 as3 b3 cs4 ds4 e4 fs4 gs4 as4 b4 cs5))))
            :set-map '((1 (1 1 1 1 1)))
            :rthm-seq-palette '((1 ((((2 4) q (e) s (32) 32))
                                    :pitch-seq-palette ((1 2 3)))))
            :rthm-seq-map '((1 ((vn (1 1 1 1 1))
                                (va (1 1 1 1 1))
                                (vc (1 1 1 1 1))))))))
      (total-bars (first (data (ensemble mini)))))

    => 5

SYNOPSIS

    (defmethod total-bars ((p player))

## player/total-degrees [ Methods ]

[ Top ] [ player ] [ Methods ]

DESCRIPTION

     Return a number that reflects the mean note (tessitura) of a player's
     part. This is calculated by incrementing the TOTAL-DEGREES slot of the
     corresponding instrument object for each attacked note in the player's part
     by the degree of that note (in the scale of the piece), and then dividing
     the sum by the total number of notes in the player's part.

ARGUMENTS

     - A player object.

RETURN VALUE

     - An integer.

EXAMPLE

    (in-scale :chromatic)

    (let ((mini
           (make-slippery-chicken
            '+mini+
            :ensemble '(((vn (violin :midi-channel 1))
                         (va (violin :midi-channel 2))
                         (vc (cello :midi-channel 3))))
            :set-palette '((1 ((gs3 as3 b3 cs4 ds4 e4 fs4 gs4 as4 b4 cs5))))
            :set-map '((1 (1 1 1 1 1)))
            :rthm-seq-palette '((1 ((((2 4) q (e) s (32) 32))
                                    :pitch-seq-palette ((1 2 3)))))
            :rthm-seq-map '((1 ((vn (1 1 1 1 1))
                                (va (1 1 1 1 1))
                                (vc (1 1 1 1 1))))))))
      (total-degrees (first (data (ensemble mini)))))

    => 865

SYNOPSIS

    (defmethod total-degrees ((p player))

## player/total-duration [ Methods ]

[ Top ] [ player ] [ Methods ]

DESCRIPTION

     Get the total duration of played notes for a given player over the span of
     a piece.

ARGUMENTS

     - A player object.

RETURN VALUE

     A number that is the total duration in seconds of played notes.

EXAMPLE

    (let ((mini
           (make-slippery-chicken
            '+mini+
            :ensemble '(((vn (violin :midi-channel 1))
                         (va (violin :midi-channel 2))
                         (vc (cello :midi-channel 3))))
            :set-palette '((1 ((gs3 as3 b3 cs4 ds4 e4 fs4 gs4 as4 b4 cs5))))
            :set-map '((1 (1 1 1 1 1)))
            :rthm-seq-palette '((1 ((((2 4) q (e) s (32) 32))
                                    :pitch-seq-palette ((1 2 3))))
                                (2 ((((2 4) (q) e (s) 32 32))
                                    :pitch-seq-palette ((1 2 3)))))
            :rthm-seq-map '((1 ((vn (1 1 1 1 1))
                                (va (2 2 2 2 2))
                                (vc (1 2 1 2 1))))))))
      (print (total-duration (get-data 'vn (ensemble mini))))
      (print (total-duration (get-data 'va (ensemble mini))))
      (print (total-duration (get-data 'vc (ensemble mini)))))

    =>
    6.875
    3.75
    5.625

SYNOPSIS

    (defmethod total-duration ((p player))

## player/total-notes [ Methods ]

[ Top ] [ player ] [ Methods ]

DESCRIPTION

     Get the total number of notes played by a specified player.

ARGUMENTS

     - A player object.

RETURN VALUE

     - An integer that is the number of notes for that player.

EXAMPLE

    (let ((mini
           (make-slippery-chicken
            '+mini+
            :ensemble '(((vn (violin :midi-channel 1))
                         (va (violin :midi-channel 2))
                         (vc (cello :midi-channel 3))))
            :set-palette '((1 ((gs3 as3 b3 cs4 ds4 e4 fs4 gs4 as4 b4 cs5))))
            :set-map '((1 (1 1 1 1 1)))
            :rthm-seq-palette '((1 ((((2 4) q (e) s (32) 32))
                                    :pitch-seq-palette ((1 2 3)))))
            :rthm-seq-map '((1 ((vn (1 1 1 1 1))
                                (va (1 1 1 1 1))
                                (vc (1 1 1 1 1))))))))
      (print (total-notes (get-data 'vc (ensemble mini)))))

    => 15

SYNOPSIS

    (defmethod total-notes ((p player))