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

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

新規登録して質問してみよう
ただいま回答率
85.46%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

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

解決済

1回答

889閲覧

Pythonでコマンド実行した際の出力を,ファイルではなくソースコード内の変数にしたい

Poly_Zeta

総合スコア11

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

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クリップ

投稿2021/06/25 04:00

編集2021/06/25 07:24

環境
RaspberryPi3B+
Python 3.6(だったはず)

現在,次のようにしてAquestalkPiの出力wavを一旦ラズパイに外付けしたUSBに保存し
その後他の関数からファイルを呼び出して利用しています

Python

1os.system('./AquesTalkPi ' + text + ' > /mnt/usb1/output.wav') 2source = discord.FFmpegPCMAudio("/mnt/usb1/output.wav")

この書き出し先をファイルではなく変数にする方法はありませんか?
os.systemはもう利用すべきではなくなっていて,subprocessを利用したほうがいいのは把握しているのですが,どう書いたらいいのかいまいちよくわからず困っています.

AquesTalkPiの使い方について:http://blog-yama.a-quest.com/?eid=970157

以下追記
wavファイルをAquesTalkPiで生成,discord内VCで再生

Pyhton

1async def speakQueueLoop(self,speakQueue): 2 while True: 3 self.playNextQueue.clear() 4 queueTop = await self.speakQueue.get() 5 print(str(list(queueTop.keys())[0])) 6 os.system('./AquesTalkPi ' + str(list(queueTop.keys())[0]) + ' > /mnt/usb1/output.wav') 7 source = discord.FFmpegPCMAudio("/mnt/usb1/output.wav") 8 (list(queueTop.values())[0]).play(source,after=self.toggle_next) 9 await self.playNextQueue.wait() 10 11def toggle_next(self,error): 12 try: 13 self.bot.loop.call_soon_threadsafe(self.playNextQueue.set) 14 except Exception as e: 15 print(e)

queueに追加するコード

Python

1await self.speakQueue.put_nowait({str(message.content):message.guild.voice_client})
teamikl👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

discord を利用という事は非同期処理内のコードでしょうか?
別スレッドなのかどうかで、利用するモジュールが変わってきます。

サブプロセスの出力をプログラム内で直接扱いたい場合は、
subprocess の引数に stdout=PIPE を指定します。

例: 戻り値のstdout属性にデータがバイト列で格納。

python

1>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE) 2CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0, 3stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')
  • stdout=PIPE を指定する場合、subprocess.call は使えません
  • プロセスの完了を待たず、少しずつ読み出しするには低水準APIの Popen を使う。

投稿2021/06/25 07:03

teamikl

総合スコア8664

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

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

Poly_Zeta

2021/06/25 07:20 編集

そうです,非同期内のコードです テキストチャットに書きこまれた文を読み上げるbotを作成しており 読み上げの必要があるものを都度queueに追加, ループでqueueを監視して読み上げています 毎回ファイル生成とUSBへのIOで時間を食っていそうだったのでIOだけでも削れないかと質問しました 実行するコマンドを"./AquesTalkPi 対象テキスト"等に書き換えたとして stdout=PIPEでも出力されるwavを拾って適当な変数に代入できるのでしょうか? ※質問文側にソースコード追記します
teamikl

2021/06/25 08:04

非同期処理の場合は、 - タスク内で asyncio.create_subprocess_exec - run_in_executor 内で subprocess が選択肢ですが、 FFmpegPCMAudio は非同期ストリームを取れるような設計ではないので、 subprocess を直接使う方が良さそうです。 >適当な変数に代入できるのでしょうか? 実行環境が無いので試せませんが、エラー処理は省くと >>> ret = subprocess.run(['./AquesTalkPi', text], stdout=subprocess.PIPE) >>> wav = ret.stdout FFmpegPCMAudio の扱いは解らないので、候補案のみ - pipe=True で標準入力に渡す - io.BytesIO() 等で包んで file-like オブジェクトとして渡す - Popen も受け取れるかどうかは未確認。 もう少し改善できるポイントとしては、 同期処理だと、「wav出力が完了してから」FFmpegへ~なのでラグが少しありますが、 パイプで繋ぐことが出来れば、完了を待たずに次のサブプロセスを開始できます。 低水準API の Popenを使い、wavのデータを少しずつffmpegへ送る事で、省メモリ化も期待できます。 (但し、コードは複雑になり、コードの記述量は増えます) FFmpegAudioの実装 が丁度良さそうな subprocess.Popen stdout=PIPE の利用例 https://github.com/Rapptz/discord.py/blob/3864fb37a0814345913c7ca4fd1978fa5e2ef7e2/discord/player.py#L120
Poly_Zeta

2021/06/25 10:49 編集

PCMAudioについてはここにあります https://discordpy.readthedocs.io/ja/latest/api.html#ffmpegpcmaudio 同期のまま動くようにしようと考え,いくつかの方法を試しました. とりあえずそのまま入れてみて ret = subprocess.run(['./AquesTalkPi', str(list(queueTop.keys())[0])], stdout=subprocess.PIPE) source = discord.FFmpegPCMAudio(ret.stdout,pipe=True) としたところ,source = discord.FFmpegPCMAudio(ret.stdout,pipe=True)の部分について AttributeError: 'bytes' object has no attribute 'fileno' と返されました 次に,BytesIOとwaveを経由させてみて ret = subprocess.run(['./AquesTalkPi', str(list(queueTop.keys())[0])], stdout=subprocess.PIPE) fp=wave.open(BytesIO(ret.stdout)) source = discord.FFmpegPCMAudio(fp.readframes(fp.getnframes()),pipe=True) としても,source = discord.FFmpegPCMAudio(fp.readframes(fp.getnframes()),pipe=True)について AttributeError: 'bytes' object has no attribute 'fileno' と返されます. waveを外して ret = subprocess.run(['./AquesTalkPi', str(list(queueTop.keys())[0])], stdout=subprocess.PIPE) source = discord.FFmpegPCMAudio(BytesIO(ret.stdout)),pipe=True) としたところ,今度はsource = discord.FFmpegPCMAudio(BytesIO(ret.stdout),pipe=True)について io.UnsupportedOperation: fileno と返りました. 以下に書いてあるのはわかるのですが,discord.FFmpegPCMAudio側の問題なのか調べてもよくわかりませんでした... https://github.com/Rapptz/discord.py/issues/5192
teamikl

2021/06/25 11:39

> とりあえずそのまま入れてみて > 次に,BytesIOとwaveを経由させてみて 上2つは明らかに間違いです。 > source = discord.FFmpegPCMAudio(BytesIO(ret.stdout)),pipe=True) は、私の(上のコメントを書いてた時点で)想定していたコードですが、 FFmpegPCMAudioクラス側が subprocessの stdin パラメータに直接渡そうとしているのが問題でした。 (ドキュメントには file-like オブジェクトを取れると書かれてるので、ライブラリ側の問題のようです) discord.FFmpegPCMAudioクラス内で NG: subprocess.Popen(..., stdin=BytesIO(ret.stdout)) 引数が間違い OK: subprocess.Popen(..., stdin=PIPE) の後、communicate() で入力データを渡すのが正解 解決策は、その issue 内コメントのクラスを試してみてください。 バイト型オブジェクトをそのまま渡せるみたいです。 > If anyone needs a solution, use this modified FFmpegPCMAudio class: ~に完全な代替クラスの実装が掲載されてます。 使い方 source = FFmpecPCMAudio(ret.stdout, pipe=True)
Poly_Zeta

2021/06/25 11:49 編集

Popenに変えて試していたら動作しました,最終的には以下のようになりました self.playNextQueue.clear() queueTop = await self.speakQueue.get() ret = subprocess.Popen(['./AquesTalkPi', str(list(queueTop.keys())[0])], stdout=subprocess.PIPE) source = discord.FFmpegPCMAudio(ret.stdout,pipe=True) (list(queueTop.values())[0]).play(source,after=self.toggle_next) await self.playNextQueue.wait() タイトルの質問に関係ない部分まで回答していただきありがとうございます!
teamikl

2021/06/25 12:02

Popen で渡せたのなら、そちらの方が良い解決策です。 ffmpegの環境構築はしてなかったので、予想での回答になりましたが、 後、非同期処理内という事で懸念が一点。 もし、一連の同期処理のラグが問題になるようなら、 run_in_executor でバックグラウンドでの実行を検討してください。 完全に非同期のタスクとして処理したい場合は、FFmpegCPMAudio クラスは使えず、 独自に ffmpeg を asyncio.create_subprocess_exec (内部では subprocess.Popen) を使って呼び出す事になります。 許容できる範囲のラグであれば問題ありませんが、 例えば時報が少しずれたり~等のラグに繋がる事があります。
Poly_Zeta

2021/06/25 13:41

いまのところ応答自体はほぼ気にならない範囲ですが,何らかの原因でそういった点が問題になったら検討します,ありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問