たけし備忘録

自分の好奇心の赴くままに勉強メモ LL系が大好き Python bash Julia C

PyAudioの使い方まとめ

音声入出力ライブラリであるPyAudioの使い方をまとめた記事です。

PyAudioの基本メモ

PyAudioの基本メモ1 - たけし備忘録
PyAudioの基本メモ2 音声入出力 - たけし備忘録

PyAudioとpyatgraphでリアルタイムプロット

pyqtgraph+PyAudioによるリアルタイムで音声プロット - たけし備忘録
pyqtgraph+PyAudioによるリアルタイムで音声プロット その2 - たけし備忘録

PyODE+VisualPythonで物理シミュレーション 目次

一度はやってみたい物理シミュレーション
物理シミュレーションといえば物理演算エンジン 色々な種類があります。
今回はその中でもPythonバインディングされているC++物理エンジンライブラリであるODE(OpenDynamicsEngine)を用いてシミュレーションをしてみます。

参考文献

ODE関連のサイト

VisualPython関連のサイト

基本を学ぶ

1. PyODEとVPythonのインストール - たけし備忘録

2. ボールの自由落下 - たけし備忘録

3. ボールの自由落下(衝突判定有り) - たけし備忘録

Julia+SymPyの勝手なまとめ

自分の気になったところだけメモしていく形です
基本的にはJuliaのSymPyパッケージ内に入っているtutorial.mdというファイルから抜粋する形です。

SymPy の導入

まずはjuliaを立ち上げてSymPyのパッケージをインストールしましょう。
PyCallに依存しているので入れてない方はPyCallもインストールしましょう。

$ julia
              _
   _       _ _(_)_     |  A fresh approach to technical co
  (_)     | (_) (_)    |  Documentation: http://docs.julia
   _ _   _| |_  __ _   |  Type "?help" for help.
  | | | | | | |/ _  |  |
  | | |_| | | | (_| |  |  Version 0.4.3 (2016-01-12 21:37)
 _/ |\__'_|_|_|\__'_|  |  Official http://julialang.org/ r
|__/                   |  x86_64-w64-mingw32

julia> Pkg.add("PyCall")
...........なんかいろいろ出る
julia> Pkg.add("SymPy")
...........なんかいろいろ出る
julia>

<*追記*>
依存がPyCallとSymPyだけじゃありませんでした。
JuliaのPyCallとSymPyパッケージを入れた環境に、Python(2でも3でもいい)をインストールし、かつPythonのSymPyライブラリをインストールする必要があります。

python.jp
こちらのPython日本語ホームページからダウンロードできます。バージョンは2でも3でもお好きな方で大丈夫です。


Pythonのインストールが終わったら、次はPythonのSymPyをインストールする必要があります。
Pythonは2.7.9以上のバージョン(3を含む)ならば、PIPというパッケージ管理ツールが同梱していますのでそのままお使いいただけます。

$ python -m pip install sympy

で基本的にはインストールできます。

  • 上記でインストール出来ない場合(Windowsのみ記載)

上記の方法でインストール出来ない場合、次の非公式パッケージがダウンロードできるサイトで.whlというファイルをダウンロードしましょう。
Python非公式パッケージ
現時点(2016/1)ではsympy-0.7.6.1-py2.py3-none-any.whlが最新のようです。
この.whlファイルを、ターミナルから操作しやすいディレクトリに入れておきましょう。
今回の場合、C:\test\sympy-0.7.6.1-py2.py3-none-any.whlとして保存しておくことにします。

$ pwd # 現在地
C:\test

$ ls
sympy-0.7.6.1-py2.py3-none-any.whl

$ python -m pip install sympy-0.7.6.1-py2.py3-none-any.whl
(色々出る)

で完了です。

  • 上記でインストール出来ないかつ不安だからpython2と3の両方インストールしちゃったよの場合(Windowsのみ記載)

pythonはデフォルトで2と3が共存できます(3の方が新しいですが2への後方互換性が無いです)。
そのような場合 pyコマンドで2と3を明示的に切り替えることが出来ます。

# Python2を使う場合
$ py -2 -m pip install sympy-0.7.6.1-py2.py3-none-any.whl

# Python3を使う場合
$ py -3 -m pip install sympy-0.7.6.1-py2.py3-none-any.whl

シンボルの生成

SymPyのJuliaでのラッパは色々なシンボルの生成の仕方があります。

1つずつシンボルを生成
julia> x = Sym("x") # Sym関数での生成
x
julia> @syms x      # symsマクロでの生成
(x,)
julia> x
x


複数のシンボルを一気に生成
julia> x, y, z = symbols("x, y, z")   # symbols関数での生成
(x,y,z)
julia> a, b, c, d, e = symbols("a:e") # ":"というイテレータで一気に生成
(a,b,c,d,e)
julia> @syms x y z                  # symsマクロで生成
(x,y,z)

マクロでの生成が一番手軽でよさそう


特殊な定数 PI, E, oo

PIは円周率
Eは自然定数の底(ネイピア数)
ooは無限大です

julia> PI,E,oo
(pi,E,oo)

juliaはデフォルトでpiという定数がありますがPIとは異なります。

julia> [asin(1), asin(Sym(1))]
2-element Array{SymPy.Sym,1}
[1.5707963267949]
[               ]
[      pi       ]
[      --       ]
[      2        ]


代入

シンボルで定義した式に、数値またはシンボルを代入します。
Julia固有の色々な代入の仕方があります。

subs関数による代入

前準備
julia> @syms x y
(x,y)

julia> f = x^2+2x+1
 2
x  + 2*x + 1
シンボルxにシンボルyを代入
julia> subs(f, x, y)
 2
y  + 2*y + 1
シンボルxに数値1を代入
julia> subs(f, x, 1)
4



便利な代入

前準備
julia> @syms x y z
(x,y,z)

julia> f=x+y+z
x + y + z
便利な代入1

これは便利な気がする

julia> f(x=>1, y=>pi)
z + 1 + pi
便利な代入2

代入の順序がよくわかんない

julia> f(1, pi)
y + 1 + pi
便利な代入3

パイプライン(|>という演算子)による代入です

julia> f |> subs(x, 1)
y + z + 1


便利な代入1の=>による代入が一番わかりやすい気がする。

シンボルから数値への変換

evalf関数とN関数の二つの方法があります。
NはBigFloatという型らしいです。よく知りません。
evalfはお馴染みです。

julia> evalf(PI)
3.14159265358979

julia> N(PI)
3.141592653589793

julia> evalf(PI, 30)            # 桁数指定 30桁
3.14159265358979323846264338328

julia> N(PI, 30)                # 桁数じゃなかった。何者だろうこの引数は
3.1415926535897932384626433832793 

方程式の解

solve関数を使います。

前準備
julia> @syms x
(x,)

julia> f=x^2+x+1
 2
x  + x + 1
解を得る1 x^2+x+1=0
julia> solve(f)
2***element Array{SymPy.Sym,1}
[        ___  ]
[  1   \/ 3 *I]
[- - - -------]
[  2      2   ]
[             ]
[        ___  ]
[  1   \/ 3 *I]
[- - + -------]
[  2      2   ]
解を得る2 x^2+x+1=1
julia> solve(Eq(f, 1))
2-element Array{SymPy.Sym,1}
[-1]
[  ]
[0 ]
解を得る3 x^2+x+1=0
julia> solve(f⩵0)    
2-element Array{SymPy.Sym,1}
[        ___  ]
[  1   \/ 3 *I]
[- - - -------]
[  2      2   ]
[             ]
[        ___  ]
[  1   \/ 3 *I]
[- - - -------]
[  2      2   ]

# ※注意!! f==0と書いていますがこれは \Equalの後にTabを押して出る特殊記号です。

極限

極限はlimit関数で操作できます。

基本の計算方法
julia> @syms x h
(x,h)

julia> limit(sin(x)/x, x, 0)
1

julia> limit(sin(x)/x, x=>0)
1

julia> limit((1+1/x)^x, x=>oo)
E

julia> limit((sin(x+h)-sin(x))/h, h=>0)
cos(x)
右極限と左極限

sign関数を使って例を書きます。
sign関数とは

という関数です。つまり左極限と右極限が異なる不連続関数です。

julia> limit(sign(x), x=>0, dir="-") # 左極限
-1

julia> limit(sign(x), x=>0, dir="+") # 右極限
1

数値計算

やっぱりなんだかんだ数値計算が出来てなんぼさ。
ということで数値計算の主な方法です。

関数の定義

Juliaでの関数の定義はいろいろなやり方があります。
まずSymPyを使うとシンボルを定義します。
シンボルはSymPy.Sym型の変数ですのでJuliaの性質である多重ディスパッチが使えます。
多重ディスパッチとは、同名の関数、例えばtestという関数を

function test(x::Int)
    return x
end

function test(x::Float64)
    return 2x
end

として同名で、引数の型の違いによって出力や内容を変える性質のことです。

多重ディスパッチを使うと、

@syms x
f(x) = x^2+x+1

という風に定義すると

julia> f(x)
2
x  + 2*x + 1

julia> f(1)
4

julia> f(1.0)
4.0

julia> f(1:10)
ERROR: MethodError: `*` has no method matching *(::UnitRange{Int64}, ::UnitRange{Int64})
Closest candidates are:
  *(::Any, ::Any, ::Any, ::Any...)
  *{T}(::Bidiagonal{T}, ::AbstractArray{T,1})
  *(::Number, ::AbstractArray{T,N})
  ...
 in power_by_squaring at intfuncs.jl:78
 in f at none:1

1:10を引数にするとエラーが出ました。
そこでArray型にも対応できるように

f(x) = x.^2+2x+1

とします。 x^2がx.^2になっただけです。
このようにすれば

julia> f(1:10)
10-element Array{Int64,1}:
   4
   9
  16
  25
  36
  49
  64
  81
 100
 121

となります。
行列も引数に与えられます。

SymPyのままでも

@syms x
f = x.^2+2x+1

としても

julia> f(x)
 2
x  + 2*x + 1

julia> f(1)
4

julia> f(1.0)
4.00000000000000

julia> f(1:10)
ERROR: MethodError: `convert` has no method matching convert(::Type{SymPy.Sym}, ::UnitRange{Int64})
This may have arisen from a call to the constructor SymPy.Sym(...),
since type constructors fall back to convert methods.
Closest candidates are:
  SymPy.Sym(::Any)
  SymPy.Sym(::Any...)
  call{T}(::Type{T}, ::Any)
  ...
 in subs at C:\Users\takeshi\.julia\v0.4\SymPy\src\subs.jl:46
 in call at C:\Users\takeshi\.julia\v0.4\SymPy\src\subs.jl:115

とこのように関数のように使うことはできます。
しかし1:10などの配列や行列などは代入できません。
この理由としては
f = x.^2+2x+1
と定義するとSymPy.Sym型であり
f(x) = x.^2+2x+1
と定義するとこれは多重ディスパッチによって無名関数になるからです。
型を確認してみましょう。

区別がつきやすいように

@syms x
f(x) = x.^2+2x+1
g = x.^2+2x+1

としておきます。

julia> typeof(f)
Function

julia> typeof(g)
SymPy.Sym

fがFunction型、gがSymPy.Sym型になっています。

またさらにfの場合

julia> typeof(f(x))
SymPy.Sym

julia> typeof(f(1))
Int64

julia> typeof(f(1.0))
Float64

julia> typeof(f(1:10))
Array{Int64,1}

となります。
gの場合は

julia> typeof(g(x))
SymPy.Sym

julia> typeof(g(1))
SymPy.Sym

julia> typeof(g(1.0))
SymPy.Sym

となっていずれもSympy.Sym型になります。
なかなかこれが使えます。

微分

当たり前ですがPythonのSymPyと同様に記号微分が出来ます。

julia> @syms x
(x,)

julia> f(x) = x.^2+2x+1
f (generic function with 1 method)

julia> diff(f(x))
2*x + 2

julia> diff(f(x), x)
2*x + 2

julia> diff(f)
2*x + 2

diff関数は多重ディスパッチで
diff(f:SymPy.Sym)だけでなく
diff(f::Function)も定義されているので、無名関数として定義したfを入れても微分してくれます。

diff関数のオプション

diff関数は任意の回数だけ微分することができます。
以下に例を書きます。

julia> f(x)
 2
x  + 2*x + 1

julia> diff(f(x), x, 0)  # 0階微分
 2
x  + 2*x + 1

julia> diff(f(x), x, 1)  # 1階微分
2*x + 2

julia> diff(f(x), x, 2)  # 2階微分
2

もちろんfのままでも渡せます。が、少し文法が異なります。
要するにxが消えます。無名関数のまま渡すので、引数の情報がいらないわけです。

julia> f(x)
 2
x  + 2*x + 1

julia> diff(f, 0)  # 0階微分
 2
x  + 2*x + 1

julia> diff(f, 1)  # 1階微分
2*x + 2

julia> diff(f, 2)  # 2階微分
2
偏微分

2つのシンボルで定義された関数は偏微分できます。
さっそく例を出していきましょう。

julia> @syms x y
(x,y)

julia> f(x, y) = x^2 + y^2 + x*y
f (generic function with 2 methods)

julia> diff(f(x,y), x)    # xについて偏微分
2*x + y

julia> diff(f(x,y), y)    # yについて偏微分
x + 2*y

julia> diff(f(x,y), x, y) # x,yについて偏微分
1

julia> diff(f(x,y))
ERROR: PyError (:PyObject_Call) <type 'exceptions.ValueError'>
ValueError('\nSince there is more than one variable in the expression, the\nvariable(s) of differentiation must be supplied to differentiate x**2\n+ x*y + y**2',)
  File "C:\Python27\lib\site-packages\sympy\core\function.py", line 1638, in diff
    return Derivative(f, *symbols, **kwargs)
  File "C:\Python27\lib\site-packages\sympy\core\function.py", line 987, in __new__
    must be supplied to differentiate %s''' % expr))

 [inlined code] from C:\Users\takeshi\.julia\v0.4\PyCall\src\exception.jl:81
 in pycall at C:\Users\takeshi\.julia\v0.4\PyCall\src\PyCall.jl:361
 in fn at C:\Users\takeshi\.julia\v0.4\PyCall\src\conversions.jl:194
 in call_sympy_fun at C:\Users\takeshi\.julia\v0.4\SymPy\src\SymPy.jl:262
 in sympy_meth at C:\Users\takeshi\.julia\v0.4\SymPy\src\SymPy.jl:268
 in diff at C:\Users\takeshi\.julia\v0.4\SymPy\src\math.jl:190

julia> diff(f)    # 無名関数を偏微分
2*x + 2

積分

微分と同様に積分です。

不定積分
julia> f(x)
 2
x  + 2*x + 1

julia> integrate(f(x), x)
 3
x     2
-- + x  + x
3

julia> integrate(f(x))
 3
x     2
-- + x  + x
3

julia> integrate(f)
 3
x     2
-- + x  + x
3
より一般的な書き方
julia> @syms x n
(x,n)

julia> integrate(x^n, x)
/log(x)  for n = -1
|
| n + 1
<x
|------  otherwise
|n + 1
\

めちゃめちゃわかりにくいですがこれは

ということです。

積分
julia> integrate(f, 0, 3)
21

julia> integrate(f, 0, x)
 3
x     2
-- + x  + x
3

julia> integrate(f, x, 3)
   3
  x     2
- -- - x  - x + 21
  3

julia> integrate(f, x, 2x)
   3
7*x       2
---- + 3*x  + x
 3

積分範囲もシンボルが使えます。

積分

同様に重積分も行えます。

julia> @syms x y
(x,y)

julia> integrate(x*y, (y, 0, 1), (x, 0, 1))
1/4

julia> integrate(x^2*y, (y, 0, 1-x^2), (x, -1, 1))
8/105

シンボルを含んだ積分をした後に数値のみの積分も出来ます。

テイラー展開

テイラー展開もできちゃいます。
めんどくさいので略。

第n部分和と無限級数

基本的な使い方

まずは基本からです。summation関数を使います。

julia> @syms k n
(k,n)

julia> summation(2^k, (k, 1, n))    # 第n部分和
 n + 1
2      *** 2

julia> summation(1/k^2, (k, 1, oo)) # 無限級数(この例はゼータ関数)
  2
pi
---
 6
limit関数を使った無限級数

limitを使えば部分和を無限級数にできちゃいます。

julia> Sn = summation(1/k^2, (k, 1, n))
harmonic(n, 2)

julia> limit(Sn, n=>oo)
  2
pi
---
 6

harmonic(n, 2)はnをシンボルとした2次の調和級数です。要するにζ(2)です。

PyAudioの基本メモ2 音声入出力

PyAudioの基本メモ1の続きです。

今回はPyAudioの基本的な使い方を書きます。
ほとんどPyAudio: PortAudio v19 Python Bindingsの例題のままです。

音声の出力

import pyaudio
import wave

CHUNK = 1024
filename="好きなwavファイル"

wf = wave.open(filename, 'rb')

p = pyaudio.PyAudio()

stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
                channels=wf.getnchannels(),
                rate=wf.getframerate(),
                output=True)

""" 
   format  : ストリームを読み書きするときのデータ型
   channels: ステレオかモノラルかの選択 1でモノラル 2でステレオ
   rate    : サンプル周波数
   output  : 出力モード

"""

# 1024個読み取り
data = wf.readframes(CHUNK)

while data != '':
    stream.write(data)          # ストリームへの書き込み(バイナリ)
    data = wf.readframes(CHUNK) # ファイルから1024個*2個の

stream.stop_stream()
stream.close()

p.terminate()

これで好きなwavファイルを再生できる

音声の入力

import pyaudio
import wave

CHUNK = 1024
FORMAT = pyaudio.paInt16 # int16型
CHANNELS = 2             # ステレオ
RATE = 44100             # 441.kHz
RECORD_SECONDS = 5       # 5秒録音
WAVE_OUTPUT_FILENAME = "output.wav"

p = pyaudio.PyAudio()

stream = p.open(format=FORMAT,
                channels=CHANNELS,
                rate=RATE,
                input=True,
                frames_per_buffer=CHUNK)

print("* recording")

frames = []

for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
    data = stream.read(CHUNK)
    frames.append(data)

print("* done recording")

stream.stop_stream()
stream.close()
p.terminate()

wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()

frames_per_bufferがよくわからん
とりあえず1024にしておけば大丈夫そう

リアルタイムで音声入出力

マイク入力した音声をリアルタイムでスピーカーから出力します。
マイクはOSで設定したデフォルト、スピーカーもOSで設定したデフォルトの機器を使います。
※注意! イヤホンをしていないとハウリングして耳がキィーンとします。

# -*- coding:utf-8 -*-

import pyaudio

CHUNK=1024
RATE=44100
p=pyaudio.PyAudio()

stream=p.open(	format = pyaudio.paInt16,
		channels = 1,
		rate = RATE,
		frames_per_buffer = CHUNK,
		input = True,
		output = True) # inputとoutputを同時にTrueにする

while stream.is_active():
	input = stream.read(CHUNK)
	output = stream.write(input)
	
stream.stop_stream()
stream.close()
p.terminate()

print "Stop Streaming"

リアルタイムで音声加工

マイク入力した音声をリアルタイムで加工して出力します。

# -*- coding:utf-8 -*-

import pyaudio

CHUNK=1024*2
RATE=44100
p=pyaudio.PyAudio()

stream=p.open(	format = pyaudio.paInt16,
		channels = 1,
		rate = RATE,
		frames_per_buffer = CHUNK,
		input = True,
		output = True) # inputとoutputを同時にTrueにする


def audio_trans(input):
    # なんかしらの処理
    return ret

while stream.is_active():
	input = stream.read(CHUNK)

        input = audio_trans(input)

	output = stream.write(input)
	
stream.stop_stream()
stream.close()
p.terminate()

print "Stop Streaming"

加工する場合はCHUNKを2倍の2048にして少し処理を遅くしました。

なぜならばまず、アウトプットする時のストリームへの書き込みに必要となる時間がCHUNK=1024とすると
(書き込みに必要な時間)=CHUNK/RATE=0.023[sec] でした。
timeモジュールで測定してみましたが確かにそのくらいの時間のようです。
ストリームから音声を読み取る時間と入力音声を加工する処理の時間の合計が、書き込みに必要な時間より遅いと

音声出力中→→→終了 空白の時間   音声出力...→→
読み取り→→→→加工 処理中......... 書き込み

              ↑
              ここで空白の時間(音声が出ない→声が途切れて聞こえる)

という現象が起こりました。(わかりにく)
この空白の時間が人間が感じ取れないほど短い時間(またサンプル周期よりも小さい時間)であればプツプツ音は出ないようです。 
また読み込みよりも書き込みのほうが圧倒的に時間がかかるようなのでCHUNKを大きくしても書き込み時間だけを気にしていれば平気そうです。
このため、CHUNKを2倍にして書き込みに必要な時間を 0.046[sec]としました。
読み取り時間+処理時間 がテキトーに処理を書いた(ピッチ抽出など)ときおよそ 0.03[sec]程度だったのでこれで空白の時間はなくなりました
が、入力から出力の遅れ時間は当たり前のごとく増えました。
適宜CHUNK幅を調整して遅れさせてください。

PyAudioの基本メモ1

PyAudioの使い方を時々忘れてしまうのでメモ書き
用語の名前は私が勝手に読んでいる名前もあるので一般的な呼び方では無いこともあります。

基本的な用語

音源
 基本的には全てバイナリデータ(16進数 0x13 0x76など)

静的な音源
 wavファイル, rawファイル, mp3ファイルなど

動的な音源
 マイクに現在入力している音声など

wav, raw, mp3の違い
 通常の静的な音源は

 ヘッダ(サンプル周波数などのメタデータ)
       +
   ボディ(音源の本体)

 という構成になっている。

 rawファイル→ヘッダ無し, ボディ有り
 wavファイル→ヘッダ有り, ボディ有り
 mp3ファイル→ヘッダ有り, ボディ有り

 htmlみたいなもんだと思っていいかもしれない。たまにフッタも付いてるやつもある。

wavファイルとmp3ファイルの違い
 wavファイルはrawファイルにヘッダを付けたもの
 mp3ファイルは音源のある周波数(44.1kHz? 22.05kHzだったかな)以上の音をカットしてサイズ小さくしている。

 まとめると
 wavファイル→生音声
 mp3ファイル→加工された音声(音楽聞けりゃオッケー程度)

動的な音源からの読み込み
 後述するチャンクというサイズごとに読み取る必要がある。

静的な音源からの読み込み
 チャンク毎に読み取ってもいいし、全部一気に読み取ってもOK。

ストリーム
 データストリームとも言う。ストリーミング方式の動画などがある。データの流れ。
 音声で言うと、マイクからは常に音声データが流れて来ていて、ストリームに流れている。河みたいなものだと思えばいい。
 ストリームに書き込むとは 河にデータを流すこと
 ストリームを読み込むとは 河からデータを取ってくること
 

パラメータなどの用語

チャンク(CHUNK)
 音源から1回読み込むときのデータサイズ。1024(=2の10乗) とする場合が多い

サンプル周波数
 サンプルレートだとか、フレームレートとも言われる。よくfsとかsrと書く。次元は[個/sec]。
 データを読み取るときに、何秒ごとに1点のデータを取ってくるかを決める値。
 逆数はサンプル周期と言われTsなどと書く。
 よく使われるのは 44.1kHz, 16kHzなど。

 (例) fs = 44.1[kHz]の場合
   1/fs=Ts=22.7[μsec]毎に1点データを取ってくる。
 
 たまにナイキスト周波数とか言われることがあるけどナイキスト周波数はサンプル周波数の半分の周波数のこと(標本化定理)。

フレーム数
 少なくともPythonのwaveモジュール上ではバイナリデータの個数。
 0x00 などが1024個入ってるデータは1024フレームと言う。
 たぶん分野だとか動画だとかそういうジャンルによって使われ方が違う。
 よくわかってない。

音源の秒数の計算
 音源の秒数の計算には
 サンプル周波数 バイナリデータ数
 の2つが必要。
 
 (秒数)=バイナリデータ数/サンプル周波数

 という計算で出せる。

 (例) CHUNK個のデータをfsというサンプル周波数で取ってきた。
  (秒数)=CHUNK/fs

読み込んだバイナリデータを数値に変換

 マイクから音声を読み込んで、プロットする時の基本的な動きは

 1. ストリームから音声をCHUNK(ここでは1024とする)の長さでバイナリ形式で読み込む

 2. 読み込んだバイナリデータはCHUNKの2倍の長さの2048(罠!)

 3. バイナリデータをint16型に変換
  ただしint16型に変換するのが通常なだけでfloat64型などにも変換できる。意味は無い。

 4. int16型に変換すると長さがCHUNKと同じになる
   バイナリ2つ "0x16 0x08" などのセットで1つの値になる。
   バイナリ1つは8bitなのでint16の16bit数値にするには2つ分必要。なので2048個のバイナリデータを先頭から2つずつint16型の数値に変換すると全体として1/2のサイズ、1024個のint16データになる。
   意味は無いがfloat64型に変換すると8個ずつ読み込んでfloat64の数値にするので2048個の1/8のサイズになる。

 5. int16に変換した1024個のデータをプロット
  フィルタなどを掛けるときはint型に戻してからのほうがPythonでは扱いやすい(そもそもバイナリのままバイナリとして扱えるのか?)


 

Pythonでtreeコマンド実装

Windowsにもtreeコマンドがありますがなんとも気に入らなかったので自分で使う用にtreeコマンドを実装しました。
bashだとかCだとかでやったほうが日本語周りはかなり楽なんだろうけど、あえて日本語周りが大変なpythonで練習。
普段あんまりpythonで日本語扱うことが少ないのでいい機会かもしれない。
ということで獣のごとくテキトーに思うまま実装しました。保守性は皆無です。

コマンドプロンプト文字コードはcp932で、Cygwinは確かめて無いので知りません。変えてないからデフォルトのままのはず。

以下よりソースコード

[tree.py]

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import os
import sys

def print_enc(str):
    try:
        print str
    except:
	print str.encode("utf-8")

def tree(path = u".", d = 0, depth = 2, tab=u""):
	#深さの指定で再帰中断
	if d==depth:
	    return
	else:
	    #指定path下(未指定でカレントディレクトリ)のフォルダとファイルを取得
            file_list = []
	    dir_list = []
	    for p in os.listdir(path):
	        if os.path.isfile(path+u"/"+p):
		    file_list.append(p)
		if os.path.isdir(path+u"/"+p):
		    dir_list.append(p)
			
	    #ルートを表示
	    if d==0:
		print u"/%s" % os.getcwd().split("\\")[-1]
		
	    #ファイルの表示
	    for i in xrange(len(file_list)):
		if i!=len(file_list)-1:
		    print tab+u"┣━",
		    print_enc(file_list[i])
		else:
		    if len(dir_list)==0:
			print tab+u"┗━",
			print_enc(file_list[i])
		    else:
			print tab+u"┣━",
			print_enc(file_list[i])

	    #ディレクトリの表示
	    for i in xrange(len(dir_list)):
		if i!=len(dir_list)-1:
		    print tab+u"┣━",
		    print_enc(dir_list[i])
		    tree(path = path+u"/"+dir_list[i], d=d+1, depth=depth, tab=tab+u"┃\t")
		else:
		    print tab+u"┗━",
		    print_enc(dir_list[i])
		    tree(path = path+u"/"+dir_list[i], d=d+1, depth=depth, tab=tab+u"  \t")
            
            return


if __name__=="__main__":
    if len(sys.argv)==2 and sys.argv[1]:
        tree(depth=int(sys.argv[1]))
    else:
        tree()


すんごい見づらいし汚い感じですが一応動きました。
ただ、使うターミナルの設定だとかlessを使った場合だとかで表示がかなり違うのでpythonだとめんどいなぁという印象。3系だと文字周りが簡単になったとか聞くけどどうなんだろうか。
とりあえず

  • 標準モジュールだけで作成
  • 日本語を表示できること(特殊文字は除く)

が実現できたのでいいかな

自分で使う用なのでexe化してしまってテキトーにpath通してしまえばいいや
使い方は(現時点では)

$python tree.py 3

という形で使います。
コマンドライン引数の3は表示するディレクトリの深さです。上の場合3階層まで表示します。1でカレントディレクトリ内を表示します。
デフォルトでは2になっています。

以下より様々な表示結果


[テスト用フォルダ]
f:id:takeshiD:20151218024604p:plain

[コマンドプロンプト(引数:デフォルト)]

python tree.py

f:id:takeshiD:20151218024616p:plain

[コマンドプロンプト(引数:1)]

python tree.py 1

f:id:takeshiD:20151218024620p:plain

[コマンドプロンプト(lessをパイプでつなげた状態)]

python tree.py | less

f:id:takeshiD:20151218024624p:plain

[コマンドプロンプト(引数:4)]

python tree.py 4

f:id:takeshiD:20151218024627p:plain


[Cygwin(引数:デフォルト)]

python tree.py

f:id:takeshiD:20151218024632p:plain

[Cygwin(lessをパイプでつなげた状態)]

python tree.py | less

f:id:takeshiD:20151218024635p:plain


lessをつなげたときだけなぜか特殊文字の♡まで表示出来たのはなんでだろう。しかもコマンドプロンプトの時だけ。
lessコマンドは双方ともCygwin内蔵のlessから持ってきているので文字コードの違いなんだろうなきっと。

コマンドとして使うときディレクトリ指定もできたらいいのですがコマンドライン引数のなんちゃらが面倒でした。
調べた感じだと組み込みでargparseというモジュールがあるらしいのでいずれいじってみたいです。
めんどうだからここまでで終わりにしました。

Bottle日本語ドキュメント(自分用) 記事一覧まとめ

チュートリアル

この記事は、下記の情報を訳したものです。
Tutorial — Bottle 0.13-dev documentation

 このチュートリアルでは、ボトルのWebフレームワークの概念と機能を紹介し、同様に基本的かつ高度なトピックをカバーしています。あなたが最初から最後までそれを読んで、またはそれ以降のリファレンスとして使用することができます。自動的に生成されたAPIリファレンスにも、あなたにとっては興味深いかも知れません。

 それ以上の詳細について説明しますが、このチュートリアル未満を説明しています。最も一般的な質問のためのソリューションは、当社のレシピ集やFAQページに記載されています。何か助けが必要な場合は、私たちのメーリングリストに参加したり、私たちのIRCチャン​​ネルで私たちをご覧ください。


※注意※これらの記事は自分用に翻訳したものですので翻訳ミスその他については一切責任は負いません。
また、翻訳も中途半端な状態です。今後修正していきます。(2015/12/16)