【问题标题】:Send Audio data represent as numpy array from python to Javascript将音频数据表示为从 python 到 Javascript 的 numpy 数组
【发布时间】:2019-12-14 19:51:51
【问题描述】:

我有一个 TTS(文本到语音)系统,它以 numpy 数组形式生成音频,其数据类型为 np.float32。该系统在后台运行,我想将数据从后台传输到前台,以便在某个事件发生时播放。

这个问题的明显解决方案是将音频数据作为wav文件写入磁盘,然后将路径传递给前端播放。这很好用,但出于管理原因,我不想这样做。我只想将音频数据(numpy 数组)传输到前端。

到目前为止,我所做的如下:

后端

text = "Hello"
wav, sr = tts_model.synthesize(text)
data = {"snd", wav.tolist()}
flask_response = app.response_class(response=flask.json.dumps(data),
                                    status=200,
                                    mimetype='application/json' )
# then return flask_response

前端

// gets wav from backend
let arrayData = new Float32Array(wav);
let blob = new Blob([ arrayData ]);
let url = URL.createObjectURL(blob);
let snd = new Audio(url);
snd.play()

这就是我到目前为止所做的,但是 JavaScript 会抛出以下错误:

Uncaught (in promise) DOMException: Failed to load because no supported source was found.

这是我正在尝试做的事情的要点。很抱歉,由于您没有 TTS 系统,因此无法重现错误,所以这是由它生成的 audio file,您可以使用它来查看我做错了什么。

我尝试过的其他事情:

  • 将音频数据类型更改为np.int8np.int16,以便分别由Int8Array()int16Array() 在JavaScript 中进行转换。
  • 在创建blob 时尝试了不同的类型,例如{"type": "application/text;charset=utf-8;"}{"type": "audio/ogg; codecs=opus;"}

我已经在这个问题上苦苦挣扎了这么久,所以任何帮助都会得到帮助!

【问题讨论】:

  • 从我记得的 tts 中,他们发送了一个 base64 buf,你试过这样做吗?
  • 不,数据是在numpy中返回的,所以你知道如何将numpy转换为base64缓冲区...我会google一下,但也许你有更快的答案
  • 我已经尝试使用base64.b64encode(wav)。在前端,我使用了let snd = new Audio("data:base64," + path;);,但它不起作用。我试过data:audio/ogg;base64," + path;data:audio/wav;base64," + path; 也没有用。

标签: javascript python-3.x numpy flask html5-audio


【解决方案1】:

将值的 wav 数组转换为字节

合成后,您可以将 wav 的 numpy 数组转换为字节对象,然后通过 base64 进行编码。

import io
from scipy.io.wavfile import write

bytes_wav = bytes()
byte_io = io.BytesIO(bytes_wav)
write(byte_io, sr, wav)
wav_bytes = byte_io.read()

audio_data = base64.b64encode(wav_bytes).decode('UTF-8')

这可以直接用来创建html音频标签作为源(带flask):

<audio controls src="data:audio/wav;base64, {{ audio_data }}"></audio>

因此,您只需将wavsr 转换为代表原始.wav 文件的audio_data。并作为 render_template 的参数用于您的烧瓶应用程序。 (不发送解决)

或者如果您发送audio_data,在您接受响应的.js 文件中,使用audio_data 构造url(将被放置为src 属性,就像在html 中一样):

// get audio_data from response

let snd = new Audio("data:audio/wav;base64, " + audio_data);
snd.play()

因为:

Audio(url) 返回值: 一个新的 HTMLAudioElement 对象,配置为用于从 url 指定的文件播放音频。新对象的 preload 属性设置为 auto 并且 其 src 属性设置为指定的 URL 或 null 如果没有给出 URL。如果指定了 URL,浏览器会在返回新对象之前开始异步加载媒体资源。

【讨论】:

    【解决方案2】:

    您的样品不能开箱即用。 (不玩)

    但是:

    • StarWars3.wav:好的。取自cs.uic.edu
    • 您的样本编码为 PCM16 而不是 PCM32:好的(检查 wav 元数据)

    烧瓶

    from flask import Flask, render_template, json
    import base64
    
    app = Flask(__name__)
    
    with open("sample_16.wav", "rb") as binary_file:
        # Read the whole file at once
        data = binary_file.read()
        wav_file = base64.b64encode(data).decode('UTF-8')
    
    @app.route('/wav')
    def hello_world():
        data = {"snd": wav_file}
        res = app.response_class(response=json.dumps(data),
            status=200,
            mimetype='application/json')
        return res
    
    @app.route('/')
    def stat():
        return render_template('index.html')
    
    if __name__ == '__main__':
        app.run(debug = True)
    

    js

    
      <audio controls></audio>
      <script>
        ;(async _ => {
          const res = await fetch('/wav')
          let {snd: b64buf} = await res.json()
          document.querySelector('audio').src="data:audio/wav;base64, "+b64buf;
        })()
      </script>
    

    原始海报编辑

    所以,我之前(使用此解决方案)解决我的问题的最终做法是:

    • 首先,将数据类型从np.float32更改为np.int16
    wav = (wav * np.iinfo(np.int16).max).astype(np.int16)
    
    • 使用scipy.io.wavfile将numpy数组写入临时wav文件:
    from scipy.io import wavfile
    wavfile.write(".tmp.wav", sr, wav)
    
    • 从 tmp 文件中读取字节:
    # read the bytes
    with open(".tmp.wav", "rb") as fin:
        wav = fin.read()
    
    • 删除临时文件
    import os
    os.remove(".tmp.wav")
    

    【讨论】:

      猜你喜欢
      • 2022-10-25
      • 2017-02-04
      • 2014-09-18
      • 2017-07-21
      • 2017-02-13
      • 2023-03-06
      • 2017-12-20
      • 2019-05-07
      • 2019-11-08
      相关资源
      最近更新 更多