Exemple #1
0
    def _createCadence(self, harmonicRhythm):
        """Applies a stock cadence

        Args:
            harmonicRhythm (list): List of RhythmTree objects

        Returns:
            cadenceChordProgression (list): List of Chord objects
        """
        random = RandomManager.getActive()

        # choose cadence to apply
        cadences = self.chordProfile.getCadences()

        #TODO: Choose cadence in more intelligent way
        cadence = random.choice(cadences)

        scale = self.chordProfile.getScale().getName()
        cadenceChordProgression = []

        reversedHarmonicRhythm = reversed(harmonicRhythm[:])
        # create as many  cadence
        for count, durationObj in enumerate(reversedHarmonicRhythm):
            duration = durationObj.getDuration()
            code = cadence[-count+1]
            chord = Chord(code, duration=duration, scale=scale, octave=4)

            if count >= len(cadence):
                return cadenceChordProgression

            # prepend chord
            cadenceChordProgression.insert(0, chord)
        return cadenceChordProgression
    def generateHarmonicRhythmMU(self, metre, numBarsMU, densityImpact=None):
        """Generates a harmonic rhythm sequence for a MU

        Args:
            metre (Metre):
            harmonicDensityImpact (float): Arousal feature that influences
                                           the density of the harmony
            numBarsMU (int): Number of bars in a MU
        """
        # if we need to change the densityImpact, do so on the parent class which is how it's used
        if densityImpact is not None:
            super(HarmonyRhythmGenerator, self).setDensityImpact(densityImpact)

        rhythmicSeq = []

        # decide whether to use bar as a repeated pattern
        random = RandomManager.getActive()
        r = random.random()
        if r < self._probabilityRepeatBar:
            rhythmicSeqBar = self._generateHarmonicRhythmBar(metre)
            rhythmicSeq = []
            for i in range(numBarsMU):
                rhythmicSeq += rhythmicSeqBar

        else:

            # create harmonic rhythm for each bar
            for i in range(numBarsMU):
                rhythmicSeqBar = self._generateHarmonicRhythmBar(metre)
                rhythmicSeq += rhythmicSeqBar

        #print()
        #print(rhythmicSeq)
        return rhythmicSeq
    def _decideShape(self, numBackboneNotes):
        """Decides contour shapes for a backbone

        Args:
            numBackboneNotes (int): Number of notes of the backbone

        Returns:
            shape (list): List of "UPs" and "DOWNs" that determine the shape
                          of the melodic contour
        """
        type = self.type
        typeTemplate = self._availableTypes[type]
        random = RandomManager.getActive()

        # manage "ascending" and "descending" contour types
        if type == "ascending" or type == "descending":
            shape = typeTemplate * (numBackboneNotes - 1)

        # manage "arch" and "invertedArch" types
        elif type == "arch" or type == "invertedArch":
            if type == "arch":
                shape = [UP, DOWN]
            else:
                shape = [DOWN, UP]

            numBackboneNotesLeft = numBackboneNotes - (len(shape) + 1)

            # insert motions if we still have backbone notes
            if numBackboneNotesLeft:

                # decide how many notes reuse the first motion
                firstMotionProlongations = random.randrange(
                    numBackboneNotesLeft)

                # insert motions between first and last motions
                for i in range(numBackboneNotesLeft):

                    # case we reuse the last motion
                    if i > firstMotionProlongations:

                        # insert motion in penultimate position
                        shape.insert(-1, shape[-1])

                    # case we reuse the first motion
                    else:

                        # insert motion in penultimate position
                        shape.insert(-1, shape[0])

        # manage "random" type
        else:
            shape = []

            # choose up and down motions randomly
            for _ in range(numBackboneNotes - 1):
                t = random.choice([UP, DOWN])
                shape.append(t)

        return shape
