In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Quasi Speecher ADV (like Famicon sound)

Get Adobe Flash player
by heriet 07 Oct 2009
/**
 * Copyright heriet ( http://wonderfl.net/user/heriet )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/5RNI
 */

package  
{
  import flash.display.BlendMode;
  import flash.display.Shape;
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.events.KeyboardEvent;
  import flash.events.MouseEvent;
  import flash.events.SampleDataEvent;
  import flash.media.Sound;
  import flash.text.TextField;
  import flash.text.TextFormat;
  
  [SWF(width = "465", height = "465", frameRate = "60", backgroundColor = "0x202030")]
  public class QuasiSpeecher extends Sprite
  {
    private static const TYPE_NONE:int = 0;
    private static const TYPE_MALE:int = 1;
    private static const TYPE_FEMALE:int = 2;
    private static const TYPE_MALE2:int = 3;
    
    private static const FREQENCYS:Vector.<int> = Vector.<int>([0, 220, 587, 330]);
    
    private static const SAMPLE_SIZE:int = 32;
    
    private var _triangleWaveTable:Vector.<int>;
    
    private const NOVEL_TEXT:Vector.<NovelLine> = Vector.<NovelLine>([
      l("真っ暗だ・・・目の前が見えない・・・怖い・・・", TYPE_MALE),
      l("ここはいったい・・・どこだ?", TYPE_MALE),
      l("体も・・・動かない。手足の感覚すらない", TYPE_MALE),
      l("かろうじて目蓋を開け閉めする感覚はある。しかし、開けても閉じても真っ暗闇だ", TYPE_MALE),
      l("落ち着いて目を閉じる。目蓋の皮膚を透ける光すら感じられない", TYPE_MALE),
      l("ゆっくりと目を開ける。やはり一片の光も感じられない", TYPE_MALE),
      l("つまり、光が一切ない、閉じられた場所に自分は居るという事だ", TYPE_MALE),
      l("「あーあー」", TYPE_MALE2),
      l("声は出せる。耳も正常なようだ", TYPE_MALE),
      l("しかし、首から下の感覚がない", TYPE_MALE),
      l("『あら、起きたのね』", TYPE_FEMALE),
      l("若い女性の声が、左の耳に届く", TYPE_MALE),
      l("『目覚めはどう?わたしがわかる?』", TYPE_FEMALE),
      l("コツコツと歩く音。女の声が近づいてくる", TYPE_MALE),
      l("「わからない。きみは誰だ?ここはどこだ?」", TYPE_MALE2),
      l("『わかるようね。ここはわたしの部屋』", TYPE_FEMALE),
      l("わからない。この女の声は誰だ?聞き覚えがない", TYPE_MALE),
      l("わたしの部屋と言われても、誰かわからないのでは場所がわからないも同然だ", TYPE_MALE),
      l("『文章書くの飽きた。ただのADVっぽいテストだしめんどくさいからこれで終わり』", TYPE_FEMALE),
      l("E$5N$5D", TYPE_NONE),
    ])
    
    private var _currentLine:int;
    private var _quasiSpeecherText:QuasiSpeecherText = new QuasiSpeecherText();
    private var _nextTriangle:Shape;
    private var _frameCount:int;
    
    private var _sound:Sound;
    private var _frequency:int;
    
    private var _textField:TextField = new TextField();
    
    private function l(text:String, type:int = 0):NovelLine
    {
      return new NovelLine(text, type);
    }
    
    public function QuasiSpeecher() 
    {
      _sound = new Sound();
      _sound.addEventListener(SampleDataEvent.SAMPLE_DATA, sampleDataHandler);
      
      var i:int;
      _triangleWaveTable = new Vector.<int>();
      for (i = 0; i < 16; i++ )
        _triangleWaveTable.push(0xF - i - 8);
      for (i = 0; i < 16; i++ )
        _triangleWaveTable.push(i - 8);
      
      var textFormat:TextFormat = new TextFormat(null, 24, 0xFFFFFF, true);
      textFormat.leading = 16;
      
      _quasiSpeecherText.x = 16;
      _quasiSpeecherText.y = 300;
      _quasiSpeecherText.width = 465 - _quasiSpeecherText.x * 2;
      _quasiSpeecherText.height = 150;
      _quasiSpeecherText.defaultTextFormat = textFormat;
      _quasiSpeecherText.sound = _sound;
      addChild(_quasiSpeecherText);
      
      _nextTriangle = new Shape();
      _nextTriangle.graphics.beginFill(0xFFFFFF);
      _nextTriangle.graphics.moveTo(0, 0);
      _nextTriangle.graphics.lineTo(0, 24);
      _nextTriangle.graphics.lineTo(16, 12);
      _nextTriangle.graphics.lineTo(0, 0);
      _nextTriangle.graphics.endFill();
      
      _nextTriangle.x = 435;
      _nextTriangle.y = 435;
      
      _quasiSpeecherText.addEventListener(Event.COMPLETE, showNextTriangle);
      
      _currentLine = -1;
      
      _textField.defaultTextFormat = textFormat;
      _textField.text = "click to start";
      addChild(_textField);
      _textField.x = 160;
      _textField.y = 200;
      _textField.width = 200;
      
      stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
      stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
    }
    // see http://www.geocities.jp/daichi1969/synthprog/index.html
    private function sampleDataHandler(event:SampleDataEvent):void
    {
      if (event.position > 0)
        return;
      
      var phase:uint = 16;
      var delta:uint = (int)((_frequency << 16) * SAMPLE_SIZE / 44100);
      var n:int;
      for (var i:int = 0; i < 2048; i++) {
        var amp:Number = (_triangleWaveTable[phase >> 16]) / 7 / 2;
        event.data.writeFloat(amp);
        event.data.writeFloat(amp);
        phase += delta;
        phase = phase & (SAMPLE_SIZE << 16) - 1;
      }
    }
    private function keyDownHandler(event:KeyboardEvent):void
    {
      if (contains(_textField))
        removeChild(_textField)
      
      updateText();
    }
    private function mouseDownHandler(event:MouseEvent):void
    {
      if (contains(_textField))
        removeChild(_textField)
        
      updateText();
    }
    private function updateText():void
    {
      if (_quasiSpeecherText.isPlaying) {
        _quasiSpeecherText.showAll();
      }
      else {
        clearNextTriangle();
        
        _currentLine++;
        if (_currentLine >= NOVEL_TEXT.length)
          _currentLine = 0;
        
        var novelLine:NovelLine = NOVEL_TEXT[_currentLine];
        setLine(novelLine);
      }
    }
    private function setLine(novelLine:NovelLine):void
    {
      _quasiSpeecherText.text = novelLine.text;
      _quasiSpeecherText.isSound = novelLine.type != TYPE_NONE;
      _frequency = FREQENCYS[novelLine.type];
      _quasiSpeecherText.start();
    }
    private function showNextTriangle(event:Event = null):void
    {
      if (contains(_nextTriangle))
        return;
        
      addChild(_nextTriangle);
      _frameCount = 0;
      addEventListener(Event.ENTER_FRAME, updateNextTriangle);
    }
    private function updateNextTriangle(event:Event):void
    {
      _frameCount++;
      var f:int = _frameCount % 45;
      if (f == 15) {
        _nextTriangle.blendMode = BlendMode.NORMAL;
      }
      else if (f == 30) {
        _nextTriangle.blendMode = BlendMode.DARKEN;
      }
    }
    private function clearNextTriangle():void
    {
      if (!contains(_nextTriangle))
        return;
      
      removeChild(_nextTriangle);
      removeEventListener(Event.ENTER_FRAME, updateNextTriangle);
    }
  }
}
import flash.display.Sprite;
import flash.events.Event;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.media.Sound;

