├── .gitattributes ├── .gitignore ├── AIR installation error.png ├── Bosca Ceoil.as3proj ├── BoscaCeoilV3.app.zip ├── Building V3 for Catalina.md ├── How To Run On Catalina.md ├── Quarantine.command ├── README.md ├── RUN.bat ├── Working Proof.png ├── application.xml ├── assets ├── bc_128.png ├── bc_16.png ├── bc_32.png └── bc_48.png ├── boscaceoil fileformat.txt ├── boscalogo.png ├── changelog.txt ├── how to build.MD ├── lib └── sion065.swc ├── src ├── MMLSong.as ├── Main.as ├── Midiexporter.as ├── TrackerModuleXM.as ├── arrangementclass.as ├── barclass.as ├── bigroom │ └── input │ │ └── KeyPoll.as ├── co │ └── sparemind │ │ └── trackermodule │ │ ├── XMInstrument.as │ │ ├── XMPattern.as │ │ ├── XMPatternCell.as │ │ ├── XMPatternLine.as │ │ ├── XMSample.as │ │ ├── XMSampleFake.as │ │ └── XMSong.as ├── control.as ├── de │ ├── MIT-LICENSE.txt │ └── polygonal │ │ └── ds │ │ ├── Array2.as │ │ ├── Array3.as │ │ ├── ArrayedQueue.as │ │ ├── ArrayedStack.as │ │ ├── BinarySearchTree.as │ │ ├── BinaryTreeNode.as │ │ ├── BitVector.as │ │ ├── Collection.as │ │ ├── DLinkedList.as │ │ ├── DListIterator.as │ │ ├── DListNode.as │ │ ├── Graph.as │ │ ├── GraphArc.as │ │ ├── GraphNode.as │ │ ├── HashMap.as │ │ ├── HashTable.as │ │ ├── Heap.as │ │ ├── Iterator.as │ │ ├── LinkedList.as │ │ ├── LinkedQueue.as │ │ ├── LinkedStack.as │ │ ├── NullIterator.as │ │ ├── Prioritizable.as │ │ ├── PriorityQueue.as │ │ ├── SLinkedList.as │ │ ├── SListIterator.as │ │ ├── SListNode.as │ │ ├── TreeIterator.as │ │ └── TreeNode.as ├── drumkitclass.as ├── gfx.as ├── graphics │ ├── font.swf │ ├── icons.png │ ├── logo_blue.png │ ├── logo_cyan.png │ ├── logo_gray.png │ ├── logo_green.png │ ├── logo_orange.png │ ├── logo_purple.png │ ├── logo_red.png │ ├── logo_shadow.png │ ├── tutorial_drag.png │ ├── tutorial_longnote.png │ ├── tutorial_patterndrag.png │ ├── tutorial_secret.png │ └── tutorial_timelinedrag.png ├── guibutton.as ├── guiclass.as ├── help.as ├── includes │ ├── input.as │ ├── logic.as │ └── render.as ├── instrumentclass.as ├── keypoll.as ├── listclass.as ├── midicontrol.as ├── musicphraseclass.as ├── ocean │ ├── midi │ │ ├── InvalidMidiError.as │ │ ├── MidiEnum.as │ │ ├── MidiFile.as │ │ ├── MidiInstrument.as │ │ ├── MidiTrack.as │ │ ├── controller │ │ │ ├── History.as │ │ │ ├── MultiTrackEditor.as │ │ │ └── TrackEditor.as │ │ ├── event │ │ │ └── MvcEvent.as │ │ └── model │ │ │ ├── ChannelItem.as │ │ │ ├── MessageItem.as │ │ │ ├── MessageList.as │ │ │ ├── MetaItem.as │ │ │ ├── NoteItem.as │ │ │ ├── RawItem.as │ │ │ └── SysxItem.as │ └── utils │ │ └── GreedyUINT.as ├── paletteclass.as └── voicelistclass.as ├── successfuly quarantined.png ├── terminal pwd promt.png └── test ├── build-desktop.sh ├── build-web.sh ├── test-web.html └── test-web.rb /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bat/ 9 | air/ 10 | bin/ 11 | tmp/ 12 | obj/ 13 | AIR_readme.txt 14 | *.tmp 15 | *.bak 16 | *.swp 17 | *.bat 18 | *~.nib 19 | local.properties 20 | .classpath 21 | .settings/ 22 | .loadpath 23 | 24 | # External tool builders 25 | .externalToolBuilders/ 26 | 27 | # Locally stored "Eclipse launch configurations" 28 | *.launch 29 | 30 | # CDT-specific 31 | .cproject 32 | 33 | # PDT-specific 34 | .buildpath 35 | 36 | 37 | ################# 38 | ## Visual Studio 39 | ################# 40 | 41 | ## Ignore Visual Studio temporary files, build results, and 42 | ## files generated by popular Visual Studio add-ons. 43 | 44 | # User-specific files 45 | *.suo 46 | *.user 47 | *.sln.docstates 48 | 49 | # Build results 50 | [Dd]ebug/ 51 | [Rr]elease/ 52 | *_i.c 53 | *_p.c 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.vspscc 68 | .builds 69 | *.dotCover 70 | 71 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 72 | #packages/ 73 | 74 | # Visual C++ cache files 75 | ipch/ 76 | *.aps 77 | *.ncb 78 | *.opensdf 79 | *.sdf 80 | 81 | # Visual Studio profiler 82 | *.psess 83 | *.vsp 84 | 85 | # ReSharper is a .NET coding add-in 86 | _ReSharper* 87 | 88 | # Installshield output folder 89 | [Ee]xpress 90 | 91 | # DocProject is a documentation generator add-in 92 | DocProject/buildhelp/ 93 | DocProject/Help/*.HxT 94 | DocProject/Help/*.HxC 95 | DocProject/Help/*.hhc 96 | DocProject/Help/*.hhk 97 | DocProject/Help/*.hhp 98 | DocProject/Help/Html2 99 | DocProject/Help/html 100 | 101 | # Click-Once directory 102 | publish 103 | 104 | # Others 105 | [Bb]in 106 | [Oo]bj 107 | sql 108 | TestResults 109 | *.Cache 110 | ClientBin 111 | stylecop.* 112 | ~$* 113 | *.dbmdl 114 | Generated_Code #added for RIA/Silverlight projects 115 | 116 | # Backup & report files from converting an old project file to a newer 117 | # Visual Studio version. Backup files are not needed, because we have git ;-) 118 | _UpgradeReport_Files/ 119 | Backup*/ 120 | UpgradeLog*.XML 121 | 122 | 123 | 124 | ############ 125 | ## Windows 126 | ############ 127 | 128 | # Windows image file caches 129 | Thumbs.db 130 | 131 | # Folder config file 132 | Desktop.ini 133 | 134 | 135 | ############# 136 | ## Python 137 | ############# 138 | 139 | *.py[co] 140 | 141 | # Packages 142 | *.egg 143 | *.egg-info 144 | dist 145 | build 146 | eggs 147 | parts 148 | bin 149 | var 150 | sdist 151 | develop-eggs 152 | .installed.cfg 153 | 154 | # Installer logs 155 | pip-log.txt 156 | 157 | # Unit test / coverage reports 158 | .coverage 159 | .tox 160 | 161 | #Translations 162 | *.mo 163 | 164 | #Mr Developer 165 | .mr.developer.cfg 166 | 167 | # Mac crap 168 | .DS_Store 169 | -------------------------------------------------------------------------------- /AIR installation error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/AIR installation error.png -------------------------------------------------------------------------------- /Bosca Ceoil.as3proj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /BoscaCeoilV3.app.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/BoscaCeoilV3.app.zip -------------------------------------------------------------------------------- /Building V3 for Catalina.md: -------------------------------------------------------------------------------- 1 | I downloaded and installed the [AIRSDK](https://www.adobe.com/devnet/air/air-sdk-download.html) 2 | and installed the Adobe AIR 29(cause few people told me AIR32 wasn’t working and AIR 29 was working on Catalina ). 3 | 4 | But it wasn’t running on Catalina due to some issues, so I found this [post](https://community.adobe.com/t5/air/quot-installation-file-is-damaged-quot-when-installing-an-air-supported-app/td-p/9540338?page=1) which said the date of my Mac needs to be set to somewhere older than October 2016 and now the air apps was opening and I could make BoscaCeoil run, but I wanted to make it more easy and not change date and stuff so I decided to build a dmg. 5 | 6 | I used this command as provided by the AIRSDK (to know more about tinkering with AIRSDK [read here](https://help.adobe.com/en_US/air/build/index.html) 7 | 8 | (using 9 | `adt -package -target native myApp.dmg myApp.air` 10 | ) 11 | 12 | I had trouble configuring the PATH variables to get the SDK up and running but at last got it working. 13 | 14 | 15 | But the final dmg had some similar date issues so I had to change the date back to an older one and get the .app file 16 | Now after I got the .app file it still said it couldn’t open so I knew the problem was due the signing of the certificates so I resigned them and changed the date of creation and modification and had to quarantine the AIR app from apple to check its validity and used the following commands. 17 | 18 | ```shell 19 | cd /Library/Frameworks 20 | sudo xattr -r -d com.apple.quarantine ./Adobe\ AIR.framework 21 | ls -l@ ./Adobe\ AIR.framework/ 22 | ``` 23 | 24 | 25 | Now the app was running without any date related issues but required the installation of latest version of AIR and the following 3 commands to be executed after a semi-successful installation of AIR so I made a .command executable. 26 | 27 | This whole process requires a few clicks and your password to be entered 2 times, however I’ll try to make it a single click process in the near future. 28 | 29 | Catalina is known to cause many problems for many apps especially the AIR thing being broken this is the only way to resolve it for now. 30 | 31 | -------------------------------------------------------------------------------- /How To Run On Catalina.md: -------------------------------------------------------------------------------- 1 | Okay so here’s what I did to make it work in Catalina 2 | 3 | **Prerequisites** 4 | 5 | 6 | In order to run it you will need Adobe Air installed on your Mac you can get it from : [Click Here](https://get.adobe.com/air/) 7 | 8 | **Installation** 9 | 10 | So as soon as you download the dmg file install it and enter your password if it asks 11 | 12 | After the installation is done and it says successful and you exit it you’ll get a prompter’s like this : 13 | 14 | ![alt text](https://github.com/Pikachuxxxx/boscaceoil/blob/master/AIR%20installation%20error.png) 15 | 16 | Ignore it and click ok 17 | 18 | Now download and double click on the [Quarantine.command](https://github.com/Pikachuxxxx/boscaceoil/raw/master/Quarantine.command) file it will ask you to enter your password again and it may look something like this : 19 | 20 | ![alt text](https://github.com/Pikachuxxxx/boscaceoil/blob/master/terminal%20pwd%20promt.png) 21 | 22 | However you won’t be able to see the password, not a problem just type it and hit enter. 23 | 24 | After it’s done download it should look like this : 25 | 26 | ![alt text](https://github.com/Pikachuxxxx/boscaceoil/blob/master/successfuly%20quarantined.png) 27 | 28 | Great you’re just one step away from getting BoscaCeoil up and running 29 | 30 | Download the [BoscaCeoilV3.app](https://github.com/Pikachuxxxx/boscaceoil/raw/master/BoscaCeoilV3.app.zip) and double click it and it should open up like any other app. 31 | 32 | 33 | **Learn about Rebuilding V3** 34 | 35 | Please read [Building V3 for Catalina.md](https://github.com/Pikachuxxxx/boscaceoil/blob/master/Building%20V3%20for%20Catalina.md) to learn more about how the V3 app was rebuild to work on catalina. 36 | 37 | **Here is the working proof on Catalina** 38 | ![alt text](https://github.com/Pikachuxxxx/boscaceoil/blob/master/Working%20Proof.png) 39 | 40 | -------------------------------------------------------------------------------- /Quarantine.command: -------------------------------------------------------------------------------- 1 | cd /Library/Frameworks 2 | sudo xattr -r -d com.apple.quarantine ./Adobe\ AIR.framework 3 | ls -l@ ./Adobe\ AIR.framework/ 4 | echo Done fixing the application now open is just like you would open any app 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![logo](boscalogo.png "Bosca Ceoil") 2 | 3 | This is the repo for the original Adobe AIR version of Bosca Ceoil, which is now archived. 4 | 5 | Check out the modern remake, [Bosca Ceoil Blue](https://github.com/YuriSizov/boscaceoil-blue)! (for more info, see [this announcement](https://github.com/TerryCavanagh/boscaceoil/releases/tag/announcement)). 6 | 7 | Terry Cavanagh / http://www.distractionware.com 8 | -------------------------------------------------------------------------------- /RUN.bat: -------------------------------------------------------------------------------- 1 | 2 | @echo off 3 | 4 | if exist application.xml ( 5 | ECHO The file application.xml exists! 6 | ECHO. 7 | ) else ( 8 | ECHO The file application.xml doesn't exist. 9 | ECHO. 10 | ECHO Please make sure this file is available and try again. 11 | ECHO. 12 | PAUSE 13 | goto end 14 | ) 15 | 16 | :: 17 | :: Lets find the SWF's name inside application.xml for the file we want to create 18 | :: 19 | setlocal enableextensions enabledelayedexpansion 20 | set xmlFile=application.xml 21 | set fileName= 22 | for /f "tokens=3 delims=<>" %%v in ('findstr /n /i /c:"" "%xmlFile%"') do ( 23 | if "%%v" == "" ( 24 | goto defaultName 25 | ) 26 | if "%%v" == " " ( 27 | goto defaultName 28 | ) 29 | set fileName=%%v 30 | goto checkFile 31 | ) 32 | 33 | :defaultName 34 | ECHO No file name found in appplication.xml. Using BoscaCeoil.swf... 35 | ECHO. 36 | set fileName=BoscaCeoil.swf 37 | 38 | :checkFile 39 | ECHO Searching for %fileName%... 40 | ECHO. 41 | 42 | if exist %fileName% ( 43 | ECHO %fileName% exists! 44 | ECHO. 45 | goto fileExists 46 | ) else ( 47 | ECHO %fileName% doesn't exist. Compiling the application... 48 | ECHO. 49 | goto createSwf 50 | ) 51 | 52 | :createSwf 53 | SET airVar=%AIR_SDK_HOME% 54 | if "%airVar%"=="" ( 55 | ECHO AIR_SDK_HOME enviroment variable doesn't exist. 56 | ECHO. 57 | ECHO Please create it before running this bat. 58 | ECHO. 59 | PAUSE 60 | goto end 61 | ) else ( 62 | CALL %AIR_SDK_HOME%\bin\amxmlc.bat -swf-version 28 -default-frame-rate 30 -default-size 768 560 -library-path+=lib/sion065.swc -source-path+=src -default-background-color 0x000000 -warnings -strict src/Main.as -o %fileName% -define+=CONFIG::desktop,true -define+=CONFIG::web,false 63 | ECHO. 64 | ECHO Compilation finished. 65 | ECHO. 66 | ECHO If no error was thrown by the Java Runtime, %fileName% should now exist. 67 | ECHO. 68 | goto checkFile 69 | ) 70 | 71 | :fileExists 72 | ECHO. 73 | ECHO Running the application... 74 | %AIR_SDK_HOME%\bin\adl application.xml 75 | 76 | :end -------------------------------------------------------------------------------- /Working Proof.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/Working Proof.png -------------------------------------------------------------------------------- /application.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | BoscaCeoil 5 | 2.0 6 | BoscaCeoil 7 | 8 | Bosca Ceoil 9 | 10 | 11 | 12 | 13 | assets/bc_16.png 14 | assets/bc_32.png 15 | assets/bc_48.png 16 | assets/bc_128.png 17 | 18 | 19 | 20 | Bosca Ceoil 21 | BoscaCeoil.swf 22 | standard 23 | gpu 24 | false 25 | true 26 | true 27 | true 28 | true 29 | 30 | 31 | 32 | 33 | foo.ceol 34 | ceol 35 | CEOL music file 36 | text/plain 37 | 38 | 39 | 40 | 44 | -------------------------------------------------------------------------------- /assets/bc_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/assets/bc_128.png -------------------------------------------------------------------------------- /assets/bc_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/assets/bc_16.png -------------------------------------------------------------------------------- /assets/bc_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/assets/bc_32.png -------------------------------------------------------------------------------- /assets/bc_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/assets/bc_48.png -------------------------------------------------------------------------------- /boscalogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/boscalogo.png -------------------------------------------------------------------------------- /changelog.txt: -------------------------------------------------------------------------------- 1 | Version 2.1 (work in progress, binary versions not currently live) 2 | --------- 3 | 4 | - Fix pattern editor letting you write out of bounds notes 5 | [contributed by thomcc, https://github.com/TerryCavanagh/boscaceoil/pull/50] 6 | - Filepath memory - Bosca Ceoil now remembers last directory used 7 | [contributed by Ryusui, https://github.com/TerryCavanagh/boscaceoil/pull/53] 8 | 9 | Version 2.0 (Current live version on boscaceoil.net and itch.io, 24th July 2015) 10 | --------- 11 | 12 | * Major update! 13 | 14 | - Built in tutorial 15 | - Resizable window 16 | - Now exports to Midi, XM and MML 17 | - Support for Midi importing 18 | - Major performance improvements 19 | - Nicer GUI, new scrollbars/buttons in various places 20 | - Web version 21 | 22 | Version 1.1 (1st September 2013) 23 | --------- 24 | 25 | - You can now zoom the arrangement view. (Use the mouse wheel, or SHIFT+ARROWS) 26 | - Now supports double pattern sizes: up to 32 notes per pattern instead of 16. 27 | - Added global effects (delay, chorus, distortion, a bunch more!) 28 | - Added tab for advanced settings (replaces the weird HOLD LEFT secret) 29 | - The .ceol file type is properly associated now. You can double click a .ceol file to load it. 30 | 31 | LITTLE THINGS: 32 | 33 | - You can use WASD instead of the arrow keys now. 34 | - Long notes stop playing when you start and stop the track. 35 | - Support for different window sizes (x1, x2, x3 etc) 36 | - Placing a short note on a long note removes the long note. 37 | - Escape key quits. 38 | - Added program icon. 39 | 40 | BUGS: 41 | 42 | - BPM now set correctly when creating new song / loading a song with a different BPM. 43 | - Copying columns works properly now. 44 | - Fixed fullscreen setting bug. Should remember fullscreen/window settings. 45 | 46 | 47 | Version 1.01 (25th August 2013) 48 | --------- 49 | 50 | New Features: 51 | - You can copy and paste columns from the arrangement view - copy the entire currently looping region with CTRL+C, and paste it with CTRL+V. 52 | - A hidden advanced control panel lets you change sound buffer size (for higher quality wav exports). To acce ss this panel, HOLD LEFT on the file menu. 53 | - Swing control (thanks @increpare!). This is in the advanced control panel too. 54 | 55 | Bugfixes: 56 | - Fixed a bug that caused instruments to get mixed up sometimes 57 | - Instrument volumes are now saved correctly! 58 | - WAV exporter now works properly when used multiple times 59 | - Deleting patterns no longer screws up advanced filter settings 60 | 61 | Little things: 62 | - Patterns in arrangement view are a bit more legible when selected 63 | - Default vertical positions of patterns in pattern editor now based on lowest note rather than O4 64 | 65 | Version 1.0 (23rd August 2013) 66 | --------- 67 | 68 | Inital release. 69 | -------------------------------------------------------------------------------- /how to build.MD: -------------------------------------------------------------------------------- 1 | # Bosca Ceoil 2 | 3 | A simple music making program 4 | 5 | ## Modifying Bosca Ceoil itself 6 | 7 | Bosca Ceoil is an Adobe AIR application, written in the programming language 8 | called "ActionScript 3". Making changes to Bosca Ceoil involves changing 9 | ActionScript code. 10 | 11 | ### Pre-requisites 12 | 13 | Make sure you've got the [Adobe AIR SDK](http://www.adobe.com/devnet/air/air-sdk-download.html) 14 | installed. 15 | 16 | ### Building 17 | 18 | The easiest way to compile Bosca Ceoil is on windows - install FlashDevelop on your computer, then install the latest AIR SDK from Adobe. Then you can compile it by opening the Bosca Ceoil.as3proj file. Alternatively, you can use the command line. 19 | 20 | The AIR SDK includes a tool called `amxmlc`, which is the compiler we'll use to 21 | turn the ActionScript 3 code into an .swf "movie" (which is the term for 22 | `.swf` files even when they represent applications). 23 | 24 | The compiler needs quite a few options to produce a working Bosca Ceoil 25 | "movie": 26 | 27 | ``` 28 | amxmlc -swf-version 28 -default-frame-rate 30 -default-size 768 560 -library-path+=lib/sion065.swc -source-path+=src -default-background-color 0x000000 -warnings -strict src/Main.as -o BoscaCeoil.swf -define+=CONFIG::desktop,true -define+=CONFIG::web,false 29 | ``` 30 | 31 | All the NativeApplication, File, etc. stuff from the Air API needs to be wrapped in CONFIG::desktop { ... } blocks so they don't get compiled into the web version, or else it breaks. 32 | 33 | Desktop builds will now have to be compiled with the -define+=CONFIG::desktop,true -define+=CONFIG::web,false flags. 34 | Likewise, web builds will have to be compiled with -define+=CONFIG::desktop,false -define+=CONFIG::web,true. 35 | 36 | 37 | ### Running 38 | 39 | The AIR application description file, `application.xml`, tells AIR about the application you'd like to create from which movie files. 40 | 41 | The AIR SDK comes with a tool called `adl`, the Application Description Loader, which lets you run Bosca with the newly-compiled SWF: 42 | 43 | ``` 44 | adl application.xml 45 | ``` 46 | 47 | If you want to distribute the application, the AIR SDK contains all the tools you'll need for that. 48 | 49 | Available under the FreeBSD licence. Feel free to fork Bosca Ceoil and do your own thing with it! 50 | -------------------------------------------------------------------------------- /lib/sion065.swc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/lib/sion065.swc -------------------------------------------------------------------------------- /src/MMLSong.as: -------------------------------------------------------------------------------- 1 | package { 2 | import flash.utils.IDataOutput; 3 | import flash.geom.Rectangle; 4 | import mx.utils.StringUtil; 5 | 6 | public class MMLSong { 7 | protected var instrumentDefinitions:Vector.; 8 | protected var mmlToUseInstrument:Vector.; 9 | protected var noteDivisions:uint = 4; 10 | protected var bpm:uint = 120; 11 | protected var lengthOfPattern:uint = 16; 12 | protected var monophonicTracksForBoscaTrack:Vector.>; 13 | 14 | public function MMLSong() { 15 | } 16 | 17 | public function loadFromLiveBoscaCeoilModel():void { 18 | noteDivisions = control.barcount; 19 | bpm = control.bpm; 20 | lengthOfPattern = control.boxcount; 21 | 22 | var emptyBarMML:String = "\n// empty bar\n" + StringUtil.repeat(" r ", lengthOfPattern) + "\n"; 23 | var bar:uint; 24 | var patternNum:int; 25 | var numberOfPatterns:int = control.numboxes; 26 | 27 | instrumentDefinitions = new Vector.(); 28 | mmlToUseInstrument = new Vector.(); 29 | for (var i:uint = 0; i < control.numinstrument; i++) { 30 | var boscaInstrument:instrumentclass = control.instrument[i]; 31 | if (boscaInstrument.type == 0) { //regular instrument, not a drumkit 32 | instrumentDefinitions[i] = _boscaInstrumentToMML(boscaInstrument, i); 33 | mmlToUseInstrument[i] = _boscaInstrumentToMMLUse(boscaInstrument, i); 34 | } else { 35 | instrumentDefinitions[i] = "#OPN@" + i + " { //drum kit placeholder\n" + 36 | "4,6,\n" + 37 | "31,15, 0, 9, 1, 0, 0,15, 0, 0\n" + 38 | "31,20, 5,14, 5, 3, 0, 4, 0, 0\n" + 39 | "31,10, 9, 9, 1, 0, 0,10, 0, 0\n" + 40 | "31,22, 5,14, 5, 0, 1, 7, 0, 0};\n"; 41 | mmlToUseInstrument[i] = _boscaInstrumentToMMLUse(boscaInstrument, i); 42 | } 43 | } 44 | 45 | var monophonicTracksForBoscaPattern:Vector.> = new Vector.>(numberOfPatterns + 1); 46 | monophonicTracksForBoscaTrack = new Vector.>(); 47 | for (var track:uint = 0; track < 8; track++) { 48 | var maxMonoTracksForBoscaTrack:uint = 0; 49 | for (bar = 0; bar < control.arrange.lastbar; bar++) { 50 | patternNum = control.arrange.bar[bar].channel[track]; 51 | 52 | if (patternNum < 0) { continue; } 53 | var monoTracksForBar:Vector. = _mmlTracksForBoscaPattern(patternNum, control.musicbox); 54 | maxMonoTracksForBoscaTrack = Math.max(maxMonoTracksForBoscaTrack, monoTracksForBar.length); 55 | 56 | monophonicTracksForBoscaPattern[patternNum] = monoTracksForBar; 57 | } 58 | 59 | var outTracks:Vector. = new Vector.(); 60 | for(var monoTrackNo:uint = 0; monoTrackNo < maxMonoTracksForBoscaTrack; monoTrackNo++) { 61 | var outTrack:String = "\n"; 62 | for (bar = 0; bar < control.arrange.lastbar; bar++) { 63 | patternNum = control.arrange.bar[bar].channel[track]; 64 | if (patternNum < 0) { 65 | outTrack += emptyBarMML; 66 | continue; 67 | } 68 | 69 | monoTracksForBar = monophonicTracksForBoscaPattern[patternNum]; 70 | if (monoTrackNo in monoTracksForBar) { 71 | outTrack += ("\n// pattern " + patternNum + "\n"); 72 | outTrack += monoTracksForBar[monoTrackNo]; 73 | } else { 74 | outTrack += emptyBarMML; 75 | } 76 | } 77 | outTracks.push(outTrack) 78 | } 79 | monophonicTracksForBoscaTrack[track] = outTracks; 80 | } 81 | } 82 | 83 | public function writeToStream(stream:IDataOutput):void { 84 | var out:String = ""; 85 | out += "/** Music Macro Language (MML) exported from Bosca Ceoil */\n"; 86 | for each (var def:String in instrumentDefinitions) { 87 | out += def; 88 | out += "\n"; 89 | } 90 | 91 | for each (var monoTracks:Vector. in monophonicTracksForBoscaTrack) { 92 | if (monoTracks.length == 0) { continue; } // don't bother printing entirely empty tracks 93 | 94 | out += StringUtil.substitute("\n\n// === Bosca Ceoil track with up to {0} notes played at a time\n", monoTracks.length); 95 | 96 | for each (var monoTrack:String in monoTracks) { 97 | out += "\n// ---- track\n" 98 | 99 | // XXX: I thought note length would be something like (lengthOfPattern / noteDivisions) but I clearly misunderstand 100 | out += StringUtil.substitute("\nt{0} l{1} // timing (tempo and note length)\n", bpm, 16); 101 | 102 | out += monoTrack; 103 | out += ";\n" 104 | } 105 | } 106 | stream.writeMultiByte(out, "utf-8"); 107 | } 108 | 109 | protected function _mmlTracksForBoscaPattern(patternNum:int, patternDefinitions:Vector.):Vector. { 110 | var tracks:Vector. = new Vector.(); 111 | 112 | var pattern:musicphraseclass = patternDefinitions[patternNum]; 113 | var octave:int = -1; 114 | 115 | for (var place:uint = 0; place < lengthOfPattern; place++) { 116 | var notesInThisSlot:Vector. = new Vector.(); 117 | for (var n:int = 0; n < pattern.numnotes; n++) { 118 | var note:Rectangle = pattern.notes[n]; 119 | var noteStartingAt:int = note.width; 120 | var sionNoteNum:int = note.x; 121 | var noteLength:uint = note.y; 122 | var noteEndingAt:int = noteStartingAt + noteLength - 1; 123 | 124 | var isNotePlaying:Boolean = (noteStartingAt <= place) && (place <= noteEndingAt); 125 | 126 | if (!isNotePlaying) { continue; } 127 | 128 | var newOctave:int = _octaveFromSiONNoteNumber(sionNoteNum); 129 | var mmlOctave:String = _mmlTransitionFromOctaveToOctave(octave, newOctave); 130 | var mmlNoteName:String = _mmlNoteNameFromSiONNoteNumber(sionNoteNum); 131 | var mmlSlur:String = (noteEndingAt > place) ? "& " : " "; 132 | 133 | octave = newOctave; 134 | 135 | notesInThisSlot.push(mmlOctave + mmlNoteName + mmlSlur); 136 | } 137 | while (notesInThisSlot.length > tracks.length) { 138 | var emptyTrackSoFar:String = StringUtil.repeat(emptyNoteMML, place); 139 | tracks.push(mmlToUseInstrument[pattern.instr] + "\n" + emptyTrackSoFar); 140 | } 141 | var emptyNoteMML:String = " r "; 142 | 143 | for (var track:uint = 0; track < tracks.length; track++) { 144 | var noteMML:String; 145 | if (track in notesInThisSlot) { 146 | noteMML = notesInThisSlot[track]; 147 | } else { 148 | noteMML = emptyNoteMML; 149 | } 150 | tracks[track] += noteMML; 151 | } 152 | } 153 | 154 | return tracks; 155 | } 156 | 157 | /** 158 | * XXX: Duplicated from TrackerModuleXM (consider factoring out) 159 | */ 160 | protected function _mmlNoteNameFromSiONNoteNumber(noteNum:int):String { 161 | var noteNames:Vector. = Vector.(['c ', 'c+', 'd ', 'd+', 'e ', 'f ', 'f+', 'g ', 'g+', 'a ', 'a+', 'b ']); 162 | 163 | var noteName:String = noteNames[noteNum % 12]; 164 | return noteName; 165 | } 166 | 167 | /** 168 | * XXX: Duplicated from TrackerModuleXM (consider factoring out) 169 | */ 170 | protected function _octaveFromSiONNoteNumber(noteNum:int):int { 171 | var octave:int = int(noteNum / 12); 172 | return octave; 173 | } 174 | 175 | protected function _mmlTransitionFromOctaveToOctave(oldOctave:int, newOctave:int):String { 176 | if (oldOctave == newOctave) { 177 | return " "; 178 | } 179 | if ((oldOctave + 1) == newOctave) { 180 | return "< "; 181 | } 182 | if ((oldOctave - 1) == newOctave) { 183 | return "> "; 184 | } 185 | return "o" + newOctave; 186 | } 187 | 188 | protected function _boscaInstrumentToMML(instrument:instrumentclass, channel:int):String { 189 | return StringUtil.substitute("// instrument \"{0}\"\n{1}\n", instrument.name, instrument.voice.getMML(channel)); 190 | } 191 | 192 | protected function _boscaInstrumentToMMLUse(instrument:instrumentclass, channel:int):String { 193 | return StringUtil.substitute("%6@{0} v{1} @f{2},{3}", channel, int(instrument.volume / 16), instrument.cutoff, instrument.resonance); 194 | } 195 | 196 | } 197 | } -------------------------------------------------------------------------------- /src/Midiexporter.as: -------------------------------------------------------------------------------- 1 | package { 2 | import flash.display.*; 3 | import flash.geom.*; 4 | import flash.events.*; 5 | import flash.utils.*; 6 | import flash.net.*; 7 | import ocean.midi.*; 8 | import ocean.midi.event.*; 9 | import ocean.midi.model.*; 10 | 11 | //Taking Midias library calls away from midicontrol 12 | public class Midiexporter { 13 | //MidiFile 14 | //MidiTrack 15 | //MetaItem 16 | //NoteItem 17 | //ChannelItem 18 | public function Midiexporter() { 19 | midifile = new MidiFile; 20 | } 21 | 22 | public function addnewtrack():void { 23 | midifile.addTrack(new MidiTrack()); 24 | } 25 | 26 | public function nexttrack():void { 27 | addnewtrack(); 28 | currenttrack = midifile.track(midifile._trackArray.length - 1); 29 | } 30 | 31 | public function writetimesig():void { 32 | currenttrack._msgList.push(new MetaItem()); 33 | var t:int = currenttrack._msgList.length - 1; 34 | currenttrack._msgList[t].type = 0x58; // Time Signature 35 | var myba:ByteArray = new ByteArray(); 36 | myba.writeByte(0x04); 37 | myba.writeByte(0x02); 38 | myba.writeByte(0x18); 39 | myba.writeByte(0x08); 40 | currenttrack._msgList[t].text = myba; 41 | } 42 | 43 | public function writetempo(tempo:int):void { 44 | currenttrack._msgList.push(new MetaItem()); 45 | var t:int = currenttrack._msgList.length - 1; 46 | currenttrack._msgList[t].type = 0x51; // Set Tempo 47 | var tempoinmidiformat:int = 60000000 / tempo; 48 | 49 | var byte1:int = (tempoinmidiformat >> 16) & 0xFF; 50 | var byte2:int = (tempoinmidiformat >> 8) & 0xFF; 51 | var byte3:int = tempoinmidiformat & 0xFF; 52 | 53 | var myba:ByteArray = new ByteArray(); 54 | myba.writeByte(byte1); 55 | myba.writeByte(byte2); 56 | myba.writeByte(byte3); 57 | currenttrack._msgList[t].text = myba; 58 | } 59 | 60 | 61 | public function writeinstrument(instr:int, channel:int):void { 62 | currenttrack._msgList.push(new ChannelItem()); 63 | var t:int = currenttrack._msgList.length - 1; 64 | currenttrack._msgList[t]._kind = 0xC0; // Program Change 65 | currenttrack._msgList[t]._command = 192 + channel; 66 | currenttrack._msgList[t]._data1 = instr; 67 | } 68 | 69 | public function writenote(channel:int, pitch:int, time:int, length:int, volume:int):void { 70 | volume = volume / 2; 71 | if (volume > 127) volume = 127; 72 | 73 | currenttrack._msgList.push(new NoteItem(channel, pitch, volume, length, time)); 74 | } 75 | 76 | public var midifile:MidiFile; 77 | public var currenttrack:MidiTrack; 78 | } 79 | } -------------------------------------------------------------------------------- /src/arrangementclass.as: -------------------------------------------------------------------------------- 1 | package { 2 | import flash.display.*; 3 | import flash.geom.*; 4 | import flash.events.*; 5 | import flash.net.*; 6 | 7 | public class arrangementclass { 8 | public function arrangementclass():void { 9 | for (var i:int = 0; i < 1000; i++) { 10 | bar.push(new barclass); 11 | } 12 | for (i = 0; i < 100; i++) { 13 | copybuffer.push(new barclass); 14 | } 15 | copybuffersize = 0; 16 | 17 | for (i = 0; i < 8; i++) { 18 | channelon.push(true); 19 | } 20 | clear(); 21 | } 22 | 23 | public function copy():void { 24 | for (var i:int = loopstart; i < loopend; i++) { 25 | for (var j:int = 0; j < 8; j++) { 26 | copybuffer[i-loopstart].channel[j] = bar[i].channel[j]; 27 | } 28 | } 29 | copybuffersize = loopend-loopstart; 30 | } 31 | 32 | public function paste(t:int):void { 33 | for (var i:int = 0; i < copybuffersize; i++) { 34 | insertbar(t); 35 | } 36 | 37 | for (i = t; i < t + copybuffersize; i++) { 38 | for (var j:int = 0; j < 8; j++) { 39 | bar[i].channel[j] = copybuffer[i - t].channel[j]; 40 | } 41 | } 42 | } 43 | 44 | public function clear():void { 45 | loopstart = 0; 46 | loopend = 1; 47 | currentbar = 0; 48 | 49 | for (var i:int = 0; i < lastbar; i++) { 50 | for (var j:int = 0; j < 8; j++) { 51 | bar[i].channel[j] = -1; 52 | } 53 | } 54 | 55 | lastbar = 1; 56 | } 57 | 58 | public function addpattern(a:int, b:int, t:int):void { 59 | bar[a].channel[b] = t; 60 | if (a + 1 > lastbar) lastbar = a + 1; 61 | } 62 | 63 | public function removepattern(a:int, b:int):void { 64 | bar[a].channel[b] = -1; 65 | var lbcheck:int = 0; 66 | for (var i:int = 0; i <= lastbar; i++) { 67 | for (var j:int = 0; j < 8; j++) { 68 | if (bar[i].channel[j] > -1) { 69 | lbcheck = i; 70 | } 71 | } 72 | } 73 | lastbar = lbcheck + 1; 74 | } 75 | 76 | public function insertbar(t:int):void { 77 | for (var i:int = lastbar+1; i > t; i--) { 78 | for (var j:int = 0; j < 8; j++) { 79 | bar[i].channel[j] = bar[i - 1].channel[j]; 80 | } 81 | } 82 | for (j = 0; j < 8; j++) { 83 | bar[t].channel[j] = -1; 84 | } 85 | lastbar++; 86 | } 87 | 88 | public function deletebar(t:int):void { 89 | for (var i:int = t; i < lastbar+1; i++) { 90 | for (var j:int = 0; j < 8; j++) { 91 | bar[i].channel[j] = bar[i + 1].channel[j]; 92 | } 93 | } 94 | lastbar--; 95 | } 96 | 97 | public var copybuffer:Vector. = new Vector.; 98 | public var copybuffersize:int; 99 | 100 | public var bar:Vector. = new Vector.; 101 | public var channelon:Vector. = new Vector.; 102 | public var loopstart:int, loopend:int; 103 | public var currentbar:int; 104 | 105 | public var lastbar:int; 106 | 107 | public var viewstart:int; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/barclass.as: -------------------------------------------------------------------------------- 1 | package { 2 | import flash.display.*; 3 | import flash.geom.*; 4 | import flash.events.*; 5 | import flash.net.*; 6 | 7 | public class barclass { 8 | public function barclass():void { 9 | for (var i:int = 0; i < 8; i++) { 10 | channel.push( -1); 11 | } 12 | clear(); 13 | } 14 | 15 | public function clear():void { 16 | for (var i:int = 0; i < 8; i++) { 17 | channel[i] = -1; 18 | } 19 | } 20 | 21 | public var channel:Vector. = new Vector.; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/co/sparemind/trackermodule/XMInstrument.as: -------------------------------------------------------------------------------- 1 | package co.sparemind.trackermodule { 2 | public class XMInstrument { 3 | import flash.utils.ByteArray; 4 | import flash.utils.Endian; 5 | 6 | protected var _name:ByteArray; 7 | public var volume:uint = 40; 8 | public var samples:Vector. = new Vector.(); 9 | public var keymapAssignments:Vector. = Vector.([ 10 | 0,0,0,0,0,0,0,0,0,0,0,0, 11 | 0,0,0,0,0,0,0,0,0,0,0,0, 12 | 0,0,0,0,0,0,0,0,0,0,0,0, 13 | 0,0,0,0,0,0,0,0,0,0,0,0, 14 | 0,0,0,0,0,0,0,0,0,0,0,0, 15 | 0,0,0,0,0,0,0,0,0,0,0,0, 16 | 0,0,0,0,0,0,0,0,0,0,0,0, 17 | 0,0,0,0,0,0,0,0,0,0,0,0 18 | ]); 19 | 20 | public function XMInstrument() { 21 | _name = new ByteArray(); 22 | _name.endian = Endian.LITTLE_ENDIAN; 23 | this.name = ' '; 24 | } 25 | 26 | public function addSample(sample:XMSample):void { 27 | samples.push(sample); 28 | } 29 | 30 | /** 31 | * XM only seems to support 16 samples per instrument 32 | * so this silently discards any past that. 33 | */ 34 | public function addSamples(extraSamples:Vector.):void { 35 | samples = samples.concat(extraSamples).slice(0,16); 36 | } 37 | 38 | public function get name():String { 39 | return _name.toString(); 40 | } 41 | public function set name(unpadded:String):void { 42 | _name.clear(); 43 | _name.writeMultiByte(unpadded.slice(0,22), 'us-ascii'); 44 | for (var i:uint = _name.length; i < 22; i++) { 45 | _name.writeByte(0x20); // space-padded 46 | } 47 | } 48 | } 49 | 50 | } 51 | 52 | -------------------------------------------------------------------------------- /src/co/sparemind/trackermodule/XMPattern.as: -------------------------------------------------------------------------------- 1 | package co.sparemind.trackermodule { 2 | public class XMPattern { 3 | public var rows:Vector.; 4 | public function XMPattern(numrows:int) { 5 | rows = new Vector.(numrows, true); 6 | } 7 | } 8 | 9 | } 10 | 11 | -------------------------------------------------------------------------------- /src/co/sparemind/trackermodule/XMPatternCell.as: -------------------------------------------------------------------------------- 1 | package co.sparemind.trackermodule { 2 | public class XMPatternCell { 3 | public var note:uint = 0; 4 | public var instrument:uint = 0; 5 | public var volume:uint = 0; 6 | public var effect:uint = 0; 7 | public var effectParam:uint = 0; 8 | public function XMPatternCell(config:Object = null) { 9 | if (config === null) { return; } 10 | 11 | note = config.note; 12 | instrument = config.instrument; 13 | volume = config.volume; 14 | effect = config.effect; 15 | effectParam = config.effectParam; 16 | } 17 | public function isEmpty():Boolean { 18 | return (note === 0 && 19 | instrument === 0 && 20 | volume === 0 && 21 | effect === 0 && 22 | effectParam === 0 23 | ); 24 | } 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/co/sparemind/trackermodule/XMPatternLine.as: -------------------------------------------------------------------------------- 1 | package co.sparemind.trackermodule { 2 | public class XMPatternLine { 3 | public var cellOnTrack:Vector.; 4 | 5 | public function XMPatternLine(numtracks:int) { 6 | cellOnTrack = new Vector.(numtracks, true); 7 | for (var i:uint = 0; i < numtracks; i++) { 8 | cellOnTrack[i] = new XMPatternCell(); 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/co/sparemind/trackermodule/XMSample.as: -------------------------------------------------------------------------------- 1 | package co.sparemind.trackermodule { 2 | public class XMSample { 3 | import flash.utils.ByteArray; 4 | import flash.utils.Endian; 5 | 6 | public var volume:uint; 7 | public var finuetune:uint = 0; 8 | // type bitfield: looping, 8-bit/16-bit 9 | public var panning:uint = 0x80; 10 | public var relativeNoteNumber:int = 0; 11 | protected var _name:ByteArray; 12 | public var data:ByteArray; 13 | public var bitsPerSample:uint = 8; 14 | public var finetune:uint = 0; 15 | public var loopStart:uint = 0; 16 | public var loopLength:uint = 0; 17 | public var loopsForward:Boolean = false; 18 | 19 | public function XMSample() { 20 | _name = new ByteArray(); 21 | _name.endian = Endian.LITTLE_ENDIAN; 22 | this.name = ' '; 23 | } 24 | public function get name():String { 25 | return _name.toString(); 26 | } 27 | public function set name(unpadded:String):void { 28 | _name.clear(); 29 | _name.writeMultiByte(unpadded.slice(0,22), 'us-ascii'); 30 | for (var i:uint = _name.length; i < 22; i++) { 31 | _name.writeByte(0x20); // space-padded 32 | } 33 | } 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/co/sparemind/trackermodule/XMSampleFake.as: -------------------------------------------------------------------------------- 1 | package co.sparemind.trackermodule { 2 | public class XMSampleFake extends XMSample { 3 | import flash.utils.ByteArray; 4 | import flash.utils.Endian; 5 | public function XMSampleFake() { 6 | this.bitsPerSample = 8; 7 | this.name = 'fake sample '; 8 | this.data = new ByteArray(); 9 | var sinewave:Array = [ 10 | 0x0a,0x64,0x08,0x9c,0x06,0x05,0x04,0x03,0x64,0x00,0x00, 11 | 0x00,0x9c,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 12 | 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 13 | 0xd8,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, 14 | 0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, 15 | 0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe 16 | ]; 17 | this.data.endian = Endian.LITTLE_ENDIAN; 18 | for (var i:uint = 0; i < sinewave.length; i++) { 19 | this.data.writeByte(sinewave[i]); 20 | } 21 | loopLength = sinewave.length; 22 | loopsForward = true; 23 | volume = 40; 24 | } 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/de/MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007 Michael Baczynski, http://www.polygonal.de 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/de/polygonal/ds/Array3.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.Collection; 12 | 13 | /** 14 | * A three-dimensonal array build upon a single linear array. 15 | */ 16 | public class Array3 implements Collection 17 | { 18 | private var _a:Array; 19 | private var _w:int, _h:int, _d:int; 20 | 21 | /** 22 | * Initializes a three-dimensional array to match the given width, height and depth. 23 | * 24 | * width - The width (number of columns). 25 | * height - The height (number of rows). 26 | * depth - The depth (number of layers). 27 | */ 28 | public function Array3(w:int, h:int, d:int) 29 | { 30 | _a = new Array((_w = w) * (_h = h) * (_d = d)); 31 | } 32 | 33 | /** 34 | * Indicates the width (columns). 35 | * If a new width is set, the structure is resized accordingly. 36 | */ 37 | public function get width():int 38 | { 39 | return _w; 40 | } 41 | 42 | public function set width(w:int):void 43 | { 44 | resize(w, _h, _d); 45 | } 46 | 47 | /** 48 | * Indicates the height (rows). 49 | * If a new height is set, the structure is resized accordingly. 50 | */ 51 | public function get height():int 52 | { 53 | return _h; 54 | } 55 | 56 | public function set height(h:int):void 57 | { 58 | resize(_w, h, _d); 59 | } 60 | 61 | /** 62 | * Indicates the depth (layers). 63 | * If a new depth is set, the structure is resized accordingly. 64 | */ 65 | public function get depth():int 66 | { 67 | return _d; 68 | } 69 | 70 | public function set depth(d:int):void 71 | { 72 | resize(_w, _h, d); 73 | } 74 | 75 | /** 76 | * Sets each cell in the three-dimensional array to a given value. 77 | * 78 | * @param obj The data. 79 | */ 80 | public function fill(obj:*):void 81 | { 82 | var k:int = size; 83 | for (var i:int = 0; i < k; i++) 84 | _a[i] = obj; 85 | } 86 | 87 | /** 88 | * Reads the data at the given x/y/z index. 89 | * No boundary check is performed, so you have to 90 | * make sure the x, y and z index does not exceed the 91 | * width, height or depth of the structure. 92 | * 93 | * @param x The x index. 94 | * @param y The y index. 95 | * @param z The z index. 96 | */ 97 | public function get(x:int, y:int, z:int):* 98 | { 99 | return _a[int((z * _w * _h) + (y * _w) + x)]; 100 | } 101 | 102 | /** 103 | * Writes data into the cell at the given x/y/z index. 104 | * No boundary check is performed, so you have to 105 | * make sure the x, y and z index does not exceed the 106 | * width, height or depth of the structure. 107 | * 108 | * @param x The x index. 109 | * @param y The y index. 110 | * @param z The z index. 111 | * @param obj The data to store. 112 | */ 113 | public function set(x:int, y:int, z:int, obj:*):void 114 | { 115 | _a[int((z * _w * _h) + (y * _w) + x)] = obj; 116 | } 117 | 118 | /** 119 | * Resizes the array to match the given width, height and depth 120 | * while preserving existing values. 121 | * 122 | * @param w The new width (columns) 123 | * @param h The new height (rows) 124 | * @param d The new depth (layers) 125 | */ 126 | public function resize(w:int, h:int, d:int):void 127 | { 128 | var tmp:Array = _a.concat(); 129 | 130 | _a.length = 0; 131 | _a.length = w * h * d; 132 | 133 | if (_a.length == 0) 134 | return; 135 | 136 | var xMin:int = w < _w ? w : _w; 137 | var yMin:int = h < _h ? h : _h; 138 | var zMin:int = d < _d ? d : _d; 139 | 140 | var x:int, y:int, z:int; 141 | var t1:int, t2:int, t3:int, t4:int; 142 | 143 | for (z = 0; z < zMin; z++) 144 | { 145 | t1 = z * w * h; 146 | t2 = z * _w * _h; 147 | 148 | for (y = 0; y < yMin; y++) 149 | { 150 | t3 = y * w; 151 | t4 = y * _w; 152 | 153 | for (x = 0; x < xMin; x++) 154 | _a[t1 + t3 + x] = tmp[t2 + t4 + x]; 155 | } 156 | } 157 | 158 | _w = w; 159 | _h = h; 160 | _d = d; 161 | } 162 | 163 | /** 164 | * Checks if a given item exists. 165 | * 166 | * @return True if the item is found, otherwise false. 167 | */ 168 | public function contains(obj:*):Boolean 169 | { 170 | var k:int = size; 171 | for (var i:int = 0; i < k; i++) 172 | { 173 | if (_a[i] === obj) 174 | return true; 175 | } 176 | return false; 177 | } 178 | 179 | /** 180 | * Clears all elements. 181 | */ 182 | public function clear():void 183 | { 184 | _a = new Array(size); 185 | } 186 | 187 | /** 188 | * Initializes an iterator object pointing to the 189 | * first item (0, 0) in the first layer. 190 | */ 191 | public function getIterator():Iterator 192 | { 193 | return new Array3Iterator(this); 194 | } 195 | 196 | /** 197 | * The total number of cells. 198 | */ 199 | public function get size():int 200 | { 201 | return _w * _h * _d; 202 | } 203 | 204 | /** 205 | * Checks if the 3d array is empty. 206 | */ 207 | public function isEmpty():Boolean 208 | { 209 | return false; 210 | } 211 | 212 | 213 | /** 214 | * Converts the structure into an array. 215 | * 216 | * @return An array. 217 | */ 218 | public function toArray():Array 219 | { 220 | var a:Array = _a.concat(); 221 | 222 | var k:int = size; 223 | if (a.length > k) a.length = k; 224 | return a; 225 | } 226 | 227 | /** 228 | * Returns a string representing the current object. 229 | */ 230 | public function toString():String 231 | { 232 | return "[Array3, size=" + size + "]"; 233 | } 234 | } 235 | } 236 | 237 | import de.polygonal.ds.Iterator; 238 | import de.polygonal.ds.Array3; 239 | 240 | internal class Array3Iterator implements Iterator 241 | { 242 | private var _values:Array; 243 | private var _length:int; 244 | private var _cursor:int; 245 | 246 | public function Array3Iterator(a3:Array3) 247 | { 248 | _values = a3.toArray(); 249 | _length = _values.length; 250 | _cursor = 0; 251 | } 252 | 253 | public function get data():* 254 | { 255 | return _values[_cursor]; 256 | } 257 | 258 | public function set data(obj:*):void 259 | { 260 | _values[_cursor] = obj; 261 | } 262 | 263 | public function start():void 264 | { 265 | _cursor = 0; 266 | } 267 | 268 | public function hasNext():Boolean 269 | { 270 | return _cursor < _length; 271 | } 272 | 273 | public function next():* 274 | { 275 | return _values[_cursor++]; 276 | } 277 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/ArrayedQueue.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.Collection; 12 | 13 | /** 14 | * An arrayed queue (circular queue). 15 | *

