#---------------------------------------------
# 必要ライブラリ / Import libraries
#---------------------------------------------
!pip install mido scipy -q
import mido
import numpy as np
from scipy.io.wavfile import write
from google.colab import files
from IPython.display import Audio
#---------------------------------------------
# ① MIDIファイルをアップロード / Upload MIDI file
#---------------------------------------------
print("🎵 MIDIファイルをアップロードしてください (.mid)")
uploaded = files.upload()
midi_path = list(uploaded.keys())[0]
print("✅ Uploaded:", midi_path)
#---------------------------------------------
# ② パラメータ設定 / Parameter settings
#---------------------------------------------
sr = 44100 # サンプリング周波数
volume = 0.5 # 基本音量
decay_factor = 1.8 # 減衰係数(小さいほど長い余韻)
attack_time = 0.02 # アタックの立ち上がり時間 [s]
output_wav = "/content/high_quality_musicbox.wav"
#---------------------------------------------
# ③ 改良オルゴール音合成関数 / Enhanced music-box tone
#---------------------------------------------
def smooth_envelope(t, decay_factor=1.8, attack_time=0.02):
"""滑らかな立ち上がり+指数減衰エンベロープ"""
attack_env = np.clip(t / attack_time, 0, 1)
decay_env = np.exp(-decay_factor * t)
return attack_env * decay_env
def rich_musicbox_tone(freq, duration, velocity=64):
"""
高音質オルゴール風波形を生成
- 正弦波を中心に柔らかい倍音構成
- 指数減衰+滑らかな立ち上がり
- velocityで音量スケーリング
"""
t = np.linspace(0, duration, int(sr * duration), endpoint=False)
env = smooth_envelope(t, decay_factor, attack_time)
amp = volume * (velocity / 127.0)
# 基本波と倍音を柔らかく混合(オルゴールの金属音を模倣)
wave = (
1.0 * np.sin(2 * np.pi * freq * t)
+ 0.3 * np.sin(2 * np.pi * 2 * freq * t + np.pi / 6)
+ 0.15 * np.sin(2 * np.pi * 3 * freq * t + np.pi / 3)
+ 0.05 * np.sin(2 * np.pi * 4 * freq * t)
)
# 軽い非線形補正でアナログ感を加える
wave = np.tanh(wave * 1.2)
# エンベロープを適用
return amp * wave * env
#---------------------------------------------
# ④ MIDI読み込み / Load MIDI
#---------------------------------------------
mid = mido.MidiFile(midi_path)
print(f"Loaded: {midi_path} | Length: {round(mid.length,2)} sec")
#---------------------------------------------
# ⑤ 音声合成 / Generate audio
#---------------------------------------------
audio = np.zeros(int(mid.length * sr) + sr, dtype=np.float32)
current_time = 0.0
for msg in mid:
current_time += msg.time
if msg.type == 'note_on' and msg.velocity > 0:
freq = 440.0 * (2.0 ** ((msg.note - 69) / 12.0))
start = int(current_time * sr)
dur = 0.7 # 音の持続時間
end = start + int(dur * sr)
if end <= len(audio):
audio[start:end] += rich_musicbox_tone(freq, dur, msg.velocity)
#---------------------------------------------
# ⑥ ポスト処理 / Post-processing
#---------------------------------------------
# 軽いローパスで高域をなめらかに
audio = np.convolve(audio, np.hanning(64)/np.sum(np.hanning(64)), mode='same')
# 正規化と保存
audio = np.clip(audio / np.max(np.abs(audio)), -1.0, 1.0)
write(output_wav, sr, (audio * 32767).astype(np.int16))
print("✅ 高音質電子オルゴール音を保存しました:", output_wav)
#---------------------------------------------
# ⑦ 再生 / Playback
#---------------------------------------------
Audio(output_wav)