
    rh[             !         S r SSKJr  SSKJr  SSKrSSKrSSKJr  SSKrSSK	J
r
  SSKrSSKJr  SSKJr  SS	KJr  SSKJr  SS
KJr  \R(                  " S5      r " S S\R,                  5      r " S S\R,                  5      r " S S\R,                  5      r " S S\R,                  5      r " S S\R,                  5      r " S S\R,                  5      r " S S\R,                  5      r " S S\R,                  5      r " S S\R,                  5      r " S S\R,                  5      r  " S  S!\R,                  5      r! " S" S#\R,                  5      r" " S$ S%\R,                  5      r# " S& S'\R,                  5      r$ " S( S)\R,                  5      r% " S* S+\R,                  5      r& " S, S-\R,                  5      r' " S. S/\R,                  5      r( " S0 S1\R,                  5      r) " S2 S3\R,                  5      r* " S4 S5\R,                  5      r+ " S6 S7\R,                  5      r, " S8 S9\R,                  5      r- " S: S;\R,                  5      r. " S< S=\R,                  5      r/ " S> S?\R,                  5      r0 " S@ SA\R,                  5      r1 " SB SC\R,                  5      r2 " SD SE\R,                  5      r3 " SF SG\R,                  5      r4 " SH SI\R,                  5      r5 " SJ SK\R,                  5      r6 " SL SM\R,                  5      r7 " SN SO\R,                  5      r8 " SP SQ\R,                  5      r9 " SR SS\R,                  5      r: " ST SU\R,                  5      r; " SV SW\R,                  5      r< " SX SY\R,                  5      r= " SZ S[\R,                  5      r> " S\ S]\R,                  5      r? " S^ S_\R,                  5      r@ " S` Sa\R,                  5      rA " Sb Sc\R,                  5      rB " Sd Se\R,                  5      rC " Sf Sg\R,                  5      rD " Sh Si\R,                  5      rE " Sj Sk\R,                  5      rF " Sl Sm\R,                  5      rG " Sn So\R,                  5      rH " Sp Sq\R,                  5      rI " Sr Ss\R,                  5      rJ " St Su\R,                  5      rK " Sv Sw\R,                  5      rL " Sx Sy\R,                  5      rM " Sz S{\R,                  5      rN " S| S}\R,                  5      rO " S~ S\R,                  5      rP " S S\R,                  5      rQ " S S\R,                  5      rR " S S\R,                  5      rS " S S\R,                  5      rT " S S\R,                  5      rU " S S\R,                  5      rV " S S\R,                  5      rW " S S\R,                  5      rX " S S\R,                  5      rY " S S\R,                  5      rZ " S S\R,                  5      r[ " S S\R,                  5      r\ " S S\R,                  5      r] " S S\R,                  5      r^ " S S\R,                  5      r_ " S S\R,                  5      r` " S S\R,                  5      ra " S S\R,                  5      rb " S S\R,                  5      rc " S S\R,                  5      rd " S S\R,                  5      re " S S\R,                  5      rf " S S\R,                  5      rg " S S\R,                  5      rh " S S\R,                  5      ri " S S\R,                  5      rj " S S\R,                  5      rk " S S\R,                  5      rl " S S\R,                  5      rm " S S\R,                  5      rn " S S\R,                  5      ro " S S\R,                  5      rp " S S\R,                  5      rq " S S\R,                  5      rr " S S\R,                  5      rs " S S\R,                  5      rt " S S\R,                  5      ru " S S\R,                  5      rv " S S\R,                  5      rw " S S\R,                  5      rx " S S\R,                  5      ry " S S\R,                  5      rz " S S\R,                  5      r{ " S S\R,                  5      r| " S S\R,                  5      r} " S S\R,                  5      r~ " S S\~5      r " S S\~5      r " S S\~5      r " S S\~5      r " S S\~5      r " S S\~5      r " S S\~5      r " S S\~5      r " S S\~5      r " S S\~5      r " S S\GR                  5      r\" SS\b\c\d\e/4SS\t\u\v\w\x\y\z\{\|\}\\\\\\\\\\/4SS\\\\\\\\\\ \!\"\#\$\%S\&\'\(S/4SS\)\*\+\,\-\.\/\0\1\2\3\4\5\6\7\8\9\:\;\<\=\>\?\@\AS/4S/ SP\CP\DP\EP\FP\GP\HP\IP\JP\KP\LP\MP\NP\OP\PP\QPSP\RP\SP\TP\UP\VP\WP\XP\YP\ZPSPSPSPSP\[P\\P\]P\^P\_P\`P\aP4SS\f\g\h\i\j\k\l\m\n\oS\p\qS\rSSSS\s/4S/ SQ4/5      rS r/ \P\P\P\P\P\P\P\P\P\ P\!P\"P\#P\$P\%P\&P\'P\(P\tP\vP\yP\{P\P\P\P\P\P\P\P\P\P\P\QP\RP\SP\TP\UP\VP\WP\XP\YP\ZP\[P\\P\]P\^P\_P\`P\aP\fP\gP\hP\)P\*P\+P\,P\-P\.P\/P\0P\1P\2P\3P\4P\5P\6P\7P\8P\;P\<P\=P\>PrS r " S S\GR                  5      r\S:X  a  SSKr\GR$                  " \5        gg)z
The features implemented here are based on those found in jSymbolic and
defined in Cory McKay's MA Thesis, "Automatic Genre Classification of MIDI Recordings"
    )annotations)OrderedDictN)isclose)dedent)base)environment)exceptions21)
Instrumentzfeatures.jSymbolicc                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )MelodicIntervalHistogramFeature)   a%  
A features array with bins corresponding to the values of the melodic interval histogram.

128 dimensions

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.MelodicIntervalHistogramFeature(s)
>>> f = fe.extract()
>>> f.vector[0:5]
[0.144..., 0.220..., 0.364..., 0.062..., 0.050...]
M1c                p   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SU l        g )NdataOrStreamzMelodic Interval HistogramzYA features array with bins corresponding to the values of the melodic interval histogram.T    super__init__namedescriptionisSequential
dimensions	normalizeselfr   keywords	__class__s      T/home/james-whalen/.local/lib/python3.13/site-packages/music21/features/jSymbolic.pyr   (MelodicIntervalHistogramFeature.__init__7   s@    ?l?h?0	L     c                v    [        U R                  S   5       H  u  pX R                  R                  U'   M     g)5
Do processing necessary, storing result in feature.
midiIntervalHistogramN)	enumeratedatafeaturevector)r   ivalues      r   process'MelodicIntervalHistogramFeature.processA   s2     "$)),C"DEHA%*LL" Fr!   r   r   r   r   r   N
__name__
__module____qualname____firstlineno____doc__idr   r+   __static_attributes____classcell__r   s   @r   r   r   )   s    
 
B+ +r!   r   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )AverageMelodicIntervalFeatureI   z
Average melodic interval (in semitones).

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.AverageMelodicIntervalFeature(s)
>>> f = fe.extract()
>>> f.vector
[2.44...]
M2c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zAverage Melodic Intervalz(Average melodic interval (in semitones).T   r   r   r   r   r   r   r   r   s      r   r   &AverageMelodicIntervalFeature.__init__U   s6    ?l?h?.	E r!   c                   / nU R                   S   n[        U5       H(  u  p4[        U5       H  nUR                  U5        M     M*     U(       d  [	        S5      e[        U5      [        U5      -  U R                  R                  S'   gr#   r$   input lacks notesr   N)	r&   r%   rangeappendJSymbolicFeatureExceptionsumlenr'   r(   )r   valueshistor)   r*   js         r   r+   %AverageMelodicIntervalFeature.process]   su     		12!%(HA5\a  " ) +,?@@!$Vs6{!:Ar!   r   r   r   r   r.   r/   r8   s   @r   r:   r:   I   s     
B; ;r!   r:   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ ) MostCommonMelodicIntervalFeaturel   z

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.MostCommonMelodicIntervalFeature(s)
>>> f = fe.extract()
>>> f.vector
[2]
M3c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zMost Common Melodic Intervalz,Melodic interval with the highest frequency.Tr>   r   r?   r   s      r   r   )MostCommonMelodicIntervalFeature.__init__w   s6    ?l?h?2	I r!   c                    U R                   S   n[        U5      nUR                  U5      nX0R                  R                  S'   gr#   r$   r   N)r&   maxindexr'   r(   )r   rJ   maxValuemaxIndexs       r   r+   (MostCommonMelodicIntervalFeature.process   s<    
 		12u:;;x(!)Ar!   rM   r.   r/   r8   s   @r   rO   rO   l   s     
B* *r!   rO   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )0DistanceBetweenMostCommonMelodicIntervalsFeature   z

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.DistanceBetweenMostCommonMelodicIntervalsFeature(s)
>>> f = fe.extract()
>>> f.vector
[1]
M4c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z.Distance Between Most Common Melodic IntervalszvAbsolute value of the difference between the most common melodic interval and the second most common melodic interval.Tr>   r   r?   r   s      r   r   9DistanceBetweenMostCommonMelodicIntervalsFeature.__init__   s:    ?l?h?D	7 !r!   c                
   [         R                  " U R                  S   5      n[        U5      nUR	                  U5      nSX'   [        U5      nUR	                  U5      n[        X5-
  5      U R                  R                  S'   grU   )copydeepcopyr&   rV   rW   absr'   r(   )r   rJ   rX   rY   secondValuesecondIndexs         r   r+   8DistanceBetweenMostCommonMelodicIntervalsFeature.process   sm    
 dii(?@Au:;;x(%jkk+.!$X%;!<Ar!   rM   r.   r/   r8   s   @r   r\   r\      s     
B= =r!   r\   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )*MostCommonMelodicIntervalPrevalenceFeature   z
Fraction of melodic intervals that belong to the most common interval.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.MostCommonMelodicIntervalPrevalenceFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.364...]
M5c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z'Most Common Melodic Interval PrevalencezFFraction of melodic intervals that belong to the most common interval.Tr>   r   r?   r   s      r   r   3MostCommonMelodicIntervalPrevalenceFeature.__init__   s6    ?l?h?=	c r!   c                    [         R                  " U R                  S   5      n[        U5      n[	        U5      nU(       d  [        S5      eX#-  U R                  R                  S'   grB   )rb   rc   r&   rV   rG   rF   r'   r(   )r   rJ   rX   counts       r   r+   2MostCommonMelodicIntervalPrevalenceFeature.process   sT    
 dii(?@Au:E
+,?@@!)!1Ar!   rM   r.   r/   r8   s   @r   ri   ri      s     
B
2 
2r!   ri   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ ),RelativeStrengthOfMostCommonIntervalsFeature   z

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.RelativeStrengthOfMostCommonIntervalsFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.603...]
M6c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z*Relative Strength of Most Common IntervalszFraction of melodic intervals that belong to the second most common interval divided by the fraction of melodic intervals belonging to the most common interval.Tr>   r   r?   r   s      r   r   5RelativeStrengthOfMostCommonIntervalsFeature.__init__   s;    ?l?h?@	c !r!   c                   [         R                  " U R                  S   5      n[        U5      n[	        U5      nUR                  U5      nSX'   [	        U5      nU(       d  [        S5      eXR-  X2-  -  U R                  R                  S'   g)r#   r$   r   rC   N)	rb   rc   r&   rG   rV   rW   rF   r'   r(   )r   rJ   ro   rX   rY   re   s         r   r+   4RelativeStrengthOfMostCommonIntervalsFeature.process   sz    
 dii(?@AE
u:;;x(%j+,?@@"-"5(:J!KAr!   rM   r.   r/   r8   s   @r   rr   rr      s      
BL Lr!   rr   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )%NumberOfCommonMelodicIntervalsFeature   z
Number of melodic intervals that represent at least 9% of all melodic intervals.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.NumberOfCommonMelodicIntervalsFeature(s)
>>> f = fe.extract()
>>> f.vector
[3]
M7c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z"Number of Common Melodic IntervalszPNumber of melodic intervals that represent at least 9% of all melodic intervals.Tr>   r   r?   r   s      r   r   .NumberOfCommonMelodicIntervalsFeature.__init__  s9    ?l?h?8	D r!   c                    U R                   S   n[        U5      nU(       d  [        S5      eSn[        U5       H  u  pEXR-  S:  d  M  US-  nM     X0R                  R
                  S'   g)r#   r$   rC   r   
ףp=
?r>   N)r&   rG   rF   r%   r'   r(   )r   rJ   totalpostr)   ro   s         r   r+   -NumberOfCommonMelodicIntervalsFeature.process  sh     		12E
+,?@@!%(HA}$	 ) "&Ar!   rM   r.   r/   r8   s   @r   rz   rz      s     
B& &r!   rz   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )AmountOfArpeggiationFeaturei  a[  
Fraction of horizontal intervals that are repeated notes, minor thirds, major thirds,
perfect fifths, minor sevenths, major sevenths, octaves, minor tenths or major tenths.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.AmountOfArpeggiationFeature(s)
>>> f = fe.extract()
>>> f.name
'Amount of Arpeggiation'
>>> f.vector
[0.333...]
M8c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zAmount of ArpeggiationzFraction of horizontal intervals that are repeated notes, minor thirds, major thirds, perfect fifths, minor sevenths, major sevenths, octaves, minor tenths or major tenths.Tr>   r   r?   r   s      r   r   $AmountOfArpeggiationFeature.__init__+  s;    ?l?h?,	U !r!   c                    U R                   S   n[        U5      nUS:X  a  g/ SQn[        U5      nSnU H
  nXAU   -  nM     U(       d  [        S5      eXB-  U R                  R                  S'   g)r#   r$   r   N)	r            
               rC   r&   rG   rF   r'   r(   r   rJ   r   targetsro   ts         r   r+   #AmountOfArpeggiationFeature.process5  st     		12E
A:2E
A1XE +,?@@!&Ar!   rM   r.   r/   r8   s   @r   r   r     s     
B/ /r!   r   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )RepeatedNotesFeatureiH  z
Fraction of notes that are repeated melodically

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.RepeatedNotesFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.144...]
M9c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zRepeated Notesz0Fraction of notes that are repeated melodically.Tr>   r   r?   r   s      r   r   RepeatedNotesFeature.__init__T  s6    ?l?h?$	M r!   c                    U R                   S   n[        U5      nUS:X  a  gS/n[        U5      nU(       d  [        S5      eSnU H
  nXAU   -  nM     XB-  U R                  R                  S'   g)r#   r$   r   NrC   r   r   s         r   r+   RepeatedNotesFeature.process\  sv     		12E
A:#E
+,?@@A1XE !&Ar!   rM   r.   r/   r8   s   @r   r   r   H  s     
B/ /r!   r   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )ChromaticMotionFeatureio  z
Fraction of melodic intervals corresponding to a semitone.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.ChromaticMotionFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.220...]
m10c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zChromatic Motionz;Fraction of melodic intervals corresponding to a semi-tone.Tr>   r   r?   r   s      r   r   ChromaticMotionFeature.__init__{  s6    ?l?h?&	X r!   c                    U R                   S   n[        U5      nU(       d  [        S5      eS/nSnU H
  nXAU   -  nM     XB-  U R                  R                  S'   g)r#   r$   rC   r>   r   Nr   r   s         r   r+   ChromaticMotionFeature.process  c     		12E
+,?@@#A1XE !&Ar!   rM   r.   r/   r8   s   @r   r   r   o       
B/ /r!   r   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )StepwiseMotionFeaturei  z
Fraction of melodic intervals that corresponded to a minor or major second

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.StepwiseMotionFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.584...]
M11c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zStepwise MotionzKFraction of melodic intervals that corresponded to a minor or major second.Tr>   r   r?   r   s      r   r   StepwiseMotionFeature.__init__  s8    ?l?h?%	: r!   c                    U R                   S   n[        U5      nU(       d  [        S5      eSS/nSnU H
  nXAU   -  nM     XB-  U R                  R                  S'   g)r#   r$   rC   r>      r   Nr   r   s         r   r+   StepwiseMotionFeature.process  e     		12E
+,?@@a&A1XE !&Ar!   rM   r.   r/   r8   s   @r   r   r     s     
B/ /r!   r   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )MelodicThirdsFeaturei  z
Fraction of melodic intervals that are major or minor thirds

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.MelodicThirdsFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.113...]
M12c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zMelodic Thirdsz=Fraction of melodic intervals that are major or minor thirds.Tr>   r   r?   r   s      r   r   MelodicThirdsFeature.__init__  s6    ?l?h?$	Z r!   c                    U R                   S   n[        U5      nU(       d  [        S5      eSS/nSnU H
  nXAU   -  nM     XB-  U R                  R                  S'   g)r#   r$   rC   r   r   r   Nr   r   s         r   r+   MelodicThirdsFeature.process  r   r!   rM   r.   r/   r8   s   @r   r   r     r   r!   r   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )MelodicFifthsFeaturei  z
Fraction of melodic intervals that are perfect fifths

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.MelodicFifthsFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.056...]
M13c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zMelodic Fifthsz6Fraction of melodic intervals that are perfect fifths.Tr>   r   r?   r   s      r   r   MelodicFifthsFeature.__init__  s6    ?l?h?$	S r!   c                    U R                   S   n[        U5      nU(       d  [        S5      eS/nSnU H
  nXAU   -  nM     XB-  U R                  R                  S'   g)r#   r$   rC   r   r   Nr   r   s         r   r+   MelodicFifthsFeature.process  r   r!   rM   r.   r/   r8   s   @r   r   r     r   r!   r   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )MelodicTritonesFeaturei   z
Fraction of melodic intervals that are tritones

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.MelodicTritonesFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.012...]
M14c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zMelodic Tritonesz0Fraction of melodic intervals that are tritones.Tr>   r   r?   r   s      r   r   MelodicTritonesFeature.__init__  s6    ?l?h?&	M r!   c                    U R                   S   n[        U5      nU(       d  [        S5      eS/nSnU H
  nXAU   -  nM     XB-  U R                  R                  S'   g)r#   r$   rC      r   Nr   r   s         r   r+   MelodicTritonesFeature.process  r   r!   rM   r.   r/   r8   s   @r   r   r      r   r!   r   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )MelodicOctavesFeaturei$  z
Fraction of melodic intervals that are octaves

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.MelodicOctavesFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.018...]
M15c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zMelodic Octavesz/Fraction of melodic intervals that are octaves.Tr>   r   r?   r   s      r   r   MelodicOctavesFeature.__init__0  s6    ?l?h?%	L r!   c                    U R                   S   n[        U5      nU(       d  [        S5      e/ SQnSnU H
  nXAU   -  nM     XB-  U R                  R                  S'   g)r#   r$   rC   )	r      0   <   H   T   `   rP   x   r   Nr   r   s         r   r+   MelodicOctavesFeature.process8  sa     		12E
+,?@@8A1XE !&Ar!   rM   r.   r/   r8   s   @r   r   r   $  r   r!   r   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )DirectionOfMotionFeatureiH  z
Returns the fraction of melodic intervals that are rising rather than falling.
Unisons are omitted.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.DirectionOfMotionFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.470...]
m17c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zDirection of MotionzBFraction of melodic intervals that are rising rather than falling.Tr>   r   r?   r   s      r   r   !DirectionOfMotionFeature.__init__U  s6    ?l?h?)	_ r!   c                   SnSn/ nU R                   R                  S:  aM  [        U R                   R                  5       H)  nU R                   S   U   S   nUR                  U5        M+     O U R                   S   nUR                  U5        U H&  nU H  nUS:  a  US-  nM  US:  d  M  US-  nM     M(     U(       d  U(       d  [	        S5      eXU-   -  U R
                  R                  S'   g)r#   r   partscontourListr>   rC   N)r&   
partsCountrD   rE   rF   r'   r(   )r   risingfallingcBundler)   cListcs          r   r+    DirectionOfMotionFeature.process]  s     99!#499//0		'*1-m<u% 1 IIm,ENN5!Eq5aKFUqLG	   6+,?@@!'V+;!<Ar!   rM   r.   r/   r8   s   @r   r   r   H  s    	 
B= =r!   r   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )DurationOfMelodicArcsFeatureiw  a  
Average number of notes that separate melodic peaks and troughs
in any part. This is calculated as the total number of intervals
(not counting unisons) divided by the number of times the melody
changes direction.

Example: C D E D C D E C C
Intervals: [0] 2 2 -2 -2 2 2 -4 0
Changes direction (equivalent to +/- sign) three times.
There are seven non-unison (nonzero) intervals.
Thus, the duration of arcs is 7/3 ~= 2.333...

>>> s = converter.parse("tinyNotation: c' d' e' d' c' d' e'2 c'2 c'2")
>>> fe = features.jSymbolic.DurationOfMelodicArcsFeature(s)
>>> fe.extract().vector
[2.333...]

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.DurationOfMelodicArcsFeature(s)
>>> fe.extract().vector
[1.74...]
M18c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zDuration of Melodic ArcszAverage number of notes that separate melodic peaks and troughs in any part. This is calculated as the total number of intervals (not counting unisons) divided by the number of times the melody changes direction.Tr>   r   r?   r   s      r   r   %DurationOfMelodicArcsFeature.__init__  s;    ?l?h?.	S !r!   c                2   / nU R                   R                  S:  aM  [        U R                   R                  5       H)  nU R                   S   U   S   nUR                  U5        M+     O U R                   S   nUR                  U5        SnSnSnSnSnU HY  nUn	U HN  n
U
S:w  a  US-  nX:X  a  U
S:  a	  US-  nUn	M"  M$  X:X  a  U
S:  a	  US-  nUn	M8  M:  U
S:  a  Un	MD  U
S:  d  ML  Un	MP     M[     US:X  a  SnOXT-  nXR                  R
                  S'   gr#   r   r   r   r>   N)r&   r   rD   rE   r'   r(   )r   r   r)   r   direction_changesnonUnison_intervals	ASCENDING
DESCENDING
STATIONARYcurrent_directionintervalduration_of_melodic_arcss               r   r+   $DurationOfMelodicArcsFeature.process  sL    99!#499//0		'*1-m<u% 1 IIm,ENN5! 	

E *!q='1,'$1!|)Q.),6) $ '4!|)Q.),5) $  !|,5)!A,6) " & !'($':'N$!9Ar!   rM   r.   r/   r8   s   @r   r   r   w  s    , 
B	/: /:r!   r   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )SizeOfMelodicArcsFeaturei  a  
Average span (in semitones) between melodic peaks and troughs
in any part. Each time the melody changes direction begins a
new arc. The average size of melodic arcs is defined as the
total size of melodic intervals between changes of directions -
or between the start of the melody and the first change of
direction - divided by the number of direction changes.

Example: C D E D C E D C C
Intervals: [0] 2 2 -2 -2 2 2 -4 0
Changes direction (equivalent to +/- sign) three times.
The total sum of interval distance up to the last change
of direction is 12. We don't count the last interval,
the descending major third, because it is not between
changes of direction.
Thus, the average size of melodic arcs is 12/3 = 4.

>>> s = converter.parse("tinyNotation: c' d' e' d' c' d' e'2 c'2 c'2")
>>> fe = features.jSymbolic.SizeOfMelodicArcsFeature(s)
>>> fe.extract().vector
[4.0]

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.SizeOfMelodicArcsFeature(s)
>>> fe.extract().vector
[4.84...]
M19c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zSize of Melodic Arcsae  Average span (in semitones) between melodic peaks and troughs in any part. Each time the melody changes direction begins a new arc. The average size ofmelodic arcs is defined as the total size of melodicintervals between changes of directions - or betweenthe start of the melody and the first change ofdirection - divided by the number of direction changes.Tr>   r   r?   r   s      r   r   !SizeOfMelodicArcsFeature.__init__  s;    ?l?h?*	V !r!   c                   / nU R                   R                  S:  aM  [        U R                   R                  5       H)  nU R                   S   U   S   nUR                  U5        M+     O U R                   S   nUR                  U5        SnSnSnSnSnU H  nUn	Sn
U H  nX:X  a6  US:  a  U
[	        U5      -  n
M  US:  a  XZ-  nUS-  nUn	[	        U5      n
M<  M>  X:X  a6  US:  a  U
[	        U5      -  n
MY  US:  a  XZ-  nUS-  nUn	[	        U5      n
Mw  My  US:  a  Un	U
[	        U5      -  n
M  US:  d  M  Un	U
[	        U5      -  n
M     M     US:X  a  SnOXT-  nXR
                  R                  S'   gr   )r&   r   rD   rE   rd   r'   r(   )r   r   r)   r   r   sum_of_intervalsr   r   r   r   this_arc_intervalr   size_of_melodic_arcss                r   r+    SizeOfMelodicArcsFeature.process  s    99!#499//0		'*1-m<u% 1 IIm,ENN5! 	

E * !!$1!|)S]:)!A(=()Q.),6),/M) & '4!|)S]:)!A(=()Q.),5),/M) &  !|,5))S]:)!A,6))S]:)7 " B !#$ #3#G !5Ar!   rM   r.   r/   r8   s   @r   r   r     s    6 
B=6 =6r!   r   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ ) MostCommonPitchPrevalenceFeaturei=  z
Fraction of Notes corresponding to the most common pitch.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.MostCommonPitchPrevalenceFeature(s)
>>> fe.extract().vector[0]
0.116...
P1c                p   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SU l        g )Nr   zMost Common Pitch Prevalencez<Fraction of Note Ons corresponding to the most common pitch.Tr>   Fr   r   r   r   r   r   r   discreter   s      r   r   )MostCommonPitchPrevalenceFeature.__init__H  s=    ?l?h?2	Y r!   c                    U R                   S   nU(       d  [        S5      e[        UR                  5       5      n[	        UR                  5       5      nX#-  U R
                  R                  S'   gr#   pitches.midiPitchHistogramrC   r   N)r&   rF   rV   rI   rG   r'   r(   )r   rJ   pcMaxpcCounts       r   r+   (MostCommonPitchPrevalenceFeature.processQ  sZ     		67+,?@@ ELLN#elln%!&Ar!   r   r   r  r   r   r.   r/   r8   s   @r   r   r   =  s     
B1 1r!   r   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )%MostCommonPitchClassPrevalenceFeaturei`  z
Fraction of Notes corresponding to the most common pitch class.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.MostCommonPitchClassPrevalenceFeature(s)
>>> fe.extract().vector
[0.196...]
P2c                p   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SU l        g )Nr   z"Most Common Pitch Class PrevalencezBFraction of Note Ons corresponding to the most common pitch class.Tr>   Fr   r  r   s      r   r   .MostCommonPitchClassPrevalenceFeature.__init__k  s=    ?l?h?8	_ r!   c                    U R                   S   nUR                  [        U5      5      n[        U5      nU(       d  [	        S5      eX   U-  U R
                  R                  S'   gr#   pitches.pitchClassHistogramrC   r   N)r&   rW   rV   rG   rF   r'   r(   )r   rJ   pcr	  s       r   r+   -MostCommonPitchClassPrevalenceFeature.processt  sZ     		78 [[U$e*+,?@@!&W!4Ar!   r  r.   r/   r8   s   @r   r  r  `  s     
B5 5r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )#RelativeStrengthOfTopPitchesFeaturei  z
The frequency of the 2nd most common pitch divided by the frequency of the most common pitch.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.RelativeStrengthOfTopPitchesFeature(s)
>>> fe.extract().vector
[0.947...]
P3c                p   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SU l        g )Nr   z Relative Strength of Top Pitchesz]The frequency of the 2nd most common pitch divided by the frequency of the most common pitch.Tr>   Fr   r  r   s      r   r   ,RelativeStrengthOfTopPitchesFeature.__init__  s@    ?l?h?6	Q r!   c                ,   U R                   S   n UR                  S5      SS u  p#[        US   US   -  5      U R                  R                  S'   g! [
         a    [        S5      e[        [        4 a    SU R                  R                  S'    gf = f)r#   r  r   Nr>   r   rC           )	r&   most_commonfloatr'   r(   ZeroDivisionErrorrF   
IndexError
ValueErrorr   rJ   pMaxpSeconds       r   r+   +RelativeStrengthOfTopPitchesFeature.process  s     		67	)!--a0!4MD%*71:Q+?%@DLL"  	A+,?@@J' 	)%(DLL"	)s   AA =BBr  r.   r/   r8   s   @r   r  r    s     
B) )r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )(RelativeStrengthOfTopPitchClassesFeaturei  z

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.RelativeStrengthOfTopPitchClassesFeature(s)
>>> fe.extract().vector
[0.906...]
P4c                p   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SU l        g )Nr   z&Relative Strength of Top Pitch ClassesziThe frequency of the 2nd most common pitch class divided by the frequency of the most common pitch class.Tr>   Fr   r  r   s      r   r   1RelativeStrengthOfTopPitchClassesFeature.__init__  s@    ?l?h?<	W r!   c                $   [         R                  " U R                  S   5      nUR                  [	        U5      5      nX   nU(       d  [        S5      eSX'   UR                  [	        U5      5      nX   nXS-  U R                  R                  S'   gr  )rb   rc   r&   rW   rV   rF   r'   r(   )r   rJ   	pIndexMax	pCountMaxpIndexSecondpCountSeconds         r   r+   0RelativeStrengthOfTopPitchClassesFeature.process  s    
 dii(EFG KKE
+	$	+,?@@{{3u:.*!-!9Ar!   r  r.   r/   r8   s   @r   r'  r'    s     
B: :r!   r'  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )&IntervalBetweenStrongestPitchesFeaturei  z
Absolute value of the difference between the pitches of the two most common MIDI pitches.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.IntervalBetweenStrongestPitchesFeature(s)
>>> fe.extract().vector
[5]
P5c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z"Interval Between Strongest PitcheszYAbsolute value of the difference between the pitches of the two most common MIDI pitches.Tr>   r   r?   r   s      r   r   /IntervalBetweenStrongestPitchesFeature.__init__  s9    ?l?h?8	O r!   c                   U R                   S   n UR                  S5      SS u  p#[        US   US   -
  5      U R                  R                  S'   g! [
        [        4 a    SU R                  R                  S'    gf = f)r#   r  r   Nr   r  )r&   r  rd   r'   r(   r   r!  r"  s       r   r+   .IntervalBetweenStrongestPitchesFeature.process  s     		67	)!--a0!4MD%(d1g)=%>DLL"J' 	)%(DLL"	)s   AA )A?>A?rM   r.   r/   r8   s   @r   r2  r2    s     
B) )r!   r2  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )+IntervalBetweenStrongestPitchClassesFeaturei  z

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.IntervalBetweenStrongestPitchClassesFeature(s)
>>> fe.extract().vector
[5]
P6c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z(Interval Between Strongest Pitch ClasseszeAbsolute value of the difference between the pitch classes of the two most common MIDI pitch classes.Tr>   r   r?   r   s      r   r   4IntervalBetweenStrongestPitchClassesFeature.__init__  s9    ?l?h?>	Q r!   c                   [         R                  " U R                  S   5      nUR                  [	        U5      5      nSX'   UR                  [	        U5      5      n[        X#-
  5      U R                  R                  S'   gr#   r  r   N)rb   rc   r&   rW   rV   rd   r'   r(   )r   rJ   r,  r.  s       r   r+   3IntervalBetweenStrongestPitchClassesFeature.process  sh     dii(EFG KKE
+	{{3u:. "%Y%=!>Ar!   rM   r.   r/   r8   s   @r   r9  r9    s     
B? ?r!   r9  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )NumberOfCommonPitchesFeaturei  z
Number of pitches that account individually for at least 9% of all notes.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.NumberOfCommonPitchesFeature(s)
>>> fe.extract().vector
[3]
P7c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zNumber of Common PitcheszINumber of pitches that account individually for at least 9% of all notes.Tr>   r   r?   r   s      r   r   %NumberOfCommonPitchesFeature.__init__"  s8    ?l?h?.	< r!   c                    U R                   S   n[        UR                  5       5      nSnUR                  5        H  nXB-  S:  d  M  US-  nM     X0R                  R                  S'   g)r#   r  r   r   r>   N)r&   rG   rI   r'   r(   )r   rJ   r   r   ro   s        r   r+   $NumberOfCommonPitchesFeature.process+  s_     		67ELLN#\\^E}$	 $ "&Ar!   rM   r.   r/   r8   s   @r   rA  rA    s     
B
& 
&r!   rA  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )PitchVarietyFeaturei8  z
Number of pitches used at least once.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.PitchVarietyFeature(s)
>>> fe.extract().vector
[24]
P8c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zPitch Varietyz%Number of pitches used at least once.Tr>   r   r?   r   s      r   r   PitchVarietyFeature.__init__C  s6    ?l?h?#	B r!   c                    U R                   S   nSn[        U5       H  u  p4US:  d  M  US-  nM     X R                  R                  S'   g)r#   r  r   r>   Nr&   r%   r'   r(   r   rJ   r   r)   ro   s        r   r+   PitchVarietyFeature.processK  sM     		67!%(HAz	 ) "&Ar!   rM   r.   r/   r8   s   @r   rH  rH  8       
B	& 	&r!   rH  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )PitchClassVarietyFeatureiW  z
Number of pitch classes used at least once.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.PitchClassVarietyFeature(s)
>>> fe.extract().vector
[10]
P9c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zPitch Class Varietyz+Number of pitch classes used at least once.Tr>   r   r?   r   s      r   r   !PitchClassVarietyFeature.__init__b  s6    ?l?h?)	H r!   c                    U R                   S   nSn[        U5       H  u  p4US:  d  M  US-  nM     X R                  R                  S'   g)r#   r  r   r>   NrM  rN  s        r   r+    PitchClassVarietyFeature.processj  sM     		78!%(HAz	 ) "&Ar!   rM   r.   r/   r8   s   @r   rR  rR  W  rP  r!   rR  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )RangeFeatureiv  z
Difference between highest and lowest pitches. In semitones

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.RangeFeature(s)
>>> fe.extract().vector
[34]
P10c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   Rangez.Difference between highest and lowest pitches.Tr>   r   r?   r   s      r   r   RangeFeature.__init__  s6    ?l?h?	K r!   c                    U R                   S   nU(       d  [        S5      e[        UR                  5       5      n[	        UR                  5       5      nX2-
  U R
                  R                  S'   gr  )r&   rF   minkeysrV   r'   r(   )r   rJ   minIndexrY   s       r   r+   RangeFeature.process  sY     		67+,?@@uzz|$uzz|$!)!4Ar!   rM   r.   r/   r8   s   @r   rY  rY  v  s     
B
5 
5r!   rY  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )MostCommonPitchFeaturei  z
Bin label of the most common pitch.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.MostCommonPitchFeature(s)
>>> fe.extract().vector
[61]
P11c                p   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SU l        g )Nr   zMost Common Pitchz#Bin label of the most common pitch.Tr>   Fr   r  r   s      r   r   MostCommonPitchFeature.__init__  s=    ?l?h?'	@ r!   c                    U R                   S   n UR                  S5      S   S   nX R                  R                  S'   g! [         a    SU R                  R                  S'    gf = f)r#   r  r>   r   r  N)r&   r  r'   r(   r   )r   rJ   
pNumberMaxs      r   r+   MostCommonPitchFeature.process  sg     		67	)**1-a03J%/LL" 	)%(DLL"	)s   /A #A'&A'r  r.   r/   r8   s   @r   rd  rd    s     
B	) 	)r!   rd  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )PrimaryRegisterFeaturei  z
Average MIDI pitch.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.PrimaryRegisterFeature(s)
>>> fe.extract().vector
[61.12...]
P12c                p   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SU l        g )Nr   zPrimary RegisterzAverage MIDI pitch.Tr>   Fr   r  r   s      r   r   PrimaryRegisterFeature.__init__  s=    ?l?h?&	0 r!   c                    U R                   S   nU(       d  [        S5      e[        R                  " U Vs/ s H  o"R                  PM     sn5      U R
                  R                  S'   gs  snf )r#   pitchesrC   r   N)r&   rF   
statisticsmeanpsr'   r(   )r   rJ   ps      r   r+   PrimaryRegisterFeature.process  sR     		)$+,?@@!+1F1$$1F!GA1Fs   A*r  r.   r/   r8   s   @r   rl  rl    s      
BH Hr!   rl  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )ImportanceOfBassRegisterFeaturei  z
Fraction of Notes between MIDI pitches 0 and 54.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.ImportanceOfBassRegisterFeature(s)
>>> fe.extract().vector
[0.184...]
P13c                p   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SU l        g )Nr   zImportance of Bass Registerz3Fraction of Note Ons between MIDI pitches 0 and 54.Tr>   Fr   r  r   s      r   r   (ImportanceOfBassRegisterFeature.__init__  s=    ?l?h?1	P r!   c                *   U R                   S   nU(       d  [        S5      e/ nUR                  5        H  u  p4US::  d  M  UR                  U5        M      [	        U5      nU[	        UR                  5       5      -  U R                  R                  S'   g)r#   r  rC   6   r   Nr&   rF   itemsrE   rG   rI   r'   r(   r   rJ   matchesr)   ro   
matchedSums         r   r+   'ImportanceOfBassRegisterFeature.process  {     		67+,?@@HABwu% & \
!+c%,,..A!AAr!   r  r.   r/   r8   s   @r   rx  rx          
BB Br!   rx  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )!ImportanceOfMiddleRegisterFeaturei  z
Fraction of Notes between MIDI pitches 55 and 72

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.ImportanceOfMiddleRegisterFeature(s)
>>> fe.extract().vector
[0.766...]
P14c                p   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SU l        g )Nr   zImportance of Middle Registerz4Fraction of Note Ons between MIDI pitches 55 and 72.Tr>   Fr   r  r   s      r   r   *ImportanceOfMiddleRegisterFeature.__init__  s=    ?l?h?3	Q r!   c                @   U R                   S   nU(       d  [        S5      e/ nUR                  5        H)  u  p4SUs=::  a  S::  d  M  O  M  UR                  U5        M+     [	        U5      nU[	        UR                  5       5      -  U R                  R                  S'   g)r#   r  rC   7   r   r   Nr~  r  s         r   r+   )ImportanceOfMiddleRegisterFeature.process  s     		67+,?@@HAQ}"}}u% & \
!+c%,,..A!AAr!   r  r.   r/   r8   s   @r   r  r    r  r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )ImportanceOfHighRegisterFeaturei  z
Fraction of Notes between MIDI pitches 73 and 127.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.ImportanceOfHighRegisterFeature(s)
>>> fe.extract().vector
[0.049...]
P15c                p   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SU l        g )Nr   zImportance of High Registerz5Fraction of Note Ons between MIDI pitches 73 and 127.Tr>   Fr   r  r   s      r   r   (ImportanceOfHighRegisterFeature.__init__)  s=    ?l?h?1	R r!   c                *   U R                   S   nU(       d  [        S5      e/ nUR                  5        H  u  p4US:  d  M  UR                  U5        M      [	        U5      nU[	        UR                  5       5      -  U R                  R                  S'   g)r#   r  rC   r;   r   Nr~  r  s         r   r+   'ImportanceOfHighRegisterFeature.process2  r  r!   r  r.   r/   r8   s   @r   r  r    r  r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )MostCommonPitchClassFeatureiC  z
Bin label of the most common pitch class.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.MostCommonPitchClassFeature(s)
>>> fe.extract().vector
[1]
P16c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zMost Common Pitch Classz)Bin label of the most common pitch class.Tr>   r   r?   r   s      r   r   $MostCommonPitchClassFeature.__init__N  s6    ?l?h?-	F r!   c                    U R                   S   nUR                  [        U5      5      nX R                  R                  S'   gr>  r&   rW   rV   r'   r(   )r   rJ   r,  s      r   r+   #MostCommonPitchClassFeature.processV  s7     		78KKE
+	!*Ar!   rM   r.   r/   r8   s   @r   r  r  C  s     
B+ +r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )DominantSpreadFeaturei_  z
Not implemented

Largest number of consecutive pitch classes separated by perfect
5ths that accounted for at least 9% each of the notes.
P17c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zDominant SpreadzwLargest number of consecutive pitch classes separated by perfect 5ths that accounted for at least 9% each of the notes.Tr>   r   r?   r   s      r   r   DominantSpreadFeature.__init__h  s9    ?l?h?%	] r!   c                    [        S5      eNznot yet implementedrF   r   s    r   r+   DominantSpreadFeature.processq      '(=>>r!   rM   r.   r/   r8   s   @r   r  r  _       
B? ?r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )StrongTonalCentresFeatureiv  zs
Not implemented

Number of peaks in the fifths pitch histogram that each account
for at least 9% of all Note Ons.
P18c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zStrong Tonal Centresz`Number of peaks in the fifths pitch histogram that each account for at least 9% of all Note Ons.Tr>   r   r?   r   s      r   r   "StrongTonalCentresFeature.__init__  s8    ?l?h?*	? r!   c                    [        S5      er  r  r  s    r   r+   !StrongTonalCentresFeature.process  r  r!   rM   r.   r/   r8   s   @r   r  r  v  r  r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )BasicPitchHistogramFeaturei  a  
A feature extractor that finds a features array with bins corresponding
to the values of the basic pitch histogram.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.BasicPitchHistogramFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
 0.0, 0.0, 0.0, 0.006..., 0.0, 0.0, 0.006..., 0.006..., 0.030...,
 0.0, 0.036..., 0.012..., 0.0, 0.006..., 0.018..., 0.061..., 0.0,
 0.042..., 0.073..., 0.012..., 0.092..., 0.0, 0.116..., 0.061...,
 0.006..., 0.085..., 0.018..., 0.110..., 0.0, 0.042..., 0.055...,
 0.0, 0.049..., 0.0, 0.042..., 0.0, 0.0, 0.006..., 0.0, 0.0, 0.0,
 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
P19c                p   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SU l        g )Nr   zBasic Pitch HistogramzTA features array with bins corresponding to the values of the basic pitch histogram.Tr   r   r   r   s      r   r   #BasicPitchHistogramFeature.__init__  s@    ?l?h?+	C r!   c                    U R                   S   R                  5        H  u  pX R                  R                  U'   M     g)r#   r  N)r&   r  r'   r(   r   r)   ro   s      r   r+   "BasicPitchHistogramFeature.process  s6     		">?EEGHA%*LL" Hr!   r-   r.   r/   r8   s   @r   r  r    s    * 
B+ +r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )PitchClassDistributionFeaturei  a  
A feature array with 12 entries where the first holds the frequency
of the bin of the pitch class histogram with the highest frequency,
and the following entries holding the successive bins of the histogram,
wrapping around if necessary.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.PitchClassDistributionFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.196..., 0.073..., 0.006..., 0.098..., 0.036..., 0.177..., 0.0,
 0.085..., 0.134..., 0.018..., 0.171..., 0.0]
P20c                ~   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SU l        SU l        g )Nr   zPitch Class DistributionzA feature array with 12 entries where the first holds the frequency of the bin of the pitch class histogram with the highest frequency, and the following entries holding the successive bins of the histogram, wrapping around if necessary.Tr   Fr   )r   r   r   r   r   r   r  r   r   s      r   r   &PitchClassDistributionFeature.__init__  sI    ?l?h?.	b !r!   c                   S/U R                   -  n[        U R                  S   5       H	  u  p#X1U'   M     UR                  [	        U5      5      n[        U5       H,  u  p%XPR
                  R                  X$-
  U R                   -  '   M.     g)r#   r   r  N)r   r%   r&   rW   rV   r'   r(   )r   tempr)   ro   mvals         r   r+   %PitchClassDistributionFeature.process  sx    
 sT__$!$)),I"JKHAG L JJs4y!oFA=@LL$// 9: &r!   )r   r   r  r   r   r   r.   r/   r8   s   @r   r  r    s      
BA Ar!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )FifthsPitchHistogramFeaturei  a  
A feature array with bins corresponding to the values of the 5ths pitch class
histogram. Instead of the bins being arranged according to semitones --
[C, C#, D, etc.] -- they are arranged according to the circle of fifths:
[C, G, D, A, E, B, F#, C#, G#, D#, A#, F]. Viewing such a histogram
may draw attention to the prevalence of a tonal center, including the
prevalence of dominant relationships in the piece.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.FifthsPitchHistogramFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.0, 0.0, 0.073..., 0.134..., 0.098..., 0.171..., 0.177..., 0.196...,
 0.085..., 0.006..., 0.018..., 0.036...]
P21c                   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SU l        0 U l        [        S5       H  nSU-  S-  U R                  U'   M     g )Nr   zFifths Pitch HistogramzXA feature array with bins corresponding to the values of the 5ths pitch class histogram.Tr   r   r   )	r   r   r   r   r   r   r   _mappingrD   )r   r   r   r)   r   s       r   r   $FifthsPitchHistogramFeature.__init__  sl    ?l?h?,	:  rA !A|DMM! r!   c                    [        U R                  S   5       H*  u  pX R                  R                  U R                  U   '   M,     g)r#   r  N)r%   r&   r'   r(   r  r  s      r   r+   #FifthsPitchHistogramFeature.process  s;     "$)),I"JKHA49LLa 01 Lr!   )r  r   r   r   r   r   r.   r/   r8   s   @r   r  r    s     
B,: :r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )QualityFeaturei  aP  
Set to 0 if the key signature indicates that
a recording is major, set to 1 if it indicates
that it is minor.  In jSymbolic, this is set to 0 if key signature is unknown.

See features.native.QualityFeature for a music21 improvement on this method

Example: Handel, Rinaldo Aria (musicxml) is explicitly encoded as being in Major:

>>> s = corpus.parse('handel/rinaldo/lascia_chio_pianga')
>>> fe = features.jSymbolic.QualityFeature(s)
>>> f = fe.extract()
>>> f.vector
[0]

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.QualityFeature(s)
>>> f = fe.extract()
>>> f.vector
[1]
P22c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   Qualityz
            Set to 0 if the key signature indicates that
            a recording is major, set to 1 if it indicates
            that it is minor and set to 0 if key signature is unknown.
            Tr>   r   r?   r   s      r   r   QualityFeature.__init__%  s:    ?l?h?	
 !r!   c                    U R                   S   nSnU H+  nUR                  S:X  a  Sn  OUR                  S:X  d  M)  Sn  O   Uc  SnX R                  R                  S'   g)r#   zflat.getElementsByClass(Key)Nmajorr   minorr>   )r&   moder'   r(   )r   allKeys
keyFeaturexs       r   r+   QualityFeature.process1  si     )):;
Avv 
7"
  J!+Ar!   rM   r.   r/   r8   s   @r   r  r    s    * 
B
, ,r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )GlissandoPrevalenceFeatureiD  z
Not yet implemented in music21

Number of Note Ons that have at least one MIDI Pitch Bend associated
with them divided by total number of pitched Note Ons.
P23c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zGlissando Prevalencez{Number of Note Ons that have at least one MIDI Pitch Bend associated with them divided by total number of pitched Note Ons.Tr>   r   r?   r   s      r   r   #GlissandoPrevalenceFeature.__init__M  s9    ?l?h?*	` r!   c                    [        S5      er  r  r  s    r   r+   "GlissandoPrevalenceFeature.processV  r  r!   rM   r.   r/   r8   s   @r   r  r  D  r  r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )AverageRangeOfGlissandosFeaturei[  a  
Not yet implemented in music21

Average range of MIDI Pitch Bends, where "range" is defined
as the greatest value of the absolute difference between 64 and the
second data byte of all MIDI Pitch Bend messages falling between the
Note On and Note Off messages of any note
P24c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zAverage Range Of GlissandoszAverage range of MIDI Pitch Bends, where "range" is defined as the greatest value of the absolute difference between 64 and the second data byte of all MIDI Pitch Bend messages falling between the Note On and Note Off messages of any note.Tr>   r   r?   r   s      r   r   (AverageRangeOfGlissandosFeature.__init__f  s:    ?l?h?1	+
 !r!   c                    [        S5      er  r  r  s    r   r+   'AverageRangeOfGlissandosFeature.processr  r  r!   rM   r.   r/   r8   s   @r   r  r  [       
B
? ?r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )VibratoPrevalenceFeatureiw  z
Not yet implemented in music21

Number of notes for which Pitch Bend messages change direction at least twice divided by
total number of notes that have Pitch Bend messages associated with them.

P25c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zVibrato PrevalencezNumber of notes for which Pitch Bend messages change direction at least twice divided by total number of notes that have Pitch Bend messages associated with them.Tr>   r   r?   r   s      r   r   !VibratoPrevalenceFeature.__init__  s;    ?l?h?(	R !r!   c                    [        S5      er  r  r  s    r   r+    VibratoPrevalenceFeature.process  r  r!   rM   r.   r/   r8   s   @r   r  r  w       
B? ?r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )PrevalenceOfMicrotonesFeaturei  z
not yet implemented

Number of Note Ons that are preceded by isolated MIDI Pitch Bend
messages as a fraction of the total number of Note Ons.'

P26c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zPrevalence Of MicrotoneszxNumber of Note Ons that are preceded by isolated MIDI Pitch Bend messages as a fraction of the total number of Note Ons.Tr>   r   r?   r   s      r   r   &PrevalenceOfMicrotonesFeature.__init__  sB     	%l 	%#	% /	[ r!   c                    [        S5      er  r  r  s    r   r+   %PrevalenceOfMicrotonesFeature.process  r  r!   rM   r.   r/   r8   s   @r   r  r    r  r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )StrongestRhythmicPulseFeaturei  a  
Bin label of the beat bin of the peak with the highest frequency.

>>> sch = corpus.parse('schoenberg/opus19', 2)
>>> for p in sch.parts:
...     p.insert(0, tempo.MetronomeMark('Langsam', 70))
>>> fe = features.jSymbolic.StrongestRhythmicPulseFeature(sch)
>>> f = fe.extract()
>>> f.vector[0]
140

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.StrongestRhythmicPulseFeature(s)
>>> f = fe.extract()
>>> f.vector
[96]
R1c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zStrongest Rhythmic Pulsez5Bin label of the beat bin with the highest frequency.Tr>   r   r?   r   s      r   r   &StrongestRhythmicPulseFeature.__init__  s6    ?l?h?.	R r!   c                    U R                   S   nUR                  [        U5      5      U R                  R                  S'   g Nzflat.secondsMap.beatHistogramr   r  r   	beatHistos     r   r+   %StrongestRhythmicPulseFeature.process  s2    II=>	!*Y!@Ar!   rM   r.   r/   r8   s   @r   r  r    s     $ 
BA Ar!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )#SecondStrongestRhythmicPulseFeaturei  a  
Bin label of the beat bin of the peak with the second-highest frequency.

>>> sch = corpus.parse('schoenberg/opus19', 2)
>>> for p in sch.parts:
...     p.insert(0, tempo.MetronomeMark('Langsam', 70))
>>> fe = features.jSymbolic.SecondStrongestRhythmicPulseFeature(sch)
>>> f = fe.extract()
>>> f.vector[0]
70

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.SecondStrongestRhythmicPulseFeature(s)
>>> f = fe.extract()
>>> f.vector
[192]

R2c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zSecond Strongest Rhythmic PulsezHBin label of the beat bin of the peak with the second highest frequency.Tr>   r   r?   r   s      r   r   ,SecondStrongestRhythmicPulseFeature.__init__  s9    ?l?h?5	A r!   c                    [         R                   " U R                  S   5      nUR                  [        U5      5      nSX'   UR                  [        U5      5      U R                  R
                  S'   g r  )rb   r&   rW   rV   r'   r(   )r   r  highestIndexs      r   r+   +SecondStrongestRhythmicPulseFeature.process  sU    IIdii(GHI	 s9~6"#	!*Y!@Ar!   rM   r.   r/   r8   s   @r   r  r    s     $ 
BA Ar!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ ).HarmonicityOfTwoStrongestRhythmicPulsesFeaturei  a*  
The bin label of the higher (in terms of bin label) of the two beat bins of the
peaks with the highest frequency divided by the bin label of the lower.

>>> sch = corpus.parse('schoenberg/opus19', 2)
>>> for p in sch.parts:
...     p.insert(0, tempo.MetronomeMark('Langsam', 70))
>>> fe = features.jSymbolic.HarmonicityOfTwoStrongestRhythmicPulsesFeature(sch)
>>> f = fe.extract()
>>> f.vector[0]
2.0

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.HarmonicityOfTwoStrongestRhythmicPulsesFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.5]

R3c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z,Harmonicity of Two Strongest Rhythmic PulseszThe bin label of the higher (in terms of bin label) of the two beat bins of the peaks with the highest frequency divided by the bin label of the lower.Tr>   r   r?   r   s      r   r   7HarmonicityOfTwoStrongestRhythmicPulsesFeature.__init__  s;    ?l?h?B	E !r!   c                   [         R                   " U R                  S   5      nUR                  [        U5      5      nSX'   UR                  [        U5      5      n[	        X#-  5      U R
                  R                  S'   g r  )rb   r&   rW   rV   r  r'   r(   )r   r  r  secondHighests       r   r+   6HarmonicityOfTwoStrongestRhythmicPulsesFeature.process  sb    IIdii(GHI	 s9~6"#	!I7!&|'C!DAr!   rM   r.   r/   r8   s   @r   r	  r	    s     & 
BE Er!   r	  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )'StrengthOfStrongestRhythmicPulseFeaturei  a$  
Frequency of the beat bin with the highest frequency.

>>> sch = corpus.parse('schoenberg/opus19', 2)
>>> for p in sch.parts:
...     p.insert(0, tempo.MetronomeMark('Langsam', 70))
>>> fe = features.jSymbolic.StrengthOfStrongestRhythmicPulseFeature(sch)
>>> fe.extract().vector[0]
0.853...
R4c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z$Strength of Strongest Rhythmic Pulsez5Frequency of the beat bin with the highest frequency.Tr>   r   r?   r   s      r   r   0StrengthOfStrongestRhythmicPulseFeature.__init__+  s6    ?l?h?:	R r!   c                ~    U R                   S   n[        U5      [        U5      -  U R                  R                  S'   g r  )r&   rV   rG   r'   r(   r  s     r   r+   /StrengthOfStrongestRhythmicPulseFeature.process3  s2    II=>	!$Y#i.!@Ar!   rM   r.   r/   r8   s   @r   r  r    s     	 
BA Ar!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )-StrengthOfSecondStrongestRhythmicPulseFeaturei8  a=  
Frequency of the beat bin of the peak with the second-highest frequency.

>>> sch = corpus.parse('schoenberg/opus19', 2)
>>> for p in sch.parts:
...     p.insert(0, tempo.MetronomeMark('Langsam', 70))
>>> fe = features.jSymbolic.StrengthOfSecondStrongestRhythmicPulseFeature(sch)
>>> fe.extract().vector[0]
0.121...
R5c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z+Strength of Second Strongest Rhythmic PulsezHFrequency of the beat bin of the peak with the second highest frequency.Tr>   r   r?   r   s      r   r   6StrengthOfSecondStrongestRhythmicPulseFeature.__init__F  s9    ?l?h?A	A r!   c                    [         R                   " U R                  S   5      n[        U5      nUR                  [	        U5      5      nSX'   [	        U5      nXB-  U R
                  R                  S'   g r  )rb   r&   rG   rW   rV   r'   r(   )r   r  sumHistor  r  s        r   r+   5StrengthOfSecondStrongestRhythmicPulseFeature.processO  s]    IIdii(GHI	y> s9~6"#	I!.!9Ar!   rM   r.   r/   r8   s   @r   r  r  8  s    	 
B: :r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )0StrengthRatioOfTwoStrongestRhythmicPulsesFeatureiZ  a  
The frequency of the higher (in terms of frequency) of the two beat bins
corresponding to the peaks with the highest frequency divided by the frequency of the lower.


>>> sch = corpus.parse('schoenberg/opus19', 2)
>>> for p in sch.parts:
...     p.insert(0, tempo.MetronomeMark('Langsam', 70))
>>> fe = features.jSymbolic.StrengthRatioOfTwoStrongestRhythmicPulsesFeature(sch)
>>> fe.extract().vector[0]
7.0

R6c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z/Strength Ratio of Two Strongest Rhythmic PulseszThe frequency of the higher (in terms of frequency) of the two beat bins corresponding to the peaks with the highest frequency divided by the frequency of the lower.Tr>   r   r?   r   s      r   r   9StrengthRatioOfTwoStrongestRhythmicPulsesFeature.__init__k  s;    ?l?h?E	O !r!   c                    [         R                   " U R                  S   5      n[        U5      nUR                  U5      nSX'   [        U5      nX$-  U R                  R
                  S'   g r  )rb   r&   rV   rW   r'   r(   )r   r  
theHighestr  r  s        r   r+   8StrengthRatioOfTwoStrongestRhythmicPulsesFeature.processu  sY    IIdii(GHI	^
 z2"#	I!+!;Ar!   rM   r.   r/   r8   s   @r   r   r   Z  s     
B< <r!   r   c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )3CombinedStrengthOfTwoStrongestRhythmicPulsesFeaturei  aU  
The sum of the frequencies of the two beat bins of the peaks with the highest frequencies.

>>> sch = corpus.parse('schoenberg/opus19', 2)
>>> for p in sch.parts:
...     p.insert(0, tempo.MetronomeMark('Langsam', 70))
>>> fe = features.jSymbolic.CombinedStrengthOfTwoStrongestRhythmicPulsesFeature(sch)
>>> fe.extract().vector[0]
0.975...
R7c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z2Combined Strength of Two Strongest Rhythmic PulseszZThe sum of the frequencies of the two beat bins of the peaks with the highest frequencies.Tr>   r   r?   r   s      r   r   <CombinedStrengthOfTwoStrongestRhythmicPulsesFeature.__init__  s9    ?l?h?H	I r!   c                    [         R                   " U R                  S   5      n[        U5      n[        U5      nUR	                  U5      nSX'   [        U5      nX5-   U-  U R
                  R                  S'   g r  )rb   r&   rG   rV   rW   r'   r(   )r   r  r  r%  r  r  s         r   r+   ;CombinedStrengthOfTwoStrongestRhythmicPulsesFeature.process  sg    IIdii(GHI	y>^
 z2"#	I","<!HAr!   rM   r.   r/   r8   s   @r   r(  r(    s     	 
B	I 	Ir!   r(  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )NumberOfStrongPulsesFeaturei  zR
Not yet implemented

Number of beat peaks with normalized frequencies over 0.1.

R8c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zNumber of Strong Pulsesz:Number of beat peaks with normalized frequencies over 0.1.Tr>   r   r?   r   s      r   r   $NumberOfStrongPulsesFeature.__init__  s6    ?l?h?-	W r!   c                    [        S5      er  r  r  s    r   r+   #NumberOfStrongPulsesFeature.process  r  r!   rM   r.   r/   r8   s   @r   r/  r/    s     
B? ?r!   r/  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )NumberOfModeratePulsesFeaturei  zR
Not yet implemented

Number of beat peaks with normalized frequencies over 0.01.
R9c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zNumber of Moderate Pulsesz;Number of beat peaks with normalized frequencies over 0.01.Tr>   r   r?   r   s      r   r   &NumberOfModeratePulsesFeature.__init__  s6    ?l?h?/	X r!   c                    [        S5      er  r  r  s    r   r+   %NumberOfModeratePulsesFeature.process  r  r!   rM   r.   r/   r8   s   @r   r6  r6    s    
 
B? ?r!   r6  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )%NumberOfRelativelyStrongPulsesFeaturei  z
not yet implemented

Number of beat peaks with frequencies at least 30% as high as the
frequency of the bin with the highest frequency.
R10c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z"Number of Relatively Strong PulseszrNumber of beat peaks with frequencies at least 30% as high as the frequency of the bin with the highest frequency.Tr>   r   r?   r   s      r   r   .NumberOfRelativelyStrongPulsesFeature.__init__  s9    ?l?h?8	S r!   rM   r.   	r0   r1   r2   r3   r4   r5   r   r6   r7   r8   s   @r   r=  r=    s     
B r!   r=  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )RhythmicLoosenessFeaturei  a   
not yet implemented

Average width of beat histogram peaks (in beats per minute).
Width is measured for all peaks with frequencies at least 30% as high as the highest peak,
and is defined by the distance between the points on the peak in question that are
30% of the height of the peak.
R11c                t   > [         TU ]  " SSU0UD6  SU l        [        S5      U l        SU l        SU l        g )Nr   zRhythmic Loosenessa:  
            Average width of beat histogram peaks (in beats per minute).
            Width is measured for all peaks with frequencies at least 30% as high as the
            highest peak, and is defined by the distance between the points on the peak in
            question that are 30% of the height of the peak.Tr>   r   r   r   r   r   r   r   r   r   s      r   r   !RhythmicLoosenessFeature.__init__  sD    ?l?h?(	! #@ A
 !r!   c                    [        S5      er  r  r  s    r   r+    RhythmicLoosenessFeature.process  r  r!   rM   r.   r/   r8   s   @r   rC  rC    r  r!   rC  c                  ,    \ rS rSrSrSrSS jrS rSrg)	PolyrhythmsFeaturei  a  
Not yet implemented

Number of beat peaks with frequencies at least 30% of the highest frequency
whose bin labels are not integer multiples or factors
(using only multipliers of 1, 2, 3, 4, 6 and 8) (with an accepted
error of +/- 3 bins) of the bin label of the peak with the highest frequency.
This number is then divided by the total number of beat bins with frequencies
over 30% of the highest frequency.
R12Nc                    [         R                  R                  " U 4SU0UD6  SU l        SU l        SU l        SU l        g )Nr   Polyrhythmsa  
        Number of beat peaks with frequencies at least 30% of the highest frequency
        whose bin labels are not integer multiples or factors
        (using only multipliers of 1, 2, 3, 4, 6 and 8) (with an accepted
        error of +/- 3 bins) of the bin label of the peak with the highest frequency.
        This number is then divided by the total number of beat bins with frequencies
        over 30% of the highest frequency.Tr>   )featuresModuleFeatureExtractorr   r   r   r   r   )r   r   r   s      r   r   PolyrhythmsFeature.__init__
  sL    ''00 	=>J	=3;	= "	. !r!   c                    [        S5      er  r  r  s    r   r+   PolyrhythmsFeature.process  r  r!   rM   r.   )	r0   r1   r2   r3   r4   r5   r   r+   r6   r   r!   r   rK  rK    s    	 
B ?r!   rK  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )RhythmicVariabilityFeaturei  z]
Not yet implemented

Standard deviation of the bin values (except the first 40 empty ones).
R13c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zRhythmic VariabilityzFStandard deviation of the bin values (except the first 40 empty ones).Tr>   r   r?   r   s      r   r   #RhythmicVariabilityFeature.__init__'  s6    ?l?h?*	c r!   c                    [        S5      er  r  r  s    r   r+   "RhythmicVariabilityFeature.process/  r  r!   rM   r.   r/   r8   s   @r   rU  rU    s    
 
B? ?r!   rU  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )BeatHistogramFeaturei4  z
Not yet implemented

A feature extractor that finds a feature array with entries corresponding to the frequency
values of each of the bins of the beat histogram (except the first 40 empty ones).


R14c                p   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SU l        g )Nr   zBeat HistogramzA feature array with entries corresponding to the frequency values of each of the bins of the beat histogram (except the first 40 empty ones).T   Fr   r  r   s      r   r   BeatHistogramFeature.__init__?  sB    ?l?h?$	@ !r!   c                    [        S5      er  r  r  s    r   r+   BeatHistogramFeature.processJ  r  r!   r  r.   r/   r8   s   @r   r\  r\  4  s     
B	? ?r!   r\  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )NoteDensityFeatureiO  a  
Gives the average number of notes per second, taking into account
the tempo at any moment in the piece.  Unlike jSymbolic, music21
quantizes notes from MIDI somewhat before running this test; this
function is meant to be run on encoded MIDI scores rather than
recorded MIDI performances.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.NoteDensityFeature(s)
>>> f = fe.extract()
>>> f.vector
[7.244...]
R15c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zNote Densityz#Average number of notes per second.Tr>   r   r?   r   s      r   r   NoteDensityFeature.__init___  s6    ?l?h?"	@ r!   c                   U R                   S   nU Vs/ s H  o"S   PM	     nnUR                  5         U(       d  SU R                  R                  S'   g [	        [        U5      5      US   -  U R                  R                  S'   g s  snf )Nflat.secondsMapendTimeSecondsr  r   r   )r&   sortr'   r(   r  rH   r   
secondsMapbundle	end_timess       r   r+   NoteDensityFeature.processg  sy    YY01
 =GGJ&,-J	G%(DLL"%*3y>%:Yr]%JDLL" Hs   BrM   r.   r/   r8   s   @r   rd  rd  O  s      
BK Kr!   rd  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )AverageNoteDurationFeatureiu  aK  
Average duration of notes in seconds.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.AverageNoteDurationFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.552...]

>>> s.insert(0, tempo.MetronomeMark(number=240))
>>> fe = features.jSymbolic.AverageNoteDurationFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.220858...]
R17c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zAverage Note Durationz%Average duration of notes in seconds.Tr>   r   r?   r   s      r   r   #AverageNoteDurationFeature.__init__  s6    ?l?h?+	B r!   c                    U R                   S   nU(       d  [        S5      eSnU H
  nX#S   -  nM     U[        U5      -  U R                  R                  S'   g Nri  rC   r  durationSecondsr   r&   rF   rH   r'   r(   )r   rm  r   rn  s       r   r+   "AverageNoteDurationFeature.process  sZ    YY01
+,?@@ F-..E !!&Z!8Ar!   rM   r.   r/   r8   s   @r   rr  rr  u  s      
B9 9r!   rr  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ ) VariabilityOfNoteDurationFeaturei  a2  
Standard deviation of note durations in seconds.

# In this piece, we have:
#     9 half notes or tied pair of quarters
#     98 untied quarters or tied pair of eighths
#     56 untied eighths
# BPM = 120 means a half note is a second.
# Mean duration should thus be 0.44171779141104295
# and standard deviation should be  0.17854763448902145

>>> s = corpus.parse('bwv66.6')
>>> for p in s.parts:
...     p.insert(0, tempo.MetronomeMark(number=120))
>>> fe = features.jSymbolic.VariabilityOfNoteDurationFeature(s)
>>> f = fe.extract()
>>> f.vector[0]
0.178...
R18c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zVariability of Note Durationz0Standard deviation of note durations in seconds.Tr>   r   r?   r   s      r   r   )VariabilityOfNoteDurationFeature.__init__  s6    ?l?h?2	M r!   c                    U R                   S   nU(       d  [        S5      e/ nU H  nUR                  US   5        M     [        R                  " U5      U R
                  R                  S'   g )Nri  rC   rx  r   )r&   rF   rE   rr  pstdevr'   r(   )r   rm  note_durationsrn  s       r   r+   (VariabilityOfNoteDurationFeature.process  sb    YY01
+,?@@ F!!&):";< !!+!2!2>!BAr!   rM   r.   r/   r8   s   @r   r|  r|    s     & 
BC Cr!   r|  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )MaximumNoteDurationFeaturei  z
Duration of the longest note (in seconds).

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.MaximumNoteDurationFeature(s)
>>> f = fe.extract()
>>> f.vector
[1.25]
R19c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zMaximum Note Durationz*Duration of the longest note (in seconds).Tr>   r   r?   r   s      r   r   #MaximumNoteDurationFeature.__init__  s6    ?l?h?+	G r!   c                    U R                   S   nU(       d  [        S5      eSnU H  nUS   U:  d  M  US   nM     X R                  R                  S'   g rw  r&   rF   r'   r(   )r   rm  
maxSecondsrn  s       r   r+   "MaximumNoteDurationFeature.process  s\    YY01
+,?@@
 F'(:5#$56
 ! ",Ar!   rM   r.   r/   r8   s   @r   r  r    s     
B, ,r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )MinimumNoteDurationFeaturei  z
Duration of the shortest note (in seconds).

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.MinimumNoteDurationFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.3125]
R20c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zMinimum Note Durationz+Duration of the shortest note (in seconds).Tr>   r   r?   r   s      r   r   #MinimumNoteDurationFeature.__init__  s6    ?l?h?+	H r!   c                    U R                   S   nU(       d  [        S5      eUS   S   nU H  nUS   U:  d  M  US   nM     X R                  R                  S'   g )Nri  rC   r   rx  r  )r   rm  
minSecondsrn  s       r   r+   "MinimumNoteDurationFeature.process  sf    YY01
+,?@@]#45
 F'(:5#$56
 ! ",Ar!   rM   r.   r/   r8   s   @r   r  r    s     
B	, 	,r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )StaccatoIncidenceFeaturei	  z
Number of notes with durations of less than a 10th of a second divided by
the total number of notes in the recording.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.StaccatoIncidenceFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.0]
R21c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zStaccato IncidencezuNumber of notes with durations of less than a 10th of a second divided by the total number of notes in the recording.Tr>   r   r?   r   s      r   r   !StaccatoIncidenceFeature.__init__	  s9    ?l?h?(	a r!   c                    U R                   S   nU(       d  [        S5      eSnU H  nUS   S:  d  M  US-  nM     U[        U5      -  U R                  R                  S'   g )Nri  rC   r   rx  g?r>   ry  )r   rm  ro   rn  s       r   r+    StaccatoIncidenceFeature.process	  se    YY01
+,?@@ F'(4/
 ! "'Z!8Ar!   rM   r.   r/   r8   s   @r   r  r  	  s    	 
B9 9r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ ) AverageTimeBetweenAttacksFeaturei$	  a%  
Average time in seconds between Note On events (regardless of channel).

>>> s = corpus.parse('bwv66.6')
>>> for p in s.parts:
...     p.insert(0, tempo.MetronomeMark(number=120))
>>> fe = features.jSymbolic.AverageTimeBetweenAttacksFeature(s)
>>> f = fe.extract()
>>> print(f.vector)
[0.35]
R22c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zAverage Time Between AttackszGAverage time in seconds between Note On events (regardless of channel).Tr>   r   r?   r   s      r   r   )AverageTimeBetweenAttacksFeature.__init__3	  s6    ?l?h?2	d r!   c                   U R                   S   nU Vs/ s H  o"S   PM	     nnU(       d  [        S5      eUR                  5         / n[        U5       HG  u  pVU[	        U5      S-
  :X  a    O2X5S-      nXv-
  n[        USSS9(       a  M6  UR                  U5        MI     [        U5      [	        U5      -  U R                  R                  S'   g s  snf 	Nri  offsetSecondsrC   r>   r  Hz>abs_tolr   )
r&   rF   rk  r%   rH   r   rE   rG   r'   r(   	r   rm  rn  onsetsdifferencesr)   ooNextdifs	            r   r+   (AverageTimeBetweenAttacksFeature.process;	  s    YY01
8BC
f)
C+,?@@f%DACK!O#q5ME)C3T22""3' & "%[!1C4D!DA Ds   CrM   r.   r/   r8   s   @r   r  r  $	  s     
 
BE Er!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )&VariabilityOfTimeBetweenAttacksFeatureiO	  z
Standard deviation of the times, in seconds, between Note On events (regardless of channel).

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.VariabilityOfTimeBetweenAttacksFeature(s)
>>> f = fe.extract()
>>> print(f.vector)
[0.1875]
R23c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z#Variability of Time Between Attacksz\Standard deviation of the times, in seconds, between Note On events (regardless of channel).Tr>   r   r?   r   s      r   r   /VariabilityOfTimeBetweenAttacksFeature.__init__\	  s9    ?l?h?9	N r!   c                   U R                   S   nU Vs/ s H  o"S   PM	     nnU(       d  [        S5      eUR                  5         / n[        U5       HG  u  pVU[	        U5      S-
  :X  a    O2X5S-      nXv-
  n[        USSS9(       a  M6  UR                  U5        MI     [        R                  " U5      U R                  R                  S'   g s  snf r  )r&   rF   rk  r%   rH   r   rE   rr  r  r'   r(   r  s	            r   r+   .VariabilityOfTimeBetweenAttacksFeature.processe	  s    YY01
8BC
f)
C+,?@@f%DACK!O#q5ME)C3T22""3' & ",!2!2;!?A Ds   CrM   r.   r/   r8   s   @r   r  r  O	  s      
B@ @r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ ),AverageTimeBetweenAttacksForEachVoiceFeatureix	  a`  
Average of average times in seconds between Note On events on individual channels
that contain at least one note.

>>> s = corpus.parse('bwv66.6')
>>> for p in s.parts:
...     p.insert(0, tempo.MetronomeMark(number=120))
>>> fe = features.jSymbolic.AverageTimeBetweenAttacksForEachVoiceFeature(s)
>>> f = fe.extract()
>>> print(f.vector[0])
0.442...
R24c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z+Average Time Between Attacks For Each VoicezqAverage of average times in seconds between Note On events on individual channels that contain at least one note.Tr>   r   r?   r   s      r   r   5AverageTimeBetweenAttacksForEachVoiceFeature.__init__	  s9    ?l?h?A	U r!   c                ,   / n/ nU R                   R                  S:  aa  [        U R                   R                  5       H=  nU R                   S   U   S   nU Vs/ s H  oUS   PM	     nnUR                  U5        M?     O4U R                   S   nU Vs/ s H  oUS   PM	     nnUR                  U5        U H  nUR	                  5         / n[        U5       HG  u  p8U[        U5      S-
  :X  a    O2XcS-      n	X-
  n
[        U
SSS9(       a  M6  UR                  U
5        MI     U(       d  [        S	5      eUR                  [        U5      [        U5      -  5        M     [        U5      [        U5      -  U R                  R                  S'   g s  snf s  snf 
Nr   r   ri  r  r>   r  r  r  zat least one part lacks notes)r&   r   rD   rE   rk  r%   rH   r   rF   rG   r'   r(   )r   onsetsByPart	avgByPartr)   rm  rn  r  r  r  r  r  s              r   r+   4AverageTimeBetweenAttacksForEachVoiceFeature.process	  ss   	99!#499//0!YYw/23DE
@JK
f1
K##F+ 1
 #45J<FGJ&_-JFG'"FKKMK!&)Fa'1uisC66&&s+ * /0OPPS-K0@@A #  "%Y#i.!@A/ L Hs   FFrM   r.   r/   r8   s   @r   r  r  x	  s      
BA Ar!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )9AverageVariabilityOfTimeBetweenAttacksForEachVoiceFeaturei	  aq  
Average standard deviation, in seconds, of time between Note On events on individual
channels that contain at least one note.

>>> s = corpus.parse('bwv66.6')
>>> for p in s.parts:
...     p.insert(0, tempo.MetronomeMark(number=120))
>>> fe = features.jSymbolic.AverageVariabilityOfTimeBetweenAttacksForEachVoiceFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.177...]
R25c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z:Average Variability of Time Between Attacks For Each Voicez}Average standard deviation, in seconds, of time between Note On events on individual channels that contain at least one note.Tr>   r   r?   r   s      r   r   BAverageVariabilityOfTimeBetweenAttacksForEachVoiceFeature.__init__	  s:    ?l?h?P	1 !r!   c                *   / n/ nU R                   R                  S:  aa  [        U R                   R                  5       H=  nU R                   S   U   S   nU Vs/ s H  oUS   PM	     nnUR                  U5        M?     O4U R                   S   nU Vs/ s H  oUS   PM	     nnUR                  U5        U H  nUR	                  5         / n[        U5       HG  u  p8U[        U5      S-
  :X  a    O2XcS-      n	X-
  n
[        U
SSS9(       a  M6  UR                  U
5        MI     U(       d  [        S	5      eUR                  [        R                  " U5      5        M     [        U5      [        U5      -  U R                  R                  S'   g s  snf s  snf r  )r&   r   rD   rE   rk  r%   rH   r   rF   rr  r  rG   r'   r(   )r   r  stdDeviationByPartr)   rm  rn  r  r  r  r  r  s              r   r+   AAverageVariabilityOfTimeBetweenAttacksForEachVoiceFeature.process	  sw   99!#499//0!YYw/23DE
@JK
f1
K##F+ 1
 #45J<FGJ&_-JFG'"FKKMK!&)Fa'1uisC66&&s+ * /0OPP%%j&7&7&DE # #&&8"9$'(:$;#<A- L Hs   FFrM   r.   r/   r8   s   @r   r  r  	  s     
B= =r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )InitialTempoFeaturei,
  z
Tempo in beats per minute at the start of the recording.

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.InitialTempoFeature(s)
>>> f = fe.extract()
>>> f.vector  # a default
[96.0]
R30c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zInitial Tempoz8Tempo in beats per minute at the start of the recording.Tr>   r   r?   r   s      r   r   InitialTempoFeature.__init__9
  s6    ?l?h?#	U r!   c                    U R                   S   nUS   S   nUR                  5       U R                  R                  S'   g )NmetronomeMarkBoundariesr   r   )r&   getQuarterBPMr'   r(   )r   triplesmms      r   r+   InitialTempoFeature.processA
  s;    ))56QZ]!#!1!1!3Ar!   rM   r.   r/   r8   s   @r   r  r  ,
  s     
B4 4r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )InitialTimeSignatureFeatureiI
  a  
A feature array with two elements. The first is the numerator of the first occurring
time signature and the second is the denominator of the first occurring time signature.
Both are set to 0 if no time signature is present.

>>> s1 = stream.Stream()
>>> s1.append(meter.TimeSignature('3/4'))
>>> fe = features.jSymbolic.InitialTimeSignatureFeature(s1)
>>> fe.extract().vector
[3, 4]

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.InitialTimeSignatureFeature(s)
>>> f = fe.extract()
>>> f.vector
[4, 4]
R31c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zInitial Time SignaturezA feature array with two elements. The first is the numerator of the first occurring time signature and the second is the denominator of the first occurring time signature. Both are set to 0 if no time signature is present.Tr   r   r?   r   s      r   r   $InitialTimeSignatureFeature.__init__^
  s;    ?l?h?,	\ !r!   c                   U R                   S   nU(       d  g US   n[        R                  SU/5        US   R                  U R                  R
                  S'   US   R                  U R                  R
                  S'   g )N&flat.getElementsByClass(TimeSignature)r   zfound tsr>   )r&   environLocal
printDebug	numeratorr'   r(   denominator)r   elementstss      r   r+   #InitialTimeSignatureFeature.processi
  so    99EFa[R 01!)!!6!6A!)!!8!8Ar!   rM   r.   r/   r8   s   @r   r  r  I
  s    $ 
B	9 9r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )CompoundOrSimpleMeterFeatureis
  an  
Set to 1 if the initial meter is compound (numerator of time signature
is greater than or equal to 6 and is evenly divisible by 3) and to 0 if it is simple
(if the above condition is not fulfilled).

>>> s1 = stream.Stream()
>>> s1.append(meter.TimeSignature('3/4'))
>>> fe = features.jSymbolic.CompoundOrSimpleMeterFeature(s1)
>>> fe.extract().vector
[0]

>>> s2 = stream.Stream()
>>> s2.append(meter.TimeSignature('9/8'))
>>> fe.setData(s2)  # change the data
>>> fe.extract().vector
[1]

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.CompoundOrSimpleMeterFeature(s)
>>> f = fe.extract()
>>> f.vector
[0]
R32c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zCompound Or Simple MeterzSet to 1 if the initial meter is compound (numerator of time signature is greater than or equal to 6 and is evenly divisible by 3) and to 0 if it is simple (if the above condition is not fulfilled).Tr>   r   r?   r   s      r   r   %CompoundOrSimpleMeterFeature.__init__
  s;    ?l?h?.	I !r!   c                    U R                   S   nU(       a1   US   R                  nUS:X  a  SU R                  R
                  S'   g g g ! [        R                   a     g f = f)Nr  r   Compoundr>   )r&   beatDivisionCountNamer	   TimeSignatureExceptionr'   r(   )r   r  	countNames      r   r+   $CompoundOrSimpleMeterFeature.process
  sj    99EF$QK==	 J&)*##A& '   66 s   A	 	A A rM   r.   r/   r8   s   @r   r  r  s
  s    0 
B		+ 	+r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )TripleMeterFeaturei
  a  
Set to 1 if numerator of initial time signature is 3, set to 0 otherwise.

>>> s1 = stream.Stream()
>>> s1.append(meter.TimeSignature('5/4'))
>>> fe = features.jSymbolic.TripleMeterFeature(s1)
>>> fe.extract().vector
[0]

>>> s2 = stream.Stream()
>>> s2.append(meter.TimeSignature('3/4'))
>>> fe.setData(s2)  # change the data
>>> fe.extract().vector
[1]

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.TripleMeterFeature(s)
>>> f = fe.extract()
>>> f.vector
[0]
R33c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zTriple MeterzISet to 1 if numerator of initial time signature is 3, set to 0 otherwise.Tr>   r   r?   r   s      r   r   TripleMeterFeature.__init__
  s8    ?l?h?"	2 r!   c                    U R                   S   nU(       a.  US   R                  S:X  a  SU R                  R                  S'   g g g )Nr  r   r   r>   r&   r  r'   r(   r   r  s     r   r+   TripleMeterFeature.process
  s@    99EF--2%&DLL" 38r!   rM   r.   r/   r8   s   @r   r  r  
  s    , 
B' 'r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )QuintupleMeterFeaturei
  a  
Set to 1 if numerator of initial time signature is 5, set to 0 otherwise.

>>> s1 = stream.Stream()
>>> s1.append(meter.TimeSignature('5/4'))
>>> fe = features.jSymbolic.QuintupleMeterFeature(s1)
>>> fe.extract().vector
[1]

>>> s2 = stream.Stream()
>>> s2.append(meter.TimeSignature('3/4'))
>>> fe.setData(s2)  # change the data
>>> fe.extract().vector
[0]

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.QuintupleMeterFeature(s)
>>> f = fe.extract()
>>> f.vector
[0]
R34c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zQuintuple MeterzISet to 1 if numerator of initial time signature is 5, set to 0 otherwise.Tr>   r   r?   r   s      r   r   QuintupleMeterFeature.__init__
  s8    ?l?h?%	2 r!   c                    U R                   S   nU(       a.  US   R                  S:X  a  SU R                  R                  S'   g g g )Nr  r      r>   r  r  s     r   r+   QuintupleMeterFeature.process
  s@    99EF--2%&DLL" 38r!   rM   r.   r/   r8   s   @r   r  r  
  s    , 
B' 'r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )ChangesOfMeterFeaturei
  a  
Returns 1 if the time signature is changed one or more
times during the recording.

>>> s1 = stream.Stream()
>>> s1.append(meter.TimeSignature('3/4'))
>>> fe = features.jSymbolic.ChangesOfMeterFeature(s1)
>>> fe.extract().vector
[0]

>>> s2 = stream.Stream()
>>> s2.append(meter.TimeSignature('3/4'))
>>> s2.append(meter.TimeSignature('4/4'))
>>> fe.setData(s2)  # change the data
>>> fe.extract().vector
[1]

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.ChangesOfMeterFeature(s)
>>> f = fe.extract()
>>> f.vector
[0]
R35c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zChanges of MeterzPSet to 1 if the time signature is changed one or more times during the recordingTr>   r   r?   r   s      r   r   ChangesOfMeterFeature.__init__  s8    ?l?h?&	9 r!   c                    U R                   S   n[        U5      S::  a  g US   nUSS   H4  nUR                  U5      (       a  M  SU R                  R                  S'     g    g )Nr  r>   r   )r&   rH   
ratioEqualr'   r(   )r   r  firstes       r   r+   ChangesOfMeterFeature.process  sa    99EFx=A!"A##A&&)*##A& r!   rM   r.   r/   r8   s   @r   r  r  
  s    . 
B r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )DurationFeaturei$  a  
A feature extractor that extracts the duration of the piece in seconds.

>>> s = corpus.parse('bwv66.6')
>>> for p in s.parts:
...     p.insert(0, tempo.MetronomeMark(number=120))
>>> fe = features.jSymbolic.DurationFeature(s)
>>> f = fe.extract()
>>> f.vector[0]
18.0
R36c                p   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SU l        g )Nr   Durationz+The total duration in seconds of the music.Fr>   r   r  r   s      r   r   DurationFeature.__init__2  s=    ?l?h?	H!r!   c                    U R                   S   nU(       d  [        S5      eU Vs/ s H  o"S   PM	     nnUR                  5         US   U R                  R                  S'   g s  snf )Nri  zinput lacks durationrj  r   r   )r&   rF   rk  r'   r(   rl  s       r   r+   DurationFeature.process;  sc    YY01
+,BCC =GGJ&,-J	G!*2A Hs   A#r  r.   r/   r8   s   @r   r  r  $  s    
 
B/ /r!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )OverallDynamicRangeFeatureiJ  zZ
Not implemented

The maximum loudness minus the minimum loudness value.

TODO: implement
D1c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zOverall Dynamic Rangez6The maximum loudness minus the minimum loudness value.Tr>   r   r?   r   s      r   r   #OverallDynamicRangeFeature.__init__T  s6    ?l?h?+	S r!   rM   r.   rA  r8   s   @r   r  r  J  s     
B r!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )VariationOfDynamicsFeaturei]  zY
Not implemented

Standard deviation of loudness levels of all notes.


TODO: implement

D2c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zVariation of Dynamicsz3Standard deviation of loudness levels of all notes.Tr>   r   r?   r   s      r   r   #VariationOfDynamicsFeature.__init__i  s6    ?l?h?+	P r!   rM   r.   rA  r8   s   @r   r  r  ]  s     
B r!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )%VariationOfDynamicsInEachVoiceFeatureir  z
Not implemented

The average of the standard deviations of loudness levels within each
channel that contains at least one note.

TODO: implement

D3c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z#Variation of Dynamics In Each VoiceznThe average of the standard deviations of loudness levels within each channel that contains at least one note.Tr>   r   r?   r   s      r   r   .VariationOfDynamicsInEachVoiceFeature.__init__~  s9    ?l?h?9	Z r!   rM   r.   rA  r8   s   @r   r  r  r  s     
B r!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )&AverageNoteToNoteDynamicsChangeFeaturei  z
Not implemented

Average change of loudness from one note to the next note in the
same channel (in MIDI velocity units).


TODO: implement

D4c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z$Average Note To Note Dynamics ChangezgAverage change of loudness from one note to the next note in the same channel (in MIDI velocity units).Tr>   r   r?   r   s      r   r   /AverageNoteToNoteDynamicsChangeFeature.__init__  s9    ?l?h?:	L r!   rM   r.   rA  r8   s   @r   r  r    s    	 
B r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )'MaximumNumberOfIndependentVoicesFeaturei  a  
Maximum number of different channels in which notes have sounded simultaneously.
Here, Parts are treated as channels.

>>> s = corpus.parse('handel/rinaldo/lascia_chio_pianga')
>>> fe = features.jSymbolic.MaximumNumberOfIndependentVoicesFeature(s)
>>> f = fe.extract()
>>> f.vector
[3]

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.MaximumNumberOfIndependentVoicesFeature(s)
>>> f = fe.extract()
>>> f.vector
[4]
T1c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z$Maximum Number of Independent VoiceszuMaximum number of different channels in which notes have sounded simultaneously. Here, Parts are treated as channels.Tr>   r   r?   r   s      r   r   0MaximumNumberOfIndependentVoicesFeature.__init__  s9    ?l?h?:	` r!   c                &   SnU R                   S    Hd  n[        R                  " 5       nUR                   H'  nUR                   H  nUR                  U5        M     M)     [        U[        U5      5      nMf     XR                  R                  S'   g )Nr   'chordify.flat.getElementsByClass(Chord))
r&   r   Groupsrq  groupsrE   rV   rH   r'   r(   r   foundr   gru  gSubs         r   r+   /MaximumNumberOfIndependentVoicesFeature.process  sv    DEA AYYHHDHHTN %  s1v&E F "'Ar!   rM   r.   r/   r8   s   @r   r#  r#    s    " 
B' 'r!   r#  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )'AverageNumberOfIndependentVoicesFeaturei  a  
Average number of different channels in which notes have sounded simultaneously.
Rests are not included in this calculation. Here, Parts are treated as voices

>>> s = corpus.parse('handel/rinaldo/lascia_chio_pianga')
>>> fe = features.jSymbolic.AverageNumberOfIndependentVoicesFeature(s)
>>> f = fe.extract()
>>> f.vector
[1.528...]

>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.AverageNumberOfIndependentVoicesFeature(s)
>>> f = fe.extract()
>>> f.vector
[3.90...]
T2c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z$Average Number of Independent VoiceszAverage number of different channels in which notes have sounded simultaneously. Rests are not included in this calculation. Here, Parts are treated as voicesTr>   r   r?   r   s      r   r   0AverageNumberOfIndependentVoicesFeature.__init__  s;    ?l?h?:	M !r!   c                   / nU R                   S    Hi  n[        R                  " 5       nUR                   H'  nUR                   H  nUR                  U5        M     M)     UR                  [        U5      5        Mk     U(       d  [        S5      e[        U5      [        U5      -  U R                  R                  S'   g )Nr(  rC   r   )r&   r   r)  rq  r*  rE   rH   rF   rG   r'   r(   r+  s         r   r+   /AverageNumberOfIndependentVoicesFeature.process  s    DEA AYYHHDHHTN %  LLQ  F +,?@@!$Uc%j!8Ar!   rM   r.   r/   r8   s   @r   r1  r1    s      
B9 9r!   r1  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )-VariabilityOfNumberOfIndependentVoicesFeaturei  a(  
Standard deviation of number of different channels in which notes have sounded simultaneously.
Rests are not included in this calculation.


>>> s = corpus.parse('bwv66.6')
>>> fe = features.jSymbolic.VariabilityOfNumberOfIndependentVoicesFeature(s)
>>> f = fe.extract()
>>> f.vector
[0.449...]
T3c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z+Variability of Number of Independent VoiceszStandard deviation of number of different channels in which notes have sounded simultaneously. Rests are not included in this calculation.Tr>   r   r?   r   s      r   r   6VariabilityOfNumberOfIndependentVoicesFeature.__init__  s;    ?l?h?A	@ !r!   c                ~   / nU R                   S    Hi  n[        R                  " 5       nUR                   H'  nUR                   H  nUR                  U5        M     M)     UR                  [        U5      5        Mk     U(       a.  [        R                  " U5      U R                  R                  S'   g [        S5      e)Nr(  r   rC   )r&   r   r)  rq  r*  rE   rH   rr  r  r'   r(   rF   r+  s         r   r+   5VariabilityOfNumberOfIndependentVoicesFeature.process  s    DEA AYYHHDHHTN %  LLQ  F %/%6%6u%=DLL"+,?@@r!   rM   r.   r/   r8   s   @r   r8  r8    s     
 
BA Ar!   r8  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )!VoiceEqualityNumberOfNotesFeaturei&  z
Not implemented



TODO: implement

Standard deviation of the total number of Note Ons in each channel
that contains at least one note.
T4c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z Voice Equality - Number of NoteszcStandard deviation of the total number of Note Ons in each channel that contains at least one note.Tr>   r   r?   r   s      r   r   *VoiceEqualityNumberOfNotesFeature.__init__3  s9    ?l?h?6	O r!   rM   r.   rA  r8   s   @r   r?  r?  &  s    	 
B r!   r?  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ ) VoiceEqualityNoteDurationFeaturei=  %
Not implemented



TODO: implement

T5c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zVoice Equality - Note DurationzmStandard deviation of the total duration of notes in seconds in each channel that contains at least one note.Tr>   r   r?   r   s      r   r   )VoiceEqualityNoteDurationFeature.__init__H  s9    ?l?h?4	O r!   rM   r.   rA  r8   s   @r   rD  rD  =       
B r!   rD  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )VoiceEqualityDynamicsFeatureiR  rE  T6c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zVoice Equality - DynamicszbStandard deviation of the average volume of notes in each channel that contains at least one note.Tr>   r   r?   r   s      r   r   %VoiceEqualityDynamicsFeature.__init__]  s9    ?l?h?/	O r!   rM   r.   rA  r8   s   @r   rK  rK  R  rI  r!   rK  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ ) VoiceEqualityMelodicLeapsFeatureig  rE  T7c                t   > [         TU ]  " SSU0UD6  SU l        [        S5      U l        SU l        SU l        g )Nr   zVoice Equality - Melodic Leapsz
            Standard deviation
            of the average melodic leap in MIDI pitches
            for each channel that contains at least one note.Tr>   r   rF  r   s      r   r   )VoiceEqualityMelodicLeapsFeature.__init__r  sD    ?l?h?4	! #A B !r!   rM   r.   rA  r8   s   @r   rP  rP  g  s     
B	 	r!   rP  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )VoiceEqualityRangeFeaturei~  z
Not implemented

Standard deviation of the differences between the highest and lowest
pitches in each channel that contains at least one note.
T8c                t   > [         TU ]  " SSU0UD6  SU l        [        S5      U l        SU l        SU l        g )Nr   zVoice Equality - Rangez
            Standard deviation of the differences between the
            highest and lowest pitches in each channel that contains at least one note.Tr>   r   rF  r   s      r   r   "VoiceEqualityRangeFeature.__init__  sD    ?l?h?,	! #[ \ !r!   rM   r.   rA  r8   s   @r   rU  rU  ~  s     
B r!   rU  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )ImportanceOfLoudestVoiceFeaturei  "
Not implemented

TODO: implement
T9c                t   > [         TU ]  " SSU0UD6  SU l        [        S5      U l        SU l        SU l        g )Nr   zImportance of Loudest Voicez
            Difference between the average loudness
            of the loudest channel and the average loudness of the other channels
            that contain at least one note.Tr>   r   rF  r   s      r   r   (ImportanceOfLoudestVoiceFeature.__init__  sB    ?l?h?1	! #/ 0 !r!   rM   r.   rA  r8   s   @r   rZ  rZ    s    
 
B	 	r!   rZ  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )"RelativeRangeOfLoudestVoiceFeaturei  r[  T10c                t   > [         TU ]  " SSU0UD6  SU l        [        S5      U l        SU l        SU l        g )Nr   zRelative Range of Loudest Voicez
            Difference between the highest note and the lowest note
            played in the channel with the highest average loudness divided by the difference
            between the highest note and the lowest note overall in the piece.Tr>   r   rF  r   s      r   r   +RelativeRangeOfLoudestVoiceFeature.__init__  sD    ?l?h?5	! #R S !r!   rM   r.   rA  r8   s   @r   r`  r`        
 
B	 	r!   r`  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )RangeOfHighestLineFeaturei  r[  T12c                t   > [         TU ]  " SSU0UD6  SU l        [        S5      U l        SU l        SU l        g )Nr   zRange of Highest Linez
            Difference between the highest note and the lowest note
            played in the channel with the highest average pitch divided by the difference
            between the highest note and the lowest note in the piece.Tr>   r   rF  r   s      r   r   "RangeOfHighestLineFeature.__init__  sD    ?l?h?+	! #J K !r!   rM   r.   rA  r8   s   @r   rf  rf    rd  r!   rf  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )'RelativeNoteDensityOfHighestLineFeaturei  rE  T13c                t   > [         TU ]  " SSU0UD6  SU l        [        S5      U l        SU l        SU l        g )Nr   z%Relative Note Density of Highest Linez
            Number of Note Ons in the channel with the highest average
            pitch divided by the average number of Note Ons in all channels that contain at
            least one note.Tr>   r   rF  r   s      r   r   0RelativeNoteDensityOfHighestLineFeature.__init__  sB    ?l?h?;	! #   !r!   rM   r.   rA  r8   s   @r   rk  rk    s     
B	 	r!   rk  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )#MelodicIntervalsInLowestLineFeaturei  r[  T15c                t   > [         TU ]  " SSU0UD6  SU l        [        S5      U l        SU l        SU l        g )Nr   z Melodic Intervals in Lowest Linez
            Average melodic interval in semitones of the channel
            with the lowest average pitch divided by the average melodic interval of all
            channels that contain at least two notes.Tr>   r   rF  r   s      r   r   ,MelodicIntervalsInLowestLineFeature.__init__  sB    ?l?h?6	! #9 : !r!   rM   r.   rA  r8   s   @r   rp  rp    rd  r!   rp  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )VoiceSeparationFeaturei  z
Not implemented

Average separation in semitones between the average pitches of consecutive
channels (after sorting based/non-average pitch) that contain at least one note.
T20c                t   > [         TU ]  " SSU0UD6  SU l        [        S5      U l        SU l        SU l        g )Nr   zVoice Separationz
            Average separation in semi-tones between the average pitches of
            consecutive channels (after sorting based/non average pitch) that contain at
            least one note.Tr>   r   rF  r   s      r   r   VoiceSeparationFeature.__init__  sB    ?l?h?&	! #   !r!   rM   r.   rA  r8   s   @r   ru  ru    s     
B	 	r!   ru  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ ) PitchedInstrumentsPresentFeaturei  a  
Which pitched General MIDI Instruments are present. There is one entry
for each instrument, which is set to 1.0 if there is at least one Note On
in the recording corresponding to the instrument and to 0.0 if there is not.

>>> s1 = stream.Stream()
>>> s1.append(instrument.AcousticGuitar())
>>> s1.append(note.Note())
>>> s1.append(instrument.Tuba())
>>> s1.append(note.Note())
>>> fe = features.jSymbolic.PitchedInstrumentsPresentFeature(s1)
>>> fe.extract().vector
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Default instruments will lack a `.midiProgram`, so they raise exceptions:

>>> i = instrument.Instrument()
>>> i.midiProgram is None
True
>>> s2 = stream.Stream()
>>> s2.append(i)
>>> s2.append(note.Note())
>>> fe2 = features.jSymbolic.PitchedInstrumentsPresentFeature(s2)
>>> fe2.extract()
Traceback (most recent call last):
music21.features.jSymbolic.JSymbolicFeatureException:
<music21.instrument.Instrument ''> lacks a midiProgram
I1c                t   > [         TU ]  " SSU0UD6  SU l        [        S5      U l        SU l        SU l        g )Nr   zPitched Instruments Presenta  
            Which pitched General MIDI Instruments are present.
            There is one entry for each instrument, which is set to 1.0 if there is at
            least one Note On in the recording corresponding to the instrument and to
            0.0 if there is not.Tr   r   rF  r   s      r   r   )PitchedInstrumentsPresentFeature.__init__6  sB    ?l?h?1	! #$ %
 !r!   c                   U R                   S   nU(       d  [        S5      eUR                   H  nUR                  [        5      R                  5       nUR                  5       R                  (       d  MG  UR                  c+  [        U5      =(       d    [        U5      n[        U S35      eSU R                  R                  UR                  '   M     g)r#   partitionByInstrumentinput lacks instrumentsN lacks a midiProgramr>   )r&   rF   r   getElementsByClassr
   r  recursenotesmidiProgramstrreprr'   r(   )r   sru  r)   iStrs        r   r+   (PitchedInstrumentsPresentFeature.processB  s     II-. +,EFFA$$Z0668Ayy{   ==(q6,T!WD3tf<P4QRR56##AMM2 r!   rM   r.   r/   r8   s   @r   rz  rz    s     B 
B
7 7r!   rz  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )"UnpitchedInstrumentsPresentFeatureiU  a  
Not yet implemented

Which unpitched MIDI Percussion Key Map instruments are present.
There is one entry for each instrument, which is set to 1.0 if there is
at least one Note On in the recording corresponding to the instrument and to
0.0 if there is not. It should be noted that only instruments 35 to 81 are included here,
as they are the ones that meet the official standard. They are numbered in this
array from 0 to 46.
I2c                t   > [         TU ]  " SSU0UD6  SU l        [        S5      U l        SU l        SU l        g )Nr   zUnpitched Instruments Presenta  
            Which unpitched MIDI Percussion Key Map instruments are present.
            There is one entry for each instrument, which is set to 1.0 if there is at least one
            Note On in the recording corresponding to the instrument and to 0.0 if there is not.
            It should be noted that only instruments 35 to 81 are included here, as they are the
            ones that meet the official standard. They are numbered in this array from 0 to 46.T/   r   rF  r   s      r   r   +UnpitchedInstrumentsPresentFeature.__init__e  sD    ?l?h?3	! #c d !r!   c                    [        S5      er  r  r  s    r   r+   *UnpitchedInstrumentsPresentFeature.processr  r  r!   rM   r.   r/   r8   s   @r   r  r  U  s    	 
B? ?r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ ))NotePrevalenceOfPitchedInstrumentsFeatureiw  a  

>>> s1 = stream.Stream()
>>> s1.append(instrument.AcousticGuitar())
>>> s1.repeatAppend(note.Note(), 4)
>>> s1.append(instrument.Tuba())
>>> s1.append(note.Note())
>>> fe = features.jSymbolic.NotePrevalenceOfPitchedInstrumentsFeature(s1)
>>> fe.extract().vector
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 0.8..., 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2...,
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

`.midiProgram` cannot be None:

>>> s1.getInstruments().first().midiProgram = None
>>> fe2 = features.jSymbolic.NotePrevalenceOfPitchedInstrumentsFeature(s1)
>>> fe2.extract()
Traceback (most recent call last):
music21.features.jSymbolic.JSymbolicFeatureException: Acoustic Guitar lacks a midiProgram
I3c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z&Note Prevalence of Pitched InstrumentszThe fraction of (pitched) notes played by each General MIDI Instrument. There is one entry for each instrument, which is set to the number of Note Ons played using the corresponding MIDI patch divided by the total number of Note Ons in the recording.Tr   r   r?   r   s      r   r   2NotePrevalenceOfPitchedInstrumentsFeature.__init__  s;    ?l?h?<	X
 !r!   c                   U R                   S   n[        U R                   S   5      nU(       d  [        S5      eUR                   H  nUR	                  [
        5      R                  5       nUR                  5       R                  nU(       d  MI  UR                  c+  [        U5      =(       d    [        U5      n[        U S35      e[        U5      U-  U R                  R                  UR                  '   M     g)r#   r  r  rC   Nr  )r&   rG   rF   r   r  r
   r  r  r  r  r  r  rH   r'   r(   )r   r  r   ru  r)   pNotesr  s          r   r+   1NotePrevalenceOfPitchedInstrumentsFeature.process  s     II-.DII;<= +,?@@A$$Z0668AYY[&&Fv==(q6,T!WD3tf<P4QRR58[55H##AMM2 r!   rM   r.   r/   r8   s   @r   r  r  w  s     2 
B
I Ir!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )+NotePrevalenceOfUnpitchedInstrumentsFeaturei  rE  I4c                t   > [         TU ]  " SSU0UD6  SU l        [        S5      U l        SU l        SU l        g )Nr   z(Note Prevalence of Unpitched Instrumentsa  
            The fraction of (unpitched) notes played by each General MIDI
            Percussion Key Map Instrument. There is one entry for each instrument, which is set
            to the number of Note Ons played using the corresponding MIDI note value divided by
            the total number of Note Ons in the recording. It should be noted that only instruments
            35 to 81 are included here, as they are the ones that meet the official standard.
            They are numbered in this array from 0 to 46.Tr  r   rF  r   s      r   r   4NotePrevalenceOfUnpitchedInstrumentsFeature.__init__  sB    ?l?h?>	! #= > !r!   rM   r.   rA  r8   s   @r   r  r    s     
B r!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ ))TimePrevalenceOfPitchedInstrumentsFeaturei  ad  
Not implemented

The fraction of the total time of the recording in
which a note was sounding for each (pitched) General
MIDI Instrument. There is one entry for each instrument,
which is set to the total time in seconds during which a
given instrument was sounding one or more notes divided by the total length
in seconds of the piece.'

TODO: implement

I5c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z&Time Prevalence of Pitched Instrumentsa>  The fraction of the total time of the recording in which a note was sounding for each (pitched) General MIDI Instrument. There is one entry for each instrument, which is set to the total time in seconds during which a given instrument was sounding one or more notes divided by the total length in seconds of the piece.Tr   r   r?   r   s      r   r   2TimePrevalenceOfPitchedInstrumentsFeature.__init__  s;    ?l?h?<	a
 !r!   rM   r.   rA  r8   s   @r   r  r    s     
B
 
r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )6VariabilityOfNotePrevalenceOfPitchedInstrumentsFeaturei  a  
Standard deviation of the fraction of Note Ons played
by each (pitched) General MIDI instrument that is
used to play at least one note.

>>> s1 = stream.Stream()
>>> s1.append(instrument.AcousticGuitar())
>>> s1.repeatAppend(note.Note(), 5)
>>> s1.append(instrument.Tuba())
>>> s1.append(note.Note())
>>> fe = features.jSymbolic.VariabilityOfNotePrevalenceOfPitchedInstrumentsFeature(s1)
>>> fe.extract().vector
[0.33333...]

I6c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z5Variability of Note Prevalence of Pitched InstrumentszStandard deviation of the fraction of Note Ons played by each (pitched) General MIDI instrument that is used to play at least one note.Tr>   r   r?   r   s      r   r   ?VariabilityOfNotePrevalenceOfPitchedInstrumentsFeature.__init__  s:    ?l?h?K	> !r!   c                   U R                   S   n[        U R                   S   5      nU(       d  [        S5      eU(       d  [        S5      e/ nUR                   Hf  nUR	                  [
        5      R                  5       nUR                  5       R                  nU(       d  MI  UR                  [        U5      U-  5        Mh     [        U5      [        U5      -  nU Vs/ s H  n[        X-
  S5      PM     n	n[        R                  " [        U	5      [        U	5      -  5      U R                  R                  S'   g s  snf )Nr  r  r  rC   r   r   )r&   rG   rF   r   r  r
   r  r  r  rE   rH   powmathsqrtr'   r(   )
r   r  r   collru  r)   r  rs  npartials
             r   r+   >VariabilityOfNotePrevalenceOfPitchedInstrumentsFeature.process  s    II-.DII;<=+,EFF+,?@@A$$Z0668AYY[&&FvCK%/0  4y3t9$-12T3qx#T2!%3w<#g,+F!GA 3s   D<rM   r.   r/   r8   s   @r   r  r    s      
BH Hr!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )8VariabilityOfNotePrevalenceOfUnpitchedInstrumentsFeaturei%  a@  
Not implemented

Standard deviation of the fraction of Note Ons played by each (unpitched) MIDI Percussion Key
Map instrument that is used to play at least one note. It should be noted that only
instruments 35 to 81 are included here, as they are the ones that are included in the
official standard.


TODO: implement

I7c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   z7Variability of Note Prevalence of Unpitched Instrumentsa  Standard deviation of the fraction of Note Ons played by each (unpitched) MIDI Percussion Key Map instrument that is used to play at least one note. It should be noted that only instruments 35 to 81 are included here, as they are the ones that are included in the official standard.Tr>   r   r?   r   s      r   r   AVariabilityOfNotePrevalenceOfUnpitchedInstrumentsFeature.__init__5  s>    ?l?h?M	O 	
 !r!   rM   r.   rA  r8   s   @r   r  r  %  s     
B
 
r!   r  c                  :   ^  \ rS rSrSrSrSU 4S jjrS rSrU =r	$ )!NumberOfPitchedInstrumentsFeatureiB  aJ  
Total number of General MIDI patches that are used to play at least one note.

>>> s1 = stream.Stream()
>>> s1.append(instrument.AcousticGuitar())
>>> s1.append(note.Note())
>>> s1.append(instrument.Tuba())
>>> s1.append(note.Note())
>>> fe = features.jSymbolic.NumberOfPitchedInstrumentsFeature(s1)
>>> fe.extract().vector
[2]

I8c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zNumber of Pitched InstrumentszMTotal number of General MIDI patches that are used to play at least one note.Tr>   r   r?   r   s      r   r   *NumberOfPitchedInstrumentsFeature.__init__R  s8    ?l?h?3	6 r!   c                    U R                   S   nSnU(       d  [        S5      eUR                   H)  nUR                  5       R                  (       d  M$  US-  nM+     X R
                  R                  S'   g)r#   r  r   r  r>   N)r&   rF   r   r  r  r'   r(   )r   r  ro   ru  s       r   r+   )NumberOfPitchedInstrumentsFeature.process[  sd     II-.+,EFFAyy{   
  "'Ar!   rM   r.   r/   r8   s   @r   r  r  B  s     
B' 'r!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )#NumberOfUnpitchedInstrumentsFeatureij  a  
Not implemented

Number of distinct MIDI Percussion Key Map patches that were used to play at
least one note. It should be noted that only instruments 35 to 81 are
included here, as they are the ones that are included in the official standard.

TODO: implement
I9c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zNumber of Unpitched InstrumentszNumber of distinct MIDI Percussion Key Map patches that were used to play at least one note. It should be noted that only instruments 35 to 81 are included here, as they are the ones that are included in the official standard.Tr>   r   r?   r   s      r   r   ,NumberOfUnpitchedInstrumentsFeature.__init__w  s;    ?l?h?5	J !r!   rM   r.   rA  r8   s   @r   r  r  j  s     
B	 	r!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )PercussionPrevalenceFeaturei  z
Not implemented

Total number of Note Ons corresponding to unpitched percussion instruments
divided by the total number of Note Ons in the recording.
I10c                b   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        g )Nr   zPercussion PrevalencezTotal number of Note Ons corresponding to unpitched percussion instruments divided by total number of Note Ons in the recording.Tr>   r   r?   r   s      r   r   $PercussionPrevalenceFeature.__init__  s9    ?l?h?+	` r!   rM   r.   rA  r8   s   @r   r  r    s     
B r!   r  c                  6   ^  \ rS rSrSrSU 4S jjrS rSrU =r$ )InstrumentFractionFeaturei  z
TODO: Add description of feature

This subclass is in-turn subclassed by all FeatureExtractors that
look at the proportional usage of an Instrument
c                8   > [         TU ]  " SSU0UD6  / U l        g )Nr   r   )r   r   _targetProgramsr   s      r   r   "InstrumentFractionFeature.__init__  s"    ?l?h?  "r!   c                   U R                   S   n[        U R                   S   5      nSnU(       d  [        S5      eU(       d  [        S5      eUR                   Hh  nUR	                  [
        5      R                  5       nUR                  U R                  ;   d  MB  U[        UR                  5       R                  5      -  nMj     X2-  U R                  R                  S'   g)r#   r  r  r   r  rC   N)r&   rG   rF   r   r  r
   r  r  r  rH   r  r  r'   r(   )r   r  r   ro   ru  r)   s         r   r+   !InstrumentFractionFeature.process  s     II-.DII;<=+,EFF+,?@@A$$Z0668A}} 4 44QYY[..//  "'Ar!   )r  r.   )	r0   r1   r2   r3   r4   r   r+   r6   r7   r8   s   @r   r  r    s    "/ /r!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )StringKeyboardFractionFeaturei  aY  
Fraction of all Note Ons belonging to string keyboard patches
(General MIDI patches 1 to 8).

>>> s1 = stream.Stream()
>>> s1.append(instrument.Piano())
>>> s1.repeatAppend(note.Note(), 9)
>>> s1.append(instrument.Tuba())
>>> s1.append(note.Note())
>>> fe = features.jSymbolic.StringKeyboardFractionFeature(s1)
>>> fe.extract().vector
[0.9...]
I11c                   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        [        S5      U l        g )Nr   zString Keyboard Fractionz\Fraction of all Note Ons belonging to string keyboard patches (General MIDI patches 1 to 8).Tr>      r   )r   r   r   r   r   r   rD   r  r   s      r   r   &StringKeyboardFractionFeature.__init__  sD    ?l?h?.	= $Qxr!   r  r   r   r   r   r.   rA  r8   s   @r   r  r         
B	( 	(r!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )AcousticGuitarFractionFeaturei  a  
A feature extractor that extracts the fraction of all Note Ons belonging to
acoustic guitar patches (General MIDI patches 25 and 26).

>>> s1 = stream.Stream()
>>> s1.append(instrument.AcousticGuitar())
>>> s1.repeatAppend(note.Note(), 3)
>>> s1.append(instrument.Tuba())
>>> s1.append(note.Note())
>>> fe = features.jSymbolic.AcousticGuitarFractionFeature(s1)
>>> fe.extract().vector
[0.75]
I12c                t   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SS/U l        g )	Nr   zAcoustic Guitar Fractionz_Fraction of all Note Ons belonging to acoustic guitar patches (General MIDI patches 25 and 26).Tr>   r      r   r   r   r   r   r   r   r  r   s      r   r   &AcousticGuitarFractionFeature.__init__  sE    ?l?h?.	@  "Bxr!   r  r.   rA  r8   s   @r   r  r    r  r!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )ElectricGuitarFractionFeaturei  a
  
>>> s1 = stream.Stream()
>>> s1.append(instrument.ElectricGuitar())
>>> s1.repeatAppend(note.Note(), 4)
>>> s1.append(instrument.Tuba())
>>> s1.repeatAppend(note.Note(), 4)
>>> fe = features.jSymbolic.ElectricGuitarFractionFeature(s1)
>>> fe.extract().vector
[0.5]
I13c                   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        [        [        SS5      5      U l        g )	Nr   zElectric Guitar Fractionz^Fraction of all Note Ons belonging to electric guitar patches (General MIDI patches 27 to 32).Tr>          r   	r   r   r   r   r   r   listrD   r  r   s      r   r   &ElectricGuitarFractionFeature.__init__  sL    ?l?h?.	W #E"bM2r!   r  r.   rA  r8   s   @r   r  r    s    	 
B	3 	3r!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )ViolinFractionFeaturei  aU  
Fraction of all Note Ons belonging to violin patches (General MIDI
patches 41 or 111).

>>> s1 = stream.Stream()
>>> s1.append(instrument.Violin())
>>> s1.repeatAppend(note.Note(), 2)
>>> s1.append(instrument.Tuba())
>>> s1.repeatAppend(note.Note(), 8)
>>> fe = features.jSymbolic.ViolinFractionFeature(s1)
>>> fe.extract().vector
[0.2...]
I14c                t   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        SS/U l        g )	Nr   zViolin FractionzVFraction of all Note Ons belonging to violin patches (General MIDI patches 41 or 111).Tr>   (   n   r   r  r   s      r   r   ViolinFractionFeature.__init__  sE    ?l?h?%	@  "Cyr!   r  r.   rA  r8   s   @r   r  r    s     
B	) 	)r!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )SaxophoneFractionFeaturei(  a  
Fraction of all Note Ons belonging to saxophone patches (General MIDI
patches 65 through 68).
# NOTE: incorrect

>>> s1 = stream.Stream()
>>> s1.append(instrument.SopranoSaxophone())
>>> s1.repeatAppend(note.Note(), 6)
>>> s1.append(instrument.Tuba())
>>> s1.repeatAppend(note.Note(), 4)
>>> fe = features.jSymbolic.SaxophoneFractionFeature(s1)
>>> print(fe.extract().vector[0])
0.6
I15c                t   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        / SQU l        g )Nr   zSaxophone Fractionz]Fraction of all Note Ons belonging to saxophone patches (General MIDI patches 65 through 68).Tr>   )@   A   B   C   r   r  r   s      r   r   !SaxophoneFractionFeature.__init__9  sA    ?l?h?(	D /r!   r  r.   rA  r8   s   @r   r  r  (  s     
B	0 	0r!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )BrassFractionFeatureiE  a  
A feature extractor that extracts the fraction of all Note Ons
belonging to brass patches (General MIDI patches 57 through 68).

TODO: Conflict in source: only does 57-62?

>>> s1 = stream.Stream()
>>> s1.append(instrument.SopranoSaxophone())
>>> s1.repeatAppend(note.Note(), 6)
>>> s1.append(instrument.Tuba())
>>> s1.repeatAppend(note.Note(), 4)
>>> fe = features.jSymbolic.BrassFractionFeature(s1)
>>> print(fe.extract().vector[0])
0.4
I16c                   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        [        [        SS5      5      U l        g )	Nr   zBrass FractionzYFraction of all Note Ons belonging to brass patches (General MIDI patches 57 through 68).Tr>   8   >   r   r  r   s      r   r   BrassFractionFeature.__init__X  sL    ?l?h?$	D #E"bM2r!   r  r.   rA  r8   s   @r   r  r  E        
B	3 	3r!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )WoodwindsFractionFeatureid  a  
Fraction of all Note Ons belonging to woodwind patches
(General MIDI patches 69 through 76).

TODO: Conflict in source: does 69-79?

>>> s1 = stream.Stream()
>>> s1.append(instrument.Flute())
>>> s1.repeatAppend(note.Note(), 3)
>>> s1.append(instrument.Tuba())
>>> s1.repeatAppend(note.Note(), 7)
>>> fe = features.jSymbolic.WoodwindsFractionFeature(s1)
>>> print(fe.extract().vector[0])
0.3
I17c                   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        [        [        SS5      5      U l        g )	Nr   zWoodwinds Fractionz\Fraction of all Note Ons belonging to woodwind patches (General MIDI patches 69 through 76).Tr>   D   P   r   r  r   s      r   r   !WoodwindsFractionFeature.__init__w  sL    ?l?h?(	D #E"bM2r!   r  r.   rA  r8   s   @r   r   r   d  r  r!   r   c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ ) OrchestralStringsFractionFeaturei  au  
Fraction of all Note Ons belonging to orchestral strings patches
(General MIDI patches 41 or 47).

>>> s1 = stream.Stream()
>>> s1.append(instrument.Violoncello())
>>> s1.repeatAppend(note.Note(), 4)
>>> s1.append(instrument.Tuba())
>>> s1.repeatAppend(note.Note(), 6)
>>> fe = features.jSymbolic.OrchestralStringsFractionFeature(s1)
>>> print(fe.extract().vector[0])
0.4
I18c                   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        [        [        SS5      5      U l        g )	Nr   zOrchestral Strings FractionzaFraction of all Note Ons belonging to orchestral strings patches (General MIDI patches 41 or 47).Tr>   r   .   r   r  r   s      r   r   )OrchestralStringsFractionFeature.__init__  sK    ?l?h?1	? #E"bM2r!   r  r.   rA  r8   s   @r   r  r    s     
B	3 	3r!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )StringEnsembleFractionFeaturei  zq
Not implemented

Fraction of all Note Ons belonging to string ensemble patches
(General MIDI patches 49 to 52).
I19c                t   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        / SQU l        g )Nr   zString Ensemble Fractionz^Fraction of all Note Ons belonging to string ensemble patches (General MIDI patches 49 to 52).Tr>   )r   1   2   3   r   r  r   s      r   r   &StringEnsembleFractionFeature.__init__  s@    ?l?h?.	? /r!   r  r.   rA  r8   s   @r   r  r    s     
B	0 	0r!   r  c                  4   ^  \ rS rSrSrSrSU 4S jjrSrU =r$ )!ElectricInstrumentFractionFeaturei  a  
Fraction of all Note Ons belonging to electric instrument patches
(General MIDI patches 5, 6, 17, 19, 27 through 32, 24 through 40).

>>> s1 = stream.Stream()
>>> s1.append(instrument.ElectricOrgan())
>>> s1.repeatAppend(note.Note(), 8)
>>> s1.append(instrument.Tuba())
>>> s1.repeatAppend(note.Note(), 2)
>>> fe = features.jSymbolic.ElectricInstrumentFractionFeature(s1)
>>> print(fe.extract().vector[0])
0.8
I20c                t   > [         TU ]  " SSU0UD6  SU l        SU l        SU l        SU l        / SQU l        g )Nr   zElectric Instrument Fractionz|Fraction of all Note Ons belonging to electric instrument patches (General MIDI patches 5, 6, 17, 19, 27 to 32 or 34 to 40).Tr>   )r   r  r      r                 !   "   #   $   %   &   '   r   r  r   s      r   r   *ElectricInstrumentFractionFeature.__init__  sD    ?l?h?2	Y  Dr!   r  r.   rA  r8   s   @r   r  r    s     
B
D 
Dr!   r  c                      \ rS rSrSrg)rF   i  r   N)r0   r1   r2   r3   r6   r   r!   r   rF   rF     s    r!   rF   DIMPRTC)NNNNNNNNNNNNNNNNNNNNNNNNNNNNNc                     [         U    U   $ ! [         a    [        SU  35      e[         a    [        SU  SU 35      ef = f)a1  
Typical usage:

>>> t5 = features.jSymbolic.getExtractorByTypeAndNumber('T', 5)
>>> t5.__name__
'VoiceEqualityNoteDurationFeature'
>>> bachExample = corpus.parse('bach/bwv66.6')
>>> fe = t5(bachExample)

Features unimplemented in jSymbolic but documented in the dissertation return None

>>> features.jSymbolic.getExtractorByTypeAndNumber('C', 20) is None
True

Totally unknown features return an exception:

>>> features.jSymbolic.getExtractorByTypeAndNumber('L', 900)
Traceback (most recent call last):
music21.features.jSymbolic.JSymbolicFeatureException: Could not find
    any jSymbolic features of type L

>>> features.jSymbolic.getExtractorByTypeAndNumber('C', 200)
Traceback (most recent call last):
music21.features.jSymbolic.JSymbolicFeatureException: jSymbolic
    features of type C do not have number 200

You could also find all the feature extractors this way:

>>> fs = features.jSymbolic.extractorsById
>>> for k in fs:
...     for i in range(len(fs[k])):
...       if fs[k][i] is not None:
...         n = fs[k][i].__name__
...         if fs[k][i] not in features.jSymbolic.featureExtractors:
...            n += ' (not implemented)'
...         print(f'{k} {i} {n}')
D 1 OverallDynamicRangeFeature (not implemented)
D 2 VariationOfDynamicsFeature (not implemented)
D 3 VariationOfDynamicsInEachVoiceFeature (not implemented)
D 4 AverageNoteToNoteDynamicsChangeFeature (not implemented)
I 1 PitchedInstrumentsPresentFeature
I 2 UnpitchedInstrumentsPresentFeature (not implemented)
I 3 NotePrevalenceOfPitchedInstrumentsFeature
I 4 NotePrevalenceOfUnpitchedInstrumentsFeature (not implemented)
I 5 TimePrevalenceOfPitchedInstrumentsFeature (not implemented)
I 6 VariabilityOfNotePrevalenceOfPitchedInstrumentsFeature
I 7 VariabilityOfNotePrevalenceOfUnpitchedInstrumentsFeature (not implemented)
I 8 NumberOfPitchedInstrumentsFeature
I 9 NumberOfUnpitchedInstrumentsFeature (not implemented)
I 10 PercussionPrevalenceFeature (not implemented)
I 11 StringKeyboardFractionFeature
I 12 AcousticGuitarFractionFeature
I 13 ElectricGuitarFractionFeature
I 14 ViolinFractionFeature
I 15 SaxophoneFractionFeature
I 16 BrassFractionFeature
I 17 WoodwindsFractionFeature
I 18 OrchestralStringsFractionFeature
I 19 StringEnsembleFractionFeature
I 20 ElectricInstrumentFractionFeature
M 1 MelodicIntervalHistogramFeature
M 2 AverageMelodicIntervalFeature
M 3 MostCommonMelodicIntervalFeature
M 4 DistanceBetweenMostCommonMelodicIntervalsFeature
M 5 MostCommonMelodicIntervalPrevalenceFeature
M 6 RelativeStrengthOfMostCommonIntervalsFeature
M 7 NumberOfCommonMelodicIntervalsFeature
M 8 AmountOfArpeggiationFeature
M 9 RepeatedNotesFeature
M 10 ChromaticMotionFeature
M 11 StepwiseMotionFeature
M 12 MelodicThirdsFeature
M 13 MelodicFifthsFeature
M 14 MelodicTritonesFeature
M 15 MelodicOctavesFeature
M 17 DirectionOfMotionFeature
M 18 DurationOfMelodicArcsFeature
M 19 SizeOfMelodicArcsFeature
P 1 MostCommonPitchPrevalenceFeature
P 2 MostCommonPitchClassPrevalenceFeature
P 3 RelativeStrengthOfTopPitchesFeature
P 4 RelativeStrengthOfTopPitchClassesFeature
P 5 IntervalBetweenStrongestPitchesFeature
P 6 IntervalBetweenStrongestPitchClassesFeature
P 7 NumberOfCommonPitchesFeature
P 8 PitchVarietyFeature
P 9 PitchClassVarietyFeature
P 10 RangeFeature
P 11 MostCommonPitchFeature
P 12 PrimaryRegisterFeature
P 13 ImportanceOfBassRegisterFeature
P 14 ImportanceOfMiddleRegisterFeature
P 15 ImportanceOfHighRegisterFeature
P 16 MostCommonPitchClassFeature
P 17 DominantSpreadFeature (not implemented)
P 18 StrongTonalCentresFeature (not implemented)
P 19 BasicPitchHistogramFeature
P 20 PitchClassDistributionFeature
P 21 FifthsPitchHistogramFeature
P 22 QualityFeature
P 23 GlissandoPrevalenceFeature (not implemented)
P 24 AverageRangeOfGlissandosFeature (not implemented)
P 25 VibratoPrevalenceFeature (not implemented)
R 1 StrongestRhythmicPulseFeature (not implemented)
R 2 SecondStrongestRhythmicPulseFeature (not implemented)
R 3 HarmonicityOfTwoStrongestRhythmicPulsesFeature (not implemented)
R 4 StrengthOfStrongestRhythmicPulseFeature (not implemented)
R 5 StrengthOfSecondStrongestRhythmicPulseFeature (not implemented)
R 6 StrengthRatioOfTwoStrongestRhythmicPulsesFeature (not implemented)
R 7 CombinedStrengthOfTwoStrongestRhythmicPulsesFeature (not implemented)
R 8 NumberOfStrongPulsesFeature (not implemented)
R 9 NumberOfModeratePulsesFeature (not implemented)
R 10 NumberOfRelativelyStrongPulsesFeature (not implemented)
R 11 RhythmicLoosenessFeature (not implemented)
R 12 PolyrhythmsFeature (not implemented)
R 13 RhythmicVariabilityFeature (not implemented)
R 14 BeatHistogramFeature (not implemented)
R 15 NoteDensityFeature
R 17 AverageNoteDurationFeature
R 18 VariabilityOfNoteDurationFeature
R 19 MaximumNoteDurationFeature
R 20 MinimumNoteDurationFeature
R 21 StaccatoIncidenceFeature
R 22 AverageTimeBetweenAttacksFeature
R 23 VariabilityOfTimeBetweenAttacksFeature
R 24 AverageTimeBetweenAttacksForEachVoiceFeature
R 25 AverageVariabilityOfTimeBetweenAttacksForEachVoiceFeature
R 30 InitialTempoFeature
R 31 InitialTimeSignatureFeature
R 32 CompoundOrSimpleMeterFeature
R 33 TripleMeterFeature
R 34 QuintupleMeterFeature
R 35 ChangesOfMeterFeature
R 36 DurationFeature
T 1 MaximumNumberOfIndependentVoicesFeature
T 2 AverageNumberOfIndependentVoicesFeature
T 3 VariabilityOfNumberOfIndependentVoicesFeature
T 4 VoiceEqualityNumberOfNotesFeature (not implemented)
T 5 VoiceEqualityNoteDurationFeature (not implemented)
T 6 VoiceEqualityDynamicsFeature (not implemented)
T 7 VoiceEqualityMelodicLeapsFeature (not implemented)
T 8 VoiceEqualityRangeFeature (not implemented)
T 9 ImportanceOfLoudestVoiceFeature (not implemented)
T 10 RelativeRangeOfLoudestVoiceFeature (not implemented)
T 12 RangeOfHighestLineFeature (not implemented)
T 13 RelativeNoteDensityOfHighestLineFeature (not implemented)
T 15 MelodicIntervalsInLowestLineFeature (not implemented)
T 20 VoiceSeparationFeature (not implemented)
z.Could not find any jSymbolic features of type zjSymbolic features of type z do not have number )extractorsByIdKeyErrorrF   r   )extractorTypenumbers     r   getExtractorByTypeAndNumberr3    sl    lWm,V44 N'<]OLN 	N W')-8LVHUW 	WWs	    3Ac            	         Sn Sn[          HT  n[         U   n[        [        U5      5       H0  nX4   c  M
  X4   R                  nU S-  n X4   [        ;   d  M+  US-  nM2     MV     [        SU SU  SX-   S35        g)zR
>>> features.jSymbolic.getCompletionStats()
completion stats: 72/112 (0.6428...)
r   Nr>   zcompletion stats: /z ())r/  rD   rH   r0   featureExtractorsprint)
countTotalcountCompletekgroupr)   unused_ns         r   getCompletionStatsr>    s    
 JMq!s5z"Ax# 8,,a
800!Q&M #  
}oQzl"]=W<XXY
Z[r!   c                      \ rS rSrS rS rS rS rS rS r	S r
S	 rS
 rS rS rS rS rS rS rS rS rS rS rS rSrg)Testi  c                
   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        g )	Nr   streampitchnotefeaturesc2)p5rK  rK  p4rL  rL  g      @)music21rC  rE  rG  rI  StreamPitchrE   Noterb   rc   	transpose	jSymbolicr:   extractassertEqualr(   
r   rC  rE  rG  rI  r  ru  r)   fefs
             r   !testAverageMelodicIntervalFeature&Test.testAverageMelodicIntervalFeature  s    "! $MMOKK	4==+,-5AAAHHTYYt}}Q/01 6 ==a@JJLC5)r!   c                
   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        g )	Nr   rB  rD  rF  rH  rJ  )rK  rK  rK  rL  rL  rL  rL  r  )rM  rC  rE  rG  rI  rN  rO  rE   rP  rb   rc   rQ  rR  rO   rS  rT  r(   rU  s
             r   $testMostCommonMelodicIntervalFeature)Test.testMostCommonMelodicIntervalFeature  s    "! $MMOKK	4==+,-;AAAHHTYYt}}Q/01 < @@CJJLA3'r!   c                
   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        g )	Nr   rB  rD  rF  rH  rJ  	rK  rK  rK  rL  rL  rL  rL  m2m3r   )rM  rC  rE  rG  rI  rN  rO  rE   rP  rb   rc   rQ  rR  r\   rS  rT  r(   rU  s
             r   4testDistanceBetweenMostCommonMelodicIntervalsFeature9Test.testDistanceBetweenMostCommonMelodicIntervalsFeature  s    "! $MMOKK	4==+,-GAAAHHTYYt}}Q/01 H PPQRSJJLA3'r!   c                
   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        g )	Nr   rB  rD  rF  rH  rJ  )rK  rK  rL  rL  rL  rL  r_  r`        ?)rM  rC  rE  rG  rI  rN  rO  rE   rP  rb   rc   rQ  rR  ri   rS  rT  r(   rU  s
             r   .testMostCommonMelodicIntervalPrevalenceFeature3Test.testMostCommonMelodicIntervalPrevalenceFeature  s    "! $MMOKK	4==+,-AAAAHHTYYt}}Q/01 B JJ1MJJLC5)r!   c                
   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        g )	Nr   rB  rD  rF  rH  rJ  r^  g      ?)rM  rC  rE  rG  rI  rN  rO  rE   rP  rb   rc   rQ  rR  rr   rS  rT  r(   rU  s
             r   0testRelativeStrengthOfMostCommonIntervalsFeature5Test.testRelativeStrengthOfMostCommonIntervalsFeature  s    "! $MMOKK	4==+,-GAAAHHTYYt}}Q/01 H LLQOJJLD6*r!   c                
   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        g )	Nr   rB  rD  rF  rH  rJ  )rK  rL  rL  rL  rL  rL  rL  rL  rL  rL  rL  r_  r`  r>   )rM  rC  rE  rG  rI  rN  rO  rE   rP  rb   rc   rQ  rR  rz   rS  rT  r(   rU  s
             r   )testNumberOfCommonMelodicIntervalsFeature.Test.testNumberOfCommonMelodicIntervalsFeature  s    "! $MMOKK	4==+,-_AAAHHTYYt}}Q/01 ` EEaHJJLA3'r!   c                
   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        g )	Nr   rB  rD  rF  rH  rJ  )r_  r_  r<   rQ   rK  p8rd  )rM  rC  rE  rG  rI  rN  rO  rE   rP  rb   rc   rQ  rR  r   rS  rT  r(   rU  s
             r   testAmountOfArpeggiationFeature$Test.testAmountOfArpeggiationFeature  s    "! $MMOKK	4==+,-5AAAHHTYYt}}Q/01 6 ;;A>JJLC5)r!   c                
   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        g )	Nr   rB  rD  rF  rH  rJ  )p1rr  rr  r<   rQ   rK  rd  )rM  rC  rE  rG  rI  rN  rO  rE   rP  rb   rc   rQ  rR  r   rS  rT  r(   rU  s
             r   testRepeatedNotesFeatureTest.testRepeatedNotesFeature  s    "! $MMOKK	4==+,-5AAAHHTYYt}}Q/01 6 44Q7JJLC5)r!   c                
   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        g )	Nr   rB  rD  rF  rH  rJ  r_  r_  r_  r<   rQ   rK  rd  )rM  rC  rE  rG  rI  rN  rO  rE   rP  rb   rc   rQ  rR  r   rS  rT  r(   rU  s
             r   testChromaticMotionFeatureTest.testChromaticMotionFeature&  s    "! $MMOKK	4==+,-5AAAHHTYYt}}Q/01 6 66q9JJLC5)r!   c                
   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        g )	Nr   rB  rD  rF  rH  rJ  rv  gUUUUUU?)rM  rC  rE  rG  rI  rN  rO  rE   rP  rb   rc   rQ  rR  r   rS  rT  r(   rU  s
             r   testStepwiseMotionFeatureTest.testStepwiseMotionFeature7      "! $MMOKK	4==+,-5AAAHHTYYt}}Q/01 6 55a8JJLE7+r!   c                
   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        g )	Nr   rB  rD  rF  rH  rJ  rv  UUUUUU?)rM  rC  rE  rG  rI  rN  rO  rE   rP  rb   rc   rQ  rR  r   rS  rT  r(   rU  s
             r   testMelodicThirdsFeatureTest.testMelodicThirdsFeatureH      "! $MMOKK	4==+,-5AAAHHTYYt}}Q/01 6 44Q7JJLE7+r!   c                
   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        g )	Nr   rB  rD  rF  rH  rJ  )r_  r_  r_  r<   rK  rK  gUUUUUU?)rM  rC  rE  rG  rI  rN  rO  rE   rP  rb   rc   rQ  rR  r   rS  rT  r(   rU  s
             r   testMelodicFifthsFeatureTest.testMelodicFifthsFeatureY  r  r!   c                
   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        g )	Nr   rB  rD  rF  rH  rJ  )r_  r_  r_  r<   rK  d5r~  )rM  rC  rE  rG  rI  rN  rO  rE   rP  rb   rc   rQ  rR  r   rS  rT  r(   rU  s
             r   testMelodicTritonesFeatureTest.testMelodicTritonesFeaturej  s    "! $MMOKK	4==+,-5AAAHHTYYt}}Q/01 6 66q9JJLE7+r!   c                
   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        g )	Nr   rB  rD  rF  rH  rJ  r_  r_  r_  r<   rK  rn  r~  )rM  rC  rE  rG  rI  rN  rO  rE   rP  rb   rc   rQ  rR  r   rS  rT  r(   rU  s
             r   testMelodicOctavesFeatureTest.testMelodicOctavesFeature{  r|  r!   c                   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S	 HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S
/5        UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        g )Nr   rB  rD  rF  rH  rJ  r        ?)r_  r_  -m2-M2-p5rn  rd  )r  r  r  r  r  -p8r  )rM  rC  rE  rG  rI  rN  rO  rE   rP  rb   rc   rQ  rR  r   rS  rT  r(   rU  s
             r   testDirectionOfMotionFeature!Test.testDirectionOfMotionFeature  s   "! $MMOKK	4==+,-5AAAHHTYYt}}Q/01 6 88;JJLC5) MMOKK	4==+,-8AAAHHTYYt}}Q/01 9 88;JJLC5) MMOKK	4==+,-;AAAHHTYYt}}Q/01 < 88;JJLC5)r!   c                   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R                  U	R                   S/5        UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	U R#                  U	R                   S   S	5        g )
Nr   rB  rD  rF  rH  rJ  r  r_  r_  r  r<   rK  r  rn  r  g?)rM  rC  rE  rG  rI  rN  rO  rE   rP  rb   rc   rQ  rR  r   rS  rT  r(   assertAlmostEqualrU  s
             r    testDurationOfMelodicArcsFeature%Test.testDurationOfMelodicArcsFeature  s]   "! $
 MMOKK	4==+,-5AAAHHTYYt}}Q/01 6 <<Q?JJLA3'MMOKK	4==+,-DAAAHHTYYt}}Q/01 E <<Q?JJLqxx{E2r!   c                l   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	UR                  5       nUR                  S5      nUR                  UR                  [        R                  " U5      5      5        S HH  nUR                  U5      nUR                  UR                  [        R                  " U5      5      5        MJ     UR                  R                  U5      nUR                  5       n	g )	Nr   rB  rD  rF  rH  rJ  r  r  )rM  rC  rE  rG  rI  rN  rO  rE   rP  rb   rc   rQ  rR  r   rS  )
