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

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

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

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Q&A

1回答

547閲覧

サンプルレートを変えた際にノイズが入る

lkl191

総合スコア14

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

0グッド

0クリップ

投稿2023/03/02 05:25

実現したいこと

Go言語で音声ファイルを読み込んでサンプルレートを48000から8000に変更してchunkで送信したい。

前提

Go言語で音声ファイルを読み込んでその音声をchunkで送信したいのですが、その際にchunkごとにサンプルレートを変更して送信しています。
そうすると、時々ノイズが入ったり音声が二重に聞こえたりします。

Go

1import "github.com/zaf/resample" 2 3var buf bytes.Buffer 4res, err := resample.New(&buf, float64(48000), float64(8000), 1, resample.I16, resample.HighQ)

上記のchunkごとにサンプルレートを変更せずに読み込んだデータのサンプルレートを一気に変更して送信すると問題なく聞き取れます。

おそらくchunkごとにサンプルレートを変更する際に最後の方のデータが抜け落ちて、次に来る音声とうまく噛み合わないのかもしれません。この場合だとサンプルレートを48000から8000に変更する際にどのようにchunkを区切るのが良いのでしょうか?

もしくは他に原因があるのでしょうか?

https://github.com/zaf/resample

サンプルレートの変更には上記のライブラリを使っていますが、他にGo言語でサンプルレートを変更する良い方法があれば教えてくださると幸いです。

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

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

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

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

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

kikukiku

2023/03/02 05:44

おそらくですが、 音声の存在する部分で区切った上でサンプルレートを下げると 発生する場合があるのだと思います。 よって、先に区切りたいのであるならば音声がない部分で区切る必要があると思います。 音声のある部分でも区切りたいのであれば、 一気に変換した結果を区切れば、良いと思います。
kikukiku

2023/03/02 05:52

音声がある部分でも区切った上でサンプルレートを下げることも理論上はできます。 その場合、区切る部分に音声がないようにするために、窓関数(フィルタ)をかけた上で サンプルレートを下げることになりますが、当然音は劣化する可能性があります。
kikukiku

2023/03/02 05:54

なぜ音がある部分で区切ると、ノイズが入るかの説明はできますが 音声処理の基礎知識がないと理解できないため、ここでは説明しません。
kikukiku

2023/03/02 05:56

ちなみに、サンプルレートを下げるだけでも、音声は劣化します。 高音が表現できなくなります。
lkl191

2023/03/02 07:40

コメントありがとうございます。 では、音声のない部分というのはどのように判断すれば良いのでしょうか?
kikukiku

2023/03/02 07:57

当方は、Go言語の専門家ではなく、音声処理の専門家になります。 よって、具体的なプログラムの話に関してはアドバイスできません。 他の方の回答を待ってください。 音声のない部分を探すライブラリなどを探してみてはどうでしょうか? また、一気にサンプルレートを下げてから分割すれば問題ないと 思うのでこちらで実装してみたらどうでしょう。
kikukiku

2023/03/02 08:09

無音検出のアルゴリズムとしては、音声のパワーを計算し、一定時間しきい値以下が 続いたらその区間が無音であると判定すれば良いと思います。 ※しきい値は背景音があった場合の対処として必要です。
guest

回答1

0

リサンプルですがその組み合わせ限定ですが6個ずつの平均値に変換するという手もあります。
(もちろん、6個未満のデータは次のデータが読めるところまで持ち越すという処理は必要です)

追記

区切り方を質問されていますが、はっきり言って(音声処理のプロでも苦労するほど)難関過ぎて区切るのはお勧めしません。
一通りの処理が終わるまでストリーミングを「区切らない」が正解です。

Resamplerも入力も出力も一度インスタンスを作ったら、一通りのデータ処理が終わるまで使いまわしましょう。

また、chunkedエンコードのことを言っているのならGoのサーバーはContent-Lengthを付けないようにしつつレスポンス全体の処理を繰り返しResponseWriterに書き込むことで自動的にchunkedエンコードでレスポンスを組み立ててくれます。

あと以下のコードが部分バッファ書き出しごとにあるとよいでしょう。

go

1if flusher, ok := w.(http.Flusher); ok { 2 flusher.Flush() 3}

実例追記

このようにまとめてレスポンスを返すように組むと、chunkedエンコーディングでレスポンスが返る事を確認できましたし、ノイズもありませんでした。

https://go.dev/play/p/qkKllEZQH2r

go

1package main 2 3import ( 4 "fmt" 5 "io" 6 "log" 7 "net/http" 8 "os" 9 10 "github.com/zaf/resample" 11) 12 13func index(w http.ResponseWriter, r *http.Request) { 14 fmt.Fprintln(w, "index") 15} 16 17func handler(w http.ResponseWriter, r *http.Request) { 18 input, err := os.Open("OUTPUT.raw") 19 if err != nil { 20 log.Print(err) 21 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 22 return 23 } 24 res, err := resample.New(w, float64(48000), float64(8000), 1, resample.I16, resample.HighQ) 25 if err != nil { 26 log.Print(err) 27 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) 28 return 29 } 30 io.Copy(res, input) 31} 32 33func main() { 34 http.HandleFunc("/", index) 35 http.HandleFunc("/audio", handler) 36 if err := http.ListenAndServe(":8080", nil); err != nil { 37 log.Fatal(err) 38 } 39}

投稿2023/03/06 13:57

編集2023/03/07 02:04
nobonobo

総合スコア3367

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

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

nobonobo

2023/03/07 02:11

もしかするとHTTPサーバーは関係ないのかもしれませんが。 送信や受信がどういった対象間で行いたいものか説明を頂ければそれに対応できるかと思います。 ただ、音声データの扱いは連続性が重要です。勝手に切ったりする戦略が使えるのはかなり限定的です。 上記の部分チャンクを採りたいなら自作のio.WriterをResamplerに渡すとよいでしょう。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.44%

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

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

質問する

関連した質問