class NovelLine {
  public var text:String;
  public var type:int;
  
  public function NovelLine(text:String, type:int)
  {
    this.text = text;
    this.type = type;
  }
}

class QuasiSpeecherText extends Sprite {
  
  private var _textField:TextField;
  private var _text:String;
  private var _textSpeed:Number = 2.0;
  private var _soundFreq:Number = 1.5;
  private var _isPlaying:Boolean;
  private var _frameCount:Number;
  private var _soundPosition:Number;
  private var _currentIndex:int;
  private var _sound:Sound;
  private var _isSound:Boolean = true;
  
  public function get textSpeed():Number { return _textSpeed }
  public function set textSpeed(value:Number):void { _textSpeed = value }
  public function get soundFreq():Number { return _soundFreq }
  public function set soundFreq(value:Number):void { _soundFreq = value }
  public function get sound():Sound { return _sound }
  public function set sound(value:Sound):void { _sound = value }
  public function get isSound():Boolean { return _isSound }
  public function set isSound(value:Boolean):void { _isSound = value }
  
  public function get isPlaying():Boolean { return _isPlaying }
  
  override public function set width(value:Number):void
  {
    _textField.width = value;
  }
  override public function set height(value:Number):void
  {
    _textField.height = value;
  }
  
  public function set defaultTextFormat(value:TextFormat):void
  {
    _textField.defaultTextFormat = value;
  }
  public function get text():String
  {
    return _text;
  }
  public function set text(value:String):void
  {
    _text = value;
  }
  
  public function QuasiSpeecherText()
  {
    _textField = new TextField();
    _textField.selectable = false;
    _textField.tabEnabled = false;
    _textField.multiline = true;
    _textField.wordWrap = true;
    addChild(_textField);
  }
  public function start():void
  {
    if (_isPlaying)
      return;
    
    stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
    _isPlaying = true;
    
    _textField.text = "";
    _frameCount = 0.0;
    _currentIndex = 0;
    _soundPosition = 0.0;
  }
  public function enterFrameHandler(event:Event):void
  {
    _frameCount += 1.0;
    
    var f:Number = _frameCount - _textSpeed;
    while (f > 0) {
      if(_currentIndex >= _text.length)
        stop();
      
      _frameCount = 0.0;
      var char:String = _text.charAt(_currentIndex);
      
      if(char == "$" && _currentIndex + 1 < _text.length){
        var nextChar:String = _text.charAt(_currentIndex + 1);
        var nextCharCode:int = nextChar.charCodeAt(0);
        
        if (48 < nextCharCode && nextCharCode <= 57) { // (0, 9]
          var rate:int = nextCharCode - 48;
          _frameCount -= rate * _textSpeed;
        }
        else {
          _textField.appendText(char);
        }
        _currentIndex++;
      }
      else {
        _textField.appendText(char);
      }
      _currentIndex++;
      f -= _textSpeed;
    }
    
    var len:int = _textField.text.length;
    if (len - _soundPosition >= _soundFreq) {
      _soundPosition += _soundFreq;
      if(isSound)
        _sound.play();
    }
  }
  public function showAll():void
  {
    var t:String = "";
    var n:int = _text.length;
    for (var i:int = 0; i < n; i++ ) {
      var char:String = _text.charAt(i);
      if (char == '$')
        i++;
      else
        t += char;
    }
    
    _textField.text = t;
    stop();
  }
  public function stop():void
  {
    if (!_isPlaying)
      return;
    
    stage.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
    _isPlaying = false;
    
    dispatchEvent(new Event(Event.COMPLETE));
  }
}