こんばんは。市民祭りというものに初めていったんですが、プロが全くいず、素人の出す出店やステージのディープな雰囲気にのみこまれそうになってしまい、クセになりそうなきんくまです。
さて、ようやくWAVデータを読み込めるようになったんですが、この本によると、データが読み込めるようになったら次はフィルタ処理。みたいに書いてあったので挑戦してみました。
なんかリングバッファとかいう仕組みでやるみたいです。
FIRフィルタという名前の遅延制御ができるやつを作ってみました。
サンプルはこちら(要Player10)
上のスライダで遅延時間を制御。
下のスライダでもとの音楽との割合を制御します。
それで、この遅延制御ができるようになると、次はローパス・ハイパス・バンドパスフィルターができるようになるみたいです。以前はこのあたりよくわかんない概念だったんですが、DS-10で音のイメージができるようになったんで、あとは実装だけですね。恐るべしDS-10。
以下ソースです。今回、CS3からLabelとSliderのコンポーネントをSWC化して読み込んでます。
package { import fl.controls.Label; import fl.controls.Slider; import fl.events.SliderEvent; import flash.display.Graphics; import flash.display.Sprite; import flash.display.StageScaleMode; import flash.events.Event; import flash.events.MouseEvent; import flash.events.SampleDataEvent; import flash.media.Sound; import flash.net.URLLoader; import flash.net.URLLoaderDataFormat; import flash.net.URLRequest; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; import flash.text.TextFormatAlign; import flash.utils.ByteArray; import flash.utils.Endian; [SWF(width="400", height="300", frameRate="30", backgroundColor="#ffffff")] public class WAV_Sample extends Sprite { private var path:String = "theme.wav"; private var originalData:ByteArray; private var wavData:ByteArray; private var slider:Slider; private var delayRateSlider:Slider; private var ringBuffer:ByteArray; private var isRingBufferFull:Boolean; private var delayRate:uint; public function WAV_Sample() { stage.scaleMode = StageScaleMode.NO_SCALE; setStartBtn(); } private function initializeRingBuffer(delaySampleNum:uint):void { isRingBufferFull = false; ringBuffer = new ByteArray(); ringBuffer.endian = Endian.LITTLE_ENDIAN; while(delaySampleNum) { ringBuffer.writeShort(0);//left ringBuffer.writeShort(0);//right delaySampleNum--; } ringBuffer.position = 0; } private function sliderEventHandler(e:SliderEvent):void { var sampleNum:uint = 44100 * slider.value; initializeRingBuffer(sampleNum); } private function delayRateSliderEventHandler(e:SliderEvent):void { delayRate = delayRateSlider.value; } private function initializeSlider():void { //delay time var label2:Label = new Label(); var sliderControler:SliderController = new SliderController(label2); slider = sliderControler.slider; this.addChild(slider); slider.width = 200; slider.x = (stage.stageWidth - slider.width) / 2; slider.y = stage.stageHeight - 200; slider.minimum = 0; slider.maximum = 3; slider.value = slider.minimum; slider.snapInterval = 0.1; slider.addEventListener(SliderEvent.THUMB_DRAG, sliderEventHandler); var label1:Label = new Label(); label1.text = "delayの時間(秒)"; this.addChild(label1); label1.x = slider.x; label1.y = slider.y - label1.height - 5; this.addChild(label2); label2.x = label1.x + label1.width + 10; label2.y = label1.y; label2.text = slider.value.toString(); //delayRateSlider var label3:Label = new Label(); var label4:Label = new Label(); sliderControler = new SliderController(label3); delayRateSlider = sliderControler.slider; this.addChild(delayRateSlider); delayRateSlider.width = 200; delayRateSlider.x = (stage.stageWidth - slider.width) / 2; delayRateSlider.y = stage.stageHeight - 100; delayRateSlider.minimum = 0; delayRateSlider.maximum = 100; delayRateSlider.value = 50; delayRate = delayRateSlider.value; delayRateSlider.snapInterval = 1; delayRateSlider.addEventListener(SliderEvent.THUMB_DRAG, delayRateSliderEventHandler); label4.text = "delayのもとの音との割合(%)"; label4.width = 150; this.addChild(label4); label4.x = delayRateSlider.x; label4.y = delayRateSlider.y - label4.height - 5; this.addChild(label3); label3.x = label4.x + label4.width + 10; label3.y = label4.y; label3.text = delayRateSlider.value.toString(); } private function soundWAV(e:SampleDataEvent):void { var inLeft:Number; var inRight:Number; var outLeft:Number; var outRight:Number; var readPosition:uint; var A0:Number = (100 - delayRate) / 100; var A1:Number = delayRate / 100; for ( var c:int=0; c < 2048; c++ ) { inLeft = wavData.readShort(); inRight = wavData.readShort(); if(wavData.position == wavData.length) { wavData.position = 0; } //FIRフィルタ。ringBufferが1週してたまったら if(isRingBufferFull) { readPosition = ringBuffer.position; outLeft = A0 * inLeft + A1 * ringBuffer.readShort(); outRight = A0 * inRight + A1 * ringBuffer.readShort(); ringBuffer.position = readPosition; //戻しておく } //たまるまで else { outLeft = inLeft; outRight = inRight; } //ringBuffer ringBuffer.writeShort(inLeft); ringBuffer.writeShort(inRight); if(ringBuffer.position == ringBuffer.length) { isRingBufferFull = true; ringBuffer.position = 0; } //サンプリング。1から-1に収める //割る数は16bitの場合の最大のとる幅 = 32767 outLeft = outLeft / 32767; outLeft = (outLeft > 1) ? 1 : outLeft; outLeft = (outLeft < -1) ? -1 : outLeft; outRight = outRight / 32767; outRight = (outRight > 1) ? 1 : outRight; outRight = (outRight < -1) ? -1 : outRight; e.data.writeFloat(outLeft); e.data.writeFloat(outRight); } } private function init():void { var loader:URLLoader = new URLLoader(); loader.dataFormat = URLLoaderDataFormat.BINARY; loader.addEventListener(Event.COMPLETE, completeHandler); var request:URLRequest = new URLRequest(path); try { loader.load(request); } catch (error:Error) { trace("Unable to load requested document."); } initializeSlider(); } private function completeHandler(event:Event):void { 読み込んだバイトデータをWav形式で解析 var loader:URLLoader = URLLoader(event.target); wavData = event.target.data as ByteArray; wavData.endian = Endian.LITTLE_ENDIAN; wavData = parse(wavData); wavData.position = 0; originalData = new ByteArray(); originalData.endian = Endian.LITTLE_ENDIAN; originalData.writeBytes(wavData); initializeRingBuffer(0); //音楽スタート var mySound:Sound = new Sound(); mySound.addEventListener("sampleData", soundWAV); mySound.play(); } private function setStartBtn():void { var sp:Sprite = new Sprite(); sp.graphics.beginFill(0x00ff00, 1); sp.graphics.drawRect(0,0,250,50); sp.graphics.endFill(); var tff:TextFormat = new TextFormat(); tff.align = TextFormatAlign.CENTER; tff.size = 14; var tf:TextField = new TextField(); tf.autoSize = TextFieldAutoSize.LEFT; tf.selectable = false; tf.text = "音量をしぼってから慎重にスタート。"; tf.setTextFormat(tff); sp.addChild(tf); tf.x = 20; tf.y = 15; addChild(sp); sp.x = (stage.stageWidth - sp.width) / 2; sp.y = (stage.stageHeight - sp.height) / 2 - 20; sp.addEventListener(MouseEvent.MOUSE_DOWN, onStartDown); } private function onStartDown(e:MouseEvent):void { var sp:Sprite = e.currentTarget as Sprite; removeChild(sp); init(); } private function parse( bytes: ByteArray ): ByteArray { bytes.position = 0; bytes.endian = Endian.LITTLE_ENDIAN; bytes.readUTFBytes( 4 ); // RIFF bytes.readUnsignedInt(); // entire fileLength - 8 bytes.readUTFBytes( 4 ); // WAVE var id: String; var length: uint; var position: uint; var parseBytes:ByteArray = new ByteArray(); var compression:uint; var channels:uint; var rate:uint; var bytesPerSecond:uint; var blockAlign:uint; var bits:uint; while( bytes.position < bytes.length ) { id = bytes.readUTFBytes( 4 ); length = bytes.readUnsignedInt(); position = bytes.position; switch( id ) { case 'fmt ': compression = bytes.readUnsignedShort(); channels = bytes.readUnsignedShort(); rate = bytes.readUnsignedInt(); bytesPerSecond = bytes.readUnsignedInt(); blockAlign = bytes.readUnsignedShort(); bits = bytes.readUnsignedShort(); bytes.position = position + length; var log:String = ""; log += "フォーマットタイプ(1だとPCM): " + compression; log += "nチャネル数(2だとステレオ) : " + channels; log += "nサンプリング周波数 : " + rate + "[Hz]"; log += "n平均データ転送速度 : " + bytesPerSecond; log += "nブロックサイズ : " + blockAlign; log += "nサンプルあたりのビット数 : " + bits + "[bit]"; trace(log); break; case 'data': var data: ByteArray = new ByteArray(); data.endian = Endian.LITTLE_ENDIAN; data.writeBytes( bytes, position, length ); data.position = 0; parseBytes = data; bytes.position = position + length; trace("総サンプル数: " + length / 2); break; default: bytes.position = position + length; break; } } return parseBytes; } } } import flash.display.Sprite; import flash.text.TextField; import flash.geom.Rectangle; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; import fl.controls.Slider; import fl.events.SliderEvent; import fl.controls.Label; import flash.utils.ByteArray; import flash.events.Event; class Button extends Sprite { private var textbox:TextField; private var textf:TextFormat; private var background:Sprite; public function Button(text:String, color:Number) { textbox = new TextField(); addChild(textbox); textbox.autoSize = TextFieldAutoSize.LEFT; textbox.selectable = false; textbox.x = 5; textbox.y = 5; textbox.text = text; textf = new TextFormat(); textf.color = 0xffffff; textbox.setTextFormat(textf); background = new Sprite(); drawRect(background, color); addChildAt(background,0); var bk:Sprite = new Sprite(); drawRect(bk, 0, 0); addChild(bk); } private function drawRect(sp:Sprite, color:Number, alpha:Number = 1):void { sp.graphics.clear(); var rect:Rectangle = this.getBounds(textbox); sp.graphics.beginFill(color, alpha); sp.graphics.drawRect(0, 0, rect.width + 10, 30); sp.graphics.endFill(); } public function setColor(color:Number, alpha:Number = 1):void { drawRect(background, color, alpha); } public function setText(text:String):void { textbox.text = text; textbox.setTextFormat(textf); } } class SliderController { public var slider:Slider; public var label:Label; public function SliderController(label:Label) { slider = new Slider(); this.configureListeners(); this.label = label; } private function configureListeners():void { slider.addEventListener(SliderEvent.CHANGE, sliderChanged); slider.addEventListener(SliderEvent.THUMB_DRAG, sliderDrag); slider.addEventListener(SliderEvent.THUMB_PRESS, sliderPress); slider.addEventListener(SliderEvent.THUMB_RELEASE, sliderRelease); } private function sliderDrag(e:SliderEvent):void { trace("Slider dragging: " + e.target.value); label.text = e.target.value; } private function sliderPress(e:SliderEvent):void { trace("Slider pressed"); } private function sliderRelease(e:SliderEvent):void { trace("Slider released"); } private function sliderChanged(e:SliderEvent):void { trace("Slider changed: " + e.target.value); label.text = e.target.value; } }
■ 自作iPhoneアプリ 好評発売中!
・フォルメモ - シンプルなフォルダつきメモ帳
・ジッピー電卓 - 消費税や割引もサクサク計算!
■ LINEスタンプ作りました!
毎日使える。とぼけたウサギ