JS Download File.

JavaScript create file download to local.

by Tinytsunami

HTML

<div id="demo">
  <table>
    <tr>
      <th>檔案名稱</th>
      <td>
        <input type="text" value="wave" />
      </td>
    </tr>
    <tr>
      <th>聲波 t 函數</th>
      <td>
        <input type="text" value="32767 * Math.cos(t)" />
      </td>
    </tr>
    <tr>
      <th>時間 s 秒</th>
      <td>
        <input type="number" value="3" />
      </td>
    </tr>
    <tr>
      <td colspan="2">
        <button>下載</button>
      </td>
    </tr>
  </table>
  <div>

CSS

body {
  color: #ffffff;
  background: #20262e;
  font-family: monospace, sans-serif;
}

#demo {
  padding: 5px;
}

#demo table {
  width: 340px;
}

#demo table th {
  width: 90px;
}

#demo table td {
  width: 140px;
}

#demo input {
  width: calc(100% - 5px);
  color: #ffffff;
  background: #20262e;
  outline: none;
  border: none;
  border-bottom: 1px solid #ffffff;
}

#demo button {
  width: calc(100% - 20px);
  height: 24px;
  color: #ffffff;
  background: #20262e;
  border: 1px solid #ffffff;
  outline: none;
  margin: 10px;
}

#demo button:hover {
  color: #20262e;
  background: #ffffff;
  border: 1px solid #ffffff;
}

JavaScript

(function() {
  /* get elements */
  let root = document.getElementById("demo");
  let nameNode = root.getElementsByTagName("input")[0];
  let valueNode = root.getElementsByTagName("input")[1];
  let timeNode = root.getElementsByTagName("input")[2];
  let buttonNode = root.getElementsByTagName("Button")[0];

  buttonNode.onclick = function() {
    let s = timeNode.value;
    let samples = s * 1000;
    let buffer = new ArrayBuffer(44 + samples * 2);
    let contents = new DataView(buffer);

    /* set binary file's header */
    contents.setUint32(0, 0x52494646); // CHUNK_ID
    contents.setUint32(4, 36 + samples * 2, true); // CHUNK_SIZE
    contents.setUint32(8, 0x57415645); // FORMAT
    contents.setUint32(12, 0x666d7420); // SUBCHUNK_1_ID
    contents.setUint32(16, 16, true); // SUBCHUNK_1_SIZE
    contents.setUint16(20, 1, true); // AUDIO_FORMAT
    contents.setUint16(22, 1, true); // NUM_CHANNELS
    contents.setUint32(24, 1000, true); // SAMPLE_RATE
    contents.setUint32(28, 2000, true); // BYTE_RATE
    contents.setUint16(32, 2, true); // BLOCK_ALIGN
    contents.setUint16(34, 16, true); // BITS_PER_SAMPLE
    contents.setUint32(36, 0x64617461); // SUBCHUNK_2_ID
    contents.setUint32(40, samples * 2, true); // SUBCHUNK_2_SIZE

    /* set binary file's data */
    eval(`f = function(t){ return Math.floor(${valueNode.value}); };`);
    for (let t = 0; t < samples; t++)
      contents.setInt16(44 + t * 2, f(t), true);

    /* create URL and download */
    let blob = new Blob([buffer], {
      type: "application/octet-stream"
    });
    let url = window.URL.createObjectURL(blob);

    let downloadNode = document.createElement("a");
    downloadNode.style.display = "none";
    downloadNode.href = url;
    downloadNode.download = `${nameNode.value}.wav`;

    document.body.appendChild(downloadNode);
    downloadNode.click();
    window.URL.revokeObjectURL(url);
  };
})();