view base/generics.lisp @ 330:2fbff655ba47 tip

Removed cpitch-adj and cents SQL columns
author Jeremy Gow <jeremy.gow@gmail.com>
date Mon, 21 Jan 2013 11:08:11 +0000
parents 6c57b16a7829
children
line wrap: on
line source
(cl:in-package #:amuse) 

;;; Identifiers

(defgeneric identifier (object))

(defgeneric event-id (object))

(defgeneric composition-id (object))

;;; Pulling compositions from the database 

(defgeneric get-composition (identifier)
  (:documentation "Returns a composition of type dependant on
  identifier"))

(defgeneric get-constituents (constituent-identifier)
  (:documentation "Returns a list of constituents matching the
  criteria in identifier"))

(defgeneric monody (object)
  (:documentation "Returns a monody."))
(defgeneric ensure-monody (object)
  (:documentation "Returns a generalised boolean."))

;;; Getting constituents from compositions
;; IS this the mechanism we want to use
(defgeneric time-signatures (composition)
  (:documentation "Returns all time-signatures in a composition
  Probably shouldn't be exported - can be replaced
  by (get-applicable-time-signature commposition composition)"))
(defgeneric (setf time-signatures) (sequence composition)
  (:documentation "Sets all time-signatures in a composition.
  Is this wanted here?"))
(defgeneric tempi (composition)
  (:documentation "Returns all tempi in a composition Probably
  shouldn't be exported - can be replaced
  by (get-applicable-tempi commposition composition)"))
(defgeneric (setf tempi) (sequence composition)
  (:documentation "Sets all tempi in a composition.
  Is this wanted here?"))
(defgeneric key-signatures (composition)
  (:documentation "Returns all key-signatures in a composition
  Probably shouldn't be exported - can be replaced
  by (get-applicable-key-signature commposition composition)"))
(defgeneric (setf key-signatures) (sequence composition)
  (:documentation "Sets all key sigs in a composition.
  Is this wanted here?"))

;;; Simple Accessors

;; pitch-based

(defgeneric pitch (object &key kind)) ; ? Maybe this returns the pitch
				      ; in its ur form?
(defgeneric chromatic-pitch (pitch))
(defgeneric diatonic-pitch (pitch))
(defgeneric frequency (object)) ;?

(defgeneric octave (pitch)
  (:documentation "Return an integer representing the octave of
pitch where middle c is defined to be the lowest pitch in
octave 4."))

(defgeneric diatonic-pitch-octave (pitch)
  (:documentation "Return an integer representing the diatonic octave
of pitch."))

(defgeneric diatonic-pitch-accidental (pitch)
  (:documentation "Return an integer representing the inflection of a
diatonic pitch where where negative values indicate numbers of flats,
0 indicates natural and positive values indicate numbers of sharps."))

(defgeneric diatonic-pitch-mp (pitch)
  (:documentation "Return an integer representing the morphetic pitch
\(in MIPS terms) of a diatonic pitch."))
(defgeneric diatonic-pitch-cp (pitch)
  (:documentation "Return an integer representing the chromatic pitch
\(in MIPS terms) of a diatonic pitch."))

(defgeneric middle-c (pitch) 
  (:documentation "Returns the value of middle C in the particular
representation of pitch used by PITCH."))
(defgeneric midi-pitch-number (pitch)
  (:documentation "Takes a pitch (usually a pitched event) and
  returns an integer between 0 and 127 representing the chromatic
  pitch represented (60=middle C, 48 the C below that, etc.)"))
(defgeneric asa-pitch-string (pitch)
  (:documentation "Returns a string representing the designated ASA
pitch name which has three parts: a letter name in the set
{A,B,C,D,E,F,G}, an inflection in the set {n,f,s,ff,ss,fff,sss,...}
and an octave number. E.g., Cn4 = Middle C."))
(defgeneric asa-interval-string (pitch)
  (:documentation "Returns a string representing the designated ASA
interval name which has two or three parts: a direction in the set
{r,f} (absent for unisons/primes), a type in the set
{p,ma,mi,a,d,aa,dd,aaa,ddd,...}, and a size number.  E.g. rma2 =
rising major second."))
(defgeneric diatonic-pitch-name (pitch)
  (:documentation "Returns a char in the set
{#\A,#\B,#\C,#\D,#\E,#\F,#\G}, representing the pitch name of
PITCH."))
(defgeneric pitch-class (pitch)
  (:documentation "Takes a pitch (usually a pitched event) and
  returns an integer between 0 and 12 representing the
  octave-independant pitch, with c=0, c#=1, etc.")
  (:method (p) (mod (midi-pitch-number p) 12)))
(defgeneric span (pitch-interval))

;; time

(defgeneric duration (period)
  (:documentation "Returns a real. Probably should only apply do
  standard-periods (rather than periods? or should it return
  something other than a value in other cases)"))
(defgeneric (setf duration) (value period)
  (:documentation "As with duration, perhaps this should work only
  with standard-periods"))
(defgeneric timepoint (moment)
  (:documentation "Returns a number for a moment. Does this make
  any sense on an abstrace class? Should it just apply to
  standard-moment?"))
(defgeneric (setf timepoint) (value moment)
  (:documentation "Sets timepoint. What does this mean for an
 abstract class? Should it just apply to standard-moment"))
(defgeneric cut-off (anchored-period) ; name?
  (:documentation "Returns a <moment> representing the point at
  which the anchored period has ended. By default, is calculated
  as the result of running time+ on the onset and period of the
  object.")
  (:method (apd) (time+ (moment apd) (period apd))))
(defgeneric crotchet (object)
  (:documentation "Returns a period, the duration of which represents
a crotchet in the time representation used by object."))

;; others

;; I've given the time-sig accessors general names because it allows
;; for symbols in time-signatures as well as numbers - numerator is an
;; odd accessor if the time sig is C (even in common practice) but
;; its meaning is clear. beat-units-per-bar is clearer, though, I
;; think.

(defgeneric beat-units-per-bar (time-signature)
  (:documentation "In a standard, fraction-like time-signature or
  a symbolic equivalent, this is the numerator."))
(defgeneric time-signature-numerator (time-signature)
  (:method (ts) (beat-units-per-bar ts))
  (:documentation "Not obviously meaningful for non fraction-like
  time signatures"))
(defgeneric beat-units (time-signature)
  (:documentation "In a standard, fraction-like time-signature or
  a symbolic equivalent, this is the denominator (n.b.  the
  difference between this and @code{tactus-duration} is only
  visible for compound time, where this returns the lower portion
  of the time signature, but @code{tactus-duration} returns the
  higher-level unit)."))
(defgeneric time-signature-denominator (time-signature)
  (:method (ts) (beat-units ts))
  (:documentation "Not obviously meaningful for non fraction-like
  time signatures"))
(defgeneric tactus-duration (time-signature)
  ;; basic, but should do? NO! This defines 6/4 as compound. We need
  ;; proper simplep and compoundp predicates.
  (:method (ts)
    (warn "FIXME: tactus-duration is broken")
    (cond
      ;; ((and (not (= (beat-units-per-bar ts) 3))
      ;; 	    (= (rem (beat-units-per-bar ts) 3) 0))
      ((and (= (beat-units ts) 8)
	    (= (rem (beat-units-per-bar ts) 3) 0))
       ;; compound time
       (* (/ 4 (beat-units ts))
	  3))
      (t (/ 4 (beat-units ts)))))
  (:documentation "Returns a number of crotchets to represent the
  tactus, based on some idea of time signature patterns. Should,
  in future, return a duration rather than a number."))

(defgeneric key-signature-sharps (key-signature)
  (:documentation "Simple query for normal key-signatures."))
(defgeneric key-signature-mode (ks)
  (:documentation "Query that only makes sense for midi-like key
  signatures"))

(defgeneric bpm (tempo)
  (:documentation "Basic tempo query")) ;; in bpm
(defgeneric microseconds-per-crotchet (tempo)
  ;; As used (when rounded) in MIDI
  (:method (tp) (/ 60000000 (bpm tp)))
  (:documentation "Basic tempo query for MIDI. N.B. This will be
  a fraction and must be rounded before being used for output."))

;;; Coerce-type accessors

;; Should I be including these default methods?  Should the accessors
;; be direct slot accessors or the generics I'm using? Should we
;; return the object itself if it already is in the target class?

(defgeneric anchored-period (anchored-period)
  (:method (apd) (make-anchored-period (onset apd) (duration apd)))
  (:documentation "Coerce any anchored period to a plain anchored
  period"))

(defgeneric period (period)
  (:method (pd) (make-period (duration pd)))
  (:documentation "Coerce any period to a floating period"))

(defgeneric moment (moment)
  (:method (md) (make-moment (timepoint md)))
  (:documentation "Coerce any moment, including an
  anchored-period to a moment"))

(defgeneric onset (anchored-period)
  (:method (ap) (moment ap))
  (:documentation "Return a moment for the start of an anchored period"))
(defgeneric (setf onset) (value anchored-period))

;;; Time Protocol (or moments?)

;; negative times/durations -> ERROR? 

;; time+: <time>      <duration> -> <time>
;;        <duration>  <time>     -> <time> (same as previous?) 
;;        <duration>  <duration> -> <duration> (or a distinct duration+?) 
;;        <time>      <time>     -> ERROR? 
;; 
;; time-: <time>      <time>     -> <duration>
;;        <time>      <duration> -> <time> 
;;        <duration>  <duration> -> <duration> (or a distinct duration-?) 
;;        <duration>  <time>     -> ERROR? 
;;        <anchored>  <anchored> -> (time- (moment o1) (moment o2)) ? or error?

(defgeneric time+ (object1 object2)
  (:documentation "Addition for time objects"))
(defgeneric time- (object1 object2)
  (:documentation "Subtraction for time objects"))

(defgeneric time> (object1 object2)
  (:documentation "> operator for moments"))
(defgeneric time< (object1 object2)
  (:documentation "< operator for moments")
  (:method (o1 o2) (time> o2 o1)))
(defgeneric time= (object1 object2)
  (:documentation "= operator for moments")) 
(defgeneric time>= (object1 object2)
  (:documentation ">= operator for moments")
  (:method (o1 o2) (or (time> o1 o2) (time= o1 o2))))
(defgeneric time<= (object1 object2)
  (:documentation "<= operator for moments")
  (:method (o1 o2) (or (time< o1 o2) (time= o1 o2))))
(defgeneric time/= (object1 object2)
  (:documentation "not = operator for moments")
  (:method (o1 o2) (not (time= o1 o2))))

;;; Duration protocol 

(defgeneric duration> (object1 object2)
  (:documentation "> operator for periods"))
(defgeneric duration< (object1 object2)
  (:documentation "< operator for periods")
  (:method (o1 o2) (duration> o2 o1)))
(defgeneric duration= (object1 object2)
  (:documentation "= operator for periods")) 
(defgeneric duration>= (object1 object2) 
  (:documentation ">= operator for periods")
  (:method (o1 o2) (or (duration> o1 o2) (duration= o1 o2))))
(defgeneric duration<= (object1 object2)
  (:documentation "<= operator for periods")
  (:method (o1 o2) (or (duration< o1 o2) (duration= o1 o2))))
(defgeneric duration/= (object1 object2) 
  (:documentation "not = operator for periods")
  (:method (o1 o2) (not (duration= o1 o2))))

;; for linear scaling:
(defgeneric duration* (object1 object2)
  (:documentation "Multiplication operator for
  periods. Intuitively, this makes sense, but it may cause us
  trouble with some implementations in the future."))
(defgeneric duration/ (object1 number)
  (:documentation "Division operator for periods. This may turn
  out not to mean much. Division is probably useful, but we may
  need to define what we mean with care."))

;;; Pitch protocol 

;; pitch+: <pitch>    <pitch>     -> ERROR
;;         <pitch>    <interval>  -> <pitch> 
;;         <interval> <pitch>     -> <pitch> (same as previous?) 
;;         <interval> <interval>  -> <interval> (or a distinct interval+?) 
;; 
;; pitch-: <pitch>    <pitch>     -> <interval>
;;         <pitch>    <interval>  -> <pitch> 
;;         <interval> <interval>  -> <interval>
;;         <interval> <pitch>     -> ERROR 

(defgeneric pitch+ (object1 object2))
(defgeneric pitch- (object1 object2))

(defgeneric pitch> (object1 object2))
(defgeneric pitch< (object1 object2)
  (:method (o1 o2) (pitch> o2 o1)))
(defgeneric pitch= (object1 object2)) 
(defgeneric pitch>= (object1 object2) 
  (:method (o1 o2) (or (pitch> o1 o2) (pitch= o1 o2))))
(defgeneric pitch<= (object1 object2)
  (:method (o1 o2) (or (pitch< o1 o2) (pitch= o1 o2))))
(defgeneric pitch/= (object1 object2) 
  (:method (o1 o2) (not (pitch= o1 o2))))

;;; Interval protocol (emphasise _pitch_ not _time_ interval?) 

(defgeneric interval> (object1 object2))
(defgeneric interval< (object1 object2)
  (:method (o1 o2) (interval> o2 o1)))
(defgeneric interval= (object1 object2)) 
(defgeneric interval>= (object1 object2) 
  (:method (o1 o2) (or (interval> o1 o2) (interval= o1 o2))))
(defgeneric interval<= (object1 object2)
  (:method (o1 o2) (or (interval< o1 o2) (interval= o1 o2))))
(defgeneric interval/= (object1 object2) 
  (:method (o1 o2) (not (interval= o1 o2))))

;;; Allen's (1984) interval relations 
;;;  . equals already defined as INTERVAL= above 
;;;  . inverses ommitted for now (just use CL:NOT) 
;;;  . can all be defined in terms of MEETS (apparently)

(defgeneric meets (object1 object2))
(defgeneric before (object1 object2))
(defgeneric overlaps (object1 object2))
(defgeneric during (object1 object2))
(defgeneric starts (object1 object2))
(defgeneric ends (object1 object2))

;;; and extensions thereof ...

(defgeneric subinterval (object1 object2)
  (:method (o1 o2) (or (starts o1 o2) (during o1 o2) (ends o1 o2))))

(defgeneric disjoint (object1 object2)
  (:method (o1 o2) 
    (or (before o1 o2) (meets o1 o2) (meets o2 o1) (before o2 o1))))

;;; More time-based functions

(defgeneric period= (object1 object2)
  (:method (x y) nil))

(defgeneric find-overlapping (anchored-period sequence)
  ;; Returns all members of a sequence of period signifiers that overlap
  ;; with the supplied period
  (:method (ap s) (remove-if #'(lambda (x) (amuse:disjoint ap x)) s)))

;; Return the anchored-period representing the intersection of two
;; anchored-period.
(defgeneric period-intersection (anchored-period1
				 anchored-period2))

(defgeneric inter-onset-interval (moment1 moment2)
  (:method (moment1 moment2) (time- (moment moment2) (moment moment1))))


;;; Time Signature 

(defgeneric get-applicable-time-signatures (anchored-period composition)
  (:method (ap c) (find-overlapping ap (time-signatures c)))
  (:documentation "Return a list of TIME-SIGNATURE-PERIODs that are
  relevant to <anchored-period>. The period may contain
  information such as staff position and voicing, and the method
  may use this to filter its response"))

(defgeneric time-signature-equal (ts1 ts2)
  (:documentation "Comparison operator. The definition of
  equality is left open for implementers"))

;;; Tempo 

(defgeneric get-applicable-tempi  (anchored-period composition)
  (:method (ap c) (find-overlapping ap (tempi c)))
  (:documentation "Return a list of TEMPO-PERIODs that are
  relevant to <anchored-period>. The period may contain
  information such as staff position and voicing, and the method
  may use this to filter its response"))

(defgeneric tempo-equal (t1 t2)
  (:documentation "Comparison operator. The definition of
  equality is left open for implementers"))

;;; Tonality (Key Signature / Mode) 

(defgeneric get-applicable-key-signatures (object1 object2)
  (:documentation "Return a list of KEY-SIGNATURE-PERIODs that are
  relevant to <anchored-period>. The period may contain
  information such as staff position and voicing, and the method
  may use this to filter its response"))

(defgeneric key-signature-equal (ks1 ks2)
  (:documentation "Comparison operator. The definition of
  equality is left open to implementers"))

;;; Some generic constructors - are these useful? (DL 31/8/07)
(defgeneric make-moment (value)
  (:documentation "Returns MOMENT of subclass appropriate to the
  class of value. Probably guessed."))
(defgeneric make-period (value)
  (:documentation "Returns PERIOD of subclass appropriate to the
  class of value. Probably guessed."))
(defgeneric make-anchored-period (start-value duration-value)
  (:documentation "Returns ANCHORED-PERIOD of subclass
  appropriate to the class of value. Probably guessed."))

 (defgeneric trim-enclosing-silence (composition)
  (:documentation "Returns a composition of the same type as
  composition provided, with leading and following silences/rests
  removed, but preserving all relevant information. Where
  relevant, any silence in a bar containing musical material may
  be preserved."))

;;; Dynamics 
;;; Voice 
;;; Boundary Strength (phrasing) 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Experimental:
;;

;;; Proposed new metre functions
;; These should provide sufficient functionality that the users need
;; not refer to get-applicable-time-signatures unless they really mean
;; it. In turn, this means that barline based representations have a
;; better chance at guessing.

;; Notes:
;; * iteration is possible with
;;     (do ((beat (current-beat (make-moment 0) composition))
;;                (current-beat (cut-off beat) composition))) ...
;;   [That's probably not very efficient. there must be better ways]
;; * gsharp and tabcode can answer bar questions, but not beat
;; questions. Appropriate conditions and restarts will be needed.
;; * a good test of this functionality will prob be amuse-harmony.

(defgeneric bar-period (time-signature implementation-object)
  (:documentation "Returns a <period> with a duration equal to the
  duration of a bar in the given time signature for the given
  implementation. FIXME: this isn't guaranteed to be
  meaningful (double time signatures break this"))
(defgeneric current-bar (moment composition)
  (:documentation "Returns an <anchored-period> representing the
  bar which contains moment"))

(defgeneric beat-period (moment time-signature implementation-object)
  (:documentation "Takes a moment, time signature object and crotchet
  and returns an <anchored-period> for the containing beat containing
  moment. This is more useful when there's a complex time
  signature (not currently possible) in which tactus is different in
  different parts of the bar (e.g. 3+3+2/8)"))
(defgeneric current-beat (moment composition)
  (:documentation "Returns an <anchored-period> representing the
  tactus unit which contains moment"))

(defgeneric ioi-from-bar (moment)
  (:documentation "Returns the IOI of moment (i.e. an event) from the
  bar line."))

(defgeneric onset-in-bar (moment)
  (:documentation "The position of moment in the bar, measured in
  beats."))

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

(defgeneric get-applicable-clefs (anchored-period constituent))

;;;=====================================================================
;;; Copying events in time
;;;=====================================================================

(defgeneric move-to-first-bar (composition))

(defgeneric copy-event (event))

(defgeneric voice (event))


;;;=====================================================================
;;; Searching for events
;;;=====================================================================

(defgeneric find-next-event (source-event &key predicate test
					  break-test search-list))

;;;=====================================================================
;;; Sorting Compositions
;;;=====================================================================

(defgeneric event< (event1 event2 attribute-list))

(defgeneric sort-composition (composition attribute-list))