YouTube音楽音声をMP3に変換し、Pythonを用いてLLMで分析

### 目的

YouTube動画から音声を抽出し、MP3/WAV形式に変換した上で、音響的特徴（ピッチ、スペクトルエントロピー、テンポ、ピークなど）を計算し、それらの特徴量をLLM（大規模言語モデル）に入力して生成的・意味的な解析を行う。Google Colab上で処理・解析を実行する。


---

### 🧾 **スクリプトの構成と処理フロー**



### ✅ ライブラリのインストール / Install required libraries

```python
!pip install -U yt-dlp librosa==0.10.1 numpy==1.24.4 pydub matplotlib scipy soundfile ffmpeg-python
```

* **目的**：すべての必要な音声処理・可視化ライブラリをGoogle Colabなどにインストール
* `yt-dlp`: YouTube動画のダウンロード
* `librosa`: 音声処理（ピッチ・テンポ・スペクトル等）
* `pydub`: MP3 ⇄ WAV 変換
* `matplotlib`: グラフ可視化
* `numpy`, `scipy`: 数値・信号処理
* `soundfile`: WAVの保存処理

---

### ✅ パラメータ定義 / Define parameters

```python
url = 'https://www.youtube.com/watch?v=-tg6WdgiDm8'
mp3_path = 'audio.mp3'
wav_path = 'audio.wav'
sr = 22050
frame_length = 2048
hop_length = 512
peak_threshold = 0.05
```

* 音声処理に必要な基本設定（サンプリングレート、フレーム長など）
* `peak_threshold` は **音量ピーク検出のしきい値**（0.05以上をピークとみなす）

---

### ✅ YouTube音声をダウンロード / Download YouTube audio

```python
subprocess.run([...])
```

* `yt-dlp` を使って **音声ストリームのみをMP3で保存**
* 自動で変換とファイル名指定が可能

---

### ✅ MP3 → WAV変換 / Convert to WAV

```python
AudioSegment.from_file(mp3_path).export(wav_path, format='wav')
```

* `librosa` はWAV形式を推奨するため、MP3をWAVに変換して次処理へ

---

### ✅ 音声読み込み / Load audio

```python
y, _ = librosa.load(wav_path, sr=sr)
```

* WAVファイルを **NumPy配列（y）として読み込み**
* `y`: 音圧（-1.0〜1.0）の1次元信号列

---

### ✅ ピッチ抽出 / Extract pitch

```python
f0, _, _ = librosa.pyin(...)
```

* `pyin` アルゴリズムで **時間変化する基本周波数（F0）を抽出**
* 有声部のみ数値、無声音は `NaN`

---

### ✅ エントロピー計算 / Spectral entropy

```python
S = np.abs(librosa.stft(...))**2
entropy = -np.sum(S * np.log2(S + 1e-10), axis=0)
```

* STFTスペクトルから **情報量（意外性）を時系列で計算**
* 雑音や変化が大きいほどエントロピーも高い傾向

---

### ✅ 音源分離 / Source separation

```python
harmonic, percussive = librosa.effects.hpss(y)
```

* 音声を **旋律成分（harmonic）とリズム成分（percussive）に分解**
* それぞれを `.wav` で保存 → ボーカル抽出やBPM分析に有効

---

### ✅ テンポ推定 / Tempo estimation

```python
tempo, beats = librosa.beat.beat_track(...)
```

* `percussive` 成分からテンポ（BPM）を推定
* `beats` はビート（拍）の時系列インデックス列

---

### ✅ 音量ピーク検出 / Volume peak detection

```python
envelope = np.abs(y)
peak_times = np.where(envelope > peak_threshold)[0] / sr
```

* 波形の**絶対値が閾値を超えた箇所**を「音量ピーク」として抽出
* `peak_times` はその**時間情報（秒）**

---

### ✅ ピークの間引き（可視化用） / Downsampling for plotting

```python
max_peaks_to_plot = 1000
```

* 描画過多防止のため、ピークは最大1000点にサンプリングして表示

---

### ✅ 可視化（統合プロット）/ Unified visualization

* 3つのグラフを1枚の画像にまとめて保存：

| グラフ位置 | 内容                      |
| ----- | ----------------------- |
| 上段    | スペクトログラム（周波数 × 時間 × 音圧） |
| 中段    | 波形＋間引きされた音量ピーク          |
| 下段    | FFT（周波数成分の強度分布）         |

```python
plt.savefig('analysis_with_tempo.png')
```

---

### ✅ 最終出力（統計）/ Summary

```python
print(f"Pitch Mean ...")
```

