forked from: loadPCMFromByteArrayでサイン波の再生
----------------------------------------------------------------------------------------------------
インポート
loadPCMFromByteArrayでサイン波の再生【音量にご注意!】
参考記事:
http://dev.yuichiroharai.com/post/play-sine-wave-with-loadpcmfrombytearray/
@author Yuichiroh Arai
/**
* Copyright yuinore ( http://wonderfl.net/user/yuinore )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/mjQs
*/
// forked from yuichiroharai's loadPCMFromByteArrayでサイン波の再生
package {
// ----------------------------------------------------------------------------------------------------
// インポート
//
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Loader;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.external.ExternalInterface;
import flash.geom.Rectangle;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundMixer;
import flash.net.URLRequest;
import flash.system.ApplicationDomain;
import flash.system.Capabilities;
import flash.system.LoaderContext;
import flash.system.SecurityDomain;
import flash.text.Font;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.utils.ByteArray;
import net.hires.debug.Stats;
/**
* loadPCMFromByteArrayでサイン波の再生【音量にご注意!】
* 参考記事:
* http://dev.yuichiroharai.com/post/play-sine-wave-with-loadpcmfrombytearray/
*
* @author Yuichiroh Arai
*/
public class LoadPCMFromByteArray extends Sprite {
// ----------------------------------------------------------------------------------------------------
// メイン処理
//
private const FPS:uint = 60; // フレームレート
private const STAGE_SIZE:uint = 465; // ステージサイズ
private const SAMPLE_RATE:uint = 44100;
private const LENGTH:uint = 1;
private const SAMPLE_LENGTH:uint = SAMPLE_RATE*(LENGTH+0.2); // 少し長めにデータを生成
private const HERTZ_LIST:Vector.<Number> = Vector.<Number>([16.3516, 17.3239, 18.3540, 19.4454, 20.6017, 21.8268, 23.1247, 24.4997, 25.9565, 27.5000, 29.1352, 30.8677, 32.7032]);
private const KEY_CODE_LIST:Vector.<uint> = Vector.<uint>([90, 83, 88, 68, 67, 86, 71, 66, 72, 78, 74, 77, 188]);
private var _sound:Vector.<Sound>;
private var _soundChannel:SoundChannel;
private var _byteArrayList:Vector.<ByteArray>;
private var _currentHertz:int = -1;
private var _currentOctave:int = 4;
public function LoadPCMFromByteArray() {
stage.frameRate = FPS;
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
_initBack();
stage.addEventListener(Event.RESIZE, _onResize);
stage.addEventListener(Event.FULLSCREEN, _onResize);
_loadFont(step1);
function step1():void {
//_initStats();
_initKeyboard();
_initSpectrum();
_initHertzOctave();
_initSlideBar();
_initCaution();
_byteArrayList = new Vector.<ByteArray>(HERTZ_LIST.length, true);
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyBoardDown);
}
function onKeyBoardDown(e:KeyboardEvent):void {
if (e.keyCode == 38) {
if (_currentOctave < 9) {
++_currentOctave;
_byteArrayList = new Vector.<ByteArray>(HERTZ_LIST.length, true);
_textOctave.text = _currentOctave.toString();
}
} else if (e.keyCode == 40) {
if (_currentOctave > 0) {
--_currentOctave;
_byteArrayList = new Vector.<ByteArray>(HERTZ_LIST.length, true);
_textOctave.text = _currentOctave.toString();
}
} else {
_currentHertz = KEY_CODE_LIST.indexOf(e.keyCode);
if (_currentHertz == -1) return;
_destroySound();
_createByteArray();
_loadAndPlaySound();
_textHertz.text = (HERTZ_LIST[_currentHertz]*Math.pow(2, _currentOctave)).toString();
}
}
}
/**
* ステージリサイズ時の処理
*/
private function _onResize(e:Event):void {
_moveSpectrum();
_moveKeyboard();
_moveOctave();
_moveSlideBar();
_moveCaution();
_resizeBack();
}
// ----------------------------------------------------------------------------------------------------
// サウンドの生成、再生など
//
/**
* 現在の音程のByteArrayからサウンドを再生
*/
private function _loadAndPlaySound():void {
_sound = Vector.<Sound>([new Sound()]);
_byteArrayList[_currentHertz].position = 0;
_sound[0].loadPCMFromByteArray(_byteArrayList[_currentHertz], SAMPLE_LENGTH, "float", true, SAMPLE_RATE);
_soundChannel = _sound[0].play(0);
stage.addEventListener(Event.ENTER_FRAME, _onPlayingSound);
}
/**
* 現在のサウンドを破棄
*/
private function _destroySound():void {
if (_soundChannel != null) {
_soundChannel.stop();
_soundChannel = null;
}
if (_sound != null && _sound[0] != null) {
try { _sound[0].close(); } catch (e:Error) {}
delete _sound[0];
_sound = null;
}
stage.removeEventListener(Event.ENTER_FRAME, _onPlayingSound);
}
/**
* 現在の音程のByteArrayデータが無ければ生成
*/
private function _createByteArray():void {
var i:uint, byteArray:ByteArray, unit:Number, amp:Number;
if (_byteArrayList[_currentHertz] != null) return;
byteArray = new ByteArray();
unit = Math.PI*2/SAMPLE_RATE*(HERTZ_LIST[_currentHertz]*Math.pow(2, _currentOctave));
for (i=0;i<SAMPLE_LENGTH;i++) {
var j = 0;
amp = 0;
for(j = 1; j < 64; j++) {
amp += Math.round(Math.sin(i*j*unit) / j * 1000000000000000) / 1000000000000000;
}
amp *= 0.1;
if(i < 100) amp *= i / 100.0;
if(i > SAMPLE_LENGTH - 100) amp *= (SAMPLE_LENGTH - 100) / 100;
//amp *= Math.pow(Math.max(0, 1.0 - i / 10000), 2);
byteArray.writeFloat(amp);
byteArray.writeFloat(amp);
}
_byteArrayList[_currentHertz] = byteArray;
}
// ----------------------------------------------------------------------------------------------------
// スペクトラム表示
//
private const SPECTRUM_SIZE_WIDTH:uint = 256;
private const SPECTRUM_SIZE_HEIGHT:uint = 200;
private var _spSpectrum:Sprite;
private var _bmpSpectrumBorder:Bitmap;
private var _bmpSpectrumMeter:Bitmap;
/**
* スペクトラム表示を初期化
*/
private function _initSpectrum():void {
_spSpectrum = new Sprite();
addChild(_spSpectrum);
_bmpSpectrumMeter = new Bitmap();
_bmpSpectrumMeter.x = _bmpSpectrumMeter.y = 1;
_spSpectrum.addChild(_bmpSpectrumMeter);
_bmpSpectrumBorder = new Bitmap(makeBorderBitmapData(SPECTRUM_SIZE_WIDTH+2, SPECTRUM_SIZE_HEIGHT+2, 0xff404040));
_spSpectrum.addChild(_bmpSpectrumBorder);
_moveSpectrum();
}
/**
* スペクトラム表示の配置を更新
*/
private function _moveSpectrum():void {
if (_spSpectrum == null) return;
_spSpectrum.x = int((stage.stageWidth - SPECTRUM_SIZE_WIDTH+2)/2);
_spSpectrum.y = int((stage.stageHeight - SPECTRUM_SIZE_HEIGHT+2)/2);
}
// ----------------------------------------------------------------------------------------------------
// スペクトラム
//
private const SPECTRUM_MAX:Number = 1.4142136;
private const STRETCH_FACTOR_LIST:Vector.<Number> = Vector.<Number>([0, 1, 2, 3, 5, 9, 17, 33, 65, 129, 257]);
private var _spectrumDiv:uint=0;
/**
* サウンドに合わせてスペクトラムを描画
*/
private function _onPlayingSound(e:Event):void {
var i:uint, bytes:ByteArray, l:Number, r:Number, value:Number, h:uint, stretchFactor:uint, bmpd:BitmapData;
if (_soundChannel.position > LENGTH*1000) {
_bmpSpectrumMeter.bitmapData = null;
_destroySound();
return;
}
stretchFactor = STRETCH_FACTOR_LIST[_spectrumDiv];
bytes = new ByteArray();
SoundMixer.computeSpectrum(bytes, true, stretchFactor);
bmpd = new BitmapData(SPECTRUM_SIZE_WIDTH, SPECTRUM_SIZE_HEIGHT, true, 0);
bmpd.lock();
for (i=0;i<256;i++) {
bytes.position = i*4;
l = bytes.readFloat();
bytes.position = i*4 + 1024;
r = bytes.readFloat();
value = (l > r) ? l : r;
h = int(value/SPECTRUM_MAX*200+0.5);
bmpd.fillRect(new Rectangle(i, SPECTRUM_SIZE_HEIGHT - h, 1, h), 0xff808080);
}
bmpd.unlock();
if (_bmpSpectrumMeter.bitmapData != null) _bmpSpectrumMeter.bitmapData.dispose();
_bmpSpectrumMeter.bitmapData = bmpd;
}
// ----------------------------------------------------------------------------------------------------
// 鍵盤表示
//
private const KEYBOARD_WHITE_WIDTH:uint = 20;
private const KEYBOARD_WHITE_HEIGHT:uint = 50;
private const KEYBOARD_BLACK_WIDTH:uint = 15;
private const KEYBOARD_BLACK_HEIGHT:uint = 30;
private const KEY_WHITE_LIST:Vector.<String> = Vector.<String>(["Z", "X", "C", "V", "B", "N", "M", ","]);
private const KEY_BLACK_LIST:Vector.<String> = Vector.<String>(["S", "D", "", "G", "H", "J"]);
private var _spKeyboard:Sprite;
/**
* 鍵盤表示を初期化
*/
private function _initKeyboard():void {
var i:uint, text:TextField, bmp:Bitmap, bmpd:BitmapData, s:Shape, g:Graphics;
_spKeyboard = new Sprite();
addChild(_spKeyboard);
// 白鍵盤
bmpd = new BitmapData(KEYBOARD_WHITE_WIDTH, KEYBOARD_WHITE_HEIGHT, true, 0xffffffff);
for (i=0;i<8;i++) {
bmp = new Bitmap(bmpd);
bmp.x = i*(KEYBOARD_WHITE_WIDTH+1);
_spKeyboard.addChild(bmp);
text = new TextField();
text.defaultTextFormat = new TextFormat(FONT_NAME_KROEGER_0655, 8, 0x000000);
text.embedFonts = true;
text.autoSize = TextFieldAutoSize.LEFT;
text.multiline = false;
text.selectable = false;
text.text = KEY_WHITE_LIST[i];
text.x = int(i*(KEYBOARD_WHITE_WIDTH+1) + (KEYBOARD_WHITE_WIDTH-text.width)/2);
text.y = KEYBOARD_WHITE_HEIGHT - 15;
_spKeyboard.addChild(text);
}
// 黒鍵盤
bmpd = new BitmapData(KEYBOARD_BLACK_WIDTH, KEYBOARD_BLACK_HEIGHT, true, 0xff000000);
for (i=0;i<6;i++) {
if (i == 2) continue;
bmp = new Bitmap(bmpd);
bmp.x = (i+1)*(KEYBOARD_WHITE_WIDTH+1) - KEYBOARD_BLACK_WIDTH/2 - 1;
_spKeyboard.addChild(bmp);
text = new TextField();
text.defaultTextFormat = new TextFormat(FONT_NAME_KROEGER_0655, 8, 0xffffff);
text.embedFonts = true;
text.autoSize = TextFieldAutoSize.LEFT;
text.multiline = false;
text.selectable = false;
text.text = KEY_BLACK_LIST[i];
text.x = int((i+1)*(KEYBOARD_WHITE_WIDTH+1) - text.width/2);
text.y = KEYBOARD_BLACK_HEIGHT - 15;
_spKeyboard.addChild(text);
}
// オクターブ
s = new Shape();
g = s.graphics;
g.clear();
g.beginFill(0xffffff, 1);
g.moveTo(4, 0);
g.lineTo(8, 8);
g.lineTo(0, 8);
g.lineTo(4, 0);
g.endFill();
bmpd = new BitmapData(8, 8, true, 0);
bmpd.draw(s);
bmp = new Bitmap(bmpd);
bmp.x = (KEYBOARD_WHITE_WIDTH+1)*8 + 20;
bmp.y = KEYBOARD_WHITE_HEIGHT/2 - 15;
_spKeyboard.addChild(bmp);
g.clear();
g.beginFill(0xffffff, 1);
g.moveTo(0, 0);
g.lineTo(8, 0);
g.lineTo(4, 8);
g.lineTo(0, 0);
g.endFill();
bmpd = new BitmapData(8, 8, true, 0);
bmpd.draw(s);
bmp = new Bitmap(bmpd);
bmp.x = (KEYBOARD_WHITE_WIDTH+1)*8 + 20;
bmp.y = KEYBOARD_WHITE_HEIGHT/2 + 5;
_spKeyboard.addChild(bmp);
_moveKeyboard();
}
/**
* 鍵盤表示の配置を更新
*/
private function _moveKeyboard():void {
if (_spKeyboard == null) return;
_spKeyboard.x = int((stage.stageWidth - _spKeyboard.width)/2);
_spKeyboard.y = int((stage.stageHeight + SPECTRUM_SIZE_HEIGHT+2)/2 + 40);
}
// ----------------------------------------------------------------------------------------------------
// 周波数とオクターブの表示
//
private var _spHertzOctave:Sprite;
private var _textHertz:TextField;
private var _textOctave:TextField;
/**
* 周波数とオクターブの表示を初期化
*/
private function _initHertzOctave():void {
var text:TextField;
_spHertzOctave = new Sprite();
addChild(_spHertzOctave);
// 周波数
text = new TextField();
text.defaultTextFormat = new TextFormat(FONT_NAME_KROEGER_0555, 8, 0x808080);
text.embedFonts = true;
text.autoSize = TextFieldAutoSize.LEFT;
text.multiline = false;
text.selectable = false;
text.text = "HERTZ:";
_spHertzOctave.addChild(text);
_textHertz = new TextField();
_textHertz.defaultTextFormat = new TextFormat(FONT_NAME_KROEGER_0655, 8, 0xffffff);
_textHertz.embedFonts = true;
_textHertz.autoSize = TextFieldAutoSize.LEFT;
_textHertz.multiline = false;
_textHertz.selectable = false;
_textHertz.text = "---";
_textHertz.x = text.width;
_textHertz.y = -2;
_spHertzOctave.addChild(_textHertz);
// オクターブ
text = new TextField();
text.defaultTextFormat = new TextFormat(FONT_NAME_KROEGER_0555, 8, 0x808080);
text.embedFonts = true;
text.autoSize = TextFieldAutoSize.LEFT;
text.multiline = false;
text.selectable = false;
text.text = "OCTAVE:";
text.x = (KEYBOARD_WHITE_WIDTH+1)*5;
_spHertzOctave.addChild(text);
_textOctave = new TextField();
_textOctave.defaultTextFormat = new TextFormat(FONT_NAME_KROEGER_0655, 8, 0xffffff);
_textOctave.embedFonts = true;
_textHertz.autoSize = TextFieldAutoSize.LEFT;
_textOctave.multiline = false;
_textOctave.selectable = false;
_textOctave.text = _currentOctave.toString();
_textOctave.x = text.x + text.width;
_textOctave.y = -2;
_spHertzOctave.addChild(_textOctave);
_moveOctave();
}
/**
* 周波数とオクターブの配置を更新
*/
private function _moveOctave():void {
if (_spHertzOctave == null) return;
_spHertzOctave.x = int((stage.stageWidth - _spKeyboard.width)/2 - 2);
_spHertzOctave.y = int((stage.stageHeight + SPECTRUM_SIZE_HEIGHT+2)/2 + 20);
}
// ----------------------------------------------------------------------------------------------------
// stretchFactorを変更するためのスライドバー
//
private const SLIDE_BAR_WIDTH:uint = 120;
private var _spSlideBar:Sprite;
private var _slideBar:SlideBar;
private var _textSlideBar:TextField;
/**
* スライドバーを初期化
*/
private function _initSlideBar():void {
var text:TextField;
_spSlideBar = new Sprite();
addChild(_spSlideBar);
text = new TextField();
text.defaultTextFormat = new TextFormat(FONT_NAME_KROEGER_0555, 8, 0x808080);
text.embedFonts = true;
text.autoSize = TextFieldAutoSize.LEFT;
text.multiline = false;
text.selectable = false;
text.text = "STRETCH FACTOR:";
text.x = -5;
_spSlideBar.addChild(text);
_textSlideBar = new TextField();
_textSlideBar.defaultTextFormat = new TextFormat(FONT_NAME_KROEGER_0655, 8, 0xffffff);
_textSlideBar.embedFonts = true;
_textSlideBar.autoSize = TextFieldAutoSize.LEFT;
_textSlideBar.multiline = false;
_textSlideBar.selectable = false;
_textSlideBar.text = STRETCH_FACTOR_LIST[_spectrumDiv].toString();
_textSlideBar.x = text.width;
_textSlideBar.y = -2;
_spSlideBar.addChild(_textSlideBar);
_slideBar = new SlideBar(SLIDE_BAR_WIDTH, STRETCH_FACTOR_LIST.length-1, SlideBar.createBar(7, 15, 0xffffffff), SlideBar.createRail(SLIDE_BAR_WIDTH, 1, 0xff404040));
_slideBar.value = _spectrumDiv;
_slideBar.onChange = onChange;
_slideBar.y = 25;
_spSlideBar.addChild(_slideBar);
_moveSlideBar();
function onChange(value:uint):void {
_spectrumDiv = value;
_textSlideBar.text = STRETCH_FACTOR_LIST[_spectrumDiv].toString();
}
}
/**
* スライドバーの配置を更新
*/
private function _moveSlideBar():void {
if (_spSlideBar == null) return;
_spSlideBar.x = int((stage.stageWidth - _spSlideBar.width)/2 + 5);
_spSlideBar.y = int((stage.stageHeight - SPECTRUM_SIZE_HEIGHT+2)/2 - 48);
}
// ----------------------------------------------------------------------------------------------------
// 警告テキスト
//
private var _textCaution:TextField;
/**
* 警告テキストを初期化
*/
private function _initCaution():void {
_textCaution = new TextField();
_textCaution.defaultTextFormat = new TextFormat(FONT_NAME_KROEGER_0655, 8, 0xCC0000);
_textCaution.embedFonts = true;
_textCaution.autoSize = TextFieldAutoSize.LEFT;
_textCaution.multiline = false;
_textCaution.selectable = false;
_textCaution.text = "CAUTION! HIGH VOLUME SOUND!";
addChild(_textCaution);
_moveCaution();
}
/**
* 警告テキストの配置を更新
*/
private function _moveCaution():void {
if (_textCaution == null) return;
_textCaution.x = int((stage.stageWidth - _textCaution.width)/2);
_textCaution.y = int((stage.stageHeight - SPECTRUM_SIZE_HEIGHT+2)/2 - 80);
}
// ----------------------------------------------------------------------------------------------------
// フォント内蔵のSWFをロード、登録
//
private const FONT_CLASS_KROEGER_0555:String = "Kroeger0555";
private const FONT_CLASS_KROEGER_0655:String = "Kroeger0655";
private const FONT_NAME_KROEGER_0555:String = "kroeger 05_55";
private const FONT_NAME_KROEGER_0655:String = "kroeger 06_55";
private const FONT_SWF_URL:String = "http://global.yuichiroharai.com/swf/FontKroeger.swf";
/**
* フォント内蔵のSWFをロード
*
* @param callback コールバック関数
*/
private function _loadFont(callBack:Function):void {
var loader:Loader;
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, complete);
loader.load(new URLRequest(FONT_SWF_URL), new LoaderContext(true, ApplicationDomain.currentDomain, SecurityDomain.currentDomain));
function complete(e:Event):void {
try {
Font.registerFont(loader.contentLoaderInfo.applicationDomain.getDefinition(FONT_CLASS_KROEGER_0555) as Class);
Font.registerFont(loader.contentLoaderInfo.applicationDomain.getDefinition(FONT_CLASS_KROEGER_0655) as Class);
} catch (e:Error) { return; }
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, complete);
loader = null;
if (callBack is Function) callBack.apply();
}
}
// ----------------------------------------------------------------------------------------------------
// 背景色
//
private var _bmpBack:Bitmap;
/**
* 背景用のBitmapを作成
*/
private function _initBack():void {
_bmpBack = new Bitmap(new BitmapData(stage.stageWidth, stage.stageHeight, false, 0));
addChildAt(_bmpBack, 0);
}
/**
* 背景用のBitmapをリサイズ
*/
private function _resizeBack():void {
if (_bmpBack == null || _bmpBack.bitmapData == null) return;
_bmpBack.bitmapData.dispose();
_bmpBack.bitmapData = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0);
}
// ----------------------------------------------------------------------------------------------------
// ユーティリティメソッド
//
/**
* ボーダーBitmapDataを作成
*
* @param width 横幅
* @param height 高さ
* @param argb ARGBカラー
* @return ボーダーBitmapData
*/
public function makeBorderBitmapData(width:uint, height:uint, argb:uint):BitmapData {
var bmpd:BitmapData;
bmpd = new BitmapData(width, height, true, 0);
addBorderBitmapData(bmpd, argb);
return bmpd;
}
/**
* BitmapDataにボーダーを上書き
*
* @param bmpd 対象のBitmapData
* @param argb ARGBカラー
*/
public function addBorderBitmapData(bmpd:BitmapData, argb:uint):void {
var width:uint, height:uint, i:uint;
width = bmpd.width;
height = bmpd.height;
bmpd.lock();
for (i=0;i<height;i++) {
bmpd.setPixel32(0, i, argb);
bmpd.setPixel32(width-1, i, argb);
}
for (i=1;i<width-1;i++) {
bmpd.setPixel32(i, 0, argb);
bmpd.setPixel32(i, height-1, argb);
}
bmpd.unlock();
}
// ----------------------------------------------------------------------------------------------------
// スタッツ
//
/**
* スタッツを表示
*/
private function _initStats():void {
var stats:Stats;
stats = new Stats();
addChild(stats);
}
}
}
// ----------------------------------------------------------------------------------------------------
// インポート
//
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.SimpleButton;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
/**
* スライドバー(X軸)を構成するクラスです。
*/
class SlideBar extends Sprite {
// ----------------------------------------------------------------------------------------------------
// 変数
//
// スライドバーのボタン
private var _bar:SimpleButton;
// スライドバーのレール
private var _rail:Sprite;
// スライドバーの横幅
private var _width:uint;
// スライドバーの取り得る値の範囲
private var _range:uint;
/**
* バーの値です。
*/
public function get value():uint {
return _value;
}
public function set value(v:uint):void {
_value = (v > _range) ? _range : v;
_barMoveJust();
if (onChange is Function) onChange.apply(null, [_value]);
}
private var _value:uint = 0;
/**
* バーの移動係数です。
*/
public function get moveFactor():Number {
return _moveFactor;
}
public function set moveFactor(v:Number):void {
_moveFactor = (v >= 0 && v <= 1) ? v : 0.5;
}
private var _moveFactor:Number = 0.5;
// valueに対応するX座標
private var _x:Number=0;
// スライドバーが移動中かどうか
private var _moving:Boolean=false;
/**
* SlideBarの値が変更された時に呼び出されるコールバック関数です。
*/
public var onChange:Function;
// ----------------------------------------------------------------------------------------------------
// コンストラクタ
//
/**
* スライドバーを作成します。
*
* @param width スライドバーの幅
* @param range スライドバーの値の数
* @param bar スライドバーのバーを表すSimpleButtonです。
* @param rail スライドバーのレールを表すSpriteです。
*/
public function SlideBar(width:uint, range:uint, bar:SimpleButton, rail:Sprite) {
_width = (width < 2) ? 2 : width;
_range = (range < 2 || range > width) ? width : range;
addChildAt(_rail = rail, 0);
addChild(_bar = bar);
_bar.addEventListener(MouseEvent.MOUSE_DOWN, _barMouseDown, false, 0, true);
}
// ----------------------------------------------------------------------------------------------------
// スライドバーの操作
//
// バーのドラッグ開始
private function _barMouseDown(e:Event):void {
if (stage == null) return;
stage.addEventListener(MouseEvent.MOUSE_MOVE, _mouseMove);
stage.addEventListener(MouseEvent.MOUSE_UP, _mouseUp);
}
// バーのドラッグ終了
private function _mouseUp(e:Event):void {
if (stage == null) return;
stage.removeEventListener(MouseEvent.MOUSE_MOVE, _mouseMove);
stage.removeEventListener(MouseEvent.MOUSE_UP, _mouseUp);
}
// バーのドラッグ
private function _mouseMove(e:Event):void {
var temp:uint = _value;
if (stage == null) return;
if (!_moving) {
stage.addEventListener(Event.ENTER_FRAME, _barMove);
_moving = true;
}
if (mouseX < 0) {
_value = 0;
_x = 0;
} else if (mouseX > _width) {
_value = _range;
_x = _width;
} else {
_value = uint(mouseX/_width*_range + 0.5);
_x = uint(_width*_value/_range);
}
if (temp != _value && onChange is Function) onChange.apply(null, [_value]);
}
// バーの移動
private function _barMove(e:Event):void {
var diff:Number, abs:Number;
diff = _x - _bar.x;
abs = (diff < 0) ? -diff : diff;
if (abs*_moveFactor < 0.05) {
_bar.x = _x;
if (_moving) {
stage.removeEventListener(Event.ENTER_FRAME, _barMove);
_moving = false;
}
} else {
_bar.x += diff*_moveFactor;
}
}
// バーの強制移動
private function _barMoveJust():void {
_bar.x = _x = uint(_width*_value/_range);
if (_moving) {
stage.removeEventListener(Event.ENTER_FRAME, _barMove);
_moving = false;
}
}
/**
* バーを作成
*
* @param width バーの幅
* @param range バーの高さ
* @param argb バーのARGBカラー
*/
public static function createBar(width:uint, height:uint, argb:uint):SimpleButton {
var bmp:Bitmap;
bmp = new Bitmap(new BitmapData(width, height, true, argb));
bmp.x = - uint(width/2);
bmp.y = - uint(height/2);
return new SimpleButton(bmp, bmp, bmp, bmp);
}
/**
* レールを作成
*
* @param width バーの幅
* @param range バーの高さ
* @param argb バーのARGBカラー
*/
public static function createRail(width:uint, height:uint, argb:uint):Sprite {
var bmp:Bitmap, sprite:Sprite;
bmp = new Bitmap(new BitmapData(width, height, true, argb));
bmp.x = 0;
bmp.y = - uint(height/2);
sprite = new Sprite();
sprite.addChild(bmp);
return sprite;
}
}