Created
November 13, 2017 17:03
-
-
Save azyobuzin/7655c16938338ec9670a878bc7429d2e to your computer and use it in GitHub Desktop.
This file contains hidden or 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
# 生成したファイルの出力先ディレクトリ | |
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) |
This file contains hidden or 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
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() |
This file contains hidden or 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
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