Advertisement
Guest User

Untitled

a guest
Aug 25th, 2019
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.24 KB | None | 0 0
  1. import sys
  2. import itertools
  3. from os import listdir
  4. from os.path import isfile, join
  5.  
  6. from music21 import *
  7.  
  8. def analyzePiece(piece, title):
  9.     """ analyze a piece to find all potential subdominant tritones. """
  10.     if piece is not None:
  11.         print 'analyzing ' + title
  12.         chords = piece.chordify()
  13.  
  14.         outer_tt = False
  15.         tt_bass = None
  16.         tt_soprano  = None
  17.         tt_chord = None # the chord where the outer tritone appears
  18.         potential_sdtt = []
  19.  
  20.         # iterate through every harmony looking for a tritone between outer voices
  21.         # and the soprano resolving down
  22.         for current_chord in chords.recurse().getElementsByClass('Chord'):
  23.             current_bass_note = current_chord[-1]
  24.             current_soprano_note = current_chord[0]
  25.  
  26.             if outer_tt:
  27.                 current_soprano_note_interval = interval.Interval(tt_soprano,current_soprano_note)
  28.                 if current_bass_note.pitch != tt_bass.pitch:
  29.                     outer_tt = False
  30.                 # the soprano resolves down by a second, indicating a potential SdTT
  31.                 elif descSecond(current_soprano_note_interval) :
  32.                     outer_tt = False
  33.                     potential_sdtt.append({
  34.                         'measure': tt_chord.measureNumber,
  35.                         'beat': tt_chord.beatStr,
  36.                         'chord': tt_chord,
  37.                         'title': title,
  38.                     })
  39.                     print potential_sdtt[-1]
  40.             # indicate that the current bass note forms a tritone with the soprano voice
  41.             elif outerTritone(current_chord):
  42.                 outer_tt   = True
  43.                 tt_chord   = current_chord
  44.                 tt_bass    = current_bass_note
  45.                 tt_soprano = current_soprano_note
  46.  
  47.         return potential_sdtt
  48.     else:
  49.         print >> sys.stderr, '%s did not contain any score data' % (title)
  50.  
  51. def outerTritone(chrd):
  52.     """ determine whether the outer notes of the chord form a tritone. """
  53.     top = max(chrd.pitches)
  54.     bottom = min(chrd.pitches)
  55.     interv = interval.Interval(top,bottom).simpleName # reduce to simple interval
  56.     tritone = interval.Interval('a4').simpleName # both intervals need to be simple to compare
  57.     return interv == tritone
  58.  
  59. def descSecond(interv):
  60.     """ check if an interval is a descending second. """
  61.     return (interv.name == 'm2' or interv.name == 'M2') and interv.direction == -1
  62.  
  63. def analyzeComposer(composer):
  64.     """ analyze all the works of a composer available in the music21 corpus.
  65.  
  66.    Parameters
  67.    ----------
  68.    composer : string
  69.           The name of the composer
  70.    """
  71.     print 'analyzing the works of ' + composer
  72.  
  73.     # get the file paths of all of a composer's works
  74.     paths = corpus.getComposer(composer)
  75.     works = map(corpus.parse,paths)
  76.     titles = paths
  77.  
  78.     # find any possible instances of the SdTT
  79.     sdtts = []
  80.     for work, title in zip(works, titles):
  81.         sdtts.append(analyzePiece(work, title))
  82.  
  83.     return filter(lambda x: len(x) > 0, sdtts)
  84.  
  85. def analyzeFilePath(path):
  86.     """ analyze all files in the given directory (e.g. /music/haydn_quartets/).
  87.  
  88.    Parameters
  89.    ----------
  90.    path : string
  91.           The filepath containing files to analyze (e.g. /music/haydn_quartets/)
  92.    """
  93.     filenames = [f for f in listdir(path) if isfile(join(path, f))]
  94.     paths = map(lambda filename: path + filename, filenames)
  95.     print 'parsing all files in file path'
  96.     works = map(converter.parse,paths)
  97.  
  98.     titles = paths
  99.  
  100.     print 'analyzing pieces'
  101.     # find any possible instances of the sdtt
  102.     sdtts = []
  103.     for work, title in zip(works, titles):
  104.         sdtts.append(analyzePiece(work, title))
  105.  
  106.     return filter(lambda x: len(x) > 0, sdtts)
  107.  
  108. def analyzeWork(work_title):
  109.     """ analyze a work in the music21 corpus.
  110.  
  111.    Parameters
  112.    ----------
  113.    work_title : string
  114.                 The title of the work to analyze
  115.    """
  116.     parsed_work= corpus.parse(work_title)
  117.     print 'analyzing {0}'.format(work_title)
  118.     return analyzePiece(parsed_work, work_title)
  119.  
  120. def printResults(works):
  121.     """ pretty print the potential SdTTs. """
  122.  
  123.     print '-------------------------------'
  124.     print 'Potential Subdominant Tritones:'
  125.     print '-------------------------------'
  126.  
  127.     for work in works:
  128.         if len(work) > 0:
  129.             print work[0]['title']
  130.             for sdtt in work:
  131.                 print '\tChord:   {0}'.format(sdtt['chord'])
  132.                 print '\tMeasure: {0}'.format(sdtt['measure'])
  133.                 print '\tBeat:    {0}\n'.format(sdtt['beat'])
  134.  
  135. def main():
  136.     print sys.argv
  137.     if len(sys.argv) != 3:
  138.         print >> sys.stderr, 'incorrect number of arguments, must have 2 arguments'
  139.         sys.exit(0)
  140.  
  141.     results = None
  142.  
  143.     if sys.argv[1] == 'composer':
  144.         results = analyzeComposer(sys.argv[2])
  145.     elif sys.argv[1] == 'filepath':
  146.         results = analyzeFilePath(sys.argv[2])
  147.     elif sys.argv[1] == 'work':
  148.         results = [analyzeWork(sys.argv[2])]
  149.     else:
  150.         print >> sys.stderr, 'incorrect analysis options, must be one of [composer|filepath|work].'
  151.         sys.exit(0)
  152.  
  153.     printResults(results)
  154.  
  155. if __name__ == "__main__":
  156.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement