iT邦幫忙

2024 iThome 鐵人賽

DAY 19
0
生成式 AI

用AI寫程式也是要點本事的系列 第 19

存起來的「生肉」錄音檔無法播放

  • 分享至 

  • xImage
  •  

承上一篇,在下載錄音內容之前,先將它測試性的重播一次吧!

  //播放URL的內容
  void playAudio(String url) {
    final audio = html.AudioElement()
      ..src = url
      ..autoplay = true
      ..play();
  }
  
    //產生本地端URL後丟給上面的函數播放
    final url = html.Url.createObjectUrl(blob);
    print(url);
    playAudio(url);

OK!可以播放,看來「資料」本身是沒問題的!
但是...下載後的檔案無法在其他播放器中播放啊!

這是因為AI寫的程式碼幫我們存起來的是種叫做「raw data」的東西,(因為raw的意思同「生肉」,所以有時後這種資料會被戲稱為「生肉」。)
任何資料(不管是圖檔、文檔、影片、甚至程式本身)在raw data型態看起來都是一樣的!(就是0跟1,)必須要具備特定「格式」的「檔頭」(用非常特殊且固定的順序組成的0跟1)才能「辨識資料的型態」和「知道該用什麼樣的播放器播放」。(這段描述不是很正確,有很多需要修正釐清的細節。)

仔細看一下目前為止完成的所有功能...
存起來的檔案沒有檔頭無誤!

那接下來繼續問AI啦!

「為何檔案無法被外部播放器播放?」

還真告訴我答案啦!

「WAVE檔其實是種格式為PCM的檔案包裝,而PCM又包含了個種RIFF格式的檔案。」講得挺饒舌,但簡單來說就是要取得「PCM」或「RIFF」的檔案格式,或是包裝的辦法。

這裡快轉一下....簡單來說,Flutter上並沒有可靠的、產生PCM格式檔案的功能或是套件,所以想要這樣做就必須要自己幫檔案加上格式化。

那....「有幫raw資料加上PCM/RIFF格式的辦法嗎?」

還真的有!

  ByteData createRiffHeader(int fileSize, int audioFormat, int numChannels, int sampleRate, int byteRate, int blockAlign, int bitsPerSample) {
    var buffer = ByteData(44); // RIFF header size is 44 bytes

    // "RIFF"
    buffer.setUint8(0, 0x52);
    buffer.setUint8(1, 0x49);
    buffer.setUint8(2, 0x46);
    buffer.setUint8(3, 0x46);

    // File size
    buffer.setUint32(4, fileSize, Endian.little);

    // "WAVE"
    buffer.setUint8(8, 0x57);
    buffer.setUint8(9, 0x41);
    buffer.setUint8(10, 0x56);
    buffer.setUint8(11, 0x45);

    // "fmt "
    buffer.setUint8(12, 0x66);
    buffer.setUint8(13, 0x6d);
    buffer.setUint8(14, 0x74);
    buffer.setUint8(15, 0x20);

    // Subchunk size
    buffer.setUint32(16, 16, Endian.little);

    // Audio format
    buffer.setUint16(20, audioFormat, Endian.little);

    // Number of channels
    buffer.setUint16(22, numChannels, Endian.little);

    // Sample rate
    buffer.setUint32(24, sampleRate, Endian.little);

    // Byte rate
    buffer.setUint32(28, byteRate, Endian.little);

    // Block align
    buffer.setUint16(32, blockAlign, Endian.little);

    // Bits per sample
    buffer.setUint16(34, bitsPerSample, Endian.little);

    // "data"
    buffer.setUint8(36, 0x64);
    buffer.setUint8(37, 0x61);
    buffer.setUint8(38, 0x74);
    buffer.setUint8(39, 0x61);

    // Subchunk size
    buffer.setUint32(40, fileSize - 36, Endian.little);

    return buffer;
  }

要使用這個函數,就必須要取得「Audio format」「Number of channels」「Sample rate」「Byte rate」「Block align」「Bits per sample」等資料....

去哪取啊????

繼續...啊!不!明天待續!


上一篇
如何存檔
下一篇
音檔,除了格式檔頭以外,的各種學問...
系列文
用AI寫程式也是要點本事的30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言