Open JTalk mpg123

Open JTalkの出力したwavをmpg123で再生したらエラー出た。

[src/libmpg123/layer1.c:30] error: Illegal bit allocation value.
[src/libmpg123/layer1.c:171] error: Aborting layer I decoding after step one.

ffmpegでmp3に変換して再生するとok。mpg123では同じくエラーで変換できなかった。

ffmpeg -i b.wav b.mp3
mpg123 b.mp3

ffmpegのinfo

Guessed Channel Layout for Input Stream #0.0 : mono
Input #0, wav, from 'b.wav':
  Duration: 00:00:01.17, bitrate: 768 kb/s
    Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 48000 Hz, mono, s16, 768 kb/s
Input #0, mp3, from 'b.mp3':
  Metadata:
    encoder         : Lavf57.56.101
  Duration: 00:00:01.20, start: 0.023021, bitrate: 65 kb/s
    Stream #0:0: Audio: mp3, 48000 Hz, mono, s16p, 64 kb/s
ffmpeg -i b.wav c.wav

これもダメ

Guessed Channel Layout for Input Stream #0.0 : mono
Input #0, wav, from 'c.wav':
  Metadata:
    encoder         : Lavf57.56.101
  Duration: 00:00:01.17, bitrate: 768 kb/s
    Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 48000 Hz, mono, s16, 768 kb/s
ffmpeg -i b.mp3 d.wav

これもダメ

Guessed Channel Layout for Input Stream #0.0 : mono
Input #0, wav, from 'd.wav':
  Metadata:
    encoder         : Lavf57.56.101
  Duration: 00:00:01.17, bitrate: 768 kb/s
    Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 48000 Hz, mono, s16, 768 kb/s
ffmpeg -i b.wav -ac 2 e.wav

ステレオにしてみたけどこれもダメ

Guessed Channel Layout for Input Stream #0.0 : stereo
Input #0, wav, from 'e.wav':
  Metadata:
    encoder         : Lavf57.56.101
  Duration: 00:00:01.17, bitrate: 1536 kb/s
    Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 48000 Hz, stereo, s16, 1536 kb/s

うーん...

import subprocess

p = subprocess.Popen('open_jtalk -x /var/lib/mecab/dic/open-jtalk/naist-jdic -m mei/mei_normal.htsvoice -r 1.0 -ow /dev/stdout', stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)

text = msg
out, _ = p.communicate(text.encode('utf-8'))
wav = out

