cocuh's note

type(あうとぷっと) -> 駄文

haskellで周波数スペクトルを描画したはなし

大学のHな授業の課題が自由課題だったので適当に深夜テンションでつくりました。

github.com

demo

用いたライブラリ

  • pure-fft
  • WAVE
    • .wav を読み込むため
  • hscurses
    • 可視化のため
  • pulse-simple
    • wavを再生するためにpulse audioのbinding
  • pipes
    • fftと可視化が重いのでマルチスレッド化

やったこと

だいたいこんなかんじ

`.wav`を`WAVE`で読み込み  
 ↓[[int32]]  
 ↓(時間xチャンネル)  
chunksOfでchunkに分ける  
 ↓[[[int32]]]  
 ↓(chunkNum x chunkSize x channelNum)  
pipesでstream化  
 ⇓[[int32]]  
 ⇓ひとつのchunk  
 ⇓(chunkSize x channelNum)  
音量調節(map `div` 3)  
 ⇓[[int32]]  
pulseaudioがLRLRLR…のような[int32]で受け取るのでチャンネルをconcat  
 ⇓[int32]  
 ⇓(chunkSize*channelNum)  
pulseaudioにwrite(Pipes.chainで)  
 ⇓[int32]  
別スレッドにstreamをつなげる ⇛ plotterOutput  
  
plotterInput  
 ⇓[int32]  
 ⇓(chunkSize*channelNum)  
chunkNum次元をdftすると遅いので16個ごとに取って雑に次元削減してベクトル作成  
  ↓[int32]
  ↓(chunkSize*channelNum/16)  
dftしてスペクトルの絶対値を取る  
 ⇓[int32]
 ⇓(chunkSize*channelNum/16)
ncursesでplotする

問題点

  • ウンコード
  • なぜか周波数に対して左右対称になってる
    • 使用してるライブラリがおかしいのか自分の実装がおかしいのか
    • なおすのめんどくさい
    • (追記:サンプリング周波数/2で左右対称になるのはナイキストの定理というらしい。なぜそうなるだろう。。。(勉強不足))

悩んだ点

  • haskellは遅延評価なので、pipes使わないとbufferが遅延評価されてブツブツになる
  • dft遅いのでリアルタイム処理るの大変
  • 型があわない
  • Monad書き慣れてないので、んんんっっっっ
  • 型があわない
  • pulseaudioのspecの型指定Int16と入力型Int32と合ってなかったのに動いて謎な挙動した
    • モノラルだと(bitrateを倍にすると)問題なく聴こえる
    • ステレオにすると右耳だけ聞こえる
    • 割る2すると右耳は変わらず、左がノイズが聴こえる
    • ↑この現象に遭遇してやっと型が違うことにきづいた
  • 型があわない
  • 型があわない
  • 型があわない
  • 型があわない
  • 型があわない

本当に顧客が望んでいたこと

  • ウェーブレット変換
  • cmusみたいな便利なplayer

深夜テンションはこわい。敬具。