WAVLoaderを作ってみようとしたが失敗(Astro)

2008/08/19

なんだかもうすぐ夏も終わりに近づいてきているなという感じですね。きんくまです。

この間こんな本を買いました。
WAVプログラミング―C言語で学ぶ音響処理

それで、「よーし、これで俺もサウンドプログラミングマスターだ!」なんて思ったんですが、そんなに甘いわけありませんね。
まず、C言語の壁。
画像とサウンド、ARとか、ちょっと楽しそうなものに手をだそうとするといつもぶつかる壁、C。
Cでおみくじプログラムまでしか作ったことのない私には、高度すぎるわけです。でも、本のプログラムをコンパイルするぐらいならできるかも。そこからいろいろいじってみて勉強ですね。

Cができたとしても、次にぶつかるのがバイトコード。これもこれで、正直高度すぎます。

そんなレベルの私ですが、思いつきました。
WAVデータをバイドコードにデコードして、Astroの新機能のSound生成にぶちこめば、音がなるんじゃないの?

それで、試してみたのが、以下のもの。
サンプルです。※要Player10 beta2

いや、見事にホワイトノイズです。


まず、WAVをバイトコードに入れる処理から。WAVをバイトコードにいれて、swfに変換して読み込むという超絶処理をしている方がいました。
wavファイルを再生する方法

それで、そこからバイトコードに入れる部分を拝借させていただきました。

private function completeHandler(event:Event):Boolean
{
    var loader:URLLoader = URLLoader(event.target);
    var ba:ByteArray = event.target.data;

    var tag:uint;
    var len:uint;
    var tmp:uint;
    var pos:uint;

    wavData = new ByteArray();

    ba.endian = Endian.LITTLE_ENDIAN;
    ba.position = 0;

    if(ba.readUnsignedInt() != RIFF){
        trace("WAV Format Error(RIFF)");
        return false;
    }
    fileSize = ba.readUnsignedInt();
    if(ba.readUnsignedInt() != WAVE){
        trace("WAV Format Error(WAVE)");
        return false;
    }
    while(ba.bytesAvailable > 0){
        tag = ba.readUnsignedInt();
        len = ba.readUnsignedInt();
        pos = ba.position;
        switch(tag){
        case FMT:
            //fmtチャンクの読込
            formatID = ba.readUnsignedShort();
            channel = ba.readUnsignedShort();
            rate = ba.readUnsignedInt();
            bps = ba.readUnsignedInt();
            blockSize = ba.readUnsignedShort();
            sampling = ba.readUnsignedShort();
            break;
        case DATA:
            //dataチャンクの読込
            wavData.writeBytes(ba, ba.position, len);
            break;
        }
        ba.position = pos + len;
    }
    wavData.position = 0;
    var mySound:Sound = new Sound();
      mySound.addEventListener(Event.SAMPLE_DATA, soundWAV);
      mySound.play();

      var log:String =   "formatID:" + formatID + "n"
               + "channel:" + channel + "n"
               + "rate:" + rate + "n"
               + "bps:" + bps + "n"
               + "blockSize:" + blockSize + "n"
               + "sampling:" + sampling + "n"
    trace(log);
    return true;
}

それで、これをAstroの新機能にひもづければと思って調べてみました。情報ありがとうございます。
Adobe Is Making Some Noise Part 2
Adobe Is Making Some Noise Part 3
Flash Player 10 Astroを予習。Dynamic Sound Generate編 #1

private function soundWAV(e:SampleDataEvent):void {
    for ( var c:int=0; c<2048; c++ ) {
      var left:Number = wavData.readFloat();
      var right:Number = wavData.readFloat();
      e.data.writeFloat(left);
      e.data.writeFloat(right);
    }
}

たぶん、バイトコードに落とし込むところはすごい人がやっていることなんで間違いないと思うのですが、サンプルデータにいれるところがうまくいってません。明らかに実際の音楽より早く終わってしまうんで。なので、サンプルデータの生成処理についてもう少しわかってないとうまくできなそうです。

サンプルのwavデータとASファイルを固めたものをおいておきますので、どうぞご自由に。
wavはDS-10でつくったものなんですが、当然ながら曲の版権はもってないんでサンプル用ということで。

以下ソースです。

package {
	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";

        //プロパティ
        public var formatID:int;
        public var channel:int;
        public var rate:uint;
        public var bps:uint;
        public var blockSize:int;
        public var sampling:int;
        public var fileSize:uint;

        //WAV 定数
        private const RIFF:uint = 0x46464952;
        private const WAVE:uint = 0x45564157;
        private const FMT :uint = 0x20746D66;
        private const DATA:uint = 0x61746164;
        private const FormatID_PCM:uint = 0x0001;

        private var wavData:ByteArray;

		public function WAV_Sample()
		{
			stage.scaleMode = StageScaleMode.NO_SCALE;
			setStartBtn();
		}

		private function soundWAV(e:SampleDataEvent):void {
            for ( var c:int=0; c<2048; c++ )
            {
				var left:Number = wavData.readFloat();
				var right:Number = wavData.readFloat();
				e.data.writeFloat(left);
				e.data.writeFloat(right);
            }
		}

		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.");
            }
		}

        private function completeHandler(event:Event):Boolean
        {
            var loader:URLLoader = URLLoader(event.target);
            var ba:ByteArray = event.target.data;

            var tag:uint;
            var len:uint;
            var tmp:uint;
            var pos:uint;

            wavData = new ByteArray();

            ba.endian = Endian.LITTLE_ENDIAN;
            ba.position = 0;

            if(ba.readUnsignedInt() != RIFF){
                trace("WAV Format Error(RIFF)");
                return false;
            }
            fileSize = ba.readUnsignedInt();
            if(ba.readUnsignedInt() != WAVE){
                trace("WAV Format Error(WAVE)");
                return false;
            }
            while(ba.bytesAvailable > 0){
                tag = ba.readUnsignedInt();
                len = ba.readUnsignedInt();
                pos = ba.position;
                switch(tag){
                case FMT:
                    //fmtチャンクの読込
                    formatID = ba.readUnsignedShort();
                    channel = ba.readUnsignedShort();
                    rate = ba.readUnsignedInt();
                    bps = ba.readUnsignedInt();
                    blockSize = ba.readUnsignedShort();
                    sampling = ba.readUnsignedShort();
                    break;
                case DATA:
                    //dataチャンクの読込
                    wavData.writeBytes(ba, ba.position, len);
                    break;
                }
                ba.position = pos + len;
            }
            wavData.position = 0;
            var mySound:Sound = new Sound();
			mySound.addEventListener(Event.SAMPLE_DATA, soundWAV);
			mySound.play();

			var log:String =   "formatID:" + formatID + "n"
							 + "channel:" + channel + "n"
							 + "rate:" + rate + "n"
							 + "bps:" + bps + "n"
							 + "blockSize:" + blockSize + "n"
							 + "sampling:" + sampling + "n"
            trace(log);
            return true;
        }

	    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();
	    }
	}
}

import flash.display.Sprite;
import flash.text.TextField;
import flash.geom.Rectangle;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;

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);
	}
}



自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る