用Python做有趣的AI项目 6:AI音乐生成器(LSTM Melody Generator)

🎵 项目名称: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

cpp 复制代码
python

import 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: 提取音符

cpp 复制代码
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.notes

        for 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: 准备训练序列

cpp 复制代码
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: 创建模型

cpp 复制代码
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: 生成音符

cpp 复制代码
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 文件

cpp 复制代码
def create_midi(prediction_output, filename="output.mid"):
    offset = 0
    output_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 = offset
            output_notes.append(chord_notes)
        else:
            new_note = note.Note(pattern)
            new_note.offset = offset
            output_notes.append(new_note)
        offset += 0.5

    midi_stream = stream.Stream(output_notes)
    midi_stream.write('midi', fp=filename)

▶️ 使用说明

下载一些 MIDI 文件放入 midi_songs/ 文件夹

创建 data/ 文件夹用于保存训练数据

执行以下代码:

cpp 复制代码
python

notes = 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)

生成音乐

cpp 复制代码
prediction = generate_notes(model, network_input, pitchnames, note_to_int, num_notes=200)
create_midi(prediction)
相关推荐
像风一样_4 分钟前
机器学习-入门-决策树(1)
人工智能·决策树·机器学习
飞火流星020275 分钟前
Weka通过10天的内存指标数据计算内存指标动态阈值
人工智能·机器学习·数据挖掘·weka·计算指标动态阈值·使用统计方法计算动态阈值
xiaoniu66714 分钟前
毕业设计-基于预训练语言模型与深度神经网络的Web入侵检测系统
人工智能·语言模型·dnn
豆芽81921 分钟前
感受野(Receptive Field)
人工智能·python·深度学习·yolo·计算机视觉
赛卡27 分钟前
IPOF方法学应用案例:动态电压频率调整(DVFS)在AIoT芯片中的应用
开发语言·人工智能·python·硬件工程·软件工程·系统工程·ipof
蒙双眼看世界38 分钟前
AI应用实战:Excel表的操作工具
人工智能
机器学习之心43 分钟前
飞蛾扑火算法优化+Transformer四模型回归打包(内含MFO-Transformer-LSTM及单独模型)
算法·回归·lstm·transformer·飞蛾扑火算法优化
决战软件之巅43 分钟前
Python3 基础语法
python
jndingxin1 小时前
OpenCV 图形API(64)图像结构分析和形状描述符------在图像中查找轮廓函数findContours()
人工智能·opencv
唯创电子1 小时前
芯资讯|WTR096-16S录音语音芯片:重塑智能家居的情感连接与安全守护
人工智能·智能家居·语音识别·语音芯片·录音芯片