SPC-700 emulation is completely running probably.
This sound does not look like Real SNES because maybe DSP code was simplified version.
Real version DSP code is too heavy for execution on the Flash Player.
Notice: snes_spc-0.9.0's licence is LGPL. be careful it's usage.
SPC Player
Require Flash Player 10 or later for Playing.
Source Code (AS3)
package
{
import cmodule.libspc.CLibInit;
import flash.display.SimpleButton;
import flash.display.Sprite;
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.system.Security;
import flash.system.SecurityDomain;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.utils.ByteArray;
import flash.utils.Endian;
/**
* SPC Player Sample
* @author Hikipuro
*/
public class Main extends Sprite
{
/**
* SPC File's URL
*/
private const spcurl:String = "smw-10a.spc";
/**
* URL Loader for SPC file
*/
private var urlLoader:URLLoader;
/**
* SPC library
*/
private var libspc:Object;
/**
* ByteArray for wave sound
*/
private var out:ByteArray;
/**
* sound playing flag
*/
private var playing:Boolean;
/**
* SPC file's binary
*/
private var spcdata:ByteArray;
/**
* sound object
*/
private var sound:Sound;
/**
* "Play" button
*/
private var playButton:SimpleButton;
/**
* "Stop" button
*/
private var stopButton:SimpleButton;
/**
* "Loading" text
*/
private var loadingTextFiled:TextField;
/**
* constructor
*/
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
/**
* initialize method
* @param e
*/
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
// init member
playing = false;
// load snes_spc-0.9.0
var loader:CLibInit = new CLibInit;
libspc = loader.init();
// load SPC in URL
urlLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.addEventListener(Event.COMPLETE, onLoadComplete);
urlLoader.load(new URLRequest(spcurl));
// create "Play" button
playButton = new SimpleButton();
playButton.upState = makeButton(0xDDDDDD, 100, 20, 10, "Play");
playButton.overState = makeButton(0xEEEEEE, 100, 20, 10, "Play");
playButton.downState = makeButton(0xCCCCCC, 100, 20, 10, "Play");
playButton.hitTestState = playButton.upState;
playButton.addEventListener(MouseEvent.MOUSE_DOWN, onPlayStopButtonDown);
playButton.x = (320 - playButton.width) / 2;
playButton.y = (240 - playButton.height) / 2;
addChild(playButton);
playButton.visible = false;
// create "Stop" button
stopButton = new SimpleButton();
stopButton.upState = makeButton(0xDDDDDD, 100, 20, 10, "Stop");
stopButton.overState = makeButton(0xEEEEEE, 100, 20, 10, "Stop");
stopButton.downState = makeButton(0xCCCCCC, 100, 20, 10, "Stop");
stopButton.hitTestState = stopButton.upState;
stopButton.addEventListener(MouseEvent.MOUSE_DOWN, onPlayStopButtonDown);
stopButton.x = (320 - stopButton.width) / 2;
stopButton.y = (240 - stopButton.height) / 2;
addChild(stopButton);
stopButton.visible = false;
// create "Loading" text
loadingTextFiled = new TextField();
loadingTextFiled.autoSize = TextFieldAutoSize.CENTER;
loadingTextFiled.text = "Loading ...";
loadingTextFiled.x = (320 - loadingTextFiled.width) / 2;
loadingTextFiled.y = (240 - loadingTextFiled.height) / 2;
addChild(loadingTextFiled);
}
/**
* load complete event for URL Loader
* @param e
*/
private function onLoadComplete(e:Event):void
{
// SPC file's content into ByteArray
spcdata = urlLoader.data as ByteArray;
spcdata.endian = Endian.LITTLE_ENDIAN;
spcdata.position = 0;
// prepare output buffer
out = new ByteArray();
out.endian = Endian.LITTLE_ENDIAN;
// show play button
loadingTextFiled.visible = false;
playButton.visible = true;
}
/**
* audio data require event
* @param event
*/
private function onSampleData(e:SampleDataEvent):void
{
var data:ByteArray = e.data;
// execute SPC emulator for getting wave audio
out.position = 0;
libspc.play(out, 8192);
out.position = 0;
// executing while for wave length
for (var i:uint = 0; i < 8192; i++) {
var s1:Number = 0;
var s2:Number = 0;
// play() method returned for 16 bit wave sound data
// but it is not playable for Flash Player.
// converting float type wave sound data.
s1 = out.readShort();
s1 /= 32768;
s2 = out.readShort();
s2 /= 32768;
// control sound volume
//s *= 0.5;
// write wave sound buffer
data.writeFloat(s1); // left channel
data.writeFloat(s2); // right channel
}
}
/**
* "Play" / "Stop" button pressed event
* @param e
*/
private function onPlayStopButtonDown(e:MouseEvent):void
{
if ( playing == false ) {
playing = true;
playButton.visible = false;
stopButton.visible = true;
// Flash's Sound object uses sampling rate for 44100 Hz.
// to a little slowly play sound (SNES's sampling rate 32000 Hz)
// 256 is normal tempo.
var tempo:int = 256 / (44100 / 32000);
libspc.load(spcdata, spcdata.length, tempo);
// create new sound object and play sound
sound = new Sound();
sound.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);
sound.play(0, 1);
} else {
playing = false;
playButton.visible = true;
stopButton.visible = false;
sound.removeEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);
sound = null;
}
}
/**
* create button method
* @param color surface color
* @param width
* @param height
* @param round corner roundness
* @param text button's caption
* @return button spirte object
*/
private function makeButton(color:uint, width:int, height:int, round:int, text:String):Sprite
{
var t:TextField = new TextField();
var s:Sprite = new Sprite();
s.graphics.lineStyle(2);
s.graphics.beginFill(color);
s.graphics.drawRoundRect(0, 0, width, height, round);
s.graphics.endFill();
t.text = text;
t.selectable = false;
t.width = width;
t.autoSize = TextFieldAutoSize.CENTER;
s.addChild(t);
return s;
}
}
}