Source code for mingus.extra.lilypond

#!/usr/bin/python
# -*- coding: utf-8 -*-

#    mingus - Music theory Python package, lilypond module.
#    Copyright (C) 2008-2009, Bart Spaans
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""Functions to generate files in the LilyPond format.

This allows you to create sheet music from some of the objects in
mingus.containers.
"""

from mingus.core.keys import Key
from mingus.containers.mt_exceptions import (NoteFormatError,
        UnexpectedObjectError)
import mingus.core.value as value
import os
import subprocess

[docs]def from_Note(note, process_octaves=True, standalone=True): """Get a Note object and return the LilyPond equivalent in a string. If process_octaves is set to False, all data regarding octaves will be ignored. If standalone is True, the result can be used by functions like to_png and will produce a valid output. The argument is mostly here to let from_NoteContainer make use of this function. """ # Throw exception if not hasattr(note, 'name'): return False # Lower the case of the name result = note.name[0].lower() # Convert #'s and b's to 'is' and 'es' suffixes for accidental in note.name[1:]: if accidental == '#': result += 'is' elif accidental == 'b': result += 'es' # Place ' and , for octaves if process_octaves: oct = note.octave if oct >= 4: while oct > 3: result += "'" oct -= 1 elif oct < 3: while oct < 3: result += ',' oct += 1 if standalone: return '{ %s }' % result else: return result
[docs]def from_NoteContainer(nc, duration=None, standalone=True): """Get a NoteContainer object and return the LilyPond equivalent in a string. The second argument determining the duration of the NoteContainer is optional. When the standalone argument is True the result of this function can be used directly by functions like to_png. It is mostly here to be used by from_Bar. """ # Throw exception if nc is not None and not hasattr(nc, 'notes'): return False # Return rests for None or empty lists if nc is None or len(nc.notes) == 0: result = 'r' elif len(nc.notes) == 1: # Return a single note if the list contains only one note result = from_Note(nc.notes[0], standalone=False) else: # Return the notes grouped in '<' and '>' result = '<' for notes in nc.notes: result += from_Note(notes, standalone=False) + ' ' result = result[:-1] + '>' # Add the duration if duration != None: parsed_value = value.determine(duration) # Special case: check for longa and breve in the duration (issue #37) dur = parsed_value[0] if dur == value.longa: result += '\\longa' elif dur == value.breve: result += '\\breve' else: result += str(int(parsed_value[0])) for i in range(parsed_value[1]): result += '.' if not standalone: return result else: return '{ %s }' % result
[docs]def from_Bar(bar, showkey=True, showtime=True): """Get a Bar object and return the LilyPond equivalent in a string. The showkey and showtime parameters can be set to determine whether the key and the time should be shown. """ # Throw exception if not hasattr(bar, 'bar'): return False # Process the key if showkey: key = '\\key %s \\major ' % from_Note(bar.key, False, standalone=False) result = key else: result = '' # Handle the NoteContainers latest_ratio = (1, 1) ratio_has_changed = False for bar_entry in bar.bar: parsed_value = value.determine(bar_entry[1]) ratio = parsed_value[2:] if ratio == latest_ratio: result += from_NoteContainer(bar_entry[2], bar_entry[1], standalone=False) + ' ' else: if ratio_has_changed: result += '}' result += '\\times %d/%d {' % (ratio[1], ratio[0]) result += from_NoteContainer(bar_entry[2], bar_entry[1], standalone=False) + ' ' latest_ratio = ratio ratio_has_changed = True if ratio_has_changed: result += '}' # Process the time if showtime: return '{ \\time %d/%d %s}' % (bar.meter[0], bar.meter[1], result) else: return '{ %s}' % result
[docs]def from_Track(track): """Process a Track object and return the LilyPond equivalent in a string.""" # Throw exception if not hasattr(track, 'bars'): return False lastkey = Key('C') lasttime = (4, 4) # Handle the Bars: result = '' for bar in track.bars: if lastkey != bar.key: showkey = True else: showkey = False if lasttime != bar.meter: showtime = True else: showtime = False result += from_Bar(bar, showkey, showtime) + ' ' lastkey = bar.key lasttime = bar.meter return '{ %s}' % result
[docs]def from_Composition(composition): """Return the LilyPond equivalent of a Composition in a string.""" # warning Throw exception if not hasattr(composition, 'tracks'): return False result = '\\header { title = "%s" composer = "%s" opus = "%s" } '\ % (composition.title, composition.author, composition.subtitle) for track in composition.tracks: result += from_Track(track) + ' ' return result[:-1]
[docs]def from_Suite(suite): pass
[docs]def to_png(ly_string, filename): """Save a string in LilyPond format to a PNG. LilyPond in the $PATH is needed. """ return save_string_and_execute_LilyPond(ly_string, filename, '-fpng')
[docs]def to_pdf(ly_string, filename): """Save a string in LilyPond format to a PDF. LilyPond in the $PATH is needed. """ return save_string_and_execute_LilyPond(ly_string, filename, '-fpdf')
[docs]def save_string_and_execute_LilyPond(ly_string, filename, command): """A helper function for to_png and to_pdf. Should not be used directly.""" ly_string = '\\version "2.10.33"\n' + ly_string if filename[-4] in ['.pdf' or '.png']: filename = filename[:-4] try: f = open(filename + '.ly', 'w') f.write(ly_string) f.close() except: return False command = 'lilypond %s -o "%s" "%s.ly"' % (command, filename, filename) print 'Executing: %s' % command p = subprocess.Popen(command, shell=True).wait() os.remove(filename + '.ly') return True