François Pinot1920001920219200019202truefalsefalsefalsetruetruetruetrue-dfalsefalsetruetruetruetrue-d -ffalsefalse0falsecfmidur = p3
iamp = p4
ifq1a = p5
ifq1b = p6
ifq2a = p7
ifq2b = p8
inx1a = p9
inx1b = p10
inx2a = p11
inx2b = p12
icpsa = p13
icpsb = p14
ifn1 = p15
ifn2 = p16
iphs1 = p17
iphs2 = p18
kfrq1 line ifq1a, idur, ifq1b
kfrq2 line ifq2a, idur, ifq2b
kndx1 line inx1a, idur, inx1b
kndx2 line inx2a, idur, inx2b
kcps line icpsa, idur, icpsb
kenv linen iamp, 0.05, idur, 0.2
a1, a2 crossfm kfrq1, kfrq2, kndx1, kndx2, kcps, ifn1, ifn2, iphs1, iphs2
outs a1*kenv, a2*kenv
cpmidur = p3
iamp = p4
ifq1a = p5
ifq1b = p6
ifq2a = p7
ifq2b = p8
inx1a = p9
inx1b = p10
inx2a = p11
inx2b = p12
icpsa = p13
icpsb = p14
ifn1 = p15
ifn2 = p16
iphs1 = p17
iphs2 = p18
kfrq1 line ifq1a, idur, ifq1b
kfrq2 line ifq2a, idur, ifq2b
kndx1 line inx1a, idur, inx1b
kndx2 line inx2a, idur, inx2b
kcps line icpsa, idur, icpsb
kenv linen iamp, 0.05, idur, 0.2
a1, a2 crosspm kfrq1, kfrq2, kndx1, kndx2, kcps, ifn1, ifn2, iphs1, iphs2
outs a1*kenv, a2*kenv
cfmpmidur = p3
iamp = p4
ifq1a = p5
ifq1b = p6
ifq2a = p7
ifq2b = p8
inx1a = p9
inx1b = p10
inx2a = p11
inx2b = p12
icpsa = p13
icpsb = p14
ifn1 = p15
ifn2 = p16
iphs1 = p17
iphs2 = p18
kfrq1 line ifq1a, idur, ifq1b
kfrq2 line ifq2a, idur, ifq2b
kndx1 line inx1a, idur, inx1b
kndx2 line inx2a, idur, inx2b
kcps line icpsa, idur, icpsb
kenv linen iamp, 0.05, idur, 0.2
a1, a2 crossfmpm kfrq1, kfrq2, kndx1, kndx2, kcps, ifn1, ifn2, iphs1, iphs2
outs a1*kenv, a2*kenv
false0.01Master0.0falsefalse2Master0.0falsefalse3Master0.0falsefalseMasterMaster0.0falsefalse;sine wave
f 1 0 16384 10 1
;pseudo square wave
f 2 0 16384 10 1000 0 333.333 0 200 0 142.857 0 111.111 0 90.909 \
0 76.923 0 66.667 0 58.824 0 52.632 0
;pseudo triangle wave
f 3 0 16384 10 1000 0 111.111 0 40 0 20.408 0 12.346 0 8.264 0 \
5.917 0 4.444 0 3.46 0 2.77 0
;pseudo sawtooth wave
f 4 0 16384 10 1000 500 333.333 250 200 166.667 142.857 125 111.111 \
100 90.909 83.333 76.923 71.429 66.667 62.5 58.824 \
55.556 52.632 50
0dbfs = 1csound -Wdo devaudio -L stdinfalsefalse2.00.0root-100662790true300true1.0053.00.0Comment-12566464Implementation of a Simple Genetic Algorithm to explore the parameter space of the crossfm opcodes.
The SGA Classes soundObject is a PythonObject including the SGA classes. It is a generic SGA and
can be used to explore other orchestras. A Genetic Algorithm is initiated with the following instruction:
ga = SGA(params, popSize, crossoverProbability, mutationProbability)
where params is a list of Allele objects. The other arguments have default values when not specified:
popSize defaults to 20, crossoverProbability defaults to 0.6, and mutationProbability defaults to 0.0333.
A new generation of the SGA is calculated by calling its setFitness() method, and then its action() method.
The decoded values from the calculation are get through the getValues() method.
________________________________
The Parameters coding soundObject is an ObjectBuilder. Its graphical interface allows the user to
set the parameters coding for the crossfm exploration. The scripting part of the object defines the
Parameters class which is a list of Allele objects corresponding to the parameters defined in the
graphical interface. The Parameters class has a newNote() method used to yield a new note from an
Individual values.
________________________________
The UI soundObject is an ObjectBuilder. Its graphical interface allows the user to control the
SGA evolution, and to set the fitness values for each sound through each pass. The scripting part of the
object shows how we use the persistence of the Jython environment during a blue session to pass information
from one generation of the SGA to the other one.
You first have to select the Parameters Coding soundObject and choose the settings you want. Then you
select the UI soundObject. Each time you press the play button, one of three possibilities happens. If the
Init box is checked, a new SGA is initiated with its first generation randomly calculated. If the Init
box is unchecked and the New gen box is unchecked, you ear again the sounds of the last calculated
generation. This is useful to set correctly the fitness values (slider controls). Finally, if the
Init box is unchecked and the New gen box is checked, a new generation is calculated by the SGA
depending on the fitness values set by the user.
Note: the first time you hit the play button, the Init box MUST be checked, otherwise you will
get a Jython error. This is due to the fact that when you open the cfm_ga.blue file, the ga object
does not exist within the Jython memory space, and the only way to create a new ga object is to
hit the play button while the UI Init box is checked.4.00.0SGA Classes-125664640#
# Copyright (C) 2009 Francois Pinot
#
# This code is free software; you can redistribute it
# and/or modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This code 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this code; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# 02111-1307 USA
#
import random
class Sga(object):
"""Simple genetic algorithm.
Adapted from Genetic Algorithms, by David E. Goldberg
Addison-Wesley USA, (15767), 1991
"""
def __init__(self, alleles, popSize=20, pCross=0.6, pMut=0.0333):
self.popSize = popSize
self.pCross = pCross
self.pMut = pMut
self.nCross = 0
self.nMut = 0
self.oldPop = Population(self.popSize, alleles)
self.newPop = Population(self.popSize, alleles)
def incCross(self):
self.nCross += 1
def incMut(self):
self.nMut += 1
def getCross(self):
return self.nCross
def getMut(self):
return self.nMut
def setCrossProb(self, prob):
if (prob >= 0 and prob <= 1.0):
self.pCross = prob
def setMutProb(self, prob):
if (prob >= 0 and prob <= 1.0):
self.pMut = prob
def generation(self):
"""Create a new generation through select, crossover, and mutation.
Note: an even-numbered popSize is assumed
"""
self.oldPop.statistics()
for i in xrange(0, self.popSize, 2):
mate1 = self.oldPop.select()
mate2 = self.oldPop.select()
child1 = self.newPop[i]
child2 = self.newPop[i+1]
child1.setParent1(mate1)
child1.setParent2(mate2)
child2.setParent1(mate1)
child2.setParent2(mate2)
cp1 = mate1.getChromosome()
cp2 = mate2.getChromosome()
cc1 = child1.getChromosome()
cc2 = child2.getChromosome()
lchrom = len(cc1)
if (random.random() <= self.pCross):
jcross = random.randint(1, lchrom-1)
self.nCross += 1
else:
jcross = lchrom
child1.setCrossPoint(jcross)
child2.setCrossPoint(jcross)
# 1st exchange, 1 to 1 and 2 to 2
for j in xrange(jcross):
if (random.random() <= self.pMut):
cc1[j] = 1 - cp1[j]
self.nMut += 1
else:
cc1[j] = cp1[j]
if (random.random() <= self.pMut):
cc2[j] = 1 - cp2[j]
self.nMut += 1
else:
cc2[j] = cp2[j]
# 2nd exchange, 1 to 2 and 2 to 1
for j in xrange(jcross, lchrom):
if (random.random() <= self.pMut):
cc1[j] = 1 - cp2[j]
self.nMut += 1
else:
cc1[j] = cp2[j]
if (random.random() <= self.pMut):
cc2[j] = 1 - cp1[j]
self.nMut += 1
else:
cc2[j] = cp1[j]
child1.setValues()
child2.setValues()
def flipPop(self):
tempPop = self.oldPop
self.oldPop = self.newPop
self.newPop = tempPop
def action(self):
self.generation()
self.flipPop()
def getValues(self):
ret = []
for ind in self.oldPop:
ret.append(ind.getValues())
return ret
def setFitness(self, val):
if len(val) < len(self.oldPop):
return
i = 0
for ind in self.oldPop:
ind.setFitness(val[i])
i += 1
class Allele(object):
"""Character in a Chromosome.
Allows the decoding of the character.
"""
def __init__(self, min=0.0, max=0.0, length=1, rounded=False, fixed=False):
self.fixed = fixed
self.rounded = rounded
self.offset = min
if self.fixed:
self.length = 0
self.coef = 0.0
else:
self.length = int(length)
self.coef = (max - min) / (2.0 ** length)
def getLength(self):
return self.length
def isFixed(self):
return self.fixed
def value(self, val=[]):
if self.fixed:
v = self.offset
else:
accum = 0.0
powerof2 = 1.0
for i in val:
if i == 1:
accum += powerof2
powerof2 *= 2.0;
v = accum * self.coef + self.offset
if self.rounded:
v = round(v)
else:
v = round(v, 3)
return v
class Chromosome(list):
"""Includes all the characters explored by the GA."""
def __init__(self, alleles):
self.alleles = alleles
length = 0
for a in self.alleles:
length += a.getLength()
for i in xrange(length):
if random.random() >= 0.5:
self.append(1)
else:
self.append(0)
def decode(self):
ret = []
i = j = 0
for a in self.alleles:
v = []
if not a.isFixed():
j += a.getLength()
v = self[i:j]
i = j
ret.append(a.value(v))
return ret
class Individual(object):
"""A member of the population treated by the GA."""
def __init__(self, alleles):
self.parent1 = self.parent2 = None
self.fitness = 0.0
self.chrom = Chromosome(alleles)
self.setValues()
self.xsite = 0
def getChromosome(self):
return self.chrom
def getFitness(self):
return self.fitness
def setFitness(self, val):
self.fitness = val
def getParent1(self):
return self.parent1
def setParent1(self, ind):
self.parent1 = ind
def getParent2(self):
return self.parent2
def setParent2(self, ind):
self.parent2 = ind
def getValues(self):
return self.values
def setValues(self):
self.values = self.chrom.decode()
def getCrossPoint(self):
return self.xsite
def setCrossPoint(self, n):
self.xsite = n
class Population(list):
"A population treated by the GA."""
MAXPOP = 100
def __init__(self, size=0, alleles=[]):
self.sumFitness = 0.0
self.max = self.avg = self.min = 0.0
if (size <= 0 or size > Population.MAXPOP):
size = Population.MAXPOP
for i in xrange(size):
ind = Individual(alleles)
self.append(ind)
def select(self):
"""Select a single individual via roulette wheel selection."""
partsum = 0.0
rand = random.random() * self.sumFitness
for ind in self:
partsum += ind.getFitness()
if (partsum >= rand):
return ind
return self[-1]
def statistics(self):
self.sumFitness = self.min = self.max = 0.0
for ind in self:
fitness = ind.getFitness()
self.sumFitness += fitness
if (fitness > self.max):
self.max = fitness
if (fitness < min):
self.min = fitness
self.avg = self.sumFitness / len(self)
def getAverage(self):
return self.avg
def getBestFitness(self):
return self.max
def showStats(self, n, nmut, ncross):
self.statistics()
print "Gen %d max=%f, min=%f, avg=%f, sum=%f, mut=%d, ncross=%d" % \
(n, self.max, self.min, self.avg, self.sumFitness, nmut, ncross)
5.00.0Parameters coding-125664640#
# Copyright (C) 2009 Francois Pinot
#
# This code is free software; you can redistribute it
# and/or modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This code 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this code; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# 02111-1307 USA
#
class Parameters(list):
def __init__(self, orcNum=1, dt=1.0):
self.append(Allele(<durMin>, <durMax>, <durLen>, <durRound>, <durConst>))
self.append(Allele(<frq1aMin>, <frq1aMax>, <frq1aLen>, <frq1aRound>, <frq1aConst>))
if <Frq1bOn>:
self.append(Allele(<frq1bMin>, <frq1bMax>, <frq1bLen>, <frq1bRound>, <frq1bConst>))
self.append(Allele(<frq2aMin>, <frq2aMax>, <frq2aLen>, <frq2aRound>, <frq2aConst>))
if <Frq2bOn>:
self.append(Allele(<frq2bMin>, <frq2bMax>, <frq2bLen>, <frq2bRound>, <frq2bConst>))
self.append(Allele(<inx1aMin>, <inx1aMax>, <inx1aLen>, <inx1aRound>, <inx1aConst>))
if <Inx1bOn>:
self.append(Allele(<inx1bMin>, <inx1bMax>, <inx1bLen>, <inx1bRound>, <inx1bConst>))
self.append(Allele(<inx2aMin>, <inx2aMax>, <inx2aLen>, <inx2aRound>, <inx2aConst>))
if <Inx2bOn>:
self.append(Allele(<inx2bMin>, <inx2bMax>, <inx2bLen>, <inx2bRound>, <inx2bConst>))
self.append(Allele(<cps_aMin>, <cps_aMax>, <cps_aLen>, <cps_aRound>, <cps_aConst>))
if <Cps_bOn>:
self.append(Allele(<cps_bMin>, <cps_bMax>, <cps_bLen>, <cps_bRound>, <cps_bConst>))
self.append(Allele(<fun1Min>, <fun1Max>, <fun1Len>, <fun1Round>, <fun1Const>))
self.append(Allele(<fun2Min>, <fun2Max>, <fun2Len>, <fun2Round>, <fun2Const>))
self.orcNum = orcNum
self.dt = dt
self.t = 0.0
self.template = "i %d %f %f 0.5 %f %f %f %f %f %f %f %f %f %f %d %d 0 0 \n"
def clearDate(self):
self.t = 0.0
def newNote(self, values):
v = values[:]
if not <Frq1bOn>:
v.insert(2, v[1])
if not <Frq2bOn>:
v.insert(4, v[3])
if not <Inx1bOn>:
v.insert(6, v[5])
if not <Inx2bOn>:
v.insert(8, v[7])
if not <Cps_bOn>:
v.insert(10, v[9])
s = self.template % tuple([self.orcNum, self.t] + v)
self.t += (v[0] + self.dt)
return s
false1351110222392235522durMin87505100durMax2185010100durLen3425013100durRound46147falsefalse2095frq1aMin879455100frq1aMax218941760100frq1aLen3429424100frq1aRound46191falsefalse20124frq1bMin8712355100frq1bMax2181231760100frq1bLen34212324100frq1bRound461120falsefalse20175frq2aMin8717355100frq2aMax2181731760100frq2aLen34217324100frq2aRound461170falsefalse20204frq2bMin8720355100frq2bMax2182031760100frq2bLen34220324100frq2bRound461199falsefalse21262inx1aMin862610100inx1aMax2172615100inx1aLen34126117100inx1aRound461258falsefalse21291inx1bMin862900100inx1bMax2172905100inx1bLen34129017100inx1bRound461287falsefalse21343inx2aMin863420100inx2aMax2173425100inx2aLen34134217100inx2aRound461339falsefalse21374inx2bMin863730100inx2bMax2173735100inx2bLen34137317100inx2bRound461370falsefalse20424cps_aMin854231100cps_aMax2164231100cps_aLen3404230100cps_aRound461420falsefalse23504fun1Min855031100fun1Max2165034100fun1Len3405032100fun1Round461500truefalse23534fun2Min855331100fun2Max2165334100fun2Len3405332100fun2Round461530truefalsedurConst55847truefalsefrq1aConst55891falsefalsefrq1bConst558120falsefalsefrq2bConst558199falsefalsefrq2aConst558170falsefalseinx1bConst558287falsefalseinx1aConst558258falsefalseinx2bConst558370falsefalseinx2aConst558339falsefalsecps_aConst558420truefalsefun2Const558530truefalsefun1Const558500truefalse74349743687438874310774312774315674319274321274323374325420455cps_bMin85454-2100cps_bMax2164542100cps_bLen34045416100cps_bRound461451falsefalsecps_bConst558451falsefalseFrq1bOn634120falsefalseFrq2bOn634199falsefalseInx1bOn634287truefalseInx2bOn634370truefalseCps_bOn634451falsefalse743277743299743321743343Python100.00.0UI-125664640#
# Copyright (C) 2009 Francois Pinot
#
# This code is free software; you can redistribute it
# and/or modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This code 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this code; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# 02111-1307 USA
#
def notes(ga, p):
values = ga.getValues()
p.clearDate()
s = ""
for v in values:
s += p.newNote(v)
return s
if <initFlag>:
params = Parameters(<orchNum>, <dtField>)
ga = Sga(params)
elif <newGenFlag>:
ga.setFitness([<fitness_0>, <fitness_1>, <fitness_2>, <fitness_3>, <fitness_4>,
<fitness_5>, <fitness_6>, <fitness_7>, <fitness_8>, <fitness_9>,
<fitness_10>, <fitness_11>, <fitness_12>, <fitness_13>, <fitness_14>,
<fitness_15>, <fitness_16>, <fitness_17>, <fitness_18>, <fitness_19>])
ga.action()
score = notes(ga, params)
falsefitness2121true0.01.00.053005true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300true00true0.01.00.050.0300truenewGenFlag97395falsefalseinitFlag32395truefalseorchNum227395cfm1cpm2cfmpm30false303399424399dtField444399060Pythontrue0.0-1.0falsefalsefalse