A queue is a FIFO structure (First In, First Out).

16 | */ 17 | public class ArrayedQueue implements Collection 18 | { 19 | private var _que:Array; 20 | private var _size:int; 21 | private var _divisor:int; 22 | 23 | private var _count:int; 24 | private var _front:int; 25 | 26 | /** 27 | * Initializes a queue object to match the given size. 28 | * The size must be a power of two to use fast bitwise AND modulo. 29 | * 30 | * @param sizeShift The size exponent. (e.g. size is 1 << sizeShift eq. 2^sizeShift) 31 | */ 32 | public function ArrayedQueue(sizeShift:int) 33 | { 34 | if (sizeShift < 3) sizeShift = 3; 35 | _size = 1 << sizeShift; 36 | _divisor = _size - 1; 37 | clear(); 38 | } 39 | 40 | /** 41 | * Indicates the front item. 42 | * 43 | * @return The front item. 44 | */ 45 | public function peek():* 46 | { 47 | return _que[_front]; 48 | } 49 | 50 | /** 51 | * Enqueues some data. 52 | * 53 | * @param obj The data. 54 | * @return True if operation succeeded, otherwise false (queue is full). 55 | */ 56 | public function enqueue(obj:*):Boolean 57 | { 58 | if (_size != _count) 59 | { 60 | _que[int((_count++ + _front) & _divisor)] = obj; 61 | return true; 62 | } 63 | return false; 64 | } 65 | 66 | /** 67 | * Dequeues and returns the front item. 68 | * 69 | * @return The front item or null if the queue is empty. 70 | */ 71 | public function dequeue():* 72 | { 73 | if (_count > 0) 74 | { 75 | var data:* = _que[_front++]; 76 | if (_front == _size) _front = 0; 77 | _count--; 78 | return data; 79 | } 80 | return null; 81 | } 82 | 83 | /** 84 | * Deletes the last dequeued item to free it 85 | * for the garbage collector. Use only directly 86 | * after calling the dequeue() function. 87 | */ 88 | public function dispose():void 89 | { 90 | if (!_front) _que[int(_size - 1)] = null; 91 | else _que[int(_front - 1)] = null; 92 | } 93 | 94 | /** 95 | * Reads an item relative to the front index. 96 | * 97 | * @param i The index of the item. 98 | * @return The item at the given relative index. 99 | */ 100 | public function getAt(i:int):* 101 | { 102 | if (i >= _count) return null; 103 | return _que[int((i + _front) & _divisor)]; 104 | } 105 | 106 | /** 107 | * Writes an item relative to the front index. 108 | * 109 | * @param i The index of the item. 110 | * @param obj The data. 111 | */ 112 | public function setAt(i:int, obj:*):void 113 | { 114 | if (i >= _count) return; 115 | _que[int((i + _front) & _divisor)] = obj; 116 | } 117 | 118 | /** 119 | * Checks if a given item exists. 120 | * 121 | * @return True if the item is found, otherwise false. 122 | */ 123 | public function contains(obj:*):Boolean 124 | { 125 | for (var i:int = 0; i < _count; i++) 126 | { 127 | if (_que[int((i + _front) & _divisor)] === obj) 128 | return true; 129 | } 130 | return false; 131 | } 132 | 133 | /** 134 | * Clears all elements. 135 | */ 136 | public function clear():void 137 | { 138 | _que = new Array(_size); 139 | _front = _count = 0; 140 | } 141 | 142 | /** 143 | * Creates a new iterator pointing to the front of the queue. 144 | */ 145 | public function getIterator():Iterator 146 | { 147 | return new ArrayedQueueIterator(this); 148 | } 149 | 150 | /** 151 | * The total number of items in the queue. 152 | */ 153 | public function get size():int 154 | { 155 | return _count; 156 | } 157 | 158 | /** 159 | * Checks if the queue is empty. 160 | */ 161 | public function isEmpty():Boolean 162 | { 163 | return _count == 0; 164 | } 165 | 166 | /** 167 | * The maximum allowed size. 168 | */ 169 | public function get maxSize():int 170 | { 171 | return _size; 172 | } 173 | 174 | /** 175 | * Converts the structure into an array. 176 | * 177 | * @return An array. 178 | */ 179 | public function toArray():Array 180 | { 181 | var a:Array = new Array(_count); 182 | for (var i:int = 0; i < _count; i++) 183 | a[i] = _que[int((i + _front) & _divisor)]; 184 | return a; 185 | } 186 | 187 | /** 188 | * Returns a string representing the current object. 189 | */ 190 | public function toString():String 191 | { 192 | return "[ArrayedQueue, size=" + size + "]"; 193 | } 194 | 195 | /** 196 | * Prints out all elements in the queue (for debug/demo purposes). 197 | */ 198 | public function dump():String 199 | { 200 | var s:String = "[ArrayedQueue]\n"; 201 | 202 | s += "\t" + getAt(i) + " -> front\n"; 203 | for (var i:int = 1; i < _count; i++) 204 | s += "\t" + getAt(i) + "\n"; 205 | 206 | return s; 207 | } 208 | } 209 | } 210 | 211 | import de.polygonal.ds.Iterator; 212 | import de.polygonal.ds.ArrayedQueue; 213 | 214 | internal class ArrayedQueueIterator implements Iterator 215 | { 216 | private var _que:ArrayedQueue; 217 | private var _cursor:int; 218 | 219 | public function ArrayedQueueIterator(que:ArrayedQueue) 220 | { 221 | _que = que; 222 | _cursor = 0; 223 | } 224 | 225 | public function get data():* 226 | { 227 | return _que.getAt(_cursor); 228 | } 229 | 230 | public function set data(obj:*):void 231 | { 232 | _que.setAt(_cursor, obj); 233 | } 234 | 235 | public function start():void 236 | { 237 | _cursor = 0; 238 | } 239 | 240 | public function hasNext():Boolean 241 | { 242 | return _cursor < _que.size; 243 | } 244 | 245 | public function next():* 246 | { 247 | if (_cursor < _que.size) 248 | return _que.getAt(_cursor++); 249 | return null; 250 | } 251 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/ArrayedStack.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.Collection; 12 | 13 | /** 14 | * An arrayed stack. 15 | *

A stack is a LIFO structure (Last In, First Out).

16 | */ 17 | public class ArrayedStack implements Collection 18 | { 19 | private var _stack:Array; 20 | private var _size:int; 21 | private var _top:int; 22 | 23 | /** 24 | * Initializes a stack to match the given size. 25 | * 26 | * @param size The total number of elements the stack can store. 27 | */ 28 | public function ArrayedStack(size:int) 29 | { 30 | _size = size; 31 | clear(); 32 | } 33 | 34 | /** 35 | * Indicates the top item. 36 | * 37 | * @return The top item. 38 | */ 39 | public function peek():* 40 | { 41 | return _stack[int(_top - 1)]; 42 | } 43 | 44 | /** 45 | * Pushes data onto the stack. 46 | * 47 | * @param obj The data. 48 | */ 49 | public function push(obj:*):Boolean 50 | { 51 | if (_size != _top) 52 | { 53 | _stack[_top++] = obj; 54 | return true; 55 | } 56 | return false; 57 | } 58 | 59 | /** 60 | * Pops data from the stack. 61 | * 62 | * @return The top item. 63 | */ 64 | public function pop():void 65 | { 66 | if (_top > 0) _top-- 67 | } 68 | 69 | /** 70 | * Reads an item at a given index. 71 | * 72 | * @param i The index. 73 | * @return The item at the given index. 74 | */ 75 | public function getAt(i:int):* 76 | { 77 | if (i >= _top) return null; 78 | return _stack[i]; 79 | } 80 | 81 | /** 82 | * Writes an item at a given index. 83 | * 84 | * @param i The index. 85 | * @param obj The data. 86 | */ 87 | public function setAt(i:int, obj:*):void 88 | { 89 | if (i >= _top) return; 90 | _stack[i] = obj; 91 | } 92 | 93 | /** 94 | * Checks if a given item exists. 95 | * 96 | * @return True if the item is found, otherwise false. 97 | */ 98 | public function contains(obj:*):Boolean 99 | { 100 | for (var i:int = 0; i < _top; i++) 101 | { 102 | if (_stack[i] === obj) 103 | return true; 104 | } 105 | return false; 106 | } 107 | 108 | /** 109 | * Clears the stack. 110 | */ 111 | public function clear():void 112 | { 113 | _stack = new Array(_size); 114 | _top = 0; 115 | } 116 | 117 | /** 118 | * Creates a new iterator pointing to the top item. 119 | */ 120 | public function getIterator():Iterator 121 | { 122 | return new ArrayedStackIterator(this); 123 | } 124 | 125 | /** 126 | * The total number of items in the stack. 127 | */ 128 | public function get size():int 129 | { 130 | return _top; 131 | } 132 | 133 | /** 134 | * Checks if the stack is empty. 135 | */ 136 | public function isEmpty():Boolean 137 | { 138 | return _size == 0; 139 | } 140 | 141 | /** 142 | * The maximum allowed size. 143 | */ 144 | public function get maxSize():int 145 | { 146 | return _size; 147 | } 148 | 149 | /** 150 | * Converts the structure into an array. 151 | * 152 | * @return An array. 153 | */ 154 | public function toArray():Array 155 | { 156 | return _stack.concat(); 157 | } 158 | 159 | /** 160 | * Returns a string representing the current object. 161 | */ 162 | public function toString():String 163 | { 164 | return "[ArrayedStack, size= " + _top + "]"; 165 | } 166 | 167 | /** 168 | * Prints out all elements in the queue (for debug/demo purposes). 169 | */ 170 | public function dump():String 171 | { 172 | var s:String = "[ArrayedStack]"; 173 | if (_top == 0) return s; 174 | 175 | var k:int = _top - 1; 176 | s += "\n\t" + _stack[k--] + " -> front\n"; 177 | for (var i:int = k; i >= 0; i--) 178 | s += "\t" + _stack[i] + "\n"; 179 | return s; 180 | } 181 | } 182 | } 183 | 184 | import de.polygonal.ds.Iterator; 185 | import de.polygonal.ds.ArrayedStack; 186 | 187 | internal class ArrayedStackIterator implements Iterator 188 | { 189 | private var _stack:ArrayedStack; 190 | private var _cursor:int; 191 | 192 | public function ArrayedStackIterator(stack:ArrayedStack) 193 | { 194 | _stack = stack; 195 | start(); 196 | } 197 | 198 | public function get data():* 199 | { 200 | return _stack.getAt(_cursor); 201 | } 202 | 203 | public function set data(obj:*):void 204 | { 205 | _stack.setAt(_cursor, obj); 206 | } 207 | 208 | public function start():void 209 | { 210 | _cursor = _stack.size - 1; 211 | } 212 | 213 | public function hasNext():Boolean 214 | { 215 | return _cursor >= 0; 216 | } 217 | 218 | public function next():* 219 | { 220 | if (_cursor >= 0) 221 | return _stack.getAt(_cursor--); 222 | return null; 223 | } 224 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/BinarySearchTree.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.Collection; 12 | import de.polygonal.ds.NullIterator; 13 | import de.polygonal.ds.BinaryTreeNode; 14 | 15 | /** 16 | * A Binary Search Tree (BST). 17 | * 18 | *

A BST stores data in a recursive manner so that you can 19 | * access it quickly by using a key. Therefore, a BST automatically 20 | * sorts data as it is inserted.
21 | * For a BST to be valid, every node has to follow two rules:

22 | * 1. The data value in the left subtree must be less than the data value in the current node.
23 | * 2. The data value in the right subtree must be greater than the data value in the current node. 24 | */ 25 | public class BinarySearchTree implements Collection 26 | { 27 | /** 28 | * The root node being referenced. 29 | */ 30 | public var root:BinaryTreeNode; 31 | 32 | private var _compare:Function; 33 | 34 | /** 35 | * Initializes a BST tree with a given comparison function. 36 | * The function should return -1 if the left is 'less than' 37 | * the right, 0 if they are equal, and 1 if the left is 'greater than' 38 | * the right. If the function is omitted, the BST uses a 39 | * default function for comparing integers. 40 | * 41 | * @param compare The comparison function. 42 | */ 43 | public function BinarySearchTree(compare:Function = null) 44 | { 45 | root = null; 46 | 47 | if (compare == null) 48 | { 49 | _compare = function(a:int, b:int):int 50 | { 51 | return a - b; 52 | } 53 | } 54 | else 55 | _compare = compare; 56 | } 57 | 58 | /** 59 | * Inserts data into the tree. 60 | * 61 | * @param obj The data. 62 | */ 63 | public function insert(obj:*):void 64 | { 65 | var cur:BinaryTreeNode = root; 66 | 67 | if (!root) root = new BinaryTreeNode(obj); 68 | else 69 | { 70 | while (cur) 71 | { 72 | if (_compare(obj, cur.data) < 0) 73 | { 74 | if (cur.left) 75 | cur = cur.left 76 | else 77 | { 78 | cur.setLeft(obj); 79 | return; 80 | } 81 | } 82 | else 83 | { 84 | if (cur.right) 85 | cur = cur.right; 86 | else 87 | { 88 | cur.setRight(obj); 89 | return; 90 | } 91 | } 92 | } 93 | } 94 | } 95 | 96 | /** 97 | * Finds a piece of data in the tree and returns a reference 98 | * to the node that contains a match, or null if no match is found. 99 | * 100 | * @param obj The data to find. 101 | * @return A node containing the data or null if the data isn't found. 102 | */ 103 | public function find(obj:*):BinaryTreeNode 104 | { 105 | var cur:BinaryTreeNode = root, i:int; 106 | while (cur) 107 | { 108 | i = _compare(obj, cur.data); 109 | if (i == 0) return cur; 110 | cur = i < 0 ? cur.left : cur.right; 111 | } 112 | return null; 113 | } 114 | 115 | /** 116 | * Removes a node from the BST. 117 | * 118 | * @param node The node to remove. 119 | */ 120 | public function remove(node:BinaryTreeNode):void 121 | { 122 | if (node.left && node.right) 123 | { 124 | var t:BinaryTreeNode = node; 125 | while (t.right) t = t.right; 126 | 127 | if (node.left == t) 128 | { 129 | t.right = node.right; 130 | t.right.parent = t; 131 | } 132 | else 133 | { 134 | t.parent.right = t.left; 135 | if (t.left) t.left.parent = t.parent; 136 | 137 | t.left = node.left; 138 | t.left.parent = t; 139 | t.right = node.right; 140 | t.right.parent = t; 141 | } 142 | 143 | if (node == root) 144 | root = t; 145 | else 146 | { 147 | if (node.isLeft()) 148 | node.parent.left = t; 149 | else 150 | node.parent.right = t; 151 | } 152 | 153 | t.parent = node.parent; 154 | node.left = null; 155 | node.right = null; 156 | node = null; 157 | } 158 | else 159 | { 160 | var child:BinaryTreeNode = null; 161 | 162 | if (node.left) 163 | child = node.left; 164 | else 165 | if (node.right) 166 | child = node.right; 167 | 168 | if (node == root) 169 | root = child; 170 | else 171 | { 172 | if (node.isLeft()) 173 | node.parent.left = child; 174 | else 175 | node.parent.right = child; 176 | } 177 | 178 | if (child) child.parent = node.parent; 179 | node.left = node.right = null; 180 | node = null; 181 | } 182 | } 183 | 184 | /** 185 | * Checks if a given item exists. 186 | * 187 | * @return True if the item is found, otherwise false. 188 | */ 189 | public function contains(obj:*):Boolean 190 | { 191 | if (find(obj)) return true; 192 | return false; 193 | } 194 | 195 | /** 196 | * Clears the tree recursively, starting from this node. 197 | */ 198 | public function clear():void 199 | { 200 | if (root) 201 | { 202 | root.destroy(); 203 | root = null; 204 | } 205 | } 206 | 207 | /** 208 | * Regular iterator is not supported, 209 | * use BinaryTreeNode.preorder(), inorder() and postorder() instead. 210 | */ 211 | public function getIterator():Iterator 212 | { 213 | return new NullIterator(); 214 | } 215 | 216 | /** 217 | * The total number of tree nodes. 218 | */ 219 | public function get size():int 220 | { 221 | if (!root) return 0; 222 | return root.count(); 223 | } 224 | 225 | /** 226 | * Checks if the BST is empty. 227 | */ 228 | public function isEmpty():Boolean 229 | { 230 | if (root) 231 | return root.count() == 0; 232 | else 233 | return true; 234 | } 235 | 236 | /** 237 | * Converts the structure into an array. 238 | * 239 | * @return An array. 240 | */ 241 | public function toArray():Array 242 | { 243 | var a:Array = []; 244 | var copy:Function = function(node:BinaryTreeNode):void 245 | { 246 | a.push(node.data); 247 | } 248 | BinaryTreeNode.inorder(root, copy); 249 | return a; 250 | } 251 | 252 | /** 253 | * Returns a string representing the current object. 254 | */ 255 | public function toString():String 256 | { 257 | return "[BST, size=" + size + "]"; 258 | } 259 | 260 | /** 261 | * Prints out all elements in the queue (for debug/demo purposes). 262 | */ 263 | public function dump():String 264 | { 265 | var s:String = ""; 266 | var dumpNode:Function = function (node:BinaryTreeNode):void 267 | { 268 | s += node + "\n"; 269 | } 270 | BinaryTreeNode.inorder(root, dumpNode); 271 | return s; 272 | } 273 | } 274 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/BinaryTreeNode.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | /** 12 | * A binary tree node from which you can build a binary tree. 13 | * 14 | *

A Binary Tree is a simplified tree structure in which every node is 15 | * only allowed to have up to two children nodes, which are called 16 | * the left and right child.

17 | */ 18 | public class BinaryTreeNode 19 | { 20 | /** 21 | * Performs a preorder traversal on a tree. 22 | * This processes the current tree node before its children. 23 | * 24 | * @param node The node to start from. 25 | * @param process A process function applied to each traversed node. 26 | */ 27 | public static function preorder(node:BinaryTreeNode, process:Function):void 28 | { 29 | if (node) 30 | { 31 | process(node); 32 | 33 | if (node.left) 34 | BinaryTreeNode.preorder(node.left, process); 35 | 36 | if (node.right) 37 | BinaryTreeNode.preorder(node.right, process); 38 | } 39 | } 40 | 41 | /** 42 | * Performs an inorder traversal on a tree. 43 | * This processes the current node in between the children nodes. 44 | * 45 | * @param node The node to start from. 46 | * @param process A process function applied to each traversed node. 47 | */ 48 | public static function inorder(node:BinaryTreeNode, process:Function):void 49 | { 50 | if (node) 51 | { 52 | if (node.left) 53 | BinaryTreeNode.inorder(node.left, process); 54 | 55 | process(node); 56 | 57 | if (node.right) 58 | BinaryTreeNode.inorder(node.right, process); 59 | } 60 | } 61 | 62 | /** 63 | * Performs a postorder traversal on a tree. 64 | * This processes the current node after its children nodes. 65 | * 66 | * @param node The node to start from. 67 | * @param process A process function applied to each traversed node. 68 | */ 69 | public static function postorder(node:BinaryTreeNode, process:Function):void 70 | { 71 | if (node) 72 | { 73 | if (node.left) 74 | BinaryTreeNode.postorder(node.left, process); 75 | 76 | if (node.right) 77 | BinaryTreeNode.postorder(node.right, process); 78 | 79 | process(node); 80 | } 81 | } 82 | 83 | /** 84 | * The left child node being referenced. 85 | */ 86 | public var left:BinaryTreeNode; 87 | 88 | /** 89 | * The right child node being referenced. 90 | */ 91 | public var right:BinaryTreeNode; 92 | 93 | /** 94 | * The parent node being referenced. 95 | */ 96 | public var parent:BinaryTreeNode; 97 | 98 | /** 99 | * The node's data. 100 | */ 101 | public var data:*; 102 | 103 | /** 104 | * Creates an empty node. 105 | * 106 | * @param obj The data to store inside the node. 107 | */ 108 | public function BinaryTreeNode(obj:*) 109 | { 110 | this.data = data; 111 | parent = left = right = null; 112 | } 113 | 114 | /** 115 | * Writes data into the left child. 116 | * 117 | * @param obj The data. 118 | */ 119 | public function setLeft(obj:*):void 120 | { 121 | if (!left) 122 | { 123 | left = new BinaryTreeNode(obj); 124 | left.parent = this; 125 | } 126 | else 127 | left.data = data; 128 | } 129 | 130 | /** 131 | * Writes data into the right child. 132 | * 133 | * @param obj The data. 134 | */ 135 | public function setRight(obj:*):void 136 | { 137 | if (!right) 138 | { 139 | right = new BinaryTreeNode(obj); 140 | right.parent = this; 141 | } 142 | else 143 | right.data = data; 144 | } 145 | 146 | /** 147 | * Checks if this node is left of its parent. 148 | * 149 | * @return True if this node is left, otherwise false. 150 | */ 151 | public function isLeft():Boolean 152 | { 153 | return this == parent.left; 154 | } 155 | 156 | 157 | /** 158 | * Check if this node is a right of its parent. 159 | * 160 | * @return True if this node is right, otherwise false. 161 | */ 162 | public function isRight():Boolean 163 | { 164 | return this == parent.right; 165 | } 166 | 167 | /** 168 | * Recursively calculates the depth of a tree. 169 | * 170 | * @return The depth of the tree. 171 | */ 172 | public function getDepth(node:BinaryTreeNode = null):int 173 | { 174 | var left:int = -1, right:int = -1; 175 | 176 | if (node == null) node = this; 177 | 178 | if (node.left) 179 | left = getDepth(node.left); 180 | 181 | if (node.right) 182 | right = getDepth(node.right); 183 | 184 | return (Math.max(left, right) + 1); 185 | } 186 | 187 | /** 188 | * Recursively counts the total number 189 | * of nodes including this node. 190 | */ 191 | public function count():int 192 | { 193 | var c:int = 1; 194 | 195 | if (left) 196 | c += left.count(); 197 | 198 | if (right) 199 | c += right.count(); 200 | 201 | return c; 202 | } 203 | 204 | /** 205 | * Recursively clears the tree by deleting 206 | * all child nodes underneath the node 207 | * the method is called on. 208 | */ 209 | public function destroy():void 210 | { 211 | if (left) 212 | left.destroy(); 213 | 214 | left = null; 215 | 216 | if (right) 217 | right.destroy(); 218 | 219 | right = null; 220 | } 221 | 222 | /** 223 | * Returns a string representing the current object. 224 | */ 225 | public function toString():String 226 | { 227 | return "[BinaryTreeNode, data= " + data + "]"; 228 | } 229 | } 230 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/BitVector.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | /** 12 | * A bitvector. 13 | * 14 | * A bitvector is meant to condense bit values (or booleans) into 15 | * an array as close as possible so that no space is wasted. 16 | */ 17 | public class BitVector 18 | { 19 | private var _bits:Array; 20 | private var _arrSize:int; 21 | private var _bitSize:int; 22 | 23 | /** 24 | * Creates a bitvector with a given number of bits. 25 | * Each cell holds a 31-bit signed integer. 26 | * 27 | * @param bits The total number of bits. 28 | */ 29 | public function BitVector(bits:int) 30 | { 31 | _bits = []; 32 | _arrSize = 0; 33 | 34 | resize(bits); 35 | } 36 | 37 | /** 38 | * The total number of bits. 39 | */ 40 | public function get bitCount():int 41 | { 42 | return _arrSize * 31; 43 | } 44 | 45 | /** 46 | * The total number of cells. 47 | */ 48 | public function get cellCount():int 49 | { 50 | return _arrSize; 51 | } 52 | 53 | /** 54 | * Gets a bit from a given index. 55 | * 56 | * @param index The index of the bit. 57 | */ 58 | public function getBit(index:int):int 59 | { 60 | var bit:int = index % 31; 61 | return (_bits[(index / 31) >> 0] & (1 << bit)) >> bit; 62 | } 63 | 64 | /** 65 | * Sets a bit at a given index. 66 | * 67 | * @param index The index of the bit. 68 | * @param b The boolean flag to set. 69 | */ 70 | public function setBit(index:int, b:Boolean):void 71 | { 72 | var cell:int = index / 31; 73 | var mask:int = 1 << index % 31; 74 | _bits[cell] = b ? (_bits[cell] | mask) : (_bits[cell] & (~mask)); 75 | } 76 | 77 | /** 78 | * Resizes the bitvector to an appropriate number of bits. 79 | * 80 | * @param size The total number of bits. 81 | */ 82 | public function resize(size:int):void 83 | { 84 | if (size == _bitSize) return; 85 | _bitSize = size; 86 | 87 | //convert the bit-size to integer-size 88 | if (size % 31 == 0) 89 | size /= 31; 90 | else 91 | size = (size / 31) + 1; 92 | 93 | if (size < _arrSize) 94 | { 95 | _bits.splice(size); 96 | _arrSize = size; 97 | } 98 | else 99 | { 100 | _bits = _bits.concat(new Array(size - _arrSize)); 101 | _arrSize = _bits.length; 102 | } 103 | } 104 | 105 | /** 106 | * Resets all bits to 0; 107 | */ 108 | public function clear():void 109 | { 110 | var k:int = _bits.length; 111 | for (var i:int = 0; i < k; i++) 112 | _bits[i] = 0; 113 | } 114 | 115 | /** 116 | * Sets each bit to 1. 117 | */ 118 | public function setAll():void 119 | { 120 | var k:int = _bits.length; 121 | for (var i:int = 0; i < k; i++) 122 | _bits[i] = int.MAX_VALUE; 123 | } 124 | 125 | /** 126 | * Returns a string representing the current object. 127 | */ 128 | public function toString():String 129 | { 130 | return "[BitVector, size=" + _bitSize + "]"; 131 | } 132 | } 133 | } 134 | 135 | -------------------------------------------------------------------------------- /src/de/polygonal/ds/Collection.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.Iterator; 12 | 13 | /** 14 | * A 'java-style' collection interface. 15 | */ 16 | public interface Collection 17 | { 18 | /** 19 | * Searches the collection for a matching item. 20 | * 21 | * @return True if the item exists, otherwise false. 22 | */ 23 | function contains(obj:*):Boolean 24 | 25 | /** 26 | * Clears all items. 27 | */ 28 | function clear():void 29 | 30 | /** 31 | * Initializes an iterator object pointing 32 | * to the first item in the collection. 33 | * 34 | * @return An iterator object. 35 | */ 36 | function getIterator():Iterator 37 | 38 | /** 39 | * The total number of items. 40 | * 41 | * @return The size. 42 | */ 43 | function get size():int; 44 | 45 | /** 46 | * Checks if the collection is empty. 47 | * 48 | * @return True if empty, otherwise false. 49 | */ 50 | function isEmpty():Boolean 51 | 52 | /** 53 | * Converts the collection into an array. 54 | * 55 | * @return An array. 56 | */ 57 | function toArray():Array 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/de/polygonal/ds/DLinkedList.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.Iterator; 12 | import de.polygonal.ds.Collection; 13 | 14 | import de.polygonal.ds.DListNode; 15 | import de.polygonal.ds.DListIterator; 16 | 17 | /** 18 | * A doubly linked list. 19 | * 20 | *

A doubly linked list stores a reference to the next 21 | * and previous node which makes it possible to traverse 22 | * the list in both directions.

23 | */ 24 | public class DLinkedList implements Collection 25 | { 26 | private var _count:int; 27 | 28 | /** 29 | * The head node being referenced. 30 | */ 31 | public var head:DListNode; 32 | 33 | /** 34 | * The tail node being referenced. 35 | */ 36 | public var tail:DListNode; 37 | 38 | /** 39 | * Initializes an empty list. 40 | */ 41 | public function DLinkedList() 42 | { 43 | head = tail = null; 44 | _count = 0; 45 | } 46 | 47 | /** 48 | * Appends an item to the list. 49 | * 50 | * @param obj The data. 51 | * @return A doubly linked list node wrapping the data. 52 | */ 53 | public function append(obj:*):DListNode 54 | { 55 | var node:DListNode = new DListNode(obj); 56 | if (head) 57 | { 58 | tail.insertAfter(node); 59 | tail = tail.next; 60 | } 61 | else 62 | head = tail = node; 63 | 64 | _count++; 65 | return node; 66 | } 67 | 68 | /** 69 | * Prepends an item to the list. 70 | * 71 | * @param obj The data. 72 | * @return A doubly linked list node wrapping the data. 73 | */ 74 | public function prepend(obj:*):DListNode 75 | { 76 | var node:DListNode = new DListNode(obj); 77 | 78 | if (head) 79 | { 80 | head.insertBefore(node); 81 | head = head.prev; 82 | } 83 | else 84 | head = tail = node; 85 | 86 | _count++; 87 | return node; 88 | } 89 | 90 | /** 91 | * Inserts an item after a given iterator or appends it 92 | * if the iterator is invalid. 93 | * 94 | * @param itr A doubly linked list iterator. 95 | * @param obj The data. 96 | * @return A doubly linked list node wrapping the data. 97 | */ 98 | public function insertAfter(itr:DListIterator, obj:*):DListNode 99 | { 100 | if (itr.list != this) return null; 101 | if (itr.node) 102 | { 103 | var node:DListNode = new DListNode(obj); 104 | itr.node.insertAfter(node); 105 | 106 | if (itr.node == tail) 107 | tail = itr.node.next; 108 | 109 | _count++; 110 | return node; 111 | } 112 | else 113 | return append(obj); 114 | } 115 | 116 | /** 117 | * Inserts an item before a given iterator or appends it 118 | * if the iterator is invalid. 119 | * 120 | * @param itr A doubly linked list iterator. 121 | * @param obj The data. 122 | * @return A doubly linked list node wrapping the data. 123 | */ 124 | public function insertBefore(itr:DListIterator, obj:*):DListNode 125 | { 126 | if (itr.list != this) return null; 127 | if (itr.node) 128 | { 129 | var node:DListNode = new DListNode(obj); 130 | itr.node.insertBefore(node); 131 | if (itr.node == head) 132 | head = head.prev; 133 | 134 | _count++; 135 | return node; 136 | } 137 | else 138 | return prepend(obj); 139 | } 140 | 141 | /** 142 | * Removes the node the iterator is pointing 143 | * at and moves the iterator to the next node. 144 | * 145 | * @return True if the removal succeeded, otherwise false. 146 | */ 147 | public function remove(itr:DListIterator):Boolean 148 | { 149 | if (itr.list != this || !itr.node) return false; 150 | 151 | var node:DListNode = itr.node; 152 | 153 | if (node == head) 154 | head = head.next; 155 | else 156 | if (node == tail) 157 | tail = tail.prev; 158 | 159 | itr.forth(); 160 | node.unlink(); 161 | 162 | if (head == null) tail = null; 163 | 164 | _count--; 165 | return true; 166 | } 167 | 168 | /** 169 | * Removes the head of the list. 170 | */ 171 | public function removeHead():void 172 | { 173 | if (head) 174 | { 175 | head = head.next; 176 | 177 | if (head) 178 | head.prev = null; 179 | else 180 | tail = null 181 | 182 | _count--; 183 | } 184 | } 185 | 186 | /** 187 | * Removes the tail of the list. 188 | */ 189 | public function removeTail():void 190 | { 191 | if (tail) 192 | { 193 | tail = tail.prev; 194 | 195 | if (tail) 196 | tail.next = null; 197 | else 198 | head = null; 199 | 200 | _count--; 201 | } 202 | } 203 | 204 | /** 205 | * Checks if a given item exists. 206 | * 207 | * @return True if the item is found, otherwise false. 208 | */ 209 | public function contains(obj:*):Boolean 210 | { 211 | var node:DListNode = head; 212 | while (node) 213 | { 214 | if (node.data == obj) return true; 215 | node = node.next; 216 | } 217 | return false; 218 | } 219 | 220 | /** 221 | * Clears the list by unlinking all nodes 222 | * from it. This is important to unlock 223 | * the nodes for the garbage collector. 224 | */ 225 | public function clear():void 226 | { 227 | var node:DListNode = head; 228 | head = null; 229 | 230 | var next:DListNode; 231 | while (node) 232 | { 233 | next = node.next; 234 | node.next = node.prev = null; 235 | node = next; 236 | } 237 | _count = 0; 238 | } 239 | 240 | /** 241 | * Creates an iterator object pointing 242 | * at the first node in the list. 243 | * 244 | * @returns An iterator object. 245 | */ 246 | public function getIterator():Iterator 247 | { 248 | return new DListIterator(this, head); 249 | } 250 | 251 | /** 252 | * Creates a doubly linked iterator object pointing 253 | * at the first node in the list. 254 | * 255 | * @returns A DListIterator object. 256 | */ 257 | public function getListIterator():DListIterator 258 | { 259 | return new DListIterator(this, head); 260 | } 261 | 262 | /** 263 | * The total number of nodes in the list. 264 | */ 265 | public function get size():int 266 | { 267 | return _count; 268 | } 269 | 270 | /** 271 | * Checks if the list is empty. 272 | */ 273 | public function isEmpty():Boolean 274 | { 275 | return _count == 0; 276 | } 277 | 278 | /** 279 | * Converts the linked list into an array. 280 | * 281 | * @return An array. 282 | */ 283 | public function toArray():Array 284 | { 285 | var a:Array = []; 286 | var node:DListNode = head; 287 | while (node) 288 | { 289 | a.push(node.data); 290 | node = node.next; 291 | } 292 | return a; 293 | } 294 | 295 | /** 296 | * Returns a string representing the current object. 297 | */ 298 | public function toString():String 299 | { 300 | return "[DLinkedList > has " + size + " nodes]"; 301 | } 302 | 303 | /** 304 | * Prints out all elements in the list (for debug/demo purposes). 305 | */ 306 | public function dump():String 307 | { 308 | if (head == null) return "DLinkedList, empty"; 309 | 310 | var s:String = "DLinkedList, has " + _count + " node" + (_count == 1 ? "" : "s") + "\n|< Head\n"; 311 | 312 | var itr:DListIterator = getListIterator(); 313 | for (; itr.valid(); itr.forth()) 314 | s += "\t" + itr.data + "\n"; 315 | 316 | s += "Tail >|"; 317 | 318 | return s; 319 | } 320 | } 321 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/DListIterator.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.DListNode; 12 | import de.polygonal.ds.DLinkedList; 13 | 14 | /** 15 | * A list iterator. 16 | */ 17 | public class DListIterator implements Iterator 18 | { 19 | /** 20 | * The node the iterator is pointing to. 21 | */ 22 | public var node:DListNode; 23 | 24 | /** 25 | * The list of the iterator is referenced. 26 | */ 27 | public var list:DLinkedList; 28 | 29 | /** 30 | * Initializes a new DListIterator instance pointing to a given node. 31 | * Usually created by invoking SLinkedList.getIterator(). 32 | * 33 | * @param list The linked list the iterator should use. 34 | * @param node The iterator's initial node. 35 | */ 36 | public function DListIterator(list:DLinkedList, node:DListNode = null) 37 | { 38 | this.list = list; 39 | this.node = node; 40 | } 41 | 42 | /** 43 | * Moves the iterator to the start of the list. 44 | */ 45 | public function start():void 46 | { 47 | node = list.head; 48 | } 49 | 50 | /** 51 | * Returns the current node's data while 52 | * moving the iterator forward by one position. 53 | */ 54 | public function next():* 55 | { 56 | if (hasNext()) 57 | { 58 | var obj:* = node.data; 59 | node = node.next; 60 | return obj; 61 | } 62 | return null; 63 | } 64 | 65 | /** 66 | * Checks if the next node exists. 67 | */ 68 | public function hasNext():Boolean 69 | { 70 | return Boolean(node); 71 | } 72 | 73 | /** 74 | * Read/writes the current node's data. 75 | * 76 | * @return The data. 77 | */ 78 | public function get data():* 79 | { 80 | if (node) return node.data; 81 | return null; 82 | } 83 | 84 | public function set data(obj:*):void 85 | { 86 | node.data = obj; 87 | } 88 | 89 | /** 90 | * Moves the iterator to the end of the list. 91 | */ 92 | public function end():void 93 | { 94 | node = list.tail; 95 | } 96 | 97 | /** 98 | * Moves the iterator to the next node. 99 | */ 100 | public function forth():void 101 | { 102 | if (node) node = node.next; 103 | } 104 | 105 | /** 106 | * Moves the iterator to the previous node. 107 | */ 108 | public function back():void 109 | { 110 | if (node) node = node.prev; 111 | } 112 | 113 | /** 114 | * Checks if the current referenced node is valid. 115 | * 116 | * @return True if the node exists, otherwise false. 117 | */ 118 | public function valid():Boolean 119 | { 120 | return Boolean(node); 121 | } 122 | 123 | /** 124 | * Removes the node the iterator is 125 | * pointing to. 126 | */ 127 | public function remove():void 128 | { 129 | list.remove(this); 130 | } 131 | 132 | /** 133 | * Returns a string representing the current object. 134 | */ 135 | public function toString():String 136 | { 137 | return "{DListIterator, data=" + (node ? node.data : "null") + "}"; 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/DListNode.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | /** 12 | * A list node. 13 | * 14 | * The node acts as a data container and also 15 | * holds a reference to next and previous node 16 | * in the list. 17 | */ 18 | public class DListNode 19 | { 20 | /** 21 | * The node's data. 22 | */ 23 | public var data:*; 24 | 25 | /** 26 | * The next node in the list being referenced. 27 | */ 28 | public var next:DListNode; 29 | 30 | /** 31 | * The previous node in the list being referenced. 32 | */ 33 | public var prev:DListNode; 34 | 35 | /** 36 | * Initializes a new node that stores 37 | * the given item. 38 | * 39 | * @param obj The data to store in the node. 40 | */ 41 | public function DListNode(obj:*) 42 | { 43 | next = prev = null; 44 | data = obj; 45 | } 46 | 47 | /** 48 | * A helper function used solely by the DLinkedList class 49 | * for inserting this node after a given node. 50 | * 51 | * @param node A doubly linked list node. 52 | */ 53 | public function insertAfter(node:DListNode):void 54 | { 55 | node.next = next; 56 | node.prev = this; 57 | if (next) next.prev = node; 58 | next = node; 59 | } 60 | 61 | /** 62 | * A helper function used solely by the DLinkedList class 63 | * for inserting this node in front of a given node. 64 | * 65 | * @param node A doubly linked list node. 66 | */ 67 | public function insertBefore(node:DListNode):void 68 | { 69 | node.next = this; 70 | node.prev = prev; 71 | if (prev) prev.next = node; 72 | prev = node; 73 | } 74 | 75 | /** 76 | * A helper function used solely by the DLinkedList class 77 | * to unlink the node from the list. 78 | */ 79 | public function unlink():void 80 | { 81 | if (prev) prev.next = next; 82 | if (next) next.prev = prev; 83 | next = prev = null; 84 | } 85 | 86 | /** 87 | * Returns a string representing the current object. 88 | */ 89 | public function toString():String 90 | { 91 | return "[DListNode, data=" + data + "]" 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/Graph.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.GraphNode; 12 | 13 | /** 14 | * A linked uni-directional weighted graph structure. 15 | *

The Graph class manages all graph nodes. Each graph node has 16 | * a linked list of arcs, pointing to different nodes.

17 | */ 18 | public class Graph 19 | { 20 | /** 21 | * An array containing all graph nodes. 22 | */ 23 | public var nodes:Array; 24 | 25 | private var _nodeCount:int; 26 | private var _maxSize:int; 27 | 28 | /** 29 | * Constructs an empty graph. 30 | * 31 | * @param size The total number of nodes allowed. 32 | */ 33 | public function Graph(size:int) 34 | { 35 | nodes = new Array(_maxSize = size); 36 | _nodeCount = 0; 37 | } 38 | 39 | /** 40 | * Performs a depth-first traversal on the given node. 41 | * 42 | * @param node The starting graph node. 43 | * @param process A function to apply to each traversed node. 44 | */ 45 | public function depthFirst(node:GraphNode, process:Function):void 46 | { 47 | if (!node) return; 48 | 49 | process(node); 50 | node.marked = true; 51 | 52 | var k:int = node.numArcs, t:GraphNode; 53 | for (var i:int = 0; i < k; i++) 54 | { 55 | t = node.arcs[i].node; 56 | if (!t.marked) depthFirst(t, process); 57 | } 58 | } 59 | 60 | /** 61 | * Performs a breadth-first traversal on the given node. 62 | * 63 | * @param node The starting graph node. 64 | * @param process A function to apply to each traversed node. 65 | */ 66 | public function breadthFirst(node:GraphNode, process:Function):void 67 | { 68 | if (!node) return; 69 | 70 | var que:Array = []; 71 | que.push(node); 72 | node.marked = true; 73 | 74 | var c:int = 1; 75 | 76 | var t:GraphNode, u:GraphNode; 77 | while (c > 0) 78 | { 79 | process(t = que[0]); 80 | 81 | var arcs:Array = t.arcs, k:int = t.numArcs; 82 | for (var i:int = 0; i < k; i++) 83 | { 84 | u = arcs[i].node; 85 | if (!u.marked) 86 | { 87 | u.marked = true; 88 | que.push(u); 89 | c++; 90 | } 91 | } 92 | que.shift(); 93 | c--; 94 | } 95 | } 96 | 97 | /** 98 | * Adds a node at a given index to the graph. 99 | * 100 | * @param obj The data to store in the node. 101 | * @param i The index the node is stored at. 102 | * @return True if successful, otherwise false. 103 | */ 104 | public function addNode(obj:*, i:int):Boolean 105 | { 106 | if (nodes[i]) return false; 107 | 108 | nodes[i] = new GraphNode(obj); 109 | _nodeCount++; 110 | return true; 111 | } 112 | 113 | /** 114 | * Removes a node from the graph at a given index. 115 | * 116 | * @param index Index of the node to remove 117 | * @return True if successful, otherwise false. 118 | */ 119 | public function removeNode(i:int):Boolean 120 | { 121 | var node:GraphNode = nodes[i]; 122 | if(!node) return false; 123 | 124 | var arc:GraphArc; 125 | for (var j:int = 0; j < _maxSize; j++) 126 | { 127 | var t:GraphNode = nodes[j]; 128 | if (t && t.getArc(node)) removeArc(j, i); 129 | } 130 | 131 | nodes[i] = null; 132 | _nodeCount--; 133 | return true; 134 | } 135 | 136 | /** 137 | * Finds an arc pointing to the node 138 | * at the 'from' index to the node at the 'to' index. 139 | * 140 | * @param from The originating graph node index. 141 | * @param to The ending graph node index. 142 | * @return A GraphArc object or null if it doesn't exist. 143 | */ 144 | public function getArc(from:int, to:int):GraphArc 145 | { 146 | var node0:GraphNode = nodes[from]; 147 | var node1:GraphNode = nodes[to]; 148 | if (node0 && node1) return node0.getArc(node1); 149 | return null; 150 | } 151 | 152 | /** 153 | * Adds an arc pointing to the node located at the 154 | * 'from' index to the node at the 'to' index. 155 | * 156 | * @param from The originating graph node index. 157 | * @param to The ending graph node index. 158 | * @param weight The arc's weight 159 | * 160 | * @return True if an arc was added, otherwise false. 161 | */ 162 | public function addArc(from:int, to:int, weight:int = 1):Boolean 163 | { 164 | var node0:GraphNode = nodes[from]; 165 | var node1:GraphNode = nodes[to]; 166 | 167 | if (node0 && node1) 168 | { 169 | if (node0.getArc(node1)) return false; 170 | 171 | node0.addArc(node1, weight); 172 | return true; 173 | } 174 | return false; 175 | } 176 | 177 | /** 178 | * Removes an arc pointing to the node located at the 179 | * 'from' index to the node at the 'to' index. 180 | * 181 | * @param from The originating graph node index. 182 | * @param to The ending graph node index. 183 | * 184 | * @return True if an arc was removed, otherwise false. 185 | */ 186 | public function removeArc(from:int, to:int):Boolean 187 | { 188 | var node0:GraphNode = nodes[from]; 189 | var node1:GraphNode = nodes[to]; 190 | 191 | if (node0 && node1) 192 | { 193 | node0.removeArc(node1); 194 | return true; 195 | } 196 | return false; 197 | } 198 | 199 | /** 200 | * Clears the markers on all nodes in the graph 201 | * so the breadth-first and depth-first traversal 202 | * algorithms can 'see' the nodes. 203 | */ 204 | public function clearMarks():void 205 | { 206 | for (var i:int = 0; i < _maxSize; i++) 207 | { 208 | var node:GraphNode = nodes[i]; 209 | if (node) node.marked = false; 210 | } 211 | } 212 | 213 | /** 214 | * The number of nodes in the graph. 215 | */ 216 | public function get size():int 217 | { 218 | return _nodeCount; 219 | } 220 | 221 | /** 222 | * The maximum number of nodes the 223 | * graph can store. 224 | */ 225 | public function get maxSize():int 226 | { 227 | return _maxSize; 228 | } 229 | 230 | /** 231 | * Clears every node in the graph. 232 | */ 233 | public function clear():void 234 | { 235 | nodes = new Array(_maxSize); 236 | _nodeCount = 0; 237 | } 238 | } 239 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/GraphArc.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | /** 12 | * A weighted arc pointing to a graph node. 13 | */ 14 | public class GraphArc 15 | { 16 | /** 17 | * The node that the arc points to being referenced. 18 | */ 19 | public var node:GraphNode; 20 | 21 | /** 22 | * The weight (or cost) of the arc. 23 | */ 24 | public var weight:Number 25 | 26 | /** 27 | * Initializes a new graph arc with a given weight. 28 | * 29 | * @param node The graph node. 30 | * @param weight The weight. 31 | */ 32 | public function GraphArc(node:GraphNode, weight:Number = 1) 33 | { 34 | this.node = node; 35 | this.weight = weight; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/GraphNode.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.GraphArc; 12 | 13 | /** 14 | * A graph node. 15 | */ 16 | public class GraphNode 17 | { 18 | /** 19 | * The data being referenced. 20 | */ 21 | public var data:*; 22 | 23 | /** 24 | * An array of arcs connecting this node to other nodes. 25 | */ 26 | public var arcs:Array; 27 | 28 | /** 29 | * A flag indicating whether the node is marked or not. 30 | * Used for iterating over a graph structure. 31 | */ 32 | public var marked:Boolean; 33 | 34 | private var _arcCount:int = 0; 35 | 36 | /** 37 | * Constructs a new graph node. 38 | * 39 | * @param obj The data to store inside the node. 40 | */ 41 | public function GraphNode(obj:*) 42 | { 43 | this.data = obj; 44 | arcs = []; 45 | _arcCount = 0; 46 | marked = false; 47 | } 48 | 49 | /** 50 | * Adds an arc to the current graph node, pointing to a different 51 | * graph node and with a given weight. 52 | * 53 | * @param target The destination node the arc should point to. 54 | * @param weigth The arc's weigth. 55 | */ 56 | public function addArc(target:GraphNode, weight:Number):void 57 | { 58 | arcs.push(new GraphArc(target, weight)); 59 | _arcCount++; 60 | } 61 | 62 | /** 63 | * Removes the arc that points to the given node. 64 | * 65 | * @return True if removal was successful, otherwise false. 66 | */ 67 | public function removeArc(target:GraphNode):Boolean 68 | { 69 | for (var i:int = 0; i < _arcCount; i++) 70 | { 71 | if (arcs[i].node == target) 72 | { 73 | arcs.splice(i, 1); 74 | _arcCount--; 75 | return true; 76 | } 77 | } 78 | return false; 79 | } 80 | 81 | /** 82 | * Finds the arc that points to the given node. 83 | * 84 | * @param target The destination node. 85 | * 86 | * @return A GraphArc object or null if the arc doesn't exist. 87 | */ 88 | public function getArc(target:GraphNode):GraphArc 89 | { 90 | for (var i:int = 0 ; i < _arcCount; i++) 91 | { 92 | var arc:GraphArc = arcs[i]; 93 | if (arc.node == target) return arc; 94 | } 95 | return null; 96 | } 97 | 98 | /** 99 | * The number of arcs extending from this node. 100 | */ 101 | public function get numArcs():int 102 | { 103 | return _arcCount; 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/HashMap.as: -------------------------------------------------------------------------------- 1 | package de.polygonal.ds 2 | { 3 | import flash.utils.Dictionary; 4 | import de.polygonal.ds.Collection; 5 | 6 | public class HashMap implements Collection 7 | { 8 | private var _keyMap:Dictionary; 9 | private var _objMap:Dictionary; 10 | private var _size:int; 11 | 12 | /** 13 | * Initializes a hash map, which maps 14 | * keys to values. It cannot contain duplicate keys so 15 | * each key can map to at most one value. 16 | */ 17 | public function HashMap() 18 | { 19 | _keyMap = new Dictionary(true); 20 | _objMap = new Dictionary(true); 21 | _size = 0; 22 | } 23 | 24 | /** 25 | * Inserts a key/data couple into the table. 26 | * 27 | * @param key The key. 28 | * @param obj The data associated with the key. 29 | */ 30 | public function insert(key:*, obj:*):Boolean 31 | { 32 | if (_keyMap[key]) return false; 33 | ++_size; 34 | _objMap[obj] = key; 35 | _keyMap[key] = obj; 36 | return true; 37 | } 38 | 39 | /** 40 | * Finds the entry that is associated with the given key. 41 | * 42 | * @param key The key to search for. 43 | * @return The data associated with the key or null if no matching 44 | * entry was found. 45 | */ 46 | public function find(key:*):* 47 | { 48 | return _keyMap[key] || null; 49 | } 50 | 51 | /** 52 | * Finds the key that maps the given value. 53 | * 54 | * @param val The value which maps the sought-after key. 55 | * @return The key mapping the given value or null if no matching 56 | * key was found. 57 | */ 58 | public function findKey(val:*):* 59 | { 60 | return _objMap[val] || null; 61 | } 62 | 63 | /** 64 | * Removes an entry based on a given key. 65 | * 66 | * @param key The entry's key. 67 | * @return The data associated with the key or null if no matching 68 | * entry was found. 69 | */ 70 | public function remove(key:*):* 71 | { 72 | var obj:* = _keyMap[key]; 73 | 74 | if (obj) 75 | { 76 | --_size; 77 | delete _keyMap[key]; 78 | delete _objMap[obj]; 79 | return obj; 80 | } 81 | return null; 82 | } 83 | 84 | /** 85 | * Checks if a key maps the given value. 86 | * 87 | * @return True if value exists, otherwise false. 88 | */ 89 | public function contains(obj:*):Boolean 90 | { 91 | return _objMap[obj] ? true : false; 92 | } 93 | 94 | /** 95 | * Checks if a mapping exists for the given key. 96 | * 97 | * @return True if key exists, otherwise false. 98 | */ 99 | public function containsKey(key:*):Boolean 100 | { 101 | return _keyMap[key] ? true : false; 102 | } 103 | 104 | /** 105 | * Creates an interator for traversing the values. 106 | */ 107 | public function getIterator():Iterator 108 | { 109 | return new HashMapValueIterator(this); 110 | } 111 | 112 | /** 113 | * Creates an interator for traversing the keys. 114 | */ 115 | public function getKeyIterator():Iterator 116 | { 117 | return new HashMapKeyIterator(this); 118 | } 119 | 120 | /** 121 | * Clears all elements. 122 | */ 123 | public function clear():void 124 | { 125 | _keyMap = new Dictionary(true); 126 | _objMap = new Dictionary(true); 127 | _size = 0; 128 | } 129 | 130 | /** 131 | * The total number of items. 132 | */ 133 | public function get size():int 134 | { 135 | return _size; 136 | } 137 | 138 | /** 139 | * Checks if the map is empty. 140 | * 141 | * @return True if empty, otherwise false. 142 | */ 143 | public function isEmpty():Boolean 144 | { 145 | return _size == 0; 146 | } 147 | 148 | /** 149 | * Writes all values into an array. 150 | * 151 | * @return An array. 152 | */ 153 | public function toArray():Array 154 | { 155 | var a:Array = new Array(_size), j:int = 0; 156 | for each (var i:* in _keyMap) 157 | { 158 | a[j++] = i; 159 | } 160 | return a; 161 | } 162 | 163 | /** 164 | * Writes all keys into an array. 165 | * 166 | * @return An array. 167 | */ 168 | public function getKeySet():Array 169 | { 170 | var a:Array = new Array(_size), j:int = 0; 171 | for each (var i:* in _objMap) 172 | { 173 | a[j++] = i; 174 | } 175 | return a; 176 | } 177 | 178 | /** 179 | * Returns a string representing the current object. 180 | */ 181 | public function toString():String 182 | { 183 | return "[HashMap, size=" + size + "]"; 184 | } 185 | 186 | /** 187 | * Prints all elements (for debug/demo purposes only). 188 | */ 189 | public function dump():String 190 | { 191 | var s:String = "HashMap:\n"; 192 | for each (var i:* in _objMap) 193 | s += "[key: " + i + " val:" + _keyMap[i] + "]\n"; 194 | return s; 195 | } 196 | } 197 | } 198 | 199 | import de.polygonal.ds.Iterator; 200 | import de.polygonal.ds.HashMap; 201 | 202 | internal class HashMapValueIterator implements Iterator 203 | { 204 | private var _h:HashMap; 205 | private var _values:Array; 206 | private var _cursor:int; 207 | private var _size:int; 208 | 209 | public function HashMapValueIterator(h:HashMap) 210 | { 211 | _h = h; 212 | _values = h.toArray(); 213 | _cursor = 0; 214 | _size = _h.size; 215 | } 216 | 217 | public function get data():* 218 | { 219 | return _values[_cursor]; 220 | } 221 | 222 | public function set data(obj:*):void 223 | { 224 | var key:* = _h.findKey(_values[_cursor]); 225 | _h.remove(key); 226 | _h.insert(key, obj); 227 | } 228 | 229 | public function start():void 230 | { 231 | _cursor = 0; 232 | } 233 | 234 | public function hasNext():Boolean 235 | { 236 | return _cursor < _size; 237 | } 238 | 239 | public function next():* 240 | { 241 | return _values[_cursor++]; 242 | } 243 | } 244 | 245 | internal class HashMapKeyIterator implements Iterator 246 | { 247 | private var _h:HashMap; 248 | private var _keys:Array; 249 | private var _cursor:int; 250 | private var _size:int; 251 | 252 | public function HashMapKeyIterator(h:HashMap) 253 | { 254 | _h = h; 255 | _keys = h.getKeySet(); 256 | _cursor = 0; 257 | _size = _h.size; 258 | } 259 | 260 | public function get data():* 261 | { 262 | return _keys[_cursor]; 263 | } 264 | 265 | public function set data(obj:*):void 266 | { 267 | var key:* = _keys[_cursor]; 268 | var val:* = _h.find(key); 269 | _h.remove(key); 270 | _h.insert(obj, val); 271 | } 272 | 273 | public function start():void 274 | { 275 | _cursor = 0; 276 | } 277 | 278 | public function hasNext():Boolean 279 | { 280 | return _cursor < _size; 281 | } 282 | 283 | public function next():* 284 | { 285 | return _keys[_cursor++]; 286 | } 287 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/HashTable.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.Iterator; 12 | 13 | /** 14 | * A hash table using linked overflow for resolving collisions. 15 | */ 16 | public class HashTable 17 | { 18 | /** 19 | * A simple function for hashing strings. 20 | */ 21 | public static function hashString(s:String):int 22 | { 23 | var hash:int = 0, i:int, k:int = s.length; 24 | for (i = 0; i < k; i++) 25 | hash += (i + 1) * s.charCodeAt(i); 26 | return hash; 27 | } 28 | 29 | /** 30 | * A simple function for hashing integers. 31 | */ 32 | public static function hashInt(i:int):int 33 | { 34 | return hashString(i.toString()); 35 | } 36 | 37 | private var _table:Array; 38 | private var _hash:Function; 39 | 40 | private var _size:int; 41 | private var _divisor:int; 42 | private var _count:int; 43 | 44 | /** 45 | * Initializes a hash table. 46 | * 47 | * @param size The size of the hash table. 48 | * @param hash A hashing function. 49 | */ 50 | public function HashTable(size:int, hash:Function = null) 51 | { 52 | _count = 0; 53 | 54 | _hash = (hash == null) ? function(key:int):int { return key } : hash; 55 | _table = new Array(_size = size); 56 | 57 | for (var i:int = 0; i < size; i++) 58 | _table[i] = []; 59 | 60 | _divisor = _size - 1; 61 | } 62 | 63 | /** 64 | * Inserts a key/data couple into the table. 65 | * 66 | * @param key The key. 67 | * @param obj The data associated with the key. 68 | */ 69 | public function insert(key:*, obj:*):void 70 | { 71 | _table[int(_hash(key) & _divisor)].push(new HashEntry(key, obj)); 72 | _count++; 73 | } 74 | 75 | /** 76 | * Finds the entry that is associated with the given key. 77 | * 78 | * @param key The key to search for. 79 | * @return The data associated with the key or null if no matching 80 | * entry was found. 81 | */ 82 | public function find(key:*):* 83 | { 84 | var list:Array = _table[int(_hash(key) & _divisor)]; 85 | var k:int = list.length, entry:HashEntry; 86 | for (var i:int = 0; i < k; i++) 87 | { 88 | entry = list[i]; 89 | if (entry.key === key) 90 | return entry.data; 91 | } 92 | return null; 93 | } 94 | 95 | /** 96 | * Removes an entry based on a given key. 97 | * 98 | * @param key The entry's key. 99 | * @return The data associated with the key or null if no matching 100 | * entry was found. 101 | */ 102 | public function remove(key:*):* 103 | { 104 | var list:Array = _table[int(_hash(key) & _divisor)]; 105 | var k:int = list.length; 106 | for (var i:int = 0; i < k; i++) 107 | { 108 | var entry:HashEntry = list[i]; 109 | if (entry.key === key) 110 | { 111 | list.splice(i, 1); 112 | return entry.data; 113 | } 114 | } 115 | return null; 116 | } 117 | 118 | /** 119 | * Checks if a given item exists. 120 | * 121 | * @return True if item exists, otherwise false. 122 | */ 123 | public function contains(obj:*):Boolean 124 | { 125 | var list:Array, k:int = size; 126 | for (var i:int = 0; i < k; i++) 127 | { 128 | list = _table[i]; 129 | var l:int = list.length; 130 | 131 | for (var j:int = 0; j < l; j++) 132 | if (list[j].data === obj) return true; 133 | } 134 | return false; 135 | } 136 | 137 | /** 138 | * Iterator not supported (yet). 139 | */ 140 | public function getIterator():Iterator 141 | { 142 | return new NullIterator(); 143 | } 144 | 145 | /** 146 | * Clears all elements. 147 | */ 148 | public function clear():void 149 | { 150 | _table = new Array(_size); 151 | _count = 0; 152 | } 153 | 154 | /** 155 | * The total number of items. 156 | */ 157 | public function get size():int 158 | { 159 | return _count; 160 | } 161 | 162 | /** 163 | * The maximum allowed size of the queue. 164 | */ 165 | public function get maxSize():int 166 | { 167 | return _size; 168 | } 169 | 170 | /** 171 | * Converts the structure into an array. 172 | * 173 | * @return An array. 174 | */ 175 | public function toArray():Array 176 | { 177 | var a:Array = [], list:Array, k:int = size; 178 | for (var i:int = 0; i < k; i++) 179 | { 180 | list = _table[i]; 181 | var l:int = list.length; 182 | 183 | for (var j:int = 0; j < l; j++) 184 | a.push(list[j]); 185 | } 186 | return a; 187 | } 188 | 189 | /** 190 | * Returns a string representing the current object. 191 | */ 192 | public function toString():String 193 | { 194 | return "[HashTable, size=" + size + "]"; 195 | } 196 | 197 | public function print():String 198 | { 199 | var s:String = "HashTable:\n"; 200 | for (var i:int = 0; i < _size; i++) 201 | { 202 | if (_table[i]) 203 | s += "[" + i + "]" + "\n" + _table[i]; 204 | } 205 | return s; 206 | } 207 | } 208 | } 209 | 210 | /** 211 | * Simple container class for storing a key/data couple. 212 | */ 213 | internal class HashEntry 214 | { 215 | public var key:int; 216 | 217 | public var data:*; 218 | 219 | public function HashEntry(key:int, data:*) 220 | { 221 | this.key = key; 222 | this.data = data; 223 | } 224 | } 225 | 226 | 227 | -------------------------------------------------------------------------------- /src/de/polygonal/ds/Heap.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.Collection; 12 | import de.polygonal.ds.Iterator; 13 | 14 | /** 15 | * A heap. 16 | * 17 | *

A heap is a special kind of binary tree in which every node is 18 | * greater than all of its children. The implementation is based on an arrayed binary tree. 19 | * It can be used as an efficient priority queue.

20 | * @see PriorityQueue 21 | */ 22 | public class Heap implements Collection 23 | { 24 | public var _heap:Array; 25 | 26 | private var _size:int; 27 | private var _count:int; 28 | private var _compare:Function; 29 | 30 | /** 31 | * Initializes a new heap. 32 | */ 33 | public function Heap(size:int, compare:Function = null) 34 | { 35 | _heap = new Array(_size = size + 1); 36 | _count = 0; 37 | 38 | if (compare == null) 39 | { 40 | _compare = function(a:int, b:int):int 41 | { 42 | return a - b; 43 | } 44 | } 45 | else 46 | _compare = compare; 47 | } 48 | 49 | /** 50 | * The heap's front item. 51 | */ 52 | public function get front():* 53 | { 54 | return _heap[1]; 55 | } 56 | 57 | /** 58 | * Enqueues some data. 59 | * 60 | * @param obj The data. 61 | */ 62 | public function enqueue(obj:*):void 63 | { 64 | _heap[++_count] = obj; 65 | walkUp(_count); 66 | } 67 | 68 | /** 69 | * Dequeues the front item. 70 | */ 71 | public function dequeue():void 72 | { 73 | if (_count >= 1) 74 | { 75 | _heap[1] = _heap[_count]; 76 | delete _heap[_count]; 77 | 78 | walkDown(1); 79 | _count--; 80 | } 81 | } 82 | 83 | /** 84 | * Checks if a given item exists. 85 | * 86 | * @return True if the item is found, otherwise false. 87 | */ 88 | public function contains(obj:*):Boolean 89 | { 90 | for (var i:int = 1; i <= _count; i++) 91 | { 92 | if (_heap[i] === obj) 93 | return true; 94 | } 95 | return false; 96 | } 97 | 98 | /** 99 | * Clears all items. 100 | */ 101 | public function clear():void 102 | { 103 | _heap = new Array(_size); 104 | _count = 0; 105 | } 106 | 107 | /** 108 | * Returns an iterator object pointing to the front 109 | * item. 110 | * 111 | * @return An iterator object. 112 | */ 113 | public function getIterator():Iterator 114 | { 115 | return new HeapIterator(this); 116 | } 117 | 118 | /** 119 | * The total number of items in the heap. 120 | */ 121 | public function get size():int 122 | { 123 | return _count; 124 | } 125 | 126 | /** 127 | * Checks if the heap is empty. 128 | */ 129 | public function isEmpty():Boolean 130 | { 131 | return false; 132 | } 133 | 134 | /** 135 | * The maximum allowed size of the queue. 136 | */ 137 | public function get maxSize():int 138 | { 139 | return _size; 140 | } 141 | 142 | /** 143 | * Converts the heap into an array. 144 | * 145 | * @return An array containing all heap values. 146 | */ 147 | public function toArray():Array 148 | { 149 | return _heap.slice(1, _count); 150 | } 151 | 152 | private function walkUp(index:int):void 153 | { 154 | var parent:int = index >> 1; 155 | var tmp:* = _heap[index]; 156 | while (parent > 0) 157 | { 158 | if (_compare(tmp, _heap[parent]) > 0) 159 | { 160 | _heap[index] = _heap[parent]; 161 | index = parent; 162 | parent >>= 1; 163 | } 164 | else break; 165 | } 166 | _heap[index] = tmp; 167 | } 168 | 169 | private function walkDown(index:int):void 170 | { 171 | var child:int = index << 1; 172 | 173 | var tmp:* = _heap[index], c:*; 174 | 175 | while (child < _count) 176 | { 177 | if (child < _count - 1) 178 | { 179 | if (_compare(_heap[child], _heap[int(child + 1)]) < 0) 180 | child++; 181 | } 182 | if (_compare(tmp, _heap[child]) < 0) 183 | { 184 | _heap[index] = _heap[child]; 185 | index = child; 186 | child <<= 1; 187 | } 188 | else break; 189 | } 190 | _heap[index] = tmp; 191 | } 192 | } 193 | } 194 | 195 | import de.polygonal.ds.Iterator; 196 | import de.polygonal.ds.Heap; 197 | 198 | internal class HeapIterator implements Iterator 199 | { 200 | private var _values:Array; 201 | private var _length:int; 202 | private var _cursor:int; 203 | 204 | public function HeapIterator(heap:Heap) 205 | { 206 | _values = heap.toArray(); 207 | _length = _values.length; 208 | _cursor = 0; 209 | } 210 | 211 | public function get data():* 212 | { 213 | return _values[_cursor]; 214 | } 215 | 216 | public function set data(obj:*):void 217 | { 218 | _values[_cursor] = obj; 219 | } 220 | 221 | public function start():void 222 | { 223 | _cursor = 0; 224 | } 225 | 226 | public function hasNext():Boolean 227 | { 228 | return _cursor < _length; 229 | } 230 | 231 | public function next():* 232 | { 233 | return _values[_cursor++]; 234 | } 235 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/Iterator.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | /** 12 | * A 'java-style' iterator interface. 13 | */ 14 | public interface Iterator 15 | { 16 | /** 17 | * Retrieves the current item and moves 18 | * the iterator to the next item in the sequence. 19 | */ 20 | function next():* 21 | 22 | /** 23 | * Checks if the next item exists. 24 | * 25 | * @return True if a next item exists, otherwise false. 26 | */ 27 | function hasNext():Boolean 28 | 29 | /** 30 | * Moves the iterator to the first item 31 | * in the sequence. 32 | */ 33 | function start():void 34 | 35 | /** 36 | * Grants access to the current item being 37 | * referenced by the iterator. This provides 38 | * a quick way to read or write the current data. 39 | */ 40 | function get data():* 41 | function set data(obj:*):void 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/de/polygonal/ds/LinkedList.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | /** 12 | * A marker interface for the singly linked and doubly 13 | * linked list class. 14 | */ 15 | public interface LinkedList 16 | { 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/de/polygonal/ds/LinkedQueue.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.SLinkedList; 12 | 13 | /** 14 | * A linked queue. 15 | * 16 | *

A queue is a FIFO structure (First In, First Out).

17 | */ 18 | public class LinkedQueue 19 | { 20 | private var _list:SLinkedList; 21 | 22 | /** 23 | * Initializes an empty linked queue. 24 | * You can pass an existing singly linked list 25 | * to provide queue-like access. 26 | * 27 | * @param list An existing list to use as a queue. 28 | */ 29 | public function LinkedQueue(list:SLinkedList = null) 30 | { 31 | if (list == null) 32 | _list = new SLinkedList(); 33 | else 34 | _list = list; 35 | } 36 | 37 | /** 38 | * The total number of items in the queue. 39 | */ 40 | public function get size():int 41 | { 42 | return _list.size; 43 | } 44 | 45 | /** 46 | * Indicates the front item. 47 | * 48 | * @return The front item. 49 | */ 50 | public function peek():* 51 | { 52 | if (_list.size > 0) 53 | return _list.head.data; 54 | return null; 55 | } 56 | 57 | /** 58 | * Clears all elements. 59 | */ 60 | public function clear():void 61 | { 62 | _list.clear(); 63 | } 64 | 65 | /** 66 | * Enqueues some data. 67 | * 68 | * @param obj The data. 69 | */ 70 | public function enqueue(obj:*):void 71 | { 72 | _list.append(obj); 73 | } 74 | 75 | /** 76 | * Dequeues the front item. 77 | */ 78 | /** 79 | * Dequeues and returns the front item. 80 | * 81 | * @return The front item or null if the queue is empty. 82 | */ 83 | public function dequeue():* 84 | { 85 | if (_list.size > 0) 86 | { 87 | var front:* = _list.head.data; 88 | _list.removeHead(); 89 | return front; 90 | } 91 | return null; 92 | } 93 | 94 | /** 95 | * Returns a string representing the current object. 96 | */ 97 | public function toString():String 98 | { 99 | return "[LinkedQueue > " + _list + "]"; 100 | } 101 | 102 | /** 103 | * Prints out all elements in the queue (for debug/demo purposes). 104 | */ 105 | public function dump():String 106 | { 107 | return "LinkedQueue:\n" + _list.dump(); 108 | } 109 | } 110 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/LinkedStack.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.DLinkedList; 12 | 13 | /** 14 | * A linked stack. 15 | *

A stack is a LIFO structure (Last In, First Out)

. 16 | */ 17 | public class LinkedStack 18 | { 19 | private var _list:DLinkedList; 20 | 21 | /** 22 | * Initializes a linked stack. 23 | * You can pass an existing doubly linked list 24 | * to provide stack-like access. 25 | * 26 | * @param list An existing list to use as a stack. 27 | */ 28 | public function LinkedStack(list:DLinkedList = null) 29 | { 30 | if (list == null) 31 | _list = new DLinkedList(); 32 | else 33 | _list = list; 34 | } 35 | 36 | /** 37 | * The total number of items in the stack. 38 | */ 39 | public function get size():int 40 | { 41 | return _list.size; 42 | } 43 | 44 | /** 45 | * Indicates the top item. 46 | * 47 | * @return The top item. 48 | */ 49 | public function peek():* 50 | { 51 | if (_list.size > 0) 52 | return _list.tail.data; 53 | else 54 | return null; 55 | } 56 | 57 | /** 58 | * Pushes data onto the stack. 59 | * 60 | * @param obj The data to insert. 61 | */ 62 | public function push(obj:*):void 63 | { 64 | _list.append(obj); 65 | } 66 | 67 | /** 68 | * Pops data from the stack. 69 | * 70 | * @return The top item. 71 | */ 72 | public function pop():void 73 | { 74 | _list.removeTail(); 75 | } 76 | 77 | /** 78 | * Returns a string representing the current object. 79 | */ 80 | public function toString():String 81 | { 82 | return "[LinkedStack > " + _list + "]"; 83 | } 84 | 85 | /** 86 | * Prints out all elements in the stack (for debug/demo purposes). 87 | */ 88 | public function dump():String 89 | { 90 | return "LinkedStack:\n" + _list.dump(); 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/NullIterator.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.Iterator; 12 | 13 | /** 14 | * An do-nothing iterator for structures that don't support iterators. 15 | */ 16 | public class NullIterator implements Iterator 17 | { 18 | public function start():void 19 | { 20 | } 21 | 22 | public function next():* 23 | { 24 | return null; 25 | } 26 | 27 | public function hasNext():Boolean 28 | { 29 | return false; 30 | } 31 | 32 | public function get data():* 33 | { 34 | return null; 35 | } 36 | 37 | public function set data(obj:*):void 38 | { 39 | } 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/de/polygonal/ds/Prioritizable.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | /** 12 | * All objects you want to insert into a PriorityQueue have to extend this class. 13 | * 14 | *

I could have defined this as an interface, but this would 15 | * force me to write functions to just get or set the priority value.

16 | */ 17 | public class Prioritizable 18 | { 19 | public var priority:int; 20 | 21 | public function Prioritizable() 22 | { 23 | priority = -1; 24 | } 25 | 26 | public function toString():String 27 | { 28 | return "[Prioritizable, priority=" + priority + "]"; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/PriorityQueue.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import flash.utils.Dictionary; 12 | import de.polygonal.ds.Collection; 13 | 14 | /** 15 | * A priority queue. 16 | * 17 | *

The priority queue is based on the heap structure and 18 | * manages prioritized data.

19 | */ 20 | public class PriorityQueue implements Collection 21 | { 22 | private var _heap:Array; 23 | private var _size:int; 24 | private var _count:int; 25 | private var _posLookup:Dictionary; 26 | 27 | /** 28 | * Initializes a priority queue with a given size. 29 | * 30 | * @param size The size of the priority queue. 31 | */ 32 | public function PriorityQueue(size:int) 33 | { 34 | _heap = new Array(_size = size + 1); 35 | _posLookup = new Dictionary(true); 36 | _count = 0; 37 | } 38 | 39 | /** 40 | * The priority queue's front item. 41 | */ 42 | public function get front():Prioritizable 43 | { 44 | return _heap[1]; 45 | } 46 | 47 | /** 48 | * Enqueues a prioritized object. 49 | * 50 | * @param obj The prioritized data. 51 | */ 52 | public function enqueue(obj:Prioritizable):void 53 | { 54 | _count++; 55 | _heap[_count] = obj; 56 | _posLookup[obj] = _count; 57 | walkUp(_count); 58 | } 59 | 60 | /** 61 | * Dequeues the front item, which is the item 62 | * with the highest priority. 63 | */ 64 | public function dequeue():void 65 | { 66 | if (_count >= 1) 67 | { 68 | delete _posLookup[_heap[1]]; 69 | 70 | _heap[1] = _heap[_count]; 71 | walkDown(1); 72 | delete _heap[_count]; 73 | _count--; 74 | } 75 | } 76 | 77 | /** 78 | * Reprioritizes an item. 79 | * 80 | * @param obj The object whose priority is changed. 81 | * @param newPriority The new priority. 82 | * @return True if the repriorization succeeded, otherwise false. 83 | */ 84 | public function reprioritize(obj:Prioritizable, newPriority:int):Boolean 85 | { 86 | if (!_posLookup[obj]) return false; 87 | 88 | var oldPriority:int = obj.priority; 89 | 90 | //App.tr("old priority=", obj.priority); 91 | 92 | obj.priority = newPriority; 93 | 94 | //App.tr("new priority=", obj.priority); 95 | 96 | var pos:int = _posLookup[obj]; 97 | 98 | //App.tr("current pos=", pos); 99 | 100 | //App.tr("now ", newPriority > p ? "Walkup" : "WalkDown"); 101 | 102 | newPriority > oldPriority ? walkUp(pos) : walkDown(pos); 103 | 104 | return true; 105 | } 106 | 107 | /** 108 | * Removes an item. 109 | * 110 | * @param obj The object to remove. 111 | * @return True if removal succeeded, otherwise false. 112 | */ 113 | public function remove(obj:Prioritizable):Boolean 114 | { 115 | if (!_posLookup[obj]) return false; 116 | 117 | var pos:int = _posLookup[obj]; 118 | delete _posLookup[obj]; 119 | 120 | _heap[pos] = _heap[_count]; 121 | delete _heap[_count]; 122 | 123 | walkDown(pos); 124 | _count--; 125 | 126 | return true; 127 | } 128 | 129 | /** 130 | * Checks if a given item exists. 131 | * 132 | * @return True if the item is found, otherwise false. 133 | */ 134 | public function contains(obj:*):Boolean 135 | { 136 | for (var i:int = 1; i <= _count; i++) 137 | { 138 | if (_heap[i] === obj) 139 | return true; 140 | } 141 | return false; 142 | } 143 | 144 | /** 145 | * Clears all items. 146 | */ 147 | public function clear():void 148 | { 149 | _heap = new Array(_size); 150 | _posLookup = new Dictionary(true); 151 | _count = 0; 152 | } 153 | 154 | /** 155 | * Returns an iterator object pointing to the front 156 | * item. 157 | * 158 | * @return An iterator object. 159 | */ 160 | public function getIterator():Iterator 161 | { 162 | return new PriorityQueueIterator(this); 163 | } 164 | 165 | /** 166 | * The total number of items in the priority queue. 167 | */ 168 | public function get size():int 169 | { 170 | return _count; 171 | } 172 | 173 | /** 174 | * Checks if the priority queue is empty. 175 | */ 176 | public function isEmpty():Boolean 177 | { 178 | return false; 179 | } 180 | 181 | /** 182 | * The maximum allowed size of the queue. 183 | */ 184 | public function get maxSize():int 185 | { 186 | return _size; 187 | } 188 | 189 | /** 190 | * Converts the priority queue into an array. 191 | * 192 | * @return An array containing all values. 193 | */ 194 | public function toArray():Array 195 | { 196 | return _heap.slice(1, _count); 197 | } 198 | 199 | private function walkUp(index:int):void 200 | { 201 | var parent:int = index >> 1; 202 | var parentObj:Prioritizable; 203 | 204 | var tmp:Prioritizable = _heap[index]; 205 | var p:int = tmp.priority; 206 | 207 | while (parent > 0) 208 | { 209 | parentObj = _heap[parent]; 210 | 211 | if (p - parentObj.priority > 0) 212 | { 213 | _heap[index] = parentObj; 214 | _posLookup[parentObj] = index; 215 | 216 | index = parent; 217 | parent >>= 1; 218 | } 219 | else break; 220 | } 221 | 222 | _heap[index] = tmp; 223 | _posLookup[tmp] = index; 224 | } 225 | 226 | private function walkDown(index:int):void 227 | { 228 | var child:int = index << 1; 229 | var childObj:Prioritizable; 230 | 231 | var tmp:Prioritizable = _heap[index]; 232 | var p:int = tmp.priority; 233 | 234 | while (child < _count) 235 | { 236 | if (child < _count - 1) 237 | { 238 | if (_heap[child].priority - _heap[int(child + 1)].priority < 0) 239 | child++; 240 | } 241 | 242 | childObj = _heap[child]; 243 | 244 | if (p - childObj.priority < 0) 245 | { 246 | _heap[index] = childObj; 247 | _posLookup[childObj] = child; 248 | 249 | index = child; 250 | child <<= 1; 251 | } 252 | else break; 253 | } 254 | _heap[index] = tmp; 255 | _posLookup[tmp] = index; 256 | } 257 | } 258 | } 259 | 260 | import de.polygonal.ds.Iterator; 261 | import de.polygonal.ds.PriorityQueue; 262 | 263 | internal class PriorityQueueIterator implements Iterator 264 | { 265 | private var _values:Array; 266 | private var _length:int; 267 | private var _cursor:int; 268 | 269 | public function PriorityQueueIterator(pq:PriorityQueue) 270 | { 271 | _values = pq.toArray(); 272 | _length = _values.length; 273 | _cursor = 0; 274 | } 275 | 276 | public function get data():* 277 | { 278 | return _values[_cursor]; 279 | } 280 | 281 | public function set data(obj:*):void 282 | { 283 | _values[_cursor] = obj; 284 | } 285 | 286 | public function start():void 287 | { 288 | _cursor = 0; 289 | } 290 | 291 | public function hasNext():Boolean 292 | { 293 | return _cursor < _length; 294 | } 295 | 296 | public function next():* 297 | { 298 | return _values[_cursor++]; 299 | } 300 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/SLinkedList.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.Collection; 12 | import de.polygonal.ds.Iterator; 13 | import de.polygonal.ds.SListNode; 14 | import de.polygonal.ds.SListIterator; 15 | 16 | /** 17 | * A singly linked list. 18 | */ 19 | public class SLinkedList implements Collection 20 | { 21 | private var _count:int; 22 | 23 | /** 24 | * The head node being referenced. 25 | */ 26 | public var head:SListNode; 27 | 28 | /** 29 | * The tail node being referenced. 30 | */ 31 | public var tail:SListNode; 32 | 33 | /** 34 | * Initializes an empty list. 35 | */ 36 | public function SLinkedList() 37 | { 38 | head = tail = null; 39 | _count = 0; 40 | } 41 | 42 | /** 43 | * Appends an item to the list. 44 | * 45 | * @param obj The data. 46 | * @return A singly linked list node wrapping the data. 47 | */ 48 | public function append(obj:*):SListNode 49 | { 50 | var node:SListNode = new SListNode(obj); 51 | if (head) 52 | { 53 | tail.next = node; 54 | tail = node; 55 | } 56 | else 57 | head = tail = node; 58 | 59 | _count++; 60 | return node; 61 | } 62 | 63 | /** 64 | * Prepends an item to the list. 65 | * 66 | * @param obj The data. 67 | * @return A singly linked list node wrapping the data. 68 | */ 69 | public function prepend(obj:*):SListNode 70 | { 71 | var node:SListNode = new SListNode(obj); 72 | 73 | if (head) 74 | { 75 | node.next = head; 76 | head = node; 77 | } 78 | else 79 | head = tail = node; 80 | 81 | _count++; 82 | return node; 83 | } 84 | 85 | /** 86 | * Inserts data after a given iterator or appends it 87 | * if the iterator is invalid. 88 | * 89 | * @param itr A singly linked list iterator. 90 | * @param obj The data. 91 | * @return A singly linked list node wrapping the data. 92 | */ 93 | public function insertAfter(itr:SListIterator, obj:*):SListNode 94 | { 95 | if (itr.list != this) return null; 96 | if (itr.node) 97 | { 98 | var node:SListNode = new SListNode(obj); 99 | itr.node.insertAfter(node); 100 | if (itr.node == tail) 101 | tail = itr.node.next; 102 | 103 | _count++; 104 | return node; 105 | } 106 | else 107 | return append(obj); 108 | } 109 | 110 | /** 111 | * Removes the node the iterator is pointing 112 | * to and move the iterator to the next node. 113 | * 114 | * @return True if the removal succeeded, otherwise false. 115 | */ 116 | public function remove(itr:SListIterator):Boolean 117 | { 118 | if (itr.list != this || !itr.node) return false; 119 | 120 | var node:SListNode = head; 121 | if (itr.node == head) 122 | { 123 | itr.forth(); 124 | removeHead(); 125 | } 126 | else 127 | { 128 | while (node.next != itr.node) node = node.next; 129 | itr.forth(); 130 | if (node.next == tail) tail = node; 131 | node.next = itr.node; 132 | } 133 | _count--; 134 | return true; 135 | } 136 | 137 | /** 138 | * Removes the head of the list. 139 | */ 140 | public function removeHead():void 141 | { 142 | if (!head) return; 143 | 144 | if (head == tail) 145 | head = tail = null; 146 | else 147 | { 148 | var node:SListNode = head; 149 | 150 | head = head.next; 151 | node.next = null; 152 | if (head == null) tail = null; 153 | } 154 | _count--; 155 | } 156 | 157 | /** 158 | * Removes the tail of the list. 159 | */ 160 | public function removeTail():void 161 | { 162 | if (!tail) return; 163 | 164 | if (head == tail) 165 | head = tail = null; 166 | else 167 | { 168 | var node:SListNode = head; 169 | while (node.next != tail) 170 | node = node.next; 171 | 172 | tail = node; 173 | node.next = null; 174 | } 175 | _count--; 176 | } 177 | 178 | /** 179 | * Checks if a given item exists. 180 | * 181 | * @return True if the item is found, otherwise false. 182 | */ 183 | public function contains(obj:*):Boolean 184 | { 185 | var node:SListNode = head; 186 | while (node) 187 | { 188 | if (node.data == obj) return true; 189 | node = node.next; 190 | } 191 | return false; 192 | } 193 | 194 | /** 195 | * Clears the list by unlinking all nodes 196 | * from it. This is important to unlock 197 | * the nodes for the garbage collector. 198 | */ 199 | public function clear():void 200 | { 201 | var node:SListNode = head; 202 | head = null; 203 | 204 | var next:SListNode; 205 | while (node) 206 | { 207 | next = node.next; 208 | node.next = null; 209 | node = next; 210 | } 211 | _count = 0; 212 | } 213 | 214 | /** 215 | * Creates an iterator pointing 216 | * to the first node in the list. 217 | * 218 | * @returns An iterator object. 219 | */ 220 | public function getIterator():Iterator 221 | { 222 | return new SListIterator(this, head); 223 | } 224 | 225 | /** 226 | * Creates a list iterator pointing 227 | * to the first node in the list. 228 | * 229 | * @returns A SListIterator object. 230 | */ 231 | public function getListIterator():SListIterator 232 | { 233 | return new SListIterator(this, head); 234 | } 235 | 236 | /** 237 | * The total number of nodes in the list. 238 | */ 239 | public function get size():int 240 | { 241 | return _count; 242 | } 243 | 244 | /** 245 | * Checks if the list is empty. 246 | */ 247 | public function isEmpty():Boolean 248 | { 249 | return _count == 0; 250 | } 251 | 252 | /** 253 | * Converts the linked list into an array. 254 | * 255 | * @return An array. 256 | */ 257 | public function toArray():Array 258 | { 259 | var a:Array = []; 260 | var node:SListNode = head; 261 | while (node) 262 | { 263 | a.push(node.data); 264 | node = node.next; 265 | } 266 | return a; 267 | } 268 | 269 | /** 270 | * Returns a string representing the current object. 271 | */ 272 | public function toString():String 273 | { 274 | return "[SlinkedList, size=" + size + "]"; 275 | } 276 | 277 | /** 278 | * Prints out all elements in the list (for debug/demo purposes). 279 | */ 280 | public function dump():String 281 | { 282 | if (!head) 283 | return "SLinkedList: (empty)"; 284 | 285 | var s:String = "SLinkedList: (has " + _count + " node" + (_count == 1 ? ")" : "s") + "\n|< Head\n"; 286 | 287 | var itr:SListIterator = getListIterator(); 288 | for (; itr.valid(); itr.forth()) 289 | s += "\t" + itr.data + "\n"; 290 | 291 | s += "Tail >|"; 292 | 293 | return s; 294 | } 295 | } 296 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/SListIterator.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.SListNode; 12 | import de.polygonal.ds.SLinkedList; 13 | 14 | /** 15 | * A singly linked list iterator. 16 | */ 17 | public class SListIterator implements Iterator 18 | { 19 | /** 20 | * The node the iterator is pointing. 21 | */ 22 | public var node:SListNode; 23 | 24 | /** 25 | * The list of the iterator is referenced. 26 | */ 27 | public var list:SLinkedList; 28 | 29 | /** 30 | * Initializes a new SListIterator instance pointing to a given node. 31 | * Usually created by invoking SLinkedList.getIterator(). 32 | * 33 | * @param list The linked list the iterator should use. 34 | * @param node The iterator's initial node. 35 | */ 36 | public function SListIterator(list:SLinkedList = null, node:SListNode = null) 37 | { 38 | this.list = list; 39 | this.node = node; 40 | } 41 | 42 | /** 43 | * Returns the current node's data while 44 | * moving the iterator forward by one position. 45 | */ 46 | public function next():* 47 | { 48 | if (hasNext()) 49 | { 50 | var obj:* = node.data; 51 | node = node.next; 52 | return obj; 53 | } 54 | return null 55 | } 56 | 57 | /** 58 | * Checks if a next node exists. 59 | */ 60 | public function hasNext():Boolean 61 | { 62 | return Boolean(node); 63 | } 64 | 65 | /** 66 | * Read/writes the current node's data. 67 | * 68 | * @return The data. 69 | */ 70 | public function get data():* 71 | { 72 | if (node) return node.data; 73 | return null; 74 | } 75 | 76 | public function set data(obj:*):void 77 | { 78 | node.data = obj; 79 | } 80 | 81 | 82 | /** 83 | * Moves the iterator to the start of the list. 84 | */ 85 | public function start():void 86 | { 87 | if (list) node = list.head; 88 | } 89 | 90 | /** 91 | * Moves the iterator to the end of the list. 92 | */ 93 | public function end():void 94 | { 95 | if (list) node = list.tail; 96 | } 97 | 98 | /** 99 | * Moves the iterator to the next node. 100 | */ 101 | public function forth():void 102 | { 103 | if (node) node = node.next; 104 | } 105 | 106 | /** 107 | * Checks if the current referenced node is valid. 108 | * 109 | * @return True if the node exists, otherwise false. 110 | */ 111 | public function valid():Boolean 112 | { 113 | return Boolean(node); 114 | } 115 | 116 | /** 117 | * Removes the node the iterator is 118 | * pointing to. 119 | */ 120 | public function remove():void 121 | { 122 | list.remove(this); 123 | } 124 | 125 | /** 126 | * Returns a string representing the current object. 127 | */ 128 | public function toString():String 129 | { 130 | return "{SListIterator: data=" + node.data + "}"; 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/SListNode.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | /** 12 | * A singly linked list node. 13 | * 14 | * The node acts as a data container and also 15 | * holds a reference to next node in the list. 16 | */ 17 | public class SListNode 18 | { 19 | /** 20 | * The node's data. 21 | */ 22 | public var data:*; 23 | 24 | /** 25 | * The next node in the list being referenced. 26 | */ 27 | public var next:SListNode; 28 | 29 | /** 30 | * Initializes a new node that stores 31 | * the given item. 32 | * 33 | * @param obj The data to store in the node. 34 | */ 35 | public function SListNode(obj:*) 36 | { 37 | data = obj; 38 | next = null; 39 | } 40 | 41 | /** 42 | * A helper function used solely by the SLinkedList class 43 | * for node insertion. 44 | * 45 | * @param node The node after which this node is inserted. 46 | */ 47 | public function insertAfter(node:SListNode):void 48 | { 49 | node.next = next; 50 | next = node; 51 | } 52 | 53 | /** 54 | * Returns a string representing the current object. 55 | */ 56 | public function toString():String 57 | { 58 | return "[SListNode, data=" + data + "]"; 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /src/de/polygonal/ds/TreeNode.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Michael Baczynski 2007 3 | * http://lab.polygonal.de/ds/ 4 | * 5 | * This software is distributed under licence. Use of this software 6 | * implies agreement with all terms and conditions of the accompanying 7 | * software licence. 8 | */ 9 | package de.polygonal.ds 10 | { 11 | import de.polygonal.ds.Iterator; 12 | import de.polygonal.ds.Collection; 13 | 14 | import de.polygonal.ds.TreeNode; 15 | import de.polygonal.ds.TreeIterator; 16 | 17 | import de.polygonal.ds.DListNode; 18 | import de.polygonal.ds.DLinkedList; 19 | 20 | /** 21 | * A tree node. 22 | * 23 | *

A tree only consists of TreeNode objects - there is no class that manages a tree structure. 24 | * Every tree node has a linked list of child nodes and a pointer to its parent node.

25 | */ 26 | public class TreeNode implements Collection 27 | { 28 | /** 29 | * The parent node being referenced. 30 | */ 31 | public var parent:TreeNode; 32 | 33 | /** 34 | * A list of child nodes being referenced. 35 | */ 36 | public var children:DLinkedList; 37 | 38 | /** 39 | * The data being referened. 40 | */ 41 | public var data:*; 42 | 43 | /** 44 | * Initializes a tree node. 45 | * 46 | * @param obj The data to store. 47 | * @param parent The node's parent node. 48 | */ 49 | public function TreeNode(obj:* = null, parent:TreeNode = null) 50 | { 51 | data = obj; 52 | children = new DLinkedList(); 53 | 54 | if (parent) 55 | { 56 | this.parent = parent; 57 | parent.children.append(this); 58 | } 59 | } 60 | 61 | /** 62 | * Counts the total number of tree nodes 63 | * starting from the current tree node. 64 | */ 65 | public function get size():int 66 | { 67 | var c:int = 1; 68 | var node:DListNode = children.head; 69 | while (node) 70 | { 71 | c += node.data.size; 72 | node = node.next; 73 | } 74 | return c; 75 | } 76 | 77 | /** 78 | * Checks is the tree node is empty (has no children). 79 | */ 80 | public function isEmpty():Boolean 81 | { 82 | return children.size == 0; 83 | } 84 | 85 | /** 86 | * Computes the depth of the tree, 87 | * starting from this node. 88 | */ 89 | public function get depth():int 90 | { 91 | if (!parent) return 0; 92 | 93 | var node:TreeNode = this, c:int = 0; 94 | while (node.parent) 95 | { 96 | c++; 97 | node = node.parent; 98 | } 99 | return c; 100 | } 101 | 102 | /** 103 | * The total number of childrens. 104 | */ 105 | public function get numChildrens():int 106 | { 107 | return children.size; 108 | } 109 | 110 | /** 111 | * The total number of siblings. 112 | */ 113 | public function get numSiblings():int 114 | { 115 | if (parent) 116 | return parent.children.size; 117 | return 0; 118 | } 119 | 120 | /** 121 | * Recursively removes every child node from this node. 122 | * This is important for unlocking the nodes for 123 | * the garbage collector. 124 | */ 125 | public function destroy():void 126 | { 127 | while (children.head) 128 | { 129 | var node:TreeNode = children.head.data; 130 | children.removeHead(); 131 | node.destroy(); 132 | } 133 | } 134 | 135 | /** 136 | * Checks if a given item exists. 137 | * 138 | * @return True if the item is found, otherwise false. 139 | */ 140 | public function contains(obj:*):Boolean 141 | { 142 | var found:Boolean = false; 143 | TreeIterator.preorder(this, function(node:TreeNode):void 144 | { 145 | if (obj == node.data) 146 | found = true; 147 | }); 148 | return found; 149 | } 150 | 151 | /** 152 | * Clears the tree by unlinking 153 | * all child nodes from the node on which 154 | * the method is called. 155 | */ 156 | public function clear():void 157 | { 158 | destroy(); 159 | } 160 | 161 | /** 162 | * Creates an iterator object pointing to the 163 | * node the method is called on. 164 | */ 165 | public function getIterator():Iterator 166 | { 167 | return new TreeIterator(this); 168 | } 169 | 170 | /** 171 | * Creates a tree iterator object pointing 172 | * at the node on which the method is called. 173 | * 174 | * @returns A TreeIterator object. 175 | */ 176 | public function getTreeIterator():TreeIterator 177 | { 178 | return new TreeIterator(this); 179 | } 180 | 181 | /** 182 | * Converts the tree into an array. 183 | * 184 | * @return An array. 185 | */ 186 | public function toArray():Array 187 | { 188 | var a:Array = []; 189 | TreeIterator.preorder(this, function(node:TreeNode):void 190 | { 191 | a.push(node.data); 192 | }); 193 | return a; 194 | } 195 | 196 | 197 | 198 | /** 199 | * Returns a string representing the current object. 200 | */ 201 | public function toString():String 202 | { 203 | var s:String = "[TreeNode > " + (parent == null ? "(root)" : ""); 204 | 205 | if (children.size == 0) 206 | s += "(leaf)"; 207 | else 208 | s += " has " + children.size + " child node" + (size > 1 || size == 0 ? "s" : ""); 209 | 210 | s += ", data=" + data + "]"; 211 | 212 | return s; 213 | } 214 | 215 | /** 216 | * Prints out all children recursively starting from the current node. 217 | */ 218 | public function dump():String 219 | { 220 | var s:String = ""; 221 | TreeIterator.preorder(this, function(node:TreeNode):void 222 | { 223 | var d:int = node.depth; 224 | 225 | for (var i:int = 0; i < d; i++) 226 | { 227 | if (i == d - 1) 228 | s += "+---"; 229 | else 230 | s += "| "; 231 | } 232 | s += node + "\n"; 233 | }); 234 | return s; 235 | } 236 | } 237 | } -------------------------------------------------------------------------------- /src/drumkitclass.as: -------------------------------------------------------------------------------- 1 | package { 2 | import flash.display.*; 3 | import flash.geom.*; 4 | import flash.events.*; 5 | import flash.net.*; 6 | import org.si.sion.SiONVoice; 7 | 8 | public class drumkitclass { 9 | public function drumkitclass():void { 10 | size = 0; 11 | } 12 | 13 | public function updatefilter(cutoff:int, resonance:int):void { 14 | for (var i:int = 0; i < size; i++) { 15 | if(voicelist[i].channelParam.cutoff != cutoff || voicelist[i].channelParam.resonance != resonance){ 16 | voicelist[i].setFilterEnvelop(0, cutoff, resonance); 17 | } 18 | } 19 | } 20 | 21 | public function updatevolume(volume:int):void { 22 | for (var i:int = 0; i < size; i++) { 23 | if(voicelist[i].velocity!=volume){ 24 | voicelist[i].updateVolumes = true; 25 | voicelist[i].velocity = volume; 26 | } 27 | } 28 | } 29 | 30 | public var voicelist:Vector. = new Vector.; 31 | public var voicename:Vector. = new Vector.; 32 | public var voicenote:Vector. = new Vector.; 33 | public var midivoice:Vector. = new Vector.; 34 | public var kitname:String; 35 | public var size:int; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/graphics/font.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/src/graphics/font.swf -------------------------------------------------------------------------------- /src/graphics/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/src/graphics/icons.png -------------------------------------------------------------------------------- /src/graphics/logo_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/src/graphics/logo_blue.png -------------------------------------------------------------------------------- /src/graphics/logo_cyan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/src/graphics/logo_cyan.png -------------------------------------------------------------------------------- /src/graphics/logo_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/src/graphics/logo_gray.png -------------------------------------------------------------------------------- /src/graphics/logo_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/src/graphics/logo_green.png -------------------------------------------------------------------------------- /src/graphics/logo_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/src/graphics/logo_orange.png -------------------------------------------------------------------------------- /src/graphics/logo_purple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/src/graphics/logo_purple.png -------------------------------------------------------------------------------- /src/graphics/logo_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/src/graphics/logo_red.png -------------------------------------------------------------------------------- /src/graphics/logo_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/src/graphics/logo_shadow.png -------------------------------------------------------------------------------- /src/graphics/tutorial_drag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/src/graphics/tutorial_drag.png -------------------------------------------------------------------------------- /src/graphics/tutorial_longnote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/src/graphics/tutorial_longnote.png -------------------------------------------------------------------------------- /src/graphics/tutorial_patterndrag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/src/graphics/tutorial_patterndrag.png -------------------------------------------------------------------------------- /src/graphics/tutorial_secret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/src/graphics/tutorial_secret.png -------------------------------------------------------------------------------- /src/graphics/tutorial_timelinedrag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/src/graphics/tutorial_timelinedrag.png -------------------------------------------------------------------------------- /src/guibutton.as: -------------------------------------------------------------------------------- 1 | package { 2 | import flash.geom.*; 3 | 4 | public class guibutton { 5 | public function guibutton() { 6 | position = new Rectangle(0, 0, 0, 0); 7 | selected = false; 8 | active = false; 9 | visable = false; 10 | mouseover = false; 11 | } 12 | 13 | public function init(x:int, y:int, w:int, h:int, contents:String, act:String = "", sty:String = "normal"):void { 14 | position.setTo(x, y, w, h); 15 | text = contents; 16 | action = act; 17 | style = sty; 18 | 19 | selected = false; 20 | moveable = false; 21 | visable = true; 22 | active = true; 23 | onwindow = false; 24 | textoffset = 0; 25 | pressed = 0; 26 | } 27 | 28 | public function press():void { 29 | pressed = 6; 30 | } 31 | 32 | public var position:Rectangle; 33 | public var text:String; 34 | public var action:String; 35 | public var style:String; 36 | 37 | public var visable:Boolean; 38 | public var mouseover:Boolean; 39 | public var selected:Boolean; 40 | public var active:Boolean; 41 | public var moveable:Boolean; 42 | public var onwindow:Boolean; 43 | 44 | public var pressed:int; 45 | public var textoffset:int; 46 | } 47 | } -------------------------------------------------------------------------------- /src/help.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.display.*; 4 | import flash.geom.*; 5 | import flash.events.*; 6 | import flash.net.*; 7 | 8 | public class help 9 | { 10 | public static function init():void 11 | { 12 | glow = 0; 13 | glowdir = 0; 14 | slowsine = 0; 15 | } 16 | 17 | public function RGB(red:Number, green:Number, blue:Number):Number 18 | { 19 | return (blue | (green << 8) | (red << 16)) 20 | } 21 | 22 | public static function removeObject(obj:Object, arr:Array):void 23 | { 24 | var i:String; 25 | for (i in arr) 26 | { 27 | if (arr[i] == obj) 28 | { 29 | arr.splice(i, 1) 30 | break; 31 | } 32 | } 33 | } 34 | 35 | public static function updateglow():void 36 | { 37 | slowsine += 2; 38 | if (slowsine >= 64) slowsine = 0; 39 | 40 | if (glowdir == 0) 41 | { 42 | glow += 2; 43 | if (glow >= 63) glowdir = 1; 44 | } 45 | else 46 | { 47 | glow -= 2; 48 | if (glow < 1) glowdir = 0; 49 | } 50 | } 51 | 52 | public static function inbox(xc:int, yc:int, x1:int, y1:int, x2:int, y2:int):Boolean 53 | { 54 | if (xc >= x1 && xc <= x2) 55 | { 56 | if (yc >= y1 && yc <= y2) 57 | { 58 | return true; 59 | } 60 | } 61 | return false; 62 | } 63 | 64 | public static function inboxw(xc:int, yc:int, x1:int, y1:int, x2:int, y2:int):Boolean 65 | { 66 | if (xc >= x1 && xc <= x1 + x2) 67 | { 68 | if (yc >= y1 && yc <= y1 + y2) 69 | { 70 | return true; 71 | } 72 | } 73 | return false; 74 | } 75 | 76 | public static function Instr(s:String, c:String, start:int = 1):int 77 | { 78 | return (s.indexOf(c, start - 1) + 1); 79 | } 80 | 81 | public static function Mid(s:String, start:int = 0, length:int = 1):String 82 | { 83 | return s.substr(start, length); 84 | } 85 | 86 | public static function Left(s:String, length:int = 1):String 87 | { 88 | return s.substr(0, length); 89 | } 90 | 91 | public static function Right(s:String, length:int = 1):String 92 | { 93 | return s.substr(s.length - length, length); 94 | } 95 | 96 | public static var glow:int, slowsine:int; 97 | public static var glowdir:int; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/includes/logic.as: -------------------------------------------------------------------------------- 1 | public function logic(key:KeyPoll):void { 2 | var i:int, j:int, k:int; 3 | 4 | if (control.arrangescrolldelay > 0) { 5 | control.arrangescrolldelay--; 6 | } 7 | 8 | if (control.messagedelay > 0) { 9 | control.messagedelay -= 2; 10 | if (control.messagedelay < 0) control.messagedelay = 0; 11 | } 12 | if (control.doubleclickcheck > 0) { 13 | control.doubleclickcheck -= 2; 14 | if (control.doubleclickcheck < 0) control.doubleclickcheck = 0; 15 | } 16 | if (gfx.buttonpress > 0) { 17 | gfx.buttonpress -= 2; 18 | if (gfx.buttonpress < 0) gfx.buttonpress = 0; 19 | } 20 | 21 | if (control.minresizecountdown > 0) { 22 | control.minresizecountdown -= 2; 23 | if (control.minresizecountdown <= 0) { 24 | control.minresizecountdown = 0; 25 | gfx.forceminimumsize(); 26 | } 27 | } 28 | 29 | if (control.savescreencountdown > 0) { 30 | control.savescreencountdown -= 2; 31 | if (control.savescreencountdown <= 0) { 32 | control.savescreencountdown = 0; 33 | control.savescreensettings(); 34 | } 35 | } 36 | 37 | if (control.dragaction == 2) { 38 | control.trashbutton+=2; 39 | if (control.trashbutton > 10) control.trashbutton = 10; 40 | }else { 41 | if (control.trashbutton > 0) control.trashbutton--; 42 | } 43 | 44 | if (control.followmode) { 45 | if (control.arrange.currentbar < control.arrange.viewstart) { 46 | control.arrange.viewstart = control.arrange.currentbar; 47 | } 48 | if (control.arrange.currentbar > control.arrange.viewstart+5) { 49 | control.arrange.viewstart = control.arrange.currentbar; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/includes/render.as: -------------------------------------------------------------------------------- 1 | public function render(key:KeyPoll):void { 2 | var i:int, j:int, k:int; 3 | 4 | if (gfx.updatebackground > 0) { 5 | gfx.changeframerate(30); 6 | //Background 7 | gfx.fillrect(0, 0, gfx.screenwidth, gfx.screenheight, 1); 8 | 9 | //Tabs 10 | CONFIG::desktop { 11 | j = (gfx.screenwidth - 40) / 4; 12 | } 13 | CONFIG::web { 14 | j = (gfx.screenwidth) / 4; 15 | } 16 | if (control.currenttab == control.MENUTAB_HELP) { 17 | gfx.fillrect(0, 0, j, gfx.linesize, 5); 18 | gfx.print(14, 0, "HELP", control.currenttab == control.MENUTAB_HELP?0:2, false, true); 19 | }else if (control.currenttab == control.MENUTAB_CREDITS || control.currenttab == control.MENUTAB_GITHUB) { 20 | gfx.fillrect(0, 0, j, gfx.linesize, 5); 21 | gfx.print(14, 0, "CREDITS", (control.currenttab == control.MENUTAB_CREDITS || control.currenttab == control.MENUTAB_GITHUB)?0:2, false, true); 22 | }else{ 23 | gfx.fillrect(control.currenttab * j, 0, j, gfx.linesize, 5); 24 | gfx.print(14, 0, "FILE", control.currenttab == control.MENUTAB_FILE?0:2, false, true); 25 | } 26 | gfx.print(j + 14, 0, "ARRANGEMENT", control.currenttab==control.MENUTAB_ARRANGEMENTS?0:2, false, true); 27 | gfx.print((j * 2) + 14, 0, "INSTRUMENT", control.currenttab == control.MENUTAB_INSTRUMENTS?0:2, false, true); 28 | gfx.print((j * 3) + 14, 0, "ADVANCED", control.currenttab == control.MENUTAB_ADVANCED?0:2, false, true); 29 | CONFIG::desktop { 30 | gfx.fillrect((j * 4), 0, 42, 20, 3); 31 | gfx.drawicon((j * 4) + 12, 1, control.fullscreen?5:4); 32 | } 33 | 34 | if (control.nowexporting) { 35 | gfx.updatebackground = 5; 36 | gfx.fillrect(0, gfx.pianorollposition + gfx.linesize, gfx.screenwidth, gfx.screenheight - (gfx.pianorollposition + gfx.linesize), 14); 37 | if (control.arrange.currentbar % 2 == 0) { 38 | guiclass.tx = int(gfx.screenwidth / 64) + 1; 39 | for (i = -1; i < guiclass.tx; i++) { 40 | gfx.fillrect((i * 64) + help.slowsine, gfx.pianorollposition + gfx.linesize, 32, gfx.screenheight - (gfx.pianorollposition + gfx.linesize), 1); 41 | } 42 | }else { 43 | guiclass.tx = int(gfx.screenheight - (gfx.pianorollposition + gfx.linesize) / 64) + 1; 44 | for (i = 0; i < guiclass.tx; i++) { 45 | gfx.fillrect(0, gfx.pianorollposition + gfx.linesize + (i * 64) + help.slowsine, gfx.screenwidth, 32, 1); 46 | } 47 | if (help.slowsine >= 32) { 48 | gfx.fillrect(0, gfx.pianorollposition + gfx.linesize, gfx.screenwidth, help.slowsine-32, 1); 49 | } 50 | } 51 | if (help.slowsine < 32) { 52 | gfx.print(gfx.screenwidthmid - (gfx.len("NOW EXPORTING AS WAV, PLEASE WAIT") / 2), (gfx.pianorollposition + gfx.linesize)+ (gfx.screenheight - gfx.hig("WAV") - (gfx.pianorollposition + gfx.linesize))/2, "NOW EXPORTING AS WAV, PLEASE WAIT", 0, false, true); 53 | } 54 | }else if(control.currentbox>-1){ 55 | gfx.drawpatterneditor(); 56 | }else { 57 | gfx.fillrect(0, gfx.pianorollposition + gfx.linesize, gfx.screenwidth, gfx.screenheight - gfx.pianorollposition, 14); 58 | } 59 | 60 | //Draw menu area 61 | gfx.fillrect(0, gfx.linesize, gfx.screenwidth, gfx.linesize * 10, 5); 62 | for (j = 0; j < gfx.linesize * 10; j++) { 63 | if (j % 4 == 0) { 64 | gfx.fillrect(0, gfx.linesize + j, gfx.screenwidth, 2, 1); 65 | } 66 | } 67 | 68 | switch(control.currenttab) { 69 | case control.MENUTAB_FILE: 70 | guiclass.tx = (gfx.screenwidth - 768) / 4; 71 | gfx.fillrect(guiclass.tx, gfx.linesize, 408, gfx.linesize * 10, 5); 72 | gfx.fillrect(gfx.screenwidth - guiclass.tx - 408+24, gfx.linesize, 408, gfx.linesize * 10, 5); 73 | break; 74 | case control.MENUTAB_CREDITS: 75 | guiclass.tx = (gfx.screenwidth - 768) / 4; 76 | gfx.fillrect(guiclass.tx, gfx.linesize, 408, gfx.linesize * 10, 5); 77 | gfx.fillrect(gfx.screenwidth - guiclass.tx - 408+24, gfx.linesize, 408, gfx.linesize * 10, 5); 78 | break; 79 | case control.MENUTAB_GITHUB: 80 | guiclass.tx = (gfx.screenwidth - 768) / 4; 81 | gfx.fillrect(guiclass.tx, gfx.linesize, 408, gfx.linesize * 10, 5); 82 | gfx.fillrect(gfx.screenwidth - guiclass.tx - 408+24, gfx.linesize, 408, gfx.linesize * 10, 5); 83 | break; 84 | case control.MENUTAB_HELP: 85 | guiclass.tx = (gfx.screenwidth - 768) / 2; 86 | gfx.fillrect(guiclass.tx, gfx.linesize, 768, gfx.linesize * 10, 5); 87 | break; 88 | case control.MENUTAB_ARRANGEMENTS: 89 | gfx.drawarrangementeditor(); 90 | gfx.drawtimeline(); 91 | gfx.drawpatternmanager(); 92 | break; 93 | case control.MENUTAB_INSTRUMENTS: 94 | gfx.drawinstrumentlist(); 95 | gfx.drawinstrument(); 96 | break; 97 | case control.MENUTAB_ADVANCED: 98 | guiclass.tx = (gfx.screenwidth - 768) / 4; 99 | gfx.fillrect(guiclass.tx, gfx.linesize, 408, gfx.linesize * 10, 5); 100 | gfx.fillrect(gfx.screenwidth - guiclass.tx - 408+24, gfx.linesize, 408, gfx.linesize * 10, 5); 101 | break; 102 | } 103 | 104 | //Cache bitmap at this point 105 | gfx.updatebackground--; 106 | if (gfx.updatebackground == 0) { 107 | gfx.settrect(gfx.backbuffer.rect.x, gfx.backbuffer.rect.y, gfx.backbuffer.rect.width, gfx.backbuffer.rect.height); 108 | gfx.backbuffercache.copyPixels(gfx.backbuffer, gfx.trect, gfx.tl); 109 | } 110 | }else { 111 | if(!control.musicplaying) gfx.changeframerate(15); //If there's no music playing, drop the framerate! 112 | //Draw from cache 113 | gfx.settrect(gfx.backbuffercache.rect.x, gfx.backbuffercache.rect.y, gfx.backbuffercache.rect.width, gfx.backbuffercache.rect.height); 114 | gfx.backbuffer.copyPixels(gfx.backbuffercache, gfx.trect, gfx.tl); 115 | } 116 | 117 | if (control.currenttab == control.MENUTAB_ARRANGEMENTS) { 118 | gfx.drawarrangementcursor(); 119 | if (control.mx > gfx.patternmanagerx - 108) { 120 | gfx.drawpatternmanager(); 121 | } 122 | gfx.drawtimeline_cursor(); 123 | gfx.drawpatternmanager_cursor(); 124 | } 125 | 126 | if (!control.nowexporting) { 127 | if (control.currentbox > -1) { 128 | gfx.drawpatterneditor_cursor(); 129 | } 130 | } 131 | 132 | guiclass.drawbuttons(); 133 | 134 | if (control.messagedelay > 0) { 135 | i = control.messagedelay > 10?10:control.messagedelay; 136 | gfx.fillrect(0, gfx.screenheight - (i * 2), gfx.screenwidth, 20, 16); 137 | gfx.print(gfx.screenwidthmid - (gfx.len(control.message) / 2), gfx.screenheight - (i * 2), control.message, 0, false, true); 138 | } 139 | 140 | //Draw pop up lists over all that 141 | gfx.drawlist(); 142 | 143 | //Draw mouse dragging stuff over everything 144 | if (control.dragaction == 1 || control.dragaction == 2) { 145 | if (Math.abs(control.mx - control.dragx) > 4 || Math.abs(control.my - control.dragy) > 4) { 146 | gfx.drawmusicbox(control.mx, control.my, control.dragpattern); 147 | } 148 | } 149 | 150 | gfx.render(); 151 | } -------------------------------------------------------------------------------- /src/instrumentclass.as: -------------------------------------------------------------------------------- 1 | package { 2 | import flash.display.*; 3 | import flash.geom.*; 4 | import flash.events.*; 5 | import flash.net.*; 6 | import org.si.sion.SiONVoice; 7 | 8 | public class instrumentclass { 9 | public function instrumentclass():void { 10 | clear(); 11 | } 12 | 13 | public function clear():void { 14 | category = "MIDI"; 15 | name = "Grand Piano"; type = 0; index = 0; 16 | cutoff = 128; resonance = 0; 17 | palette = 0; 18 | volume = 256; 19 | } 20 | 21 | public function setfilter(c:int, r:int):void { 22 | cutoff = c; resonance = r; 23 | } 24 | 25 | public function setvolume(v:int):void { 26 | volume = v; 27 | } 28 | 29 | public function updatefilter():void { 30 | if (voice != null) { 31 | if(voice.velocity!=volume){ 32 | voice.updateVolumes = true; 33 | voice.velocity = volume; 34 | } 35 | if(voice.channelParam.cutoff != cutoff || voice.channelParam.resonance != resonance){ 36 | voice.setFilterEnvelop(0, cutoff, resonance); 37 | } 38 | } 39 | } 40 | 41 | public function changefilterto(c:int, r:int, v:int):void { 42 | if (voice != null) { 43 | voice.updateVolumes = true; 44 | voice.velocity = v; 45 | voice.setFilterEnvelop(0, c, r); 46 | } 47 | } 48 | 49 | public function changevolumeto(v:int):void { 50 | if (voice != null) { 51 | voice.updateVolumes = true; 52 | voice.velocity = v; 53 | } 54 | } 55 | 56 | public var cutoff:int, resonance:int; 57 | public var voice:SiONVoice = new SiONVoice; 58 | 59 | public var category:String; 60 | public var name:String; 61 | public var palette:int; 62 | public var type:int; 63 | public var index:int; 64 | public var volume:int; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/keypoll.as: -------------------------------------------------------------------------------- 1 | public function generickeypoll():void { 2 | control.press_up = false; control.press_down = false; 3 | control.press_left = false; control.press_right = false; 4 | control.press_space = false; control.press_enter = false; 5 | 6 | if (key.isDown(Keyboard.LEFT) || key.isDown(Keyboard.A)) control.press_left = true; 7 | if (key.isDown(Keyboard.RIGHT) || key.isDown(Keyboard.D)) control.press_right = true; 8 | if (key.isDown(Keyboard.UP) || key.isDown(Keyboard.W)) control.press_up= true; 9 | if (key.isDown(Keyboard.DOWN) || key.isDown(Keyboard.S)) control.press_down = true; 10 | if (key.isDown(Keyboard.SPACE)) control.press_space = true; 11 | if (key.isDown(Keyboard.ENTER)) control.press_enter = true; 12 | 13 | control.keypriority = 0; 14 | 15 | if (control.keypriority == 3) {control.press_up = false; control.press_down = false; 16 | }else if (control.keypriority == 4) { control.press_left = false; control.press_right = false; } 17 | 18 | if ((key.isDown(15) || key.isDown(17)) && key.isDown(70) && !control.fullscreentoggleheld) { 19 | //Toggle fullscreen 20 | control.fullscreentoggleheld = true; 21 | if (control.fullscreen) {control.fullscreen = false; 22 | }else { control.fullscreen = true; } 23 | updategraphicsmode(); 24 | } 25 | 26 | if (control.fullscreentoggleheld) { 27 | if (!key.isDown(15) && !key.isDown(17) && !key.isDown(70)) { 28 | control.fullscreentoggleheld = false; 29 | } 30 | } 31 | 32 | if (control.keyheld) { 33 | if (control.press_space || control.press_right || control.press_left || control.press_enter || 34 | control.press_down || control.press_up) { 35 | control.press_space = false; 36 | control.press_enter = false; 37 | control.press_up = false; 38 | control.press_down = false; 39 | control.press_left = false; 40 | control.press_right = false; 41 | }else { 42 | control.keyheld = false; 43 | } 44 | } 45 | 46 | if (control.press_space || control.press_right || control.press_left || control.press_enter || 47 | control.press_down || control.press_up) { 48 | //Update screen when there is input. 49 | gfx.updatebackground = 5; 50 | } 51 | } -------------------------------------------------------------------------------- /src/listclass.as: -------------------------------------------------------------------------------- 1 | package { 2 | import flash.display.*; 3 | import flash.geom.*; 4 | import flash.events.*; 5 | import flash.net.*; 6 | 7 | public class listclass { 8 | public function listclass():void { 9 | for (var i:int = 0; i < 30; i++) { 10 | item.push(""); 11 | } 12 | clear(); 13 | } 14 | 15 | public function clear():void { 16 | numitems = 0; 17 | active = false; 18 | x = 0; y = 0; 19 | selection = -1; 20 | } 21 | 22 | public function init(xp:int, yp:int):void { 23 | x = xp; y = yp; active = true; 24 | getwidth(); 25 | h = numitems * gfx.linesize; 26 | } 27 | 28 | public function close():void { 29 | active = false; 30 | } 31 | 32 | public function getwidth():void { 33 | w = 0; 34 | var temp:int; 35 | for (var i:int = 0; i < numitems; i++) { 36 | temp = gfx.len(item[i]); 37 | if (w < temp) w = temp; 38 | } 39 | w += 10; 40 | } 41 | 42 | public var item:Vector. = new Vector.; 43 | public var numitems:int; 44 | public var active:Boolean; 45 | public var x:int, y:int, w:int, h:int; 46 | public var type:int; 47 | public var selection:int; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/musicphraseclass.as: -------------------------------------------------------------------------------- 1 | package { 2 | import flash.display.*; 3 | import flash.geom.*; 4 | import flash.events.*; 5 | import flash.net.*; 6 | 7 | public class musicphraseclass { 8 | public function musicphraseclass():void { 9 | for (var i:int = 0; i < 129; i++) { 10 | notes.push(new Rectangle(-1, 0, 0, 0)); 11 | } 12 | for (i = 0; i < 16; i++) { 13 | cutoffgraph.push(128); 14 | resonancegraph.push(0); 15 | volumegraph.push(256); 16 | } 17 | clear(); 18 | } 19 | 20 | public function clear():void { 21 | for (var i:int = 0; i < 128; i++) { 22 | notes[i].setTo(-1, 0, 0, 0); 23 | } 24 | 25 | for (i = 0; i < 16; i++) { 26 | cutoffgraph[i] = 128; 27 | resonancegraph[i] = 0; 28 | volumegraph[i] = 256; 29 | } 30 | start = 48; //start at c4 31 | numnotes = 0; 32 | instr = 0; 33 | scale = 0; key = 0; 34 | 35 | palette = 0; 36 | isplayed = false; 37 | 38 | recordfilter = 0; 39 | topnote = -1; bottomnote = 250; 40 | 41 | hash = 0; 42 | } 43 | 44 | public function findtopnote():void { 45 | topnote = -1; 46 | for (var i:int = 0; i < numnotes; i++) { 47 | if (notes[i].x > topnote) { 48 | topnote = notes[i].x; 49 | } 50 | } 51 | } 52 | 53 | public function findbottomnote():void { 54 | bottomnote = 250; 55 | for (var i:int = 0; i < numnotes; i++) { 56 | if (notes[i].x < bottomnote) { 57 | bottomnote = notes[i].x; 58 | } 59 | } 60 | } 61 | 62 | public function transpose(amount:int):void { 63 | for (var i:int = 0; i < numnotes; i++) { 64 | if (notes[i].x != -1) { 65 | if (control.invertpianoroll[notes[i].x] + amount != -1) { 66 | notes[i].x = control.pianoroll[control.invertpianoroll[notes[i].x] + amount]; 67 | } 68 | } 69 | if (notes[i].x < 0) notes[i].x = 0; 70 | if (notes[i].x > 104) notes[i].x = 104; 71 | } 72 | } 73 | 74 | public function addnote(noteindex:int, note:int, time:int):void { 75 | if (numnotes < 128) { 76 | notes[numnotes].setTo(note, time, noteindex, 0); 77 | numnotes++; 78 | } 79 | 80 | if (note > topnote) topnote = note; 81 | if (note < bottomnote) bottomnote = note; 82 | notespan = topnote - bottomnote; 83 | 84 | hash = (hash + (note * time)) % 2147483647; 85 | } 86 | 87 | public function noteat(noteindex:int, note:int):Boolean { 88 | //Returns true if there is a note that intersects the cursor position 89 | for (var i:int = 0; i < numnotes; i++) { 90 | if (notes[i].x == note) { 91 | if (noteindex >= notes[i].width && noteindex < notes[i].width + notes[i].y) { 92 | return true; 93 | } 94 | } 95 | } 96 | return false; 97 | } 98 | 99 | public function removenote(noteindex:int, note:int):void { 100 | //Remove any note that intersects that cursor position! 101 | for (var i:int = 0; i < numnotes; i++) { 102 | if (notes[i].x == note) { 103 | if (noteindex >= notes[i].width && noteindex < notes[i].width + notes[i].y) { 104 | deletenote(i); 105 | i--; 106 | } 107 | } 108 | } 109 | 110 | findtopnote(); findbottomnote(); notespan = topnote-bottomnote; 111 | } 112 | 113 | public function setnotespan():void { 114 | findtopnote(); findbottomnote(); notespan = topnote-bottomnote; 115 | } 116 | 117 | public function deletenote(t:int):void { 118 | //Remove note t, rearrange note vector 119 | for (var i:int = t; i < numnotes; i++) { 120 | notes[i].x = notes[i + 1].x; 121 | notes[i].y = notes[i + 1].y; 122 | notes[i].width = notes[i + 1].width; 123 | notes[i].height = notes[i + 1].height; 124 | } 125 | numnotes--; 126 | } 127 | 128 | public var notes:Vector. = new Vector.; 129 | public var start:int; 130 | public var numnotes:int; 131 | 132 | public var cutoffgraph:Vector. = new Vector.; 133 | public var resonancegraph:Vector. = new Vector.; 134 | public var volumegraph:Vector. = new Vector.; 135 | public var recordfilter:int; 136 | 137 | public var topnote:int, bottomnote:int, notespan:Number; 138 | 139 | public var key:int, scale:int; 140 | 141 | public var instr:int; 142 | 143 | public var palette:int; 144 | 145 | public var isplayed:Boolean; 146 | 147 | public var hash:int; //massively simplified thing 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/ocean/midi/InvalidMidiError.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright(C) 2008 Efishocean 3 | * 4 | * This file is part of Midias. 5 | * 6 | * Midias is an ActionScript3 midi lib developed by Efishocean. 7 | * Midias was extracted from my project 'ocean' which purpose to 8 | * impletement a commen audio formats libray. 9 | * More infos might appear on my blog http://www.tan66.cn 10 | * 11 | * Midias is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * Midias is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see 23 | */ 24 | package ocean.midi { 25 | 26 | /** 27 | * Invalid Midi Error 28 | */ 29 | public dynamic class InvalidMidiError extends Error { 30 | 31 | /** 32 | * @param message error message text. 33 | * @param id @see Error 34 | */ 35 | public function InvalidMidiError(message:String="",id:int=0):void{ 36 | super(message,id); 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/ocean/midi/MidiEnum.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright(C) 2008 Efishocean 3 | * 4 | * This file is part of Midias. 5 | * 6 | * Midias is an ActionScript3 midi lib developed by Efishocean. 7 | * Midias was extracted from my project 'ocean' which purpose to 8 | * impletement a commen audio formats libray. 9 | * More infos might appear on my blog http://www.tan66.cn 10 | * 11 | * Midias is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * Midias is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see 23 | */ 24 | 25 | package ocean.midi { 26 | import flash.utils.Dictionary; 27 | 28 | /** 29 | * MidiEnum class 30 | */ 31 | public class MidiEnum { 32 | /** 33 | * Channel message 34 | */ 35 | public static const NOTE_OFF:int = 0x80; // ???? 36 | public static const NOTE_ON:int = 0x90; // ???? 37 | public static const POLY_PRESSURE:int = 0xA0; // ???????(??) 38 | public static const CONTROL_CHANGE:int = 0xB0; // ?????? 39 | public static const PROGRAM_CHANGE:int = 0xC0; // ??(??)?? 40 | public static const CHANNEL_PRESSURE:int = 0xD0; // ????? 41 | public static const PITCH_BEND:int = 0xE0; // ?? 42 | /** 43 | * Meta message 44 | */ 45 | public static const META:int = 0xFF; // Meta tag 46 | public static const SEQ_NUM:int = 0x00; // Sequence number 47 | public static const TEXT:int = 0x01; // Text 48 | public static const COPY_RIGHT:int = 0x02; // Copyright notice 49 | public static const SEQ_TRK_NAME:int = 0x03; // Sequence or track name 50 | public static const INSTRUMENT_NAME:int = 0x04; // Instrument name 51 | public static const LYRIC_TXT:int = 0x05; // Lyric text 52 | public static const MARKER_TXT:int = 0x06; // Marker text 53 | public static const CUE_POINT :int = 0x07; // Cue point 54 | public static const PROGRAM_NAME:int = 0x08; // Program name 55 | public static const DEVICE_NAME:int = 0x09; // Device name 56 | public static const CHANNEL_PREFIX:int = 0x20; // MIDI channel prefix assignment 57 | public static const END_OF_TRK:int = 0x2F; // End of track 58 | public static const SET_TEMPO:int = 0x51; // 1/4 Tempo setting 59 | public static const SMPTE_OFFSET:int = 0x54; // SMPTE offset 60 | public static const TIME_SIGN:int = 0x58; // Time signature 61 | public static const KEY_SIGN:int = 0x59; // Key signature 62 | public static const SEQ_SPEC:int = 0x7F; // Sequencer specific event 63 | /** 64 | * System Real Time Message---- 65 | */ 66 | public static const TIMING_CLOCK:int = 0xF8; // ???? 67 | public static const RESERVED_0xF9:int = 0xF9; // ?? 68 | public static const SYS_START:int = 0xFA; // ?????????(????????????????) 69 | public static const SYS_CONTINUE:int = 0xFB; // ??????????????? 70 | public static const SYS_STOP:int = 0xFC; // ?????? 71 | public static const RESERVED_0xFD:int = 0xFD; // ?? 72 | public static const ACTIVE_SENDING:int = 0xFE; // ?????? 73 | //public static const SYS_RESET:int = 0xFF; // ???? 74 | /** 75 | * System message 76 | */ 77 | public static const SYSTEM_EXCLUSIVE:int = 0xF0; // ???????,???????? 78 | public static const MIDI_TIME_CODE:int = 0xF1; // midi??? 79 | public static const SONG_POSITION:int = 0xF2; // ???? 80 | public static const SONG_SELECT:int = 0xF3; // ?? 81 | public static const RESERVED_0xF4:int = 0xF4; // ?? 82 | public static const RESERVED_0xF5:int = 0xF5; // ?? 83 | public static const TUNE_REQUEST:int = 0xF6; // ?? 84 | public static const END_OF_SYS_EX:int = 0xF7; // ?????????? 85 | 86 | public static const NOTE:int = 0x00; // zero can be presents the note kind 87 | 88 | private static const _message:Dictionary = new Dictionary(true); 89 | 90 | //Initialize the static block 91 | { 92 | _message[NOTE_OFF]="NOTE_OFF"; 93 | _message[NOTE_ON]="NOTE_ON"; 94 | _message[POLY_PRESSURE]="POLY_PRESSURE"; 95 | _message[CONTROL_CHANGE]="CONTROL_CHANGE"; 96 | _message[PROGRAM_CHANGE]="PROGRAM_CHANGE"; 97 | _message[CHANNEL_PRESSURE]="CHANNEL_PRESSURE"; 98 | _message[PITCH_BEND]="PITCH_BEND"; 99 | 100 | _message[META]="META"; 101 | _message[SEQ_NUM]="SEQ_NUM"; 102 | _message[TEXT]="TEXT"; 103 | _message[COPY_RIGHT]="COPY_RIGHT"; 104 | _message[SEQ_TRK_NAME]="SEQ_TRK_NAME"; 105 | _message[INSTRUMENT_NAME]="INSTRUMENT_NAME"; 106 | _message[LYRIC_TXT]="LYRIC_TXT"; 107 | _message[MARKER_TXT]="MARKER_TXT"; 108 | _message[CUE_POINT]="CUE_POINT"; 109 | _message[PROGRAM_NAME]="PROGRAM_NAME"; 110 | _message[DEVICE_NAME]="DEVICE_NAME"; 111 | _message[CHANNEL_PREFIX]="CHANNEL_PREFIX"; 112 | _message[END_OF_TRK]="END_OF_TRK"; 113 | _message[SET_TEMPO]="SET_TEMPO"; 114 | _message[SMPTE_OFFSET]="SMPTE_OFFSET"; 115 | _message[TIME_SIGN]="TIME_SIGN"; 116 | _message[KEY_SIGN]="KEY_SIGN"; 117 | _message[SEQ_SPEC]="SEQ_SPEC"; 118 | 119 | _message[TIMING_CLOCK]="TIMING_CLOCK"; 120 | _message[RESERVED_0xF9]="RESERVED_0xF9"; 121 | _message[SYS_START]="SYS_START"; 122 | _message[SYS_CONTINUE]="SYS_CONTINUE"; 123 | _message[SYS_STOP]="SYS_STOP"; 124 | _message[RESERVED_0xFD]="RESERVED_0xFD"; 125 | _message[ACTIVE_SENDING]="ACTIVE_SENDING"; 126 | //_message[SYS_RESET]="SYS_RESET"; 127 | 128 | _message[SYSTEM_EXCLUSIVE]="SYSTEM_EXCLUSIVE"; 129 | _message[MIDI_TIME_CODE]="MIDI_TIME_CODE"; 130 | _message[SONG_POSITION]="SONG_POSITION"; 131 | _message[SONG_SELECT]="SONG_SELECT"; 132 | _message[RESERVED_0xF4]="RESERVED_0xF4"; 133 | _message[RESERVED_0xF5]="RESERVED_0xF5"; 134 | _message[TUNE_REQUEST]="TUNE_REQUEST"; 135 | _message[END_OF_SYS_EX]="END_OF_SYS_EX"; 136 | 137 | _message[NOTE]="NOTE"; 138 | //_message[]=""; 139 | //_message[]=""; 140 | //_message[]=""; 141 | //_message[]=""; 142 | //_message[]=""; 143 | } 144 | /** 145 | * Initializes the static dictionary. 146 | */ 147 | public function MidiEnum():void{ 148 | undefined; 149 | } 150 | 151 | /** 152 | * @param n message value. 153 | * @return message name. 154 | */ 155 | public static function getMessageName(n:int):String{ 156 | return _message[n]; 157 | } 158 | 159 | 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /src/ocean/midi/controller/History.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright(C) 2008 Efishocean 3 | * 4 | * This file is part of Midias. 5 | * 6 | * Midias is an ActionScript3 midi lib developed by Efishocean. 7 | * Midias was extracted from my project 'ocean' which purpose to 8 | * impletement a commen audio formats libray. 9 | * More infos might appear on my blog http://www.tan66.cn 10 | * 11 | * Midias is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * Midias is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see 23 | */ 24 | 25 | 26 | package ocean.midi.controller { 27 | import de.polygonal.ds.DLinkedList; 28 | import de.polygonal.ds.DListIterator; 29 | 30 | /** 31 | * Histroy is a singleton class. It holds a stack. 32 | * All local item operations will be recorded into this global stack. 33 | * Thus, undo and redo features are performed based on it. 34 | * @author Efishocean 35 | * @version 1.0.0 36 | */ 37 | public class History { 38 | private static var singleton:History; 39 | private var _size:uint; 40 | private var _stack:DLinkedList; 41 | private var _iterator:DListIterator; 42 | public static function getHistory():History{ 43 | if( singleton==null ){ 44 | singleton = new History(); 45 | return singleton; 46 | } 47 | else 48 | return singleton; 49 | } 50 | public function get size():uint{ 51 | return _size; 52 | } 53 | public function set size(s:uint):void{ 54 | _size = s; 55 | } 56 | public function get stack():DLinkedList{ 57 | return _stack; 58 | } 59 | public function get iterator():DListIterator{ 60 | return _iterator; 61 | } 62 | public function History():void{ 63 | if( singleton!=null ){ 64 | throw new Error("History is a singleton class, use getHistory() instead."); 65 | }else{ 66 | _size = 128; 67 | _stack = new DLinkedList(); 68 | // head of _stack should always be empty array. 69 | _stack.append( new Array() ); 70 | _iterator = _stack.getListIterator(); 71 | } 72 | 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/ocean/midi/controller/MultiTrackEditor.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright(C) 2008 Efishocean 3 | * 4 | * This file is part of Midias. 5 | * 6 | * Midias is an ActionScript3 midi lib developed by Efishocean. 7 | * Midias was extracted from my project 'ocean' which purpose to 8 | * impletement a commen audio formats libray. 9 | * More infos might appear on my blog http://www.tan66.cn 10 | * 11 | * Midias is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * Midias is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see 23 | */ 24 | 25 | package ocean.midi.controller { 26 | 27 | /** 28 | * This class is not impletemented. 29 | */ 30 | public class MultiTrackEditor{ 31 | private var selectedTracks:Array; 32 | 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/ocean/midi/event/MvcEvent.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright(C) 2008 Efishocean 3 | * 4 | * This file is part of Midias. 5 | * 6 | * Midias is an ActionScript3 midi lib developed by Efishocean. 7 | * Midias was extracted from my project 'ocean' which purpose to 8 | * impletement a commen audio formats libray. 9 | * More infos might appear on my blog http://www.tan66.cn 10 | * 11 | * Midias is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * Midias is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see 23 | */ 24 | 25 | package ocean.midi.event { 26 | import flash.events.Event; 27 | 28 | //public static const 29 | //public static const 30 | //public static const 31 | //public static const 32 | //public static const 33 | 34 | /** 35 | */ 36 | public class MvcEvent extends Event{ 37 | public static const APPLY_TRACK:String = "apply an other track"; 38 | public static const UPDATE_VIEW:String = "update view"; 39 | public function MvcEvent(event:String):void{ 40 | super(event); 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/ocean/midi/model/ChannelItem.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright(C) 2008 Efishocean 3 | * 4 | * This file is part of Midias. 5 | * 6 | * Midias is an ActionScript3 midi lib developed by Efishocean. 7 | * Midias was extracted from my project 'ocean' which purpose to 8 | * impletement a commen audio formats libray. 9 | * More infos might appear on my blog http://www.tan66.cn 10 | * 11 | * Midias is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * Midias is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see 23 | */ 24 | 25 | package ocean.midi.model { 26 | 27 | /** 28 | */ 29 | public class ChannelItem extends MessageItem{ 30 | public var _channel:uint; 31 | public var _command:uint; 32 | public var _data1:uint; 33 | public var _data2:*; 34 | 35 | public function ChannelItem():void{ 36 | super(); 37 | } 38 | 39 | public function get channel():uint{ 40 | return _channel; 41 | } 42 | 43 | public function set channel(c:uint):void{ 44 | _channel = c&0x0F; 45 | } 46 | 47 | public function get command():uint{ 48 | return _command; 49 | } 50 | 51 | public function set command(c:uint):void{ 52 | _command = c&0xF0; 53 | kind = _command; 54 | } 55 | 56 | 57 | 58 | public function get data1():uint{ 59 | return _data1; 60 | } 61 | 62 | public function set data1(d:uint):void{ 63 | _data1 = d; 64 | } 65 | 66 | public function get data2():*{ 67 | return _data2; 68 | } 69 | 70 | public function set data2(d:*):void{ 71 | _data2 = d; 72 | } 73 | 74 | override public function clone():MessageItem{ 75 | var item:ChannelItem = new ChannelItem(); 76 | item.kind = this.kind; 77 | item.timeline = this.timeline; 78 | item.channel = this.channel; 79 | item.command = this.command; 80 | item.data1 = this.data1; 81 | item.data2 = this.data2; 82 | return item; 83 | } 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/ocean/midi/model/MessageItem.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright(C) 2008 Efishocean 3 | * 4 | * This file is part of Midias. 5 | * 6 | * Midias is an ActionScript3 midi lib developed by Efishocean. 7 | * Midias was extracted from my project 'ocean' which purpose to 8 | * impletement a commen audio formats libray. 9 | * More infos might appear on my blog http://www.tan66.cn 10 | * 11 | * Midias is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * Midias is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see 23 | */ 24 | 25 | package ocean.midi.model { 26 | 27 | /** 28 | */ 29 | public class MessageItem { 30 | public var _timeline:uint; 31 | public var _kind:uint; 32 | /** 33 | * @default true Means this is an active item while false means to be erased. 34 | */ 35 | public var mark:Boolean; 36 | 37 | public function MessageItem():void{ 38 | mark = true; 39 | } 40 | 41 | public function set kind(k:uint):void{ 42 | _kind = k; 43 | } 44 | 45 | public function get kind():uint{ 46 | return _kind; 47 | } 48 | 49 | public function get timeline():uint{ 50 | return _timeline; 51 | } 52 | 53 | public function set timeline(t:uint):void{ 54 | _timeline = t; 55 | } 56 | 57 | public function clone():MessageItem{ 58 | var msgItem:MessageItem = new MessageItem(); 59 | msgItem.kind = this.kind; 60 | msgItem.timeline = this.timeline; 61 | return msgItem; 62 | } 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/ocean/midi/model/MessageList.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright(C) 2008 Efishocean 3 | * 4 | * This file is part of Midias. 5 | * 6 | * Midias is an ActionScript3 midi lib developed by Efishocean. 7 | * Midias was extracted from my project 'ocean' which purpose to 8 | * impletement a commen audio formats libray. 9 | * More infos might appear on my blog http://www.tan66.cn 10 | * 11 | * Midias is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * Midias is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see 23 | */ 24 | 25 | package ocean.midi.model { 26 | import ocean.midi.MidiTrack; 27 | 28 | /** 29 | */ 30 | public dynamic class MessageList extends Array{ 31 | 32 | public function MessageList():void{ 33 | super(); 34 | } 35 | 36 | /** 37 | * Export event list as midi track. Will optimize data, as well as filter unkown message. 38 | * @return 39 | */ 40 | public function output():MidiTrack{ 41 | var mt:MidiTrack = new MidiTrack(); 42 | mt.msgList = this.clone(); 43 | return mt; 44 | } 45 | 46 | /** 47 | * Parse the midi Track, cache as event list in array 48 | * @param mt 49 | * @return 50 | */ 51 | public function input(mt:MidiTrack):void{ 52 | for each( var item:* in mt.msgList ){ 53 | this.push( item.clone() ); 54 | } 55 | } 56 | 57 | /** 58 | * new instance with the same identical contents 59 | * @return a clone 60 | */ 61 | public function clone():MessageList{ 62 | var msgList:MessageList = new MessageList(); 63 | for each( var item:* in this ){ 64 | msgList.push(item.clone()); 65 | } 66 | return msgList; 67 | } 68 | 69 | 70 | } 71 | 72 | } 73 | 74 | -------------------------------------------------------------------------------- /src/ocean/midi/model/MetaItem.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright(C) 2008 Efishocean 3 | * 4 | * This file is part of Midias. 5 | * 6 | * Midias is an ActionScript3 midi lib developed by Efishocean. 7 | * Midias was extracted from my project 'ocean' which purpose to 8 | * impletement a commen audio formats libray. 9 | * More infos might appear on my blog http://www.tan66.cn 10 | * 11 | * Midias is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * Midias is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see 23 | */ 24 | 25 | package ocean.midi.model { 26 | import flash.utils.ByteArray; 27 | 28 | import ocean.midi.MidiEnum; 29 | 30 | /** 31 | * 32 | */ 33 | public class MetaItem extends MessageItem{ 34 | public var _text:ByteArray; 35 | public var _type:uint; 36 | 37 | public function MetaItem():void{ 38 | super(); 39 | //defaulte meta item is a end of track 40 | _text = new ByteArray(); 41 | _type = MidiEnum.END_OF_TRK; 42 | this.kind = MidiEnum.META; 43 | } 44 | public function get text():ByteArray{ 45 | _text.position = 0; 46 | return _text; 47 | } 48 | 49 | public function set text(t:ByteArray):void{ 50 | _text.position = 0; 51 | _text.length = 0; 52 | _text.writeBytes(t); 53 | } 54 | 55 | public function get type():uint{ 56 | return _type; 57 | } 58 | 59 | public function set type(t:uint):void{ 60 | _type = t; 61 | } 62 | public function get metaName():String{ 63 | return MidiEnum.getMessageName(type); 64 | } 65 | public function get size():uint{ 66 | if( _text ) 67 | return _text.length; 68 | else 69 | return 0; 70 | } 71 | 72 | override public function clone():MessageItem{ 73 | var item:MetaItem = new MetaItem(); 74 | item.kind = this.kind; 75 | item.timeline = this.timeline; 76 | item.text = this.text; 77 | item.type = this.type; 78 | return item; 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/ocean/midi/model/NoteItem.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright(C) 2008 Efishocean 3 | * 4 | * This file is part of Midias. 5 | * 6 | * Midias is an ActionScript3 midi lib developed by Efishocean. 7 | * Midias was extracted from my project 'ocean' which purpose to 8 | * impletement a commen audio formats libray. 9 | * More infos might appear on my blog http://www.tan66.cn 10 | * 11 | * Midias is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * Midias is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see 23 | */ 24 | 25 | package ocean.midi.model { 26 | 27 | /** 28 | */ 29 | public class NoteItem extends MessageItem{ 30 | private var _pitch:uint; 31 | private var _velocity:uint; 32 | private var _duration:uint; 33 | private var _channel:uint; 34 | private static const _pitchName:Array = ["C","Db","D","Eb","E","F","F#","G","G#","A","Bb","B"]; 35 | 36 | public function NoteItem( c:uint=0 , p:uint=67 , v:uint=127 , d:uint=120, t:int=0 ):void{ 37 | super(); 38 | _channel = c&0x0F; 39 | _pitch = p&0x7F; 40 | _velocity = v&0x7F; 41 | _duration = d; 42 | 43 | _timeline = t; 44 | } 45 | 46 | public function get channel():uint{ 47 | return _channel; 48 | } 49 | 50 | public function set channel(c:uint):void{ 51 | _channel = c; 52 | } 53 | 54 | public function get pitch():uint{ 55 | return _pitch; 56 | } 57 | 58 | public function get pitchName():String{ 59 | var level:uint = (_pitch/12>>0); 60 | var str:String = _pitchName[_pitch%12] + (level?level:""); 61 | return str; 62 | } 63 | 64 | public function set pitch(p:uint):void{ 65 | _pitch = p; 66 | } 67 | 68 | public function get duration():uint{ 69 | return _duration; 70 | } 71 | 72 | public function set duration(d:uint):void{ 73 | _duration = d; 74 | } 75 | 76 | public function get velocity():uint{ 77 | return _velocity; 78 | } 79 | 80 | public function set velocity(v:uint):void{ 81 | _velocity = v; 82 | } 83 | 84 | override public function clone():MessageItem{ 85 | var item:NoteItem = new NoteItem(); 86 | item.kind = this.kind; 87 | item.timeline = this.timeline; 88 | item.channel = this.channel; 89 | item.duration = this.duration; 90 | item.pitch = this.pitch; 91 | item.velocity = this.velocity; 92 | return item; 93 | } 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/ocean/midi/model/RawItem.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright(C) 2008 Efishocean 3 | * 4 | * This file is part of Midias. 5 | * 6 | * Midias is an ActionScript3 midi lib developed by Efishocean. 7 | * Midias was extracted from my project 'ocean' which purpose to 8 | * impletement a commen audio formats libray. 9 | * More infos might appear on my blog http://www.tan66.cn 10 | * 11 | * Midias is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * Midias is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see 23 | */ 24 | 25 | package ocean.midi.model { 26 | import flash.utils.ByteArray; 27 | 28 | /** 29 | */ 30 | public class RawItem { 31 | public var noteOn:uint; 32 | public var raw:ByteArray; 33 | public var timeline:uint; 34 | public var index:uint; 35 | public function RawItem():void{ 36 | raw = new ByteArray(); 37 | noteOn = 0; 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/ocean/midi/model/SysxItem.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright(C) 2008 Efishocean 3 | * 4 | * This file is part of Midias. 5 | * 6 | * Midias is an ActionScript3 midi lib developed by Efishocean. 7 | * Midias was extracted from my project 'ocean' which purpose to 8 | * impletement a commen audio formats libray. 9 | * More infos might appear on my blog http://www.tan66.cn 10 | * 11 | * Midias is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * Midias is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see 23 | */ 24 | package ocean.midi.model 25 | { 26 | import flash.utils.ByteArray; 27 | import ocean.midi.MidiEnum; 28 | 29 | /** 30 | */ 31 | public class SysxItem extends MessageItem 32 | { 33 | private var _data:ByteArray; 34 | public function SysxItem():void{ 35 | super(); 36 | this.kind = MidiEnum.SYSTEM_EXCLUSIVE; 37 | _data = new ByteArray(); 38 | } 39 | public function get size():uint{ 40 | if( _data ) 41 | return _data.length; 42 | else 43 | return 0; 44 | } 45 | public function get data():ByteArray{ 46 | _data.position = 0; 47 | return _data; 48 | } 49 | public function set data(d:ByteArray):void{ 50 | _data.position = 0 ; 51 | _data.length = 0; 52 | _data.writeBytes(d); 53 | } 54 | override public function clone():MessageItem{ 55 | var item:SysxItem = new SysxItem(); 56 | item.timeline = this.timeline; 57 | item.data = this.data; 58 | return item; 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /src/ocean/utils/GreedyUINT.as: -------------------------------------------------------------------------------- 1 | /** 2 | * ... 3 | */ 4 | 5 | package ocean.utils { 6 | import flash.utils.ByteArray; 7 | import flash.errors.EOFError; 8 | public class GreedyUINT { 9 | //* MEMBERS////////////////////////////////////////////////////// 10 | 11 | private var _rawBytes:ByteArray; 12 | //* PROPERTIES/////////////////////////////////////////////////// 13 | 14 | /** 15 | * The value of GreedyUINT as uint. 16 | */ 17 | public function get value():uint{ 18 | _rawBytes.position = 0; 19 | if(0==_rawBytes.length){ 20 | throw new Error("value is not defined"); 21 | } 22 | 23 | var n:uint; 24 | // value = (128^e)*b1+(128^e-1)*b2+....(128^0)*bn; 25 | for( var e:int = _rawBytes.length-1; e>=0; e-- ){ 26 | n += ( _rawBytes.readByte()&0x7F )<<(7*e); 27 | } 28 | if( n==Infinity || n==-Infinity ){ 29 | throw new Error("value is beyond uint infinity"); 30 | } 31 | return n; 32 | } 33 | 34 | /** 35 | * Set the value of GreedyUINT with uint. 36 | * @param n 37 | * @return 38 | */ 39 | public function set value(n:uint):void{ 40 | _rawBytes.position = 0; 41 | var e:uint ; 42 | var t:uint ; 43 | var temp:Array=new Array(); 44 | // bytes =[ n/(128^e)%128 | 0x80 , n/(128^e-1)%128 | 0x80 , ... n/(128^0)%128 ]; 45 | if( 0!=n ){ 46 | for( e=0 , t = n>>(7*e) ; t>=1 && e<5; ){ 47 | //变长整数最后一个字节高bit位为0。其他字节高bit位为1,低七位是余数对128求模 48 | // tips:If the divisor is a power of 2, the modulo (%) operation can be done with: 49 | // modulus = numerator & (divisor - 1); 50 | temp[e] = e?( t&(128-1) | 0x80 ): n&(128-1);//temp[e] = e?( t%128 | 0x80 ): n%128; 51 | 52 | // 余数为整数除以128的e次方 53 | t = n>>(7*(++e)); 54 | } 55 | }else{ 56 | temp[0]=0; 57 | } 58 | for( _rawBytes.length = e = temp.length ; e>0 ; e-- ){ 59 | _rawBytes.writeByte(temp[e-1]); 60 | } 61 | 62 | } 63 | 64 | /** 65 | * RawBytes value in ByteArray format 66 | */ 67 | public function get rawBytes():ByteArray{ 68 | _rawBytes.position = 0; 69 | return _rawBytes; 70 | } 71 | /** 72 | * set property rawBytes with input byteArray, this method will not effect the position of the coming byteArray. 73 | * @param raw 74 | * @return 75 | */ 76 | public function set rawBytes(raw:ByteArray):void{ 77 | _rawBytes.position = 0; 78 | _rawBytes.length = 0; 79 | if( check(raw) ){ 80 | _rawBytes.writeBytes(raw); 81 | _rawBytes.position = 0; 82 | }else{ 83 | throw new Error("input byteArrary is not a valid GreedyUINT"); 84 | } 85 | } 86 | //* METHODS////////////////////////////////////////////////////// 87 | 88 | /** 89 | * GreedyUINT is length flexible unsigned int type. 90 | * When value a greedy uint, the high bit of the last byte is 0, other byte's high bit is 1. 91 | * Each 7 bits equals the remainder moded by 128. 92 | *

bytes = [ n/(128p)%128 | 0x80 , 93 | * n/(128p-1)%128 | 0x80 , ... n/(1280)%128 ];

94 | * @param raw bytes to convert into greedy uint, if null creates a 0. 95 | * @author Efishocean 96 | * @version 1.0.0 97 | * fixed the byteArray position to zero in every function's first line 2007-7-25 11:58 98 | */ 99 | public function GreedyUINT(raw:ByteArray=null):void{ 100 | _rawBytes = new ByteArray(); 101 | if( null==raw ){ 102 | _rawBytes[0]=0; 103 | } 104 | else if( check(raw) ){ 105 | _rawBytes.writeBytes(raw); 106 | } 107 | else{ 108 | throw new Error("input byteArrary is not a valid GreedyUINT"); 109 | } 110 | } 111 | 112 | /** 113 | * Checks if the input raw datas are valid greedyUINT 114 | * @param raw bytes 115 | * @return valid or not. 116 | * @ 2007-7-18 23:08 117 | */ 118 | public function check(raw:ByteArray):Boolean{ 119 | if( null==raw ){return false;} 120 | var len:uint = raw.length; 121 | //变长只处理小于4294967295的数,这个范围内可以用小于5个字节的变长表示 122 | if( len>5 || len<=0){return false;} 123 | //变长整数最后一字节8bit位为零 124 | if( (raw[len-1] & 0x80) != 0x00 ){ 125 | return false; 126 | } 127 | //前面字节的8bit位为'1' 128 | else{ 129 | for( var i:uint=0; i r1) r = r1; } 19 | if (g < g1) { g += speed; if (g > g1) g = g1; } 20 | if (b < b1) { b += speed; if (b > b1) b = b1; } 21 | 22 | if (r > r1) { r -= speed; if (r < r1) r = r1; } 23 | if (g > g1) { g -= speed; if (g < g1) g = g1; } 24 | if (b > b1) { b -= speed; if (b < b1) b = b1; } 25 | 26 | fixbounds(); 27 | } 28 | 29 | public function fixbounds():void { 30 | if (r <= 0) r = 0; if (g <= 0) g = 0; if (b <= 0) b = 0; 31 | if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; 32 | } 33 | 34 | public var r:int, g:int, b:int; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /successfuly quarantined.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/successfuly quarantined.png -------------------------------------------------------------------------------- /terminal pwd promt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TerryCavanagh/boscaceoil/9eaa9d37405ae9b9953d1cf3d925ba330d0c7f31/terminal pwd promt.png -------------------------------------------------------------------------------- /test/build-desktop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | amxmlc -swf-version 28 -default-frame-rate 30 -default-size 768 560 -library-path+=lib/sion065.swc -source-path+=src -default-background-color 0x000000 -warnings -strict src/Main.as -o BoscaCeoil.swf -define+=CONFIG::desktop,true -define+=CONFIG::web,false 4 | 5 | # adl application.xml 6 | 7 | # adt -certificate -cn asdf 2048-RSA cert.p12 dummypass 8 | # adt -package -storetype pkcs12 -keystore cert.p12 -storepass dummypass -target bundle something.app application.xml BoscaCeoil.swf assets 9 | -------------------------------------------------------------------------------- /test/build-web.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | amxmlc -swf-version 28 -default-frame-rate 30 -default-size 768 560 -library-path+=lib/sion065.swc -source-path+=src -default-background-color 0x000000 -warnings -strict src/Main.as -o BoscaCeoil.swf -define+=CONFIG::desktop,false -define+=CONFIG::web,true 4 | -------------------------------------------------------------------------------- /test/test-web.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 | 10 | 11 |

This website requires Flash.

12 |
13 |
14 | 15 |
16 | 17 |
18 | 19 |
20 | 21 |
22 |
23 | 24 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/test-web.rb: -------------------------------------------------------------------------------- 1 | require 'watir-webdriver' 2 | require 'sinatra/base' 3 | require 'thread' 4 | 5 | 6 | # If the web build of BoscaCeoil.swf works correctly, then it 7 | # should call the window.Bosca._isReady() javascript function. 8 | # In our mock test-web.html file, that function will insert a 9 | # success message in the webpage. 10 | # 11 | # This script runs a webserver, opens test-web.html in a web 12 | # browser, and checks for the success message. 13 | 14 | 15 | class TestApp < Sinatra::Base 16 | set :public_folder, File.join(File.dirname(__FILE__), '..') 17 | end 18 | 19 | 20 | # http://stackoverflow.com/a/16543644/1924875 21 | def sinatra_run_wait(app, opts) 22 | queue = Queue.new 23 | thread = Thread.new do 24 | Thread.abort_on_exception = true 25 | app.run!(opts) do |server| 26 | queue.push("started") 27 | end 28 | end 29 | queue.pop # blocks until the run! callback runs 30 | end 31 | 32 | 33 | sinatra_run_wait(TestApp, :port => 3000, :server => 'webrick') 34 | sleep 1 35 | 36 | test_url = "http://localhost:3000/test/test-web.html" 37 | 38 | client = Selenium::WebDriver::Remote::Http::Default.new 39 | client.timeout = 180 # seconds - default is 60 40 | 41 | if Gem.win_platform? 42 | # I had mega problems getting firefox/chrome driver to work properly on 43 | # Appveyor, so I'm using IE here instead. 44 | browser = :ie 45 | else 46 | browser = :firefox 47 | end 48 | 49 | 50 | if browser == :ie 51 | ie_caps = Selenium::WebDriver::Remote::Capabilities.ie("initialBrowserUrl" => test_url) 52 | ie_driver = Selenium::WebDriver.for :ie, :desired_capabilities => ie_caps, :http_client => client 53 | b = Watir::Browser.new ie_driver 54 | else 55 | b = Watir::Browser.new browser, :http_client => client 56 | b.goto test_url 57 | end 58 | 59 | at_exit { 60 | b.close 61 | } 62 | 63 | # The actual test 64 | begin 65 | b.div(:id => "result").wait_until_present(30) 66 | Watir::Wait.until(60, 'js-enabled') { b.text.include? 'js enabled' } 67 | Watir::Wait.until(60, 'swf-js') { b.text.include? 'success' } 68 | rescue => e 69 | puts e 70 | exit 1 71 | end 72 | 73 | 74 | exit 0 75 | --------------------------------------------------------------------------------