Skip to content

Instantly share code, notes, and snippets.

@mmxgn
Forked from anonymous/gist:5891882
Last active December 19, 2015 03:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mmxgn/5891884 to your computer and use it in GitHub Desktop.
Save mmxgn/5891884 to your computer and use it in GitHub Desktop.
from constraint import Problem,\
RecursiveBacktrackingSolver,\
AllDifferentConstraint,\
MinConflictsSolver
import mingus.core.notes as notes
import mingus.extra.LilyPond as LilyPond
from mingus.containers import Bar,Track
from mingus.midi import MidiFileOut
from time import time # Time execution.
# Initialize our CSP problem.
AllIntervalCSP = Problem()
# Each variable is named `N#' where # is a number from 0 to 11
# This is not a requirement, but helps the eye.
NoteList = ['N'+ str(n) for n in range(0,12)] # N0..N11
# Same for the eleven intervals.
IntervalList = ['I'+ str(i) for i in range(1,12)] # I1..I11
# Add the variables to the csp. Each variable has a finite domain
# of integral elements that represent a pitch-class (from 0 to 11).
AllIntervalCSP.addVariables(NoteList, range(0,12)) # 0..11
AllIntervalCSP.addVariables(IntervalList, range(0, 12)) # 0..11
# Restrict every variable to take a different value.
AllIntervalCSP.addConstraint(AllDifferentConstraint(), NoteList) # All pitches different
AllIntervalCSP.addConstraint(AllDifferentConstraint(), IntervalList) # All intervals different
# A constraint restricts the intervals to be pair-wise distinct.
# The modulo is there because the intervals are inversional-equivalent
# (i.e. a 5th upward is an inverse fourth downward).
for i in range(1,12):
AllIntervalCSP.addConstraint(lambda I,N1,N2: I == (N2-N1) % 12 , (IntervalList[i-1],NoteList[i-1],NoteList[i]))
# Constraint first note to be of pitch class 0 (C) and
# last note to be of pitch class L/2
AllIntervalCSP.addConstraint(lambda x: x==0, (NoteList[0],)) # First note is a C
AllIntervalCSP.addConstraint(lambda x: x==6, (NoteList[-1],)) # Last note is a F#/Gb
# Time while searching for a solution...
print "Searching for a solution:"
startTime = time()
AllIntervalSolution = AllIntervalCSP.getSolution()
duration = time() - startTime
if AllIntervalSolution is not None:
print "Solution found in %.2fms." % (duration*1000.0)
# Store the solution on a list of integers.
Sol = [AllIntervalSolution[n] for n in NoteList]
# Create a track using mingus.
track = Track()
for n in Sol:
track.add_notes(notes.int_to_note(n))
# Create a lilypond string from our track.
lilytrack = LilyPond.from_Track(track)
# Store it to .pdf and .png files.
LilyPond.to_pdf(lilytrack, "output")
LilyPond.to_png(lilytrack, "output")
# Output it as a midi file.
MidiFileOut.write_Track('output.mid', track, 120, 0)
else:
# Solution not found. Show time wasted.
print "Solution not found. Exhausted in %ss" % duration
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment