1 <?xml version="1.0" encoding="utf-8"?>
2 <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="250" minHeight="300" width="366" height="337" backgroundColor="#D9DFEF">
5 // UI and event includes
6 import mx.events.SliderEvent;
7 import mx.controls.sliderClasses.Slider;
8 import spark.components.CheckBox;
9 import spark.components.Button;
10 import flashx.textLayout.formats.Float;
11 import mx.controls.Label;
12 import spark.components.HGroup;
13 import spark.components.HSlider;
15 // random flash includes I needed along the way
16 import flash.display.*;
17 import flash.events.*;
22 import cmodule.faustalchemy.CLibInit;
24 private var sound:Sound = new Sound();
26 private var inputSound:Sound;
27 private var inputSoundOn:Boolean = false;
28 private var inputSoundBuffer:ByteArray = new ByteArray();
29 private var inputSoundPosition:Number = 0;
31 private var samples:ByteArray = new ByteArray();
32 private var tick_:Number = 0;
33 private var f_:int = 440;
36 private var faust_loader:CLibInit;
37 private var faust:Object; // api methods are exposed as properties of this obejct
38 private var faustOK:Boolean = false; // true if library loaded.
40 public function initFaust():void {
41 faust_loader = new CLibInit();
42 faust = faust_loader.init();
43 // Initialize UI controls
44 // This changed at the last minute and may not be up-to-date in the writeup.
45 // Instead of calling back into actionscript, faust_init returns an
46 // array of Objects that allows us to set up the UI as .dsp files want.
47 var uistuff:Array = faust.api_init();
48 for (var i:int = 0; i < uistuff.length; ++i) {
49 var item:Object = uistuff[i];
50 var type:Number = item['type'];
51 var id:Number = item['id'];
52 var label:String = item['label'];
53 var min:Number = item['min'];
54 var max:Number = item['max'];
55 var init:Number = item['init'];
56 var step:Number = item['step'];
58 ui_addButton(label, id);
61 ui_addCheckButton(label, id);
64 ui_addHorizontalSlider(label, id, init, min, max, step);
71 // This function gets called by Flash when it needs more audio data.
72 public function soundCallback(event:SampleDataEvent):void {
73 // sample length can be anywhere from 2048 to 8192.
76 // We need to pass mp3 input to Faust if
77 // If we're not processing input, save cycles.
79 if (inputSoundPosition + 8192 > (inputSound.length*44100/1000)) {
81 inputSoundPosition = 0;
84 inputSoundBuffer.position = 0;
85 inputSound.extract(inputSoundBuffer, 8192, inputSoundPosition);
86 inputSoundBuffer.position = 0;
87 faust.api_tick(8192, 1, inputSoundBuffer, event.data);
88 inputSoundPosition += 8192;
90 // uncomment this section to debug in case calling C++ isn't working:
91 // just copy the mp3 data directly to the output buffer.
93 inputSound.extract(event.data, 8192, inputSoundPosition);
94 inputSoundPosition += (8192);
97 faust.api_tick(8192, 0, inputSoundBuffer, event.data);
101 // "Start" button callback.
102 protected function button1_clickHandler(event:MouseEvent):void
105 dbgtext.text = "Playback started.";
106 sound.addEventListener(SampleDataEvent.SAMPLE_DATA, soundCallback);
110 public function onControlChange(id:int, val:Number):void {
111 if (!faustOK) return;
112 faust.api_onControlChange(id, val);
116 public function ui_addButton(label:String, id:int):void {
117 var b:Button = new Button();
119 b.addEventListener("click", function(evt:Event):void {
120 onControlChange(id, 1.0);
125 public function ui_addToggleButton(label:String, id:int):void {
126 // toggle/check buttons seem to be identical.
127 return ui_addCheckButton(label, id);
130 public function ui_addCheckButton(label:String, id:int):void {
131 var cb:CheckBox = new CheckBox();
133 cb.addEventListener("change",
134 function(evt:SliderEvent):void {
135 var checked_val:int = cb.selected ? 1.0 : 0.0;
136 onControlChange(id, checked_val);
141 public function ui_addVerticalSlider(label:String, id:int, init:Number, min:Number, max:Number, step:Number):void {
142 // Just call HSlider since we have a vertical cascade of controls.
143 return ui_addHorizontalSlider(label, id, init, min, max, step);
146 public function ui_addHorizontalSlider(label:String, id:int, init:Number, min:Number, max:Number, step:Number):void {
147 var compGroup:HGroup = new HGroup();
149 var compLabel:Label = new Label();
150 compLabel.text = label;
152 var compSlider:spark.components.HSlider = new spark.components.HSlider();
153 compSlider.minimum = min;
154 compSlider.maximum = max;
155 compSlider.liveDragging = true; // update faust params while dragging the slider
156 compSlider.value = init;
157 compSlider.valueInterval = step;
158 compSlider.width = 200;
160 compSlider.addEventListener("change",
161 function(evt:Event):void {
162 onControlChange(id, compSlider.value);
164 // wire everything up
165 compGroup.addElement(compLabel);
166 compGroup.addElement(compSlider);
167 addElement(compGroup);
170 public function ui_addNumEntry(label:String, id:int, init:Number, min:Number, max:Number, step:Number):void {
171 // TODO: A proper text box requires validation.
172 // Also, slider controls could probably benefit from numeric input too...
173 // Create a unified control for {VSlider, HSlider, NumEntry}
174 return ui_addHorizontalSlider(label, id, init, min, max, step);
179 // These are "nice to have" functions but aren't critical.
180 // It doesn't look like they're widely used.
181 // TODO: if using Flex, these should be easy enough to implement.
182 public function ui_openFrameBox(label:String):void { }
183 public function ui_openTabBox(label:String):void { }
184 public function ui_openHorizontalBox(label:String):void { }
185 public function ui_openVerticalBox(label:String):void { }
186 public function ui_closeBox():void { }
187 // We don't need a run() notification since we call into Faust code directly.
188 public function ui_run():void { }
191 // "Load input sound" button callback
192 protected function button2_clickHandler(evt:MouseEvent):void {
193 inputSoundOn = false;
195 inputSound = new Sound();
196 var urlReq:URLRequest = new URLRequest(mp3path.text);
197 inputSound.load(urlReq);
198 inputSound.addEventListener(Event.COMPLETE,
199 function(evt:Event):void {
200 dbgtext.text = "sound finished loading.";
202 inputSoundPosition = 0;
207 //"Stop input sound" button callback
208 protected function button3_clickHandler(event:MouseEvent):void
210 dbgtext.text = "sound stopped.";
211 inputSoundOn = false;
212 inputSoundPosition = 0;
218 <s:Button label="Start" click="button1_clickHandler(event)"/>
219 <s:TextArea width="322" height="19" text="Click Start to begin." id="dbgtext"/>
220 <s:TextInput text="http://ccrma.stanford.edu/~travissk/faustflash/helterskelter.mp3" id="mp3path" width="359"/>
221 <s:HGroup width="237" height="28">
222 <s:Button label="Load Sound" click="button2_clickHandler(event)"/>
223 <s:Button label="Stop Sound" click="button3_clickHandler(event)"/>