LoginSignup
4
3

More than 5 years have passed since last update.

Watson API Text-To-Speechの音声がSafariで再生できない件

Posted at

WebAudio で再生しようとするとAudioContext.decodeAudioDataに失敗する

どうやら、こちらにあるヘッダーの破損が原因の様子。
https://developer.ibm.com/answers/questions/180732/seems-watson-text-to-speech-service-returns-a-wav.html

node.jsでTextToSpeechのwavファイルを取得して, クライアントにレスポンスする処理の例

実際にwavデータを見てみると...

バイナリファイルの先頭から ArrayBuffer として出力してみる

{
"0": 82,   // R
"1": 73,   // I
"2": 70,   // F
"3": 70,   // F
"4": 255,  // (totalDataLen & 0xff);
"5": 255,  // ((totalDataLen >> 8) & 0xff);
"6": 255,  // ((totalDataLen >> 16) & 0xff);
"7": 255,  // ((totalDataLen >> 24) & 0xff);
"8": 87,   // W
"9": 65,   // A
"10": 86,  // V
"11": 69,  // E
"12": 102, // f
"13": 109, // m
"14": 116, // t
"15": 32,  // ' '
"16": 16,  // 4 bytes: size of 'fmt ' chunk
"17": 0,
"18": 0,
"19": 0,
"20": 1,   // format = 1
"21": 0,
"22": 1,   // channels
"23": 0,
"24": 34,  // sampleRate & 0xff
"25": 86,  // sampleRate >> 8) & 0xff
"26": 0,   // sampleRate >> 16) & 0xff
"27": 0,   // sampleRate >> 24) & 0xff
"28": 68,  // byteRate & 0xff
"29": 172, // byteRate >> 8 ) & 0xff
"30": 0,   // byteRate >> 16) & 0xff
"31": 0,   // byteRate >> 24) & 0xff
"32": 2,   // block align
"33": 0,   // 0
"34": 16,  // bits per sample
"35": 0,
"36": 76,  // L
"37": 73,  // I
"38": 83,  // S
"39": 84,  // T
"40": 26,  // totalAudioLen & 0xff = 16x2+6=38byte??
"41": 0,   // totalAudioLen >> 8 & 0xff
"42": 0,   // totalAudioLen >> 16 & 0xff
"43": 0    // totalAudioLen >> 24 & 0xff
}

長さ部分の表示が、、明らかに違う.. 全部255で埋まっている... (実際にデータは数KB)
36-39 は "data" が入る想定だが,実際には "LIST" と入っている.

結果的に以下のように, ヘッダーを入れ替える関数を用意して、処理する.

var buffer = getBufferWithFixedWavHeader(response);

/**
 * get ArrayBuffer by fixed header data
 * @param data binaryData
 * @return ArrayBuffer
 */
function getBufferWithFixedWavHeader(data){
    var headerSize = 44;
    var metaDataSize = 48;

    var noHeaderLen   = data.length - (headerSize + metaDataSize);
    var totalAudioLen = noHeaderLen;
    var totalDataLen  = noHeaderLen + headerSize - 8;

    var header = new ArrayBuffer(headerSize);
    for(var i = 0; i < headerSize; i++){
        header[i] = data[i];
    }

    // Total Data Length
    header[4] = (totalDataLen & 0xff);
    header[5] = ((totalDataLen >> 8) & 0xff);
    header[6] = ((totalDataLen >> 16) & 0xff);
    header[7] = ((totalDataLen >> 24) & 0xff);
    // data
    header[36] = 100; //'d'
    header[37] = 97;  //'a'
    header[38] = 116; //'t'
    header[39] = 97;  //'a'
    // Total Audio Length
    header[40] = (totalAudioLen & 0xff);
    header[41] = ((totalAudioLen >> 8) & 0xff);
    header[42] = ((totalAudioLen >> 16) & 0xff);
    header[43] = ((totalAudioLen >> 24) & 0xff);

    // join
    var buffer = new ArrayBuffer(headerSize + noHeaderLen);
    // header
    for(var i = 0; i < headerSize; i++){
        buffer[i] = header[i];
    }
    // data
    for(var i = headerSize,j = (headerSize+metaDataSize) ; j < data.length ; i++,j++){
        buffer[i] = data[j];
    }

    return buffer;
}
4
3
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3