* 再生時間、ピッチ統計、エントロピー、ピーク数、テンポ（BPM）を表示
* 音楽・音声解析の**基礎指標がすべて数値化**

---




https://www.kikagaku.co.jp/kikagaku-blog/google-colab-howto/

https://colab.research.google.com/#scrollTo=bZIbJxhJy5lG

# Google Colabに貼り付けるPythonコード

使う曲

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4046871/0722b91b-056a-4527-88d9-6b1a9be36917.png)


```python
# Program Name: youtube_audio_analysis_with_tempo.py
# Creation Date: 20250614
# Overview: Download audio, convert to WAV, analyze pitch, entropy, FFT, volume peaks, tempo, and plot results
# Usage: Run in Google Colab or local Python environment

# ------------------------
# ライブラリのインストール / Install required libraries
# ------------------------
!pip install -U yt-dlp librosa==0.10.1 numpy==1.24.4 pydub matplotlib scipy soundfile ffmpeg-python

# ------------------------
# パラメータ定義 / Define parameters
# ------------------------
url = 'https://www.youtube.com/watch?v=-tg6WdgiDm8'
mp3_path = 'audio.mp3'
wav_path = 'audio.wav'
sr = 22050
frame_length = 2048
hop_length = 512
peak_threshold = 0.05

# ------------------------
# YouTube音声ダウンロード / Download YouTube audio
# ------------------------
import subprocess
subprocess.run(['yt-dlp', '-x', '--audio-format', 'mp3', '-o', mp3_path, url], check=True)

# ------------------------
# MP3 → WAV変換 / Convert to WAV
# ------------------------
from pydub import AudioSegment
AudioSegment.from_file(mp3_path).export(wav_path, format='wav')

# ------------------------
# ライブラリ読み込み / Import libraries
# ------------------------
import librosa
import librosa.display
import matplotlib.pyplot as plt
import numpy as np
import soundfile as sf

# ------------------------
# 音声読み込み / Load audio
# ------------------------
y, _ = librosa.load(wav_path, sr=sr)

# ------------------------
# ピッチ抽出 / Extract pitch
# ------------------------
f0, _, _ = librosa.pyin(
    y, fmin=librosa.note_to_hz('C2'), fmax=librosa.note_to_hz('C7'),
    sr=sr, frame_length=frame_length, hop_length=hop_length
)

# ------------------------
# エントロピー計算 / Spectral entropy
# ------------------------
S = np.abs(librosa.stft(y, n_fft=frame_length, hop_length=hop_length)) ** 2
entropy = -np.sum(S * np.log2(S + 1e-10), axis=0)

# ------------------------
# 音源分離 / Source separation
# ------------------------
harmonic, percussive = librosa.effects.hpss(y)
sf.write('harmonic.wav', harmonic, sr)
sf.write('percussive.wav', percussive, sr)

# ------------------------
# テンポ推定 / Tempo estimation
# ------------------------
tempo, beats = librosa.beat.beat_track(y=percussive, sr=sr, hop_length=hop_length)
print(f"⏱ Estimated Tempo: {tempo:.2f} BPM")
print(f"🟰 Beat Count: {len(beats)}")

# ------------------------
# 音量ピーク検出 / Volume peak detection
# ------------------------
envelope = np.abs(y)
peak_times = np.where(envelope > peak_threshold)[0] / sr

# ------------------------
# ピーク描画用に間引き / Downsample peak data for visualization
max_peaks_to_plot = 1000
if len(peak_times) > max_peaks_to_plot:
    idx = np.linspace(0, len(peak_times) - 1, max_peaks_to_plot).astype(int)
    peak_times_vis = peak_times[idx]
else:
    peak_times_vis = peak_times

# ------------------------
# 可視化 / Unified plot
# ------------------------
fig, axs = plt.subplots(3, 1, figsize=(12, 9), dpi=100)

# 1. Spectrogram
img = librosa.display.specshow(librosa.amplitude_to_db(S, ref=np.max),
                               sr=sr, hop_length=hop_length,
                               x_axis='time', y_axis='log', ax=axs[0])
axs[0].set_title('Spectrogram (dB)')
fig.colorbar(img, ax=axs[0], format='%+2.0f dB')

# 2. Waveform + Peaks
time = np.linspace(0, len(y)/sr, len(y))
axs[1].plot(time, y, linewidth=0.4, label='Waveform')
axs[1].vlines(peak_times_vis, -1, 1, color='red', alpha=0.3, linewidth=0.3, label='Peaks')
axs[1].set_title('Waveform + Volume Peaks')
axs[1].legend(loc='upper right')

# 3. FFT
Y = np.abs(np.fft.rfft(y))
f = np.fft.rfftfreq(len(y), 1/sr)
axs[2].plot(f, Y, linewidth=0.5)
axs[2].set_title('FFT Spectrum')
axs[2].set_xlabel('Frequency (Hz)')
axs[2].set_ylabel('Amplitude')

plt.tight_layout()
plt.savefig('analysis_with_tempo.png')
plt.show()

# ------------------------
# 結果出力 / Summary
# ------------------------
print(f"\n🎧 Duration: {len(y)/sr:.2f} sec")
print(f"🎼 Voiced frames: {np.sum(~np.isnan(f0))}")
print(f"📊 Entropy Mean: {np.mean(entropy):.2f}, Std: {np.std(entropy):.2f}")
print(f"🔊 Volume Peaks: {len(peak_times)} over {peak_threshold}")
print(f"📋 Pitch Mean: {np.nanmean(f0):.2f} Hz, Std: {np.nanstd(f0):.2f} Hz")
print(f"⏱ Estimated Tempo: {tempo:.2f} BPM")


```
結果


🔄 Downloading audio from YouTube...
✅ MP3 downloaded: downloaded_audio.mp3
✅ Converted to WAV: converted_audio.wav
🎧 Audio loaded: 2495472 samples, 113.17 seconds
🎼 Voiced frames: 2240
📊 Entropy - Mean: -581706.1875, Std: 406842.2500
🎤 Saved separated audio: harmonic.wav, percussive.wav
🔊 Detected 1810869 volume peaks above threshold (0.05)
📋 Pitch Mean: 121.24 Hz
📋 Pitch Std Dev: 64.24 Hz
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4046871/8eb1c518-55e1-4fa2-be9a-d9bc23e31979.png)



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4046871/3c72d373-c1e0-4ea5-a894-957594849cf1.png)



以下は、あなたの音声ファイル解析結果（スペクトル・波形・音量ピーク・FFT）とログに基づいた**技術的分析レポート**です：

---

## 🎧 **全体情報（音声概要）**

| 項目        | 値              |
| --------- | -------------- |
| 総サンプル数    | 2,495,472 サンプル |
| 長さ（秒）     | 約 113.17 秒     |
| サンプリングレート | 22,050 Hz      |

---

## 🎼 **音高（ピッチ）分析（pyinによるF0抽出）**

* **有声フレーム数**: 2,240（≒全体の約43%が有声音）
* **平均ピッチ**: 121.24 Hz（B2〜C3程度、低音寄り）
* **標準偏差**: 64.24 Hz（±1オクターブ弱）

📝 **考察**:
低めの音域を中心に安定した旋律がある。会話・ボーカル・楽器（ベースなど）の可能性。

---

## 📊 **スペクトルエントロピー分析**

* **平均**: -581,706.19
* **標準偏差**: 406,842.25

📝 **考察**:
このスケール値は**スペクトルパワーの総量が非常に大きい**ことを示唆（正規化されていないため絶対値が大きい）。
音響的には、\*\*連続した成分（ハーモニック系）**と**散漫なノイズ（パーカッシブ系）\*\*が共存。

---

## 🔊 **音量ピーク（Envelope）検出**

* **ピーク数（しきい値0.05超）**: **1,810,869箇所**

📝 **考察**:

* 音のエンベロープが非常に活発 → **高密度な発音／ビート感**
* `vlines()` により視覚的には「赤で塗り潰される」ほど密集 → **プロットには間引きが必要**

---

## 🎤 **音源分離（HPSS）**

* `harmonic.wav`: 主に旋律・ボーカル成分
* `percussive.wav`: 主にビート・リズム・ノイズ成分

📝 **考察**:

* **harmonic.wav** で主旋律抽出 → 後続で **MIDI変換や音階推定** 可能
* **percussive.wav** でビート抽出 → **BPM推定や拍検出** に展開可能

---

## 📈 **FFTスペクトル（周波数分析）**

* 最も強い成分は 0〜1000Hz に集中（楽器・声帯領域）
* 2000Hz以降は急速に減衰

📝 **考察**:

* 音声信号（特に声や低音楽器）の特性に一致
* 高域成分は弱め → **ノイズ成分は少ないが滑舌が柔らかい傾向**

---

## 📷 **可視化画像（analysis\_summary.png）構成**

| プロット | 内容                        |
| ---- | ------------------------- |
| 上段   | スペクトログラム（時間×周波数×音圧）       |
| 中段   | 波形 + 音量ピーク（※ピーク過多により真っ赤に） |
| 下段   | FFT周波数成分分布                |

---