🎵 項目名稱:AI音樂生成器(LSTM Melody Generator)
🧠 項目簡介
這個項目的目標是:用 AI 來自動生成簡單的旋律(MIDI格式),類似于基礎的鋼琴曲、背景音樂片段。
我們使用一個 LSTM(長短期記憶網絡)模型,它能學習并預測音符的序列結構,實現自動作曲。
🔧 技術棧
技術 用途
Python 編程語言
TensorFlow / Keras 構建神經網絡
music21 分析、處理和播放 MIDI 音樂
Streamlit 構建圖形界面(可視化生成結果)
🎹 音樂格式說明
我們使用的是 MIDI 格式(.mid 文件),它記錄的是音符序列而不是錄音,適合用于訓練模型和自動生成旋律。
? 項目流程
📥 Step 1:數據準備(音樂序列)
讀取一個或多個 .mid 文件,并用 music21 將其轉為音符/和弦的序列,然后用于訓練。
?? Step 2:模型訓練(LSTM)
用 LSTM 模型來學習音符之間的關系,通過預測下一個音符生成完整旋律。
🧪 Step 3:生成旋律(Predict)
給一個起始片段,自動預測接下來的 50~200 個音符。
💾 Step 4:保存為 MIDI 文件
把生成的音符序列轉換成音樂文件(.mid)并保存或播放。
📄 項目代碼(打包為 Python 文件)
保存為:music_generator.py
pythonimport numpy as np
from music21 import converter, instrument, note, chord, stream
from keras.models import Sequential
from keras.layers import LSTM, Dense, Dropout
import glob
import pickle
Step 1: 提取音符
def get_notes():notes = []for file in glob.glob("midi_songs/*.mid"):midi = converter.parse(file)parts = instrument.partitionByInstrument(midi)notes_to_parse = parts.parts[0].recurse() if parts else midi.flat.notesfor element in notes_to_parse:if isinstance(element, note.Note):notes.append(str(element.pitch))elif isinstance(element, chord.Chord):notes.append('.'.join(str(n) for n in element.normalOrder))with open("data/notes.pkl", "wb") as f:pickle.dump(notes, f)return notes
Step 2: 準備訓練序列
def prepare_sequences(notes, sequence_length=100):pitchnames = sorted(set(notes))note_to_int = {note: i for i, note in enumerate(pitchnames)}network_input = []network_output = []for i in range(len(notes) - sequence_length):seq_in = notes[i:i + sequence_length]seq_out = notes[i + sequence_length]network_input.append([note_to_int[n] for n in seq_in])network_output.append(note_to_int[seq_out])n_patterns = len(network_input)network_input = np.reshape(network_input, (n_patterns, sequence_length, 1)) / float(len(pitchnames))network_output = np.eye(len(pitchnames))[network_output]return network_input, network_output, note_to_int, pitchnames
Step 3: 創建模型
def create_network(network_input, output_dim):model = Sequential()model.add(LSTM(256, input_shape=(network_input.shape[1], network_input.shape[2]), return_sequences=True))model.add(Dropout(0.3))model.add(LSTM(256))model.add(Dense(128, activation='relu'))model.add(Dropout(0.3))model.add(Dense(output_dim, activation='softmax'))model.compile(loss='categorical_crossentropy', optimizer='adam')return model
Step 4: 生成音符
def generate_notes(model, network_input, pitchnames, note_to_int, num_notes=100):int_to_note = {num: note for note, num in note_to_int.items()}start = np.random.randint(0, len(network_input) - 1)pattern = network_input[start]prediction_output = []for note_index in range(num_notes):prediction_input = np.reshape(pattern, (1, len(pattern), 1))prediction = model.predict(prediction_input, verbose=0)[0]index = np.argmax(prediction)result = int_to_note[index]prediction_output.append(result)pattern = np.append(pattern, [[index / float(len(pitchnames))]], axis=0)pattern = pattern[1:]return prediction_output
Step 5: 將音符輸出為 MIDI 文件
def create_midi(prediction_output, filename="output.mid"):offset = 0output_notes = []for pattern in prediction_output:if "." in pattern or pattern.isdigit():notes_in_chord = pattern.split(".")notes = [note.Note(int(n)) for n in notes_in_chord]chord_notes = chord.Chord(notes)chord_notes.offset = offsetoutput_notes.append(chord_notes)else:new_note = note.Note(pattern)new_note.offset = offsetoutput_notes.append(new_note)offset += 0.5midi_stream = stream.Stream(output_notes)midi_stream.write('midi', fp=filename)
?? 使用說明
下載一些 MIDI 文件放入 midi_songs/ 文件夾
創建 data/ 文件夾用于保存訓練數據
執行以下代碼:
pythonnotes = get_notes()
network_input, network_output, note_to_int, pitchnames = prepare_sequences(notes)
model = create_network(network_input, output_dim=len(pitchnames))
model.fit(network_input, network_output, epochs=20, batch_size=64)
生成音樂
prediction = generate_notes(model, network_input, pitchnames, note_to_int, num_notes=200)
create_midi(prediction)