Quasi Speecher ADV (like Famicon sound)
/**
* 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));
}
}