ラベル Python の投稿を表示しています。 すべての投稿を表示
ラベル Python の投稿を表示しています。 すべての投稿を表示

2019年8月20日火曜日

ProcessingのPythonモードでスペクトルアナライザーをつくる

ここ最近は『ジェネラティブ・アート』を読んでいました。Processingを使って偶然性に頼ったプログラムによるアートをしてみよう、という内容です。Processingだと簡単にビジュアルを生成できて楽しいですね。ツールの選び方として「作業だけに没頭できるか?」の観点は大事だな、と思いました。

今回はPythonで音楽ファイルを読み込んで再生時にアニメーションを表示する、スペクトルアナライザーを作ってみます。下の図みたいな動画でよく見かけるアレを作ります。『ジェネラティブ・アート』の前半くらいまでの内容と、オーディオを扱うためのライブラリー「Minim」の組み合わせで充分です。

ProcessingはJavaでコードを書くのが通常ですが、モードの切替えでPythonを使うこともできます。ただ、Pythonモードが実装されてから比較的に日が浅いからなのか、書籍もWebもPythonによるサンプルはあまり見かけません……。ライブラリーもサンプルはJavaだけが多いので、JavaのコードをPythonで読み替えていく作業が必要です(大したことではないけれど)。

コード

コード全体は下に載せてあるとおり。Minimは事前に追加されていることが前提です。音楽ファイルはProcessingのエディターにドロップしておく(プロジェクトファイルと同階層にフォルダーを作ってコピーされる)と、ファイル名だけを記述すれば良くなってラクです。

add_library('minim')

def setup() :
    # 初期化
    size(640, 480, P2D)
    background(0)
    smooth()
    
    # 音楽取込み
    global _minim
    global _player
    _minim = Minim(this)
    _player = _minim.loadFile('test.mp3')

    # 描画用変数
    global _width_pad    # 幅/y方向のウィンドウパディング
    global _height_pad   # 高/x方向のウィンドウパディング
    _width_pad = 20
    _height_pad = 80
    global _width_div    # 幅/y方向の分割数
    global _height_div   # 高/x方向の分割数
    _width_div = 30
    _height_div = 20
    
    global _cell_width   # セル幅
    global _cell_height  # セル高
    _cell_width = (width - _width_pad * 2) // _width_div
    _cell_height = (height - _height_pad * 2) // _height_div

    # 周波数解析
    #    10[Hz]〜サンプリングレートの1/2までをカウント
    global _fft
    global _log_band    # _width_divに応じた対数の帯域
    global _band_base   # 10[Hz]
    _fft = FFT(_player.bufferSize(), _player.sampleRate())
    _band_base = 10.0
    _log_band = pow((_player.sampleRate() / 2.0) / _band_base, 1.0 / _width_div)


def draw() :
    background(0)
    stroke(255)
    
    # セットアップ
    _fft.forward(_player.mix)
    translate(_width_pad, height - _height_pad)
    
    # 描画
    for x in range(_width_div) :
        # 列ごとの周波数帯域を計算して平均値を得る
        band_start = _band_base * pow(_log_band, x)
        band_end = band_start * _log_band
        spec_ave = _fft.calcAvg(band_start, band_end)
        
        # 対数[dB]に変換する
        signal = -100
        if spec_ave > 0.0 :
            signal = 20.0 * log(spec_ave/255) / log(10)
        
        # 高/x方向の分割数へマッピングする
        pile_num = map(signal, -100, 0, 0, _height_div)
        
        PileUpRect(_cell_width, _cell_height, 3, int(pile_num))
        translate(_cell_width, 0)


def PileUpRect(width, height, padding, quantity) :
    pushMatrix()
    # quantityの数だけセルを積む
    for q in range(quantity) :
        rect(padding, -padding, width - padding, padding-height)
        translate(0, -height)
    popMatrix()


def keyPressed() :
    # キーで再生オン/オフ
    if _player.isPlaying() == True :
        _player.pause()
    else :
        _player.play()

2018年9月10日月曜日

pip install が使えなくなったので修復方法を模索する

久々に Python へライブラリを追加して遊ぼうと思ったのですが、pip install が一切使用できない事態になっていました……。

スクリーンショットを撮っておけばよかったのですが……。pip install 実行後に「Could not fetch URL」から始まって「There was a problem confirming the ssl certificate」を経由して「Could not find a version that satisfies the requirement 〇〇 (from versions: )」と表示されるような状態になっていました。URLに繋げられなかったのだから、〇〇(インストールしたかったライブラリ)が見つからないのは当然です。

よくある解決方法1

pip のバージョンが古いと install を使えなくなる似た事態になるようです。

Problem Confirming the SSL Certificate - OSX · Issue #5236 · pypa/pip

Pip version: pip 9.0.1 Python version: Python 3.5.2 and Python 2.7.10 installed Operating system: OSX - 10.13.4 Description: I've tried to install Keras (keras.io) and faced with a problem related confirming ssl certificate. What I've ru...

「pip が使えないなら、curl でやってみて」なんて書かれているけれど、今回は curl もダメでした。

curl https://bootstrap.pypa.io/get-pip.py | python3

よくある解決方法2

ひたすら「--trusted-host」オプションを付ける方法で改善するパターンもあるようです。ただし、自分の環境ではコレでも改善できなかった……。

Cannot update or install anything with pip, SSL error

Hi everyone, this is my first time posting on here and I really need help with this problem. I've had Python and pip on my PC since I got it about a year ago and never really used pip that much until recently. I'm working on a project with my friend ...

python -m pip install --trusted-host pypi.python.org --trusted-host files.pythonhosted.org --trusted-host pypi.org --upgrade pip

結局、何が悪かったのか?

ウイルス対策ソフトでした。端末にインストールされているカスペルスキー、これのバージョンアップ版がリリースされていたようだったので、入れ替えてみると pip コマンドが元通り使えるようになりました。ウイルス対策ソフトが原因で不通になるとか、“あるある現象”でしたね……。

似た事象で困った場合は、チェックしてみても良いかもしれません。

2018年5月13日日曜日

PythonでMIDIを扱えるようにpretty_midiを導入する

Pythonで楽譜を扱うのが面白いです。ABC記譜法であれば、楽譜を「文字」として扱えるのでPythonだと比較的にラクに処理できます。ただ、楽譜のインプットやアウトプットのことを考えるとMIDIファイルを扱えるようにしたほうが便利なように思えます。

pretty_midiを使う

PythonでMIDIを扱う場合、パッケージ『pretty_midi』をインポートすれば良さそうです。MIDIファイル内のトラックごとに、ノートをリストとして取得できるようになります。

インストールはpipコマンドだけで済むのでラクチン。

pip install pretty_midi

MIDIを読み込む

PrettyMIDI()でファイル名を指定すれば、あとはトラックとノートがリストで取得できます。

import pretty_midi

# MIDIファイルのロード
midi_data = pretty_midi.PrettyMIDI('test.mid')
# トラック別で取得
midi_tracks = midi_data.instruments
# トラック1のノートを取得
notes = midi_tracks[0].notes
for note in notes:
    # ベロシティー、ノートナンバー、
    # ノートオンタイム、ノートオフタイム
    # の順でノート情報が渡される
    print(note)

pretty_midiを使うときに注意しなければいけないのは次の事項でしょうか?

  • 基本的にTickではなく、時間で位置が管理されている
    ※Tickへ変換するメソッドが用意されている
  • 楽曲開始位置はアーフタクトが考慮されていない
  • 分解能は480Tickへ変換される

ABC記譜法では存在していた休符情報がMIDIでは在りません。機械学習で休符情報も欲しい場合はロケーションの差分を求めて、擬似ノートを置いてあげる必要がありますね。