p = subprocess.Popen('ffmpeg -i pipe:0 -f mp3 pipe:1', stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
out, _ = p.communicate(wav)

sound = out

p = subprocess.Popen('mpg123 -', stdin=subprocess.PIPE, shell=True)
p.communicate(sound)

Open JTalk

Open JTalk

# Open JTalk Test
# python3
# exec `apt install open-jtalk open-jtalk-mecab-naist-jdic`
# get `mei_normal.htsvoice` from http://www.mmdagent.jp/

import subprocess

p = subprocess.Popen('open_jtalk -x /var/lib/mecab/dic/open-jtalk/naist-jdic -m mei/mei_normal.htsvoice -r 1.0 -ow /dev/stdout', stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)

text = 'こんにちは'
out, err = p.communicate(text.encode('utf-8'))

print(text)
print(err)

# outにwavのバイナリが入ってる。必要に応じてここ変えてね
with open('b.wav', 'wb') as fp:
    fp.write(out)

See

  • mpg123

Java 11

あんまり分かってないけど、とりあえずJRE付きでエクスポートまではできた。

Java 9以降のこと

これまでの実行可能Jar

  • Javaランタイム(JRE)を同梱しなくても、システムにインストールされたPublic JREで実行できた

これから

  • システムにJREがない
  • 同様に実行できるようにするには、JREをアプリケーションに同梱する必要がある(?)
    • これまでもrt.jarJREの同梱された形としてあったはず

Jigsawモジュールシステム

Java 9以降導入されたJavaの依存関係システム。

依存関係はmodule-info.javaファイルに記述する。

module sample.module {
    requires java.base; // 不要(省略可)
}

実行可能Jarのエクスポート(MavenJREなし)

Java 8まで、こんな感じだった。

Maven pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example.sample</groupId>
    <artifactId>Sample</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>8</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.1.1</version>

                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>com.example.sample.Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

JREの生成(手動、module-info使用)

コンパイルしたクラスファイルのディレクトリを指定

jlink --module-path './classes;JDK_DIRECTORY/jmods' --add-modules sample.module --output jre

Jarを指定

jlink --module-path './sample.jar;JDK_DIRECTORY/jmods' --add-modules sample.module --output jre

圧縮

-c 2

起動用スクリプトも生成してくれる。

--launcher mycmd=sample.module/com.example.sample.Main

OpenJDK 11.0.1 (Windows)で実行すると、dll, exe, ランチャーシェルスクリプト, bat他が生成された。OpenJDKの中身を絞って移してきてる? 複数OS想定する場合、JREはOS別に作る必要があるのか? それとも別の方法があるのか。

実行可能Jarのエクスポート(MavenJREあり、ランチャー)

上の処理を自動化してくれるプラグインを使う。

ant-runの部分はjlinkツールが出力ディレクトリを上書きしてくれないので、packageを実行するごとに削除させるため。手動で消すかcleanすれば不要。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example.sample</groupId>
    <artifactId>Sample</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>11</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
    </properties>

    <build>
        <plugins>
            <!-- https://mvnrepository.com/artifact/org.moditect/moditect-maven-plugin -->
            <plugin>
                <groupId>org.moditect</groupId>
                <artifactId>moditect-maven-plugin</artifactId>
                <version>1.0.0.Beta2</version>
                <executions>
                    <execution>
                        <id>create-runtime-image</id>
                        <phase>package</phase>
                        <goals>
                            <goal>create-runtime-image</goal>
                        </goals>
                        <configuration>
                            <compression>2</compression>
                            <modulePath>
                                <path>${project.build.outputDirectory}</path>
                            </modulePath>
                            <modules>
                                <module>sample.module</module>
                            </modules>
                            <launcher>
                                <name>Sample</name>
                                <module>sample.module/com.example.sample.Main</module>
                            </launcher>
                            <outputDirectory>
                                ${project.build.directory}/jlink
                            </outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-antrun-plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.8</version>
                <executions>
                    <execution>
                        <phase>initialize</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <target>
                                <delete dir="${project.build.directory}/jlink" quiet="true" />
                            </target>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

ただ、この方法だとjarファイルが見当たらない。たぶんruntimeも自分のプログラムも混ざってどこかに入ってる。外部jarを混ぜずに読み込む方法もわからない。

JREの生成(手動、Jar使用)

module-infoを使わない方法(使わないでいいのかは分からないけど)。

jdeps --list-deps JARファイルmodule-infoのないJARの依存するモジュールリストが出力される。

このリストをもとに下のコマンドでJREを生成すれば混ざることはないはず。

jlink -c 2 -p 'JDK_DIRECTORY/jmods' -m モジュールカンマ区切りリスト --output jre

生成されたjava実行ファイルに対してjava -jar JARファイルするスクリプトを書けば外にjarを置ける。

外部Jarライブラリをlibsディレクトリに置く、というのを次はやりたい。今まで通りクラスパスに追加して、JREだけ上の方法で生成する、実行はスクリプトから、は正解じゃない気がするので、どうすればいいのか。それから、Launch4j使いたい場合?

json, bson, sqlite3 IOの実験メモ

import json
import random
import time

file = 'test.tmp'
N = 500

# Generate
start = time.time()
entries = []
for i in range(N):
    title = ''.join([ chr(random.randint(ord('あ'), ord('ん')+1)) for i in range(32) ])
    body = ''.join([ chr(random.randint(ord('あ'), ord('ん')+1)) for i in range(30000) ])
    entries.append({
        'id': i,
        'title': title,
        'body': body,
    })

data = {
    'entries': entries,
}

end = time.time()
print('Generate: %.1fs' % (end - start, ))
Generate: 38.6s
import os

# Write
start = time.time()
with open(file, 'w', encoding='utf-8') as fp:
    json.dump(data, fp, ensure_ascii=False)

end = time.time()
print('Write: %.3fs' % (end - start, ))

print('%.2fMB' % (os.path.getsize(file)/(1024**2), ))

# Read
start = time.time()
with open(file, 'r', encoding='utf-8') as fp:
    data = json.load(fp)

end = time.time()
print('Read: %.3fs' % (end - start, ))
Write: 0.252s
42.98MB
Read: 0.214s

pip install bson

import bson

# Write
start = time.time()
s = bson.dumps(data)
print('%.2fMB' % (len(s)/(1024**2), ))

dumpEnd = time.time()

with open(file, 'wb') as fp:
    fp.write(s)

end = time.time()

print('Write: %.3fs (Dump: %.3fs)' % (end - start, dumpEnd - start))


# Read
start = time.time()

with open(file, 'rb') as fp:
    s = fp.read()

loadStart = time.time()

data = bson.loads(s)
end = time.time()

print('Read: %.3fs (Load: %.3fs)' % (end - start, end - loadStart))
42.98MB
Write: 0.830s (Dump: 0.638s)
Read: 0.156s (Load: 0.095s)
import sqlite3

if os.path.exists(file):
    os.unlink(file)

start = time.time()
with sqlite3.connect(file) as db:
    cur = db.cursor()

    cur.execute('CREATE TABLE entries(id INTEGER AUTO INCREMENT, title TEXT, body TEXT)')
    for entry in data['entries']:
        cur.execute('INSERT INTO entries VALUES(?,?,?)', (entry['id'], entry['title'], entry['body'], ))
    
end = time.time()

print('Write: %.3fs' % (end - start, ))

start = time.time()
with sqlite3.connect(file) as db:
    cur = db.cursor()

    results = []
    for row in cur.execute('SELECT * FROM entries'):
        results.append(row)

end = time.time()

print('Read: %.3fs' % (end - start, ))


print('%.2fMB' % (os.path.getsize(file)/(1024**2), ))

db.close()
Write: 1.093s
Read: 0.243s
43.22MB

HOG特徴量の計算(Scikit-image)

pip install scikit-image

from skimage.feature import hog
import numpy as np

size = 32
channel = 1
image = np.random.randn(size, size, channel)
feature = hog(image)

print(feature.shape)
print(feature)

デフォルト(勾配方向数9, セルサイズ8, ブロックサイズ3)では32x32の画像に対して324次元のHOG特徴量が出力される。

出力例

(324,)
[0.01877925 0.00125122 0.00899619 0.00630656 0.01330613 0.0150924
...
0.00763393 0.01668535 0.01852621 0.01204107 0.00433798 0.01147866]

ドキュメント: http://scikit-image.org/docs/dev/api/skimage.feature.html#skimage.feature.hog

PythonからPaSoRiを使って交通系ICカードのIDmを読む

環境

セットアップ

まずPaSoRiを接続する。PaSoRiをUSBポートに挿して、VirtualBox仮想マシンの設定からUSB、USB デバイスフィルターにSONY RC-S380/Pを追加。

$ lsusb
Bus 001 Device 004: ID 054c:06c3 Sony Corp.
...

これでOK。

次にnfcpyのインストール(※Python2に導入すること、virtualenvを使うといいのでは)。

pip install nfcpy

いくらか準備が必要なので、python -m nfcを実行する。

$ python -m nfc
No handlers could be found for logger "nfc.llcp.sec"
This is the 0.13.5 version of nfcpy run in Python 2.7.15rc1
on Linux-4.15.0-33-generic-x86_64-with-Ubuntu-18.04-bionic
I'm now searching your system for contactless devices
** found usb:054c:06c3 at usb:001:004 but access is denied
-- the device is owned by 'root' but you are 'USERNAME'
-- also members of the 'root' group would be permitted
-- you could use 'sudo' but this is not recommended
-- better assign the device to the 'plugdev' group
   sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"054c\", ATTRS{idProduct}==\"06c3\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules'
   sudo udevadm control -R # then re-attach device
I'm not trying serial devices because you haven't told me
-- add the option '--search-tty' to have me looking
-- but beware that this may break other serial devs
Sorry, but I couldn't find any contactless device

一般ユーザーの場合こんなメッセージが出るので、指示通りデバイスplugdevグループに割り当てる。

sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"054c\", ATTRS{idProduct}==\"06c3\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules'

/etc/udev/rules.d/nfcdev.rulesはこうなる。

SUBSYSTEM=="usb", ACTION=="add", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="06c3", GROUP="plugdev"
...

下のコマンドはリロード、のはずだが、うまく動かないのでPaSoRiを抜き差しする(VirtualBoxのメニューからでも、ホストからでも)。

sudo udevadm control -R

もう一度チェックするとメッセージが変わる。

$ python -m nfc
No handlers could be found for logger "nfc.llcp.sec"
This is the 0.13.5 version of nfcpy run in Python 2.7.15rc1
on Linux-4.15.0-33-generic-x86_64-with-Ubuntu-18.04-bionic
I'm now searching your system for contactless devices
** found usb:054c:06c3 at usb:001:005 but it's already used
-- scan sysfs entry at '/sys/bus/usb/devices/1-2:1.0/'
-- the device is used by the 'port100' kernel driver
-- this kernel driver belongs to the linux nfc subsystem
-- you can remove it to free the device for this session
   sudo modprobe -r port100
-- and blacklist the driver to prevent loading next time
   sudo sh -c 'echo blacklist port100 >> /etc/modprobe.d/blacklist-nfc.conf'
I'm not trying serial devices because you haven't told me
-- add the option '--search-tty' to have me looking
-- but beware that this may break other serial devs
Sorry, but I couldn't find any contactless device
sudo modprobe -r port100

でport100なるドライバが止まり、動くようになる。

sudo sh -c 'echo blacklist port100 >> /etc/modprobe.d/blacklist-nfc.conf'

これで次回起動以降、port100が起動しなくなるのかな。

port100を止めたらもう一度チェック。

$ python -m nfc
No handlers could be found for logger "nfc.llcp.sec"
This is the 0.13.5 version of nfcpy run in Python 2.7.15rc1
on Linux-4.15.0-33-generic-x86_64-with-Ubuntu-18.04-bionic
I'm now searching your system for contactless devices
** found SONY RC-S380/P NFC Port-100 v1.11 at usb:001:005
I'm not trying serial devices because you haven't told me
-- add the option '--search-tty' to have me looking
-- but beware that this may break other serial devs

ちゃんと見つかったらOK。

IDmを読む

短いサンプルコード。

nf.py

import nfc
from nfc.clf import RemoteTarget

clf = nfc.ContactlessFrontend('usb')
print(clf)

tag = clf.connect(rdwr={
    'on-connect': lambda tag: False
})

print(tag)

ICカードがない場合、以下の出力の後(clf.connectで)ブロックされる。

$ python nf.py
No handlers could be found for logger "nfc.llcp.sec"
SONY RC-S380/P on usb:001:005

ここでICカードを近づけると、タグが出力(print(tag))される。

$ python nf.py
No handlers could be found for logger "nfc.llcp.sec"
SONY RC-S380/P on usb:001:005
Type3Tag ID=$$$$$$$$$$$$$$$$ PMM=$$$$$$$$$$$$$$$$ SYS=0003
>>> print(type(tag))
<class 'nfc.tag.tt3.Type3Tag'>
>>> 
>>> print(vars(tag)).keys())
['_clf', '_target', 'sys', 'idm', '_ndef', 'pmm', '_nfcid', '_authenticated']

tag.idmを使えばIDmが取れそうなのでOK。

参考




SSD換装時のOS移動(スケールダウン)

容量の小さなSSDに換装する(HDD 500GBからSSD 250GB)。

  1. 対象のHDD, SSD以外でUbuntuを起動(USBブートなど)
  2. GPartedで必要なパーティションをHDDからSSDにコピー(Boot, OSとか)
  3. コピー先でパーティションを右クリック、Manage Flagsからコピー元のパーティションとFlagsを一致させる
  4. Ubuntuとのデュアルブートにしていたため、EFIをマウントして"ubuntu"を削除