<!DOCTYPE HTML>
<HTML LANG="ja">
<HEAD>
<META CHARSET="Shift_JIS">
<TITLE>FLAC プレイヤー</TITLE>
</HEAD>
<BODY STYLE="background-color:#CCFFFF">
<DIV STYLE="text-align:center">
<BR>
<B><SPAN STYLE="color:#CC0000">FLAC プレイヤー<BR>(Firefox 3.5)</SPAN></B>
<BR><BR>
<FORM>
<TABLE STYLE="margin-left:auto; margin-right:auto"><TR><TD STYLE="text-align:left; white-space:nowrap">
<B>ファイル:</B><BR>
<INPUT TYPE=FILE ID="file" SIZE=60 onChange="sel_file()"><BR><BR>
<B>タイトル:</B> <SPAN ID="ttl" STYLE="white-space:pre"></SPAN><BR><BR>
<B>アーティスト:</B> <SPAN ID="art" STYLE="white-space:pre"></SPAN><BR><BR>
<INPUT TYPE=BUTTON ID="play" VALUE="再生" DISABLED onClick="play_stop()">
<SPAN ID="stat" STYLE="margin-left:1em"></SPAN>
<INPUT TYPE=TEXT ID="time" READONLY STYLE="border:none; background-color:transparent; font-size:medium">
</TD></TR></TABLE>
</FORM>
</DIV>
<SCRIPT TYPE="text/javascript">
<!--
function sel_file() {
elem_ttl.textContent = elem_art.textContent = "";
elem_play.disabled = true;
ready = false;
elem_aud = new Audio();
elem_aud.autoplay = true;
elem_aud.addEventListener("play", aud_play, false);
elem_aud.addEventListener("ended", aud_ended, false);
elem_aud.addEventListener("timeupdate", aud_timeupdate, false);
elem_aud.addEventListener("error", aud_error, false);
// Firefox 7 では nsIDOMFile オブジェクトの getAsBinary(),getAsDataURL() 等が削除された.
// 代わりに,Firefox 3.6 で新設された FileReader オブジェクトを使って同様のことができるので,
// FileReader オブジェクトが使えればそれを使い,使えなければ以前のままの処理とするように修正
// した.
if(typeof FileReader == "function") {
file_reader = new FileReader();
file_reader.onload = sel_file_fr;
file_reader.readAsBinaryString(elem_file.files.item(0));
}
else {
data = elem_file.files.item(0).getAsBinary();
sel_file2();
}
}
function sel_file_fr() {
data = file_reader.result;
file_reader = undefined;
sel_file2();
}
function sel_file2() {
// METADATA_BLOCK
switch(get_metadata()) {
case -1:
alert(ERR_FORMAT);
return;
case -2:
return;
}
elem_play.disabled = false;
}
function play_stop() {
if(running) {
// 停止
running = false;
return;
}
elem_file.disabled = true;
elem_play.value = "停止";
running = true;
if(ready) {
elem_aud.currentTime = 0;
elem_aud.play();
return;
}
// デコード開始
wave = "";
odd1 = undefined;
odd2 = "";
samples_sum = 0;
elem_stat.textContent = "デコード中";
elem_time.value = "0:00";
last_sec = 0;
i_data = i_audio;
sample_rate = 0;
setTimeout(frame, 0);
}
// フレーム デコード
function frame() {
if(!running) { // 停止
wave = undefined;
elem_stat.textContent = "";
aud_ended();
return;
}
for(var cnt = 50; cnt; cnt--) {
var sts;
// FRAME
switch(sts = get_frame()) {
case 0: // データあり
if(n_samples) { // total samples あり
if(samples_sum + block_size >= n_samples) {
block_size = n_samples - samples_sum;
sts = 1; // 終了
if(!block_size)
break;
}
}
var i;
var id = setTimeout(trap, 0);
var wave1 = odd2;
i = 0;
var d;
if(sample_bits < 16) {
var r = 0x7fff / (0x7fff >> (16 - sample_bits));
for(; i < block_size; i++) {
if((d = Math.round(buff0[i] * r)) < -32768)
d = -32768;
wave1 += String.fromCharCode(d & 0xff, (d & 0xff00) >> 8);
if(n_channels > 1) {
if((d = Math.round(buff1[i] * r)) < -32768)
d = -32768;
wave1 += String.fromCharCode(d & 0xff, (d & 0xff00) >> 8);
}
}
}
else {
var s = sample_bits - 16;
for(; i < block_size; i++) {
d = buff0[i] >> s;
wave1 += String.fromCharCode(d & 0xff, (d & 0xff00) >> 8);
if(n_channels > 1) {
d = buff1[i] >> s;
wave1 += String.fromCharCode(d & 0xff, (d & 0xff00) >> 8);
}
}
}
if(odd1 == undefined) { // PCM データの先頭
odd1 = wave1.substr(0, ODD1_LEN);
i = (wave1.length - ODD1_LEN) % 3;
wave += btoa(wave1.substr(ODD1_LEN, wave1.length - i - ODD1_LEN));
}
else {
i = wave1.length % 3;
wave += btoa(wave1.substr(0, wave1.length - i));
}
odd2 = (i) ? wave1.substr(- i) : "";
clearTimeout(id);
samples_sum += block_size;
var sec = Math.floor(samples_sum / sample_rate);
if(sec != last_sec) {
elem_time.value = String(Math.floor(sec / 60)) + ":" + ("0" + String(sec % 60)).substr(-2);
last_sec = sec;
}
break;
case -1:
alert(ERR_FORMAT);
// fall thru
case -2:
elem_stat.textContent = "";
aud_ended();
return;
}
if(sts) { // 終了
elem_stat.textContent = "再生準備中";
elem_time.value = "";
setTimeout(dec_end, 0);
return;
}
}
setTimeout(frame, 0);
}
function dec_end() {
var i;
data = undefined;
wave_header[I_CHANNELS] = i = (n_channels == 1) ? 1 : 2;
wave_int4(I_SAMPLES_SEC, sample_rate);
wave_int4(I_BYTES_SEC, sample_rate << i);
wave_header[I_ALIGN] = 1 << i;
var size = samples_sum << i;
wave_int4(I_DATA_SIZE, size);
wave_int4(I_RIFF_SIZE, size + wave_header.length - 8); // RIFF チャンクの ID,サイズを除く長さ
var id = setTimeout(trap, 0);
var hdr = "";
for(i = 0; i < wave_header.length; i++)
hdr += String.fromCharCode(wave_header[i]);
wave = "data:audio/wave;base64," + btoa(hdr + odd1) + wave + btoa(odd2);
elem_aud.src = wave;
clearTimeout(id);
if(elem_aud.src.length < wave.length) {
trap();
return;
}
wave = undefined;
elem_aud.load();
}
function aud_play() {
ready = true;
elem_stat.textContent = "";
elem_time.value = "0:00";
last_sec = 0;
}
function aud_ended() {
elem_time.value = "";
elem_play.value = "再生";
running = false;
elem_file.disabled = false;
}
function aud_timeupdate() {
if(!running) { // 停止
elem_aud.pause();
aud_ended();
return;
}
var sec = Math.floor(elem_aud.currentTime);
if(sec != last_sec) {
elem_time.value = String(Math.floor(sec / 60)) + ":" + ("0" + String(sec % 60)).substr(-2);
last_sec = sec;
}
}
function aud_error() {
alert("Audio エレメントでエラーが発生しました。\nエラー コード: " + String(elem_aud.error.code));
clear();
}
// データの文字列が長すぎた場合,エラーにはならずに単に処理が中止される.
function trap() {
alert("処理に失敗しました。恐らくデータが大きすぎます。");
clear();
}
function clear() {
wave = undefined;
elem_stat.textContent = "";
aud_ended();
elem_file.value = "";
elem_ttl.textContent = elem_art.textContent = "";
elem_play.disabled = true;
}
// WAVE ヘッダに 4 バイト Integer をセットする.
function wave_int4(i_wave, val) {
wave_header[i_wave ] = val & 0xff;
wave_header[i_wave + 1] = (val & 0xff00) >> 8;
wave_header[i_wave + 2] = (val & 0xff0000) >> 16;
wave_header[i_wave + 3] = val >>> 24;
}
// FLAC ****************************************************
// METADATA_BLOCK
// 戻り値 - 0: 正常,-1: エラー,-2: エラー(メッセージ出力済み)
function get_metadata() {
if(data.substr(0, 4) != "fLaC")
return -1;
i_data = 4;
for(; ; ) {
var i;
// METADATA_BLOCK_HEADER
if(i_data + 4 > data.length)
return -1;
var flg_typ = data_int1();
var len = data_int3();
if(i_data + len > data.length)
return -1;
// METADATA_BLOCK_DATA
switch(flg_typ & 0x7f) { // BLOCK_TYPE
case 0: // STREAMINFO
if(len < 34)
return -1;
min_block = data_int2(); // minimum block size
max_block = data_int2(); // maximum block size
min_frame = data_int3(); // minimum frame size
max_frame = data_int3(); // maximum frame size
var w = data_int4();
sample_rate_si = w >>> 12; // sample rate
if(sample_rate_si == 0 || sample_rate_si > 655350)
return -1;
n_channels = ((w & 0xe00) >> 9) + 1; // number of channels
if(n_channels > 6)
return -1;
sample_bits_si = ((w & 0x1f0) >> 4) + 1; // bits per sample
if(sample_bits_si < 4)
return -1;
if(sample_bits_si > 24) {
alert("このプログラムは、24 ビットを超えるサンプル サイズには対応していません。");
return -2;
}
n_samples = (((w & 0xf) << 16) | data_int2()) * 0x10000; // total samples
n_samples += data_int2();
// MD5 signature
signature = new Array();
signature.length = 16;
for(i = 0; i < 16; i++)
signature[i] = data_int1();
break;
case 4: // VORBIS_COMMENT
// 曲タイトル,アーティスト名を取得
var i_skip = i_data + len;
if(len < 4)
return -1;
if((len = data_int4_le()) & 0x80000000) // vendor_length
return -1;
if(i_data + len > data.length)
return -1;
i_data += len; // vendor_string
if(i_data + 4 > data.length)
return -1;
var n_comments = data_int4_le(); // user_comment_list_length
if(n_comments & 0x80000000)
return -1;
var f = 0x3;
for(i = 0; i < n_comments; i++) {
if(i_data + 4 > data.length)
return -1;
if((len = data_int4_le()) & 0x80000000) // length
return -1;
if(i_data + len > data.length)
return -1;
var comment = data.substr(i_data, len); // comment
i_data += len;
if(comment.substr(0, 6).toUpperCase() == "TITLE=") {
elem_ttl.textContent = utf8to16(comment.substr(6));
f &= ~0x1;
}
if(comment.substr(0, 7).toUpperCase() == "ARTIST=") {
elem_art.textContent = utf8to16(comment.substr(7));
f &= ~0x2;
}
if(!f)
break;
}
i_data = i_skip;
break;
case 127:
return -1;
default:
i_data += len;
}
if(flg_typ & 0x80) // last metadata block
break;
}
i_audio = i_data; // オーディオ開始位置保存
buff0 = [];
buff1 = (n_channels == 1) ? undefined : [];
return 0;
}
// FRAME
// 戻り値 - 0: 正常,1: EOF,-1: エラー,-2: エラー(メッセージ出力済み)
function get_frame() {
var w;
var i;
// FRAME_HEADER
var i_header = i_data;
if(i_data == data.length) // EOF
return 1;
if(i_data + 5 > data.length)
return -1;
w = data_int2(); // sync code, blocking strategy
if((w & 0xfffc) != 0xfff8) // sync code ?
return -1;
var blocking = w & 0x1; // blocking strategy(未使用)
var bs_sr = data_int1(); // block size, sample rate
w = data_int1(); // channel assignment, sample size
var channel_assign = w >> 4; // channel assignment
if(channel_assign & 0x8) {
if(n_channels != 2)
return -1;
if(channel_assign > 10)
return -1;
}
else {
if(channel_assign + 1 != n_channels)
return -1;
}
// bits per sample
switch((w & 0xe) >> 1) {
case 0:
sample_bits = sample_bits_si;
break;
case 1:
sample_bits = 8;
break;
case 2:
sample_bits = 12;
break;
case 4:
sample_bits = 16;
break;
case 5:
sample_bits = 20;
break;
case 6:
sample_bits = 24;
break;
default:
return -1;
}
// sample number/frame number(未使用)
var number;
w = data_int1();
if(w & 0x80) {
if(!(w & 0x40))
return -1;
var c = 1;
for(var bit = 0x20; bit; bit >>= 1) {
if(!(w & bit))
break;
c++;
}
if(!bit)
return -1;
number = w & (0x3f >> c);
for(; c; c--) {
if(i_data + 1 > data.length)
return -1;
w = data_int1();
if((w & 0xc0) != 0x80)
return -1;
number = number * 64 + (w & 0x3f);
}
}
else {
number = w;
}
// block size
if((w = bs_sr >> 4) & 0x8) {
block_size = 1 << w; // 256/512/1024/2048/4096/8192/16384/32768
}
else {
switch(w) {
case 0:
return -1;
case 1:
block_size = 192;
break;
case 6:
if(i_data + 1 > data.length)
return -1;
block_size = data_int1() + 1;
break;
case 7:
if(i_data + 2 > data.length)
return -1;
block_size = data_int2() + 1;
break;
default:
block_size = 576 << (w - 2); // 576/1152/2304/4608
}
}
// sample rate
switch(w = bs_sr & 0xf) {
case 0:
w = sample_rate_si;
break;
case 12:
if(i_data + 1 > data.length)
return -1;
w = data_int1() * 1000;
break;
case 13:
if(i_data + 2 > data.length)
return -1;
w = data_int2();
break;
case 14:
if(i_data + 2 > data.length)
return -1;
w = data_int2() * 10;
break;
case 15:
return -1;
default:
w = sample_rate_tbl[w];
}
if(sample_rate) {
if(w != sample_rate) {
alert("このプログラムは、可変サンプリング レートには対応していません。");
return -2;
}
}
else {
sample_rate = w;
}
// CRC-8(未使用)
if(i_data + 1 > data.length)
return -1;
data_int1();
if(block_size > buff0.length) {
buff0.length = block_size;
if(n_channels > 1)
buff1.length = block_size;
}
// ここからはビット単位で読み込み
try {
data_bit = 0;
for(var i_ch = 0; i_ch < n_channels; i_ch++) {
// SUBFRAME
var buff;
switch(i_ch) {
case 0:
buff = buff0;
break;
case 1:
buff = buff1;
break;
default:
buff = null;
}
// sample size 調整
var sample_bits_adj = sample_bits;
switch(channel_assign) {
case 8: // left/side
if(i_ch == 1)
sample_bits_adj++;
break;
case 9: // right/side
if(i_ch == 0)
sample_bits_adj++;
break;
case 10: // mid/side
if(i_ch == 1)
sample_bits_adj++;
break;
}
if(get_bits(1)) // zero
return -1;
var sub_type = get_bits(6); // subframe type
// wasted bits-per-sample
w = get_bits(1);
var wasted = 0;
if(w) {
for(; ; ) {
wasted++;
if(get_bits(1))
break;
}
sample_bits_adj -= wasted;
}
var sample_sign = 0xffffffff << (sample_bits_adj - 1);
var order; // predictor order
if (sub_type & 0x20) { // SUBFRAME_LPC
order = (sub_type & 0x1f) + 1; // order
i = 0;
if(buff) {
for(; i < order; i++)
buff[i] = (get_bits(sample_bits_adj) + sample_sign) ^ sample_sign;
}
else {
for(; i < order; i++)
get_bits(sample_bits_adj);
}
var prec = get_bits(4) + 1; // coefficient precision
if(prec == 16)
return -1;
// coefficient shift
w = get_bits(5);
// シフトがマイナスになることがあるのか?
var shift;
var shift_dir;
if(w & 0x10) { // マイナス
shift = 0x10000 >> (w & 0xf);
shift_dir = false;
}
else {
shift = 1 << w;
shift_dir = true;
}
w = 0xffffffff << (prec - 1);
for(i = 0; i < order; i++)
coeff[i] = (get_bits(prec) + w) ^ w;
// RESIDUAL
if(residual(buff, order))
return -1;
if(buff) {
for(i = order; i < block_size; i++) {
var sum = 0;
for(var j = 0, k = i - 1; j < order; j++, k--)
sum += buff[k] * coeff[j];
buff[i] += Math.floor((shift_dir) ? sum / shift : sum * shift);
}
}
}
else if(sub_type & 0x10) { // reserved
return -1;
}
else if(sub_type & 0x08) {
order = sub_type & 0x07;
if(order <= 4) { // SUBFRAME_FIXED
i = 0;
if(buff) {
for(; i < order; i++)
buff[i] = (get_bits(sample_bits_adj) + sample_sign) ^ sample_sign;
}
else {
for(; i < order; i++)
get_bits(sample_bits_adj);
}
// RESIDUAL
if(residual(buff, order))
return -1;
// データ
if(buff) {
switch(order) {
case 1:
for(; i < block_size; i++)
buff[i] += buff[i - 1];
break;
case 2:
for(; i < block_size; i++)
buff[i] += (buff[i - 1] << 1) - buff[i - 2];
break;
case 3:
for(; i < block_size; i++)
buff[i] += 3 * (buff[i - 1] - buff[i - 2]) + buff[i - 3];
break;
case 4:
for(; i < block_size; i++)
buff[i] += ((buff[i - 1] + buff[i - 3]) << 2) - 6 * buff[i - 2] - buff[i - 4];
break;
}
}
}
else { // reserved
return -1;
}
}
else if(sub_type & 0x06) { // reserved
return -1;
}
else if(sub_type & 0x01) { // SUBFRAME_VERBATIM
i = 0;
if(buff) {
for(; i < block_size; i++)
buff[i] = (get_bits(sample_bits_adj) + sample_sign) ^ sample_sign;
}
else {
for(; i < block_size; i++)
get_bits(sample_bits_adj);
}
}
else { // SUBFRAME_CONSTANT
w = (get_bits(sample_bits_adj) + sample_sign) ^ sample_sign;
if(buff) {
for(i = 0; i < block_size; i++)
buff[i] = w;
}
}
// wasted bits
if(wasted) {
if(buff) {
for(i = 0; i < block_size; i++)
buff[i] <<= wasted;
}
}
}
// Interchannel Decorrelation
if(channel_assign >= 8) {
i = 0;
switch(channel_assign) {
case 8: // left/side
for(; i < block_size; i++)
buff1[i] = buff0[i] - buff1[i];
break;
case 9: // right/side
for(; i < block_size; i++)
buff0[i] += buff1[i];
break;
default: // mid/side
for(; i < block_size; i++) {
var side = buff1[i];
var mid = (buff0[i] << 1) | (side & 0x1);
buff0[i] = (mid + side) >> 1;
buff1[i] = (mid - side) >> 1;
}
}
}
// zero-padding
// 単に,バッファに残っているビットを捨てるだけ
}
// Firefox 59 以上では使えなくなった
//catch(e if e == 0) {
// return -1;
//}
catch(e) {
if(e == 0)
return -1;
throw e;
}
// FRAME_FOOTER
if(i_data + 2 > data.length)
return -1;
// CRC-16
// x^16 + x^15 + x^2 + 1
var crc = 0;
for(i = i_header; i < i_data; )
crc = ((crc & 0xff) << 8) ^ crc_tbl[(crc >> 8) ^ data.charCodeAt(i++)];
if(data_int2() != crc)
return -1;
return 0;
}
// Residual
// 戻り値 - 0: 正常,-1: エラー
function residual(buff, pred_order) {
var param_bits;
var escape;
switch(get_bits(2)) { // coding method
case 0: // RESIDUAL_CODING_METHOD_PARTITIONED_RICE
param_bits = 4;
escape = 15;
break;
case 1: // RESIDUAL_CODING_METHOD_PARTITIONED_RICE2
param_bits = 5;
escape = 31;
break;
default: // reserved
return -1;
}
var part_order = get_bits(4); // partition order
var n_parts = 1 << part_order;
var part_size = block_size >> part_order; // partition size
var off = 0;
for(var i_part = 0; i_part < n_parts; i_part++) {
// RICE_PARTITION,RICE2_PARTITION
var param = get_bits(param_bits); // rice parameter
var i = (i_part) ? 0 : pred_order;
if(param == escape) { // escape
var n = get_bits(5);
if(!n)
return -1;
if(buff) {
var sign = 0xffffffff << (n - 1);
for(; i < part_size; i++)
buff[off + i] = (get_bits(n) + sign) ^ sign;
}
else {
for(; i < part_size; i++)
get_bits(n);
}
}
else {
if(buff) {
for(; i < part_size; i++) {
var val = 0;
while(!get_bits(1))
val++;
if(param)
val = (val << param) | get_bits(param);
buff[off + i] = (val & 0x1) ? ~(val >> 1) : val >> 1;
}
}
else {
for(; i < part_size; i++) {
while(!get_bits(1))
;
if(param)
get_bits(param);
}
}
}
off += part_size;
}
return 0;
}
// データの配列から 1 バイト Integer を取り出す.
function data_int1() {
return data.charCodeAt(i_data++);
}
// データの配列から 2 バイト Integer を取り出す.
function data_int2() {
var val = (data.charCodeAt(i_data) << 8) | data.charCodeAt(i_data + 1);
i_data += 2
return val;
}
// データの配列から 3 バイト Integer を取り出す.
function data_int3() {
var val = (data.charCodeAt(i_data) << 16) | (data.charCodeAt(i_data + 1) << 8)
| data.charCodeAt(i_data + 2);
i_data += 3
return val;
}
// データの配列から 4 バイト Integer を取り出す.
// 結果の MSB が 1 の場合,Integer の値としては負になる.
function data_int4() {
var val = (data.charCodeAt(i_data) << 24) | (data.charCodeAt(i_data + 1) << 16)
| (data.charCodeAt(i_data + 2) << 8) | data.charCodeAt(i_data + 3);
i_data += 4
return val;
}
// データの配列から little endian の 4 バイト Integer を取り出す.
// 結果の MSB が 1 の場合,Integer の値としては負になる.
function data_int4_le() {
var val = data.charCodeAt(i_data) | (data.charCodeAt(i_data + 1) << 8)
| (data.charCodeAt(i_data + 2) << 16) | (data.charCodeAt(i_data + 3) << 24);
i_data += 4
return val;
}
// ビット単位読み込み
function get_bits(n) {
var bits = 0;
for(; n; n--) {
if(!data_bit) {
if(i_data == data.length)
throw 0;
data_byte = data.charCodeAt(i_data++);
data_bit = 0x80;
}
bits <<= 1;
if(data_byte & data_bit)
bits |= 0x1;
data_bit >>= 1;
}
return bits;
}
// UTF-8 → UTF-16 変換
function utf8to16(utf8) {
var utf16 = "";
for(var i = 0; i < utf8.length; ) {
var c = utf8.charCodeAt(i);
if ((c & 0xe0) == 0xc0) {
if(i + 2 > utf8.length)
break;
utf16 += String.fromCharCode(((c & 0x1f) << 6) | utf8.charCodeAt(i + 1) & 0x3f);
i += 2;
}
else if((c & 0xf0) == 0xe0) {
if(i + 3 > utf8.length)
break;
utf16 += String.fromCharCode(((c & 0x0f) << 12) | ((utf8.charCodeAt(i + 1) & 0x3f) << 6)
| utf8.charCodeAt(i + 2) & 0x3f);
i += 3;
}
else if((c & 0xf0) == 0xf0) {
if(i + 4 > utf8.length)
break;
utf16 += String.fromCharCode(
0xd800 | ((((c & 0x07) << 8) | ((utf8.charCodeAt(i + 1) & 0x30) << 2)) - 0x40)
| ((utf8.charCodeAt(i + 1) & 0xf) << 2) | ((utf8.charCodeAt(i + 2) & 0x30) >> 4),
0xdc00 | ((utf8.charCodeAt(i + 2) & 0xf) << 6) | utf8.charCodeAt(i + 3) & 0x3f);
i += 4;
}
else {
utf16 += utf8[i++];
}
}
return utf16;
}
//----------------------------------------------------------
// WAVE ヘッダ
wave_header = [
0x52, 0x49, 0x46, 0x46, // RIFF
0x00, 0x00, 0x00, 0x00, // チャンク サイズ
0x57, 0x41, 0x56, 0x45, // WAVE
// fmt
0x66, 0x6d, 0x74, 0x20, // fmt
0x10, 0x00, 0x00, 0x00, // チャンク サイズ 16
0x01, 0x00, // wFormatTag PCM
0x00, 0x00, // wChannels
0x00, 0x00, 0x00, 0x00, // dwSamplesPerSec
0x00, 0x00, 0x00, 0x00, // dwAvgBytesPerSec
0x00, 0x00, // wBlockAlign
0x10, 0x00, // wBitsPerSample 16
// data
0x64, 0x61, 0x74, 0x61, // data
0x00, 0x00, 0x00, 0x00, // チャンク サイズ
];
I_RIFF_SIZE = 4;
I_CHANNELS = 22;
I_SAMPLES_SEC = 24;
I_BYTES_SEC = 28;
I_ALIGN = 32;
I_DATA_SIZE = 40;
ODD1_LEN = 1; // 3 の倍数に不足するバイト数
// sample rate テーブル
sample_rate_tbl = [0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000];
ERR_FORMAT = "ファイルの形式が正しくないか、このプログラムでは対応していないバージョンのファイルです。";
coeff = new Array(); // coefficients
coeff.length = 32;
// CRC テーブル
// x^16 + x^15 + x^2 + 1
crc_tbl = new Array();
crc_tbl.length = 256;
crc_tbl[0x00] = 0;
crc_tbl[0x01] = 0x8005;
crc_tbl[0x02] = 0x800f;
crc_tbl[0x04] = 0x801b;
crc_tbl[0x08] = 0x8033;
crc_tbl[0x10] = 0x8063;
crc_tbl[0x20] = 0x80c3;
crc_tbl[0x40] = 0x8183;
crc_tbl[0x80] = 0x8303;
for(i = 3; i < 256; i++)
crc_tbl[i] = crc_tbl[i & 0x01] ^ crc_tbl[i & 0x02] ^ crc_tbl[i & 0x04] ^ crc_tbl[i & 0x08]
^ crc_tbl[i & 0x10] ^ crc_tbl[i & 0x20] ^ crc_tbl[i & 0x40] ^ crc_tbl[i & 0x80];
ready = false;
running = false;
elem_file = document.getElementById("file");
elem_ttl = document.getElementById("ttl");
elem_art = document.getElementById("art");
elem_play = document.getElementById("play");
elem_stat = document.getElementById("stat");
elem_time = document.getElementById("time");
// ページを再ロードしたときのため
document.forms[0].reset();
elem_file.disabled = false;
elem_play.disabled = true;
//-->
</SCRIPT>
</BODY>
</HTML>
|