Created
January 6, 2016 05:59
-
-
Save TonyMooori/434bdfa83fcd12aa2f3d 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
# -*- coding: utf-8 -*- | |
import numpy as np | |
import pyaudio | |
import struct | |
import time | |
__author__ = "TonyMooori" | |
class MusicMorph: | |
def __init__(self,length = 8,n_child = 4,pulse = 0.25, mutation = 0.25): | |
""" | |
length: The length of a socre.(楽譜の長さ) | |
n_child: The number of the scores.(楽譜の数) | |
pulse: The length of a pulse(second).(拍の長さ[秒]) | |
mutation: The percentage of mutation.(突然変異の確率) | |
""" | |
""" The frequency of each scales.(音程の周波数) """ | |
self.scales = np.array([ 0.0, 261.63,293.66,329.63,349.23,392.00,440.00,493.88,523.25,]) | |
self.length = length | |
self.n_child = n_child | |
self.pulse = pulse | |
self.mutation = mutation | |
""" Make scores.(楽譜を作る) """ | |
self.refresh() | |
def createSineWave(self,freq,sec=1.0,rate = 44100.0): | |
""" | |
Return the sine wave.(サイン波を返します) | |
freq: The frequency of the sound.(音の周波数) | |
sec: The length of the sound(second).(音の時間[秒]) | |
rate: The sampling rate of the sound.(サンプリング周波数) | |
""" | |
x = np.linspace( 0, 2 * np.pi * sec, num = int(rate * sec)) | |
y = (32767.0 * np.sin( freq * x ) ).astype(np.int) | |
return struct.pack("h" * len(y), *y ) | |
def play(self,indx): | |
""" | |
The function to play the score.(演奏を行う関数) | |
indx: The index of score.(楽譜番号) | |
""" | |
p = pyaudio.PyAudio() | |
stream = p.open( | |
rate=44100, | |
channels=1, | |
format=pyaudio.paFloat32, | |
output=True | |
) | |
""" Play each sound.(音ごとに演奏する) """ | |
for indx,length in self.child_score[indx]: | |
sec = self.pulse * ( 2.0 ** length ) | |
freq = self.scales[int(indx)] | |
stream.write(self.createSineWave(freq,sec)) | |
stream.close() | |
p.terminate() | |
def random_sound(self,last_scale): | |
""" Return a random sound.(音をランダムに作る) """ | |
sound = np.zeros(2) | |
n_scale = len(self.scales) | |
""" Decide a scale of the sound.(音程を決める) """ | |
sound[0] = int(np.random.random_sample() * n_scale) | |
while last_scale == sound[0]: | |
sound[0] = int(np.random.random_sample() * n_scale) | |
""" Decide a length of the sound.(音の長さを決める) """ | |
sound[1] = int(np.random.random_sample() * 4) | |
return sound | |
def random_score(self): | |
""" Return a random score.(ランダムな楽譜を返す) """ | |
score = np.zeros((self.length,2)) | |
last_scale = -1 | |
for i in range(self.length): | |
score[i] = self.random_sound(last_scale) | |
last_scale = score[i,0] | |
return score | |
def make_children(self): | |
""" Remake all scores using the selected score.(選択した楽譜で全て作り直す) """ | |
scores = np.zeros((self.n_child,self.length,2)) | |
scores[0] = self.main_score | |
for i in range(1,self.n_child): | |
scores[i] = self.make_child() | |
return scores | |
def make_child(self): | |
""" Make a new score using a selected score.(類似した楽譜を作る) """ | |
score = self.main_score.copy() | |
last_scale = -1 | |
for i in range(len(score)): | |
if np.random.random_sample() < self.mutation: | |
score[i] = self.random_sound(last_scale) | |
last_scale = score[i,0] | |
return score | |
def select(self,indx): | |
""" | |
Select the best music.(選択を行うメソッド) | |
indx: The number of the score.(楽譜番号) | |
""" | |
self.main_score = self.child_score[indx] | |
self.child_score = self.make_children() | |
def refresh(self): | |
""" Refresh all the scores.(楽譜を一新するメソッド) """ | |
self.main_score = self.random_score() | |
self.child_score = self.make_children() | |
print("Music Morph") | |
n_child = 4 | |
mm = MusicMorph(n_child = n_child) | |
while True: | |
print("\n" + "*" * 40) | |
print("input command") | |
print("-3\t: exit") | |
print("-2\t: init scores") | |
print("-1\t: listen all") | |
for i in range(n_child): | |
print(str(i) + "\t: listen score no." + str(i)) | |
for i in range(n_child): | |
print(str(i+n_child) + "\t: select score no." + str(i)) | |
""" Input and parse to the integer.(入力してint型に変換) """ | |
cmd = raw_input() | |
try: | |
cmd = int(cmd) | |
except: | |
cmd = -4 | |
""" Branch.(分岐) """ | |
if cmd == -3: | |
break | |
elif cmd == -2: | |
print("refreshed") | |
mm.refresh() | |
elif cmd == -1: | |
print("listen all") | |
for i in range(n_child): | |
print("playing no." + str(i) ) | |
mm.play(i) | |
time.sleep(0.25) | |
elif 0 <= cmd <= n_child - 1: | |
print("playing no." + str(cmd)) | |
mm.play( cmd ) | |
elif n_child <= cmd <= 2 * n_child - 1: | |
print("selected no." + str(cmd%n_child)) | |
mm.select(cmd % n_child) | |
else: | |
print("wrong input") | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment