This module defines the ContourFinder and AggregateContour objects.
ContourFinder is a class for finding 2-dimensional contours of a piece based on different metrics.
Predefined metrics are ‘dissonance’, ‘tonality’, and ‘spacing’. To get a contour, use ContourFinder(myStream).getContour(‘dissonance’), for example.
If you wish to create your own metric for giving a numerical score to a stream, you can call ContourFinder(myStream).getContour(‘myMetricName’, metric=myMetric)
ContourFinder looks at a moving window of m measures, and moves that window by n measures each time. M and n are specified by ‘window’ and ‘slide’, which are both 1 by default.
>>> s = corpus.parse('bwv29.8')
>>> ContourFinder(s).plot('tonality')
TODO: image here...
ContourFinder attributes
Attributes without Documentation: isContourFinder, s, sChords, key
ContourFinder methods
- dissonanceMetric(inpStream)¶
inpStream is a stream containing some number of measures which each contain chords. Output is a number between 0 and 1 which is proportional to the number of dissonant chords.
To work correctly, input must contain measures and no parts.
>>> c = corpus.parse('bwv102.7').chordify() >>> contour.ContourFinder().dissonanceMetric( c.measures(1, 1) ) 0.25 >>> contour.ContourFinder().dissonanceMetric( c.measures(8, 8) ) 0.5 >>> contour.ContourFinder().dissonanceMetric( c.measures(1, 10)) < 1.0 True
- getContour(cType, window=None, slide=None, overwrite=False, metric=None, needsChordify=False, normalized=False)¶
Stores and then returns a normalized contour of the type cType. cType can be either ‘spacing’, ‘tonality’, or ‘dissonance’.
If using a metric that is not predefined, cType is any string that signifies what your metric measures. In this case, you must pass getContour a metric function which takes in a music21 stream and outputs a score. If passing a metric that requires the music21 stream be just chords, specify needsChordify=True.
Window is how many measures are considered at a time and slide is the number of measures the window moves over each time. By default, measure and slide are both 1.
Each time you call getContour for a cType, the result is cached. If you wish to get the contour for the same cType more than once, with different parameters (with a different window and slide, for example) then specify overwrite=True
To get a contour where measures map to the metric values, use normalized=False (the default), but to get a contour which evenly divides time between 1.0 and 100.0, use normalized=True
>>> cf = contour.ContourFinder( corpus.parse('bwv10.7')) >>> mycontour = cf.getContour('dissonance') >>> [mycontour[x] for x in sorted(mycontour.keys())] [0.0, 0.25, 0.5, 0.5, 0.0, 0.0, 0.25, 0.75, 0.0, 0.0, 0.5, 0.75, 0.75, 0.0, 0.5, 0.5, 0.5, 0.5, 0.75, 0.75, 0.75, 0.0]>>> mycontour = cf.getContour('always one', 2, 2, metric= lambda x: 1.0) >>> [mycontour[x] for x in sorted(mycontour.keys())] [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]>>> mycontour = cf.getContour('spacing', metric = lambda x: 2, overwrite=False) Traceback (most recent call last): OverwriteException: Attempted to overwrite 'spacing' metric but did not specify overwrite=True>>> mycontour = cf.getContour('spacing', slide=3, metric = lambda x: 2.0, overwrite=True) >>> [mycontour[x] for x in sorted(mycontour.keys())] [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0]>>> mycontour = cf.getContour('spacing') >>> [mycontour[x] for x in sorted(mycontour.keys())] [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0]
- getContourValuesForMetric(metric, window=1, slide=1, needChordified=False)¶
Returns a dictionary mapping measure numbers to that measure’s score under the provided metric. Ignores pickup measures entirely.
Window is a positive integer indicating how many measure the metric should look at at once, and slide is a positive integer indicating by how many measures the window should slide over each time the metric is measured.
e.g. if window=4 and slide=2, metric = f, the result will be of the form: { measures 1-4: f(measures 1-4), measures 3-6: f(measures 3-6), measures 5-8: f( measures5-8), ...}
>>> metric = lambda s: len(s.measureOffsetMap()) >>> c = corpus.parse('bwv10.7') >>> res = contour.ContourFinder(c).getContourValuesForMetric(metric, 3, 2, False) >>> #set([1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21]).issubset(set(res.keys())) >>> res.keys() [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21] >>> res.values() [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2]
- plot(cType, contour=None, regression=True, order=4, title='Contour Plot', fileName=None)¶
No documentation.
- randomize(contourDict)¶
Returns a version of contourDict where the keys-to-values mapping is scrambled.
>>> myDict = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8, 9:9, 10:10, 11:11, 12:12, 13:13, ... 14:14, 15:15, 16:16, 17:17, 18:18, 19:19, 20:20} >>> res = contour.ContourFinder().randomize(myDict) >>> res == myDict False >>> sorted(res.keys()) == sorted(myDict.keys()) True >>> sorted(res.values()) == sorted(myDict.values()) True
- setKey(key)¶
Sets the key of ContourFinder’s internal stream. If not set manually, self.key will be determined by self.s.analyze(‘key’).
- spacingMetric(inpStream)¶
Defines a metric which takes a music21 stream containng measures and no parts. This metric measures how spaced out notes in a piece are.
- tonalDistanceMetric(inpStream)¶
Returns a number between 0.0 and 1.0 that is a measure of how far away the key of inpStream is from the key of ContourFinder’s internal stream.
An AggragateContour object is an object that stores and consolidates contour information for a large group of pieces.
To add a piece to the aggregate contour, use AggregateContour.addPieceToContour(piece, cType), where cType is the type of contour (the default possibilities are ‘tonality’, ‘spacing’, and ‘dissonance’), and piece is either a parsed music21 stream or a ContourFinder object.
To get the combined contour as list of ordered pairs, use AggragateContour.getCombinedContour(), and to get the combined contour as a polynomial approximation, use AggragateContour.getCombinedContourPoly(). You can plot contours with AggragateContour.plotAggragateContour(cType).
To compare a normalized contour to the aggragate, use AggragateContour.dissimilarityScore(cType, contour).
AggregateContour attributes
Attributes without Documentation: aggContours
AggregateContour methods
- addPieceToContour(piece, cType, metric=None, window=1, slide=1, order=8, needsChordify=False)¶
Adds a piece to the aggregate contour.
piece is either a music21 stream, or a ContourFinder object (which should have a stream wrapped inside of it).
cType is the contour type.
If using a metric that is not predefined, cType is any string that signifies what your metric measures. In this case, you must pass getContour a metric function which takes in a music21 stream and outputs a score. If passing a metric that requires the music21 stream be just chords, specify needsChordify=True.
Window is how many measures are considered at a time and slide is the number of measures the window moves over each time. By default, measure and slide are both 1.
- dissimilarityScore(cType, contourDict)¶
Returns a score based on how dissimilar the input contourDict is from the aggregate contour of type cType.
Requires contourDict be normalized with values from 1.0 to 100.0
- getCombinedContour(cType)¶
Returns the combined contour of the type specified by cType. Instead of a dictionary, this contour is just a list of ordered pairs (tuples) with the first value being time and the second value being the score.
- getCombinedContourPoly(cType, order=8)¶
Returns the polynomial fit for the aggregate contour of type cType.
Order is the order of the resulting polynomial. e.g. For a linear regression, order=1.
- plot(cType, showPoints=True, comparisonContour=None, regression=True, order=6)¶
No documentation.