Karplus-Strong算法生成歌曲旋律

### 步骤概述

1. **定义音符频率**:
   - 使用 MIDI 频率表来定义常见的音符频率。
   
2. **定义旋律**:
   - 创建一个详细的旋律序列,模仿歌曲的部分旋律。
   
3. **生成音频数据**:
   - 使用 Karplus-Strong 算法生成每个音符的音频数据。
   - 将这些音符按顺序组合成完整的旋律。
   
4. **播放和保存**:
   - 播放合并后的音频数据。
   - 绘制音频信号图表。
   - 保存音频文件。

通过这些步骤,应该能够成功生成并播放一个简化的旋律,并查看生成的音频信号图表。如果需要更复杂的旋律或调整音符和节奏,请进一步修改 `melody_notes` 和 `durations` 列表。

import argparse
import numpy as np
import matplotlib.pyplot as plt
from scipy.io.wavfile import write
import sounddevice as sd
import time

# MIDI 频率表
MIDI_FREQUENCIES = {
    'C4': 261.63, 'D4': 293.66, 'E4': 329.63, 'F4': 349.23, 'G4': 392.00, 'A4': 440.00, 'B4': 493.88,
    'C5': 523.25, 'D5': 587.33, 'E5': 659.26, 'F5': 698.46, 'G5': 783.99, 'A5': 880.00, 'B5': 987.77,
}

def karplus_strong_synthesis(frequency, duration, decay, sample_rate):
    # 计算波长
    wavelength = int(sample_rate / frequency)
    # 初始化弦的状态
    string_buffer = np.random.randn(wavelength).astype(np.float32)
    string_buffer /= max(string_buffer.max(), abs(string_buffer.min()))
    
    # 生成音频数据
    num_samples = int(duration * sample_rate)
    audio_data = np.zeros(num_samples)
    
    buffer_index = 0
    for i in range(num_samples):
        audio_data[i] = string_buffer[buffer_index]
        next_val = (string_buffer[buffer_index] + string_buffer[(buffer_index + 1) % wavelength]) / 2 * decay
        string_buffer[buffer_index] = next_val
        buffer_index = (buffer_index + 1) % wavelength
    
    return audio_data

def plot_audio(audio_data, sample_rate):
    time_axis = np.linspace(0, len(audio_data) / sample_rate, num=len(audio_data))
    plt.figure(figsize=(10, 4))
    plt.plot(time_axis, audio_data)
    plt.title("Generated Audio Signal")
    plt.xlabel("Time [seconds]")
    plt.ylabel("Amplitude")
    plt.grid(True)
    plt.show()

def generate_melody(melody_notes, durations, decay, sample_rate):
    total_duration = sum(durations)
    audio_data = np.zeros(int(total_duration * sample_rate))
    
    start_time = 0
    for note, duration in zip(melody_notes, durations):
        if note is not None:
            freq = MIDI_FREQUENCIES[note]
            note_audio = karplus_strong_synthesis(freq, duration, decay, sample_rate)
            end_time = start_time + len(note_audio)
            audio_data[start_time:end_time] += note_audio[:end_time-start_time]
        start_time += int(duration * sample_rate)
    
    # 归一化音频数据
    audio_data /= max(audio_data.max(), abs(audio_data.min()))
    
    return audio_data

def main():
    parser = argparse.ArgumentParser(description="""Generating sounds with the Karplus-Strong algorithm.
This script allows you to generate and play a melody similar to the National Anthem using the Karplus-Strong string synthesis method.""")
    
    parser.add_argument('--decay', type=float, default=0.996,
                        help='Decay factor for the string simulation (default: 0.996)')
    parser.add_argument('--sample_rate', type=int, default=44100,
                        help='Sample rate for audio output (default: 44100)')

    args = parser.parse_args()

    # 定义《歌曲》的部分旋律(详细版)
    melody_notes = [
        'D5', 'D5', 'D5', 'F5', 'D5', 'G5', 'F5', 'D5', 'A5', 'G5',
        'D5', 'D5', 'D5', 'F5', 'D5', 'G5', 'F5', 'D5', 'E5', 'D5',
        'C5', 'C5', 'C5', 'E5', 'G5', 'F5', 'D5', 'D5', 'D5', 'F5',
        'D5', 'G5', 'F5', 'D5', 'A5', 'G5', 'D5', 'D5', 'D5', 'F5',
        'D5', 'G5', 'F5', 'D5', 'E5', 'D5', 'C5', 'C5', 'C5', 'E5',
        'G5', 'F5', 'D5', 'D5', 'D5', 'F5', 'D5', 'G5', 'F5', 'D5',
        'A5', 'G5', 'D5', 'D5', 'D5', 'F5', 'D5', 'G5', 'F5', 'D5',
        'E5', 'D5', 'C5', 'C5', 'C5', 'E5', 'G5', 'F5', 'D5', 'D5',
        'D5', 'F5', 'D5', 'G5', 'F5', 'D5', 'A5', 'G5', 'D5', 'D5',
        'D5', 'F5', 'D5', 'G5', 'F5', 'D5', 'E5', 'D5', 'C5', 'C5'
    ]
    
    # 定义每个音符的持续时间(秒)
    durations = [
        0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.5, 1.0,
        0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.5, 1.0,
        0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.5, 1.0,
        0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.5, 1.0,
        0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.5, 1.0,
        0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.5, 1.0,
        0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.5, 1.0,
        0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.5, 1.0,
        0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.5, 1.0,
        0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.5, 1.0
    ]
    
    # 生成旋律
    combined_audio_data = generate_melody(melody_notes, durations, args.decay, args.sample_rate)
    
    # 播放声音
    sd.play(combined_audio_data, samplerate=args.sample_rate)
    sd.wait()  # 等待播放完成
    
    # 绘制声音信号
    plot_audio(combined_audio_data, args.sample_rate)
    
    # 保存声音文件
    timestamp = time.strftime("%Y%m%d-%H%M%S")
    filename = f"national_anthem_{timestamp}.wav"
    write(filename, args.sample_rate, (combined_audio_data * 32767).astype(np.int16))
    print(f"Melody saved to {filename}")

if __name__ == "__main__":
    main()



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值