r   rC  rE  rG  rI  r  ru  r)   rV  unused_fs
             r   testSizeOfMelodicArcsFeature!Test.testSizeOfMelodicArcsFeature  s/   "! $MMOKK	4==+,-5AAAHHTYYt}}Q/01 6 88;::< MMOKK	4==+,-DAAAHHTYYt}}Q/01 E 88;::<r!   c                   SSK Jn  SSK Jn  SSK Jn  SSK Jn  UR                  5       nUR                  SUR                  SS95        UR                  SUR                  SS	95        UR                  S
UR                  SS	95        UR                  SUR                  SS	95        UR                  SUR                  SS	95        UR                  SUR                  SS	95        UR                  SUR                  SS	95        UR                  SUR                  SS	95        UR                  SUR                  S
S	95        UR                  R                  U5      nUR                  5       nU R                  UR                  S   S5        UR                  5       nUR                  SUR                  SS95        UR                  SUR                  SS	95        UR                  S
UR                  SS	95        UR                  SUR                  SS	95        UR                  SUR                  SS	95        UR                  SUR                  SS	95        UR                  SUR                  SS	95        UR                  SUR                  SS	95        UR                  SUR                  S
S	95        UR                  R                  U5      nUR                  5       nU R                  UR                  S   S5        g )Nr   rB  rF  temporH  r   )r2  r  )quarterLengthr>   r   r   r   r   r  r   r     g      @)rM  rC  rG  r  rI  rN  insertMetronomeMarkrP  rR  rd  rS  r  r(   )r   rC  rG  r  rI  r  rV  rW  s           r   testNoteDensityFeatureATest.testNoteDensityFeatureA  s`   " !$MMO	E''r'23	DIIAI./	DIIAI./	DIIAI./	DIIAI./	DIIAI./	DIIAI./	DIIAI./	DIIAI./2215JJLqxx{C0MMO	E''s'34	DIIAI./	DIIAI./	DIIAI./	DIIAI./	DIIAI./	DIIAI./	DIIAI./	DIIAI./ 2215JJLqxx{C0r!   c           	     4   SSK Jn  UR                  R                  nSnSnU HU  n[	        [        X%   5      5       H8  nX%   U   c  M  US-  nX%   U   UR                  R                  ;   d  M3  US-  nM:     MW     [        R                  SUSUSXC-  /5        g )Nr   rH  r>   z	fe total:zfe implementedpercent)	rM  rI  rR  r/  rD   rH   r7  r  r  )r   rI  fsfeTotalfeImplementedr;  r)   s          r   testFeatureCountTest.testFeatureCount  s    $..A3ru:&58'qLGuQx8#5#5#G#GG%*	 '  	g7G!.	=;R!T 	Ur!   c                   SSK Jn  SSK Jn  UR                  SS5      nUR                   H%  nUR                  SUR                  SS5      5        M'     [        U5      nUR                  5       nU R                  SUR                  S   5        g )	Nr   )corpusr  zschoenberg/opus19r   LangsamF   g     a@)rM  r  r  parser   r  r  r  rS  rT  r(   )r   r  r  schru  rV  rW  s          r   testBeatHistogramTest.testBeatHistogram  so    "!ll.2AHHQ++Ir:; *3/JJL,r!   r   N)r0   r1   r2   r3   rX  r[  ra  re  rh  rk  ro  rs  rw  rz  r  r  r  r  r  r  r  r  r  r  r6   r   r!   r   r@  r@    si    *$($("*"+"("*"*"*",",",",","$*L3: 4#1JU-r!   r@  __main__)r4   
__future__r   collectionsr   rb   r  r   rr  textwrapr   unittestrM  r   r   r	   music21.featuresrO  music21.instrumentr
   Environmentr  rP  r   r:   rO   r\   ri   rr   rz   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r'  r2  r9  rA  rH  rR  rY  rd  rl  rx  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r	  r  r  r   r(  r/  r6  r=  rC  rK  rU  r\  rd  rr  r|  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r#  r1  r8  r?  rD  rK  rP  rU  rZ  r`  rf  rk  rp  ru  rz  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r  r  r  FeatureExceptionrF   r/  r3  r7  r>  TestCaser@  r0   mainTestr   r!   r   <module>r     su   # #           3 )&&';<+n&E&E +@ ;N$C$C  ;F*~'F'F *<"=''"=J2''2D$L''$LN!&N,K,K !&H)/."A"A )/X$/>:: $/N!/^<< !/H"/N;; "/J!/>:: !/H!/>:: !/H!/^<< !/H!/N;; !/H,=~>> ,=^S:>#B#B S:li6~>> i6` 1~'F'F  1F 5N,K,K  5F").*I*I ")J%:~/N/N %:P )^-L-L  )F!?''!?H&>#B#B &B&.99 &>&~>> &>5>22 5@)^<< )@H^<< H<"Bn&E&E "BJ"B(G(G "BJ"Bn&E&E "BJ+."A"A +8?N;; ?.? ? ? ?.'+!@!@ '+T*AN$C$C *AZ&:."A"A &:R4,^44 4,n?!@!@ ?.?n&E&E ?8?~>> ?2?N$C$C ?8AN$C$C AD#A.*I*I #AL'E'''ETAn.M.M A4:'':D#<''#<L I'' IF?."A"A ?,?N$C$C ?*N,K,K &?~>> ?8?88 ?D?!@!@ ?*?>:: ?6#K88 #KL"9!@!@ "9J%C~'F'F %CP,!@!@ ,@,!@!@ ,@9~>> 9D(E~'F'F (EV&@^-L-L &@R6A''6Ar9=''9=v4.99 4:'9."A"A '9T/+>#B#B /+d&'88 &'R%'N;; %'P+N;; +\/n55 /L!@!@ &!@!@ *N,K,K ,^-L-L 8('n.M.M ('V*9n.M.M *9Z'A'''AT(G(G .~'F'F *>#B#B *~'F'F . ? ? (n&E&E ()H)H ( ? ? (n.M.M ..*I*I (^<< 2@7~'F'F @7F?)H)H ?D;I'';I|'':''>1H''1Hh'':%'(G(G %'P.*I*I 2."A"A (/ ? ? /@($= (:($= (:3$= 34)5 ):08 0:34 3>38 3>3'@ 3:0$= 0.D(A D<	 ? ? 	 ""-.  	(*131>@)+#%%%  (%)+ . 	'%(824-# $ + . 	(-+0.3$ ')'#!"%#"' 7 : 	 &&%& 	,& 	7	&
 	0& 	6& 	9& 	<& 	$& 	&& 	.& 	!& 	& 	#& 	&  	!&" 	#&$ 	#%&& 	)'&( 	#)&* 	#+&, 	!-&. 	)/&0 	/1&2 	53&4 	B5&6 	7&8 	9&: 	;&< 	=&> 	?&@ 	$A&B 	%C&D 	E&F 	G&H 	I&J 	K& &N 	//5)($(!'*!/++ . 	  cq qh]W@W#W "W %	W
 5W /W 1W *W  W W W W W W W  !W" #W$ !%W& 'W* %+W, .-W. ;/W0 &1W2 "3W4 "5W6 "7W8 9W: ;W< =W> ?W@ %AWB "CWD &EWN OWP QWR %SWT UWV WWX YWZ %[W\ +]W^ 1_W` >aWd eWf  gWh !iWj kWl mWn oWp qWt ,uWv ,wWx 2yW| %}W~ *W@ (AWB -CWD +EWF 0GWH !IWJ KWL MWN OWP QWR SWT $UWV &WWX $YWZ  [W\ ]W^ "_W`  aWb cW t\&J-8 J-Z zT r!   