Spark project の 音系ライブラリ SiON で遊んでみました。
svn : http://www.libspark.org/svn/as3/SiOPM
SiON があれば Flash でオリジナル シンセサイザを作るのも夢じゃない、あまりの高機能に驚きの連続です。
せっかくなので、最近使い始めた GUMBO(Flash Builder 4 beta)でサンプルファイルをビルドしてみることにしました。
選んだサンプルは samples/SiOPMKeyboard
。
SiON が生成できる音を画面上のキーボードを使って再生可能です。
添付 main.mxml
をGUMBOようにいくつかコンバートしなければいけないようです。
Flex Builder 3 の <mx: ...
が <s: ...
や <fx: ...
に変わっていたり <mx: ...
のままだったりするのがまだ理解できません。
エラーを確認しながら修正していきます。
外部ファイルの参照には <local: ...
が使われていました。
// original <my:KeyDisplay id="keyboard" addedToStage="stage.focus = this;"/> // GUMBO <local:KeyDisplay id="keyboard" addedToStage="stage.focus = this;"/> |
ただこのサンプルファイルこのままではビルドできません。
import されている org.si.utils.setTextField;
クラスが現在の配布データには含まれていないからです。
April 24, 2009 rev.2526
で追加されたのでここからファイルを復元してビルドすることにしました。
GUMBO 向けにコンバートしたコードはこちらです。
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo" minWidth="1024" minHeight="768" creationComplete="_onCreate();" xmlns:local="*"> <fx:Script> <![CDATA[ import flash.events.*; import flash.ui.Keyboard; import mx.events.*; import mx.controls.Alert; import mx.collections.ArrayCollection; import org.si.sion.*; import org.si.sion.events.*; import org.si.sion.sequencer.SiMMLTrack; import org.si.sion.effector.SiEffectStereoDelay; import org.si.sion.effector.SiEffectStereoChorus; import org.si.sion.utils.SiONPresetVoice; // variables //------------------------------ static private var _driver:SiONDriver; static private var _voices:SiONPresetVoice; static private var _voice:SiONVoice; static private var _keyFlag:uint; static private var _keyTable:Vector.<int>; static private var _baseNote:int; static private var _delaySend:Number; static private var _chorusSend:Number; // initializer //------------------------------ private function _onCreate() : void { // initialize instances _driver = new SiONDriver(); _voices = new SiONPresetVoice(); _delaySend = 0.25; _chorusSend = 0; _voice = _voices["sine"]; // effector setting var dly:SiEffectStereoDelay = new SiEffectStereoDelay(); dly.initialize(); dly.setParameters(200,0.2,false); var cho:SiEffectStereoChorus = new SiEffectStereoChorus(); cho.initialize(); cho.setParameters(20,0.2,4,20); // connect effectors _driver.effector.initialize(); _driver.effector.connect(1, dly); _driver.effector.connect(2, cho); // event listeners _driver.addEventListener(ErrorEvent.ERROR, _onError); _driver.addEventListener(SiONTrackEvent.NOTE_ON_FRAME, _onNoteOnFrame); _driver.addEventListener(SiONTrackEvent.NOTE_OFF_FRAME, _onNoteOffFrame); // keyboard listener addEventListener(KeyboardEvent.KEY_DOWN, _onKeyDown); addEventListener(KeyboardEvent.KEY_UP, _onKeyUp); // keyboard keys _keyFlag = 0; _keyTable = new Vector.<int>(32, true); var kt:Array = ['z','s','x','d','c','v','g','b','h','n','j','m',',','l','.',';','/']; for (var i:int=0; i<kt.length; i++) { _keyTable[i] = kt[i].charCodeAt(); } for (; i<32; i++) { _keyTable[i] = -1; } _baseNote = 60; // set selector items var categ:Array, list:Array = []; for each (categ in _voices.categolies) list.push({label:categ["name"]}); fileSelect.dataProvider = new ArrayCollection(list); _onFileSelectorChange(); // start stream without data _driver.play(null, false); } // operations //------------------------------ private function _allNoteOff() : void { for (var i:int=0; i<32; i++) _driver.noteOff(i+_baseNote); } private function _refleshChannelSelector(categolyList:Array) : void { var i:int, imax:int=categolyList.length; var list:Array = []; for (i=0; i<imax; i++) list.push({label:categolyList[i].name}); chSelect.dataProvider = new ArrayCollection(list); chSelect.selectedIndex = 0; } // driver events //------------------------------ private function _onNoteOnFrame(e:SiONTrackEvent) : void { keyboard.noteOn(e.note-_baseNote); } private function _onNoteOffFrame(e:SiONTrackEvent) : void { keyboard.noteOff(e.note-_baseNote); } private function _onError(e:ErrorEvent) : void { Alert.show(e.text, "MML Error", Alert.OK); } // keyboard events //------------------------------ private function _onKeyDown(e:KeyboardEvent) : void { for (var i:int=0; i<17; i++) { if (_keyTable[i] == e.charCode) { var flag:uint = 1<<i; if ((_keyFlag & flag) == 0) { _keyFlag |= flag; var trk:SiMMLTrack = _driver.noteOn(i+_baseNote, _voice, 0, 0, 0, 0, 0, 1, 1); trk.channel.setStreamSend(1, _delaySend); trk.channel.setStreamSend(2, _chorusSend); } return; } } if (_driver.isPlaying) { switch (String.fromCharCode(e.charCode)) { case 'w': _allNoteOff(); _baseNote += 12; if (_baseNote>84) _baseNote = 84; break; case 'q': _allNoteOff(); _baseNote -= 12; if (_baseNote<24) _baseNote = 24; break; } } } private function _onKeyUp(e:KeyboardEvent) : void { for (var i:int=0; i<32; i++) { if (_keyTable[i] == e.charCode) { var flag:uint = 1<<i; if ((_keyFlag & flag) != 0) { _keyFlag &= ~flag; _driver.noteOff(i+_baseNote); } return; } } } // UI events //------------------------------ private function _onFileSelectorChange() : void { _refleshChannelSelector(_voices.categolies[fileSelect.selectedIndex]); _onChannelSelectorChange(); } private function _onChannelSelectorChange() : void { if (chSelect.selectedItem == null) return; _voice = _voices.categolies[fileSelect.selectedIndex][chSelect.selectedIndex]; } private function _onChannelSelectorClose() : void { stage.focus = keyboard; } private function changeEffectSend() : void { _delaySend = delaySend.value * 0.01; _chorusSend = chorusSend.value * 0.01; for each (var trk:SiMMLTrack in _driver.sequencer.tracks) { trk.channel.setStreamSend(1, _delaySend); trk.channel.setStreamSend(2, _chorusSend); } } ]]> </fx:Script> <mx:TitleWindow title="SiOPM FM Keyboard" width="264" height="226" paddingTop="2" paddingBottom="2" paddingLeft="2" paddingRight="2"> <mx:ComboBox id="fileSelect" width="240" height="24" dropdownWidth="240" rowCount="6" fontSize="10" fontWeight="normal" change="_onFileSelectorChange();" close ="_onChannelSelectorClose();"/> <mx:ComboBox id="chSelect" width="240" height="24" dropdownWidth="240" rowCount="6" fontSize="10" fontWeight="normal" change="_onChannelSelectorChange();" close ="_onChannelSelectorClose();"/> <mx:HBox height="16" horizontalGap="0"> <mx:HSlider id="delaySend" width="120" height="16" maximum="100" tickInterval="10" snapInterval="5" value="25" toolTip="Delay send" change="changeEffectSend();"/> <mx:HSlider id="chorusSend" width="120" height="16" maximum="100" tickInterval="10" snapInterval="5" value="0" toolTip="Chorus send" change="changeEffectSend();"/> </mx:HBox> <local:KeyDisplay id="keyboard" addedToStage="stage.focus = this;"/> </mx:TitleWindow> </s:Application> |
できあがったサンプルファイルはホントに楽しい。
SiONの力を思い知らされます。
2009-08-07 に ver.0.5.6へアップグレードされています。
サウンドライブラリ SiON ver0.5.6 更新 GM準拠128プリセット音色追加,asdocとswc追加
音色が追加されたそうなのでまた別の機会に試してみたいと思います。
update 2009-08-20
wonderfl にご本人からアップされてました。
http://wonderfl.net/code/48d64aceb6303cf25750d4e63e52748ddf0f2df6
org.si.utils.setTextField;
がいらない形のコードになってます。
SiONの音色を全て確認できます。