IT

【Python】ノイズ流すアプリつくる時に作ったノイズ生成コード

はじめに

Flutterでノイズを再生するプレイヤーアプリを作成しました。
その際にノイズ自体の音声データが必要だったのPythonでwavファイルを作成しました。

その際のコードを備忘として残します

作成するノイズ

  • ホワイトノイズ

->ざーっとしたやつ

  • ピンクノイズ

->ごーっとしたやつ

  • ブラウンノイズ

->ぼーっとしたやつ

実際のコード

ノイズのグラフもおまけで生成しています。

importのセクションにありますが、numpy,scipy,matplotlib のライブラリが必要です。

import numpy as np
from scipy.io import wavfile
import scipy.signal as signal
import matplotlib.pyplot as plt

def generate_better_pink_noise(samples):
    """
    より正確なピンクノイズを生成する関数(FFTベースの実装)
    
    Parameters:
    samples (int): 生成するサンプル数
    
    Returns:
    numpy.ndarray: 生成されたピンクノイズ
    """
    # サンプル数の半分の周波数ビンを作成
    freqs = np.fft.fftfreq(samples)[:samples//2]
    # 0除算を避けるため、最初の周波数を無限大に設定
    freqs[0] = float('inf')
    
    # 1/fスペクトルを作成(振幅は周波数の平方根に反比例)
    spectrum = 1/np.sqrt(np.abs(freqs))
    
    # ランダムな位相を生成して複素スペクトルを作成
    phase = np.random.uniform(0, 2*np.pi, len(spectrum))
    spectrum = spectrum * np.exp(1j * phase)
    
    # スペクトルの対称性を確保して完全なスペクトルを作成
    spectrum = np.concatenate([spectrum, np.conj(spectrum[::-1][1:-1])])
    
    # 逆フーリエ変換でピンクノイズを生成
    pink = np.fft.ifft(spectrum).real
    return pink

def analyze_noise_spectrum(noise, sample_rate, noise_type):
    """
    ノイズの周波数スペクトルを分析し表示する関数
    
    Parameters:
    noise (numpy.ndarray): 分析するノイズ信号
    sample_rate (int): サンプリングレート
    noise_type (str): ノイズの種類(グラフのタイトル用)
    """
    # Welch法でパワースペクトル密度を計算
    frequencies, psd = signal.welch(noise, sample_rate, nperseg=4096)
    
    # 両対数プロットでスペクトルを表示
    plt.figure(figsize=(10, 6))
    plt.loglog(frequencies, psd)
    plt.grid(True)
    plt.xlabel('Frequency [Hz]')
    plt.ylabel('Power Spectral Density')
    plt.title(f'{noise_type} Noise Spectrum')
    plt.show()
    
    # 基本的な統計量を計算して表示
    print(f"\n{noise_type} Noise Statistics:")
    print(f"Mean: {np.mean(noise):.6f}")
    print(f"Std Dev: {np.std(noise):.6f}")
    print(f"Skewness: {stats.skew(noise):.6f}")
    print(f"Kurtosis: {stats.kurtosis(noise):.6f}")

def generate_noise(noise_type, duration=30, sample_rate=44100):
    """
    各種ノイズを生成する関数
    
    Parameters:
    noise_type (str): 'white', 'pink', or 'brown'
    duration (int): 生成する音声の長さ(秒)
    sample_rate (int): サンプリングレート(Hz)
    
    Returns:
    numpy.ndarray: 生成されたノイズ(-1.0から1.0の範囲に正規化済み)
    """
    samples = duration * sample_rate
    
    if noise_type == 'white':
        # ホワイトノイズの生成(全周波数で均一なパワー)
        noise = np.random.normal(0, 1, samples)
    
    elif noise_type == 'pink':
        # 改良版ピンクノイズの生成(1/f特性)
        noise = generate_better_pink_noise(samples)
    
    elif noise_type == 'brown':
        # ブラウンノイズの生成(1/f^2特性)
        white = np.random.normal(0, 1, samples)
        # より滑らかな積分のためにバターワースローパスフィルタを適用
        b, a = signal.butter(1, 0.02)
        noise = signal.lfilter(b, a, white)
        # 直流成分(トレンド)を除去
        noise = signal.detrend(noise)
    
    else:
        raise ValueError("Unknown noise type. Use 'white', 'pink', or 'brown'.")
    
    # RMS値による正規化
    rms = np.sqrt(np.mean(np.square(noise)))
    noise = noise / rms
    
    # ノイズタイプに応じた音量調整
    volume_adjustment = {
        'white': 0.3,
        'pink': 0.35,
        'brown': 0.4
    }
    noise = noise * volume_adjustment[noise_type]
    
    return noise

def save_wav(noise, filename, sample_rate=44100):
    """
    ノイズをWAVファイルとして保存する関数
    
    Parameters:
    noise (numpy.ndarray): 保存するノイズ信号
    filename (str): 保存するファイル名
    sample_rate (int): 元のサンプリングレート
    """
    # ファイルサイズ削減のため32kHzにダウンサンプリング
    target_rate = 32000
    samples_new = int(len(noise) * (target_rate / sample_rate))
    
    # 信号をリサンプリング
    noise = signal.resample(noise, samples_new)
    
    # 16ビット整数に変換(-32768から32767の範囲)
    scaled = np.int16(noise * 32767)
    
    # WAVファイルとして保存
    wavfile.write(filename, target_rate, scaled)

def main():
    """
    メイン実行関数
    ノイズの生成、分析、保存を行う
    """
    # 基本パラメータの設定
    duration = 30
    sample_rate = 44100
    noise_types = ['white', 'pink', 'brown']
    
    # 各種ノイズの生成、分析、保存
    for noise_type in noise_types:
        print(f"\nProcessing {noise_type} noise...")
        
        # ノイズ生成
        noise = generate_noise(noise_type, duration, sample_rate)
        
        # スペクトル分析の実行
        analyze_noise_spectrum(noise, sample_rate, noise_type)
        
        # WAVファイルとして保存
        filename = f"{noise_type}_noise.wav"
        save_wav(noise, filename, sample_rate)
        print(f"Generated and saved {filename}")

if __name__ == "__main__":
    from scipy import stats  # statsモジュールを追加
    main()

AIによるコード解説

このプログラムは、異なる種類のノイズ(ホワイトノイズ、ピンクノイズ、ブラウンノイズ)を高品質に生成し、その品質を科学的に検証できる機能を備えています。それぞれのノイズは独自の周波数特性を持ち、様々な用途に活用できます。

ノイズの種類と特徴

このプログラムで生成できる3種類のノイズについて、まず理解を深めていきましょう。

ホワイトノイズは、すべての周波数で同じパワーを持つランダムな信号です。私たちの耳には「シャー」という一定の音として聞こえます。テレビの砂嵐のような音を想像してみてください。

ピンクノイズは、周波数が2倍になるごとにパワーが半分(-3dB)になっていく特徴を持ちます。これは自然界でよく観察される1/f特性と呼ばれるもので、滝の音や風の音など、自然な音に近い特性を持っています。

ブラウンノイズは、周波数が上がるにつれてパワーがより急激に減少(-6dB/オクターブ)します。低い周波数が強調された音で、波の音や雷の遠くの轟きのような特徴を持ちます。

プログラムの主要機能

このプログラムは以下の主要な機能を提供します:

  1. 高精度なノイズ生成
  • FFTベースのピンクノイズ生成アルゴリズム
  • 理論的に正確な周波数特性の実現
  • メモリ効率の良い実装
  1. 品質検証機能
  • スペクトル分析とその可視化
  • 統計的特性の計算(平均値、標準偏差、歪度、尖度)
  • リアルタイムな品質確認
  1. 柔軟なファイル出力
  • WAVファイル形式での保存
  • ファイルサイズ最適化
  • 16ビット量子化による高品質な音質保持

コアアルゴリズムの詳細

特に注目すべきは、ピンクノイズ生成のための新しいアルゴリズムです。従来のVoss-McCartneyアルゴリズムに代わり、FFT(高速フーリエ変換)を使用した周波数領域での直接設計を採用しています。

このアプローチでは、以下のステップでピンクノイズを生成します:

  1. 周波数領域でのスペクトル設計:各周波数成分の振幅を周波数の平方根に反比例するように設定します。これにより、理論的に完璧な1/f特性を実現します。
  2. ランダムな位相の付与:各周波数成分にランダムな位相を与えることで、自然な音の広がりを持つノイズを生成します。
  3. 逆フーリエ変換:設計したスペクトルを時間領域の信号に変換します。この過程で、実数信号を得るために共役対称性を確保しています。

品質検証の重要性

本プログラムの特徴的な機能として、生成されたノイズの品質を科学的に検証できる点が挙げられます。スペクトル分析関数では、Welch法を用いたパワースペクトル密度の計算と可視化を行い、理論値との比較を可能にしています。

また、基本的な統計量の計算により、生成されたノイズの確率分布特性も確認できます。これらの検証機能により、生成されたノイズが意図した特性を持っているかを客観的に評価できます。

実用的な応用例

このプログラムで生成されるノイズは、以下のような様々な用途に活用できます:

  • 音響機器のテストや校正:周波数特性の評価に
  • 音楽制作:サウンドデザインやエフェクトとして
  • 騒音マスキング:オフィスや医療施設での会話のプライバシー保護に
  • 睡眠補助:安定した背景音として
  • 音響実験:音響特性の研究や検証に

プログラムの拡張性

コードは模块化された構造を持ち、新しい機能の追加や既存機能の改良が容易です。例えば、異なる種類のノイズの追加や、より詳細な音響分析機能の実装なども可能です。

まとめ

このプログラムは、理論的な正確性と実用性を両立した高品質なノイズ生成ツールです。FFTベースの実装により、理論的に正確な周波数特性を持つノイズを生成でき、さらに品質検証機能により、生成されたノイズの特性を客観的に評価することができます。

音響工学や音楽制作、研究など、様々な分野での活用が期待できるツールとなっています。

実際の生成物

  • ホワイトノイズ
  • ピンクノイズ
  • ブラウンノイズ

最後に

軽い気持ちでサクッと生成できるだろ。と思っていたのですが、存外うまくいかずに手こずりました。。。

音の生成にはそこそこ演算が必要なんですね。いつも楽器弾くだけだったの音の深さを思い知りました。

以上、どなたかのお役に立てば幸いです。

  • この記事を書いた人

緑川縁

ニートからシステムエンジニアになった人
クラウド案件をメインにやっています。
保持資格:CCNA,AWS SAA&SAP,秘書検定2級
趣味でボカロ曲作り始めました。

-IT
-,