Skip to content

Instantly share code, notes, and snippets.

@azyobuzin
Created November 13, 2017 17:03
Show Gist options
  • Save azyobuzin/7655c16938338ec9670a878bc7429d2e to your computer and use it in GitHub Desktop.
Save azyobuzin/7655c16938338ec9670a878bc7429d2e to your computer and use it in GitHub Desktop.
# 生成したファイルの出力先ディレクトリ
OUTPUT_DIR = 'output'
# 学習データとして使う音色
INSTS_FOR_TRAINING = [
# Piano
1, 3, 5, 7, 8,
# Chromatic Percussion
9, 11, 13, 15,
# Organ
17, 19, 21, 23, 24,
# Guitar
25, 27, 29, 31,
# Bass
33, 35, 37,
# Strings
41, 43, 45, 47,
# Ensemble
49, 51, 53, 55,
# Brass
57, 59, 60, 61, 63,
# Reed
65, 66, 68, 70, 72,
# Pipe
73, 75, 78, 80,
# Synth Lead
81, 85,
# Ethnic
105, 107, 110, 112
]
# テストデータとして使う音色
INSTS_FOR_EVALUATING = [
# Piano
2, 4, 6,
# Chromatic Percussion
10, 12, 16,
# Organ
18, 20, 22,
# Guitar
26, 28, 30,
# Bass
34, 36, 38,
# Strings
42, 44,
# Ensemble
50, 52,
# Brass
58, 62, 64,
# Reed
67, 69, 71,
# Pipe
74, 76, 79,
# Synth Lead
82, 88,
# Ethnic
106, 108, 111
]
# C3 ~ B6 の範囲
KEYNAMES = ['C', 'D', 'E', 'F', 'G', 'A', 'B']
OCTAVE_RANGE = range(3, 7)
from concurrent import futures
import csv
import os
from pathlib import Path
import typing
import numpy
import scipy
from scipy.io import wavfile
from scipy.fftpack import fft
from constants import *
START_FRAME = 110250 # 2.5s
FFTLEN = 1024
WINDOW = scipy.hamming(FFTLEN)
def _iter_notes() -> typing.Iterator[str]:
for octave in OCTAVE_RANGE:
for key in KEYNAMES:
yield key + str(octave)
NOTES = list(_iter_notes())
def create_ft_csvfile(wavfile_path: str) -> None:
rate, wav_data = wavfile.read(wavfile_path)
assert rate == 44100
# 2.5s から 1024 サンプルを取り出してフーリエ変換
fftinput = wav_data[START_FRAME : START_FRAME + FFTLEN] * WINDOW
fftresult = fft(fftinput)
# 対数パワースペクトルにする
ps = numpy.log10(numpy.absolute(fftresult[:FFTLEN // 2]))
ps = ps / numpy.max(ps)
dataname = Path(wavfile_path).stem
csvpath = os.path.join(OUTPUT_DIR, dataname + '.csv')
with open(csvpath, 'w', encoding='utf_8', newline='\r\n') as f:
for x in ps: f.write('{:.10f}\n'.format(x))
print(dataname)
def create_dataset_csvfile(insts: typing.Sequence[int], filename: str) -> None:
with open(os.path.join(OUTPUT_DIR, filename), 'w', encoding='utf_8', newline='') as f:
writer = csv.writer(f)
writer.writerow(['x:data', 'y:label'])
for inst in insts:
for octave in OCTAVE_RANGE:
for key_index in range(len(KEYNAMES)):
datapath = './{:03d}_{}{}.csv'.format(inst, KEYNAMES[key_index], octave)
writer.writerow([datapath, key_index])
def main() -> None:
with futures.ThreadPoolExecutor() as executor:
# wav ファイルをフーリエ変換した csv ファイルを作成
for entry in os.scandir(OUTPUT_DIR):
if entry.is_file() and entry.name.endswith('.wav'):
executor.submit(create_ft_csvfile, entry.path)
# 学習データ
create_dataset_csvfile(INSTS_FOR_TRAINING, 'training.csv')
# テストデータ
create_dataset_csvfile(INSTS_FOR_EVALUATING, 'evaluating.csv')
if __name__ == '__main__':
main()
from concurrent import futures
import os
import subprocess
import pretty_midi
from constants import *
INSTS = INSTS_FOR_TRAINING.copy()
INSTS.extend(INSTS_FOR_EVALUATING)
os.makedirs(OUTPUT_DIR, exist_ok=True)
def create_wavfile(inst_num: int, octave: int, key: str) -> None:
note_name = key + str(octave)
note_num = pretty_midi.note_name_to_number(note_name)
inst_disp = '{:03d}'.format(inst_num)
path_prefix = os.path.join(OUTPUT_DIR, inst_disp + '_' + note_name)
# MIDI の作成
inst = pretty_midi.Instrument(inst_num)
# timidity の出力の最初にノイズが含まれてしまうので、最初に 1 音入れておく
inst.notes.append(pretty_midi.Note(100, note_num, 0, 1))
inst.notes.append(pretty_midi.Note(100, note_num, 2, 4))
midi_file = pretty_midi.PrettyMIDI()
midi_file.instruments.append(inst)
midi_file.write(path_prefix + '.mid')
# WAV へ変換
subprocess.run(
['timidity', '-OwM', '-o', path_prefix + '.wav', path_prefix + '.mid'],
stdout=subprocess.DEVNULL, check=True)
print(inst_disp + '\t' + note_name)
def main() -> None:
# それなりに時間がかかるので並列化
with futures.ThreadPoolExecutor() as executor:
for inst_num in INSTS:
for octave in OCTAVE_RANGE:
for key in KEYNAMES:
executor.submit(create_wavfile, inst_num, octave, key)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment