package { import flash.display.Sprite; import flash.display.Shape; import flash.display.StageScaleMode; import flash.display.SimpleButton; import flash.display.Bitmap; import flash.geom.ColorTransform; import flash.text.TextField; import flash.text.TextFieldType; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; import flash.text.TextFormatAlign; import flash.events.Event; import flash.events.MouseEvent; import flash.events.IOErrorEvent; import flash.events.SampleDataEvent; import flash.events.TimerEvent; import flash.ui.Mouse; import flash.ui.MouseCursor; import flash.net.FileReference; import flash.net.FileFilter; import flash.media.Sound; import flash.media.SoundChannel; import flash.media.SoundTransform; import flash.errors.EOFError; import flash.utils.*; [SWF(width=400, height=200, frameRate=30, backgroundColor=0xCCFFFF)] public class Vorbis extends Sprite { [Embed(source="play.gif")] private var Bitmap_play:Class; [Embed(source="stop.gif")] private var Bitmap_stop:Class; [Embed(source="vol_i.gif")] private var Bitmap_vol_i:Class; [Embed(source="vol_b.gif")] private var Bitmap_vol_b:Class; [Embed(source="vol_t.gif")] private var Bitmap_vol_t:Class; private var load:SimpleButton; // 読み込みボタン private var fnam:TextField; // ファイル名 private var title:TextField; // 曲タイトル private var artist:TextField; // アーティスト名 private var play:SimpleButton; // 再生/停止ボタン private var play_u:Sprite; // 再生ボタン アップ イメージ private var play_d:Sprite; // ダウン イメージ private var stop_u:Sprite; // 停止ボタン アップ イメージ private var stop_d:Sprite; // ダウン イメージ private var elapsed:TextField; // 経過時間 private var vol_b:Sprite; // ボリューム private var vol_t:Sprite; // ボリューム つまみ private var err:TextField; // エラー表示 private var timer:Timer; // 経過時間表示用タイマー private var file:FileReference; // ファイル読み込み private var snd:Sound; // サウンド private var snd_ch:SoundChannel = null; // サウンド チャネル private var snd_tr:SoundTransform; // サウンド属性 private var file_data:ByteArray = null; // ファイル データ // page header private var version:uint; private var header_type:uint; private var granule_position_h:uint, granule_position_l:uint; private var bitstream_serial_number:uint; private var page_sequence_number:uint; private var CRC_checksum:uint; private var page_segments:uint; private var segment_table:ByteArray = new ByteArray(); private var i_segment:int; // segment table インデックス private var packet:ByteArray; // パケット データ private var packet_byte:uint; // パケット データ バイト バッファ private var packet_bit:uint; // ビット位置 private const STS_OK:int = 0; private const STS_EOP:int = 1; private const STS_EOS:int = 2; private const STS_FORMAT:int = -1; private const STS_OTHER:int = -2; // identification header private var vorbis_version:uint; private var audio_channels:int; private var audio_sample_rate:uint; private var bitrate_maximum:int; private var bitrate_nominal:int; private var bitrate_minimum:int; private var blocksize_0:int, blocksize_1:int; // setup header // codebooks private var codebooks:Vector.; private var codeword_tree:Vector.>; private var tree_n_nodes:int; private var tree_max_nodes:int; private var tree_cw:uint; private var tree_len:int; private var tree_last:Vector. = new Vector.(32); // floors private var floors:Vector.; private const N_FLOOR_LIST:int = (2 + 31 * 8); private var floor1_step2:Vector. = new Vector.(N_FLOOR_LIST); private var floor1_idx:Vector. = new Vector.(N_FLOOR_LIST); // residues private var residues:Vector.; private var sub_no_residue:Vector.; private var sub_data:Vector.>; // mappings private var mappings:Vector.; private var mapping:Mapping; // modes private var modes:Vector.; // チャネル データ private var ch_data:Vector.; private var srf:int; // サンプリング レート比(ビット数) private var sr_blocksize_0:int, sr_blocksize_1:int; // サンプリング レート変換用ブロック サイズ private var n_channels2:int; // 再生に使用するチャネル数(1 or 2) private var channels2_1:int; // 再生に使用するチャネル R private var audio_pos:uint; // オーディオ開始 ファイル位置 private var first_audio:Boolean; // オーディオ開始位置チェック用 private var n_samples:uint; // サンプル数累計 private var eos:Boolean; // ストリーム終了 private var n_data:int; // 現フレーム データ数の 1/2 private var prev_n_data:int; // 前フレーム データ数の 1/2 private var data_0:Vector., data_1:Vector.; // 再生データ 現フレーム前半 private var prev_data_0:Vector., prev_data_1:Vector.; // 前フレーム後半 private var data2_0:Vector., data2_1:Vector.; // 現フレーム後半 private var work0:Vector., work1:Vector.; // IMDCT 用ワーク private var i_ovl_p:int; // overlap/add 前フレーム インデックス private var i_ovl_c:int; // 現フレーム インデックス private var n_win:int; // ウィンドウ データ数 private var i_win:int; // ウィンドウ インデックス private var i_win_end:int; // ウィンドウ インデックス終了値 private var vol_dx:int; // ボリューム マウス ダウン位置 private var floor1_ranges:Vector. = Vector.([256, 128, 86, 64]); private var floor1_ranges_bits:Vector. = Vector.([8, 7, 7, 6]); private var floor1_inverse_dB_table:Vector. = Vector.([ 1.0649863e-07, 1.1341951e-07, 1.2079015e-07, 1.2863978e-07, 1.3699951e-07, 1.4590251e-07, 1.5538408e-07, 1.6548181e-07, 1.7623575e-07, 1.8768855e-07, 1.9988561e-07, 2.1287530e-07, 2.2670913e-07, 2.4144197e-07, 2.5713223e-07, 2.7384213e-07, 2.9163793e-07, 3.1059021e-07, 3.3077411e-07, 3.5226968e-07, 3.7516214e-07, 3.9954229e-07, 4.2550680e-07, 4.5315863e-07, 4.8260743e-07, 5.1396998e-07, 5.4737065e-07, 5.8294187e-07, 6.2082472e-07, 6.6116941e-07, 7.0413592e-07, 7.4989464e-07, 7.9862701e-07, 8.5052630e-07, 9.0579828e-07, 9.6466216e-07, 1.0273513e-06, 1.0941144e-06, 1.1652161e-06, 1.2409384e-06, 1.3215816e-06, 1.4074654e-06, 1.4989305e-06, 1.5963394e-06, 1.7000785e-06, 1.8105592e-06, 1.9282195e-06, 2.0535261e-06, 2.1869758e-06, 2.3290978e-06, 2.4804557e-06, 2.6416497e-06, 2.8133190e-06, 2.9961443e-06, 3.1908506e-06, 3.3982101e-06, 3.6190449e-06, 3.8542308e-06, 4.1047004e-06, 4.3714470e-06, 4.6555282e-06, 4.9580707e-06, 5.2802740e-06, 5.6234160e-06, 5.9888572e-06, 6.3780469e-06, 6.7925283e-06, 7.2339451e-06, 7.7040476e-06, 8.2047000e-06, 8.7378876e-06, 9.3057248e-06, 9.9104632e-06, 1.0554501e-05, 1.1240392e-05, 1.1970856e-05, 1.2748789e-05, 1.3577278e-05, 1.4459606e-05, 1.5399272e-05, 1.6400004e-05, 1.7465768e-05, 1.8600792e-05, 1.9809576e-05, 2.1096914e-05, 2.2467911e-05, 2.3928002e-05, 2.5482978e-05, 2.7139006e-05, 2.8902651e-05, 3.0780908e-05, 3.2781225e-05, 3.4911534e-05, 3.7180282e-05, 3.9596466e-05, 4.2169667e-05, 4.4910090e-05, 4.7828601e-05, 5.0936773e-05, 5.4246931e-05, 5.7772202e-05, 6.1526565e-05, 6.5524908e-05, 6.9783085e-05, 7.4317983e-05, 7.9147585e-05, 8.4291040e-05, 8.9768747e-05, 9.5602426e-05, 0.00010181521, 0.00010843174, 0.00011547824, 0.00012298267, 0.00013097477, 0.00013948625, 0.00014855085, 0.00015820453, 0.00016848555, 0.00017943469, 0.00019109536, 0.00020351382, 0.00021673929, 0.00023082423, 0.00024582449, 0.00026179955, 0.00027881276, 0.00029693158, 0.00031622787, 0.00033677814, 0.00035866388, 0.00038197188, 0.00040679456, 0.00043323036, 0.00046138411, 0.00049136745, 0.00052329927, 0.00055730621, 0.00059352311, 0.00063209358, 0.00067317058, 0.00071691700, 0.00076350630, 0.00081312324, 0.00086596457, 0.00092223983, 0.00098217216, 0.0010459992, 0.0011139742, 0.0011863665, 0.0012634633, 0.0013455702, 0.0014330129, 0.0015261382, 0.0016253153, 0.0017309374, 0.0018434235, 0.0019632195, 0.0020908006, 0.0022266726, 0.0023713743, 0.0025254795, 0.0026895994, 0.0028643847, 0.0030505286, 0.0032487691, 0.0034598925, 0.0036847358, 0.0039241906, 0.0041792066, 0.0044507950, 0.0047400328, 0.0050480668, 0.0053761186, 0.0057254891, 0.0060975636, 0.0064938176, 0.0069158225, 0.0073652516, 0.0078438871, 0.0083536271, 0.0088964928, 0.009474637, 0.010090352, 0.010746080, 0.011444421, 0.012188144, 0.012980198, 0.013823725, 0.014722068, 0.015678791, 0.016697687, 0.017782797, 0.018938423, 0.020169149, 0.021479854, 0.022875735, 0.024362330, 0.025945531, 0.027631618, 0.029427276, 0.031339626, 0.033376252, 0.035545228, 0.037855157, 0.040315199, 0.042935108, 0.045725273, 0.048696758, 0.051861348, 0.055231591, 0.058820850, 0.062643361, 0.066714279, 0.071049749, 0.075666962, 0.080584227, 0.085821044, 0.091398179, 0.097337747, 0.10366330, 0.11039993, 0.11757434, 0.12521498, 0.13335215, 0.14201813, 0.15124727, 0.16107617, 0.17154380, 0.18269168, 0.19456402, 0.20720788, 0.22067342, 0.23501402, 0.25028656, 0.26655159, 0.28387361, 0.30232132, 0.32196786, 0.34289114, 0.36517414, 0.38890521, 0.41417847, 0.44109412, 0.46975890, 0.50028648, 0.53279791, 0.56742212, 0.60429640, 0.64356699, 0.68538959, 0.72993007, 0.77736504, 0.82788260, 0.88168307, 0.9389798, 1.0 ]); // sin テーブル private var sin:Vector.; // テーブル π/2 分 private var bs_0_1:int; // ブロック サイズ比(ビット数) private var n_pi:int; // π分に相当するテーブル点数 // ウィンドウ テーブル private var win_0:Vector., win_1:Vector.; private var win:Vector.; // ビット反転テーブル private var i_rev_0:Vector., i_rev_1:Vector.; private const ERR_FORMAT:String = "ファイルの形式が正しくないか、このプログラムでは対応していないバージョンのファイルです。"; public function Vorbis():void { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); stage.scaleMode = StageScaleMode.NO_SCALE; var txt:TextField; var fmt:TextFormat; var bmp:Bitmap; // タイトル txt = new TextField(); with(txt) { x = 0; y = 8; width = 400; height = 24; type = TextFieldType.DYNAMIC; selectable = false; text = "Vorbis プレイヤー"; fmt = new TextFormat(); with(fmt) { align = TextFormatAlign.CENTER; size = 12; color = 0xCC0000; bold = true; } setTextFormat(fmt); } addChild(txt); // 読み込みボタン load = new SimpleButton(); with(load) { x = 16; y = 32; var lbl:String = "ファイル"; upState = overState = hitTestState = draw_button_t(lbl, 60, 24, false); downState = draw_button_t(lbl, 60, 24, true); tabEnabled = false; addEventListener(MouseEvent.CLICK, load_click); } addChild(load); // ファイル名 fnam = new TextField(); with(fnam) { x = 88; y = 32; width = 296; height = 24; type = TextFieldType.DYNAMIC; selectable = false; fmt = new TextFormat(); fmt.size = 14; defaultTextFormat = fmt; } addChild(fnam); // 曲タイトル txt = new TextField(); with(txt) { x = 16; y = 64; type = TextFieldType.DYNAMIC; selectable = false; autoSize = TextFieldAutoSize.LEFT; text = "タイトル:"; fmt = new TextFormat(); with(fmt) { size = 12; bold = true; } setTextFormat(fmt); } addChild(txt); title = new TextField(); with(title) { x = 16 + txt.width + 2; y = 64; width = 400 - 16 - x; height = 24; type = TextFieldType.DYNAMIC; selectable = false; fmt = new TextFormat(); fmt.size = 14; defaultTextFormat = fmt; } addChild(title); // アーティスト名 txt = new TextField(); with(txt) { x = 16; y = 88; type = TextFieldType.DYNAMIC; selectable = false; autoSize = TextFieldAutoSize.LEFT; text = "アーティスト:"; fmt = new TextFormat(); with(fmt) { size = 12; bold = true; } setTextFormat(fmt); } addChild(txt); artist = new TextField(); with(artist) { x = 16 + txt.width + 2; y = 88; width = 400 - 16 - x; height = 24; type = TextFieldType.DYNAMIC; selectable = false; fmt = new TextFormat(); fmt.size = 14; defaultTextFormat = fmt; } addChild(artist); // 再生/停止ボタン bmp = new Bitmap_play(); play_u = draw_button_b(bmp, 32, 24, false); play_d = draw_button_b(new Bitmap(bmp.bitmapData.clone()), 32, 24, true); bmp = new Bitmap_stop(); stop_u = draw_button_b(bmp, 32, 24, false); stop_d = draw_button_b(new Bitmap(bmp.bitmapData.clone()), 32, 24, true); play = new SimpleButton(); with(play) { x = 32; y = 120; upState = overState = hitTestState = play_u; downState = play_d; tabEnabled = false; addEventListener(MouseEvent.CLICK, play_click); } addChild(play); // 経過時間 elapsed = new TextField(); with(elapsed) { x = 72; y = 120; width = 48; height = 24; type = TextFieldType.DYNAMIC; selectable = false; fmt = new TextFormat(); with(fmt) { align = TextFormatAlign.RIGHT; size = 14; } defaultTextFormat = fmt; } addChild(elapsed); // ボリューム bmp = new Bitmap_vol_i(); bmp.x = 144; bmp.y = 123; addChild(bmp); vol_b = new Sprite(); with(vol_b) { x = 170; y = 120; bmp = new Bitmap_vol_b(); bmp.x = bmp.y = 0; addChild(bmp); addEventListener(MouseEvent.MOUSE_DOWN, vol_b_mouse_down); addEventListener(MouseEvent.MOUSE_UP, vol_mouse_up1); addEventListener(MouseEvent.MOUSE_OVER, vol_mouse_over); addEventListener(MouseEvent.MOUSE_OUT, vol_mouse_out); } addChild(vol_b); vol_t = new Sprite(); with(vol_t) { x = 266; y = 124; bmp = new Bitmap_vol_t(); bmp.x = bmp.y = 0; addChild(bmp); addEventListener(MouseEvent.MOUSE_DOWN, vol_mouse_down); addEventListener(MouseEvent.MOUSE_UP, vol_mouse_up1); addEventListener(MouseEvent.MOUSE_OVER, vol_mouse_over); addEventListener(MouseEvent.MOUSE_OUT, vol_mouse_out); } addChild(vol_t); // エラー表示 err = new TextField(); with(err) { x = 16; y = 152; width = 368; height = 44; type = TextFieldType.DYNAMIC; selectable = false; multiline = true; wordWrap = true; fmt = new TextFormat(); with(fmt) { size = 12; color = 0xFF0000; } defaultTextFormat = fmt; } addChild(err); packet = new ByteArray(); packet.endian = Endian.LITTLE_ENDIAN; timer = new Timer(100, 0); timer.addEventListener(TimerEvent.TIMER, timer_timer); // inverse MDCT の結果が -1.0 ~ 1.0 の範囲になるように // floor1_inverse_dB_table の値を調整しておく. for(var i:int = 0; i < 256; i++) floor1_inverse_dB_table[i] *= 0.5; } // テキスト ボタンのイメージを作成する private function draw_button_t(lbl:String, w:int, h:int, down:Boolean):Sprite { var s:Sprite = new Sprite(); with(s.graphics) { lineStyle(2, 0xCC0000); beginFill((down) ? 0xCC0000 : 0xFFFFFF); drawRoundRect(0, 0, w, h, 10); endFill(); } var txt:TextField = new TextField(); with(txt) { type = TextFieldType.DYNAMIC; txt.text = lbl; selectable = false; autoSize = TextFieldAutoSize.LEFT; var fmt:TextFormat = new TextFormat(); with(fmt) { size = 12; color = (down) ? 0xFFFFFF : 0x000000; } setTextFormat(fmt); x = (w - width) >> 1; y = (h - height) >> 1; } s.addChild(txt); return s; } // ビットマップ ボタンのイメージを作成する private function draw_button_b(lbl:Bitmap, w:int, h:int, down:Boolean):Sprite { var s:Sprite = new Sprite(); with(s.graphics) { lineStyle(2, 0xCC0000); beginFill((down) ? 0xCC0000 : 0xFFFFFF); drawRoundRect(0, 0, w, h, 10); endFill(); } with(lbl) { x = (w - width) >> 1; y = (h - height) >> 1; if(down) bitmapData.colorTransform(bitmapData.rect, new ColorTransform(0, 0, 0, 1, 0xFF, 0xFF, 0xFF, 0)); } s.addChild(lbl); return s; } // ファイル読み込み private function load_click(e:MouseEvent):void { err.text = ""; file = new FileReference(); with(file) { addEventListener(Event.SELECT, load_select); addEventListener(Event.CANCEL, load_cancel); addEventListener(Event.COMPLETE, load_complete); addEventListener(IOErrorEvent.IO_ERROR, load_io_error); } mouseChildren = false; file.browse([new FileFilter("Vorbis ファイル(*.ogg)", "*.ogg"), new FileFilter("すべてのファイル", "*")]); } private function load_select(e:Event):void { fnam.text = file.name; title.text = artist.text = ""; file.load(); } private function load_cancel(e:Event):void { with(file) { removeEventListener(Event.SELECT, load_select); removeEventListener(Event.CANCEL, load_cancel); removeEventListener(Event.COMPLETE, load_complete); removeEventListener(IOErrorEvent.IO_ERROR, load_io_error); } file = null; mouseChildren = true; } private function load_complete(e:Event):void { file_data = file.data; load_cancel(null); switch(get_header()) { case STS_EOS: case STS_FORMAT: err.text = ERR_FORMAT; // fall thru case STS_OTHER: file_data = null; break; } } private function load_io_error(e:IOErrorEvent):void { load_cancel(null); fnam.text = ""; file_data = null; err.text = "ファイルの読み込みでエラーが発生しました。"; } // 再生/停止 private function play_click(e:MouseEvent):void { err.text = ""; if(!file_data) return; if(snd_ch) { // 再生中 snd_ch.stop(); snd_ch_complete(null); return; } with(play) { upState = overState = hitTestState = stop_u; downState = stop_d; } load.enabled = load.mouseEnabled = false; file_data.position = audio_pos; header_type = 0; granule_position_h = granule_position_l = 0xFFFFFFFF; // -1 page_segments = 0; i_segment = 0; first_audio = true; n_samples = 0; i_win = i_win_end = 0; eos = false; // 最初のオーディオ パケット取得 switch(get_audio()) { case STS_FORMAT: err.text = ERR_FORMAT; // fall thru case STS_OTHER: case STS_EOS: with(play) { upState = overState = hitTestState = play_u; downState = play_d; } load.enabled = load.mouseEnabled = true; return; } snd = new Sound(); snd.addEventListener(SampleDataEvent.SAMPLE_DATA, snd_sample_data); snd_tr = new SoundTransform(); snd_tr.volume = (vol_t.x - vol_b.x) / 96; snd_ch = snd.play(0, 0, snd_tr); snd_ch.addEventListener(Event.SOUND_COMPLETE, snd_ch_complete); timer.reset(); timer.start(); } // ボリューム つまみ以外 マウス ダウン private function vol_b_mouse_down(e:MouseEvent):void { var x:int = e.localX - 4; if (x < 0) x = 0; else if(x > 96) x = 96; vol_t.x = vol_b.x + x; vol_mouse_down(e); if(snd_ch) { // 再生中 snd_tr.volume = (vol_t.x - vol_b.x) / 96; snd_ch.soundTransform = snd_tr; } } // ボリューム マウス ダウン private function vol_mouse_down(e:MouseEvent):void { vol_dx = e.stageX - vol_t.x + vol_b.x; vol_b.removeEventListener(MouseEvent.MOUSE_OUT, vol_mouse_out); vol_t.removeEventListener(MouseEvent.MOUSE_OUT, vol_mouse_out); stage.addEventListener(MouseEvent.MOUSE_UP, vol_mouse_up2); stage.addEventListener(MouseEvent.MOUSE_MOVE, vol_mouse_move); } // ボリューム マウス アップ 1 private function vol_mouse_up1(e:MouseEvent):void { Mouse.cursor = MouseCursor.BUTTON; } // ボリューム マウス アップ 2 private function vol_mouse_up2(e:MouseEvent):void { stage.removeEventListener(MouseEvent.MOUSE_UP, vol_mouse_up2); stage.removeEventListener(MouseEvent.MOUSE_MOVE, vol_mouse_move); vol_b.addEventListener(MouseEvent.MOUSE_OUT, vol_mouse_out); vol_t.addEventListener(MouseEvent.MOUSE_OUT, vol_mouse_out); if(!vol_b.hitTestPoint(e.stageX, e.stageY) && !vol_t.hitTestPoint(e.stageX, e.stageY)) Mouse.cursor = MouseCursor.AUTO; } // ボリューム マウス 移動 private function vol_mouse_move(e:MouseEvent):void { var x:int = e.stageX - vol_dx; if (x < 0) x = 0; else if(x > 96) x = 96; vol_t.x = vol_b.x + x; if(snd_ch) { // 再生中 snd_tr.volume = x / 96; snd_ch.soundTransform = snd_tr; } } private function vol_mouse_over(e:MouseEvent):void { if(!e.buttonDown) Mouse.cursor = MouseCursor.BUTTON; } private function vol_mouse_out(e:MouseEvent):void { if(!e.buttonDown) Mouse.cursor = MouseCursor.AUTO; } // サウンド private function snd_sample_data(e:SampleDataEvent):void { if(i_win == 0x7FFFFFFF) return; for(var cnt:int = 8192; cnt; cnt--) { if(i_win == i_win_end) { // バッファ データ終了 if(eos) { i_win = 0x7FFFFFFF; return; } // データ後半を保存 var len:int = n_data << srf >> 1; prev_data_0 = data2_0.slice(0, len).reverse().concat(data2_0.slice(0, len)); if(n_channels2 == 2) prev_data_1 = data2_1.slice(0, len).reverse().concat(data2_1.slice(0, len)); prev_n_data = n_data; // オーディオ パケット取得 switch(get_audio()) { case STS_EOS: i_win = 0x7FFFFFFF; return; case STS_FORMAT: err.text = ERR_FORMAT; // fall thru case STS_OTHER: if(snd_ch) { // 再生中 // sampleData イベントでサウンドを停止すると,Flash プレイヤーが異常終了する. //snd_ch.stop(); snd_ch_complete(null); } else { i_win = 0x7FFFFFFF; } return; } i_ovl_p = 0; if(prev_n_data < n_data) { i_ovl_c = (n_data - prev_n_data) >> 1 << srf; i_win = 0; n_win = prev_n_data << srf; } else { i_ovl_c = 0; i_win = - ((prev_n_data - n_data) >> 1 << srf); n_win = n_data << srf; } win = (n_win == (sr_blocksize_0 >> 1)) ? win_0 : win_1; var n_ovl_org:int = (prev_n_data + n_data) >> 1; // 最後のデータ? if(!granule_position_h && granule_position_l < n_samples + n_ovl_org) { if(granule_position_l <= n_samples) { i_win = 0x7FFFFFFF; return; } n_ovl_org = granule_position_l - n_samples; eos = true; } n_samples += n_ovl_org; var n_ovl:int = n_ovl_org << srf; i_win_end = i_win + n_ovl; } var val:Number; // L if (i_win < 0) val = prev_data_0[i_ovl_p]; else if(i_win < n_win) val = prev_data_0[i_ovl_p] * win[n_win - 1 - i_win] + data_0[i_ovl_c] * win[i_win]; else val = data_0[i_ovl_c]; if (val > 1) val = 1; else if(val < -1) val = -1; e.data.writeFloat(val); // R if(n_channels2 == 2) { if (i_win < 0) val = prev_data_1[i_ovl_p]; else if(i_win < n_win) val = prev_data_1[i_ovl_p] * win[n_win - 1 - i_win] + data_1[i_ovl_c] * win[i_win]; else val = data_1[i_ovl_c]; if (val > 1) val = 1; else if(val < -1) val = -1; } e.data.writeFloat(val); if(i_win < n_win) i_ovl_p++; if(i_win >= 0) i_ovl_c++; i_win++; } } // 再生終了 private function snd_ch_complete(e:Event):void { timer.stop(); timer_timer(null); snd_ch.removeEventListener(Event.SOUND_COMPLETE, snd_ch_complete); snd_ch = null; snd.removeEventListener(SampleDataEvent.SAMPLE_DATA, snd_sample_data); snd = null; with(play) { upState = overState = hitTestState = play_u; downState = play_d; } load.enabled = load.mouseEnabled = true; setTimeout(erase_elapsed, 100); } // 経過時間表示 private function timer_timer(e:TimerEvent):void { if(snd_ch) { // 再生中 var sec:uint = uint(snd_ch.position / 1000); elapsed.text = uint(sec / 60).toString() + ":" + ("0" + (sec % 60).toString()).substr(-2); } } // 経過時間消去 private function erase_elapsed():void { elapsed.text = ""; } // ヘッダ情報取得 private function get_header():int { file_data.endian = Endian.LITTLE_ENDIAN; header_type = 0; page_segments = 0; i_segment = 0; first_audio = false; try { var sts:int; var data_bits:uint; var m:int; var w:Number; var i:int, j:int, k:int; // **** identification header **** for(; ; ) { sts = get_packet(); if(sts) return sts; if(header_type & 0x02) // bos break; } if(packet.readUTFBytes(7) != "\x01vorbis") return STS_FORMAT; // vorbis_version if((vorbis_version = get_bits(32)) != 0) { err.text = "サポートしていない Vorbis バージョンです。"; return STS_OTHER; } // audio_channels if(!(audio_channels = get_bits(8))) return STS_FORMAT; if(audio_channels > 6) { err.text = "チャネル数が多すぎます。"; return STS_OTHER; } // audio_sample_rate switch(audio_sample_rate = get_bits(32)) { case 0: return STS_FORMAT; case 11025: case 22050: case 44100: break; default: err.text = "このプログラムは、11025 Hz/22050 Hz/44100 Hz 以外のサンプリング レートには対応していません。"; return STS_OTHER; } // bitrate_maximum bitrate_maximum = get_bits(32); // bitrate_nominal bitrate_nominal = get_bits(32); // bitrate_minimum bitrate_minimum = get_bits(32); // blocksize_0 i = get_bits(4); if(i < 6 || i > 13) // 64,128,256,512,1024,2048,4096,8192 以外 return STS_FORMAT; blocksize_0 = 1 << i; // blocksize_1 j = get_bits(4); if(j < 6 || j > 13) // 64,128,256,512,1024,2048,4096,8192 以外 return STS_FORMAT; blocksize_1 = 1 << j; if(blocksize_0 > blocksize_1) return STS_FORMAT; bs_0_1 = j - i; // ブロック サイズ比 // framing_flag if(!get_bits(1)) return STS_FORMAT; // **** comment header **** sts = get_packet(); if(sts) return sts; if(packet.readUTFBytes(7) != "\x03vorbis") return STS_FORMAT; // 曲タイトル,アーティスト名を取得 try { var len:uint = packet.readUnsignedInt(); // vendor_length packet.position += len; // vendor_string var n_comments:uint = packet.readUnsignedInt(); // user_comment_list_length var f:int = 0x3; for(var u:uint = 0; u < n_comments; u++) { len = packet.readUnsignedInt(); // length var comment:String = packet.readUTFBytes(len); // comment if(comment.substr(0, 6).toUpperCase() == "TITLE=") { title.text = comment.substr(6); f &= ~0x1; } if(comment.substr(0, 7).toUpperCase() == "ARTIST=") { artist.text = comment.substr(7); f &= ~0x2; } if(!f) break; } } catch(e:EOFError) { } // **** setup header **** sts = get_packet(); if(sts) return sts; if(packet.readUTFBytes(7) != "\x05vorbis") return STS_FORMAT; var count:int; var i_data:int; var codebook:Codebook; // **** codebooks **** // vorbis_codebook_count count = get_bits(8) + 1; codebooks = new Vector.(count); for(i_data = 0; i_data < count; i_data++) { codebook = codebooks[i_data] = new Codebook(); // sync pattern if(get_bits(24) != 0x564342) return STS_FORMAT; // codebook_dimensions var dimensions:uint = codebook.dimensions = get_bits(16); // codebook_entries var entries:uint = codebook.entries = get_bits(24); if(entries < 2) return STS_FORMAT; tree_max_nodes = entries - 1; codeword_tree = codebook.codeword_tree = new Vector.>(2); codeword_tree[0] = new Vector.(tree_max_nodes); codeword_tree[1] = new Vector.(tree_max_nodes); for(i = 0; i < tree_max_nodes; i++) codeword_tree[0][i] = codeword_tree[1][i] = 0xFFFFFFFF; // 初期値 空き tree_n_nodes = 1; if(get_bits(1)) { // ordered var huff:uint = 0; var inc:uint = 0x80000000 >>> get_bits(5); for(i = 0; i < entries; ) { // number data_bits = get_bits(ilog(entries - i)); if(i + data_bits > entries) return STS_FORMAT; for(; data_bits; data_bits--) { var i_tree:int = 0; for(var bit:uint = 0x80000000; ; bit >>>= 1) { j = (huff & bit) ? 1 : 0; if(bit == inc) { codeword_tree[j][i_tree] = i; break; } if(codeword_tree[j][i_tree] == 0xFFFFFFFF) { // 空き if(tree_n_nodes == tree_max_nodes) return STS_FORMAT; codeword_tree[j][i_tree] = uint(tree_n_nodes | 0x80000000); i_tree = tree_n_nodes++; } else { i_tree = codeword_tree[j][i_tree] & 0x7FFFFFFF; } } i++; huff += inc; } inc >>>= 1; } } else { // sparse j = get_bits(1); for(i = 0; i < 32; i++) tree_last[i] = 0; for(tree_cw = 0; tree_cw < entries; tree_cw++) { if(j) { // sparse if(!get_bits(1)) // flag continue; } tree_len = get_bits(5) + 1; // length if(reg_tree(0, 0, 0) != 1) return STS_FORMAT; } } // **** vector lookup table **** switch(codebook.lookup_type = get_bits(4)) { case 0: break; case 1: case 2: // codebook_minimum_value var minimum_value:Number = float32_unpack(get_bits(32)); // codebook_delta_value var delta_value:Number = float32_unpack(get_bits(32)); // codebook_value_bits var value_bits:uint = get_bits(4) + 1; // codebook_sequence_p codebook.sequence_p = get_bits(1); // codebook_lookup_values var lookup_values:uint; if(codebook.lookup_type == 1) { // log(),pow() を使わず,整数演算的に求めている. // log(),pow() を使う場合は計算誤差に注意. i = ilog(entries) / dimensions; if(i > 0) { for(lookup_values = (1 << (i - 1)) + 1; ; lookup_values++) { w = 1; for(i = dimensions; i; i--) { w *= lookup_values; if(w > entries) break; } if(i) break; } lookup_values--; } else { lookup_values = 1; } } else { lookup_values = entries * dimensions; } // codebook_multiplicands var values:Vector. = codebook.values = new Vector.(lookup_values); for(i = 0; i < lookup_values; i++) values[i] = get_bits(value_bits) * delta_value + minimum_value; break; default: return STS_FORMAT; } } // **** time domain transforms **** for(count = get_bits(6); count >= 0; count--) { // vorbis_time_count if(get_bits(16)) return STS_FORMAT; } // **** floors **** // vorbis_floor_count count = get_bits(6) + 1; floors = new Vector.(count); for(i_data = 0; i_data < count; i_data++) { var floor:Floor = floors[i_data] = new Floor(); // vorbis_floor_types var floor_type:uint = get_bits(16); // vorbis_floor_configurations switch(floor_type) { // type case 0: err.text = "Floor type 0 はサポートしていません。"; return STS_OTHER; case 1: // floor1_partitions var partitions:uint = get_bits(5); floor.partition_class_list = new Vector.(partitions); var maximum_class:int = -1; for(i = 0; i < partitions; i++) { // floor1_partition_class_list floor.partition_class_list[i] = j = get_bits(4); if(j > maximum_class) maximum_class = j; } floor.classes = new Vector.(maximum_class + 1); for(i = 0; i <= maximum_class; i++) { floor.classes[i] = new Floor_Class(); // floor1_class_dimensions floor.classes[i].dimension = get_bits(3) + 1; // floor1_class_subclasses floor.classes[i].subclass = data_bits = get_bits(2); m = 1 << data_bits; if(data_bits) { // floor1_class_subclasses // floor1_class_masterbooks if((floor.classes[i].masterbook = get_bits(8)) >= codebooks.length) return STS_FORMAT; } floor.classes[i].subclass_books = new Vector.(m); for(j = 0; j < m; j++) { // floor1_subclass_books if((floor.classes[i].subclass_books[j] = int(get_bits(8)) - 1) >= codebooks.length) return STS_FORMAT; } } // floor1_multiplier floor.multiplier = get_bits(2) + 1; floor.X_list = new Vector.(2); // rangebits var rangebits:int = get_bits(4); floor.X_list[0] = 0; floor.X_list[1] = 1 << rangebits; k = 2; for(i = 0; i < partitions; i++) { for(j = floor.classes[floor.partition_class_list[i]].dimension - 1; j >= 0; j--) floor.X_list[k++] = get_bits(rangebits); } break; default: return STS_FORMAT; } } // **** residues **** // vorbis_residue_count count = get_bits(6) + 1; residues = new Vector.(count); for(i_data = 0; i_data < count; i_data++) { var residue:Residue = residues[i_data] = new Residue(); // vorbis_residue_configurations switch(residue.type = get_bits(16)) { // vorbis_residue_types case 0: case 1: case 2: // residue_begin residue.begin = get_bits(24); // residue_end residue.end = get_bits(24); // residue_partition_size residue.partition_size = get_bits(24) + 1; // residue_classifications var residue_classifications:uint = get_bits(6) + 1; // residue_classbook if((residue.classbook = get_bits(8)) >= codebooks.length) return STS_FORMAT; codebook = codebooks[residue.classbook]; var wu:uint = 1; for(i = codebook.dimensions; i; i--) { wu *= residue_classifications; if(wu > codebook.entries) break; } if(wu != codebook.entries) return STS_FORMAT; var bits:uint; residue.cascade = new Vector.(residue_classifications); for(i = 0; i < residue_classifications; i++) { // low_bits bits = get_bits(3); // bitflag if(get_bits(1)) { // high_bits bits |= get_bits(5) << 3; } // residue_cascade residue.cascade[i] = bits; } residue.books = new Vector.(residue_classifications << 3); for(i = 0; i < residue_classifications; i++) { bits = residue.cascade[i]; for(j = 0; j < 8; j++) { if(bits & 0x1) { // residue_books if((residue.books[(i << 3) | j] = get_bits(8)) >= codebooks.length) return STS_FORMAT; } bits >>= 1; } } break; default: return STS_FORMAT; } } // **** mappings **** // vorbis_mapping_count count = get_bits(6) + 1; mappings = new Vector.(count); for(i_data = 0; i_data < count; i_data++) { mapping = mappings[i_data] = new Mapping(); // mapping type if(get_bits(16)) // 0 でない return STS_FORMAT; // vorbis_mapping_submaps var n_submaps:uint; if(get_bits(1)) // flag n_submaps = get_bits(4) + 1; else n_submaps = 1; if(get_bits(1)) { // flag // vorbis_mapping_coupling_steps var mapping_coupling_steps:uint = get_bits(8) + 1; mapping.couplings = new Vector.(mapping_coupling_steps); for(i = 0; i < mapping_coupling_steps; i++) { // vorbis_mapping_magnitude var mapping_magnitude:uint = get_bits(ilog(audio_channels - 1)); // vorbis_mapping_angle var mapping_angle:uint = get_bits(ilog(audio_channels - 1)); if(mapping_magnitude == mapping_angle || mapping_magnitude >= audio_channels || mapping_angle >= audio_channels) return STS_FORMAT; mapping.couplings[i] = (mapping_magnitude << 16) | mapping_angle; } } else { mapping.couplings = null; } // reserved field if(get_bits(2)) // 0 でない return STS_FORMAT; mapping.mux = new Vector.(audio_channels); if(n_submaps > 1) { for(i = 0; i < audio_channels; i++) { // vorbis_mapping_mux if((mapping.mux[i] = get_bits(4)) >= n_submaps) return STS_FORMAT; } } else { for(i = 0; i < audio_channels; i++) mapping.mux[i] = 0; } mapping.submaps = new Vector.(n_submaps); for(i = 0; i < n_submaps; i++) { // time configuration get_bits(8); // vorbis_mapping_submap_floor var submap_floor:uint = get_bits(8); if(submap_floor >= floors.length) return STS_FORMAT; // vorbis_mapping_submap_residue var submap_residue:uint = get_bits(8) if(submap_residue >= residues.length) return STS_FORMAT; mapping.submaps[i] = (submap_floor << 16) | submap_residue; } } // **** modes **** // vorbis_mode_count count = get_bits(6) + 1; modes = new Vector.(count); for(i_data = 0; i_data < count; i_data++) { // vorbis_mode_blockflag wu = get_bits(1); // vorbis_mode_windowtype if(get_bits(16)) // 0 でない return STS_FORMAT; // vorbis_mode_transformtype if(get_bits(16)) // 0 でない return STS_FORMAT; // vorbis_mode_mapping if((modes[i_data] = get_bits(8)) >= mappings.length) return STS_FORMAT; modes[i_data] |= wu << 31; } // framing flag if(!get_bits(1)) return STS_FORMAT; } catch(e:EOFError) { return STS_FORMAT; } audio_pos = file_data.position; // オーディオ開始 ファイル位置保存 // サンプリング レート変換用 switch(audio_sample_rate) { case 11025: srf = 2; break; case 22050: srf = 1; break; default: srf = 0; } sr_blocksize_0 = blocksize_0 << srf; sr_blocksize_1 = blocksize_1 << srf; // 再生チャネル選択 n_channels2 = 2; switch(audio_channels) { case 2: case 4: channels2_1 = 1; break; case 3: case 5: case 6: channels2_1 = 2; break; default: n_channels2 = 1; } // チャネル データ ch_data = new Vector.(audio_channels); for(i = 0; i < audio_channels; i++) { ch_data[i] = new Ch_Data(); ch_data[i].data = new Vector.(((i == 0 || n_channels2 == 2 && i == channels2_1) ? sr_blocksize_1 : blocksize_1) >> 1); ch_data[i].floor1_Y = new Vector.(N_FLOOR_LIST); } m = sr_blocksize_1 >> 2; data_0 = ch_data[0].data; data2_0 = new Vector.(m); if(n_channels2 == 2) { data_1 = ch_data[channels2_1].data; data2_1 = new Vector.(m); } work0 = new Vector.(m); work1 = new Vector.(m); sub_no_residue = new Vector.(audio_channels); sub_data = new Vector.>(audio_channels); // sin テーブル作成 sin = new Vector.(sr_blocksize_1 + 1); sin[0] = 0; sin[sr_blocksize_1] = 1; for(i = 1; i < sr_blocksize_1; i++) sin[i] = Math.sin((Math.PI / 2) * i / sr_blocksize_1); n_pi = sr_blocksize_1 << 1; // ビット反転テーブル作成 m = sr_blocksize_0 >> 3; i_rev_0 = new Vector.(m); j = 0; for(i = 0; ; i++) { i_rev_0[i] = j; if(i == m - 1) break; for(k = m; ; k >>= 1) { if((j ^= k) & k) break; } } m = sr_blocksize_1 >> 3; i_rev_1 = new Vector.(m); j = 0; for(i = 0; ; i++) { i_rev_1[i] = j; if(i == m - 1) break; for(k = m; ; k >>= 1) { if((j ^= k) & k) break; } } // ウィンドウ テーブル作成 win_0 = new Vector.(sr_blocksize_0 >> 1); win_1 = new Vector.(sr_blocksize_1 >> 1); // left window : sin(.5 * π * sin^2( (i + .5) / n * .5 * π) ) // right window : sin(.5 * π * sin^2( (i + .5) / n * .5 * π + .5 * π) ) for(i = (sr_blocksize_0 >> 1) - 1; i >= 0; i--) { w = sin[((i << 1) + 1) << bs_0_1]; win_0[i] = Math.sin((Math.PI / 2) * (w * w)); } for(i = (sr_blocksize_1 >> 1) - 1; i >= 0; i--) { w = sin[(i << 1) + 1]; win_1[i] = Math.sin((Math.PI / 2) * (w * w)); } return STS_OK; } // Huffman ツリー登録 // 戻り値 0:登録できない // 1:登録できた // -1:エラー private function reg_tree(i_tree:int, i_len:int, huff:uint):int { var bit:uint = 0x80000000 >>> i_len; var i:int; if (codeword_tree[0][i_tree] == 0xFFFFFFFF) // 0 空き i = 0; else if(codeword_tree[1][i_tree] == 0xFFFFFFFF) // 1 空き i = 1; else i = -1; if(i_len == tree_len - 1) { // コード長一致 if(i < 0) // 空きなし return 0; if(i) huff |= bit; } else { if(i) { // 0 空きでない var last:uint = tree_last[tree_len - 1] & (0xFFFFFFFF << (31 - i_len)); var sts:int; if(codeword_tree[0][i_tree] & 0x80000000) { // 0 枝 if(huff >= last) { sts = reg_tree(codeword_tree[0][i_tree] & 0x7FFFFFFF, i_len + 1, huff); if(sts) return sts; } } if(i < 0) { // 1 空きでない if(codeword_tree[1][i_tree] & 0x80000000) { // 1 枝 huff |= bit; if(huff >= last) { sts = reg_tree(codeword_tree[1][i_tree] & 0x7FFFFFFF, i_len + 1, huff); if(sts) return sts; } } return 0; } } if(i) huff |= bit; for(; i_len < tree_len - 1; i_len++) { if(tree_n_nodes == tree_max_nodes) return -1; codeword_tree[i][i_tree] = uint(tree_n_nodes | 0x80000000); i_tree = tree_n_nodes++; i = 0; } } codeword_tree[i][i_tree] = tree_cw; tree_last[tree_len - 1] = huff; return 1; } // オーディオ パケット private function get_audio():int { var sts:int; var blockflag:uint; var sr_n_data:int; var i_ch:int; var data:Vector.; var i:int; for(; ; ) { sts = get_packet(); if(sts) return sts; try { // packet_type if(get_bits(1)) // オーディオ パケットでない continue; // mode_number i = get_bits(ilog(modes.length - 1)); if(i >= modes.length) continue; blockflag = modes[i] & 0x80000000; if(blockflag) { // long window n_data = blocksize_1 >> 1; // previous_window_flag get_bits(1); // next_window_flag get_bits(1); } else { n_data = blocksize_0 >> 1; } sr_n_data = n_data << srf; break; } catch(e:EOFError) { continue; } } mapping = mappings[modes[i] & 0x7FFFFFFF]; // データ初期化 for(i_ch = 0; i_ch < audio_channels; i_ch++) { data = ch_data[i_ch].data; for(i = ((i_ch == 0 || n_channels2 == 2 && i_ch == channels2_1) ? sr_n_data : n_data) - 1; i >= 0; i--) data[i] = 0; ch_data[i_ch].no_residue = true; // unused } // **** floor **** sts = floor_decode(); switch(sts) { case STS_OK: // **** residue **** sts = residue_decode(); switch(sts) { case STS_OK: case STS_EOP: break; default: return sts; } break; case STS_EOP: break; default: return sts; } // **** inverse channel coupling **** inverse_coupling(); for(var i_ch2:int = 0; i_ch2 < n_channels2; i_ch2++) { i_ch = (i_ch2) ? channels2_1 : 0; data = ch_data[i_ch].data; if(ch_data[i_ch].no_residue) { for(i = sr_n_data - 1; i >= 0; i--) data[i] = 0; data = (i_ch) ? data2_1 : data2_0; for(i = (sr_n_data >> 1) - 1; i >= 0; i--) data[i] = 0; } else { // **** floor curve & dot product **** floor_curve(i_ch, data); // **** inverse MDCT **** inverse_MDCT(data, (i_ch) ? data2_1 : data2_0, blockflag); } } return STS_OK; } // floor decode private function floor_decode():int { try { for(var i_ch:int = 0; i_ch < audio_channels; i_ch++) { var floor:Floor = floors[mapping.submaps[mapping.mux[i_ch]] >> 16]; // nonzero if(!get_bits(1)) // unused continue; var floor1_Y:Vector. = ch_data[i_ch].floor1_Y; var k:int = floor1_ranges_bits[floor.multiplier - 1]; floor1_Y[0] = get_bits(k); floor1_Y[1] = get_bits(k); var range:int = floor1_ranges[floor.multiplier - 1]; k = 2; var partitions:int = floor.partition_class_list.length; for(var i:int = 0; i < partitions; i++) { var class_:Floor_Class = floor.classes[floor.partition_class_list[i]]; var cbits:uint = class_.subclass; var csub:uint = (1 << cbits) - 1; var cval:uint = 0; if(cbits) { cval = get_codeword(codebooks[class_.masterbook]); switch(cval) { case 0xFFFFFFFF: return STS_FORMAT; case 0xFFFFFFFE: return STS_EOP; } } for(var j:int = class_.dimension; j; j--) { var book:int = class_.subclass_books[cval & csub]; cval >>= cbits; if(book < 0) { floor1_Y[k] = 0; } else { var cw:uint = get_codeword(codebooks[book]); if(cw == 0xFFFFFFFE) return STS_EOP; if(cw >= range) return STS_FORMAT; floor1_Y[k] = cw; } k++; } } ch_data[i_ch].no_residue = false; } } catch(e:EOFError) { return STS_EOP; } return STS_OK; } // residue decode private function residue_decode():int { for(var i_sub:int = 0; i_sub < mapping.submaps.length; i_sub++) { var i_ch:int; var i:int; var ch:int = 0; for(i_ch = 0; i_ch < audio_channels; i_ch++) { if(mapping.mux[i_ch] == i_sub) { sub_no_residue[ch] = ch_data[i_ch].no_residue; sub_data[ch++] = ch_data[i_ch].data; } } var residue:Residue = residues[mapping.submaps[i_sub] & 0xFFFF]; var actual_size:int = n_data; if(residue.type == 2) actual_size *= ch; var limit_residue_begin:int = residue.begin; if(limit_residue_begin > actual_size) limit_residue_begin = actual_size; var limit_residue_end:int = residue.end; if(limit_residue_end > actual_size) limit_residue_end = actual_size; if(limit_residue_begin >= limit_residue_end) continue; var codebook1:Codebook = codebooks[residue.classbook]; var partitions_to_read:int = (limit_residue_end - limit_residue_begin) / residue.partition_size; var save_ch:int; var data_i:Vector.; if(residue.type == 2) { for(i_ch = ch - 1; i_ch >= 0; i_ch--) { if(!sub_no_residue[i_ch]) break; } if(i_ch < 0) continue; sub_no_residue[0] = false; save_ch = ch; ch = 1; data_i = new Vector.(actual_size); for(i = 0; i < actual_size; i++) data_i[i] = 0; } var classifications:Vector. = new Vector.(ch * partitions_to_read); var residue_classifications:uint = residue.cascade.length; for(var pass:int = 0; pass < 8; pass++) { var off:int = limit_residue_begin; for(var partition_count:int = 0; partition_count < partitions_to_read; ) { var classifications_off:int; if(!pass) { // 最初のパス classifications_off = partition_count; for(i_ch = 0; i_ch < ch; i_ch++) { if(!sub_no_residue[i_ch]) { var cw:uint = get_codeword(codebook1); switch(cw) { case 0xFFFFFFFF: return STS_FORMAT; case 0xFFFFFFFE: return STS_EOP; } for(i = codebook1.dimensions - 1; i >= 0; i--) { if(partition_count + i < partitions_to_read) classifications[classifications_off + i] = cw % residue_classifications; cw /= residue_classifications; } } classifications_off += partitions_to_read; } } for(var cwc:int = codebook1.dimensions; cwc; cwc--) { if(partition_count >= partitions_to_read) break; classifications_off = partition_count; for(i_ch = 0; i_ch < ch; i_ch++) { if(!sub_no_residue[i_ch]) { if(residue.cascade[i = classifications[classifications_off]] & (0x01 << pass)) { // unused でない var codebook2:Codebook = codebooks[residue.books[(i << 3) | pass]]; switch(codebook2.lookup_type) { case 1: case 2: break; default: return STS_FORMAT; } var data:Vector. = (residue.type == 2) ? data_i : sub_data[i_ch]; i = 0; if(residue.type) { // 1, 2 for(; i < residue.partition_size; i += codebook2.dimensions) { switch(VQ_lookup(codebook2, data, off + i, 1)) { case STS_FORMAT: return STS_FORMAT; case STS_EOP: if(residue.type == 2) residue2_deinterleave(save_ch, data_i, sub_data); return STS_EOP; } } } else { // 0 var step:int = residue.partition_size / codebook2.dimensions; for(; i < step; i++) { var sts:int = VQ_lookup(codebook2, data, off + i, step); if(sts) return sts; } } } } classifications_off += partitions_to_read; } partition_count++; off += residue.partition_size; } } } if(residue.type == 2) residue2_deinterleave(save_ch, data_i, sub_data); } return STS_OK; } // unpacking the VQ lookup table vectors private function VQ_lookup(codebook:Codebook, value:Vector., value_off:int, delta:int):int { var offset:uint = get_codeword(codebook); switch(offset) { case 0xFFFFFFFF: return STS_FORMAT; case 0xFFFFFFFE: return STS_EOP; } var last:Number = 0; var i:int = 0; if(codebook.lookup_type == 1) { var lookup_values:uint = codebook.values.length; for(; i < codebook.dimensions; i += delta) { value[value_off + i] += codebook.values[uint(offset % lookup_values)] + last; if(codebook.sequence_p) last = value[value_off + i]; offset /= lookup_values; } } else { var multiplicand_offset:uint = offset * codebook.dimensions; for(; i < codebook.dimensions; i += delta) { value[value_off + i] += codebook.values[multiplicand_offset++] + last; if(codebook.sequence_p) last = value[value_off + i]; } } return STS_OK; } private function residue2_deinterleave(ch:int, data_i:Vector., sub_data:Vector.>):void { var i2:int = 0; for(var i:int = 0; i < n_data; i++) { for(var i_ch:int = 0; i_ch < ch; i_ch++) sub_data[i_ch][i] = data_i[i2++]; } } // codeword 取得 private function get_codeword(codebook:Codebook):uint { var codeword_tree:Vector.> = codebook.codeword_tree; for(var i_tree:int = 0; ; ) { var p:uint; try { p = codeword_tree[get_bits(1)][i_tree]; } catch(e:EOFError) { return 0xFFFFFFFE; } if(p == 0xFFFFFFFF) return 0xFFFFFFFF; if(!(p & 0x80000000)) return p; i_tree = p & 0x7FFFFFFF; } return 0; // ダミー } // inverse channel coupling private function inverse_coupling():void { if(mapping.couplings) { for(var i:int = mapping.couplings.length - 1; i >= 0; i--) { var magnitude:uint = mapping.couplings[i] >> 16; var angle :uint = mapping.couplings[i] & 0xFFFF; if(ch_data[magnitude].no_residue && ch_data[angle].no_residue) // M,A 共なし continue; var M_residue:Vector. = ch_data[magnitude].data; var A_residue:Vector. = ch_data[angle].data; for(var j:int = 0; j < n_data; j++) { var M:Number = M_residue[j]; var A:Number = A_residue[j]; if(M > 0) { if(A > 0) { A_residue[j] = M - A; } else { A_residue[j] = M; M_residue[j] = M + A; } } else { if(A > 0) { A_residue[j] = M + A; } else { A_residue[j] = M; M_residue[j] = M - A; } } } } } } // floor curve & dot product private function floor_curve(i_ch:int, data:Vector.):void { var floor:Floor = floors[mapping.submaps[mapping.mux[i_ch]] >> 16]; var x0:int, y0:int, x1:int, y1:int; var i:int, j:int; // step 1 var range:int = floor1_ranges[floor.multiplier - 1]; var floor1_X:Vector. = floor.X_list; var floor_values:uint = floor1_X.length; var floor1_Y:Vector. = ch_data[i_ch].floor1_Y; for(i = 2; i < floor_values; i++) { // low_neighbor(), high_neighbor() var low_neighbor_offset:int = 0; var high_neighbor_offset:int = 1; for(j = 1; j < i; j++) { if(floor1_X[j] < floor1_X[i]) { if(floor1_X[j] > floor1_X[low_neighbor_offset]) low_neighbor_offset = j; } else { if(floor1_X[j] < floor1_X[high_neighbor_offset]) high_neighbor_offset = j; } } x0 = floor1_X[low_neighbor_offset]; y0 = floor1_Y[low_neighbor_offset]; var predicted:int = y0 + int((floor1_Y[high_neighbor_offset] - y0) * (floor1_X[i] - x0) / (floor1_X[high_neighbor_offset] - x0)); // render_point() var val:int = floor1_Y[i]; if(val) { var highroom:int = range - predicted; floor1_step2[low_neighbor_offset] = floor1_step2[high_neighbor_offset] = floor1_step2[i] = true; floor1_Y[i] = (val < (((highroom > predicted) ? predicted : highroom) << 1)) ? ((val & 0x1) ? predicted - ((val + 1) >> 1) : predicted + (val >> 1)) : ((highroom > predicted) ? val : range - val - 1); } else { floor1_step2[i] = false; floor1_Y[i] = predicted; } } // step 2 for(i = 0; i < floor_values; i++) floor1_idx[i] = i; for(i = floor_values - 1; i > 0; i--) { for(j = i - 1; j >= 0; j--) { if(floor1_X[floor1_idx[i]] < floor1_X[floor1_idx[j]]) { var w:int = floor1_idx[i]; floor1_idx[i] = floor1_idx[j]; floor1_idx[j] = w; } } } x0 = 0; y0 = floor1_Y[0] * floor.multiplier; for(i = 1; i < floor_values; i++) { j = floor1_idx[i]; if(floor1_step2[j]) { y1 = floor1_Y[j] * floor.multiplier; x1 = floor1_X[j]; // render_line() var dx:int = x1 - x0; var dy:int = y1 - y0; var dyi:int = dy / dx; var s:int; if(dy < 0) { s = -1; dy = (- dy) % dx; } else { s = 1; dy %= dx; } var err:int = 0; data[x0] *= floor1_inverse_dB_table[y0]; for(x0++; x0 < x1; x0++) { if(x0 >= n_data) break; y0 += dyi; err += dy; if(err >= dx) { err -= dx; y0 += s; } data[x0] *= floor1_inverse_dB_table[y0]; } if(x0 < x1) break; x0 = x1; y0 = y1; } } while(x1 < n_data) data[x1++] *= floor1_inverse_dB_table[y1]; } // inverse MDCT // サンプリング レートの比に応じて周波数の領域を伸張して IMDCT をかける. // これが数学的に正しいサンプリング レート変換になっているかどうか判らないが, // 聴いた限りではおかしいところはないようだ. // 伸張した領域はゼロにしているので,少なくとも折り返しノイズは発生しないはずだが... private function inverse_MDCT(data:Vector., data2:Vector., blockflag:uint):void { var n:int; var bsf:int; var i_rev:Vector.; if(blockflag) { // long window n = sr_blocksize_1; bsf = 0; i_rev = i_rev_1; } else { n = sr_blocksize_0; bsf = bs_0_1; i_rev = i_rev_0; } var n_2:int = n >> 1; var n_4:int = n >> 2; var n_8:int = n >> 3; var n_4_1:int = n_4 - 1; var bsf_1:int = bsf + 1; var bsf_2:int = bsf + 2; var bsf_3:int = bsf + 3; var bsf_4:int = bsf + 4; var a1:Number, a2:Number; var w1:Number, w2:Number, w3:Number, w4:Number; var i:int, j:int, k:int, i2:int, j2:int; // STEP 1, 2 for(i = 0, j = n_2 - 1, i2 = n_4_1, j2 = n_8 - 1; i < n_2; i += 4, j -= 4, i2--, j2--) { // a1 : cos(π * i / n) // a2 : sin(π * i / n) k = i << bsf_1; a1 = sin[sr_blocksize_1 - k]; a2 = sin[k]; w1 = data[i + 2] * a1 - data[i] * a2; w2 = data[i + 2] * a2 + data[i] * a1; // a1 : - cos(π * (n - 1 - j) / n) // a2 : sin(π * (n - 1 - j) / n) k = (n_2 + i) << bsf_1; a1 = sin[k - sr_blocksize_1]; a2 = sin[n_pi - k]; w3 = data[j] * a2 + data[j - 2] * a1; w4 = data[j] * a1 - data[j - 2] * a2; work0[i2] = w1 + w3; work1[i2] = w2 + w4; w1 -= w3; w2 -= w4; // a1 : cos(π * (n - 8 * (j2 + 1)) / n) // a2 : sin(π * (n - 8 * (j2 + 1)) / n) k = (j2 + 1) << bsf_4; if(i < n_4) { a1 = sin[k - sr_blocksize_1]; a2 = sin[n_pi - k]; } else { a1 = - sin[sr_blocksize_1 - k]; a2 = sin[k]; } work0[j2] = w1 * a1 - w2 * a2; work1[j2] = w2 * a1 + w1 * a2; } // STEP 3 var k0:int = n_8; var k1:int = 2; for(i = n_8; !(i & 0x1); i >>= 1) { var nr:int = k0 >> 1; k = 0; for(var r:int = 0; r < nr; r++) { // a1 : cos(π * (8 * r * k1) / n) // a2 : sin(π * (8 * r * k1) / n) if((r << 1) < nr) { a1 = sin[sr_blocksize_1 - k]; a2 = sin[k]; } else { a1 = - sin[k - sr_blocksize_1]; a2 = sin[n_pi - k]; } i2 = n_4_1 - r; for(var s:int = k1; s; s--) { j2 = i2 - nr; w1 = work0[i2] - work0[j2]; w2 = work1[i2] - work1[j2]; work0[i2] += work0[j2]; work1[i2] += work1[j2]; work0[j2] = w1 * a1 - w2 * a2; work1[j2] = w1 * a2 + w2 * a1; i2 -= k0; } k += k1 << bsf_4; } k0 >>= 1; k1 <<= 1; } // STEP 7, 8 for(i = 0, j = n_4_1; i < n_8; i++, j--) { // a1 : cos(π * 2 * (2 * i + 1) / n) // a2 : sin(π * 2 * (2 * i + 1) / n) k = ((i << 1) + 1) << bsf_2; a1 = sin[sr_blocksize_1 - k]; a2 = sin[k]; i2 = i_rev[i]; j2 = i_rev[j - n_8]; w2 = work0[j2 | 1] + work0[i2]; w3 = work1[j2 | 1] - work1[i2]; w1 = a1 * w2 - a2 * w3; w2 = a2 * w2 + a1 * w3; w3 = work0[j2 | 1] - work0[i2]; w4 = work1[j2 | 1] + work1[i2]; // a1 : cos(π * (2 * i + 1) / (n*2)) // a2 : sin(π * (2 * i + 1) / (n*2)) k = ((i << 1) + 1) << bsf; a1 = sin[sr_blocksize_1 - k]; a2 = sin[k]; data[n_4 + i] = - (data[n_4_1 - i] = (w4 + w1) * a2 - (w3 - w2) * a1); // データ前半 data2[i] = (w2 - w3) * a2 - (w4 + w1) * a1; // データ後半 // a1 : cos(π * (2 * j + 1) / (n*2)) // a2 : sin(π * (2 * j + 1) / (n*2)) k = ((j << 1) + 1) << bsf; a1 = sin[sr_blocksize_1 - k]; a2 = sin[k]; data[n_4 + j] = - (data[n_4_1 - j] = (w4 - w1) * a2 + (w3 + w2) * a1); // データ前半 data2[j] = (w2 + w3) * a2 - (w4 - w1) * a1; // データ後半 } } private function ilog(x:int):int { if(x <= 0) return 0; var m:int; for(m = 0; x; m++) x >>= 1; return m; } private function float32_unpack(x:uint):Number { var w:Number = (x & 0x1FFFFF) * Math.pow(2, ((x & 0x7FE00000) >> 21) - 788); return (x & 0x80000000) ? - w : w; } private function get_packet():int { packet.clear(); var first:Boolean = true; var last_seq:uint; try { for(; ; ) { var i:int; if(i_segment == page_segments) { // ページ データなし if(header_type & 0x04) // eos return STS_EOS; if(first_audio) { if(~granule_position_h | ~granule_position_l) { // -1 でない if(granule_position_h || granule_position_l != n_samples) { err.text = "オーディオの開始位置がゼロでないものはサポートしていません。"; return STS_OTHER; } first_audio = false; } } // ページ取得 // capture pattern サーチ for(; ; ) { var pos1:uint; for(pos1 = file_data.position; ; pos1++) { if(pos1 + 4 >= file_data.length) return STS_FORMAT; if(file_data[pos1] == 0x4F && file_data[pos1 + 1] == 0x67 && file_data[pos1 + 2] == 0x67 && file_data[pos1 + 3] == 0x53) // OggS break; } file_data.position = pos1 + 4; // ヘッダ version = file_data.readUnsignedByte(); header_type = file_data.readUnsignedByte(); granule_position_l = file_data.readUnsignedInt(); granule_position_h = file_data.readUnsignedInt(); bitstream_serial_number = file_data.readUnsignedInt(); page_sequence_number = file_data.readUnsignedInt(); var pos_crc:uint = file_data.position; CRC_checksum = file_data.readUnsignedInt(); page_segments = file_data.readUnsignedByte(); file_data.readBytes(segment_table, 0, page_segments); // CRC チェック // X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X+1 // MSB First var pos2:uint, pos_data:uint; pos2 = pos_data = file_data.position; for(i = 0; i < page_segments; i++) pos2 += segment_table[i]; file_data.position = pos_crc; // CRC = 0 file_data.writeUnsignedInt(0); var crc:uint = 0; while(pos1 < pos2) { var byte:uint = (crc >>> 24) ^ file_data[pos1++]; byte ^= byte >> 6; crc = uint(((crc << 8) | byte) ^ (byte << 26) ^ (byte << 23) ^ (byte << 22) ^ (byte << 16) ^ (byte << 12) ^ (byte << 11) ^ (byte << 10) ^ (byte << 8) ^ (byte << 7) ^ (byte << 5) ^ (byte << 4) ^ (byte << 2) ^ (byte << 1)); } file_data.position = pos_crc; // CRC 復旧 file_data.writeUnsignedInt(CRC_checksum); if(crc == CRC_checksum) { file_data.position = pos_data; break; } file_data.position = pos1 + 4; } i_segment = 0; if(first) { if(header_type & 0x01) { // continued packet // 次のパケットの開始位置までシーク for(; i_segment < page_segments; i_segment++) { if(segment_table[i_segment] < 255) { // パケット終了 i_segment++; break; } } if(i_segment == page_segments) continue; } } else { if(page_sequence_number != last_seq + 1) { packet.clear(); first = true; page_segments = 0; continue; } } } first = false; last_seq = page_sequence_number; var size:uint = 0; for(; i_segment < page_segments; i_segment++) { size += segment_table[i_segment]; if(segment_table[i_segment] < 255) // パケット終了 break; } if(size) file_data.readBytes(packet, packet.length, size); if(i_segment < page_segments) { // パケット終了 i_segment++; packet_bit = 0x100; return STS_OK; } } } catch(e:EOFError) { return STS_FORMAT; } return 0; // ダミー } // ビット読み込み private function get_bits(n:uint):uint { var bits:uint = 0; var bit:uint = 0x00000001; for(; n; n--) { if(packet_bit & 0x100) { packet_byte = packet.readUnsignedByte(); packet_bit = 0x01; } if(packet_byte & packet_bit) bits |= bit; packet_bit <<= 1; bit <<= 1; } return bits; } } } class Codebook { public var dimensions:uint; public var entries:uint; public var codeword_tree:Vector.>; public var lookup_type:uint; public var sequence_p:uint; public var values:Vector.; public function Codebook():void { } } class Floor_Class { public var dimension:uint; public var subclass:uint; public var masterbook:uint; public var subclass_books:Vector.; public function Floor_Class():void { } } class Floor { public var partition_class_list:Vector.; public var classes:Vector.; public var multiplier:uint; public var X_list:Vector.; public function Floor():void { } } class Residue { public var type:uint; public var begin:int; public var end:int; public var partition_size:uint; public var classbook:uint; public var cascade:Vector.; public var books:Vector.; public function Residue():void { } } class Mapping { public var couplings:Vector.; public var mux:Vector.; public var submaps:Vector.; public function Mapping():void { } } class Ch_Data { public var data:Vector.; public var floor1_Y:Vector.; public var no_residue:Boolean; public function Ch_Data():void { } }