Wizard Notes

Python, JavaScript を使った音楽信号分析の技術録、作曲活動に関する雑記

Pythonの心理音響評価モジュール"MoSQITo"でオーディオデータからラウドネスを算出

前回の記事で紹介したPythonの心理音響評価モジュールMoSQIToラウドネスを算出してみました。

基本的に以下のドキュメント・ソースコードを参考にしています。

MoSQITo/tuto3_Loudness-zwicker-time-varying.ipynb at master · Eomys/MoSQITo · GitHub

ソースコード

import numpy as np
import matplotlib.pyplot as plt
from mosqito.functions.shared.load import load
from mosqito.functions.loudness_zwicker.comp_loudness import comp_loudness


filepath = "Test signal 24 (woodpecker).wav"
is_stationary = False # 非定常信号ならばFalse, 定常信号ならば True
calib = 2 * 2**0.5  # 信号の振幅値補正用係数
field_type = 'free' # 自由音場か拡散音場か

# 分析対象である信号をロード(サンプリング周波数は48kHz)
signal, fs = load(is_stationary, filepath, calib=calib)

# ラウドネスを算出
loudness = comp_loudness(is_stationary, signal, fs, field_type=field_type)

# プロット
N = loudness['values']
time = np.linspace(0, 0.002*(N.size - 1), N.size) # 2msごとに算出されるため
plt.plot(time, N)
plt.xlabel("Time [s]")
plt.ylabel("Loudness, [sone]")
plt.show()

基本的に、

  • mosqito.functions.shared.loadload関数
  • mosqito.functions.loudness_zwicker.comp_loudnesscomp_loudness()関数

を使えば、ラウドネスの時系列 loudness['values'] を算出することができます。

このラウドネスの時系列は、2msごとに算出されています。

では、それぞれの関数の機能と使い方を見ていきます。

load関数

load 関数の引数は以下のようになっています。

load(is_stationary, file, calib=1, mat_signal='', mat_fs='' )

  • is_stationary : boolean
    • True: 定常信号
    • False: 非定常(時間変動のある)信号
    • ※現状、load()関数内でこの引数は使われていない
  • file : string
    • 分析対象である信号のパス
  • calib: float
    • 信号の振幅値補正用係数

2点ほど注意が必要です。

まず、引数 calib です。

ITU-Rで勧告されているラウドネス値(LKFS, LUFS)は、ディジタルのオーディオデータの振幅値に基づいて算出されます。 一方で、ラウドネス(sone)やラウドネスレベル(phone)は音圧レベル(SPL)に基づいているため、 聴取する音圧は再生機器の音量によって変わってしまいます。 このcalibはそれを補正するための係数のようです。

pyloudnormで学ぶ平均ラウドネス値 (LKFS/LUFS) の算出・実装方法 - Wizard Notes

次に、loadの返り値となる信号データについてです。

ソースコードを見ると、必ず 48k Hzにリサンプリングしていることが確認できます。

従って、もしmosqitoload関数ではないライブラリ/関数で信号をロードしてmosqitoで音質評価を行う場合、48kHzにリサンプリングする必要があります。

comp_loudness()関数

comp_loudness()関数の引数/返り値は以下のようになっています。

comp_loudness(is_stationary, signal, fs, field_type = 'free')

引数:

  • is_stationary: boolean -load関数の引数を参考
  • signal : numpy.array 信号データ
  • fs : integer サンプリング周波数
  • field-type: string
    • "free" もしくは "diffuse" を文字列で与えてください
      • "free": 自由音場。信号を無響室や野外など反響のない(無視できる)空間で録音した場合に選択
      • "diffuse": 拡散音場。信号を室内など音の反響がある空間で録音した場合に選択
    • 参考文献: https://www.onosokki.co.jp/HP-WK/c_support/newreport/noise/souon_13.htm

返り値:

  • N: float/numpy.array ラウドネスの値(sone)
  • N_specific: numpy.array ラウドネス密度 (sone)
    • バーク尺度(周波数)のラウドネス
    • N = ΣN_specific
    • シャープネスやラフネスといった音質評価指標を出すのに利用する
  • bark_axis: numpy.array バーク尺度(周波数)

プロット

MoSQITo/mosqito/validations/loudness_zwicker/data/ISO_532-1/Annex B.5 at master · Eomys/MoSQITo · GitHub のいくつかの信号をプロットしてみました。

比較として、2ミリ秒ごとの合計パワーの推移もプロットしています。

f:id:Kurene:20210115184135p:plain f:id:Kurene:20210115183952p:plain f:id:Kurene:20210115184614p:plain