def gaussSampling(minVal, maxVal, mean, sigma):
    random = RandomManager.getActive()
    s = random.gauss(mean, sigma)
    if s < minVal:
        return minVal
    elif s > maxVal:
        return maxVal
    else:
        return s
    def _decideToApplyDot(self, rhythmTree, maxDepth):
        """Decides whether to apply a dot either single or double.

        Args:
            rhythmTree (RhythmTree): Chosen rhythm space node

        Returns:
            newDuration (list): Pair duration, 't' (symbol for tie), if tie
                                gets applied
            numDots (int): Number of dots applied
        """

        duration = rhythmTree.getDuration()
        durationLevel = rhythmTree.getDurationLevel()
        random = RandomManager.getActive()
        r = random.random()

        numDots = 0

        # decide whether to apply a dot
        if r <= self._probabilityDot[durationLevel] and maxDepth >= 1:

            # decide which type of dot to apply
            #TODO need to verify that we're using melodrive's random manager when we integrate
            random = RandomManager.getActive()
            r2 = random.random()

            # handle single dot
            #TODO: this is confusing, but I get why you did it this way (compactness)
            if r2 <= self._probabilitySingleDot[durationLevel] or maxDepth < 2:
                numDots = 1
                duration = self._calcDotDuration(duration, numDots)
                return [duration, None], numDots

            # handle double dot
            else:
                numDots = 2
                duration = self._calcDotDuration(duration, numDots)
                return [duration, None], numDots

        # handle case in which no dots were applied
        else:
            return [duration, None], numDots
    def _decideToApplyTie(self, rhythmicSeqElement, durationLevel):
        """Decides whether to apply tie and adds a 't' to the duration

        Args:
            rhythmicSeqElement (list): [duration, None] - None indicates no tie
            durationLevel (int): Metrical level of chosen rhythm space node

        Returns:
            newDuration (list): Pair duration, 't' (symbol ofr tie), if tie
                                gets applied
        """

        duration = rhythmicSeqElement[0]
        random = RandomManager.getActive()
        r = random.random()
        if r <= self._probabilityTie[durationLevel]:
            return [duration, 't']
        else:
            return [duration, None]
    def generateMelodicRhythmMU(self, metre, numBarsMU):
        random = RandomManager.getActive()
        rhythmicSeq = []

        # decide whether to generate pickup
        if random.random() < self._additionalMUmaterial["pickup"]["prob"]:
            pickupSeq = self._generateAdditionalBar(metre, "pickup")
            rhythmicSeq.append(pickupSeq)

        # generate core bars
        for _ in range(numBarsMU):
            barSeq = self._generateMelodicRhythmBar(metre)
            rhythmicSeq.append(barSeq)

        # decide whether to generate prolongation
        if random.random() < self._additionalMUmaterial["prolongation"]["prob"]:
            prolongationSeq = self._generateAdditionalBar(metre,
                                                          "prolongation")
            rhythmicSeq.append(prolongationSeq)

        print()
        print(rhythmicSeq)
        return rhythmicSeq
    def addTupletsToRhythmTree(self, parent, probTuplets, probTupletType):
        """Inserts tuplets in the rhythm space tree

        Args:
            probTuplet (list): Prob of having a tuplet at different duration
                               levels
            probTupletType (dict): Prob of having different types of tuplets at
                                   different duration levels

        Returns:
            newTree (RhythmTree): Rhythm space with tuplets
        """

        lowestDurationLevel = parent.getLowestDurationLevel()
        currentLevel = parent.getDurationLevel()
        metricalAccent = parent.getMetricalAccent()
        random = RandomManager.getActive()

        # return up the stack if we're at the penultimate lowest duration level

        if (lowestDurationLevel - currentLevel) < 1:
            return parent

        # decide whether to insert tuplets
        r = random.random()
        if r < probTuplets[currentLevel][metricalAccent]:

            # decide which type of tuplets to insert
            tupletType = self._decideTupletType(probTupletType, currentLevel)
            self.insertTuplet(parent, tupletType)
            return parent

        children = parent.getChildren()
        for child in children:
            self.addTupletsToRhythmTree(child, probTuplets, probTupletType)
        return parent
def decideCumulativeDistrOutcomeDict(distr):
    random = RandomManager.getActive()
    r = random.random()
    return getCumulativeDistrOutcomeDict(r, distr)
Exemple #10
0
    def generateHarmonyPitchMU(self, harmonicRhythm, harmonicComplexity,
                               minMajRatio, structureLevelMU):
        """Generates a chord progression for a harmonic rhythm sequence

        Args:
            harmonicRhythm (list): List containing RhythmTree objects
            harmonicComplexity (float): Value of emotional feature
            minMajRatio (float): Value of emotional feature
            structureLevelMU (str):

        Returns:
            chordProgression (list): List of Chord objects
        """
        # decide whether to have cadence
        cadenceProbDict = self.chordProfile.getCadenceProb()
        cadenceProb = cadenceProbDict[structureLevelMU]
        random = RandomManager.getActive()
        r = random.random()

        cadenceChordProgression = []
        if r <= cadenceProb:
            cadenceChordProgression = self._createCadence(harmonicRhythm)
            if len(cadenceChordProgression) == len(harmonicRhythm):
                return cadenceChordProgression

            # remove as many durations from harmonicRhythm as the
            # number of chords used for the cadence
            harmonicRhythm = harmonicRhythm[:-len(cadenceChordProgression)]

        chordProgression = []
        previousTriadCode = None
        chordIndex = None

        # step through all durations forming the harmonic rhythm to assign
        # chord
        for durationObj in harmonicRhythm:
            duration = durationObj.getDuration()
            scale = self.chordProfile.getScale().getName()
            metricalAccentLevel = durationObj.getMetricalAccent()

            # calculate scores
            scores = self._calcMetrics(previousTriadCode, chordIndex, metricalAccentLevel,
                                harmonicComplexity, minMajRatio)

            # choose triad
            chord, chordIndex = self._decideTriad(scores, durationObj)
            code = chord.getCode()

            # get probability of adding dissonant thirds
            dissonanceProb = self._calcDissonanceProb(harmonicComplexity,
                                        metricalAccentLevel)
            r = random.random()

            # decide whether to apply dissonance
            if r <= dissonanceProb:

                # add dissonance(s)
                code = self._decideDissonance(chord)

            # create new chord
            newChord = Chord(code, duration=duration, scale=scale,
                             octave=4)

            # append chord to progression
            chordProgression.append(newChord)

            # update previous code and triad code
            previousCode = newChord.getCode()
            previousTriadCode = previousCode[:3]

        # add up chord progression and chords for cadence
        chordProgression += cadenceChordProgression

        s = self._realizeM21Sequence(chordProgression)
        s.show("midi")

        return chordProgression