質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
CPU

CPUは、コンピュータの中心となる処理装置(プロセッサ)で中央処理装置とも呼ばれています。プログラム演算や数値計算、その他の演算ユニットをコントロール。スマホやPCによって内蔵されているCPUは異なりますが、処理性能が早いほど良いとされています。

NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

3853閲覧

pythonで高速にエンディアン変換したい

masayasasaki96

総合スコア19

CPU

CPUは、コンピュータの中心となる処理装置(プロセッサ)で中央処理装置とも呼ばれています。プログラム演算や数値計算、その他の演算ユニットをコントロール。スマホやPCによって内蔵されているCPUは異なりますが、処理性能が早いほど良いとされています。

NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

1グッド

1クリップ

投稿2018/10/19 14:56

編集2018/10/23 09:44

実現したいこと

Pythonでエンディアン変換をできるだけ高速に行いたいです。

現在、pyaudioで音声を再生するプログラムを作成しています。
再生したいデータは、リニアPCM(ビッグエンディアン 16bit)です。

以前はこれをWAVEファイルとして保存したものを再生していましたが、処理に時間がかかってしまい都合が悪く、そのまま再生する方法を検討しています。しかし、元データと再生側(Raspberry Pi)でのバイトオーダが異なるため変換が必要な状況です。

そこで、ビッグエンディアンのバイト列を、16ビット単位でリトルエンディアンに変換する方法を模索しておりますが、より高速に行う方法はないでしょうか。。

Python

1big = b'\x00\x01\x02\x03 ......' # 音声データのためバイト列の長さは不定です 2little = byteSwap(big) # ここの処理を実装したいです 3print(little) 45b'\x01\x00\x03\x02 ......' # 16bit単位でエンディアン変換されたバイト列です

欲しい出力は、次のいずれかです。

b'リトルエンディアンに変換されたバイト列: [16単位] or [全部一気に] or [1024バイト単位(?)]'

最終的な目的は、音声を再生することですので、次のような処理を行うことです。

Python

1# これはpyaudioで再生する部分です。 2# どのデータ単位で出力するのがいいかの比較のため上記の3種類試してみたいと考えております。 3stream.write(b'ここに変換したバイト列を入れると再生されます')

試したこと

  1. numpyのfrombuffer()を利用し、まず16bitずつ配列に格納。その後、要素ごとに取り出し8bitをスワップしてb''.join()によりバイト列としてstream.write()に渡す。
  2. 1を改良し、frombuffer()の引数でバイトオーダを指定して16bitずつ格納。これをtobytes()を使用してstream.write()に渡す。

コメント

  • 色々と試した結果、tobytes()に時間がかかっていると思われます。。
  • structモジュールを使用できないでしょか。。
  • ndarrayに変換せず、 b'ビッグエンディアン' をそのまま b'リトルエンディアン' にできれば嬉しいです。

何か良い情報をご存知の方、どうぞよろしくお願いいたします。

set0gut1👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

numpy ライブラリの np.fromfile にエンディアン指定でバイナリファイルを読み込む、という機能があるようですね。
書き込む方にないのでどうやって指定するかはわかりませんが、numpyなら高速な部類に入るのではないでしょうか。

投稿2018/10/19 17:19

mather

総合スコア6753

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

masayasasaki96

2018/10/23 09:39

matherさん、ご回答ありがとうございます! 書き込みがあれば使えそうでしたが.. 検討してみます。ありがとうございます!
guest

0

ndarray.byteswap 使ってみるとか。

投稿2018/10/19 17:18

daisuke7

総合スコア1563

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

daisuke7

2018/10/19 17:20

あぁ、ndarrayにはしたくないのですね、、
masayasasaki96

2018/10/23 09:43

daisuke7さん、ご回答くださりありがとうございます。 以前はタプルでやっていましたが、byteswapの方が良さそうです^ ^ ありがとうございます!
guest

0

ベストアンサー

高速性を重視するなら、Cで書いてpythonからwrapして使うというのはどうでしょうか。

16.16. ctypes — Pythonのための外部関数ライブラリ — Python 3.6.5 ドキュメント

追記

書いてみました。私もctypesには慣れていないので、確実な動作は保証しません。変なところがあれば、極力修正はするつもりです。

conv.c

C

1#include <stdlib.h> 2 3char *result; 4 5char *convert(int n, char *buf){ 6 int i; 7 8 result = (char *)malloc(sizeof(char)*n); 9 10 for(i=0; i < n; i+=2) { 11 result[i] = buf[i+1]; 12 result[i+1] = buf[i]; 13 } 14 15 return result; 16} 17 18void free_result(void) { 19 free(result); 20}

コンパイルコマンド

$ gcc -shared -fPIC conv.c -o conv.so

conv_test.py

python

1import ctypes 2 3cptr = ctypes.POINTER(ctypes.c_char) 4lib = ctypes.cdll.LoadLibrary('./conv.so') 5lib.convert.restype = cptr 6lib.convert.argtypes = (ctypes.c_int, cptr) 7 8b_input = b'\x00\x01\x02\x03' 9n = len(b_input) 10result = lib.convert(n, b_input)[:n] 11lib.free_result() 12print(result) # => b'\x01\x00\x03\x02'

追記2

python

1def conv_np(b_input): 2 npa = np.frombuffer(b_input, dtype=np.int16).copy() 3 return npa.byteswap(inplace=True).tobytes()

こんなのと速度を比較したら、顕著な速度差がなかったことを申し添えておきます。悲しい。

追記3

ビットシフトで書き直して、なんとかnumpyより速くなりました。

C

1#include <stdlib.h> 2#include <stdint.h> 3 4char *result; 5 6char *convert(int n, char *buf){ 7 int i, nh; 8 uint16_t *result16, *buf16; 9 10 result16 = (uint16_t *)malloc(sizeof(char)*n); 11 buf16 = (uint16_t *)buf; 12 nh = n/2; 13 for(i=0; i < nh; i++) { 14 result16[i] = buf16[i] >> 8 | buf16[i] << 8; 15 } 16 17 result = (char *)result16; 18 return result; 19} 20 21void free_result(void) { 22 free(result); 23}

ただpythonオブジェクトへの変換に相当のオーバーヘッドがあるようですね。

あと、インターフェースを多少整えました。

convmod.py

python

1import ctypes 2 3cptr = ctypes.POINTER(ctypes.c_char) 4lib = ctypes.cdll.LoadLibrary('./conv.so') 5lib.convert.restype = cptr 6lib.convert.argtypes = (ctypes.c_int, cptr) 7 8def conv(b_input): 9 n = len(b_input) 10 result = lib.convert(n, b_input)[:n] 11 lib.free_result() 12 return result

投稿2018/10/19 15:24

編集2018/10/19 18:37
hayataka2049

総合スコア30933

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

masayasasaki96

2018/10/23 09:47

hayataka2049さん、詳しくご回答くださりありがとうございます!! ctypesは使ったことがなかったので、今後改善のために試してみたいと思います! ご丁寧にありがとうございましたm(_ _)m
hayataka2049

2018/10/23 10:45

CPUのアーキテクチャによりますが、一度に32bitや64bitずつ変換するようにすると高速化されるかもしれません
masayasasaki96

2018/10/23 12:07

そうですか^^ 色々と試してみたいと思います。本当にありがとうございます!! またよろしくお願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問