Advertisement
Guest User

Fractal song generation in Python

a guest
Jul 3rd, 2015
211
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.98 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. """
  4. Song generation using 'Fractal Wurfelspiel' technique as described in
  5. https://plus.maths.org/content/os/issue55/features/kormann/index
  6. and Fractal Motion / Midpoint Displacement, as described in
  7. http://www.tursiops.cc/fm/#midpt
  8.  
  9. The generated song is a string in MML format.
  10.  
  11. Author: a5kin
  12. """
  13.  
  14. import math, random
  15.  
  16. class FractalSong:
  17.  
  18.     def __init__(self, structure='00010011', notes=["o2e", "o2g", "o2a", "o2a+", "o2b", "o3d", "o3e", "o3g", "o3a", "o3a+", "o3b", "o4d", "o4e", ]):
  19.         self.pattern = structure
  20.         self.structure = [int(c) for c in structure]
  21.         self.items = 2
  22.         self.rhythm = ""
  23.         self.bars = []
  24.         self.notes = notes
  25.         self.melody = [None for i in range(len(self.notes))]
  26.         self.song = "l16"
  27.  
  28.     def iterate(self):
  29.         struct1 = [p for p in self.structure]
  30.         struct2 = [p + self.items for p in self.structure]
  31.         self.structure[:] = []
  32.         for i in range(len(self.pattern)):
  33.             ii = i % (len(self.pattern) // 2)
  34.             if self.pattern[i] == '0':
  35.                 self.structure += struct1[ii*self.items:(ii+1)*self.items]
  36.             else:
  37.                 self.structure += struct2[ii*self.items:(ii+1)*self.items]
  38.         self.items *= 2
  39.  
  40.     def build_melody(self, x1, x2, v1, v2):
  41.         if x2 - x1 <= 0:
  42.             return
  43.         self.melody[x1] = v1
  44.         self.melody[x2] = v2
  45.         if x2 - x1 <= 1:
  46.             return
  47.         xc = (x1 + x2) // 2
  48.         vc = max(0, min(len(self.notes) - 1, (v1 + v2) // 2 + random.randint(-2, 4)))
  49.         self.build_melody(x1, xc, v1, vc)
  50.         self.build_melody(xc, x2, vc, v2)
  51.  
  52.     def generate(self, iters, mask = 0b1111, mandatory=0b0000):
  53.         # build rhythm
  54.         for i in range(iters):
  55.             self.iterate()
  56.         num = random.randint(0, 15)
  57.         num |= mandatory
  58.         num &= mask
  59.         for i in range(self.items):
  60.             num = num ^ 2 ** random.randint(0, 3)
  61.             if i % 2 == 0 and num < 8:
  62.                 num += 8 # make sure each bar starts with note
  63.             num |= mandatory
  64.             bar = bin(num)[2:].zfill(4).replace("0", " ").replace("1", "X")
  65.             self.bars.append(bar)
  66.             num &= mask
  67.         for i in self.structure:
  68.             self.rhythm += self.bars[i] + "|"
  69.         # build melody
  70.         self.iterate()
  71.         self.iterate()
  72.         self.melody = [None for i in range(len(self.structure)*4)]
  73.         self.build_melody(0, len(self.structure)*4 - 1, 0, 0)
  74.         self.rhythm = self.rhythm.replace("|", "")
  75.         for i in range(len(self.rhythm)):
  76.             bar_num = self.structure[i // 4] * 4 + i % 2
  77.             note = self.notes[self.melody[bar_num]] if self.rhythm[i] == "X" else "r"
  78.             self.song += note
  79.  
  80. if __name__ == "__main__":
  81.     fs = FractalSong("00010011", ["o2e", "o2g", "o2a", "o2a+", "o2b", "o3d", "o3e", "o3g", "o3a", "o3a+", "o3b", "o4d", "o4e", ])
  82.     fs.generate(5)
  83.     print fs.song
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement