如何将30秒的AI音乐生成扩展到几分钟

社区文章 发布于2024年12月13日

想象一下,从一个简单的30秒音频片段创作一首交响乐,或者将一段简短的旋律变成一整首歌曲。有了AI驱动的工具,如 Facebook的MusicGen,这现在成为了可能。在本教程中,您将学习如何构建一个API,该API可以接收一个简短的音频文件,将其扩展为几分钟的连贯音乐,并对其进行专业级质量处理。


您将学到什么

  • 上传和处理音频:处理MP3、WAV等多种格式。
  • AI驱动的音乐扩展:使用 Facebook的MusicGen 无缝扩展音轨。
  • 确保连贯性:对初始和扩展音频使用相同的描述(提示)以获得更好的一致性。
  • 音频质量的后期处理:通过标准化和滤镜清理生成的音频。
  • 部署选项:本地部署或在 RunPod 上部署以实现可扩展的GPU托管。

为什么在扩展时使用相同的提示?

提示(或描述)在生成一致音乐方面起着关键作用。在扩展音轨时,使用相同的提示可确保:

  1. 音乐连贯性:扩展部分与原始音频的主题、情绪和风格相匹配。
  2. 自然过渡:相似的音景使得重叠和融合更加流畅。
  3. 创意完整性:避免原始部分和生成部分之间出现刺耳的音调或风格变化。

完整的代码实现

以下是您的 音乐生成API 的完整实现

from fastapi import FastAPI, HTTPException, BackgroundTasks, UploadFile, File, Form
from pydantic import BaseModel, Field
import uvicorn
import torch
from audiocraft.models import MusicGen
from audiocraft.data.audio import audio_write
from tempfile import NamedTemporaryFile, gettempdir
import logging
import os
import soundfile as sf
from pydub import AudioSegment
from pydub.effects import normalize, high_pass_filter, low_pass_filter
import threading

# Initialize logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = FastAPI()

# Lock for thread-safe model access
model_lock = threading.Lock()

# Function to initialize and reset the model
def get_musicgen_model():
    logger.info("Loading MusicGen model...")
    model = MusicGen.get_pretrained("facebook/musicgen-large")
    model.set_generation_params(use_sampling=True, top_k=250)
    return model

# Global model instance
model = get_musicgen_model()

@app.post("/extend-audio/")
async def extend_audio(
    total_duration: int = Form(..., gt=0, le=300, description="Desired total duration of the audio in seconds (1-300)."),
    description: str = Form(...),
    segment_duration: int = Form(30, description="Duration of generated segments in seconds (default: 30)."),
    overlap: int = Form(7, description="Overlap duration in seconds for smoother transitions (default: 7)."),
    file: UploadFile = File(...),
):
    try:
        logger.info(f"Extending audio: {total_duration}s with description '{description}'")

        # Save the uploaded file temporarily
        with NamedTemporaryFile(delete=False) as temp_file:
            temp_file.write(await file.read())
            input_audio_path = temp_file.name

        # Read and convert audio if necessary
        try:
            input_audio, sample_rate = sf.read(input_audio_path)
            input_audio = torch.tensor(input_audio).unsqueeze(0).float()
        except RuntimeError:
            logger.info("Converting unsupported format to WAV...")
            audio = AudioSegment.from_file(input_audio_path)
            wav_temp_path = f"{gettempdir()}/converted_audio.wav"
            audio.export(wav_temp_path, format="wav")
            input_audio, sample_rate = sf.read(wav_temp_path)
            input_audio = torch.tensor(input_audio).unsqueeze(0).float()
            os.remove(wav_temp_path)
        finally:
            os.remove(input_audio_path)

        # Generate audio in a thread-safe manner
        with model_lock:
            segment = model.generate_continuation(
                input_audio, sample_rate, descriptions=[description], progress=True
            )

        # Generate additional segments
        while total_duration > 0:
            last_sec = segment[:, :, -overlap * sample_rate:]
            with model_lock:
                next_segment = model.generate_continuation(
                    last_sec, sample_rate, descriptions=[description], progress=True
                )
            segment = torch.cat([segment[:, :, :-overlap * sample_rate], next_segment], dim=2)
            total_duration -= (segment_duration - overlap)

        # Save and process final audio
        final_audio = segment.detach().cpu().float()[0]
        output_path = f"extended_audio_{torch.randint(0, 100000, (1,)).item()}.wav"
        audio_write(output_path, final_audio, sample_rate)

        return {"file_path": output_path}

    except Exception as e:
        logger.error(f"Error: {e}")
        raise HTTPException(status_code=500, detail="Audio generation failed.")

API的主要功能

  1. 多格式上传
    通过在必要时转换为WAV来处理MP3、FLAC、WAV等多种格式。

  2. 无缝扩展
    生成具有重叠过渡的额外片段以保持连贯性。

  3. 可定制输出
    设置片段时长、重叠和总长度。

  4. 后期处理
    通过标准化和频率过滤提升音频质量。

  5. 线程安全模型访问
    管理并发请求,避免冲突。


如何在本地使用API

  1. 安装依赖

    pip install fastapi uvicorn torch soundfile pydub audiocraft
    
  2. 运行服务器

    python main.py
    
  3. 发送测试请求
    使用 curl 发送POST请求

    curl -X POST "http://127.0.0.1:8000/extend-audio/" \
    -F "total_duration=120" \
    -F "description='Calm piano with ambient strings'" \
    -F "file=@path_to_audio.wav"
    

在RunPod上部署

为什么选择RunPod?

RunPod 是一个优秀的 GPU 驱动部署平台。它为 MusicGen 等 AI 模型提供价格实惠、可扩展的 GPU 托管服务。

部署步骤

  1. 创建GPU实例
    访问 RunPod 并设置 GPU 环境。

  2. 准备一个 Dockerfile

    FROM python:3.9-slim
    
    WORKDIR /app
    
    COPY requirements.txt requirements.txt
    RUN pip install --no-cache-dir -r requirements.txt
    
    COPY . .
    
    CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
    
  3. 构建并运行 Docker 镜像

    docker build -t musicgen-api .
    docker run -p 8000:8000 musicgen-api
    
  4. 访问 API
    使用 RunPod 提供的公共 IP 与您的 API 交互。


扩展音频的最佳实践

  1. 重复使用相同的提示
    提示的一致性确保生成的音频与原始音频无缝对齐。

  2. 调整重叠以实现平滑过渡
    尝试调整重叠值(默认为7秒),以最大程度地减少过渡期间的伪影。

  3. 预处理输入音频
    确保您的输入音频干净且标准化,以获得最佳输出质量。

  4. 监控模型参数
    微调 MusicGen 的参数,如 top_k,以平衡创造性和连贯性。


最终思考

这个 API 赋予了创作者、音乐家和开发者将他们的短音频轨道扩展成优美、连贯的乐曲的能力。无论您是制作完整的原声带还是探索人工智能的创作潜力,本教程都为您提供了入门工具。

如需了解更多 AI 创新,请查看我在 Hugging Face 上的项目。欢迎在 LinkedIn 上与我联系并分享您的作品!🎶✨

社区

注册登录 以评论