ハイライト
Apple は Music Understanding フレームワークを発表しました。App は機械学習や信号処理の知識なしに、デバイス上でオフラインに、調性、リズム、構造、速度感、楽器活動、ラウドネスという 6 つの軸から音声を解析できます。すべての結果データは JSON としてエンコードして書き出せます。
主要内容
以前の音楽解析はどれほど大変だったか
動画編集 App では、「画面切り替えを音楽のビートに合わせる」というよくある要件があります。以前これを実装するには、開発者が自分で FFT、つまり高速フーリエ変換アルゴリズムを書いて音声特徴を抽出するか、librosa などの Python ライブラリを統合して音声をサーバーへ送り解析する必要がありました。どちらにも弱点があります。前者には深い信号処理の知識が必要で、後者はネットワークに依存し、プライバシーリスクもあります。
Final Cut Pro チームも同じ問題に直面していました。彼らは macOS と iPad 版 FCP に Beat Detection と Montage 機能を実装しましたが、その能力は FCP 内部に閉じており、サードパーティ開発者は再利用できませんでした。
Apple が作ったもの
WWDC26 で発表された Music Understanding フレームワークは、FCP チームが蓄積した音楽解析能力をすべての開発者に開放します。フレームワーク内部に信号処理とモデル推論が内包されており、開発者は数行のコードだけで呼び出せます。
(01:16)フレームワークは 6 つの解析軸を提供します。
- Key(調性):曲の主音と調式。例:D flat major
- Rhythm(リズム):各ビートと小節の正確なタイムスタンプ、および全体 BPM
- Structure(構造):曲の段落階層。コーラスやヴァースなどの sections、segments、phrases
- Pace(速度感):音楽の各段落におけるエネルギー密度。値が高いほど速く感じる
- Instrument Activity(楽器活動):各楽器がいつ現れ、どの程度強いか
- Loudness(ラウドネス):LUFS 標準に基づく全体ラウドネス、瞬時ラウドネス、ピーク値
(00:34)すべての解析はデバイス上で完了し、音声はローカルから出ません。つまりオフライン利用、ネットワーク遅延ゼロ、プライバシー保護が得られます。
この新機能がどう問題を解くか
ビート同期の動画編集機能を例にします。以前は数百行の DSP コードが必要でしたが、今はこれだけです。
- 音声ファイルを
MusicUnderstandingSessionに渡す analyze()を呼び、リズムと構造データを取得する- 返された
CMTime配列でAVPlayerのseek(to:)を直接駆動する
(15:28)FCP の Montage 機能もこのように動きます。まず曲の段落を識別し、各段落の pace 値からクリップ長を計算し、動画のリズムを音楽のエネルギーに合わせます。高エネルギー段落では短く速いカット、低エネルギー段落では長くゆったりしたショットを使います。
詳細
Session を初期化する
(04:47)フレームワークは MusicUnderstandingSession を通じて音声とやり取りします。最も簡単な初期化方法は AVAsset から作ることです。
import MusicUnderstanding
import AVFoundation
.fileImporter(isPresented: $isPresented, allowedContentTypes: [.audio]) { result in
switch result {
case .success(let url):
let asset = AVURLAsset(
url: url,
options: [AVURLAssetPreferPreciseDurationAndTimingKey: true]
)
let session = try await MusicUnderstandingSession(asset: asset)
let results = try await session.analyze()
case .failure(let error):
print("読み込みに失敗しました: \(error)")
}
}
要点:
AVURLAssetPreferPreciseDurationAndTimingKeyは必ずtrueに設定します。そうしないとビート合わせに時間ずれが出る可能性がありますanalyze()はデフォルトで 6 つの軸すべてを解析するため、計算量が大きくなります- 全体の流れは
async/awaitを使うため、バックグラウンドタスクで実行することをおすすめします
必要な解析だけを行い性能を上げる
(03:45)一部の結果だけが必要な場合は、analyze(for:) を使って不要な計算を避けます。
let results = try await session.analyze(for: [.rhythm, .pace])
if let rhythm = results.rhythm {
let bpm = rhythm.beatsPerMinute ?? 120.0
let beatTimes = rhythm.beats
print("BPM: \(bpm), ビート数: \(beatTimes.count)")
}
要点:
analyze(for:)は要求した解析型だけを返し、それ以外のフィールドはnilになりますbeatsPerMinuteはFloat?です。純粋な朗読のように明確なリズムがない音声ではnilを返します- optional な結果は常に安全に unwrap することをおすすめします
時間データ型
(05:53)フレームワークは 2 つのジェネリック構造体で時間とデータを結びつけます。
public struct TimedValue<Value>: Codable, Equatable, Sendable
where Value: Codable & Equatable & Sendable {
public let time: CMTime
public let value: Value
}
public struct RangedValue<Value>: Codable, Equatable, Sendable
where Value: Codable & Equatable & Sendable {
public let range: CMTimeRange
public let value: Value
}
要点:
TimedValueは値を特定の時点に結びつけますRangedValueは値を特定の時間範囲に結びつけます- どちらも
CodableとSendableに準拠し、直接シリアライズしたりタスク間で渡したりできます DoubleではなくCMTimeを使うことで浮動小数点精度問題を避け、AVFoundationと自然に連携できます
調性解析
(06:27)調性解析は曲の主音と調式を返します。
public struct KeyResult: Codable, Sendable {
public let ranges: [MusicUnderstandingSession.RangedValue<KeySignature>]
}
public struct KeySignature: Codable, Hashable, Sendable {
public let tonic: Tonic
public let mode: Mode
}
@frozen public enum Tonic: String, Codable, Hashable, Sendable {
case aFlat, aSharp, a, bFlat, b, c, cSharp,
d, dFlat, dSharp, eFlat, e, f, fSharp,
g, gFlat, gSharp
}
public enum Mode: String, Codable, Hashable, Sendable {
case major, minor
}
要点:
KeyResult.rangesは配列です。曲は段落によって転調することがあるためです- 各
RangedValue<KeySignature>は、その調性が有効な時間範囲を含みます Tonicはシャープとフラットを含む 17 種類の音名表記をカバーします
リズム解析
(07:16)リズム解析は各ビートと小節の正確なタイムスタンプを返します。
public struct RhythmResult: Codable, Sendable {
public let beats: [CMTime]
public let bars: [CMTime]
public let beatsPerMinute: Float?
}
要点:
beats配列には曲中の各ビートのCMTimeが含まれますbars配列には各小節の開始時刻が含まれますbeatsPerMinuteは全体平均 BPM で、音声に明確なリズムがない場合はnilです
構造解析
(08:42)構造解析は曲を 3 つの階層に分解します。
public struct StructureResult: Codable, Sendable {
public let sections: [CMTimeRange]
public let segments: [CMTimeRange]
public let phrases: [CMTimeRange]
}
要点:
sectionsはコーラス、ヴァース、イントロ、ブリッジなどの大きな段落に対応しますsegmentsは sections の下位分割ですphrasesは最も細かい粒度で、音楽における「句」に相当します- 階層関係は section > segment > phrase です
速度感解析
(09:26)Pace は音楽が聴き手に与える速度感を表します。
public struct PaceResult: Codable, Sendable {
public let ranges: [MusicUnderstandingSession.RangedValue<Double>]
}
要点:
- Pace は BPM とは異なり、「エネルギー密度」という主観的な感覚を測ります
- 値が高いほど、音楽は速く、活力があるように感じられます
- 返り値は時間範囲付きの配列であり、段落ごとに異なる pace 値を持つことがあります
(14:47)pace で動画クリップ長を計算します。
let timePerClip = 60 / paceValue
楽器活動解析
(10:13)楽器活動は 2 種類の粒度を提供します。
public struct InstrumentActivityResult: Codable, Sendable {
public let ranges: [Instrument: [CMTimeRange]]
public let activity: [Instrument: [MusicUnderstandingSession.TimedValue<Float>]]
}
要点:
rangesは特定の楽器がどの時間帯に現れるかを示します。Boolean 的な存在判定ですactivityは各時点におけるその楽器の強度を 0 から 1 の浮動小数点値で示しますactivityデータはオーディオ可視化アニメーションの駆動に適しています
ラウドネス解析
(11:45)ラウドネスは LUFS(Loudness Units Full Scale)標準で計算されます。
public struct LoudnessResult: Codable, Sendable {
public let integrated: MusicUnderstandingSession.TimedValue<Float>
public let momentary: [MusicUnderstandingSession.TimedValue<Float>]
public let shortTerm: [MusicUnderstandingSession.TimedValue<Float>]
public let peak: MusicUnderstandingSession.TimedValue<Float>
}
要点:
integrated:曲全体の平均ラウドネス。単一の値momentary:100ms ごとのラウドネス。解析窓は 400ms で、突発的な音量変化の検出に向いていますshortTerm:100ms ごとのラウドネス。解析窓は 3 秒で、より滑らかな曲線になりますpeak:曲全体の絶対ピーク音量。単位はデシベルです
ストリーミングラウドネス API
(12:48)フレームワークは AsyncSequence スタイルのストリーミングラウドネスデータを提供し、リアルタイム場面に適しています。
let audioProvider = AudioProvider()
let session = MusicUnderstandingSession(audioProvider: audioProvider)
await withThrowingTaskGroup(of: Void.self) { group in
group.addTask {
for try await result in await session.loudnessResults {
updateAudioLevel(result.momentary.value)
}
}
group.addTask {
try await session.analyze(for: [.loudness])
}
}
要点:
loudnessResultsはAsyncSequenceで、100ms ごとに結果を push します- カスタム
AudioProviderと組み合わせて使う必要があります - 2 つのタスクが並行して動きます。1 つは結果を消費し、もう 1 つは解析を駆動します
カスタム音声プロバイダ
(13:19)AVAsset 以外に、リアルタイム音声ストリームで Session を初期化することもできます。
struct AudioProvider: AsyncSequence, AsyncIteratorProtocol {
func makeAsyncIterator() -> Self {
return self
}
mutating func next() async -> AVReadOnlyAudioPCMBuffer? {
// 次の音声バッファを返す。終了を示すには nil を渡す
}
}
要点:
AudioProviderはAsyncSequenceとAsyncIteratorProtocolに準拠する必要がありますnext()は毎回 1 つのAVReadOnlyAudioPCMBufferを返します- 解析終了時には
nilを返し、フレームワークに停止を通知する必要があります - マイクのリアルタイム入力やネットワーク音声ストリームなどに適しています
解析結果を書き出す
(13:55)すべての結果は Codable に準拠しており、JSON として直接エンコードできます。
let session = try await MusicUnderstandingSession(asset: asset)
let results = try await session.analyze()
let encoder = JSONEncoder()
let data = try encoder.encode(results)
要点:
- 手動シリアライズは不要で、1 行ですべてのデータを書き出せます
- 解析結果を事前計算して App に同梱したり、サーバーへアップロードして共有したりする用途に適しています
- JSON 内のタイムスタンプは
CMTimeのエンコード形式を使います
主要な学び
1. 「自動ビート同期」動画編集 App を作る
ユーザーが音楽を読み込むと、App がビートと構造を自動解析し、beat と bar の位置にトランジションマーカーを挿入します。開発者は RhythmResult.beats 配列を読み、各 CMTime をタイムライン上のマーカーに変換するだけです。入口 API は MusicUnderstandingSession.analyze(for: [.rhythm, .structure]) です。
2. 「エネルギー可視化」音楽プレイヤーを作る
曲の再生中に、PaceResult と InstrumentActivityResult.activity を使って粒子アニメーションや波形を駆動します。高 pace 段落では粒子の動きを速くし、ドラムが現れたときに閃光効果を発火します。TimedValue<Float> のタイムスタンプを AVPlayer の現在時刻と直接比較すれば同期できます。
3. 「スマート DJ」App を作る
KeyResult でユーザーの曲ライブラリの調性を分析し、調性的に相性のよい曲を自動推薦してミックスを作ります。長調から長調、短調から短調、あるいは五度圏で隣接する調性なら自然につなげられます。入口はライブラリを走査して analyze(for: [.key]) を呼び、結果をローカルデータベースに保存することです。
4. 「リズムゲーム」を作る
事前に analyze() で曲のビートデータを計算し、ゲームリソースに同梱します。ゲーム実行時には beats 配列を読み、該当時刻にタップターゲットを生成します。実行時リアルタイム解析より省性能で、ゲーム中に解析失敗するリスクも避けられます。
5. 「ラウドネス均一化」ツールを作る
LoudnessResult.integrated でユーザーの曲ライブラリを一括解析し、各曲の再生音量を自動調整して、異なるソースの音楽が同じくらいの大きさに聞こえるようにします。Podcast App や音楽プレイヤーで有用で、「曲が変わった瞬間に驚く」問題を解決します。
関連 Session
- Meet MusicKit for Swift — MusicKit は音楽再生とライブラリ管理機能を提供し、Music Understanding の解析能力と組み合わせることで完全な音楽 App を構築できる
- Create 3D models for your spatial app — 3D モデルで空間オーディオ可視化シーンを構築し、Music Understanding の解析結果を 3D 空間へマッピングする
- What’s new in SwiftUI — SwiftUI の Canvas とアニメーション API は、Music Understanding Lab 風のリアルタイム可視化インターフェイスを描くのに適している
- Explore machine learning on Apple platforms — Apple デバイス上 ML の基盤メカニズムを学び、Music Understanding フレームワークの推論最適化戦略を理解する
コメント
GitHub Issues · utterances