PageRenderTime 185ms CodeModel.GetById 28ms RepoModel.GetById 6ms app.codeStats 0ms

/lib/as3sfxr/src/SfxrApp.as

https://github.com/dcgw/ld18
ActionScript | 938 lines | 541 code | 131 blank | 266 comment | 36 complexity | d89bec0804fdd1b7fa91da0eb34facf9 MD5 | raw file
  1. package
  2. {
  3. import flash.display.CapsStyle;
  4. import flash.display.DisplayObject;
  5. import flash.display.GraphicsPath;
  6. import flash.display.GraphicsSolidFill;
  7. import flash.display.GraphicsStroke;
  8. import flash.display.IGraphicsData;
  9. import flash.display.JointStyle;
  10. import flash.display.LineScaleMode;
  11. import flash.display.Sprite;
  12. import flash.events.ContextMenuEvent;
  13. import flash.events.Event;
  14. import flash.events.KeyboardEvent;
  15. import flash.events.MouseEvent;
  16. import flash.events.TextEvent;
  17. import flash.geom.Rectangle;
  18. import flash.net.FileFilter;
  19. import flash.net.FileReference;
  20. import flash.net.navigateToURL;
  21. import flash.net.URLRequest;
  22. import flash.text.Font;
  23. import flash.text.TextField;
  24. import flash.text.TextFieldType;
  25. import flash.text.TextFormat;
  26. import flash.text.TextFormatAlign;
  27. import flash.ui.ContextMenu;
  28. import flash.ui.Keyboard;
  29. import flash.ui.Mouse;
  30. import flash.ui.MouseCursor;
  31. import flash.utils.ByteArray;
  32. import flash.utils.Dictionary;
  33. import flash.utils.Endian;
  34. import ui.TinyButton;
  35. import ui.TinySlider;
  36. /**
  37. * SfxrApp
  38. *
  39. * Copyright 2009 Thomas Vian
  40. *
  41. * Licensed under the Apache License, Version 2.0 (the "License");
  42. * you may not use this file except in compliance with the License.
  43. * You may obtain a copy of the License at
  44. *
  45. * http://www.apache.org/licenses/LICENSE-2.0
  46. *
  47. * Unless required by applicable law or agreed to in writing, software
  48. * distributed under the License is distributed on an "AS IS" BASIS,
  49. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  50. * See the License for the specific language governing permissions and
  51. * limitations under the License.
  52. *
  53. * @author Thomas Vian
  54. */
  55. [SWF(width='640', height='480', backgroundColor='#C0B090', frameRate='25')]
  56. public class SfxrApp extends Sprite
  57. {
  58. //--------------------------------------------------------------------------
  59. //
  60. // Properties
  61. //
  62. //--------------------------------------------------------------------------
  63. [Embed(source = "assets/amiga4ever.ttf", fontName = "Amiga4Ever", mimeType = "application/x-font", embedAsCFF = "false")]
  64. private var Amiga4Ever:Class; // Pixel font, original was in a tga file
  65. [Embed(source = "assets/logo.png")]
  66. private var Logo:Class; // SFB09 logo, for the bottom left corner
  67. private var _synth:SfxrSynth; // synthesizer instance
  68. private var _propLookup:Dictionary; // Look up for property names using a slider key
  69. private var _sliderLookup:Object; // Look up for sliders using a property name key
  70. private var _waveformLookup:Array; // Look up for waveform buttons
  71. private var _squareLookup:Array; // Look up for sliders controlling a square wave property
  72. private var _back:TinyButton; // Button to skip back a sound
  73. private var _forward:TinyButton; // Button to skip forward a sound
  74. private var _history:Vector.<SfxrSynth>; // List of generated settings
  75. private var _historyPos:int; // Current history position
  76. private var _copyPaste:TextField; // Input TextField for the settings
  77. private var _fileRef:FileReference; // File reference for loading in sfs file
  78. private var _logoRect:Rectangle; // Click rectangle for SFB website link
  79. private var _sfxrRect:Rectangle; // Click rectangle for LD website link
  80. private var _volumeRect:Rectangle; // Click rectangle for resetting volume
  81. //--------------------------------------------------------------------------
  82. //
  83. // Constructor
  84. //
  85. //--------------------------------------------------------------------------
  86. /**
  87. * Waits until on the stage before init
  88. */
  89. public function SfxrApp()
  90. {
  91. if (stage) init();
  92. else addEventListener(Event.ADDED_TO_STAGE, init);
  93. }
  94. //--------------------------------------------------------------------------
  95. //
  96. // Init Method
  97. //
  98. //--------------------------------------------------------------------------
  99. /**
  100. * Initialises the synthesizer and draws the interface
  101. * @param e Added to stage event
  102. */
  103. private function init(e:Event = null):void
  104. {
  105. removeEventListener(Event.ADDED_TO_STAGE, init);
  106. _synth = new SfxrSynth();
  107. SfxrGenerator.randomize(_synth);
  108. _propLookup = new Dictionary();
  109. _sliderLookup = {};
  110. _waveformLookup = [];
  111. _squareLookup = [];
  112. _history = new Vector.<SfxrSynth>();
  113. _history.push(_synth);
  114. drawGraphics();
  115. drawButtons();
  116. drawSliders();
  117. drawCopyPaste();
  118. updateSliders();
  119. updateButtons();
  120. updateCopyPaste();
  121. }
  122. //--------------------------------------------------------------------------
  123. //
  124. // Keyboard Methods
  125. //
  126. //--------------------------------------------------------------------------
  127. //--------------------------------------------------------------------------
  128. //
  129. // Button Methods
  130. //
  131. //--------------------------------------------------------------------------
  132. /**
  133. * Adds the buttons to the stage
  134. */
  135. private function drawButtons():void
  136. {
  137. // Generator
  138. addButton("PICKUP/COIN", clickPickupCoin, 4, 32);
  139. addButton("LASER/SHOOT", clickLaserShoot, 4, 62);
  140. addButton("EXPLOSION", clickExplosion, 4, 92);
  141. addButton("POWERUP", clickPowerup, 4, 122);
  142. addButton("HIT/HURT", clickHitHurt, 4, 152);
  143. addButton("JUMP", clickJump, 4, 182);
  144. addButton("BLIP/SELECT", clickBlipSelect, 4, 212);
  145. addButton("MUTATE", clickMutate, 4, 324);
  146. addButton("RANDOMIZE", clickRandomize, 4, 354, 2);
  147. // History
  148. _back = addButton("BACK", clickBack, 4, 384);
  149. _forward = addButton("FORWARD", clickForward, 4, 414);
  150. _back.enabled = false;
  151. _forward.enabled = false;
  152. // Waveform
  153. addButton("SQUAREWAVE", clickSquarewave, 130, 28, 1, true);
  154. addButton("SAWTOOTH", clickSawtooth, 250, 28, 1, true);
  155. addButton("SINEWAVE", clickSinewave, 370, 28, 1, true);
  156. addButton("NOISE", clickNoise, 490, 28, 1, true);
  157. // Play / save / export
  158. addButton("PLAY SOUND", clickPlaySound, 490, 228);
  159. addButton("LOAD SOUND", clickLoadSound, 490, 288);
  160. addButton("SAVE SOUND", clickSaveSound, 490, 318);
  161. addButton("EXPORT .WAV", clickExportWav, 490, 378, 3);
  162. addButton("44100 HZ", clickSampleRate, 490, 408);
  163. addButton("16-BIT", clickBitDepth, 490, 438);
  164. }
  165. /**
  166. * Adds a single button
  167. * @param label Text to display on the button
  168. * @param onClick Callback function called when the button is clicked
  169. * @param x X position of the button
  170. * @param y Y position of the button
  171. * @param border Thickness of the border in pixels
  172. * @param selectable If the button is selectable
  173. * @param selected If the button starts as selected
  174. */
  175. private function addButton(label:String, onClick:Function, x:Number, y:Number, border:Number = 1, selectable:Boolean = false):TinyButton
  176. {
  177. var button:TinyButton = new TinyButton(onClick, label, border, selectable);
  178. button.x = x;
  179. button.y = y;
  180. addChild(button);
  181. if(selectable) _waveformLookup.push(button);
  182. return button;
  183. }
  184. /**
  185. * Updates the buttons to reflect the synthesizer
  186. */
  187. private function updateButtons():void
  188. {
  189. selectedSwitch(_waveformLookup[_synth.waveType]);
  190. }
  191. //--------------------------------------------------------------------------
  192. //
  193. // Generator Methods
  194. //
  195. //--------------------------------------------------------------------------
  196. /**
  197. * Sets the synthesizer to generate a pickup/coin sound and previews it
  198. * @param button Button pressed
  199. */
  200. private function clickPickupCoin(button:TinyButton):void
  201. {
  202. addToHistory();
  203. SfxrGenerator.generatePickupCoin(_synth);
  204. updateSliders();
  205. updateButtons();
  206. updateCopyPaste();
  207. _synth.play();
  208. }
  209. /**
  210. * Sets the synthesizer to generate a laser/shoot sound and previews it
  211. * @param button Button pressed
  212. */
  213. private function clickLaserShoot(button:TinyButton):void
  214. {
  215. addToHistory();
  216. SfxrGenerator.generateLaserShoot(_synth);
  217. updateSliders();
  218. updateButtons();
  219. updateCopyPaste();
  220. _synth.play();
  221. }
  222. /**
  223. * Sets the synthesizer to generate an explosion sound and previews it
  224. * @param button Button pressed
  225. */
  226. private function clickExplosion(button:TinyButton):void
  227. {
  228. addToHistory();
  229. SfxrGenerator.generateExplosion(_synth);
  230. updateSliders();
  231. updateButtons();
  232. updateCopyPaste();
  233. _synth.play();
  234. }
  235. /**
  236. * Sets the synthesizer to generate a powerup sound and previews it
  237. * @param button Button pressed
  238. */
  239. private function clickPowerup(button:TinyButton):void
  240. {
  241. addToHistory();
  242. SfxrGenerator.generatePowerup(_synth);
  243. updateSliders();
  244. updateButtons();
  245. updateCopyPaste();
  246. _synth.play();
  247. }
  248. /**
  249. * Sets the synthesizer to generate a hit/hurt sound and previews it
  250. * @param button Button pressed
  251. */
  252. private function clickHitHurt(button:TinyButton):void
  253. {
  254. addToHistory();
  255. SfxrGenerator.generateHitHurt(_synth);
  256. updateSliders();
  257. updateButtons();
  258. updateCopyPaste();
  259. _synth.play();
  260. }
  261. /**
  262. * Sets the synthesizer to generate a jump sound and previews it
  263. * @param button Button pressed
  264. */
  265. private function clickJump(button:TinyButton):void
  266. {
  267. addToHistory();
  268. SfxrGenerator.generateJump(_synth);
  269. updateSliders();
  270. updateButtons();
  271. updateCopyPaste();
  272. _synth.play();
  273. }
  274. /**
  275. * Sets the synthesizer to generate a blip/select sound and previews it
  276. * @param button Button pressed
  277. */
  278. private function clickBlipSelect(button:TinyButton):void
  279. {
  280. addToHistory();
  281. SfxrGenerator.generateBlipSelect(_synth);
  282. updateSliders();
  283. updateButtons();
  284. updateCopyPaste();
  285. _synth.play();
  286. }
  287. /**
  288. * Sets the synthesizer to mutate the sound and preview it
  289. * @param button Button pressed
  290. */
  291. private function clickMutate(button:TinyButton):void
  292. {
  293. addToHistory();
  294. SfxrGenerator.mutate(_synth);
  295. updateSliders();
  296. updateButtons();
  297. updateCopyPaste();
  298. _synth.play();
  299. }
  300. /**
  301. * Sets the synthesizer to randomize the sound and preview it
  302. * @param button Button pressed
  303. */
  304. private function clickRandomize(button:TinyButton):void
  305. {
  306. addToHistory();
  307. SfxrGenerator.randomize(_synth);
  308. updateSliders();
  309. updateButtons();
  310. updateCopyPaste();
  311. _synth.play();
  312. }
  313. //--------------------------------------------------------------------------
  314. //
  315. // History Methods
  316. //
  317. //--------------------------------------------------------------------------
  318. /**
  319. * When the back button is clicked, moves back through the history
  320. * @param button TinyButton clicked
  321. */
  322. private function clickBack(button:TinyButton):void
  323. {
  324. _historyPos--;
  325. if(_historyPos == 0) _back.enabled = false;
  326. if(_historyPos < _history.length - 1) _forward.enabled = true;
  327. _synth.stop();
  328. _synth = _history[_historyPos];
  329. updateSliders();
  330. updateButtons();
  331. updateCopyPaste();
  332. _synth.play();
  333. }
  334. /**
  335. * When the forward button is clicked, moves forward through the history
  336. * @param button TinyButton clicked
  337. */
  338. private function clickForward(button:TinyButton):void
  339. {
  340. _historyPos++;
  341. if(_historyPos > 0) _back.enabled = true;
  342. if(_historyPos == _history.length - 1) _forward.enabled = false;
  343. _synth.stop();
  344. _synth = _history[_historyPos];
  345. updateSliders();
  346. updateButtons();
  347. updateCopyPaste();
  348. _synth.play();
  349. }
  350. /**
  351. * Adds a new sound effect to the history.
  352. * Called just before a new sound effect is generated.
  353. */
  354. private function addToHistory():void
  355. {
  356. _historyPos++;
  357. _synth = _synth.clone();
  358. _history = _history.slice(0, _historyPos);
  359. _history.push(_synth);
  360. _back.enabled = true;
  361. _forward.enabled = false;
  362. }
  363. //--------------------------------------------------------------------------
  364. //
  365. // Waveform Methods
  366. //
  367. //--------------------------------------------------------------------------
  368. /**
  369. * Selects the squarewave waveform type
  370. * @param button Button pressed
  371. */
  372. private function clickSquarewave(button:TinyButton):void
  373. {
  374. _synth.waveType = 0;
  375. _synth.deleteCache();
  376. selectedSwitch(button);
  377. updateCopyPaste();
  378. }
  379. /**
  380. * Selects the sawtooth waveform type
  381. * @param button Button pressed
  382. */
  383. private function clickSawtooth(button:TinyButton):void
  384. {
  385. _synth.waveType = 1;
  386. _synth.deleteCache();
  387. selectedSwitch(button);
  388. updateCopyPaste();
  389. }
  390. /**
  391. * Selects the sinewave waveform type
  392. * @param button Button pressed
  393. */
  394. private function clickSinewave(button:TinyButton):void
  395. {
  396. _synth.waveType = 2;
  397. _synth.deleteCache();
  398. selectedSwitch(button);
  399. updateCopyPaste();
  400. }
  401. /**
  402. * Selects the noise waveform type
  403. * @param button Button pressed
  404. */
  405. private function clickNoise(button:TinyButton):void
  406. {
  407. _synth.waveType = 3;
  408. _synth.deleteCache();
  409. selectedSwitch(button);
  410. updateCopyPaste();
  411. }
  412. /**
  413. * Unselects all the waveform buttons and selects the one passed in
  414. * @param select Selects this button
  415. */
  416. private function selectedSwitch(select:TinyButton):void
  417. {
  418. for(var i:uint = 0, l:uint = _waveformLookup.length; i < l; i++)
  419. {
  420. if(_waveformLookup[i] != select) _waveformLookup[i].selected = false;
  421. }
  422. if(!select.selected) select.selected = true;
  423. for(i = 0; i < 2; i++)
  424. {
  425. _squareLookup[i].dimLabel = _synth.waveType != 0;
  426. }
  427. }
  428. //--------------------------------------------------------------------------
  429. //
  430. // Play/Save/Export Methods
  431. //
  432. //--------------------------------------------------------------------------
  433. /**
  434. * Previews the sound
  435. * @param button Button pressed
  436. */
  437. private function clickPlaySound(button:TinyButton):void
  438. {
  439. _synth.play();
  440. }
  441. /**
  442. * Opens a browse window to load a sound setting file
  443. * @param button Button pressed
  444. */
  445. private function clickLoadSound(button:TinyButton):void
  446. {
  447. _fileRef = new FileReference();
  448. _fileRef.addEventListener(Event.SELECT, onSelectSettings);
  449. _fileRef.browse([new FileFilter("SFX Sample Files (*.sfs)", "*.sfs")]);
  450. }
  451. /**
  452. * When the user selects a file, begins loading it
  453. * @param e Select event
  454. */
  455. private function onSelectSettings(e:Event):void
  456. {
  457. _fileRef.cancel();
  458. _fileRef.removeEventListener(Event.SELECT, onSelectSettings);
  459. _fileRef.addEventListener(Event.COMPLETE, onLoadSettings);
  460. _fileRef.load();
  461. }
  462. /**
  463. * Once loaded, passes the file to the synthesizer to parse
  464. * @param e Complete event
  465. */
  466. private function onLoadSettings(e:Event):void
  467. {
  468. _fileRef.removeEventListener(Event.COMPLETE, onLoadSettings);
  469. addToHistory();
  470. setSettingsFile(_fileRef.data);
  471. updateSliders();
  472. updateButtons();
  473. updateCopyPaste();
  474. _fileRef = null;
  475. }
  476. /**
  477. * Saves out a sound settings file
  478. * @param button Button pressed
  479. */
  480. private function clickSaveSound(button:TinyButton):void
  481. {
  482. var file:ByteArray = getSettingsFile();
  483. new FileReference().save(file, "sfx.sfs");
  484. }
  485. /**
  486. * Exports the sound as a .wav file
  487. * @param button Button pressed
  488. */
  489. private function clickExportWav(button:TinyButton):void
  490. {
  491. var file:ByteArray = _synth.getWavFile();
  492. new FileReference().save(file, "sfx.wav");
  493. }
  494. /**
  495. * Switches the sample rate between 44100Hz and 22050Hz
  496. * @param button Button pressed
  497. */
  498. private function clickSampleRate(button:TinyButton):void
  499. {
  500. if(_synth.sampleRate == 44100) _synth.sampleRate = 22050;
  501. else _synth.sampleRate = 44100;
  502. button.label = _synth.sampleRate + " HZ";
  503. }
  504. /**
  505. * Switches the bit depth between 16-bit and 8-bit
  506. * @param button Button pressed
  507. */
  508. private function clickBitDepth(button:TinyButton):void
  509. {
  510. if(_synth.bitDepth == 16) _synth.bitDepth = 8;
  511. else _synth.bitDepth = 16;
  512. button.label = _synth.bitDepth + "-BIT";
  513. }
  514. //--------------------------------------------------------------------------
  515. //
  516. // Settings File Methods
  517. //
  518. //--------------------------------------------------------------------------
  519. /**
  520. * Writes the current parameters to a ByteArray and returns it
  521. * Compatible with the original Sfxr files
  522. * @return ByteArray of settings data
  523. */
  524. public function getSettingsFile():ByteArray
  525. {
  526. var file:ByteArray = new ByteArray();
  527. file.endian = Endian.LITTLE_ENDIAN;
  528. file.writeInt(102);
  529. file.writeInt(_synth.waveType);
  530. file.writeFloat(_synth.masterVolume);
  531. file.writeFloat(_synth.startFrequency);
  532. file.writeFloat(_synth.minFrequency);
  533. file.writeFloat(_synth.slide);
  534. file.writeFloat(_synth.deltaSlide);
  535. file.writeFloat(_synth.squareDuty);
  536. file.writeFloat(_synth.dutySweep);
  537. file.writeFloat(_synth.vibratoDepth);
  538. file.writeFloat(_synth.vibratoSpeed);
  539. file.writeFloat(0);
  540. file.writeFloat(_synth.attackTime);
  541. file.writeFloat(_synth.sustainTime);
  542. file.writeFloat(_synth.decayTime);
  543. file.writeFloat(_synth.sustainPunch);
  544. file.writeBoolean(false);
  545. file.writeFloat(_synth.lpFilterResonance);
  546. file.writeFloat(_synth.lpFilterCutoff);
  547. file.writeFloat(_synth.lpFilterCutoffSweep);
  548. file.writeFloat(_synth.hpFilterCutoff);
  549. file.writeFloat(_synth.hpFilterCutoffSweep);
  550. file.writeFloat(_synth.phaserOffset);
  551. file.writeFloat(_synth.phaserSweep);
  552. file.writeFloat(_synth.repeatSpeed);
  553. file.writeFloat(_synth.changeSpeed);
  554. file.writeFloat(_synth.changeAmount);
  555. return file;
  556. }
  557. /**
  558. * Reads parameters from a ByteArray file
  559. * Compatible with the original Sfxr files
  560. * @param file ByteArray of settings data
  561. */
  562. public function setSettingsFile(file:ByteArray):void
  563. {
  564. _synth.deleteCache();
  565. file.position = 0;
  566. file.endian = Endian.LITTLE_ENDIAN;
  567. var version:int = file.readInt();
  568. if(version != 100 && version != 101 && version != 102) return;
  569. _synth.waveType = file.readInt();
  570. _synth.masterVolume = (version == 102) ? file.readFloat() : 0.5;
  571. _synth.startFrequency = file.readFloat();
  572. _synth.minFrequency = file.readFloat();
  573. _synth.slide = file.readFloat();
  574. _synth.deltaSlide = (version >= 101) ? file.readFloat() : 0.0;
  575. _synth.squareDuty = file.readFloat();
  576. _synth.dutySweep = file.readFloat();
  577. _synth.vibratoDepth = file.readFloat();
  578. _synth.vibratoSpeed = file.readFloat();
  579. var unusedVibratoDelay:Number = file.readFloat();
  580. _synth.attackTime = file.readFloat();
  581. _synth.sustainTime = file.readFloat();
  582. _synth.decayTime = file.readFloat();
  583. _synth.sustainPunch = file.readFloat();
  584. var unusedFilterOn:Boolean = file.readBoolean();
  585. _synth.lpFilterResonance = file.readFloat();
  586. _synth.lpFilterCutoff = file.readFloat();
  587. _synth.lpFilterCutoffSweep = file.readFloat();
  588. _synth.hpFilterCutoff = file.readFloat();
  589. _synth.hpFilterCutoffSweep = file.readFloat();
  590. _synth.phaserOffset = file.readFloat();
  591. _synth.phaserSweep = file.readFloat();
  592. _synth.repeatSpeed = file.readFloat();
  593. _synth.changeSpeed = (version >= 101) ? file.readFloat() : 0.0;
  594. _synth.changeAmount = (version >= 101) ? file.readFloat() : 0.0;
  595. _synth.validate();
  596. }
  597. //--------------------------------------------------------------------------
  598. //
  599. // Slider Methods
  600. //
  601. //--------------------------------------------------------------------------
  602. /**
  603. * Adds the sliders to the stage
  604. */
  605. private function drawSliders():void
  606. {
  607. addSlider("ATTACK TIME", "attackTime", 350, 70);
  608. addSlider("SUSTAIN TIME", "sustainTime", 350, 88);
  609. addSlider("SUSTAIN PUNCH", "sustainPunch", 350, 106);
  610. addSlider("DECAY TIME", "decayTime", 350, 124);
  611. addSlider("START FREQUENCY", "startFrequency", 350, 142);
  612. addSlider("MIN FREQUENCY", "minFrequency", 350, 160);
  613. addSlider("SLIDE", "slide", 350, 178, true);
  614. addSlider("DELTA SLIDE", "deltaSlide", 350, 196, true);
  615. addSlider("VIBRATO DEPTH", "vibratoDepth", 350, 214);
  616. addSlider("VIBRATO SPEED", "vibratoSpeed", 350, 232);
  617. addSlider("CHANGE AMOUNT", "changeAmount", 350, 250, true);
  618. addSlider("CHANGE SPEED", "changeSpeed", 350, 268);
  619. addSlider("SQUARE DUTY", "squareDuty", 350, 286, false, true);
  620. addSlider("DUTY SWEEP", "dutySweep", 350, 304, true, true);
  621. addSlider("REPEAT SPEED", "repeatSpeed", 350, 322);
  622. addSlider("PHASER OFFSET", "phaserOffset", 350, 340, true);
  623. addSlider("PHASER SWEEP", "phaserSweep", 350, 358, true);
  624. addSlider("LP FILTER CUTOFF", "lpFilterCutoff", 350, 376);
  625. addSlider("LP FILTER CUTOFF SWEEP", "lpFilterCutoffSweep", 350, 394, true);
  626. addSlider("LP FILTER RESONANCE", "lpFilterResonance", 350, 412);
  627. addSlider("HP FILTER CUTOFF", "hpFilterCutoff", 350, 430);
  628. addSlider("HP FILTER CUTOFF SWEEP", "hpFilterCutoffSweep", 350, 448, true);
  629. addSlider("", "masterVolume", 492, 208);
  630. }
  631. /**
  632. * Adds a single slider
  633. * @param label Text label to display next to the slider
  634. * @param property Property name to link with the slider
  635. * @param x X position of slider
  636. * @param y Y Position of slider
  637. * @param plusMinus If the slider ranges from -1 to 1 (true) or 0 to 1 (false)
  638. * @param square If the slider is linked to the square duty properties
  639. */
  640. private function addSlider(label:String, property:String, x:Number, y:Number, plusMinus:Boolean = false, square:Boolean = false):TinySlider
  641. {
  642. var slider:TinySlider = new TinySlider(onSliderChange, label, plusMinus);
  643. slider.x = x;
  644. slider.y = y;
  645. addChild(slider);
  646. _propLookup[slider] = property;
  647. _sliderLookup[property] = slider;
  648. if (square) _squareLookup.push(slider);
  649. return slider;
  650. }
  651. /**
  652. * Updates the property on the synthesizer to the slider's value
  653. * @param slider
  654. */
  655. private function onSliderChange(slider:TinySlider):void
  656. {
  657. _synth[_propLookup[slider]] = slider.value;
  658. _synth.deleteCache();
  659. updateCopyPaste();
  660. }
  661. /**
  662. * Updates the sliders to reflect the synthesizer
  663. */
  664. private function updateSliders():void
  665. {
  666. for(var prop:String in _sliderLookup)
  667. {
  668. _sliderLookup[prop].value = _synth[prop];
  669. }
  670. }
  671. //--------------------------------------------------------------------------
  672. //
  673. // Copy Paste Methods
  674. //
  675. //--------------------------------------------------------------------------
  676. /**
  677. * Adds a TextField over the whole app.
  678. * Allows for right-click copy/paste, as well as ctrl-c/ctrl-v
  679. */
  680. private function drawCopyPaste():void
  681. {
  682. _copyPaste = new TextField();
  683. _copyPaste.addEventListener(TextEvent.TEXT_INPUT, updateFromCopyPaste);
  684. _copyPaste.addEventListener(KeyboardEvent.KEY_DOWN, updateCopyPaste);
  685. _copyPaste.addEventListener(KeyboardEvent.KEY_UP, updateCopyPaste);
  686. _copyPaste.defaultTextFormat = new TextFormat("Amiga4Ever", 8, 0);
  687. _copyPaste.wordWrap = false;
  688. _copyPaste.multiline = false;
  689. _copyPaste.type = TextFieldType.INPUT;
  690. _copyPaste.embedFonts = true;
  691. _copyPaste.width = 640;
  692. _copyPaste.height = 580;
  693. _copyPaste.x = 0;
  694. _copyPaste.y = -20;
  695. addChild(_copyPaste);
  696. _copyPaste.contextMenu = new ContextMenu();
  697. _copyPaste.contextMenu.addEventListener(ContextMenuEvent.MENU_SELECT, updateCopyPaste);
  698. Mouse.cursor = MouseCursor.ARROW;
  699. }
  700. /**
  701. * Updates the contents of the textfield to a representation of the settings
  702. * @param e Optional event
  703. */
  704. private function updateCopyPaste(e:Event = null):void
  705. {
  706. _copyPaste.text = _synth.getSettingsString();
  707. _copyPaste.setSelection(0, _copyPaste.text.length);
  708. stage.focus = _copyPaste;
  709. }
  710. /**
  711. * When the textfield is pasted into, and the new info parses, updates the settings
  712. * @param e Text input event
  713. */
  714. private function updateFromCopyPaste(e:TextEvent):void
  715. {
  716. if (e.text.split(",").length == 24) addToHistory();
  717. if (!_synth.setSettingsString(e.text))
  718. {
  719. _copyPaste.setSelection(0, _copyPaste.text.length);
  720. stage.focus = _copyPaste;
  721. _copyPaste.text = _synth.getSettingsString();
  722. }
  723. _copyPaste.setSelection(0, _copyPaste.text.length);
  724. stage.focus = _copyPaste;
  725. updateSliders();
  726. updateButtons();
  727. }
  728. //--------------------------------------------------------------------------
  729. //
  730. // Graphics Methods
  731. //
  732. //--------------------------------------------------------------------------
  733. /**
  734. * Draws the extra labels, frames and lines to the stage
  735. */
  736. private function drawGraphics():void
  737. {
  738. var lines:Vector.<IGraphicsData> = new Vector.<IGraphicsData>();
  739. lines.push(new GraphicsStroke(2, false, LineScaleMode.NORMAL, CapsStyle.NONE, JointStyle.MITER, 3, new GraphicsSolidFill(0)));
  740. lines.push(new GraphicsPath(Vector.<int>([1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,2,2]),
  741. Vector.<Number>([ 114,0, 114,480,
  742. 160,66, 460,66,
  743. 160,138, 460,138,
  744. 160,246, 460,246,
  745. 160,282, 460,282,
  746. 160,318, 460,318,
  747. 160,336, 460,336,
  748. 160,372, 460,372,
  749. 160, 462, 460, 462,
  750. 590,212, 618,212, 618,388, 590,388])));
  751. lines.push(new GraphicsStroke(1, false, LineScaleMode.NORMAL, CapsStyle.NONE, JointStyle.MITER, 3, new GraphicsSolidFill(0)));
  752. lines.push(new GraphicsPath(Vector.<int>([1,2,1,2,1,2,1,2]),
  753. Vector.<Number>([ 160, 65, 160, 463,
  754. 460, 65, 460, 463])));
  755. graphics.drawGraphicsData(lines);
  756. graphics.lineStyle(2, 0xFF0000, 1, true, LineScaleMode.NORMAL, CapsStyle.SQUARE, JointStyle.MITER);
  757. graphics.drawRect(549.5, 207.5, 43, 10);
  758. addLabel("CLICK ON LABELS", 484, 68, 0x877569, 500);
  759. addLabel("TO RESET SLIDERS", 480, 82, 0x877569, 500);
  760. addLabel("COPY/PASTE SETTINGS", 470, 108, 0x877569, 500);
  761. addLabel("TO SHARE SOUNDS", 484, 122, 0x877569, 500);
  762. addLabel("BASED ON SFXR BY", 480, 148, 0x877569, 500);
  763. addLabel("TOMAS PETTERSSON", 480, 162, 0x877569, 500);
  764. addLabel("VOLUME", 516, 192, 0);
  765. addLabel("GENERATOR", 6, 8, 0x504030);
  766. addLabel("MANUAL SETTINGS", 122, 8, 0x504030);
  767. var logo:DisplayObject = new Logo();
  768. logo.x = 4;
  769. logo.y = 439;
  770. addChild(logo);
  771. _logoRect = logo.getBounds(stage);
  772. _sfxrRect = new Rectangle(480, 115, 100, 30);
  773. _volumeRect = new Rectangle(516, 192, 200, 15);
  774. stage.addEventListener(MouseEvent.MOUSE_DOWN, onClick);
  775. }
  776. /**
  777. * Handles clicking either
  778. * @param e Click event
  779. */
  780. private function onClick(e:MouseEvent):void
  781. {
  782. if (_logoRect.contains(stage.mouseX, stage.mouseY)) navigateToURL(new URLRequest("http://www.superflashbros.net"));
  783. if (_sfxrRect.contains(stage.mouseX, stage.mouseY)) navigateToURL(new URLRequest("http://www.ludumdare.com/compo/2007/12/13/sfxr-sound-effects-for-all/"));
  784. if (_volumeRect.contains(stage.mouseX, stage.mouseY)) _sliderLookup["masterVolume"].value = 0.5;
  785. }
  786. /**
  787. * Adds a label
  788. * @param label Text to display
  789. * @param x X position of the label
  790. * @param y Y position of the label
  791. * @param colour Colour of the text
  792. */
  793. private function addLabel(label:String, x:Number, y:Number, colour:uint, width:Number = 200):void
  794. {
  795. var txt:TextField = new TextField();
  796. txt.defaultTextFormat = new TextFormat("Amiga4Ever", 8, colour);
  797. txt.selectable = false;
  798. txt.embedFonts = true;
  799. txt.text = label;
  800. txt.width = width;
  801. txt.height = 15;
  802. txt.x = x;
  803. txt.y = y;
  804. addChild(txt);
  805. }
  806. }
  807. }