Created
March 2, 2019 23:53
-
-
Save rniwase/a360eb22f0ba8158c2bcfc2465202d8b 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
import os | |
import sys | |
import wave | |
import numpy as np | |
in_file = "amenbrother.wav" # 入力ファイル | |
out_filename_detail = True # 出力ファイル名にパラメータをつける | |
in_bar = 1 # 入力データの小節数 | |
out_bar = 8 # 出力データの小節数 | |
transient = 8 # 1小節の刻み数 | |
rand_seed = None # 乱数のシード値(None:実行毎にランダム,自然数:シード値) | |
rand_prob = 0.2 # ランダマイズ確率(0.0~1.0) | |
loop_trans = 2 # ループ分割数(1:なし,n:n分割) | |
loop_prob = 0.2 # ループ確率(0.0~1.0) | |
rev_prob = 0.1 # 逆再生確率(0.0~1.0) | |
transpose = [-2, 1, 3, 5] # ピッチシフト(半音,複数指定可) | |
transpose_prob = 0. # ピッチシフト確率 | |
stretch = 2.0 # ストレッチ(1.0以上) | |
stretch_prob = 0.08 # ストレッチ確率 | |
env_attack = 0. # エンベロープ - アタック時間(0.0~1.0) | |
env_hold = 1. # エンベロープ - ホールド時間(0.0~1.0) | |
env_release = 0.1 # エンベロープ - リリース時間(0.0~1.0) | |
env_prob = 0.1 # エンベロープ確率 | |
reduc_depth = 6 # リダクション - ビット深度 | |
reduc_rate = 0.3 # リダクション - サンプルレート(0.0~1.0) | |
reduc_prob = 0.#0.1 # リダクション確率 | |
# エフェクト | |
def timestretch(data, stretch, grain_size=800, fade=80): | |
grain_num = int(data.size / grain_size) + 1 | |
grained_data = np.hstack([data, np.zeros(grain_size * grain_num - data.size).astype(dtype="int16")]) | |
grained_data = grained_data.reshape((grain_num, grain_size)) | |
stretched_ary = np.zeros((grain_num, int(grain_size * stretch))).astype(dtype="int16") | |
if stretch > 1.: | |
fade_weight = np.ones(grain_size) | |
fade_weight[:fade] *= np.linspace(0., 1., fade_weight[:fade].size) | |
fade_weight[-fade:] *= np.linspace(1., 0., fade_weight[-fade:].size) | |
for i in range(int(stretch)): | |
stretched_ary[:, i * grain_size:(i + 1) * grain_size] = (grained_data[:, :] * fade_weight).astype(dtype="int16") | |
fade_weight = np.ones(int(grain_size * (stretch % 1. + 1.)) - grain_size) | |
fade_weight[:fade] *= np.linspace(0., 1., fade_weight[:fade].size) | |
fade_weight[-fade:] *= np.linspace(1., 0., fade_weight[-fade:].size) | |
stretched_ary[:, int(stretch) * grain_size:] = (grained_data[:, :int(grain_size * (stretch % 1. + 1.)) - grain_size] * fade_weight).astype(dtype="int16") | |
elif stretch < 1.: | |
fade_weight = np.ones(int(grain_size * stretch)) | |
fade_weight[:fade] *= np.linspace(0., 1., fade_weight[:fade].size) | |
fade_weight[-fade:] *= np.linspace(1., 0., fade_weight[-fade:].size) | |
stretched_ary[:, :] = (grained_data[:, :int(grain_size * stretch)] * fade_weight).astype(dtype="int16") | |
else: | |
return data | |
stretched_ary = stretched_ary.reshape(stretched_ary.size) | |
return stretched_ary | |
def speedx(sound_array, factor): | |
indices = np.round( np.arange(0, len(sound_array), factor) ) | |
indices = indices[indices < len(sound_array)].astype(int) | |
return sound_array[ indices.astype(int) ] | |
def pitchshift(data, semitones, grain_size=800, fade=80): | |
factor = 2**(1.0 * semitones / 12.0) | |
# resampled = scipy.signal.resample(data, int(data.size / factor)).astype("int16") | |
# stretched = timestretch(resampled, factor, grain_size=grain_size, fade=fade) | |
resampled = speedx(data, factor).astype("int16") | |
stretched = timestretch(resampled, factor, grain_size=grain_size, fade=fade) | |
return stretched[:data.size] | |
def reduction(data, depth, rate): | |
return (speedx(speedx(data, 1. / rate), rate)[:data.size] & (0xFFFF << depth)).astype("int16") | |
in_data = wave.open(in_file, "r") | |
wave_ary = in_data.readframes(in_data.getnframes()) | |
wave_ary = np.frombuffer(wave_ary, dtype="int16") | |
transient *= in_bar | |
out_bar = int(out_bar / in_bar) | |
crp_len = int(wave_ary.size / transient) | |
if rand_seed == None: | |
rand_seed = np.random.randint(0, 2**31) | |
np.random.seed(seed=rand_seed) | |
random_ary = np.random.randint(0, transient, transient * out_bar) | |
orig_ary = np.array([i for i in range(transient)] * out_bar) | |
rand_prob_ary = np.array(np.random.rand(transient * out_bar) | |
< rand_prob).astype(int) | |
seq_ary = (rand_prob_ary * random_ary) + ((-rand_prob_ary + 1) * orig_ary) | |
loop_prob_ary = np.array(np.random.rand(transient * out_bar) | |
< loop_prob).astype(int) | |
loop_crp_len = int(crp_len / loop_trans) | |
rev_prob_ary = np.array(np.random.rand(transient * out_bar) | |
< rev_prob).astype(int) | |
trps_prob_ary = np.array(np.random.rand(transient * out_bar) | |
< transpose_prob).astype(int) | |
trps_prob_ary *= np.random.randint(1, len(transpose) + 1, trps_prob_ary.size) | |
strc_prob_ary = np.array(np.random.rand(transient * out_bar) | |
< stretch_prob).astype(int) | |
env_prob_ary = np.array(np.random.rand(transient * out_bar) | |
< env_prob).astype(int) | |
env_attack_len = int(env_attack * crp_len) | |
env_hold_len = int(env_hold * crp_len) | |
env_release_len = int(env_release * crp_len) | |
env_weight = np.zeros(crp_len) | |
env_weight[:env_hold_len] += 1. | |
env_weight[:env_attack_len] *= np.linspace(0., 1., env_weight[:env_attack_len].size) | |
env_weight[env_hold_len-env_release_len:env_hold_len] *= np.linspace(1., 0., env_weight[env_hold_len-env_release_len:env_hold_len].size) | |
reduc_prob_ary = np.array(np.random.rand(transient * out_bar) | |
< reduc_prob).astype(int) | |
com_ary = np.array([seq_ary, | |
loop_prob_ary, | |
rev_prob_ary, | |
trps_prob_ary, | |
strc_prob_ary, | |
env_prob_ary, | |
reduc_prob_ary]).T | |
print(com_ary) | |
params = (os.path.split(in_file)[1], | |
in_bar, | |
transient, | |
out_bar, | |
rand_seed, | |
rand_prob, | |
loop_trans, | |
loop_prob, | |
rev_prob, | |
transpose, | |
transpose_prob, | |
stretch, | |
stretch_prob, | |
env_attack, | |
env_hold, | |
env_release, | |
env_prob, | |
reduc_depth, | |
reduc_rate, | |
reduc_prob | |
) | |
print(params) | |
try: | |
if out_filename_detail: | |
out_data = wave.Wave_write("out_{0}.wav".format(params)) | |
else: | |
out_data = wave.Wave_write("out.wav") | |
except PermissionError: | |
print("ファイルが使用中もしくは書き込む権限がありません.") | |
sys.exit() | |
out_data.setparams(in_data.getparams()) | |
for a in com_ary: | |
seq_data = wave_ary[a[0] * crp_len:(a[0] + 1) * crp_len] | |
# エフェクトの順序 | |
if a[3] != 0: # ピッチシフト | |
seq_data = pitchshift(seq_data, transpose[a[3] - 1]) | |
if a[4] != 0: # タイムストレッチ | |
seq_data = timestretch(seq_data, stretch)[:seq_data.size] | |
if a[5] != 0: # エンベロープ | |
seq_data = (seq_data * env_weight).astype("int16") | |
if a[2] != 0: # 逆再生 | |
seq_data = np.array(seq_data[::-1]) | |
if a[1] != 0: # ループ | |
seq_data = np.hstack([seq_data[:loop_crp_len]] * loop_trans) | |
if a[6] != 0: # リダクション | |
seq_data = reduction(seq_data, reduc_depth, reduc_rate) | |
out_data.writeframes(seq_data) | |
out_data.close() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment