用Python和Librosa分析古典音乐录音:波形、频谱与Chroma特征实战
2026/9/16 21:50:42 网站建设 项目流程

上次在整理一批古典音乐录音文件时,我注意到一类非常典型的命名方式:作曲家_作品名_作品编号_演奏者。比如本文要展开的H.Busser___Petite Suite, Op.12 (Leonard Garrison),一眼看过去像唱片目录,但从技术角度来看,它其实是一个非常适合用来做“音乐信息检索(MIR,Music Information Retrieval)”实验的原始素材。

这篇文章不是音乐鉴赏课,而是从工程视角出发,演示如何用 Python 对一部古典小型组曲的录音做音频特征提取。我们会用到librosamatplotlibnumpy等常用库,把一首长笛与钢琴作品拆成波形、频谱、chroma 特征、节拍和能量曲线,从而理解“计算机是怎么听音乐的”。

如果你正在接触音频处理、音乐科技、数字人文,或者只是好奇如何用代码分析古典音乐录音,这篇教程会比较适合你。全程以可复现的代码为主,不需要太深的乐理背景,跟着步骤走就能跑出结果。

1. 认识 H.Busser《Petite Suite, Op.12》:一个很好的音频分析样本

1.1 从文件名构成开始理解

先看文件名H.Busser___Petite Suite, Op.12 (Leonard Garrison)。这里面的H.Busser指向法国作曲家 H. Busser,通常写作 Henri Busser。他在 19 世纪末到 20 世纪中叶活跃,创作过歌剧、芭蕾、管弦乐和不少室内乐作品。Petite Suite是“小型组曲”的意思,Op.12是作品编号。Leonard Garrison则通常与长笛演奏录音相关。

从数据分析的角度,这个命名本身就有价值:作曲家、曲名、编号、演奏者被压缩在一个字符串里,天然适合做“曲目信息解析”的练习。不过本文不打算写一个解析文件名的正则表达式,而是把重点放在“拿到一段音频之后,能提取出哪些可以用来描述音乐的特征”。

需要说明的是,我并不打算在这里给出关于这部作品具体乐章的考据,因为不同版本、不同编曲下的录音差异可能很大。我们真正关心的是:在给定一部长约几分钟的古典室内乐录音后,如何通过程序自动分析它的声音属性。

1.2 为什么用古典小型组曲做音频分析

第一,它的时长通常不会太长。相比整部交响曲或整幕歌剧,一首小型组曲的长度更适合在本地做快速实验,不会因为音频文件过大而频繁等待。

第二,室内乐编制的声部相对清晰。长笛与钢琴的组合中,长笛的频段集中在 200Hz 到 4kHz 左右,钢琴覆盖范围更宽。分析这类音频时,频谱里往往可以看到比较清晰的乐器能量分布,便于我们理解频谱图与音色之间的关系。

第三,古典作品有相对明确的节拍、句读和段落边界。虽然机器不能像人一样理解“乐思”,但它可以通过能量变化、频谱质心变化、节拍周期性等特征,把一首音乐切分成不同的结构片段。这对做音乐推荐、自动标注、教学辅助系统都有实用价值。

1.3 本文技术方案概览

整体流程可以分为四步:

  1. 准备环境与项目目录;
  2. 加载音频并检查基本信息;
  3. 提取波形、频谱、chroma 特征与节拍;
  4. 保存分析结果,并讨论常见问题。

核心工具是librosa,它是 Python 生态里最常用的音频特征库之一。搭配soundfile处理音频解码,使用matplotlib做可视化。为了让结果方便查看,我们会把特征数据保存成 CSV,把图片保存到独立目录。

2. 环境准备与项目结构

2.1 Python 环境与工具链

开始之前,请确认你的电脑上已经安装了 Python 3。我建议使用 3.9 或更高的版本,新版本对类型注解和第三方库的支持更稳定。如果你没有装 Python,建议先去官网安装,或者在本地使用 Anaconda 管理环境。

这一步不是必须使用 Docker。直接在虚拟环境里安装依赖即可。在 Windows、macOS 和 Linux 上,后面的命令基本通用,只有激活虚拟环境的命令略有差异。

为了不让第三方包污染系统 Python,建议先创建一个独立的虚拟环境:

python -m venv venv

Linux/macOS 激活:

source venv/bin/activate

Windows 激活:

venv\Scripts\activate

2.2 安装依赖库

本文要用到的核心库包括:

  • librosa:音频加载、特征提取;
  • soundfile:音频文件读写;
  • numpy:数值计算;
  • matplotlib:绘图;
  • pandas:整理特征并导出 CSV;
  • scipy:部分高级计算依赖。

安装命令如下:

pip install librosa soundfile numpy matplotlib pandas scipy

如果在 Windows 上遇到音频解码报错,通常还要安装或确认ffmpeg是否存在。ffmpeg是一个开源的音视频处理工具,不是 Python 包。有些系统自带的 libsndfile 不支持 mp3,需要额外用 ffmpeg 转码。

你可以用下面的命令确认是否能正常读取 flac 或 wav 文件:

python -c "import soundfile; print(soundfile.available_formats())"

如果输出里包含WAVFLAC等常见格式,说明音频底层库已经可用。

2.3 项目目录与输入音频准备

建议先建立如下结构,避免到后面文件混乱:

busser_petite_suite_analysis/ ├── data/ │ ├── raw/ │ │ └── busser_petite_suite_op12.flac │ └── processed/ ├── output/ │ ├── figures/ │ └── busser_feature_summary.csv ├── src/ │ ├── 01_load_audio.py │ ├── 02_visualize.py │ └── 03_features.py └── requirements.txt

你可以把任意一段自己合法获取的古典音频命名为busser_petite_suite_op12.flac放入data/raw目录。如果你只有 mp3,可以先转成 wav 或 flac,不建议直接用 mp3 做精细频谱分析,因为压缩编码会损失一部分高频细节。

如果你暂时没有该录音,也可以换成任何测试音频,只需同步修改脚本中的文件路径即可。本文代码演示的重点是流程,不是某一段特定音频。

3. 核心概念拆解:计算机如何“听懂”音乐

3.1 音频在 Python 中的表示方式

音频本质上是空气振动的采样记录。当我们用librosa.load()读取一段音频后,得到的是一个一维数组y和一个采样率sry中每个数值代表某个采样时刻的振幅,sr表示每秒钟采样多少个点。

例如sr=22050,表示每秒有 22050 个采样点。CD 音质通常是 44100Hz,但为了计算提速,音频特征分析中常统一降到 22050Hz。人耳能听到的频率大约在 20Hz 到 20000Hz 之间,22050Hz 的采样率已经足以覆盖音频分析的大部分场景。

采样率不是越高越好。采样率越高,数据量越大,后续 STFT(短时傅里叶变换)和特征矩阵的计算就越慢。对特征提取来说,22050Hz 是一个效率与信息量都比较均衡的默认值。

3.2 频谱与短时傅里叶变换

光看波形很难判断音高和音色,所以需要把时间域信号转换成频率域信息。短时傅里叶变换(STFT)会把音频切成很多小帧,对每一帧做傅里叶变换,从而得到“时间 - 频率 - 能量”的三维分布。

librosa.stft()会返回一个复数矩阵,通常我们用amplitude_to_db()把幅度转换成以分贝为单位的数值,再通过specshow()绘制成频谱图。

频谱图横轴是时间,纵轴是频率,颜色深浅代表能量高低。古典音乐里,钢琴的高频泛音、长笛的气息声,都会在频谱图中留下不同形态的痕迹。这种可视化非常直观,也是入门音频分析时最先该做的步骤之一。

3.3 chroma 特征:更像音乐视角的和声特征

纯频谱只是描述物理声音,和“音高类别”还有距离。比如 C 大调主和弦和 A 小调主和弦在频谱上都很复杂,但人类会把它抽象成不同的音名。为了模拟这种抽象,出现了 chroma 特征。

chroma 特征把八度合并到一起,只保留 12 个半音类别,也就是 C、C#、D、D#、E、F、F#、G、G#、A、A#、B。无论音区是高还是低,只要属于同一个音名类别,就会被归入同一维。

librosa.feature.chroma_cqt()基于 CQT(常 Q 变换)计算 chroma 特征,比传统的 chroma_stft 更适合音乐分析,因为它对音高的分辨率更好。得到的结果是一个12 x N矩阵,其中N是帧数。每一列代表某一帧中 12 个音级上的能量分布。

3.4 频谱质心、RMS 与节拍

频谱质心描述的是声音的“亮度”。一段明亮、乐器穿透力强的音频,频谱质心一般偏高。长笛在高音区时,频谱质心往往明显上升。这个单一数值虽然不能完全代表音色,但可以用于判断段落之间是否存在对比。

RMS(均方根能量)则反映音量大小。结合频谱质心,可以大致观察音乐从哪里开始变强、哪里进入安静段落、哪里可能产生明显的分段边界。

节拍跟踪是另一个常用功能。librosa.beat.beat_track()会尝试估计音频的 BPM,并返回检测到的节拍帧位置。古典音乐常有变速、渐慢、华彩段落,自动节拍检测不会像流行音乐那么稳定,但这个输出仍然可以作为参考,帮助我们大致切分出小节位置。

4. 完整实战案例(上):加载音频并观察波形与频谱

4.1 音频加载与基础信息

新建文件src/01_load_audio.py,写入下面的代码。这段代码会让音频加载到一个普通 numpy 数组里,并输出基础信息。

# 文件路径:src/01_load_audio.py import librosa import numpy as np AUDIO_PATH = "data/raw/busser_petite_suite_op12.flac" y, sr = librosa.load(AUDIO_PATH, sr=22050, mono=True) duration = len(y) / sr print(f"采样率: {sr} Hz") print(f"时长: {duration:.2f} 秒") print(f"样本点数: {y.shape[0]}") print(f"峰值: {np.max(np.abs(y)):.4f}") print(f"整段RMS: {float(np.sqrt(np.mean(y ** 2))):.4f}")

运行:

python src/01_load_audio.py

预期会得到类似这样的输出:

采样率: 22050 Hz 时长: 312.45 秒 样本点数: 6894162 峰值: 0.9845 整段RMS: 0.0612

为什么把采样率设为 22050?因为对大多数音乐特征提取来说,人耳主要敏感频段都能保留下来,计算开销却只有 44100Hz 的四分之一。mono=True会把双声道混合成单声道,避免左右声道内容不一致导致特征计算偏差。

4.2 波形与频谱可视化

接着新建src/02_visualize.py,绘制波形和频谱图。

# 文件路径:src/02_visualize.py import os import librosa import librosa.display import matplotlib.pyplot as plt import numpy as np AUDIO_PATH = "data/raw/busser_petite_suite_op12.flac" OUTPUT_DIR = "output/figures" os.makedirs(OUTPUT_DIR, exist_ok=True) y, sr = librosa.load(AUDIO_PATH, sr=22050, mono=True) hop_length = 512 D = librosa.stft(y, n_fft=2048, hop_length=hop_length) S_db = librosa.amplitude_to_db(np.abs(D), ref=np.max) plt.figure(figsize=(14, 6)) librosa.display.specshow( S_db, sr=sr, hop_length=hop_length, x_axis="time", y_axis="log", ) plt.colorbar(format="%+2.0f dB") plt.title("Busser Petite Suite Op.12 - Spectrogram") plt.tight_layout() plt.savefig(os.path.join(OUTPUT_DIR, "spectrogram.png"), dpi=150) print("图片已保存:", os.path.join(OUTPUT_DIR, "spectrogram.png"))

运行:

python src/02_visualize.py

这会在output/figures下生成一张频谱图。频谱图的纵轴使用对数频率刻度,这样更接近人耳对音高的感知。低频部分位于图像下方,高频泛音位于上方。

观察时你可以重点关注几个信息:

  • 横向深色区块之间的空白,通常对应乐句之间的呼吸或停顿;
  • 颜色明亮的横线代表持续存在的音高,可能是长笛的长音,也可能是钢琴的持续和弦;
  • 高频区域的明暗变化能反映出演奏者音色的统一性。

4.3 进一步观察:波形与频谱组合图

为了把时间信息整合得更完整,可以把波形和频谱画在同一张图上。这个步骤不是必需的,但更适合后续做封面图或汇报材料。

# 文件路径:src/02_visualize_waveform.py import os import librosa import librosa.display import matplotlib.pyplot as plt import numpy as np AUDIO_PATH = "data/raw/busser_petite_suite_op12.flac" OUTPUT_DIR = "output/figures" os.makedirs(OUTPUT_DIR, exist_ok=True) y, sr = librosa.load(AUDIO_PATH, sr=22050, mono=True) hop_length = 512 D = librosa.stft(y, n_fft=2048, hop_length=hop_length) S_db = librosa.amplitude_to_db(np.abs(D), ref=np.max) fig, ax = plt.subplots(2, 1, figsize=(14, 8)) librosa.display.waveshow(y, sr=sr, ax=ax[0]) ax[0].set(title="Waveform", xlabel="Time (s)", ylabel="Amplitude") img = librosa.display.specshow( S_db, sr=sr, hop_length=hop_length, x_axis="time", y_axis="log", ax=ax[1], ) ax[1].set(title="Spectrogram", xlabel="Time (s)", ylabel="Frequency (Hz)") fig.colorbar(img, ax=ax[1], format="%+2.0f dB") plt.tight_layout() plt.savefig(os.path.join(OUTPUT_DIR, "waveform_and_spectrogram.png"), dpi=150) print("组合图已保存:", os.path.join(OUTPUT_DIR, "waveform_and_spectrogram.png"))

5. 完整实战案例(下):提取和声、节拍与分段特征

5.1 提取 chroma 特征与音高能量分布

下方代码计算 chroma_cqt 特征,并输出全曲能量最突出的几个音级。注意,这并不等同于判断调性,只是表示哪些音级在整段时间里出现得更频繁、能量更强。

# 文件路径:src/03_features.py import os import librosa import numpy as np import pandas as pd AUDIO_PATH = "data/raw/busser_petite_suite_op12.flac" OUTPUT_DIR = "output" os.makedirs(OUTPUT_DIR, exist_ok=True) HOP_LENGTH = 512 y, sr = librosa.load(AUDIO_PATH, sr=22050, mono=True) chroma = librosa.feature.chroma_cqt(y=y, sr=sr, hop_length=HOP_LENGTH) mean_chroma = np.mean(chroma, axis=1) note_names = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] top_idx = np.argsort(mean_chroma)[::-1][:3] print("全曲能量较高的音级:") for i in top_idx: print(f" {note_names[i]}: {mean_chroma[i]:.3f}") tempo, beats = librosa.beat.beat_track(y=y, sr=sr, hop_length=HOP_LENGTH) tempo_value = float(np.atleast_1d(tempo)[0]) print(f"\n估计BPM: {tempo_value:.2f}") print(f"检测到节拍数量: {len(beats)}") beat_times = librosa.frames_to_time(beats, sr=sr, hop_length=HOP_LENGTH) print("前8个节拍时间(秒):", [round(t, 2) for t in beat_times[:8]]) cent = librosa.feature.spectral_centroid(y=y, sr=sr, hop_length=HOP_LENGTH)[0] rms = librosa.feature.rms(y=y, hop_length=HOP_LENGTH)[0] times = librosa.frames_to_time( np.arange(len(cent)), sr=sr, hop_length=HOP_LENGTH, ) summary_df = pd.DataFrame({ "time_sec": times, "spectral_centroid_hz": cent, "rms": rms, }) csv_path = os.path.join(OUTPUT_DIR, "busser_feature_summary.csv") summary_df.to_csv(csv_path, index=False) print("\n特征摘要已保存:", csv_path)

运行脚本:

python src/03_features.py

输出大致如下:

全曲能量较高的音级: D: 0.332 A: 0.287 F#: 0.251 估计BPM: 96.32 检测到节拍数量: 484 前8个节拍时间(秒): [0.98, 1.95, 2.91, 3.87, ...] 特征摘要已保存: output/busser_feature_summary.csv

这里解释一下代码逻辑:

  • np.mean(chroma, axis=1)把时间帧方向求平均,得到每个音级的平均能量;
  • argsort()[::-1][:3]拿到能量最高的前三个音级下标;
  • beat_track返回的tempo在不同librosa版本里可能是标量或数组,因此用np.atleast_1d把结果统一成数组,再取第一个元素;
  • frames_to_time将帧号转换为时间坐标,单位是秒,方便后续查看某个节拍落在音频第几秒。

5.2 将 chroma 特征保存为图片

CSV 数据适合继续做统计,但如果你想直观看到和声轮廓随时间的变化,仍建议把 chroma 画成热力图。

# 文件路径:src/04_plot_chroma.py import os import librosa import librosa.display import matplotlib.pyplot as plt AUDIO_PATH = "data/raw/busser_petite_suite_op12.flac" OUTPUT_DIR = "output/figures" os.makedirs(OUTPUT_DIR, exist_ok=True) HOP_LENGTH = 512 y, sr = librosa.load(AUDIO_PATH, sr=22050, mono=True) chroma = librosa.feature.chroma_cqt(y=y, sr=sr, hop_length=HOP_LENGTH) plt.figure(figsize=(14, 6)) librosa.display.specshow( chroma, sr=sr, hop_length=HOP_LENGTH, x_axis="time", y_axis="chroma", ) plt.colorbar() plt.title("Chroma Features - Busser Petite Suite Op.12") plt.tight_layout() plt.savefig(os.path.join(OUTPUT_DIR, "chroma.png"), dpi=150) print("chroma 特征图已保存:", os.path.join(OUTPUT_DIR, "chroma.png"))

运行后查看chroma.png。横向是与音频时长一致的时间轴,纵向是 12 个音级。颜色偏亮的位置表示该时间点对应的音级能量较高。你会发现在旋律变化、和声转换时,色块会发生明显的亮暗切换。对没有乐谱的人来说,这提供了一种“用图像理解音乐走向”的方式。

5.3 简单分段:用 RMS 和谱质心观察结构

很多古典作品虽然乐章内部有复杂变化,但整体音量轮廓通常有规律。利用上一步保存的 CSV,我们可以简单画出 RMS 和频谱质心曲线,从而大致推测安静段落、高潮段落都在什么时间点。

可以用 pandas 做一次快速统计:

# 文件路径:src/05_summary_stats.py import pandas as pd df = pd.read_csv("output/busser_feature_summary.csv") print("时长范围:", df["time_sec"].min(), "~", df["time_sec"].max(), "秒") print("RMS 最高的 5 个时间点:") print(df.sort_values("rms", ascending=False).head()[["time_sec", "rms"]]) print("\n频谱质心最高的 5 个时间点:") print(df.sort_values("spectral_centroid_hz", ascending=False).head()[["time_sec", "spectral_centroid_hz"]])

这段代码并不会直接给出“第几章第几段”,但通过观察排序后的时间点,可以知道哪些位置是全曲音量最大、音色最亮的瞬间。之后再回到频谱图中定位这些时间点,往往能找到段落边界所在。

6. 常见问题与排查思路

在实际运行过程中,比较容易遇到的坑集中在音频解码、依赖版本、路径和绘图这几个方面。下面整理了一份排查表:

问题现象常见原因解决思路
librosa.load无法读取文件缺少解码库或文件本身为加密格式安装 ffmpeg 或先用格式转换工具转成 wav/flac
读取后听到明显杂音或刺耳高频音频为 mp3 且有损压缩,或采样率被二次转换优先使用原始 wav/flac,避免多次重采样
chroma_cqt计算非常慢音频过长或没有设置合理的 hop_length先降低采样率,或按段落截取片段
绘制频谱图时坐标轴单位为帧而不是秒没有把srhop_length传给specshow检查librosa.display.specshow参数是否完整
beat_track返回的 tempo 是数组,导致格式化报错不同librosa版本返回值类型不同使用float(np.atleast_1d(tempo)[0])兼容处理
中文字体在图中显示为方框系统缺少中文字体或 matplotlib 未配置改用英文标题,或设置plt.rcParams['font.sans-serif']
分析整首组曲后内存占用过高chroma 特征矩阵过大把长音频切分成多个短段分别处理
pandas 读取 CSV 后特征曲线锯齿明显hop_length 过小导致帧数太多适当增大 hop_length,例如 1024 或 2048

如果出现No such file or directory,优先检查脚本运行时所在的终端目录是否在项目根目录。建议所有脚本都从busser_petite_suite_analysis根目录执行,而不是直接在src目录下执行。相对路径只有在当前工作目录正确时才能解析。

如果希望进一步定位某个特征异常时间点,可以结合时间坐标回听音频。这个步骤往往比调参数更有效,因为机器特征只能提供线索,最终判断需要你用自己的耳朵去验证。

7. 最佳实践与工程建议

7.1 项目目录与命名规范

音频分析项目的目录最好不要只有一个 Jupyter Notebook 文件。把原始音频、中间特征、可视化图片和核心脚本分开管理,能显著提高后期回溯效率。

一个比较适合小型研究项目结构如下:

audio-analysis/ ├── config/ │ └── analysis.yaml ├── data/ │ ├── raw/ │ ├── processed/ │ └── external/ ├── output/ │ ├── figures/ │ └── tables/ ├── src/ │ ├── features/ │ ├── models/ │ └── visualization/ └── tests/

如果你只是做一次性脚本,至少也应该保持data/rawoutput分离。原始音频是只读资产,不要用程序覆盖它;所有生成结果都应该放在output中,方便随时删除重建。

7.2 保证实验可复现

音频处理库更新比较频繁,librosa的某些函数签名和返回值类型在几个大版本之间可能发生变化。为了让实验可复现,建议在项目根目录生成一份依赖清单:

pip freeze > requirements.txt

甚至在正式记录实验时,把 Python 版本和librosa.__version__也写进结果文件。很多“上次能跑这次不能跑”的问题,都是依赖版本变化引起的。

参数设置也需要统一。sr=22050hop_length=512n_fft=2048在多个脚本里重复出现时,建议放在同一个配置文件中,或至少放在脚本顶部的常量区。如果在 Jupyter 里经常修改参数,也建议最后把固定参数回写到脚本或配置文件中,否则很难回溯真正有效的参数。

7.3 面向版权与数据安全的合规意识

这一点很重要。不要随意下载、传播未经授权的商业录音。本文演示中的《Petite Suite, Op.12》虽然从作曲年代来看可能已经进入公有领域,但具体录音版本通常仍然保留录音版权。宁可自行演奏录制,或者使用获得明确授权的音频,也不要去解析来源不明的文件。

如果需要处理大量音频数据,不要在公共网络环境中随意共享原始文件。特征数据和频谱图通常不涉及原始内容,但也要根据项目方规定决定是否可以公开。如果是在企业内做音乐推荐或音频审核系统,应优先使用公司已授权的版权库,并遵守最小权限原则分配数据访问权限。

7.4 不要过度解读自动分析结果

自动节拍检测对古典音乐并不总是准确。古典作品的弹性速度(rubato)会给节拍跟踪带来很大挑战。当你看到某个 BPM 数值时,不要立刻认为这就是整首作品的速度。BPM 只是一个统计意义上的估计值,更合理的做法是按段落输出速度曲线,而不是给出单一数值。

同样的,chroma 平均能量高不代表音乐就在该调上,只是说明某些音级累计出现的能量更多。要学会区分“声学特征”和“音乐理论结论”之间的差距。技术工具能提供证据,但解释权仍然在人和乐理知识手里。

8. 后续可以继续做什么

8.1 向 MIDI 与 MusicXML 方向扩展

音频特征提取只是单条技术路线。如果你还想在乐谱层面做内容分析,可以引入music21库。它能解析 MusicXML、MIDI 等符号化音乐格式,还可以在 Python 中直接创建音符、和弦、谱表。

例如从乐谱文件入手,你能得到准确的音高序列和时值,不需要再做节拍估计。但对于一些没有乐谱或没有 MIDI 的珍贵历史录音,音频分析依然是唯一可行的方式。

8.2 与乐谱做自动对齐

当你同时拥有音频和 MusicXML 乐谱时,可以尝试做 audio-to-score alignment。这个方向属于音乐信息检索的前沿问题,目标是让计算机知道“乐谱上的某个音符大致对应录音中的第几秒”。听起来很复杂,但可以从单旋律片段做起,逐步引入钢琴或长笛录音。

实现这类系统通常要结合 chroma 特征、动态时间规整(DTW)和隐马尔可夫模型,学习曲线比较陡峭。如果你刚接触这个领域,建议先用本文的方式把音频特征跑通,再思考如何做对齐。

8.3 从单曲扩展为数据集

当你的分析对象从一首《Petite Suite, Op.12》扩展到几十部作品时,就需要考虑批量处理。这时可以写一个简单的 Python 脚本扫描整个目录,逐首提取特征,并把结果汇总到一个大的 CSV 或 Parquet 文件中。后续就能做聚类分析,看哪些作曲家或演奏风格在音色特征上更接近。

分析古典音乐录音是一件很有趣的交叉工作,它同时涉及信号处理、音乐学和软件开发。先把音频加载、频谱可视化、chroma 特征和节拍跟踪这套链路跑通,再把目光放到更复杂的任务上,后面会越走越顺。希望这份实战笔记能让你在处理第一部古典音乐录音时少踩一些坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询