-
-
Save mmxgn/5891884 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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