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

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

ただいまの
回答率

90.51%

  • Python

    11741questions

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

  • Linux

    4438questions

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

  • Raspberry Pi

    1065questions

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

  • NumPy

    642questions

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

  • CPU

    52questions

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

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,074

 実現したいこと

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

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

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

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

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


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

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


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

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

 試したこと

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

 コメント

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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

0

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

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

 追記

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

conv.c

#include <stdlib.h>

char *result;

char *convert(int n, char *buf){
  int i;

  result = (char *)malloc(sizeof(char)*n);

  for(i=0; i < n; i+=2) {
    result[i] = buf[i+1];
    result[i+1] = buf[i];
  }

  return result;
}

void free_result(void) {
  free(result);
}

コンパイルコマンド

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

conv_test.py

import ctypes

cptr = ctypes.POINTER(ctypes.c_char)
lib = ctypes.cdll.LoadLibrary('./conv.so')
lib.convert.restype = cptr
lib.convert.argtypes = (ctypes.c_int, cptr)

b_input = b'\x00\x01\x02\x03'
n = len(b_input)
result = lib.convert(n, b_input)[:n]
lib.free_result()
print(result)  # => b'\x01\x00\x03\x02'

 追記2

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

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

 追記3

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

#include <stdlib.h>
#include <stdint.h>

char *result;

char *convert(int n, char *buf){
  int i, nh;
  uint16_t *result16, *buf16;

  result16 = (uint16_t *)malloc(sizeof(char)*n);
  buf16 = (uint16_t *)buf;
  nh = n/2;
  for(i=0; i < nh; i++) {
    result16[i] = buf16[i] >> 8 | buf16[i] << 8;
  }

  result = (char *)result16;
  return result;
}

void free_result(void) {
  free(result);
}

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

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

convmod.py

import ctypes

cptr = ctypes.POINTER(ctypes.c_char)
lib = ctypes.cdll.LoadLibrary('./conv.so')
lib.convert.restype = cptr
lib.convert.argtypes = (ctypes.c_int, cptr)

def conv(b_input):
    n = len(b_input)
    result = lib.convert(n, b_input)[:n]
    lib.free_result()
    return result

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/23 18:47

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

    キャンセル

  • 2018/10/23 19:45

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

    キャンセル

  • 2018/10/23 21:07

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

    キャンセル

0

ndarray.byteswap 使ってみるとか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/20 02:20

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

    キャンセル

  • 2018/10/23 18:43

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

    キャンセル

0

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/23 18:39

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

    キャンセル

同じタグがついた質問を見る

  • Python

    11741questions

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

  • Linux

    4438questions

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

  • Raspberry Pi

    1065questions

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

  • NumPy

    642questions

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

  • CPU

    52questions