diff --git a/Flod 4.1/demos/Demo1.as b/Flod 4.1/demos/Demo1.as new file mode 100644 index 0000000..097150b --- /dev/null +++ b/Flod 4.1/demos/Demo1.as @@ -0,0 +1,66 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/10 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. + + --- + + This is a simple demo showing how to use the FileLoader class to play a module, in any of the supported + formats, loaded from the client. + +*/ +package { + import flash.display.*; + import flash.events.*; + import flash.net.*; + import neoart.flod.*; + import neoart.flod.core.*; + + public final class Demo1 extends Sprite { + private var + file : FileReference, + loader : FileLoader, + player : CorePlayer; + + public function Demo1() { + loader = new FileLoader(); + + stage.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void { + file = new FileReference(); + file.addEventListener(Event.CANCEL, cancelHandler); + file.addEventListener(Event.SELECT, selectHandler); + file.browse(); + }); + } + + private function cancelHandler(e:Event):void { + file.removeEventListener(Event.CANCEL, cancelHandler); + file.removeEventListener(Event.SELECT, selectHandler); + } + + private function selectHandler(e:Event):void { + cancelHandler(e); + if (player) player.stop(); + file.addEventListener(Event.COMPLETE, completeHandler); + file.load(); + } + + private function completeHandler(e:Event):void { + file.removeEventListener(Event.COMPLETE, completeHandler); + player = loader.load(file.data); + if (player && player.version) player.play(); + } + } +} \ No newline at end of file diff --git a/Flod 4.1/demos/Demo2.as b/Flod 4.1/demos/Demo2.as new file mode 100644 index 0000000..07f4de3 --- /dev/null +++ b/Flod 4.1/demos/Demo2.as @@ -0,0 +1,83 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/10 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. + + --- + + This is a simple demo showing how to use a single player to play a module loaded from the client. + + List of available players and include locations: + + D1Player Delta Music 1.0 neoart.flod.deltamusic + D2Player Delta Music 2.0 neoart.flod.deltamusic + DMPlayer Digital Mugician neoart.flod.digitalmugician + F2Player FastTracker II XM neoart.flod.fasttracker + FEPlayer FredEd neoart.flod.fred + FCPlayer Future Composer neoart.flod.futurecomposer + JHPlayer Jochen Hippel neoart.flod.hippel + RHPlayer Rob Hubbard neoart.flod.hubbard + S1Player SidMON neoart.flod.sidmon + S2Player SidMON II neoart.flod.sidmon + FXPlayer SoundFX neoart.flod.soundfx + BPPlayer SoundMon neoart.flod.soundmon + HMPlayer His Master's NoiseTracker neoart.flod.trackers + MKPlayer NoiseTracker neoart.flod.trackers + PTPlayer ProTracker neoart.flod.trackers + STPlayer Ultimate Soundtracker neoart.flod.trackers + DWPlayer David Whittaker neoart.flod.whittaker +*/ +package { + import flash.display.*; + import flash.events.*; + import flash.net.*; + import neoart.flod.core.*; + import neoart.flod.fasttracker.*; + + public final class Demo2 extends Sprite { + private var + file : FileReference, + player : F2Player; + + public function Demo2() { + player = new F2Player(); + + stage.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void { + file = new FileReference(); + file.addEventListener(Event.CANCEL, cancelHandler); + file.addEventListener(Event.SELECT, selectHandler); + file.browse(); + }); + } + + private function cancelHandler(e:Event):void { + file.removeEventListener(Event.CANCEL, cancelHandler); + file.removeEventListener(Event.SELECT, selectHandler); + } + + private function selectHandler(e:Event):void { + cancelHandler(e); + player.stop(); + file.addEventListener(Event.COMPLETE, completeHandler); + file.load(); + } + + private function completeHandler(e:Event):void { + file.removeEventListener(Event.COMPLETE, completeHandler); + player.load(file.data); + if (player.version) player.play(); + } + } +} \ No newline at end of file diff --git a/Flod 4.1/demos/Demo3.as b/Flod 4.1/demos/Demo3.as new file mode 100644 index 0000000..bd2a2a7 --- /dev/null +++ b/Flod 4.1/demos/Demo3.as @@ -0,0 +1,44 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/10 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. + + --- + + This is a simple demo showing how to use the FileLoader class to play a module, in any of the supported + formats, with an embedded module. + +*/ +package { + import flash.display.*; + import flash.utils.*; + import neoart.flod.*; + import neoart.flod.core.*; + + public final class Demo3 extends Sprite { + [Embed(source="filename.mod", mimeType="application/octet-stream")] + + private var + Song : Class, + loader : FileLoader, + player : CorePlayer; + + public function Demo3() { + loader = new FileLoader(); + player = loader.load(new Song() as ByteArray); + if (player && player.version) player.play(); + } + } +} \ No newline at end of file diff --git a/Flod 4.1/demos/Demo4.as b/Flod 4.1/demos/Demo4.as new file mode 100644 index 0000000..894816a --- /dev/null +++ b/Flod 4.1/demos/Demo4.as @@ -0,0 +1,62 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/10 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. + + --- + + This is a simple demo showing how to use a single player to play an embedded module. + + List of available players and include locations: + + D1Player Delta Music 1.0 neoart.flod.deltamusic + D2Player Delta Music 2.0 neoart.flod.deltamusic + DMPlayer Digital Mugician neoart.flod.digitalmugician + F2Player FastTracker II XM neoart.flod.fasttracker + FEPlayer FredEd neoart.flod.fred + FCPlayer Future Composer neoart.flod.futurecomposer + JHPlayer Jochen Hippel neoart.flod.hippel + RHPlayer Rob Hubbard neoart.flod.hubbard + S1Player SidMON neoart.flod.sidmon + S2Player SidMON II neoart.flod.sidmon + FXPlayer SoundFX neoart.flod.soundfx + BPPlayer SoundMon neoart.flod.soundmon + HMPlayer His Master's NoiseTracker neoart.flod.trackers + MKPlayer NoiseTracker neoart.flod.trackers + PTPlayer ProTracker neoart.flod.trackers + STPlayer Ultimate Soundtracker neoart.flod.trackers + DWPlayer David Whittaker neoart.flod.whittaker +*/ +package { + import flash.display.*; + import flash.events.*; + import flash.utils.*; + import neoart.flod.core.*; + import neoart.flod.fred.*; + + public final class Demo4 extends Sprite { + [Embed(source="filename.mod", mimeType="application/octet-stream")] + + private var + Song : Class, + player : FEPlayer; + + public function Demo4() { + player = new FEPlayer(); + player.load(new Song() as ByteArray); + if (player.version) player.play(); + } + } +} \ No newline at end of file diff --git a/Flod 4.1/demos/Demo5.as b/Flod 4.1/demos/Demo5.as new file mode 100644 index 0000000..ad832d1 --- /dev/null +++ b/Flod 4.1/demos/Demo5.as @@ -0,0 +1,54 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/10 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. + + --- + + This is a simple demo showing how to use the FileLoader class to play a module, in any of the supported + formats, loaded from the server. + + Warning: the server must be able to handle the correct file extension, if it can't just rename the file + to filename.wav and it should work... +*/ +package { + import flash.display.*; + import flash.events.*; + import flash.net.*; + import neoart.flod.*; + import neoart.flod.core.*; + + public final class Demo5 extends Sprite { + private var + url : URLLoader, + loader : FileLoader, + player : CorePlayer; + + public function Demo5() { + loader = new FileLoader(); + + url = new URLLoader(); + url.dataFormat = URLLoaderDataFormat.BINARY; + url.addEventListener(Event.COMPLETE, completeHandler); + url.load(new URLRequest("filename.mod")); + } + + private function completeHandler(e:Event):void { + url.removeEventListener(Event.COMPLETE, completeHandler); + player = loader.load(url.data); + if (player && player.version) player.play(); + } + } +} \ No newline at end of file diff --git a/Flod 4.1/demos/Demo6.as b/Flod 4.1/demos/Demo6.as new file mode 100644 index 0000000..47d4b9b --- /dev/null +++ b/Flod 4.1/demos/Demo6.as @@ -0,0 +1,69 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/10 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. + + --- + + This is a simple demo showing how to use a single player to play a module loaded from the server. + + List of available players and include locations: + + D1Player Delta Music 1.0 neoart.flod.deltamusic + D2Player Delta Music 2.0 neoart.flod.deltamusic + DMPlayer Digital Mugician neoart.flod.digitalmugician + F2Player FastTracker II XM neoart.flod.fasttracker + FEPlayer FredEd neoart.flod.fred + FCPlayer Future Composer neoart.flod.futurecomposer + JHPlayer Jochen Hippel neoart.flod.hippel + RHPlayer Rob Hubbard neoart.flod.hubbard + S1Player SidMON neoart.flod.sidmon + S2Player SidMON II neoart.flod.sidmon + FXPlayer SoundFX neoart.flod.soundfx + BPPlayer SoundMon neoart.flod.soundmon + HMPlayer His Master's NoiseTracker neoart.flod.trackers + MKPlayer NoiseTracker neoart.flod.trackers + PTPlayer ProTracker neoart.flod.trackers + STPlayer Ultimate Soundtracker neoart.flod.trackers + DWPlayer David Whittaker neoart.flod.whittaker +*/ +package { + import flash.display.*; + import flash.events.*; + import flash.net.*; + import neoart.flod.core.*; + import neoart.flod.sidmon.*; + + public final class Demo6 extends Sprite { + private var + url : URLLoader, + player : S1Player; + + public function Demo6() { + player = new S1Player(); + + url = new URLLoader(); + url.dataFormat = URLLoaderDataFormat.BINARY; + url.addEventListener(Event.COMPLETE, completeHandler); + url.load(new URLRequest("filename.mod")); + } + + private function completeHandler(e:Event):void { + url.removeEventListener(Event.COMPLETE, completeHandler); + player.load(url.data); + if (player.version) player.play(); + } + } +} \ No newline at end of file diff --git a/Flod 4.1/license.txt b/Flod 4.1/license.txt new file mode 100644 index 0000000..b547faf --- /dev/null +++ b/Flod 4.1/license.txt @@ -0,0 +1,18 @@ +Flod version 4.1 +Flod JS version 2.1 +Flip version 1.2 + + 2012/04/30 + Christian Corti + Neoart Costa Rica + + E-Mail: flod@neoartcr.com + +This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. +To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to +Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. + +Flod is free for non commercial user, to use it in any commercial production I'll ask you to +mention the proper credits and to make a donation to: chreil@hotmail.com via PayPal, thank you. + +Special thanks to Richard Davey, Mathew Nolan and Andreas Argirakis :) \ No newline at end of file diff --git a/Flod 4.1/neoart/flip/Huffman.as b/Flod 4.1/neoart/flip/Huffman.as new file mode 100644 index 0000000..998ab5a --- /dev/null +++ b/Flod 4.1/neoart/flip/Huffman.as @@ -0,0 +1,28 @@ +/* + Flip 1.2 + 2012/03/13 + Christian Corti + Neoart Costa Rica + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flip { + + public final class Huffman { + internal var + count : Vector., + symbol : Vector.; + + public function Huffman(length:int) { + count = new Vector.(length, true); + symbol = new Vector.(length, true); + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flip/Inflater.as b/Flod 4.1/neoart/flip/Inflater.as new file mode 100644 index 0000000..87cbb02 --- /dev/null +++ b/Flod 4.1/neoart/flip/Inflater.as @@ -0,0 +1,252 @@ +/* + Flip 1.2 + 2012/03/13 + Christian Corti + Neoart Costa Rica + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flip { + import flash.utils.*; + + public final class Inflater { + internal var + output : ByteArray; + private var + inpbuf : ByteArray, + inpcnt : int, + outcnt : int, + bitbuf : int, + bitcnt : int, + flencode : Huffman, + fdiscode : Huffman, + dlencode : Huffman, + ddiscode : Huffman; + + public function Inflater() { + initialize(); + } + + public function set input(stream:ByteArray):void { + inpbuf = stream; + output = new ByteArray(); + inpbuf.endian = output.endian = ZipFile.ENDIAN; + inpbuf.position = output.position = 0; + inpcnt = outcnt = 0; + } + + public function inflate():int { + var err:int, last:int, type:int; + + do { + last = bits(1); + type = bits(2); + err = type == 0 ? stored() : + type == 1 ? codes(flencode, fdiscode) : + type == 2 ? dynamic() : 1; + + if (err) throw new Error(ERROR1, 1); + } while (!last); + + return 0; + } + + private function bits(need:int):int { + var buff:int = bitbuf, inplen:uint = inpbuf.length; + + while (bitcnt < need) { + if (inpcnt == inplen) throw new Error(ERROR2, 2); + buff |= inpbuf[int(inpcnt++)] << bitcnt; + bitcnt += 8; + } + + bitbuf = buff >> need; + bitcnt -= need; + return buff & ((1 << need) - 1); + } + + private function codes(lencode:Huffman, discode:Huffman):int { + var dis:int, len:int, pos:int, sym:int; + + do { + sym = decode(lencode); + if (sym < 0) return sym; + + if (sym < 256) { + output[int(outcnt++)] = sym; + } else if (sym > 256) { + sym -= 257; + if (sym >= 29) throw new Error(ERROR3, 3); + len = LENG[sym] + bits(LEXT[sym]); + + sym = decode(discode); + if (sym < 0) return sym; + dis = DIST[sym] + bits(DEXT[sym]); + if (dis > outcnt) throw new Error(ERROR4, 4); + + pos = outcnt - dis; + while (len--) output[int(outcnt++)] = output[int(pos++)]; + } + } while (sym != 256); + + return 0; + } + + private function construct(huff:Huffman, length:Vector., n:int):int { + var len:int, left:int = 1, offs:Vector. = new Vector.(16, true), sym:int; + + for (len = 0; len < 16; ++len) huff.count[len] = 0; + for (sym = 0; sym < n; ++sym) huff.count[length[sym]]++; + if (huff.count[0] == n) return 0; + + for (len = 1; len < 16; ++len) { + left <<= 1; + left -= huff.count[len]; + if (left < 0) return left; + } + + for (len = 1; len < 15; ++len) + offs[int(len + 1)] = offs[len] + huff.count[len]; + + for (sym = 0; sym < n; ++sym) + if (length[sym] != 0) huff.symbol[int(offs[length[sym]]++)] = sym; + + return left; + } + + private function decode(huff:Huffman):int { + var buff:int = bitbuf, code:int, count:int, first:int, index:int, inplen:uint = inpbuf.length, left:int = bitcnt, len:int = 1; + + while (1) { + while (left--) { + code |= buff & 1; + buff >>= 1; + count = huff.count[len]; + + if (code < int(first + count)) { + bitbuf = buff; + bitcnt = (bitcnt - len) & 7; + return huff.symbol[int(index + (code - first))]; + } + + index += count; + first += count; + first <<= 1; + code <<= 1; + ++len; + } + + left = 16 - len; + if (left == 0) break; + if (inpcnt == inplen) throw new Error(ERROR2, 2); + buff = inpbuf[int(inpcnt++)]; + if (left > 8) left = 8; + } + + return -9; + } + + private function stored():int { + var inplen:uint = inpbuf.length, len:int; + bitbuf = bitcnt = 0; + + if ((inpcnt + 4) > inplen) throw new Error(ERROR2, 2); + len = inpbuf[int(inpcnt++)]; + len |= inpbuf[int(inpcnt++)] << 8; + + if (inpbuf[int(inpcnt++)] != ( ~len & 0xff) || + inpbuf[int(inpcnt++)] != ((~len >> 8) & 0xff)) throw new Error(ERROR5, 5); + + if ((inpcnt + len) > inplen) throw new Error(ERROR2, 2); + while (len--) output[int(outcnt++)] = inpbuf[int(inpcnt++)]; + return 0; + } + + private function initialize():void { + var length:Vector. = new Vector.(288, true), sym:int; + flencode = new Huffman(288); + fdiscode = new Huffman(30); + + for (sym = 0; sym < 144; ++sym) length[sym] = 8; + for (; sym < 256; ++sym) length[sym] = 9; + for (; sym < 280; ++sym) length[sym] = 7; + for (; sym < 288; ++sym) length[sym] = 8; + construct(flencode, length, 288); + + for (sym = 0; sym < 30; ++sym) length[sym] = 5; + construct(fdiscode, length, 30); + + dlencode = new Huffman(286); + ddiscode = new Huffman(30); + } + + private function dynamic():int { + var err:int, index:int, len:int, length:Vector. = new Vector.(316, true), nlen:int = bits(5) + 257, ndis:int = bits(5) + 1, ncode:int = bits(4) + 4, max:int = nlen + ndis, sym:int; + + if (nlen > 286 || ndis > 30) throw new Error(ERROR6, 6); + for (index = 0; index < ncode; ++index) length[ORDER[index]] = bits(3); + for (; index < 19; ++index) length[ORDER[index]] = 0; + + err = construct(dlencode, length, 19); + if (err) throw new Error(ERROR7, 7); + index = 0; + + while (index < max) { + sym = decode(dlencode); + + if (sym < 16) { + length[int(index++)] = sym; + } else { + len = 0; + + if (sym == 16) { + if (index == 0) throw new Error(ERROR8, 8); + len = length[int(index - 1)]; + sym = 3 + bits(2); + } else if (sym == 17) { + sym = 3 + bits(3); + } else { + sym = 11 + bits(7); + } + + if ((index + sym) > max) throw new Error(ERROR9, 9); + while (sym--) length[int(index++)] = len; + } + } + + err = construct(dlencode, length, nlen); + if (err < 0 || (err > 0 && nlen - dlencode.count[0] != 1)) throw new Error(ERROR10, 10); + + err = construct(ddiscode, length.slice(nlen), ndis); + if (err < 0 || (err > 0 && ndis - ddiscode.count[0] != 1)) throw new Error(ERROR11, 11); + + return codes(dlencode, ddiscode); + } + + private static const + ERROR1 : String = "Invalid block type.", + ERROR2 : String = "Available inflate data did not terminate.", + ERROR3 : String = "Invalid literal/length or distance code.", + ERROR4 : String = "Distance is too far back.", + ERROR5 : String = "Stored block length did not match one's complement.", + ERROR6 : String = "Too many length or distance codes.", + ERROR7 : String = "Code lengths codes incomplete.", + ERROR8 : String = "Repeat lengths with no first length.", + ERROR9 : String = "Repeat more than specified lengths.", + ERROR10 : String = "Invalid literal/length code lengths.", + ERROR11 : String = "Invalid distance code lengths.", + + LENG : Vector. = Vector.([3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258]), + LEXT : Vector. = Vector.([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]), + DIST : Vector. = Vector.([1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577]), + DEXT : Vector. = Vector.([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]), + ORDER : Vector. = Vector.([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flip/ZipEntry.as b/Flod 4.1/neoart/flip/ZipEntry.as new file mode 100644 index 0000000..e417d7d --- /dev/null +++ b/Flod 4.1/neoart/flip/ZipEntry.as @@ -0,0 +1,47 @@ +/* + Flip 1.2 + 2012/03/13 + Christian Corti + Neoart Costa Rica + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flip { + import flash.utils.*; + + public final class ZipEntry { + public var + name : String, + extra : ByteArray, + version : int, + flag : int, + method : int, + time : uint, + crc : uint, + compressed : uint, + size : uint, + offset : uint; + + public function get date():Date { + return new Date( + ((time >> 25) & 0x7f) + 1980, + ((time >> 21) & 0x0f) - 1, + (time >> 16) & 0x1f, + (time >> 11) & 0x1f, + (time >> 5) & 0x3f, + (time & 0x1f) << 1 + ); + } + + public function get isDirectory():Boolean { + return Boolean(name.charAt(name.length - 1) == "/"); + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flip/ZipFile.as b/Flod 4.1/neoart/flip/ZipFile.as new file mode 100644 index 0000000..03ef89f --- /dev/null +++ b/Flod 4.1/neoart/flip/ZipFile.as @@ -0,0 +1,135 @@ +/* + Flip 1.2 + 2012/03/13 + Christian Corti + Neoart Costa Rica + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flip { + import flash.utils.*; + + public final class ZipFile { + public static const + ENDIAN : String = "littleEndian"; + public var + entries : Vector.; + private var + stream : ByteArray; + + public function ZipFile(stream:ByteArray) { + this.stream = stream; + this.stream.endian = ENDIAN; + parseEnd(); + } + + public function extract(filename:String):ByteArray { + var entry:ZipEntry, i:int, len:int = entries.length; + if (!filename) return null; + + for (i = 0; i < len; ++i) { + entry = entries[i]; + if (entry.name == filename) return uncompress(entry); + } + + return null; + } + + public function uncompress(entry:ZipEntry):ByteArray { + var buffer:ByteArray, inflater:Inflater, size:int; + if (entry == null) return null; + + stream.position = entry.offset + 28; + size = stream.readUnsignedShort(); + stream.position += (entry.name.length + size); + + buffer = new ByteArray(); + buffer.endian = ENDIAN; + if (entry.compressed > 0) stream.readBytes(buffer, 0, entry.compressed); + + switch (entry.method) { + case 0: + return buffer; + case 8: + inflater = new Inflater(); + inflater.input = buffer; + inflater.inflate(); + return inflater.output; + default: + throw new Error(ERROR4, 4); + break; + } + } + + private function parseCentral():void { + var entry:ZipEntry, i:int, header:ByteArray = new ByteArray, len:int = entries.length, size:int; + header.endian = ENDIAN; + + for (i = 0; i < len; ++i) { + stream.readBytes(header, 0, 46); + header.position = 0; + if (header.readUnsignedInt() != 0x02014b50) throw new Error(ERROR2, 2); + header.position += 24; + + size = header.readUnsignedShort(); + if (size == 0) throw new Error(ERROR2, 2); + entry = new ZipEntry(); + entry.name = stream.readUTFBytes(size); + + size = header.readUnsignedShort(); + if (size > 0) { + entry.extra = new ByteArray(); + stream.readBytes(entry.extra, 0, size); + } + + stream.position += header.readUnsignedShort(); + header.position = 6; + entry.version = header.readUnsignedShort(); + + entry.flag = header.readUnsignedShort(); + if ((entry.flag & 1) == 1) throw new Error(ERROR3, 3); + + entry.method = header.readUnsignedShort(); + entry.time = header.readUnsignedInt(); + entry.crc = header.readUnsignedInt(); + entry.compressed = header.readUnsignedInt(); + entry.size = header.readUnsignedInt(); + + header.position = 42; + entry.offset = header.readUnsignedInt(); + entries[i] = entry; + } + } + + private function parseEnd():void { + var i:int = stream.length - 22, l:int = (i - 65536) > 0 ? i - 65536 : 0; + + do { + if (stream[i] != 0x50) continue; + stream.position = i; + if (stream.readUnsignedInt() == 0x06054b50) break; + } while (--i > l); + + if (i == l) throw new Error(ERROR1, 1); + + stream.position = i + 10; + entries = new Vector.(stream.readUnsignedShort(), true); + stream.position = i + 16; + stream.position = stream.readUnsignedInt(); + parseCentral(); + } + + private static const + ERROR1 : String = "The archive is either in unknown format or damaged.", + ERROR2 : String = "Unexpected end of archive.", + ERROR3 : String = "Encrypted archive not supported.", + ERROR4 : String = "Compression method not supported."; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/FileLoader.as b/Flod 4.1/neoart/flod/FileLoader.as new file mode 100644 index 0000000..bdb0086 --- /dev/null +++ b/Flod 4.1/neoart/flod/FileLoader.as @@ -0,0 +1,379 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.1 - 2012/04/16 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod { + import flash.utils.*; + import neoart.flip.*; + import neoart.flod.core.*; + import neoart.flod.deltamusic.*; + import neoart.flod.digitalmugician.*; + import neoart.flod.fred.*; + import neoart.flod.futurecomposer.*; + import neoart.flod.hippel.*; + import neoart.flod.hubbard.*; + import neoart.flod.sidmon.*; + import neoart.flod.soundfx.*; + import neoart.flod.soundmon.*; + import neoart.flod.trackers.*; + import neoart.flod.fasttracker.*; + import neoart.flod.whittaker.*; + + public final class FileLoader { + private var + player : CorePlayer, + index : int, + amiga : Amiga, + mixer : Soundblaster; + + public function FileLoader() { + amiga = new Amiga(); + mixer = new Soundblaster(); + } + + public function get tracker():String { + return (player) ? TRACKERS[index + player.version] : TRACKERS[0]; + } + + public function load(stream:ByteArray):CorePlayer { + var archive:ZipFile, id:String, value:int; + + stream.endian = "littleEndian"; + stream.position = 0; + + if (stream.readUnsignedInt() == 67324752) { + archive = new ZipFile(stream); + stream = archive.uncompress(archive.entries[0]); + } + + if (!stream) return null; + + if (player && !(player is STPlayer)) { + player.load(stream); + if (player.version) return player; + } + + if (stream.length > 336) { + stream.position = 38; + id = stream.readMultiByte(20, CorePlayer.ENCODING); + + if (id == "FastTracker v2.00 " || + id == "FastTracker v 2.00 " || + id == "Sk@le Tracker" || + id == "MadTracker 2.0" || + id == "MilkyTracker " || + id == "DigiBooster Pro 2.18" || + id.indexOf("OpenMPT") != -1) { + + player = new F2Player(mixer); + player.load(stream); + + if (player.version) { + index = FASTTRACKER; + return player; + } + } + } + + stream.endian = "bigEndian"; + + if (stream.length > 2105) { + stream.position = 1080; + id = stream.readMultiByte(4, CorePlayer.ENCODING); + + if (id == "M.K." || id == "FLT4") { + player = new MKPlayer(amiga); + player.load(stream); + + if (player.version) { + index = NOISETRACKER; + return player; + } + } else if (id == "FEST") { + player = new HMPlayer(amiga); + player.load(stream); + + if (player.version) { + index = HISMASTER; + return player; + } + } + } + + if (stream.length > 2105) { + stream.position = 1080; + id = stream.readMultiByte(4, CorePlayer.ENCODING); + + if (id == "M.K." || id == "M!K!") { + player = new PTPlayer(amiga); + player.load(stream); + + if (player.version) { + index = PROTRACKER; + return player; + } + } + } + + if (stream.length > 1685) { + stream.position = 60; + id = stream.readMultiByte(4, CorePlayer.ENCODING); + + if (id != "SONG") { + stream.position = 124; + id = stream.readMultiByte(4, CorePlayer.ENCODING); + } + + if (id == "SONG" || id == "SO31") { + player = new FXPlayer(amiga); + player.load(stream); + + if (player.version) { + index = SOUNDFX; + return player; + } + } + } + + if (stream.length > 4) { + stream.position = 0; + id = stream.readMultiByte(4, CorePlayer.ENCODING); + + if (id == "ALL ") { + player = new D1Player(amiga); + player.load(stream); + + if (player.version) { + index = DELTAMUSIC; + return player; + } + } + } + + if (stream.length > 3018) { + stream.position = 3014; + id = stream.readMultiByte(4, CorePlayer.ENCODING); + + if (id == ".FNL") { + player = new D2Player(amiga); + player.load(stream); + + if (player.version) { + index = DELTAMUSIC; + return player; + } + } + } + + if (stream.length > 30) { + stream.position = 26; + id = stream.readMultiByte(3, CorePlayer.ENCODING); + + if (id == "BPS" || id == "V.2" || id == "V.3") { + player = new BPPlayer(amiga); + player.load(stream); + + if (player.version) { + index = BPSOUNDMON; + return player; + } + } + } + + if (stream.length > 4) { + stream.position = 0; + id = stream.readMultiByte(4, CorePlayer.ENCODING); + + if (id == "SMOD" || id == "FC14") { + player = new FCPlayer(amiga); + player.load(stream); + + if (player.version) { + index = FUTURECOMP; + return player; + } + } + } + + if (stream.length > 10) { + stream.position = 0; + id = stream.readMultiByte(9, CorePlayer.ENCODING); + + if (id == " MUGICIAN") { + player = new DMPlayer(amiga); + player.load(stream); + + if (player.version) { + index = DIGITALMUG; + return player; + } + } + } + + if (stream.length > 86) { + stream.position = 58; + id = stream.readMultiByte(28, CorePlayer.ENCODING); + + if (id == "SIDMON II - THE MIDI VERSION") { + player = new S2Player(amiga); + player.load(stream); + + if (player.version) { + index = SIDMON; + return player; + } + } + } + + if (stream.length > 2830) { + stream.position = 0; + value = stream.readUnsignedShort(); + + if (value == 0x4efa) { + player = new FEPlayer(amiga); + player.load(stream); + + if (player.version) { + index = FREDED; + return player; + } + } + } + + if (stream.length > 5220) { + player = new S1Player(amiga); + player.load(stream); + + if (player.version) { + index = SIDMON; + return player; + } + } + + stream.position = 0; + value = stream.readUnsignedShort(); + stream.position = 0; + id = stream.readMultiByte(4, CorePlayer.ENCODING); + + if (id == "COSO" || value == 0x6000 || value == 0x6002 || value == 0x600e || value == 0x6016) { + player = new JHPlayer(amiga); + player.load(stream); + + if (player.version) { + index = HIPPEL; + return player; + } + } + + stream.position = 0; + value = stream.readUnsignedShort(); + + player = new DWPlayer(amiga); + player.load(stream); + + if (player.version) { + index = WHITTAKER; + return player; + } + + stream.position = 0; + value = stream.readUnsignedShort(); + + if (value == 0x6000) { + player = new RHPlayer(amiga); + player.load(stream); + + if (player.version) { + index = HUBBARD; + return player; + } + } + + if (stream.length > 1625) { + player = new STPlayer(amiga); + player.load(stream); + + if (player.version) { + index = SOUNDTRACKER; + return player; + } + } + + stream.clear(); + index = 0; + return player = null; + } + + private static const + SOUNDTRACKER = 0, + NOISETRACKER = 4, + PROTRACKER = 9, + HISMASTER = 12, + SOUNDFX = 13, + BPSOUNDMON = 17, + DELTAMUSIC = 20, + DIGITALMUG = 22, + FUTURECOMP = 24, + SIDMON = 26, + WHITTAKER = 28, + FREDED = 29, + HIPPEL = 30, + HUBBARD = 32, + FASTTRACKER = 33, + + TRACKERS = [ + "Unknown Format", + "Ultimate SoundTracker", + "D.O.C. SoundTracker 9", + "Master SoundTracker", + "D.O.C. SoundTracker 2.0/2.2", + "SoundTracker 2.3", + "SoundTracker 2.4", + "NoiseTracker 1.0", + "NoiseTracker 1.1", + "NoiseTracker 2.0", + "ProTracker 1.0", + "ProTracker 1.1/2.1", + "ProTracker 1.2/2.0", + "His Master's NoiseTracker", + "SoundFX 1.0/1.7", + "SoundFX 1.8", + "SoundFX 1.945", + "SoundFX 1.994/2.0", + "BP SoundMon V1", + "BP SoundMon V2", + "BP SoundMon V3", + "Delta Music 1.0", + "Delta Music 2.0", + "Digital Mugician", + "Digital Mugician 7 Voices", + "Future Composer 1.0/1.3", + "Future Composer 1.4", + "SidMon 1.0", + "SidMon 2.0", + "David Whittaker", + "FredEd", + "Jochen Hippel", + "Jochen Hippel COSO", + "Rob Hubbard", + "FastTracker II", + "Sk@leTracker", + "MadTracker 2.0", + "MilkyTracker", + "DigiBooster Pro 2.18", + "OpenMPT"]; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/core/Amiga.as b/Flod 4.1/neoart/flod/core/Amiga.as new file mode 100644 index 0000000..43ad57d --- /dev/null +++ b/Flod 4.1/neoart/flod/core/Amiga.as @@ -0,0 +1,208 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.1 - 2012/04/09 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.core { + import flash.events.*; + import flash.utils.*; + + public final class Amiga extends CoreMixer { + public static const + MODEL_A500 : int = 0, + MODEL_A1200 : int = 1; + public var + filter : AmigaFilter, + model : int = MODEL_A1200, + memory : Vector., + channels : Vector., + loopPtr : int, + loopLen : int = 4; + internal var + clock : Number = 0.0, + master : Number = 0.00390625; + + public function Amiga() { + super(); + bufferSize = 8192; + filter = new AmigaFilter(); + channels = new Vector.(4, true); + + channels[0] = new AmigaChannel(0); + channels[0].next = channels[1] = new AmigaChannel(1); + channels[1].next = channels[2] = new AmigaChannel(2); + channels[2].next = channels[3] = new AmigaChannel(3); + } + + public function set volume(value:int):void { + if (value > 0) { + if (value > 64) value = 64; + master = (value / 64) * 0.00390625; + } else { + master = 0.0; + } + } + + public function store(stream:ByteArray, len:int, pointer:int = -1):int { + var add:int, i:int, pos:int = stream.position, start:int = memory.length, total:int; + + if (pointer > -1) stream.position = pointer; + total = stream.position + len; + + if (total >= stream.length) { + add = total - stream.length; + len = stream.length - stream.position; + } + + for (i = start, len += start; i < len; ++i) + memory[i] = stream.readByte(); + + memory.length += add; + if (pointer > -1) stream.position = pos; + return start; + } + + override internal function initialize():void { + super.initialize(); + wave.clear(); + filter.initialize(); + + if (!memory.fixed) { + loopPtr = memory.length; + memory.length += loopLen; + memory.fixed = true; + } + + channels[0].initialize(); + channels[1].initialize(); + channels[2].initialize(); + channels[3].initialize(); + } + + //js function restore + override internal function reset():void { + memory = new Vector.(); + } + + override internal function fast(e:SampleDataEvent):void { + var chan:AmigaChannel, data:ByteArray = e.data, i:int, lvol:Number, mixed:int, mixLen:int, mixPos:int, rvol:Number, sample:Sample, size:int = bufferSize, speed:Number, toMix:int, value:Number; + + if (completed) { + if (!remains) return; + size = remains; + } + + while (mixed < size) { + if (!samplesLeft) { + player.process(); + samplesLeft = samplesTick; + + if (completed) { + size = mixed + samplesTick; + + if (size > bufferSize) { + remains = size - bufferSize; + size = bufferSize; + } + } + } + + toMix = samplesLeft; + if ((mixed + toMix) >= size) toMix = size - mixed; + mixLen = mixPos + toMix; + chan = channels[0]; + + while (chan) { + sample = buffer[mixPos]; + + if (chan.audena && chan.audper > 60) { + if (chan.mute) { + chan.ldata = 0.0; + chan.rdata = 0.0; + } + + speed = chan.audper / clock; + + value = chan.audvol * master; + lvol = value * (1 - chan.level); + rvol = value * (1 + chan.level); + + for (i = mixPos; i < mixLen; ++i) { + if (chan.delay) { + chan.delay--; + } else if (--chan.timer < 1.0) { + if (!chan.mute) { + value = memory[chan.audloc] * 0.0078125; + chan.ldata = value * lvol; + chan.rdata = value * rvol; + } + + chan.audloc++; + chan.timer += speed; + + if (chan.audloc >= chan.audcnt) { + chan.audloc = chan.pointer; + chan.audcnt = chan.pointer + chan.length; + } + } + + sample.l += chan.ldata; + sample.r += chan.rdata; + sample = sample.next; + } + } else { + for (i = mixPos; i < mixLen; ++i) { + sample.l += chan.ldata; + sample.r += chan.rdata; + sample = sample.next; + } + } + chan = chan.next; + } + + mixPos = mixLen; + mixed += toMix; + samplesLeft -= toMix; + } + + sample = buffer[0]; + + if (player.record) { + for (i = 0; i < size; ++i) { + filter.process(model, sample); + + wave.writeShort(int(sample.l * (sample.l < 0 ? 32768 : 32767))); + wave.writeShort(int(sample.r * (sample.r < 0 ? 32768 : 32767))); + + data.writeFloat(sample.l); + data.writeFloat(sample.r); + + sample.l = sample.r = 0.0; + sample = sample.next; + } + } else { + for (i = 0; i < size; ++i) { + filter.process(model, sample); + + data.writeFloat(sample.l); + data.writeFloat(sample.r); + + sample.l = sample.r = 0.0; + sample = sample.next; + } + } + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/core/AmigaChannel.as b/Flod 4.1/neoart/flod/core/AmigaChannel.as new file mode 100644 index 0000000..cd4ae39 --- /dev/null +++ b/Flod 4.1/neoart/flod/core/AmigaChannel.as @@ -0,0 +1,92 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.1 - 2012/04/09 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.core { + + public final class AmigaChannel { + public var + next : AmigaChannel, + mute : int, + panning : Number = 1.0, + delay : int, + pointer : int, + length : int; + internal var + audena : int, + audcnt : int, + audloc : int, + audper : int, + audvol : int, + timer : Number, + level : Number, + ldata : Number, + rdata : Number; + + public function AmigaChannel(index:int) { + if ((++index & 2) == 0) panning = -panning; + level = panning; + } + + public function get enabled():int { return audena; } + + public function set enabled(value:int):void { + if (value == audena) return; + + audena = value; + audloc = pointer; + audcnt = pointer + length; + + timer = 1.0; + if (value) delay += 2; + } + + public function set period(value:int):void { + if (value < 0) value = 0; + else if(value > 65535) value = 65535; + + audper = value; + } + + public function set volume(value:int):void { + if (value < 0) value = 0; + else if (value > 64) value = 64; + + audvol = value; + } + + public function resetData():void { + ldata = 0.0; + rdata = 0.0; + } + + internal function initialize():void { + audena = 0; + audcnt = 0; + audloc = 0; + audper = 50; + audvol = 0; + + timer = 0.0; + ldata = 0.0; + rdata = 0.0; + + delay = 0; + pointer = 0; + length = 0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/core/AmigaFilter.as b/Flod 4.1/neoart/flod/core/AmigaFilter.as new file mode 100644 index 0000000..4917a78 --- /dev/null +++ b/Flod 4.1/neoart/flod/core/AmigaFilter.as @@ -0,0 +1,73 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.core { + + public final class AmigaFilter { + public static const + AUTOMATIC : int = 0, + FORCE_ON : int = 1, + FORCE_OFF : int = -1; + public var + active : int, + forced : int = FORCE_OFF; + private var + l0 : Number, + l1 : Number, + l2 : Number, + l3 : Number, + l4 : Number, + r0 : Number, + r1 : Number, + r2 : Number, + r3 : Number, + r4 : Number; + + internal function initialize():void { + l0 = l1 = l2 = l3 = l4 = 0.0; + r0 = r1 = r2 = r3 = r4 = 0.0; + } + + internal function process(model:int, sample:Sample):void { + var FL:Number = 0.5213345843532200, P0:Number = 0.4860348337215757, P1:Number = 0.9314955486749749, d:Number = 1.0 - P0; + + if (model == 0) { + l0 = P0 * sample.l + d * l0 + 1e-18 - 1e-18; + r0 = P0 * sample.r + d * r0 + 1e-18 - 1e-18; + d = 1 - P1; + sample.l = l1 = P1 * l0 + d * l1; + sample.r = r1 = P1 * r0 + d * r1; + } + + if ((active | forced) > 0) { + d = 1 - FL; + l2 = FL * sample.l + d * l2 + 1e-18 - 1e-18; + r2 = FL * sample.r + d * r2 + 1e-18 - 1e-18; + l3 = FL * l2 + d * l3; + r3 = FL * r2 + d * r3; + sample.l = l4 = FL * l3 + d * l4; + sample.r = r4 = FL * r3 + d * r4; + } + + if (sample.l > 1.0) sample.l = 1.0; + else if (sample.l < -1.0) sample.l = -1.0; + + if (sample.r > 1.0) sample.r = 1.0; + else if (sample.r < -1.0) sample.r = -1.0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/core/AmigaPlayer.as b/Flod 4.1/neoart/flod/core/AmigaPlayer.as new file mode 100644 index 0000000..c43bbb8 --- /dev/null +++ b/Flod 4.1/neoart/flod/core/AmigaPlayer.as @@ -0,0 +1,72 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.core { + + public class AmigaPlayer extends CorePlayer { + public var + amiga : Amiga; + protected var + standard : int; + + public function AmigaPlayer(amiga:Amiga) { + this.amiga = amiga || new Amiga(); + super(this.amiga); + + channels = 4; + endian = "bigEndian"; + ntsc = 0; + speed = 6; + tempo = 125; + } + + override public function set ntsc(value:int):void { + standard = value; + + if (value) { + amiga.clock = 81.1688208; + amiga.samplesTick = 735; + } else { + amiga.clock = 80.4284580; + amiga.samplesTick = 882; + } + } + + override public function set stereo(value:Number):void { + var chan:AmigaChannel = amiga.channels[0]; + + if (value < 0.0) value = 0.0; + else if (value > 1.0) value = 1.0; + + while (chan) { + chan.level = value * chan.panning; + chan = chan.next; + } + } + + override public function set volume(value:Number):void { + if (value < 0.0) value = 0.0; + else if (value > 1.0) value = 1.0; + + amiga.master = value * 0.00390625; + } + + override public function toggle(index:int):void { + amiga.channels[index].mute ^= 1; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/core/AmigaRow.as b/Flod 4.1/neoart/flod/core/AmigaRow.as new file mode 100644 index 0000000..9676d72 --- /dev/null +++ b/Flod 4.1/neoart/flod/core/AmigaRow.as @@ -0,0 +1,27 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.core { + + public class AmigaRow { + public var + note : int, + sample : int, + effect : int, + param : int; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/core/AmigaSample.as b/Flod 4.1/neoart/flod/core/AmigaSample.as new file mode 100644 index 0000000..02eba65 --- /dev/null +++ b/Flod 4.1/neoart/flod/core/AmigaSample.as @@ -0,0 +1,30 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.core { + + public class AmigaSample { + public var + name : String = "", + length : int, + loop : int, + repeat : int, + volume : int, + pointer : int, + loopPtr : int; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/core/AmigaStep.as b/Flod 4.1/neoart/flod/core/AmigaStep.as new file mode 100644 index 0000000..83a89c7 --- /dev/null +++ b/Flod 4.1/neoart/flod/core/AmigaStep.as @@ -0,0 +1,25 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.core { + + public class AmigaStep { + public var + pattern : int, + transpose : int; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/core/CoreMixer.as b/Flod 4.1/neoart/flod/core/CoreMixer.as new file mode 100644 index 0000000..084024f --- /dev/null +++ b/Flod 4.1/neoart/flod/core/CoreMixer.as @@ -0,0 +1,109 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.core { + import flash.events.*; + import flash.utils.*; + + public class CoreMixer { + public var + player : CorePlayer, + samplesTick : int; + protected var + buffer : Vector., + samplesLeft : int, + remains : int, + completed : int, + wave : ByteArray; + + public function CoreMixer() { + wave = new ByteArray(); + wave.endian = "littleEndian"; + bufferSize = 8192; + } + + public function get bufferSize():int { return buffer.length; } + public function set bufferSize(value:int):void { + var i:int, len:int; + if (value == len || value < 2048) return; + + if (!buffer) { + buffer = new Vector.(value, true); + } else { + len = buffer.length; + buffer.fixed = false; + buffer.length = value; + buffer.fixed = true; + } + + if (value > len) { + buffer[len] = new Sample(); + + for (i = ++len; i < value; ++i) + buffer[i] = buffer[int(i - 1)].next = new Sample(); + } + } + + public function get complete():int { return completed; } + public function set complete(value:int):void { + completed = value ^ player.loopSong; + } + + //js function reset + internal function initialize():void { + var sample:Sample = buffer[0]; + + samplesLeft = 0; + remains = 0; + completed = 0; + + while (sample) { + sample.l = sample.r = 0.0; + sample = sample.next; + } + } + + //js function restore + internal function reset():void { } + + internal function fast(e:SampleDataEvent):void { } + + internal function accurate(e:SampleDataEvent):void { } + + internal function waveform():ByteArray { + var file:ByteArray = new ByteArray(); + file.endian = "littleEndian"; + + file.writeUTFBytes("RIFF"); + file.writeInt(wave.length + 44); + file.writeUTFBytes("WAVEfmt "); + file.writeInt(16); + file.writeShort(1); + file.writeShort(2); + file.writeInt(44100); + file.writeInt(44100 << 2); + file.writeShort(4); + file.writeShort(16); + file.writeUTFBytes("data"); + file.writeInt(wave.length); + file.writeBytes(wave); + + file.position = 0; + return file; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/core/CorePlayer.as b/Flod 4.1/neoart/flod/core/CorePlayer.as new file mode 100644 index 0000000..fa50e5d --- /dev/null +++ b/Flod 4.1/neoart/flod/core/CorePlayer.as @@ -0,0 +1,157 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/09 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.core { + import flash.events.*; + import flash.media.*; + import flash.utils.*; + import neoart.flip.*; + + public class CorePlayer extends EventDispatcher { + public static const + ENCODING : String = "us-ascii"; + public var + quality : int, + record : int, + playSong : int, + lastSong : int, + version : int, + variant : int, + title : String = "", + channels : int, + loopSong : int, + speed : int, + tempo : int; + protected var + hardware : CoreMixer, + sound : Sound, + soundChan : SoundChannel, + soundPos : Number = 0.0, + endian : String, + tick : int; + + public function CorePlayer(hardware:CoreMixer) { + hardware.player = this; + this.hardware = hardware; + } + + public function set force(value:int):void { + version = 0; + } + + public function set ntsc(value:int):void { } + + public function set stereo(value:Number):void { } + + public function set volume(value:Number):void { } + + public function get waveform():ByteArray { + return hardware.waveform(); + } + + public function toggle(index:int):void { } + + public function load(stream:ByteArray):int { + var zip:ZipFile; + hardware.reset(); + stream.position = 0; + + version = 0; + playSong = 0; + lastSong = 0; + + if (stream.readUnsignedInt() == 67324752) { + zip = new ZipFile(stream); + stream = zip.uncompress(zip.entries[0]); + } + + if (stream) { + stream.endian = endian; + stream.position = 0; + loader(stream); + if (version) setup(); + } + return version; + } + + public function play(processor:Sound = null):int { + if (!version) return 0; + if (soundPos == 0.0) initialize(); + sound = processor || new Sound(); + + if (quality && (hardware is Soundblaster)) { + sound.addEventListener(SampleDataEvent.SAMPLE_DATA, hardware.accurate); + } else { + sound.addEventListener(SampleDataEvent.SAMPLE_DATA, hardware.fast); + } + + soundChan = sound.play(soundPos); + soundChan.addEventListener(Event.SOUND_COMPLETE, completeHandler); + soundPos = 0.0; + return 1; + } + + public function pause():void { + if (!version || !soundChan) return; + soundPos = soundChan.position; + removeEvents(); + } + + public function stop():void { + if (!version) return; + if (soundChan) removeEvents(); + soundPos = 0.0; + reset(); + } + + public function process():void { } + + public function fast():void { } + + public function accurate():void { } + + protected function setup():void { } + + //js function reset + protected function initialize():void { + tick = 0; + hardware.initialize(); + hardware.samplesTick = 110250 / tempo; + } + + protected function reset():void { } + + protected function loader(stream:ByteArray):void { } + + private function completeHandler(e:Event):void { + stop(); + dispatchEvent(e); + } + + private function removeEvents():void { + soundChan.stop(); + soundChan.removeEventListener(Event.SOUND_COMPLETE, completeHandler); + soundChan.dispatchEvent(new Event(Event.SOUND_COMPLETE)); + + if (quality) { + sound.removeEventListener(SampleDataEvent.SAMPLE_DATA, hardware.accurate); + } else { + sound.removeEventListener(SampleDataEvent.SAMPLE_DATA, hardware.fast); + } + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/core/SBChannel.as b/Flod 4.1/neoart/flod/core/SBChannel.as new file mode 100644 index 0000000..6e0f1f9 --- /dev/null +++ b/Flod 4.1/neoart/flod/core/SBChannel.as @@ -0,0 +1,104 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.core { + + public final class SBChannel { + public var + next : SBChannel, + mute : int, + enabled : int, + sample : SBSample, + length : int, + index : int, + pointer : int, + delta : int, + fraction : Number, + speed : Number, + dir : int, + oldSample : SBSample, + oldLength : int, + oldPointer : int, + oldFraction : Number, + oldSpeed : Number, + oldDir : int, + volume : Number, + lvol : Number, + rvol : Number, + panning : int, + lpan : Number, + rpan : Number, + ldata : Number, + rdata : Number, + mixCounter : int, + lmixRampU : Number, + lmixDeltaU : Number, + rmixRampU : Number, + rmixDeltaU : Number, + lmixRampD : Number, + lmixDeltaD : Number, + rmixRampD : Number, + rmixDeltaD : Number, + volCounter : int, + lvolDelta : Number, + rvolDelta : Number, + panCounter : int, + lpanDelta : Number, + rpanDelta : Number; + + internal function initialize():void { + enabled = 0; + sample = null; + length = 0; + index = 0; + pointer = 0; + delta = 0; + fraction = 0.0; + speed = 0.0; + dir = 0; + oldSample = null; + oldLength = 0; + oldPointer = 0; + oldFraction = 0.0; + oldSpeed = 0.0; + oldDir = 0; + volume = 0.0; + lvol = 0.0; + rvol = 0.0; + panning = 128 + lpan = 0.5; + rpan = 0.5; + ldata = 0.0; + rdata = 0.0; + mixCounter = 0; + lmixRampU = 0.0; + lmixDeltaU = 0.0; + rmixRampU = 0.0; + rmixDeltaU = 0.0; + lmixRampD = 0.0; + lmixDeltaD = 0.0; + rmixRampD = 0.0; + rmixDeltaD = 0.0; + volCounter = 0; + lvolDelta = 0.0; + rvolDelta = 0.0; + panCounter = 0; + lpanDelta = 0.0; + rpanDelta = 0.0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/core/SBPlayer.as b/Flod 4.1/neoart/flod/core/SBPlayer.as new file mode 100644 index 0000000..5e8068b --- /dev/null +++ b/Flod 4.1/neoart/flod/core/SBPlayer.as @@ -0,0 +1,59 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.1 - 2012/04/21 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.core { + + public class SBPlayer extends CorePlayer { + public var + mixer : Soundblaster, + length : int, + restart : int, + track : Vector.; + protected var + timer : int, + master : int; + + public function SBPlayer(mixer:Soundblaster = null) { + this.mixer = mixer || new Soundblaster(); + super(this.mixer); + + endian = "littleEndian"; + quality = 1; + } + + override public function set volume(value:Number):void { + if (value < 0.0) value = 0.0; + else if (value > 1.0) value = 1.0; + + master = value * 64; + } + + override public function toggle(index:int):void { + mixer.channels[index].mute ^= 1; + } + + override protected function setup():void { + mixer.setup(channels); + } + + override protected function initialize():void { + super.initialize(); + timer = speed; + master = 64; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/core/SBSample.as b/Flod 4.1/neoart/flod/core/SBSample.as new file mode 100644 index 0000000..a1f83dc --- /dev/null +++ b/Flod 4.1/neoart/flod/core/SBSample.as @@ -0,0 +1,99 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.core { + import flash.utils.*; + + public class SBSample { + public var + name : String = "", + bits : int = 8, + volume : int, + length : int, + data : Vector., + loopMode : int, + loopStart : int, + loopLen : int; + + public function store(stream:ByteArray):void { + var delta:int, i:int, len:int = length, pos:int, sample:Number, total:int, value:int; + if (!loopLen) loopMode = 0; + pos = stream.position; + + if (loopMode) { + len = loopStart + loopLen; + data = new Vector.(len + 1, true); + } else { + data = new Vector.(length + 1, true); + } + + if (bits == 8) { + total = pos + len; + + if (total > stream.length) + len = stream.length - pos; + + for (i = 0; i < len; ++i) { + value = stream.readByte() + delta; + + if (value < -128) value += 256; + else if (value > 127) value -= 256; + + data[i] = value * 0.0078125; + delta = value; + } + } else { + total = pos + (len << 1); + + if (total > stream.length) + len = (stream.length - pos) >> 1; + + for (i = 0; i < len; ++i) { + value = stream.readShort() + delta; + + if (value < -32768) value += 65536; + else if (value > 32767) value -= 65536; + + data[i] = value * 0.00003051758; + delta = value; + } + } + + total = pos + length; + + if (!loopMode) { + data[length] = 0.0; + } else { + length = loopStart + loopLen; + + if (loopMode == 1) { + data[len] = data[loopStart]; + } else { + data[len] = data[int(len - 1)]; + } + } + + if (len != length) { + sample = data[int(len - 1)]; + for (i = len; i < length; ++i) data[i] = sample; + } + + if (total < stream.length) stream.position = total; + else stream.position = stream.length - 1; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/core/Sample.as b/Flod 4.1/neoart/flod/core/Sample.as new file mode 100644 index 0000000..a26a7d8 --- /dev/null +++ b/Flod 4.1/neoart/flod/core/Sample.as @@ -0,0 +1,26 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.core { + + public final class Sample { + public var + l : Number = 0.0, + r : Number = 0.0, + next : Sample; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/core/Soundblaster.as b/Flod 4.1/neoart/flod/core/Soundblaster.as new file mode 100644 index 0000000..8aea4da --- /dev/null +++ b/Flod 4.1/neoart/flod/core/Soundblaster.as @@ -0,0 +1,386 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.core { + import flash.events.*; + import flash.utils.*; + + public final class Soundblaster extends CoreMixer { + public var + channels : Vector.; + + public function Soundblaster() { + super(); + } + + internal function setup(len:int):void { + var i:int = 1; + channels = new Vector.(len, true); + channels[0] = new SBChannel(); + + for (; i < len; ++i) + channels[i] = channels[int(i - 1)].next = new SBChannel(); + } + + override internal function initialize():void { + var chan:SBChannel = channels[0]; + super.initialize(); + + while (chan) { + chan.initialize(); + chan = chan.next; + } + } + + override internal function fast(e:SampleDataEvent):void { + var chan:SBChannel, d:Vector., data:ByteArray = e.data, i:int, mixed:int, mixLen:int, mixPos:int, s:SBSample, sample:Sample, size:int = bufferSize, toMix:int, value:Number; + + if (completed) { + if (!remains) return; + size = remains; + } + + while (mixed < size) { + if (!samplesLeft) { + player.process(); + player.fast(); + samplesLeft = samplesTick; + + if (completed) { + size = mixed + samplesTick; + + if (size > bufferSize) { + remains = size - bufferSize; + size = bufferSize; + } + } + } + + toMix = samplesLeft; + if ((mixed + toMix) >= size) toMix = size - mixed; + mixLen = mixPos + toMix; + chan = channels[0]; + + while (chan) { + if (!chan.enabled) { + chan = chan.next; + continue; + } + + s = chan.sample; + d = s.data; + sample = buffer[mixPos]; + + for (i = mixPos; i < mixLen; ++i) { + if (chan.index != chan.pointer) { + if (chan.index >= chan.length) { + if (!s.loopMode) { + chan.enabled = 0; + break; + } else { + chan.pointer = s.loopStart + (chan.index - chan.length); + chan.length = s.length; + + if (s.loopMode == 2) { + if (!chan.dir) { + chan.dir = s.length + s.loopStart - 1; + } else { + chan.dir = 0; + } + } + } + } else chan.pointer = chan.index; + + if (!chan.mute) { + if (!chan.dir) value = d[chan.pointer]; + else value = d[int(chan.dir - chan.pointer)]; + + chan.ldata = value * chan.lvol; + chan.rdata = value * chan.rvol; + } else { + chan.ldata = 0.0; + chan.rdata = 0.0; + } + } + + chan.index = chan.pointer + chan.delta; + + if ((chan.fraction += chan.speed) >= 1.0) { + chan.index++; + chan.fraction--; + } + + sample.l += chan.ldata; + sample.r += chan.rdata; + sample = sample.next; + } + chan = chan.next; + } + + mixPos = mixLen; + mixed += toMix; + samplesLeft -= toMix; + } + + sample = buffer[0]; + + if (player.record) { + for (i = 0; i < size; ++i) { + if (sample.l > 1.0) sample.l = 1.0; + else if (sample.l < -1.0) sample.l = -1.0; + + if (sample.r > 1.0) sample.r = 1.0; + else if (sample.r < -1.0) sample.r = -1.0; + + wave.writeShort(int(sample.l * (sample.l < 0 ? 32768 : 32767))); + wave.writeShort(int(sample.r * (sample.r < 0 ? 32768 : 32767))); + + data.writeFloat(sample.l); + data.writeFloat(sample.r); + + sample.l = sample.r = 0.0; + sample = sample.next; + } + } else { + for (i = 0; i < size; ++i) { + if (sample.l > 1.0) sample.l = 1.0; + else if (sample.l < -1.0) sample.l = -1.0; + + if (sample.r > 1.0) sample.r = 1.0; + else if (sample.r < -1.0) sample.r = -1.0; + + data.writeFloat(sample.l); + data.writeFloat(sample.r); + + sample.l = sample.r = 0.0; + sample = sample.next; + } + } + } + + override internal function accurate(e:SampleDataEvent):void { + var chan:SBChannel, d1:Vector., d2:Vector., data:ByteArray = e.data, delta:int, i:int, mixed:int, mixLen:int, mixPos:int, mixValue:Number, s1:SBSample, s2:SBSample, sample:Sample, size:int = bufferSize, toMix:int, value:Number; + + if (completed) { + if (!remains) return; + size = remains; + } + + while (mixed < size) { + if (!samplesLeft) { + player.process(); + player.accurate(); + samplesLeft = samplesTick; + + if (completed) { + size = mixed + samplesTick; + + if (size > bufferSize) { + remains = size - bufferSize; + size = bufferSize; + } + } + } + + toMix = samplesLeft; + if ((mixed + toMix) >= size) toMix = size - mixed; + mixLen = mixPos + toMix; + chan = channels[0]; + + while (chan) { + if (!chan.enabled) { + chan = chan.next; + continue; + } + + s1 = chan.sample; + d1 = s1.data; + s2 = chan.oldSample; + if (s2) d2 = s2.data; + + sample = buffer[mixPos]; + + for (i = mixPos; i < mixLen; ++i) { + value = chan.mute ? 0.0 : d1[chan.pointer]; + value += (d1[int(chan.pointer + chan.dir)] - value) * chan.fraction; + + if ((chan.fraction += chan.speed) >= 1.0) { + delta = int(chan.fraction); + chan.fraction -= delta; + + if (chan.dir > 0) { + chan.pointer += delta; + + if (chan.pointer > chan.length) { + chan.fraction += chan.pointer - chan.length; + chan.pointer = chan.length; + } + } else { + chan.pointer -= delta; + + if (chan.pointer < chan.length) { + chan.fraction += chan.length - chan.pointer; + chan.pointer = chan.length; + } + } + } + + if (!chan.mixCounter) { + sample.l += value * chan.lvol; + sample.r += value * chan.rvol; + + if (chan.volCounter) { + chan.lvol += chan.lvolDelta; + chan.rvol += chan.rvolDelta; + chan.volCounter--; + } else if (chan.panCounter) { + chan.lpan += chan.lpanDelta; + chan.rpan += chan.rpanDelta; + chan.panCounter--; + + chan.lvol = chan.volume * chan.lpan; + chan.rvol = chan.volume * chan.rpan; + } + } else { + if (s2) { + mixValue = chan.mute ? 0.0 : d2[chan.oldPointer]; + mixValue += (d2[int(chan.oldPointer + chan.oldDir)] - mixValue) * chan.oldFraction; + + if ((chan.oldFraction += chan.oldSpeed) > 1) { + delta = int(chan.oldFraction); + chan.oldFraction -= delta; + + if (chan.oldDir > 0) { + chan.oldPointer += delta; + + if (chan.oldPointer > chan.oldLength) { + chan.oldFraction += chan.oldPointer - chan.oldLength; + chan.oldPointer = chan.oldLength; + } + } else { + chan.oldPointer -= delta; + + if (chan.oldPointer < chan.oldLength) { + chan.oldFraction += chan.oldLength - chan.oldPointer; + chan.oldPointer = chan.oldLength; + } + } + } + + sample.l += (value * chan.lmixRampU) + (mixValue * chan.lmixRampD); + sample.r += (value * chan.rmixRampU) + (mixValue * chan.rmixRampD); + + chan.lmixRampD -= chan.lmixDeltaD; + chan.rmixRampD -= chan.rmixDeltaD; + } else { + sample.l += (value * chan.lmixRampU); + sample.r += (value * chan.rmixRampU); + } + + chan.lmixRampU += chan.lmixDeltaU; + chan.rmixRampU += chan.rmixDeltaU; + chan.mixCounter--; + + if (chan.oldPointer == chan.oldLength) { + if (!s2.loopMode) { + s2 = null; + chan.oldPointer = 0; + } else if (s2.loopMode == 1) { + chan.oldPointer = s2.loopStart; + chan.oldLength = s2.length; + } else { + if (chan.oldDir > 0) { + chan.oldPointer = s2.length - 1; + chan.oldLength = s2.loopStart; + chan.oldDir = -1; + } else { + chan.oldFraction -= 1; + chan.oldPointer = s2.loopStart; + chan.oldLength = s2.length; + chan.oldDir = 1; + } + } + } + } + + if (chan.pointer == chan.length) { + if (!s1.loopMode) { + chan.enabled = 0; + break; + } else if (s1.loopMode == 1) { + chan.pointer = s1.loopStart; + chan.length = s1.length; + } else { + if (chan.dir > 0) { + chan.pointer = s1.length - 1; + chan.length = s1.loopStart; + chan.dir = -1; + } else { + chan.fraction -= 1; + chan.pointer = s1.loopStart; + chan.length = s1.length; + chan.dir = 1; + } + } + } + sample = sample.next; + } + chan = chan.next; + } + + mixPos = mixLen; + mixed += toMix; + samplesLeft -= toMix; + } + + sample = buffer[0]; + + if (player.record) { + for (i = 0; i < size; ++i) { + if (sample.l > 1.0) sample.l = 1.0; + else if (sample.l < -1.0) sample.l = -1.0; + + if (sample.r > 1.0) sample.r = 1.0; + else if (sample.r < -1.0) sample.r = -1.0; + + wave.writeShort(int(sample.l * (sample.l < 0 ? 32768 : 32767))); + wave.writeShort(int(sample.r * (sample.r < 0 ? 32768 : 32767))); + + data.writeFloat(sample.l); + data.writeFloat(sample.r); + + sample.l = sample.r = 0.0; + sample = sample.next; + } + } else { + for (i = 0; i < size; ++i) { + if (sample.l > 1.0) sample.l = 1.0; + else if (sample.l < -1.0) sample.l = -1.0; + + if (sample.r > 1.0) sample.r = 1.0; + else if (sample.r < -1.0) sample.r = -1.0; + + data.writeFloat(sample.l); + data.writeFloat(sample.r); + + sample.l = sample.r = 0.0; + sample = sample.next; + } + } + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/deltamusic/D1Player.as b/Flod 4.1/neoart/flod/deltamusic/D1Player.as new file mode 100644 index 0000000..6139a01 --- /dev/null +++ b/Flod 4.1/neoart/flod/deltamusic/D1Player.as @@ -0,0 +1,456 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.deltamusic { + import flash.utils.*; + import neoart.flod.core.*; + + public final class D1Player extends AmigaPlayer { + private var + pointers : Vector., + tracks : Vector., + patterns : Vector., + samples : Vector., + voices : Vector.; + + public function D1Player(amiga:Amiga = null) { + super(amiga); + PERIODS.fixed = true; + + samples = new Vector.(21, true); + voices = new Vector.(4, true); + + voices[0] = new D1Voice(0); + voices[0].next = voices[1] = new D1Voice(1); + voices[1].next = voices[2] = new D1Voice(2); + voices[2].next = voices[3] = new D1Voice(3); + } + + override public function process():void { + var adsr:int, chan:AmigaChannel, loop:int, row:AmigaRow, sample:D1Sample, value:int, voice:D1Voice = voices[0]; + + while (voice) { + chan = voice.channel; + + if (--voice.speed == 0) { + voice.speed = speed; + + if (voice.patternPos == 0) { + voice.step = tracks[int(pointers[voice.index] + voice.trackPos)]; + + if (voice.step.pattern < 0) { + voice.trackPos = voice.step.transpose; + voice.step = tracks[int(pointers[voice.index] + voice.trackPos)]; + } + voice.trackPos++; + } + + row = patterns[int(voice.step.pattern + voice.patternPos)]; + if (row.effect) voice.row = row; + + if (row.note) { + chan.enabled = 0; + voice.row = row; + voice.note = row.note + voice.step.transpose; + voice.arpeggioPos = voice.pitchBend = voice.status = 0; + + sample = voice.sample = samples[row.sample]; + if (!sample.synth) chan.pointer = sample.pointer; + chan.length = sample.length; + + voice.tableCtr = voice.tablePos = 0; + voice.vibratoCtr = sample.vibratoWait; + voice.vibratoPos = sample.vibratoLen; + voice.vibratoDir = sample.vibratoLen << 1; + voice.volume = voice.attackCtr = voice.decayCtr = voice.releaseCtr = 0; + voice.sustain = sample.sustain; + } + if (++voice.patternPos == 16) voice.patternPos = 0; + } + sample = voice.sample; + + if (sample.synth) { + if (voice.tableCtr == 0) { + voice.tableCtr = sample.tableDelay; + + do { + loop = 1; + if (voice.tablePos >= 48) voice.tablePos = 0; + value = sample.table[voice.tablePos]; + voice.tablePos++; + + if (value >= 0) { + chan.pointer = sample.pointer + (value << 5); + loop = 0; + } else if (value != -1) { + sample.tableDelay = value & 127; + } else { + voice.tablePos = sample.table[voice.tablePos]; + } + } while (loop); + } else + voice.tableCtr--; + } + + if (sample.portamento) { + value = PERIODS[voice.note] + voice.pitchBend; + + if (voice.period != 0) { + if (voice.period < value) { + voice.period += sample.portamento; + if (voice.period > value) voice.period = value; + } else { + voice.period -= sample.portamento; + if (voice.period < value) voice.period = value; + } + } else + voice.period = value; + } + + if (voice.vibratoCtr == 0) { + voice.vibratoPeriod = voice.vibratoPos * sample.vibratoStep; + + if ((voice.status & 1) == 0) { + voice.vibratoPos++; + if (voice.vibratoPos == voice.vibratoDir) voice.status ^= 1; + } else { + voice.vibratoPos--; + if (voice.vibratoPos == 0) voice.status ^= 1; + } + } else { + voice.vibratoCtr--; + } + + if (sample.pitchBend < 0) voice.pitchBend += sample.pitchBend; + else voice.pitchBend -= sample.pitchBend; + + if (voice.row) { + row = voice.row; + + switch (row.effect) { + case 0: + break; + case 1: + value = row.param & 15; + if (value) speed = value; + break; + case 2: + voice.pitchBend -= row.param; + break; + case 3: + voice.pitchBend += row.param; + break; + case 4: + amiga.filter.active = row.param; + break; + case 5: + sample.vibratoWait = row.param; + break; + case 6: + sample.vibratoStep = row.param; + case 7: + sample.vibratoLen = row.param; + break; + case 8: + sample.pitchBend = row.param; + break; + case 9: + sample.portamento = row.param; + break; + case 10: + value = row.param; + if (value > 64) value = 64; + sample.volume = 64; + break; + case 11: + sample.arpeggio[0] = row.param; + break; + case 12: + sample.arpeggio[1] = row.param; + break; + case 13: + sample.arpeggio[2] = row.param; + break; + case 14: + sample.arpeggio[3] = row.param; + break; + case 15: + sample.arpeggio[4] = row.param; + break; + case 16: + sample.arpeggio[5] = row.param; + break; + case 17: + sample.arpeggio[6] = row.param; + break; + case 18: + sample.arpeggio[7] = row.param; + break; + case 19: + sample.arpeggio[0] = sample.arpeggio[4] = row.param; + break; + case 20: + sample.arpeggio[1] = sample.arpeggio[5] = row.param; + break; + case 21: + sample.arpeggio[2] = sample.arpeggio[6] = row.param; + break; + case 22: + sample.arpeggio[3] = sample.arpeggio[7] = row.param; + break; + case 23: + value = row.param; + if (value > 64) value = 64; + sample.attackStep = value; + break; + case 24: + sample.attackDelay = row.param; + break; + case 25: + value = row.param; + if (value > 64) value = 64; + sample.decayStep = value; + break; + case 26: + sample.decayDelay = row.param; + break; + case 27: + sample.sustain = row.param & (sample.sustain & 255); + break; + case 28: + sample.sustain = (sample.sustain & 65280) + row.param; + break; + case 29: + value = row.param; + if (value > 64) value = 64; + sample.releaseStep = value; + break; + case 30: + sample.releaseDelay = row.param; + break; + } + } + + if (sample.portamento) + value = voice.period; + else { + value = PERIODS[int(voice.note + sample.arpeggio[voice.arpeggioPos])]; + voice.arpeggioPos = ++voice.arpeggioPos & 7; + value -= (sample.vibratoLen * sample.vibratoStep); + value += voice.pitchBend; + voice.period = 0; + } + + chan.period = value + voice.vibratoPeriod; + adsr = voice.status & 14; + value = voice.volume; + + if (adsr == 0) { + if (voice.attackCtr == 0) { + voice.attackCtr = sample.attackDelay; + value += sample.attackStep; + + if (value >= 64) { + adsr |= 2; + voice.status |= 2; + value = 64; + } + } else { + voice.attackCtr--; + } + } + + if (adsr == 2) { + if (voice.decayCtr == 0) { + voice.decayCtr = sample.decayDelay; + value -= sample.decayStep; + + if (value <= sample.volume) { + adsr |= 6; + voice.status |= 6; + value = sample.volume; + } + } else { + voice.decayCtr--; + } + } + + if (adsr == 6) { + if (voice.sustain == 0) { + adsr |= 14; + voice.status |= 14; + } else { + voice.sustain--; + } + } + + if (adsr == 14) { + if (voice.releaseCtr == 0) { + voice.releaseCtr = sample.releaseDelay; + value -= sample.releaseStep; + + if (value < 0) { + voice.status &= 9; + value = 0; + } + } else { + voice.releaseCtr--; + } + } + + chan.volume = voice.volume = value; + chan.enabled = 1; + + if (!sample.synth) { + if (sample.loop) { + chan.pointer = sample.loopPtr; + chan.length = sample.repeat; + } else { + chan.pointer = amiga.loopPtr; + chan.length = 2; + } + } + voice = voice.next; + } + } + + override protected function initialize():void { + var voice:D1Voice = voices[0]; + super.initialize(); + + speed = 6; + + while (voice) { + voice.initialize(); + voice.channel = amiga.channels[voice.index]; + voice.sample = samples[20]; + voice = voice.next; + } + } + + override protected function loader(stream:ByteArray):void { + var data:Vector., i:int, id:String, index:int, j:int, len:int, position:int, row:AmigaRow, sample:D1Sample, step:AmigaStep, value:int; + id = stream.readMultiByte(4, ENCODING); + if (id != "ALL ") return; + + position = 104; + data = new Vector.(25 ,true); + for (i = 0; i < 25; ++i) data[i] = stream.readUnsignedInt(); + + pointers = new Vector.(4, true); + for (i = 1; i < 4; ++i) + pointers[i] = pointers[j] + (data[j++] >> 1) - 1; + + len = pointers[3] + (data[3] >> 1) - 1; + tracks = new Vector.(len, true); + index = position + data[1] - 2; + stream.position = position; + j = 1; + + for (i = 0; i < len; ++i) { + step = new AmigaStep(); + value = stream.readUnsignedShort(); + + if (value == 0xffff || stream.position == index) { + step.pattern = -1; + step.transpose = stream.readUnsignedShort(); + index += data[j++]; + } else { + stream.position--; + step.pattern = ((value >> 2) & 0x3fc0) >> 2; + step.transpose = stream.readByte(); + } + tracks[i] = step; + } + + len = data[4] >> 2; + patterns = new Vector.(len, true); + + for (i = 0; i < len; ++i) { + row = new AmigaRow(); + row.sample = stream.readUnsignedByte(); + row.note = stream.readUnsignedByte(); + row.effect = stream.readUnsignedByte() & 31; + row.param = stream.readUnsignedByte(); + patterns[i] = row; + } + + index = 5; + + for (i = 0; i < 20; ++i) { + samples[i] = null; + + if (data[index] != 0) { + sample = new D1Sample(); + sample.attackStep = stream.readUnsignedByte(); + sample.attackDelay = stream.readUnsignedByte(); + sample.decayStep = stream.readUnsignedByte(); + sample.decayDelay = stream.readUnsignedByte(); + sample.sustain = stream.readUnsignedShort(); + sample.releaseStep = stream.readUnsignedByte(); + sample.releaseDelay = stream.readUnsignedByte(); + sample.volume = stream.readUnsignedByte(); + sample.vibratoWait = stream.readUnsignedByte(); + sample.vibratoStep = stream.readUnsignedByte(); + sample.vibratoLen = stream.readUnsignedByte(); + sample.pitchBend = stream.readByte(); + sample.portamento = stream.readUnsignedByte(); + sample.synth = stream.readUnsignedByte(); + sample.tableDelay = stream.readUnsignedByte(); + + for (j = 0; j < 8; ++j) + sample.arpeggio[j] = stream.readByte(); + + sample.length = stream.readUnsignedShort(); + sample.loop = stream.readUnsignedShort(); + sample.repeat = stream.readUnsignedShort() << 1; + sample.synth = sample.synth ? 0 : 1; + + if (sample.synth) { + for (j = 0; j < 48; ++j) + sample.table[j] = stream.readByte(); + + len = data[index] - 78; + } else { + len = sample.length; + } + + sample.pointer = amiga.store(stream, len); + sample.loopPtr = sample.pointer + sample.loop; + samples[i] = sample; + } + index++; + } + + sample = new D1Sample(); + sample.pointer = sample.loopPtr = amiga.memory.length; + sample.length = sample.repeat = 2; + samples[20] = sample; + version = 1; + } + + private const + PERIODS:Vector. = Vector.([ + 0000,6848,6464,6096,5760,5424,5120,4832,4560,4304,4064,3840, + 3616,3424,3232,3048,2880,2712,2560,2416,2280,2152,2032,1920, + 1808,1712,1616,1524,1440,1356,1280,1208,1140,1076,0960,0904, + 0856,0808,0762,0720,0678,0640,0604,0570,0538,0508,0480,0452, + 0428,0404,0381,0360,0339,0320,0302,0285,0269,0254,0240,0226, + 0214,0202,0190,0180,0170,0160,0151,0143,0135,0127,0120,0113, + 0113,0113,0113,0113,0113,0113,0113,0113,0113,0113,0113,0113]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/deltamusic/D1Sample.as b/Flod 4.1/neoart/flod/deltamusic/D1Sample.as new file mode 100644 index 0000000..72a6418 --- /dev/null +++ b/Flod 4.1/neoart/flod/deltamusic/D1Sample.as @@ -0,0 +1,45 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.deltamusic { + import neoart.flod.core.*; + + public final class D1Sample extends AmigaSample { + internal var + synth : int, + attackStep : int, + attackDelay : int, + decayStep : int, + decayDelay : int, + releaseStep : int, + releaseDelay : int, + sustain : int, + arpeggio : Vector., + pitchBend : int, + portamento : int, + table : Vector., + tableDelay : int, + vibratoWait : int, + vibratoStep : int, + vibratoLen : int; + + public function D1Sample() { + arpeggio = new Vector.( 8, true); + table = new Vector.(48, true); + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/deltamusic/D1Voice.as b/Flod 4.1/neoart/flod/deltamusic/D1Voice.as new file mode 100644 index 0000000..f99e29c --- /dev/null +++ b/Flod 4.1/neoart/flod/deltamusic/D1Voice.as @@ -0,0 +1,78 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.deltamusic { + import neoart.flod.core.*; + + public final class D1Voice { + internal var + index : int, + next : D1Voice, + channel : AmigaChannel, + sample : D1Sample, + trackPos : int, + patternPos : int, + status : int, + speed : int, + step : AmigaStep, + row : AmigaRow, + note : int, + period : int, + arpeggioPos : int, + pitchBend : int, + tableCtr : int, + tablePos : int, + vibratoCtr : int, + vibratoDir : int, + vibratoPos : int, + vibratoPeriod : int, + volume : int, + attackCtr : int, + decayCtr : int, + releaseCtr : int, + sustain : int; + + public function D1Voice(index:int) { + this.index = index; + } + + internal function initialize():void { + sample = null; + trackPos = 0; + patternPos = 0; + status = 0; + speed = 1; + step = null; + row = null; + note = 0; + period = 0; + arpeggioPos = 0; + pitchBend = 0; + tableCtr = 0; + tablePos = 0; + vibratoCtr = 0; + vibratoDir = 0; + vibratoPos = 0; + vibratoPeriod = 0; + volume = 0; + attackCtr = 0; + decayCtr = 0; + releaseCtr = 0; + sustain = 1; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/deltamusic/D2Player.as b/Flod 4.1/neoart/flod/deltamusic/D2Player.as new file mode 100644 index 0000000..c20c0bb --- /dev/null +++ b/Flod 4.1/neoart/flod/deltamusic/D2Player.as @@ -0,0 +1,399 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/30 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.deltamusic { + import flash.utils.*; + import neoart.flod.core.*; + + public final class D2Player extends AmigaPlayer { + private var + tracks : Vector., + patterns : Vector., + samples : Vector., + data : Vector., + arpeggios : Vector., + voices : Vector., + noise : uint; + + public function D2Player(amiga:Amiga = null) { + super(amiga); + PERIODS.fixed = true; + + arpeggios = new Vector.(1024, true); + voices = new Vector.(4, true); + + voices[0] = new D2Voice(0); + voices[0].next = voices[1] = new D2Voice(1); + voices[1].next = voices[2] = new D2Voice(2); + voices[2].next = voices[3] = new D2Voice(3); + } + + override public function process():void { + var chan:AmigaChannel, i:int = 0, level:int, row:AmigaRow, sample:D2Sample, value:int, voice:D2Voice = voices[0]; + + for (; i < 64;) { + this.noise = (this.noise << 7) | (this.noise >>> 25); + this.noise += 0x6eca756d; + this.noise ^= 0x9e59a92b; + + value = (this.noise >>> 24) & 255; + if (value > 127) value |= -256; + amiga.memory[i++] = value; + + value = (this.noise >>> 16) & 255; + if (value > 127) value |= -256; + amiga.memory[i++] = value; + + value = (this.noise >>> 8) & 255; + if (value > 127) value |= -256; + amiga.memory[i++] = value; + + value = this.noise & 255; + if (value > 127) value |= -256; + amiga.memory[i++] = value; + } + + if (--this.tick < 0) this.tick = this.speed; + + while (voice) { + if (voice.trackLen < 1) { + voice = voice.next; + continue; + } + + chan = voice.channel; + sample = voice.sample; + + if (sample.synth) { + chan.pointer = sample.loopPtr; + chan.length = sample.repeat; + } + + if (this.tick == 0) { + if (voice.patternPos == 0) { + voice.step = tracks[int(voice.trackPtr + voice.trackPos)]; + + if (++voice.trackPos == voice.trackLen) + voice.trackPos = voice.restart; + } + row = voice.row = patterns[int(voice.step.pattern + voice.patternPos)]; + + if (row.note) { + chan.enabled = 0; + voice.note = row.note; + voice.period = PERIODS[int(row.note + voice.step.transpose)]; + + sample = voice.sample = samples[row.sample]; + + if (sample.synth < 0) { + chan.pointer = sample.pointer; + chan.length = sample.length; + } + + voice.arpeggioPos = 0; + voice.tableCtr = 0; + voice.tablePos = 0; + voice.vibratoCtr = sample.vibratos[1]; + voice.vibratoPos = 0; + voice.vibratoDir = 0; + voice.vibratoPeriod = 0; + voice.vibratoSustain = sample.vibratos[2]; + voice.volume = 0; + voice.volumePos = 0; + voice.volumeSustain = 0; + } + + switch (row.effect) { + case -1: + break; + case 0: + speed = row.param & 15; + break; + case 1: + amiga.filter.active = row.param; + break; + case 2: + voice.pitchBend = ~(row.param & 255) + 1; + break; + case 3: + voice.pitchBend = row.param & 255; + break; + case 4: + voice.portamento = row.param; + break; + case 5: + voice.volumeMax = row.param & 63; + break; + case 6: + amiga.volume = row.param; + break; + case 7: + voice.arpeggioPtr = (row.param & 63) << 4; + break; + } + voice.patternPos = ++voice.patternPos & 15; + } + sample = voice.sample; + + if (sample.synth >= 0) { + if (voice.tableCtr) { + voice.tableCtr--; + } else { + voice.tableCtr = sample.index; + value = sample.table[voice.tablePos]; + + if (value == 0xff) { + value = sample.table[++voice.tablePos]; + if (value != 0xff) { + voice.tablePos = value; + value = sample.table[voice.tablePos]; + } + } + + if (value != 0xff) { + chan.pointer = value << 8; + chan.length = sample.length; + if (++voice.tablePos > 47) voice.tablePos = 0; + } + } + } + value = sample.vibratos[voice.vibratoPos]; + + if (voice.vibratoDir) voice.vibratoPeriod -= value; + else voice.vibratoPeriod += value; + + if (--voice.vibratoCtr == 0) { + voice.vibratoCtr = sample.vibratos[int(voice.vibratoPos + 1)]; + voice.vibratoDir = ~voice.vibratoDir; + } + + if (voice.vibratoSustain) { + voice.vibratoSustain--; + } else { + voice.vibratoPos += 3; + if (voice.vibratoPos == 15) voice.vibratoPos = 12; + voice.vibratoSustain = sample.vibratos[int(voice.vibratoPos + 2)]; + } + + if (voice.volumeSustain) { + voice.volumeSustain--; + } else { + value = sample.volumes[voice.volumePos]; + level = sample.volumes[int(voice.volumePos + 1)]; + + if (level < voice.volume) { + voice.volume -= value; + if (voice.volume < level) { + voice.volume = level; + voice.volumePos += 3; + voice.volumeSustain = sample.volumes[int(voice.volumePos - 1)]; + } + } else { + voice.volume += value; + if (voice.volume > level) { + voice.volume = level; + voice.volumePos += 3; + if (voice.volumePos == 15) voice.volumePos = 12; + voice.volumeSustain = sample.volumes[int(voice.volumePos - 1)]; + } + } + } + + if (voice.portamento) { + if (voice.period < voice.finalPeriod) { + voice.finalPeriod -= voice.portamento; + if (voice.finalPeriod < voice.period) voice.finalPeriod = voice.period; + } else { + voice.finalPeriod += voice.portamento; + if (voice.finalPeriod > voice.period) voice.finalPeriod = voice.period; + } + } + value = arpeggios[int(voice.arpeggioPtr + voice.arpeggioPos)]; + + if (value == -128) { + voice.arpeggioPos = 0; + value = arpeggios[voice.arpeggioPtr] + } + voice.arpeggioPos = ++voice.arpeggioPos & 15; + + if (voice.portamento == 0) { + value = voice.note + voice.step.transpose + value; + if (value < 0) value = 0; + voice.finalPeriod = PERIODS[value]; + } + + voice.vibratoPeriod -= (sample.pitchBend - voice.pitchBend); + chan.period = voice.finalPeriod + voice.vibratoPeriod; + + value = (voice.volume >> 2) & 63; + if (value > voice.volumeMax) value = voice.volumeMax; + chan.volume = value; + chan.enabled = 1; + + voice = voice.next; + } + } + + override protected function initialize():void { + var voice:D2Voice = voices[0]; + super.initialize(); + + speed = 5; + tick = 1; + noise = 0; + + while (voice) { + voice.initialize(); + voice.channel = amiga.channels[voice.index]; + voice.sample = samples[int(samples.length - 1)]; + + voice.trackPtr = data[voice.index]; + voice.restart = data[int(voice.index + 4)]; + voice.trackLen = data[int(voice.index + 8)]; + + voice = voice.next; + } + } + + override protected function loader(stream:ByteArray):void { + var i:int, id:String, j:int, len:int, offsets:Vector., position:int, row:AmigaRow, sample:D2Sample, step:AmigaStep, value:int; + stream.position = 3014; + id = stream.readMultiByte(4, ENCODING); + if (id != ".FNL") return; + + stream.position = 4042; + data = new Vector.(12, true); + + for (i = 0; i < 4; ++i) { + data[int(i + 4)] = stream.readUnsignedShort() >> 1; + value = stream.readUnsignedShort() >> 1; + data[int(i + 8)] = value; + len += value; + } + + value = len; + for (i = 3; i > 0; --i) data[i] = (value -= data[int(i + 8)]); + tracks = new Vector.(len, true); + + for (i = 0; i < len; ++i) { + step = new AmigaStep(); + step.pattern = stream.readUnsignedByte() << 4; + step.transpose = stream.readByte(); + tracks[i] = step; + } + + len = stream.readUnsignedInt() >> 2; + patterns = new Vector.(len, true); + + for (i = 0; i < len; ++i) { + row = new AmigaRow(); + row.note = stream.readUnsignedByte(); + row.sample = stream.readUnsignedByte(); + row.effect = stream.readUnsignedByte() - 1; + row.param = stream.readUnsignedByte(); + patterns[i] = row; + } + + stream.position += 254; + value = stream.readUnsignedShort(); + position = stream.position; + stream.position -= 256; + + len = 1; + offsets = new Vector.(128, true); + + for (i = 0; i < 128; ++i) { + j = stream.readUnsignedShort(); + if (j != value) offsets[len++] = j; + } + + samples = new Vector.(len); + + for (i = 0; i < len; ++i) { + stream.position = position + offsets[i]; + sample = new D2Sample(); + sample.length = stream.readUnsignedShort() << 1; + sample.loop = stream.readUnsignedShort(); + sample.repeat = stream.readUnsignedShort() << 1; + + for (j = 0; j < 15; ++j) + sample.volumes[j] = stream.readUnsignedByte(); + for (j = 0; j < 15; ++j) + sample.vibratos[j] = stream.readUnsignedByte(); + + sample.pitchBend = stream.readUnsignedShort(); + sample.synth = stream.readByte(); + sample.index = stream.readUnsignedByte(); + + for (j = 0; j < 48; ++j) + sample.table[j] = stream.readUnsignedByte(); + + samples[i] = sample; + } + + len = stream.readUnsignedInt(); + amiga.store(stream, len); + + stream.position += 64; + for (i = 0; i < 8; ++i) + offsets[i] = stream.readUnsignedInt(); + + len = samples.length; + position = stream.position; + + for (i = 0; i < len; ++i) { + sample = samples[i]; + if (sample.synth >= 0) continue; + stream.position = position + offsets[sample.index]; + sample.pointer = amiga.store(stream, sample.length); + sample.loopPtr = sample.pointer + sample.loop; + } + + stream.position = 3018; + for (i = 0; i < 1024; ++i) + arpeggios[i] = stream.readByte(); + + sample = new D2Sample(); + sample.pointer = sample.loopPtr = amiga.memory.length; + sample.length = sample.repeat = 2; + + samples[len] = sample; + samples.fixed = true; + + len = patterns.length; + j = samples.length - 1; + + for (i = 0; i < len; ++i) { + row = patterns[i]; + if (row.sample > j) row.sample = 0; + } + + version = 2; + } + + private const + PERIODS: Vector. = Vector.([ + 0,6848,6464,6096,5760,5424,5120,4832,4560,4304,4064,3840, + 3616,3424,3232,3048,2880,2712,2560,2416,2280,2152,2032,1920, + 1808,1712,1616,1524,1440,1356,1280,1208,1140,1076,1016, 960, + 904, 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, + 452, 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, + 226, 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 113]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/deltamusic/D2Sample.as b/Flod 4.1/neoart/flod/deltamusic/D2Sample.as new file mode 100644 index 0000000..d70e73c --- /dev/null +++ b/Flod 4.1/neoart/flod/deltamusic/D2Sample.as @@ -0,0 +1,36 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.deltamusic { + import neoart.flod.core.*; + + public final class D2Sample extends AmigaSample { + internal var + index : int, + pitchBend : int, + synth : int, + table : Vector., + vibratos : Vector., + volumes : Vector.; + + public function D2Sample() { + table = new Vector.(48, true); + vibratos = new Vector.(15, true); + volumes = new Vector.(15, true); + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/deltamusic/D2Voice.as b/Flod 4.1/neoart/flod/deltamusic/D2Voice.as new file mode 100644 index 0000000..163e198 --- /dev/null +++ b/Flod 4.1/neoart/flod/deltamusic/D2Voice.as @@ -0,0 +1,86 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.deltamusic { + import neoart.flod.core.*; + + public final class D2Voice { + internal var + index : int, + next : D2Voice, + channel : AmigaChannel, + sample : D2Sample, + trackPtr : int, + trackPos : int, + trackLen : int, + patternPos : int, + restart : int, + step : AmigaStep, + row : AmigaRow, + note : int, + period : int, + finalPeriod : int, + arpeggioPtr : int, + arpeggioPos : int, + pitchBend : int, + portamento : int, + tableCtr : int, + tablePos : int, + vibratoCtr : int, + vibratoDir : int, + vibratoPos : int, + vibratoPeriod : int, + vibratoSustain : int, + volume : int, + volumeMax : int, + volumePos : int, + volumeSustain : int; + + public function D2Voice(index:int) { + this.index = index; + } + + internal function initialize():void { + sample = null; + trackPtr = 0; + trackPos = 0; + trackLen = 0; + patternPos = 0; + restart = 0; + step = null; + row = null; + note = 0; + period = 0; + finalPeriod = 0; + arpeggioPtr = 0; + arpeggioPos = 0; + pitchBend = 0; + portamento = 0; + tableCtr = 0; + tablePos = 0; + vibratoCtr = 0; + vibratoDir = 0; + vibratoPos = 0; + vibratoPeriod = 0; + vibratoSustain = 0; + volume = 0; + volumeMax = 63; + volumePos = 0; + volumeSustain = 0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/digitalmugician/DMPlayer.as b/Flod 4.1/neoart/flod/digitalmugician/DMPlayer.as new file mode 100644 index 0000000..1a0dbb8 --- /dev/null +++ b/Flod 4.1/neoart/flod/digitalmugician/DMPlayer.as @@ -0,0 +1,851 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/10 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.digitalmugician { + import flash.utils.*; + import neoart.flod.core.*; + + public final class DMPlayer extends AmigaPlayer { + private var + songs : Vector., + patterns : Vector., + samples : Vector., + voices : Vector., + buffer1 : int, + buffer2 : int, + song1 : DMSong, + song2 : DMSong, + trackPos : int, + patternPos : int, + patternLen : int, + patternEnd : int, + stepEnd : int, + numChannels : int, + arpeggios : Vector., + averages : Vector., + volumes : Vector., + mixChannel : AmigaChannel, + mixPeriod : int; + + public function DMPlayer(amiga:Amiga = null) { + super(amiga); + PERIODS.fixed = true; + + songs = new Vector.(8, true); + arpeggios = new Vector.(256, true); + voices = new Vector.(7, true); + + voices[0] = new DMVoice(); + voices[1] = new DMVoice(); + voices[2] = new DMVoice(); + voices[3] = new DMVoice(); + voices[4] = new DMVoice(); + voices[5] = new DMVoice(); + voices[6] = new DMVoice(); + tables(); + } + + override public function process():void { + var chan:AmigaChannel, dst:int, i:int, idx:int, j:int, len:int, memory:Vector. = amiga.memory, r:int, row:AmigaRow, src1:int, src2:int, sample:DMSample, value:int, voice:DMVoice; + + for (i = 0; i < numChannels; ++i) { + voice = voices[i]; + sample = voice.sample; + + if (i < 3 || numChannels == 4) { + chan = voice.channel; + if (stepEnd) voice.step = song1.tracks[int(trackPos + i)]; + + if (sample.wave > 31) { + chan.pointer = sample.loopPtr; + chan.length = sample.repeat; + } + } else { + chan = mixChannel; + if (stepEnd) voice.step = song2.tracks[int(trackPos + (i - 3))]; + } + + if (patternEnd) { + row = patterns[int(voice.step.pattern + patternPos)]; + + if (row.note) { + if (row.effect != 74) { + voice.note = row.note; + if (row.sample) sample = voice.sample = samples[row.sample]; + } + voice.val1 = row.effect < 64 ? 1 : row.effect - 62; + voice.val2 = row.param; + idx = voice.step.transpose + sample.finetune; + + if (voice.val1 != 12) { + voice.pitch = row.effect; + + if (voice.val1 == 1) { + idx += voice.pitch; + if (idx < 0) voice.period = 0; + else voice.period = PERIODS[idx]; + } + } else { + voice.pitch = row.note; + idx += voice.pitch; + + if (idx < 0) voice.period = 0; + else voice.period = PERIODS[idx]; + } + + if (voice.val1 == 11) sample.arpeggio = voice.val2 & 7; + + if (voice.val1 != 12) { + if (sample.wave > 31) { + chan.pointer = sample.pointer; + chan.length = sample.length; + chan.enabled = 0; + voice.mixPtr = sample.pointer; + voice.mixEnd = sample.pointer + sample.length; + voice.mixMute = 0; + } else { + dst = sample.wave << 7; + chan.pointer = dst; + chan.length = sample.waveLen; + if (voice.val1 != 10) chan.enabled = 0; + + if (numChannels == 4) { + if (sample.effect != 0 && voice.val1 != 2 && voice.val1 != 4) { + len = dst + 128; + src1 = sample.source1 << 7; + for (j = dst; j < len; ++j) memory[j] = memory[src1++]; + + sample.effectStep = 0; + voice.effectCtr = sample.effectSpeed; + } + } + } + } + + if (voice.val1 != 3 && voice.val1 != 4 && voice.val1 != 12) { + voice.volumeCtr = 1; + voice.volumeStep = 0; + } + + voice.arpeggioStep = 0; + voice.pitchCtr = sample.pitchDelay; + voice.pitchStep = 0; + voice.portamento = 0; + } + } + + switch (voice.val1) { + case 0: + break; + case 5: //pattern length + value = voice.val2; + if (value > 0 && value < 65) patternLen = value; + break; + case 6: //song speed + value = voice.val2 & 15; + value |= value << 4; + if (voice.val2 == 0 || voice.val2 > 15) break; + speed = value; + break; + case 7: //led filter on + amiga.filter.active = 1; + break; + case 8: //led filter off + amiga.filter.active = 0; + break; + case 13: //shuffle + voice.val1 = 0; + value = voice.val2 & 0x0f; + if (value == 0) break; + value = voice.val2 & 0xf0; + if (value == 0) break; + speed = voice.val2; + break; + } + } + + for (i = 0; i < numChannels; ++i) { + voice = voices[i]; + sample = voice.sample; + + if (numChannels == 4) { + chan = voice.channel; + + if (sample.wave < 32 && sample.effect && !sample.effectDone) { + sample.effectDone = 1; + + if (voice.effectCtr) { + voice.effectCtr--; + } else { + voice.effectCtr = sample.effectSpeed; + dst = sample.wave << 7; + + switch (sample.effect) { + case 1: //filter + for (j = 0; j < 127; ++j) { + value = memory[dst]; + value += memory[int(dst + 1)]; + memory[dst++] = value >> 1; + } + break; + case 2: //mixing + src1 = sample.source1 << 7; + src2 = sample.source2 << 7; + idx = sample.effectStep; + len = sample.waveLen; + sample.effectStep = ++sample.effectStep & 127; + + for (j = 0; j < len; ++j) { + value = memory[src1++]; + value += memory[int(src2 + idx)]; + memory[dst++] = value >> 1; + idx = ++idx & 127; + } + break; + case 3: //scr left + value = memory[dst]; + for (j = 0; j < 127; ++j) memory[dst] = memory[++dst]; + memory[dst] = value; + break; + case 4: //scr right + dst += 127; + value = memory[dst]; + for (j = 0; j < 127; ++j) memory[dst] = memory[--dst]; + memory[dst] = value; + break; + case 5: //upsample + idx = value = dst; + for (j = 0; j < 64; ++j) { + memory[idx++] = memory[dst++]; + dst++; + } + idx = dst = value; + idx += 64; + for (j = 0; j < 64; ++j) memory[idx++] = memory[dst++]; + break; + case 6: //downsample + src1 = dst + 64; + dst += 128; + for (j = 0; j < 64; ++j) { + memory[--dst] = memory[--src1]; + memory[--dst] = memory[src1]; + } + break; + case 7: //negate + dst += sample.effectStep; + memory[dst] = ~memory[dst] + 1; + if (++sample.effectStep >= sample.waveLen) sample.effectStep = 0; + break; + case 8: //madmix 1 + sample.effectStep = ++sample.effectStep & 127; + src2 = (sample.source2 << 7) + sample.effectStep; + idx = memory[src2]; + len = sample.waveLen; + value = 3; + + for (j = 0; j < len; ++j) { + src1 = memory[dst] + value; + if (src1 < -128) src1 += 256; + else if (src1 > 127) src1 -= 256; + + memory[dst++] = src1; + value += idx; + + if (value < -128) value += 256; + else if (value > 127) value -= 256; + } + break; + case 9: //addition + src2 = sample.source2 << 7; + len = sample.waveLen; + + for (j = 0; j < len; ++j) { + value = memory[src2++]; + value += memory[dst]; + if (value > 127) value -= 256; + memory[dst++] = value; + } + break; + case 10: //filter 2 + for (j = 0; j < 126; ++j) { + value = memory[dst++] * 3; + value += memory[int(dst + 1)]; + memory[dst] = value >> 2; + } + break; + case 11: //morphing + src1 = sample.source1 << 7; + src2 = sample.source2 << 7; + len = sample.waveLen; + + sample.effectStep = ++sample.effectStep & 127; + value = sample.effectStep; + if (value >= 64) value = 127 - value; + idx = (value ^ 255) & 63; + + for (j = 0; j < len; ++j) { + r = memory[src1++] * value; + r += memory[src2++] * idx; + memory[dst++] = r >> 6; + } + break; + case 12: //morph f + src1 = sample.source1 << 7; + src2 = sample.source2 << 7; + len = sample.waveLen; + + sample.effectStep = ++sample.effectStep & 31; + value = sample.effectStep; + if (value >= 16) value = 31 - value; + idx = (value ^ 255) & 15; + + for (j = 0; j < len; ++j) { + r = memory[src1++] * value; + r += memory[src2++] * idx; + memory[dst++] = r >> 4; + } + break; + case 13: //filter 3 + for (j = 0; j < 126; ++j) { + value = memory[dst++]; + value += memory[int(dst + 1)]; + memory[dst] = value >> 1; + } + break; + case 14: //polygate + idx = dst + sample.effectStep; + memory[idx] = ~memory[idx] + 1; + idx = (sample.effectStep + sample.source2) & (sample.waveLen - 1); + idx += dst; + memory[idx] = ~memory[idx] + 1; + if (++sample.effectStep >= sample.waveLen) sample.effectStep = 0; + break; + case 15: //colgate + idx = dst; + for (j = 0; j < 127; ++j) { + value = memory[dst]; + value += memory[int(dst + 1)]; + memory[dst++] = value >> 1; + } + dst = idx; + sample.effectStep++; + + if (sample.effectStep == sample.source2) { + sample.effectStep = 0; + idx = value = dst; + + for (j = 0; j < 64; ++j) { + memory[idx++] = memory[dst++]; + dst++; + } + idx = dst = value; + idx += 64; + for (j = 0; j < 64; ++j) memory[idx++] = memory[dst++]; + } + break; + } + } + } + } else { + chan = (i < 3) ? voice.channel : this.mixChannel; + } + + if (voice.volumeCtr) { + voice.volumeCtr--; + + if (voice.volumeCtr == 0) { + voice.volumeCtr = sample.volumeSpeed; + voice.volumeStep = ++voice.volumeStep & 127; + + if (voice.volumeStep || sample.volumeLoop) { + idx = voice.volumeStep + (sample.volume << 7); + value = ~(memory[idx] + 129) + 1; + + voice.volume = (value & 255) >> 2; + chan.volume = voice.volume; + } else { + voice.volumeCtr = 0; + } + } + } + value = voice.note; + + if (sample.arpeggio) { + idx = voice.arpeggioStep + (sample.arpeggio << 5); + value += arpeggios[idx]; + voice.arpeggioStep = ++voice.arpeggioStep & 31; + } + + idx = value + voice.step.transpose + sample.finetune; + voice.finalPeriod = PERIODS[idx]; + dst = voice.finalPeriod; + + if (voice.val1 == 1 || voice.val1 == 12) { + value = ~voice.val2 + 1; + voice.portamento += value; + voice.finalPeriod += voice.portamento; + + if (voice.val2) { + if ((value < 0 && voice.finalPeriod <= voice.period) || (value >= 0 && voice.finalPeriod >= voice.period)) { + voice.portamento = voice.period - dst; + voice.val2 = 0; + } + } + } + + if (sample.pitch) { + if (voice.pitchCtr) { + voice.pitchCtr--; + } else { + idx = voice.pitchStep; + voice.pitchStep = ++voice.pitchStep & 127; + if (voice.pitchStep == 0) voice.pitchStep = sample.pitchLoop; + + idx += sample.pitch << 7; + value = memory[idx]; + voice.finalPeriod += (~value + 1); + } + } + chan.period = voice.finalPeriod; + } + + if (numChannels > 4) { + src1 = buffer1; + buffer1 = buffer2; + buffer2 = src1; + + chan = amiga.channels[3]; + chan.pointer = src1; + + for (i = 3; i < 7; ++i) { + voice = voices[i]; + voice.mixStep = 0; + + if (voice.finalPeriod < 125) { + voice.mixMute = 1; + voice.mixSpeed = 0; + } else { + j = ((voice.finalPeriod << 8) / mixPeriod) & 65535; + src2 = ((256 / j) & 255) << 8; + dst = ((256 % j) << 8) & 16777215; + voice.mixSpeed = (src2 | ((dst / j) & 255)) << 8; + } + + if (voice.mixMute) voice.mixVolume = 0; + else voice.mixVolume = voice.volume << 8; + } + + for (i = 0; i < 350; ++i) { + dst = 0; + + for (j = 3; j < 7; ++j) { + voice = voices[j]; + src2 = (memory[int(voice.mixPtr + (voice.mixStep >> 16))] & 255) + voice.mixVolume; + dst += volumes[src2]; + voice.mixStep += voice.mixSpeed; + } + + memory[src1++] = averages[dst]; + } + chan.length = 350; + chan.period = mixPeriod; + chan.volume = 64; + } + + if (--tick == 0) { + tick = speed & 15; + speed = (speed & 240) >> 4; + speed |= (tick << 4); + patternEnd = 1; + patternPos++; + + if (patternPos == 64 || patternPos == patternLen) { + patternPos = 0; + stepEnd = 1; + trackPos += 4; + + if (trackPos == song1.length) { + trackPos = song1.loopStep; + amiga.complete = 1; + } + } + } else { + patternEnd = 0; + stepEnd = 0; + } + + for (i = 0; i < numChannels; ++i) { + voice = voices[i]; + voice.mixPtr += voice.mixStep >> 16; + + sample = voice.sample; + sample.effectDone = 0; + + if (voice.mixPtr >= voice.mixEnd) { + if (sample.loop) { + voice.mixPtr -= sample.repeat; + } else { + voice.mixPtr = 0; + voice.mixMute = 1; + } + } + + if (i < 4) { + chan = voice.channel; + chan.enabled = 1; + } + } + } + + override protected function initialize():void { + var chan:AmigaChannel, i:int, len:int, voice:DMVoice; + super.initialize(); + + if (playSong > 7) playSong = 0; + + song1 = songs[playSong]; + speed = song1.speed & 0x0f; + speed |= speed << 4; + tick = song1.speed; + + trackPos = 0; + patternPos = 0; + patternLen = 64; + patternEnd = 1; + stepEnd = 1; + numChannels = 4; + + for (; i < 7; ++i) { + voice = voices[i]; + voice.initialize(); + voice.sample = samples[0]; + + if (i < 4) { + chan = amiga.channels[i]; + chan.enabled = 0; + chan.pointer = amiga.loopPtr; + chan.length = 2; + chan.period = 124; + chan.volume = 0; + + voice.channel = chan; + } + } + + if (version == DIGITALMUG_V2) { + if ((playSong & 1) != 0) playSong--; + song2 = songs[int(playSong + 1)]; + + mixChannel = new AmigaChannel(7); + numChannels = 7; + + chan = amiga.channels[3]; + chan.mute = 0; + chan.pointer = buffer1; + chan.length = 350; + chan.period = mixPeriod; + chan.volume = 64; + + len = buffer1 + 700; + for (i = buffer1; i < len; ++i) amiga.memory[i] = 0; + } + } + + override protected function loader(stream:ByteArray):void { + var data:int, i:int, id:String, index:Vector., instr:int, j:int, len:int, position:int, row:AmigaRow, sample:DMSample, song:DMSong, step:AmigaStep; + id = stream.readMultiByte(24, ENCODING); + + if (id == " MUGICIAN/SOFTEYES 1990 ") version = DIGITALMUG_V1; + else if (id == " MUGICIAN2/SOFTEYES 1990") version = DIGITALMUG_V2; + else return; + + stream.position = 28; + index = new Vector.(8, true); + for (; i < 8; ++i) index[i] = stream.readUnsignedInt(); + + stream.position = 76; + + for (i = 0; i < 8; ++i) { + song = new DMSong(); + song.loop = stream.readUnsignedByte(); + song.loopStep = stream.readUnsignedByte() << 2; + song.speed = stream.readUnsignedByte(); + song.length = stream.readUnsignedByte() << 2; + song.title = stream.readMultiByte(12, ENCODING); + songs[i] = song; + } + + stream.position = 204; + lastSong = songs.length - 1; + + for (i = 0; i < 8; ++i) { + song = songs[i]; + len = index[i] << 2; + + for (j = 0; j < len; ++j) { + step = new AmigaStep(); + step.pattern = stream.readUnsignedByte() << 6; + step.transpose = stream.readByte(); + song.tracks[j] = step; + } + song.tracks.fixed = true; + } + + position = stream.position; + stream.position = 60; + len = stream.readUnsignedInt(); + samples = new Vector.(++len, true); + stream.position = position; + + for (i = 1; i < len; ++i) { + sample = new DMSample(); + sample.wave = stream.readUnsignedByte(); + sample.waveLen = stream.readUnsignedByte() << 1; + sample.volume = stream.readUnsignedByte(); + sample.volumeSpeed = stream.readUnsignedByte(); + sample.arpeggio = stream.readUnsignedByte(); + sample.pitch = stream.readUnsignedByte(); + sample.effectStep = stream.readUnsignedByte(); + sample.pitchDelay = stream.readUnsignedByte(); + sample.finetune = stream.readUnsignedByte() << 6; + sample.pitchLoop = stream.readUnsignedByte(); + sample.pitchSpeed = stream.readUnsignedByte(); + sample.effect = stream.readUnsignedByte(); + sample.source1 = stream.readUnsignedByte(); + sample.source2 = stream.readUnsignedByte(); + sample.effectSpeed = stream.readUnsignedByte(); + sample.volumeLoop = stream.readUnsignedByte(); + samples[i] = sample; + } + samples[0] = samples[1]; + + position = stream.position; + stream.position = 64; + len = stream.readUnsignedInt() << 7; + stream.position = position; + amiga.store(stream, len); + + position = stream.position; + stream.position = 68; + instr = stream.readUnsignedInt(); + + stream.position = 26; + len = stream.readUnsignedShort() << 6; + patterns = new Vector.(len, true); + stream.position = position + (instr << 5); + + if (instr) instr = position; + + for (i = 0; i < len; ++i) { + row = new AmigaRow(); + row.note = stream.readUnsignedByte(); + row.sample = stream.readUnsignedByte() & 63; + row.effect = stream.readUnsignedByte(); + row.param = stream.readByte(); + patterns[i] = row; + } + + position = stream.position; + stream.position = 72; + + if (instr) { + len = stream.readUnsignedInt(); + stream.position = position; + data = amiga.store(stream, len); + position = stream.position; + + amiga.memory.length += 350; + buffer1 = amiga.memory.length; + amiga.memory.length += 350; + buffer2 = amiga.memory.length; + amiga.memory.length += 350; + amiga.loopLen = 8; + + len = samples.length; + + for (i = 1; i < len; ++i) { + sample = samples[i]; + if (sample.wave < 32) continue; + stream.position = instr + ((sample.wave - 32) << 5); + + sample.pointer = stream.readUnsignedInt(); + sample.length = stream.readUnsignedInt() - sample.pointer; + sample.loop = stream.readUnsignedInt(); + sample.name = stream.readMultiByte(12, ENCODING); + + if (sample.loop) { + sample.loop -= sample.pointer; + sample.repeat = sample.length - sample.loop; + if ((sample.repeat & 1) != 0) sample.repeat--; + } else { + sample.loopPtr = amiga.memory.length; + sample.repeat = 8; + } + + if ((sample.pointer & 1) != 0) sample.pointer--; + if ((sample.length & 1) != 0) sample.length--; + + sample.pointer += data; + if (!sample.loopPtr) sample.loopPtr = sample.pointer + sample.loop; + } + } else { + position += stream.readUnsignedInt(); + } + stream.position = 24; + + if (stream.readUnsignedShort() == 1) { + stream.position = position; + len = stream.length - stream.position; + if (len > 256) len = 256; + for (i = 0; i < len; ++i) arpeggios[i] = stream.readUnsignedByte(); + } + } + + private function tables():void { + var i:int, idx:int, j:int, pos:int, step:int, v1:int, v2:int, vol:int = 128; + + averages = new Vector.(1024, true); + volumes = new Vector.(16384, true); + mixPeriod = 203; + + for (; i < 1024; ++i) { + if (vol > 127) vol -= 256; + averages[i] = vol; + if (i > 383 && i < 639) vol = ++vol & 255; + } + + for (i = 0; i < 64; ++i) { + v1 = -128; + v2 = 128; + + for (j = 0; j < 256; ++j) { + vol = ((v1 * step) / 63) + 128; + idx = pos + v2; + volumes[idx] = vol & 255; + + if (i != 0 && i != 63 && v2 >= 128) --volumes[idx]; + v1++; + v2 = ++v2 & 255; + } + pos += 256; + step++; + } + } + + public static const + DIGITALMUG_V1 = 1, + DIGITALMUG_V2 = 2; + + private const + PERIODS: Vector. = Vector.([ + 3220,3040,2869,2708,2556,2412,2277,2149,2029,1915,1807,1706, + 1610,1520,1434,1354,1278,1206,1139,1075,1014, 957, 904, 853, + 805, 760, 717, 677, 639, 603, 569, 537, 507, 479, 452, 426, + 403, 380, 359, 338, 319, 302, 285, 269, 254, 239, 226, 213, + 201, 190, 179, 169, 160, 151, 142, 134, 127, + 4842,4571,4314,4072,3843,3628,3424,3232,3051,2879,2718,2565, + 2421,2285,2157,2036,1922,1814,1712,1616,1525,1440,1359,1283, + 1211,1143,1079,1018, 961, 907, 856, 808, 763, 720, 679, 641, + 605, 571, 539, 509, 480, 453, 428, 404, 381, 360, 340, 321, + 303, 286, 270, 254, 240, 227, 214, 202, 191, 180, 170, 160, + 151, 143, 135, 127, + 4860,4587,4330,4087,3857,3641,3437,3244,3062,2890,2728,2574, + 2430,2294,2165,2043,1929,1820,1718,1622,1531,1445,1364,1287, + 1215,1147,1082,1022, 964, 910, 859, 811, 765, 722, 682, 644, + 607, 573, 541, 511, 482, 455, 430, 405, 383, 361, 341, 322, + 304, 287, 271, 255, 241, 228, 215, 203, 191, 181, 170, 161, + 152, 143, 135, 128, + 4878,4604,4345,4102,3871,3654,3449,3255,3073,2900,2737,2584, + 2439,2302,2173,2051,1936,1827,1724,1628,1536,1450,1369,1292, + 1219,1151,1086,1025, 968, 914, 862, 814, 768, 725, 684, 646, + 610, 575, 543, 513, 484, 457, 431, 407, 384, 363, 342, 323, + 305, 288, 272, 256, 242, 228, 216, 203, 192, 181, 171, 161, + 152, 144, 136, 128, + 4895,4620,4361,4116,3885,3667,3461,3267,3084,2911,2747,2593, + 2448,2310,2181,2058,1943,1834,1731,1634,1542,1455,1374,1297, + 1224,1155,1090,1029, 971, 917, 865, 817, 771, 728, 687, 648, + 612, 578, 545, 515, 486, 458, 433, 408, 385, 364, 343, 324, + 306, 289, 273, 257, 243, 229, 216, 204, 193, 182, 172, 162, + 153, 144, 136, 129, + 4913,4637,4377,4131,3899,3681,3474,3279,3095,2921,2757,2603, + 2456,2319,2188,2066,1950,1840,1737,1639,1547,1461,1379,1301, + 1228,1159,1094,1033, 975, 920, 868, 820, 774, 730, 689, 651, + 614, 580, 547, 516, 487, 460, 434, 410, 387, 365, 345, 325, + 307, 290, 274, 258, 244, 230, 217, 205, 193, 183, 172, 163, + 154, 145, 137, 129, + 4931,4654,4393,4146,3913,3694,3486,3291,3106,2932,2767,2612, + 2465,2327,2196,2073,1957,1847,1743,1645,1553,1466,1384,1306, + 1233,1163,1098,1037, 978, 923, 872, 823, 777, 733, 692, 653, + 616, 582, 549, 518, 489, 462, 436, 411, 388, 366, 346, 326, + 308, 291, 275, 259, 245, 231, 218, 206, 194, 183, 173, 163, + 154, 145, 137, 130, + 4948,4671,4409,4161,3928,3707,3499,3303,3117,2942,2777,2621, + 2474,2335,2204,2081,1964,1854,1750,1651,1559,1471,1389,1311, + 1237,1168,1102,1040, 982, 927, 875, 826, 779, 736, 694, 655, + 619, 584, 551, 520, 491, 463, 437, 413, 390, 368, 347, 328, + 309, 292, 276, 260, 245, 232, 219, 206, 195, 184, 174, 164, + 155, 146, 138, 130, + 4966,4688,4425,4176,3942,3721,3512,3315,3129,2953,2787,2631, + 2483,2344,2212,2088,1971,1860,1756,1657,1564,1477,1394,1315, + 1242,1172,1106,1044, 985, 930, 878, 829, 782, 738, 697, 658, + 621, 586, 553, 522, 493, 465, 439, 414, 391, 369, 348, 329, + 310, 293, 277, 261, 246, 233, 219, 207, 196, 185, 174, 164, + 155, 146, 138, 131, + 4984,4705,4441,4191,3956,3734,3524,3327,3140,2964,2797,2640, + 2492,2352,2220,2096,1978,1867,1762,1663,1570,1482,1399,1320, + 1246,1176,1110,1048, 989, 934, 881, 832, 785, 741, 699, 660, + 623, 588, 555, 524, 495, 467, 441, 416, 392, 370, 350, 330, + 312, 294, 278, 262, 247, 233, 220, 208, 196, 185, 175, 165, + 156, 147, 139, 131, + 5002,4722,4457,4206,3970,3748,3537,3339,3151,2974,2807,2650, + 2501,2361,2228,2103,1985,1874,1769,1669,1576,1487,1404,1325, + 1251,1180,1114,1052, 993, 937, 884, 835, 788, 744, 702, 662, + 625, 590, 557, 526, 496, 468, 442, 417, 394, 372, 351, 331, + 313, 295, 279, 263, 248, 234, 221, 209, 197, 186, 175, 166, + 156, 148, 139, 131, + 5020,4739,4473,4222,3985,3761,3550,3351,3163,2985,2818,2659, + 2510,2369,2236,2111,1992,1881,1775,1675,1581,1493,1409,1330, + 1255,1185,1118,1055, 996, 940, 887, 838, 791, 746, 704, 665, + 628, 592, 559, 528, 498, 470, 444, 419, 395, 373, 352, 332, + 314, 296, 280, 264, 249, 235, 222, 209, 198, 187, 176, 166, + 157, 148, 140, 132, + 5039,4756,4489,4237,3999,3775,3563,3363,3174,2996,2828,2669, + 2519,2378,2244,2118,2000,1887,1781,1681,1587,1498,1414,1335, + 1260,1189,1122,1059,1000, 944, 891, 841, 794, 749, 707, 667, + 630, 594, 561, 530, 500, 472, 445, 420, 397, 374, 353, 334, + 315, 297, 281, 265, 250, 236, 223, 210, 198, 187, 177, 167, + 157, 149, 140, 132, + 5057,4773,4505,4252,4014,3788,3576,3375,3186,3007,2838,2679, + 2528,2387,2253,2126,2007,1894,1788,1688,1593,1503,1419,1339, + 1264,1193,1126,1063,1003, 947, 894, 844, 796, 752, 710, 670, + 632, 597, 563, 532, 502, 474, 447, 422, 398, 376, 355, 335, + 316, 298, 282, 266, 251, 237, 223, 211, 199, 188, 177, 167, + 158, 149, 141, 133, + 5075,4790,4521,4268,4028,3802,3589,3387,3197,3018,2848,2688, + 2538,2395,2261,2134,2014,1901,1794,1694,1599,1509,1424,1344, + 1269,1198,1130,1067,1007, 951, 897, 847, 799, 754, 712, 672, + 634, 599, 565, 533, 504, 475, 449, 423, 400, 377, 356, 336, + 317, 299, 283, 267, 252, 238, 224, 212, 200, 189, 178, 168, + 159, 150, 141, 133, + 5093,4808,4538,4283,4043,3816,3602,3399,3209,3029,2859,2698, + 2547,2404,2269,2142,2021,1908,1801,1700,1604,1514,1429,1349, + 1273,1202,1134,1071,1011, 954, 900, 850, 802, 757, 715, 675, + 637, 601, 567, 535, 505, 477, 450, 425, 401, 379, 357, 337, + 318, 300, 284, 268, 253, 238, 225, 212, 201, 189, 179, 169, + 159, 150, 142, 134]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/digitalmugician/DMSample.as b/Flod 4.1/neoart/flod/digitalmugician/DMSample.as new file mode 100644 index 0000000..5f1ed4f --- /dev/null +++ b/Flod 4.1/neoart/flod/digitalmugician/DMSample.as @@ -0,0 +1,40 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.digitalmugician { + import neoart.flod.core.*; + + public final class DMSample extends AmigaSample { + internal var + wave : int, + waveLen : int, + finetune : int, + arpeggio : int, + pitch : int, + pitchDelay : int, + pitchLoop : int, + pitchSpeed : int, + effect : int, + effectDone : int, + effectStep : int, + effectSpeed : int, + source1 : int, + source2 : int, + volumeLoop : int, + volumeSpeed : int; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/digitalmugician/DMSong.as b/Flod 4.1/neoart/flod/digitalmugician/DMSong.as new file mode 100644 index 0000000..1f96304 --- /dev/null +++ b/Flod 4.1/neoart/flod/digitalmugician/DMSong.as @@ -0,0 +1,34 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.digitalmugician { + import neoart.flod.core.*; + + public final class DMSong { + internal var + title : String, + speed : int, + length : int, + loop : int, + loopStep : int, + tracks : Vector.; + + public function DMSong() { + tracks = new Vector.(); + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/digitalmugician/DMVoice.as b/Flod 4.1/neoart/flod/digitalmugician/DMVoice.as new file mode 100644 index 0000000..788265b --- /dev/null +++ b/Flod 4.1/neoart/flod/digitalmugician/DMVoice.as @@ -0,0 +1,72 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.digitalmugician { + import neoart.flod.core.*; + + public final class DMVoice { + internal var + channel : AmigaChannel, + sample : DMSample, + step : AmigaStep, + note : int, + period : int, + val1 : int, + val2 : int, + finalPeriod : int, + arpeggioStep : int, + effectCtr : int, + pitch : int, + pitchCtr : int, + pitchStep : int, + portamento : int, + volume : int, + volumeCtr : int, + volumeStep : int, + mixMute : int, + mixPtr : int, + mixEnd : int, + mixSpeed : int, + mixStep : int, + mixVolume : int; + + internal function initialize():void { + sample = null; + step = null; + note = 0; + period = 0; + val1 = 0; + val2 = 0; + finalPeriod = 0; + arpeggioStep = 0; + effectCtr = 0; + pitch = 0; + pitchCtr = 0; + pitchStep = 0; + portamento = 0; + volume = 0; + volumeCtr = 0; + volumeStep = 0; + mixMute = 1; + mixPtr = 0; + mixEnd = 0; + mixSpeed = 0; + mixStep = 0; + mixVolume = 0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/fasttracker/F2Data.as b/Flod 4.1/neoart/flod/fasttracker/F2Data.as new file mode 100644 index 0000000..c6b4299 --- /dev/null +++ b/Flod 4.1/neoart/flod/fasttracker/F2Data.as @@ -0,0 +1,33 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.fasttracker { + + public final class F2Data { + internal var + points : Vector., + total : int, + sustain : int, + loopStart : int, + loopEnd : int, + flags : int; + + public function F2Data() { + points = new Vector.(12, true); + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/fasttracker/F2Envelope.as b/Flod 4.1/neoart/flod/fasttracker/F2Envelope.as new file mode 100644 index 0000000..c6efc55 --- /dev/null +++ b/Flod 4.1/neoart/flod/fasttracker/F2Envelope.as @@ -0,0 +1,38 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.fasttracker { + + public final class F2Envelope { + internal var + value : int, + position : int, + frame : int, + delta : int, + fraction : int, + stopped : int; + + internal function reset():void { + value = 0; + position = 0; + frame = 0; + delta = 0; + fraction = 0; + stopped = 0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/fasttracker/F2Instrument.as b/Flod 4.1/neoart/flod/fasttracker/F2Instrument.as new file mode 100644 index 0000000..037f505 --- /dev/null +++ b/Flod 4.1/neoart/flod/fasttracker/F2Instrument.as @@ -0,0 +1,41 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.fasttracker { + + public final class F2Instrument { + internal var + name : String = "", + samples : Vector., + noteSamples : Vector., + fadeout : int, + volData : F2Data, + volEnabled : int, + panData : F2Data, + panEnabled : int, + vibratoType : int, + vibratoSweep : int, + vibratoSpeed : int, + vibratoDepth : int; + + public function F2Instrument() { + noteSamples = new Vector.(96, true); + volData = new F2Data(); + panData = new F2Data(); + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/fasttracker/F2Pattern.as b/Flod 4.1/neoart/flod/fasttracker/F2Pattern.as new file mode 100644 index 0000000..0cfb4e5 --- /dev/null +++ b/Flod 4.1/neoart/flod/fasttracker/F2Pattern.as @@ -0,0 +1,32 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.fasttracker { + + public final class F2Pattern { + internal var + rows : Vector., + length : int, + size : int; + + public function F2Pattern(length, channels) { + size = length * channels; + rows = new Vector.(size, true); + this.length = length; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/fasttracker/F2Player.as b/Flod 4.1/neoart/flod/fasttracker/F2Player.as new file mode 100644 index 0000000..b5acac2 --- /dev/null +++ b/Flod 4.1/neoart/flod/fasttracker/F2Player.as @@ -0,0 +1,1297 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/05 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.fasttracker { + import flash.utils.*; + import neoart.flod.core.*; + + public final class F2Player extends SBPlayer { + internal var + patterns : Vector., + instruments : Vector., + linear : int; + private var + voices : Vector., + order : int, + position : int, + nextOrder : int, + nextPosition : int, + pattern : F2Pattern, + patternDelay : int, + patternOffset : int, + complete : int; + + public function F2Player(mixer:Soundblaster = null) { + super(mixer); + } + + override public function process():void { + var com:int, curr:F2Point, instr:F2Instrument, i:int, jumpFlag:int, next:F2Point, paramx:int, paramy:int, porta:int, row:F2Row, sample:F2Sample, slide:int, value:int, voice:F2Voice = voices[0]; + + if (!tick) { + if (nextOrder >= 0) order = nextOrder; + if (nextPosition >= 0) position = nextPosition; + + nextOrder = nextPosition = -1; + pattern = patterns[track[order]]; + + while (voice) { + row = pattern.rows[int(position + voice.index)]; + com = row.volume >> 4; + porta = int(row.effect == FX_TONE_PORTAMENTO || row.effect == FX_TONE_PORTA_VOLUME_SLIDE || com == VX_TONE_PORTAMENTO); + paramx = row.param >> 4; + voice.keyoff = 0; + + if (voice.arpDelta) { + voice.arpDelta = 0; + voice.flags |= UPDATE_PERIOD; + } + + if (row.instrument) { + voice.instrument = row.instrument < instruments.length ? instruments[row.instrument] : null; + voice.volEnvelope.reset(); + voice.panEnvelope.reset(); + voice.flags |= (UPDATE_VOLUME | UPDATE_PANNING | SHORT_RAMP); + } else if (row.note == KEYOFF_NOTE || (row.effect == FX_KEYOFF && !row.param)) { + voice.fadeEnabled = 1; + voice.keyoff = 1; + } + + if (row.note && row.note != KEYOFF_NOTE) { + if (voice.instrument) { + instr = voice.instrument; + value = row.note - 1; + sample = instr.samples[instr.noteSamples[value]]; + value += sample.relative; + + if (value >= LOWER_NOTE && value <= HIGHER_NOTE) { + if (!porta) { + voice.note = value; + voice.sample = sample; + + if (row.instrument) { + voice.volEnabled = instr.volEnabled; + voice.panEnabled = instr.panEnabled; + voice.flags |= UPDATE_ALL; + } else { + voice.flags |= (UPDATE_PERIOD | UPDATE_TRIGGER); + } + } + + if (row.instrument) { + voice.reset(); + voice.fadeDelta = instr.fadeout; + } else { + voice.finetune = (sample.finetune >> 3) << 2; + } + + if (row.effect == FX_EXTENDED_EFFECTS && paramx == EX_SET_FINETUNE) + voice.finetune = ((row.param & 15) - 8) << 3; + + if (linear) { + value = ((120 - value) << 6) - voice.finetune; + } else { + value = amiga(value, voice.finetune); + } + + if (!porta) { + voice.period = value; + voice.glissPeriod = 0; + } else { + voice.portaPeriod = value; + } + } + } else { + voice.volume = 0; + voice.flags = (UPDATE_VOLUME | SHORT_RAMP); + } + } else if (voice.vibratoReset) { + if (row.effect != FX_VIBRATO && row.effect != FX_VIBRATO_VOLUME_SLIDE) { + voice.vibDelta = 0; + voice.vibratoReset = 0; + voice.flags |= UPDATE_PERIOD; + } + } + + if (row.volume) { + if (row.volume >= 16 && row.volume <= 80) { + voice.volume = row.volume - 16; + voice.flags |= (UPDATE_VOLUME | SHORT_RAMP); + } else { + paramy = row.volume & 15; + + switch (com) { + case VX_FINE_VOLUME_SLIDE_DOWN: + voice.volume -= paramy; + if (voice.volume < 0) voice.volume = 0; + voice.flags |= UPDATE_VOLUME; + break; + case VX_FINE_VOLUME_SLIDE_UP: + voice.volume += paramy; + if (voice.volume > 64) voice.volume = 64; + voice.flags |= UPDATE_VOLUME; + break; + case VX_SET_VIBRATO_SPEED: + if (paramy) voice.vibratoSpeed = paramy; + break; + case VX_VIBRATO: + if (paramy) voice.vibratoDepth = paramy << 2; + break; + case VX_SET_PANNING: + voice.panning = paramy << 4; + voice.flags |= UPDATE_PANNING; + break; + case VX_TONE_PORTAMENTO: + if (paramy) voice.portaSpeed = paramy << 4; + break; + } + } + } + + if (row.effect) { + paramy = row.param & 15; + + switch (row.effect) { + case FX_PORTAMENTO_UP: + if (row.param) voice.portaU = row.param << 2; + break; + case FX_PORTAMENTO_DOWN: + if (row.param) voice.portaD = row.param << 2; + break; + case FX_TONE_PORTAMENTO: + if (row.param && com != VX_TONE_PORTAMENTO) voice.portaSpeed = row.param; + break; + case FX_VIBRATO: + voice.vibratoReset = 1; + break; + case FX_TONE_PORTA_VOLUME_SLIDE: + if (row.param) voice.volSlide = row.param; + break; + case FX_VIBRATO_VOLUME_SLIDE: + if (row.param) voice.volSlide = row.param; + voice.vibratoReset = 1; + break; + case FX_TREMOLO: + if (paramx) voice.tremoloSpeed = paramx; + if (paramy) voice.tremoloDepth = paramy; + break; + case FX_SET_PANNING: + voice.panning = row.param; + voice.flags |= UPDATE_PANNING; + break; + case FX_SAMPLE_OFFSET: + if (row.param) voice.sampleOffset = row.param << 8; + + if (voice.sampleOffset >= voice.sample.length) { + voice.volume = 0; + voice.sampleOffset = 0; + voice.flags &= ~(UPDATE_PERIOD | UPDATE_TRIGGER); + voice.flags |= (UPDATE_VOLUME | SHORT_RAMP); + } + break; + case FX_VOLUME_SLIDE: + if (row.param) voice.volSlide = row.param; + break; + case FX_POSITION_JUMP: + nextOrder = row.param; + + if (nextOrder >= length) complete = 1; + else nextPosition = 0; + + jumpFlag = 1; + patternOffset = 0; + break; + case FX_SET_VOLUME: + voice.volume = row.param; + voice.flags |= (UPDATE_VOLUME | SHORT_RAMP); + break; + case FX_PATTERN_BREAK: + nextPosition = ((paramx * 10) + paramy) * channels; + patternOffset = 0; + + if (!jumpFlag) { + nextOrder = order + 1; + + if (nextOrder >= length) { + complete = 1; + nextPosition = -1; + } + } + break; + case FX_EXTENDED_EFFECTS: + + switch (paramx) { + case EX_FINE_PORTAMENTO_UP: + if (paramy) voice.finePortaU = paramy << 2; + voice.period -= voice.finePortaU; + voice.flags |= UPDATE_PERIOD; + break; + case EX_FINE_PORTAMENTO_DOWN: + if (paramy) voice.finePortaD = paramy << 2; + voice.period += voice.finePortaD; + voice.flags |= UPDATE_PERIOD; + break; + case EX_GLISSANDO_CONTROL: + voice.glissando = paramy; + break; + case EX_VIBRATO_CONTROL: + voice.waveControl = (voice.waveControl & 0xf0) | paramy; + break; + case EX_PATTERN_LOOP: + if (!paramy) { + voice.patternLoopRow = patternOffset = position; + } else { + if (!voice.patternLoop) { + voice.patternLoop = paramy; + } else { + voice.patternLoop--; + } + + if (voice.patternLoop) + nextPosition = voice.patternLoopRow; + } + break; + case EX_TREMOLO_CONTROL: + voice.waveControl = (voice.waveControl & 0x0f) | (paramy << 4); + break; + case EX_FINE_VOLUME_SLIDE_UP: + if (paramy) voice.fineSlideU = paramy; + voice.volume += voice.fineSlideU; + voice.flags |= UPDATE_VOLUME; + break; + case EX_FINE_VOLUME_SLIDE_DOWN: + if (paramy) voice.fineSlideD = paramy; + voice.volume -= voice.fineSlideD; + voice.flags |= UPDATE_VOLUME; + break; + case EX_NOTE_DELAY: + voice.delay = voice.flags; + voice.flags = 0; + break; + case EX_PATTERN_DELAY: + patternDelay = paramy * timer; + break; + } + + break; + case FX_SET_SPEED: + if (!row.param) break; + if (row.param < 32) timer = row.param; + else mixer.samplesTick = 110250 / row.param; + break; + case FX_SET_GLOBAL_VOLUME: + master = row.param; + if (master > 64) master = 64; + voice.flags |= UPDATE_VOLUME; + break; + case FX_GLOBAL_VOLUME_SLIDE: + if (row.param) voice.volSlideMaster = row.param; + break; + case FX_SET_ENVELOPE_POSITION: + if (!voice.instrument || !voice.instrument.volEnabled) break; + instr = voice.instrument; + value = row.param; + paramx = instr.volData.total; + + for (i = 0; i < paramx; ++i) + if (value < instr.volData.points[i].frame) break; + + voice.volEnvelope.position = --i; + paramx--; + + if ((instr.volData.flags & ENVELOPE_LOOP) && i == instr.volData.loopEnd) { + i = voice.volEnvelope.position = instr.volData.loopStart; + value = instr.volData.points[i].frame; + voice.volEnvelope.frame = value; + } + + if (i >= paramx) { + voice.volEnvelope.value = instr.volData.points[paramx].value; + voice.volEnvelope.stopped = 1; + } else { + voice.volEnvelope.stopped = 0; + voice.volEnvelope.frame = value; + if (value > instr.volData.points[i].frame) voice.volEnvelope.position++; + + curr = instr.volData.points[i]; + next = instr.volData.points[++i]; + value = next.frame - curr.frame; + + voice.volEnvelope.delta = value ? ((next.value - curr.value) << 8) / value : 0; + voice.volEnvelope.fraction = (curr.value << 8); + } + break; + case FX_PANNING_SLIDE: + if (row.param) voice.panSlide = row.param; + break; + case FX_MULTI_RETRIG_NOTE: + if (paramx) voice.retrigx = paramx; + if (paramy) voice.retrigy = paramy; + + if (!row.volume && voice.retrigy) { + com = tick + 1; + if (com % voice.retrigy) break; + if (row.volume > 80 && voice.retrigx) retrig(voice); + } + break; + case FX_TREMOR: + if (row.param) { + voice.tremorOn = ++paramx; + voice.tremorOff = ++paramy + paramx; + } + break; + case FX_EXTRA_FINE_PORTAMENTO: + if (paramx == 1) { + if (paramy) voice.xtraPortaU = paramy; + voice.period -= voice.xtraPortaU; + voice.flags |= UPDATE_PERIOD; + } else if (paramx == 2) { + if (paramy) voice.xtraPortaD = paramy; + voice.period += voice.xtraPortaD; + voice.flags |= UPDATE_PERIOD; + } + break; + } + } + voice = voice.next; + } + } else { + while (voice) { + row = pattern.rows[int(position + voice.index)]; + + if (voice.delay) { + if ((row.param & 15) == tick) { + voice.flags = voice.delay; + voice.delay = 0; + } else { + voice = voice.next; + continue; + } + } + + if (row.volume) { + paramx = row.volume >> 4; + paramy = row.volume & 15; + + switch (paramx) { + case VX_VOLUME_SLIDE_DOWN: + voice.volume -= paramy; + if (voice.volume < 0) voice.volume = 0; + voice.flags |= UPDATE_VOLUME; + break; + case VX_VOLUME_SLIDE_UP: + voice.volume += paramy; + if (voice.volume > 64) voice.volume = 64; + voice.flags |= UPDATE_VOLUME; + break; + case VX_VIBRATO: + voice.vibrato(); + break; + case VX_PANNING_SLIDE_LEFT: + voice.panning -= paramy; + if (voice.panning < 0) voice.panning = 0; + voice.flags |= UPDATE_PANNING; + break; + case VX_PANNING_SLIDE_RIGHT: + voice.panning += paramy; + if (voice.panning > 255) voice.panning = 255; + voice.flags |= UPDATE_PANNING; + break; + case VX_TONE_PORTAMENTO: + if (voice.portaPeriod) voice.tonePortamento(); + break; + } + } + + paramx = row.param >> 4; + paramy = row.param & 15; + + switch (row.effect) { + case FX_ARPEGGIO: + if (!row.param) break; + value = (tick - timer) % 3; + if (value < 0) value += 3; + if (tick == 2 && timer == 18) value = 0; + + if (!value) { + voice.arpDelta = 0; + } else if (value == 1) { + if (linear) { + voice.arpDelta = -(paramy << 6); + } else { + value = amiga(voice.note + paramy, voice.finetune); + voice.arpDelta = value - voice.period; + } + } else { + if (linear) { + voice.arpDelta = -(paramx << 6); + } else { + value = amiga(voice.note + paramx, voice.finetune); + voice.arpDelta = value - voice.period; + } + } + + voice.flags |= UPDATE_PERIOD; + break; + case FX_PORTAMENTO_UP: + voice.period -= voice.portaU; + if (voice.period < 0) voice.period = 0; + voice.flags |= UPDATE_PERIOD; + break; + case FX_PORTAMENTO_DOWN: + voice.period += voice.portaD; + if (voice.period > 9212) voice.period = 9212; + voice.flags |= UPDATE_PERIOD; + break; + case FX_TONE_PORTAMENTO: + if (voice.portaPeriod) voice.tonePortamento(); + break; + case FX_VIBRATO: + if (paramx) voice.vibratoSpeed = paramx; + if (paramy) voice.vibratoDepth = paramy << 2; + voice.vibrato(); + break; + case FX_TONE_PORTA_VOLUME_SLIDE: + slide = 1; + if (voice.portaPeriod) voice.tonePortamento(); + break; + case FX_VIBRATO_VOLUME_SLIDE: + slide = 1; + voice.vibrato(); + break; + case FX_TREMOLO: + voice.tremolo(); + break; + case FX_VOLUME_SLIDE: + slide = 1; + break; + case FX_EXTENDED_EFFECTS: + + switch (paramx) { + case EX_RETRIG_NOTE: + if ((tick % paramy) == 0) { + voice.volEnvelope.reset(); + voice.panEnvelope.reset(); + voice.flags |= (UPDATE_VOLUME | UPDATE_PANNING | UPDATE_TRIGGER); + } + break; + case EX_NOTE_CUT: + if (tick == paramy) { + voice.volume = 0; + voice.flags |= UPDATE_VOLUME; + } + break; + } + + break; + case FX_GLOBAL_VOLUME_SLIDE: + paramx = voice.volSlideMaster >> 4; + paramy = voice.volSlideMaster & 15; + + if (paramx) { + master += paramx; + if (master > 64) master = 64; + voice.flags |= UPDATE_VOLUME; + } else if (paramy) { + master -= paramy; + if (master < 0) master = 0; + voice.flags |= UPDATE_VOLUME; + } + break; + case FX_KEYOFF: + if (tick == row.param) { + voice.fadeEnabled = 1; + voice.keyoff = 1; + } + break; + case FX_PANNING_SLIDE: + paramx = voice.panSlide >> 4; + paramy = voice.panSlide & 15; + + if (paramx) { + voice.panning += paramx; + if (voice.panning > 255) voice.panning = 255; + voice.flags |= UPDATE_PANNING; + } else if (paramy) { + voice.panning -= paramy; + if (voice.panning < 0) voice.panning = 0; + voice.flags |= UPDATE_PANNING; + } + break; + case FX_MULTI_RETRIG_NOTE: + com = tick; + if (!row.volume) com++; + if (com % voice.retrigy) break; + + if ((!row.volume || row.volume > 80) && voice.retrigx) retrig(voice); + voice.flags |= UPDATE_TRIGGER; + break; + case FX_TREMOR: + voice.tremor(); + break; + } + + if (slide) { + paramx = voice.volSlide >> 4; + paramy = voice.volSlide & 15; + slide = 0; + + if (paramx) { + voice.volume += paramx; + voice.flags |= UPDATE_VOLUME; + } else if (paramy) { + voice.volume -= paramy; + voice.flags |= UPDATE_VOLUME; + } + } + voice = voice.next; + } + } + + if (++tick >= (timer + patternDelay)) { + patternDelay = tick = 0; + + if (nextPosition < 0) { + nextPosition = position + channels; + + if (nextPosition >= pattern.size || complete) { + nextOrder = order + 1; + nextPosition = patternOffset; + + if (nextOrder >= length) { + nextOrder = restart; + mixer.complete = 1; + } + } + } + } + } + + override public function fast():void { + var chan:SBChannel, delta:int, flags:int, instr:F2Instrument, panning:int, voice:F2Voice = voices[0], volume:Number; + + while (voice) { + chan = voice.channel; + flags = voice.flags; + voice.flags = 0; + + if (flags & UPDATE_TRIGGER) { + chan.index = voice.sampleOffset; + chan.pointer = -1; + chan.dir = 0; + chan.fraction = 0; + chan.sample = voice.sample; + chan.length = voice.sample.length; + + chan.enabled = chan.sample.data ? 1 : 0; + voice.playing = voice.instrument; + voice.sampleOffset = 0; + } + + instr = voice.playing; + delta = instr.vibratoSpeed ? voice.autoVibrato() : 0; + + volume = voice.volume + voice.volDelta; + + if (instr.volEnabled) { + if (voice.volEnabled && !voice.volEnvelope.stopped) + envelope(voice, voice.volEnvelope, instr.volData); + + volume = (volume * voice.volEnvelope.value) >> 6; + flags |= UPDATE_VOLUME; + + if (voice.fadeEnabled) { + voice.fadeVolume -= voice.fadeDelta; + + if (voice.fadeVolume < 0) { + volume = 0; + + voice.fadeVolume = 0; + voice.fadeEnabled = 0; + + voice.volEnvelope.value = 0; + voice.volEnvelope.stopped = 1; + voice.panEnvelope.stopped = 1; + } else { + volume = (volume * voice.fadeVolume) >> 16; + } + } + } else if (voice.keyoff) { + volume = 0; + flags |= UPDATE_VOLUME; + } + + panning = voice.panning; + + if (instr.panEnabled) { + if (voice.panEnabled && !voice.panEnvelope.stopped) + envelope(voice, voice.panEnvelope, instr.panData); + + panning = (voice.panEnvelope.value << 2); + flags |= UPDATE_PANNING; + + if (panning < 0) panning = 0; + else if (panning > 255) panning = 255; + } + + if (flags & UPDATE_VOLUME) { + if (volume < 0) volume = 0; + else if (volume > 64) volume = 64; + + chan.volume = VOLUMES[int((volume * master) >> 6)]; + chan.lvol = chan.volume * chan.lpan; + chan.rvol = chan.volume * chan.rpan; + } + + if (flags & UPDATE_PANNING) { + chan.panning = panning; + chan.lpan = PANNING[int(256 - panning)]; + chan.rpan = PANNING[panning]; + + chan.lvol = chan.volume * chan.lpan; + chan.rvol = chan.volume * chan.rpan; + } + + if (flags & UPDATE_PERIOD) { + delta += voice.period + voice.arpDelta + voice.vibDelta; + + if (linear) { + chan.speed = int((548077568 * Math.pow(2, ((4608 - delta) / 768))) / 44100) / 65536; + } else { + chan.speed = int((65536 * (14317456 / delta)) / 44100) / 65536; + } + + chan.delta = int(chan.speed); + chan.speed -= chan.delta; + } + voice = voice.next; + } + } + + override public function accurate():void { + var chan:SBChannel, delta:int, flags:int, instr:F2Instrument, lpan:Number, lvol:Number, panning:int, rpan:Number, rvol:Number, voice:F2Voice = voices[0], volume:Number; + + while (voice) { + chan = voice.channel; + flags = voice.flags; + voice.flags = 0; + + if (flags & UPDATE_TRIGGER) { + if (chan.sample) { + flags |= SHORT_RAMP; + chan.mixCounter = 220; + chan.oldSample = null; + chan.oldPointer = -1; + + if (chan.enabled) { + chan.oldDir = chan.dir; + chan.oldFraction = chan.fraction; + chan.oldSpeed = chan.speed; + chan.oldSample = chan.sample; + chan.oldPointer = chan.pointer; + chan.oldLength = chan.length; + + chan.lmixRampD = chan.lvol; + chan.lmixDeltaD = chan.lvol / 220; + chan.rmixRampD = chan.rvol; + chan.rmixDeltaD = chan.rvol / 220; + } + } + + chan.dir = 1; + chan.fraction = 0; + chan.sample = voice.sample; + chan.pointer = voice.sampleOffset; + chan.length = voice.sample.length; + + chan.enabled = chan.sample.data ? 1 : 0; + voice.playing = voice.instrument; + voice.sampleOffset = 0; + } + + instr = voice.playing; + delta = instr.vibratoSpeed ? voice.autoVibrato() : 0; + + volume = voice.volume + voice.volDelta; + + if (instr.volEnabled) { + if (voice.volEnabled && !voice.volEnvelope.stopped) + envelope(voice, voice.volEnvelope, instr.volData); + + volume = (volume * voice.volEnvelope.value) >> 6; + flags |= UPDATE_VOLUME; + + if (voice.fadeEnabled) { + voice.fadeVolume -= voice.fadeDelta; + + if (voice.fadeVolume < 0) { + volume = 0; + + voice.fadeVolume = 0; + voice.fadeEnabled = 0; + + voice.volEnvelope.value = 0; + voice.volEnvelope.stopped = 1; + voice.panEnvelope.stopped = 1; + } else { + volume = (volume * voice.fadeVolume) >> 16; + } + } + } else if (voice.keyoff) { + volume = 0; + flags |= UPDATE_VOLUME; + } + + panning = voice.panning; + + if (instr.panEnabled) { + if (voice.panEnabled && !voice.panEnvelope.stopped) + envelope(voice, voice.panEnvelope, instr.panData); + + panning = (voice.panEnvelope.value << 2); + flags |= UPDATE_PANNING; + + if (panning < 0) panning = 0; + else if (panning > 255) panning = 255; + } + + if (!chan.enabled) { + chan.volCounter = 0; + chan.panCounter = 0; + voice = voice.next; + continue; + } + + if (flags & UPDATE_VOLUME) { + if (volume < 0) volume = 0; + else if (volume > 64) volume = 64; + + volume = VOLUMES[int((volume * master) >> 6)]; + lvol = volume * PANNING[int(256 - panning)]; + rvol = volume * PANNING[panning]; + + if (volume != chan.volume && !chan.mixCounter) { + chan.volCounter = (flags & SHORT_RAMP) ? 220 : mixer.samplesTick; + + chan.lvolDelta = (lvol - chan.lvol) / chan.volCounter; + chan.rvolDelta = (rvol - chan.rvol) / chan.volCounter; + } else { + chan.lvol = lvol; + chan.rvol = rvol; + } + chan.volume = volume; + } + + if (flags & UPDATE_PANNING) { + lpan = PANNING[int(256 - panning)]; + rpan = PANNING[panning]; + + if (panning != chan.panning && !chan.mixCounter && !chan.volCounter) { + chan.panCounter = mixer.samplesTick; + + chan.lpanDelta = (lpan - chan.lpan) / chan.panCounter; + chan.rpanDelta = (rpan - chan.rpan) / chan.panCounter; + } else { + chan.lpan = lpan; + chan.rpan = rpan; + } + chan.panning = panning; + } + + if (flags & UPDATE_PERIOD) { + delta += voice.period + voice.arpDelta + voice.vibDelta; + + if (linear) { + chan.speed = int((548077568 * Math.pow(2, ((4608 - delta) / 768))) / 44100) / 65536; + } else { + chan.speed = int((65536 * (14317456 / delta)) / 44100) / 65536; + } + } + + if (chan.mixCounter) { + chan.lmixRampU = 0.0; + chan.lmixDeltaU = chan.lvol / 220; + chan.rmixRampU = 0.0; + chan.rmixDeltaU = chan.rvol / 220; + } + voice = voice.next; + } + } + + override protected function initialize():void { + var i:int = 0, voice:F2Voice; + super.initialize(); + + timer = speed; + order = 0; + position = 0; + nextOrder = -1; + nextPosition = -1; + patternDelay = 0; + patternOffset = 0; + complete = 0; + master = 64; + + voices = new Vector.(channels, true); + + for (; i < channels; ++i) { + voice = new F2Voice(i); + + voice.channel = mixer.channels[i]; + voice.playing = instruments[0]; + voice.sample = voice.playing.samples[0]; + + voices[i] = voice; + if (i) voices[int(i - 1)].next = voice; + } + } + + override protected function loader(stream:ByteArray):void { + var header:int, i:int, id:String, iheader:int, instr:F2Instrument, ipos:int, j:int, len:int, pattern:F2Pattern, pos:int, reserved:int = 22, row:F2Row, rows:int, sample:F2Sample, value:int; + if (stream.length < 360) return; + stream.position = 17; + + title = stream.readMultiByte(20, ENCODING); + stream.position++; + id = stream.readMultiByte(20, ENCODING); + + if (id == "FastTracker v2.00 " || id == "FastTracker v 2.00 ") { + this.version = 1; + } else if (id == "Sk@le Tracker") { + reserved = 2; + this.version = 2; + } else if (id == "MadTracker 2.0") { + this.version = 3; + } else if (id == "MilkyTracker ") { + this.version = 4; + } else if (id == "DigiBooster Pro 2.18") { + this.version = 5; + } else if (id.indexOf("OpenMPT") != -1) { + this.version = 6; + } else return; + + stream.readUnsignedShort(); + + header = stream.readUnsignedInt(); + length = stream.readUnsignedShort(); + restart = stream.readUnsignedShort(); + channels = stream.readUnsignedShort(); + + value = rows = stream.readUnsignedShort(); + instruments = new Vector.(stream.readUnsignedShort() + 1, true); + + linear = stream.readUnsignedShort(); + speed = stream.readUnsignedShort(); + tempo = stream.readUnsignedShort(); + + track = new Vector.(length, true); + + for (i = 0; i < length; ++i) { + j = stream.readUnsignedByte(); + if (j >= value) rows = j + 1; + track[i] = j; + } + + patterns = new Vector.(rows, true); + + if (rows != value) { + pattern = new F2Pattern(64, channels); + j = pattern.size; + for (i = 0; i < j; ++i) pattern.rows[i] = new F2Row(); + patterns[--rows] = pattern; + } + + stream.position = pos = header + 60; + len = value; + + for (i = 0; i < len; ++i) { + header = stream.readUnsignedInt(); + stream.position++; + + pattern = new F2Pattern(stream.readUnsignedShort(), channels); + rows = pattern.size; + + value = stream.readUnsignedShort(); + stream.position = pos + header; + ipos = stream.position + value; + + if (value) { + for (j = 0; j < rows; ++j) { + row = new F2Row(); + value = stream.readUnsignedByte(); + + if (value & 128) { + if (value & 1) row.note = stream.readUnsignedByte(); + if (value & 2) row.instrument = stream.readUnsignedByte(); + if (value & 4) row.volume = stream.readUnsignedByte(); + if (value & 8) row.effect = stream.readUnsignedByte(); + if (value & 16) row.param = stream.readUnsignedByte(); + } else { + row.note = value; + row.instrument = stream.readUnsignedByte(); + row.volume = stream.readUnsignedByte(); + row.effect = stream.readUnsignedByte(); + row.param = stream.readUnsignedByte(); + } + + if (row.note != KEYOFF_NOTE) if (row.note > 96) row.note = 0; + pattern.rows[j] = row; + } + } else { + for (j = 0; j < rows; ++j) pattern.rows[j] = new F2Row(); + } + + patterns[i] = pattern; + pos = stream.position; + if (pos != ipos) pos = stream.position = ipos; + } + + ipos = stream.position; + len = instruments.length; + + for (i = 1; i < len; ++i) { + iheader = stream.readUnsignedInt(); + if ((stream.position + iheader) >= stream.length) break; + + instr = new F2Instrument(); + instr.name = stream.readMultiByte(22, ENCODING); + stream.position++; + + value = stream.readUnsignedShort(); + if (value > 16) value = 16; + header = stream.readUnsignedInt(); + if (reserved == 2 && header != 64) header = 64; + + if (value) { + instr.samples = new Vector.(value, true); + + for (j = 0; j < 96; ++j) + instr.noteSamples[j] = stream.readUnsignedByte(); + for (j = 0; j < 12; ++j) + instr.volData.points[j] = new F2Point(stream.readUnsignedShort(), stream.readUnsignedShort()); + for (j = 0; j < 12; ++j) + instr.panData.points[j] = new F2Point(stream.readUnsignedShort(), stream.readUnsignedShort()); + + instr.volData.total = stream.readUnsignedByte(); + instr.panData.total = stream.readUnsignedByte(); + instr.volData.sustain = stream.readUnsignedByte(); + instr.volData.loopStart = stream.readUnsignedByte(); + instr.volData.loopEnd = stream.readUnsignedByte(); + instr.panData.sustain = stream.readUnsignedByte(); + instr.panData.loopStart = stream.readUnsignedByte(); + instr.panData.loopEnd = stream.readUnsignedByte(); + instr.volData.flags = stream.readUnsignedByte(); + instr.panData.flags = stream.readUnsignedByte(); + + if (instr.volData.flags & ENVELOPE_ON) instr.volEnabled = 1; + if (instr.panData.flags & ENVELOPE_ON) instr.panEnabled = 1; + + instr.vibratoType = stream.readUnsignedByte(); + instr.vibratoSweep = stream.readUnsignedByte(); + instr.vibratoDepth = stream.readUnsignedByte(); + instr.vibratoSpeed = stream.readUnsignedByte(); + instr.fadeout = stream.readUnsignedShort() << 1; + + stream.position += reserved; + pos = stream.position; + instruments[i] = instr; + + for (j = 0; j < value; ++j) { + sample = new F2Sample(); + sample.length = stream.readUnsignedInt(); + sample.loopStart = stream.readUnsignedInt(); + sample.loopLen = stream.readUnsignedInt(); + sample.volume = stream.readUnsignedByte(); + sample.finetune = stream.readByte(); + sample.loopMode = stream.readUnsignedByte(); + sample.panning = stream.readUnsignedByte(); + sample.relative = stream.readByte(); + + stream.position++; + sample.name = stream.readMultiByte(22, ENCODING); + instr.samples[j] = sample; + + stream.position = (pos += header); + } + + for (j = 0; j < value; ++j) { + sample = instr.samples[j]; + if (!sample.length) continue; + pos = stream.position + sample.length; + + if (sample.loopMode & 16) { + sample.bits = 16; + sample.loopMode ^= 16; + sample.length >>= 1; + sample.loopStart >>= 1; + sample.loopLen >>= 1; + } + + if (!sample.loopLen) sample.loopMode = 0; + sample.store(stream); + if (sample.loopMode) sample.length = sample.loopStart + sample.loopLen; + stream.position = pos; + } + } else { + stream.position = ipos + iheader; + } + + ipos = stream.position; + if (ipos >= stream.length) break; + } + + instr = new F2Instrument(); + instr.volData = new F2Data(); + instr.panData = new F2Data(); + instr.samples = new Vector.(1, true); + + for (i = 0; i < 12; ++i) { + instr.volData.points[i] = new F2Point(); + instr.panData.points[i] = new F2Point(); + } + + sample = new F2Sample(); + sample.length = 220; + sample.data = new Vector.(220, true); + + for (i = 0; i < 220; ++i) sample.data[i] = 0.0; + + instr.samples[0] = sample; + instruments[0] = instr; + } + + private function envelope(voice:F2Voice, envelope:F2Envelope, data:F2Data):void { + var pos:int = envelope.position, curr:F2Point = data.points[pos], next:F2Point; + + if (envelope.frame == curr.frame) { + if ((data.flags & ENVELOPE_LOOP) && pos == data.loopEnd) { + pos = envelope.position = data.loopStart; + curr = data.points[pos]; + envelope.frame = curr.frame; + } + + if (pos == (data.total - 1)) { + envelope.value = curr.value; + envelope.stopped = 1; + return; + } + + if ((data.flags & ENVELOPE_SUSTAIN) && pos == data.sustain && !voice.fadeEnabled) { + envelope.value = curr.value; + return; + } + + envelope.position++; + next = data.points[envelope.position]; + + envelope.delta = ((next.value - curr.value) << 8) / (next.frame - curr.frame); + envelope.fraction = (curr.value << 8); + } else { + envelope.fraction += envelope.delta; + } + + envelope.value = (envelope.fraction >> 8); + envelope.frame++; + } + + private function amiga(note:int, finetune:int):int { + var delta:Number = 0.0, period:int = PERIODS[++note]; + + if (finetune < 0) { + delta = (PERIODS[--note] - period) / 64; + } else if (finetune > 0) { + delta = (period - PERIODS[++note]) / 64; + } + + return int(period - (delta * finetune)); + } + + private function retrig(voice:F2Voice):void { + switch (voice.retrigx) { + case 1: + voice.volume--; + break; + case 2: + voice.volume++; + break; + case 3: + voice.volume -= 4; + break; + case 4: + voice.volume -= 8; + break; + case 5: + voice.volume -= 16; + break; + case 6: + voice.volume = (voice.volume << 1) / 3; + break; + case 7: + voice.volume >>= 1; + break; + case 8: + voice.volume = voice.sample.volume; + break; + case 9: + voice.volume++; + break; + case 10: + voice.volume += 2; + break; + case 11: + voice.volume += 4; + break; + case 12: + voice.volume += 8; + break; + case 13: + voice.volume += 16; + break; + case 14: + voice.volume = (voice.volume * 3) >> 1; + break; + case 15: + voice.volume <<= 1; + break; + } + + if (voice.volume < 0) voice.volume = 0; + else if (voice.volume > 64) voice.volume = 64; + + voice.flags |= UPDATE_VOLUME; + } + + internal static const + UPDATE_PERIOD : int = 1, + UPDATE_VOLUME : int = 2, + UPDATE_PANNING : int = 4, + UPDATE_TRIGGER : int = 8, + UPDATE_ALL : int = 15, + SHORT_RAMP : int = 32, + + ENVELOPE_ON : int = 1, + ENVELOPE_SUSTAIN : int = 2, + ENVELOPE_LOOP : int = 4, + + LOWER_NOTE : int = 0, + HIGHER_NOTE : int = 118, + KEYOFF_NOTE : int = 97, + + FX_ARPEGGIO : int = 0, + FX_PORTAMENTO_UP : int = 1, + FX_PORTAMENTO_DOWN : int = 2, + FX_TONE_PORTAMENTO : int = 3, + FX_VIBRATO : int = 4, + FX_TONE_PORTA_VOLUME_SLIDE : int = 5, + FX_VIBRATO_VOLUME_SLIDE : int = 6, + FX_TREMOLO : int = 7, + FX_SET_PANNING : int = 8, + FX_SAMPLE_OFFSET : int = 9, + FX_VOLUME_SLIDE : int = 10, + FX_POSITION_JUMP : int = 11, + FX_SET_VOLUME : int = 12, + FX_PATTERN_BREAK : int = 13, + FX_EXTENDED_EFFECTS : int = 14, + FX_SET_SPEED : int = 15, + FX_SET_GLOBAL_VOLUME : int = 16, + FX_GLOBAL_VOLUME_SLIDE : int = 17, + FX_KEYOFF : int = 20, + FX_SET_ENVELOPE_POSITION : int = 21, + FX_PANNING_SLIDE : int = 24, + FX_MULTI_RETRIG_NOTE : int = 27, + FX_TREMOR : int = 29, + FX_EXTRA_FINE_PORTAMENTO : int = 33, + + EX_FINE_PORTAMENTO_UP : int = 1, + EX_FINE_PORTAMENTO_DOWN : int = 2, + EX_GLISSANDO_CONTROL : int = 3, + EX_VIBRATO_CONTROL : int = 4, + EX_SET_FINETUNE : int = 5, + EX_PATTERN_LOOP : int = 6, + EX_TREMOLO_CONTROL : int = 7, + EX_RETRIG_NOTE : int = 9, + EX_FINE_VOLUME_SLIDE_UP : int = 10, + EX_FINE_VOLUME_SLIDE_DOWN : int = 11, + EX_NOTE_CUT : int = 12, + EX_NOTE_DELAY : int = 13, + EX_PATTERN_DELAY : int = 14, + + VX_VOLUME_SLIDE_DOWN : int = 6, + VX_VOLUME_SLIDE_UP : int = 7, + VX_FINE_VOLUME_SLIDE_DOWN : int = 8, + VX_FINE_VOLUME_SLIDE_UP : int = 9, + VX_SET_VIBRATO_SPEED : int = 10, + VX_VIBRATO : int = 11, + VX_SET_PANNING : int = 12, + VX_PANNING_SLIDE_LEFT : int = 13, + VX_PANNING_SLIDE_RIGHT : int = 14, + VX_TONE_PORTAMENTO : int = 15, + + PANNING : Vector. = Vector.([ + 0.000000,0.044170,0.062489,0.076523,0.088371,0.098821,0.108239,0.116927,0.124977, + 0.132572,0.139741,0.146576,0.153077,0.159335,0.165350,0.171152,0.176772,0.182210, + 0.187496,0.192630,0.197643,0.202503,0.207273,0.211951,0.216477,0.220943,0.225348, + 0.229631,0.233854,0.237985,0.242056,0.246066,0.249985,0.253873,0.257670,0.261437, + 0.265144,0.268819,0.272404,0.275989,0.279482,0.282976,0.286409,0.289781,0.293153, + 0.296464,0.299714,0.302965,0.306185,0.309344,0.312473,0.315602,0.318671,0.321708, + 0.324746,0.327754,0.330700,0.333647,0.336563,0.339449,0.342305,0.345161,0.347986, + 0.350781,0.353545,0.356279,0.359013,0.361717,0.364421,0.367094,0.369737,0.372380, + 0.374992,0.377574,0.380157,0.382708,0.385260,0.387782,0.390303,0.392794,0.395285, + 0.397746,0.400176,0.402606,0.405037,0.407437,0.409836,0.412206,0.414576,0.416915, + 0.419254,0.421563,0.423841,0.426180,0.428458,0.430737,0.432985,0.435263,0.437481, + 0.439729,0.441916,0.444134,0.446321,0.448508,0.450665,0.452852,0.455009,0.457136, + 0.459262,0.461389,0.463485,0.465611,0.467708,0.469773,0.471839,0.473935,0.475970, + 0.478036,0.480072,0.482077,0.484112,0.486117,0.488122,0.490127,0.492101,0.494106, + 0.496051,0.498025,0.500000,0.501944,0.503888,0.505802,0.507746,0.509660,0.511574, + 0.513488,0.515371,0.517255,0.519138,0.521022,0.522905,0.524758,0.526611,0.528465, + 0.530318,0.532140,0.533993,0.535816,0.537639,0.539462,0.541254,0.543046,0.544839, + 0.546631,0.548423,0.550216,0.551978,0.553739,0.555501,0.557263,0.558995,0.560757, + 0.562489,0.564220,0.565952,0.567683,0.569384,0.571116,0.572817,0.574518,0.576220, + 0.577890,0.579592,0.581262,0.582964,0.584634,0.586305,0.587946,0.589617,0.591257, + 0.592928,0.594568,0.596209,0.597849,0.599459,0.601100,0.602710,0.604350,0.605960, + 0.607570,0.609150,0.610760,0.612370,0.613950,0.615560,0.617139,0.618719,0.620268, + 0.621848,0.623428,0.624977,0.626557,0.628106,0.629655,0.631205,0.632754,0.634303, + 0.635822,0.637372,0.638890,0.640440,0.641959,0.643478,0.644966,0.646485,0.648004, + 0.649523,0.651012,0.652500,0.653989,0.655477,0.656966,0.658454,0.659943,0.661431, + 0.662890,0.664378,0.665836,0.667294,0.668783,0.670241,0.671699,0.673127,0.674585, + 0.676043,0.677471,0.678929,0.680357,0.681785,0.683213,0.684641,0.686068,0.687496, + 0.688894,0.690321,0.691749,0.693147,0.694574,0.695972,0.697369,0.698767,0.700164, + 0.701561,0.702928,0.704326,0.705723,0.707110]), + + VOLUMES : Vector. = Vector.([ + 0.000000,0.005863,0.013701,0.021569,0.029406,0.037244,0.045082,0.052919,0.060757, + 0.068625,0.076463,0.084300,0.092138,0.099976,0.107844,0.115681,0.123519,0.131357, + 0.139194,0.147032,0.154900,0.162738,0.170575,0.178413,0.186251,0.194119,0.201956, + 0.209794,0.217632,0.225469,0.233307,0.241175,0.249013,0.256850,0.264688,0.272526, + 0.280394,0.288231,0.296069,0.303907,0.311744,0.319582,0.327450,0.335288,0.343125, + 0.350963,0.358800,0.366669,0.374506,0.382344,0.390182,0.398019,0.405857,0.413725, + 0.421563,0.429400,0.437238,0.445076,0.452944,0.460781,0.468619,0.476457,0.484294, + 0.492132,0.500000]), + + PERIODS : Vector. = Vector.([ + 29024,27392,25856,24384,23040,21696,20480,19328,18240,17216,16256,15360,14512, + 13696,12928,12192,11520,10848,10240, 9664, 9120, 8608, 8128, 7680, 7256, 6848, + 6464, 6096, 5760, 5424, 5120, 4832, 4560, 4304, 4064, 3840, 3628, 3424, 3232, + 3048, 2880, 2712, 2560, 2416, 2280, 2152, 2032, 1920, 1814, 1712, 1616, 1524, + 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960, 907, 856, 808, 762, 720, + 678, 640, 604, 570, 538, 508, 480, 453, 428, 404, 381, 360, 339, + 320, 302, 285, 269, 254, 240, 227, 214, 202, 190, 180, 169, 160, + 151, 142, 134, 127, 120, 113, 107, 101, 95, 90, 85, 80, 75, + 71, 67, 63, 60, 57, 53, 50, 48, 45, 42, 40, 38, 36, + 34, 32, 30, 28]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/fasttracker/F2Point.as b/Flod 4.1/neoart/flod/fasttracker/F2Point.as new file mode 100644 index 0000000..5b0229c --- /dev/null +++ b/Flod 4.1/neoart/flod/fasttracker/F2Point.as @@ -0,0 +1,30 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.fasttracker { + + public final class F2Point { + internal var + frame : int, + value : int; + + public function F2Point(x:int = 0, y:int = 0) { + frame = x; + value = y; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/fasttracker/F2Row.as b/Flod 4.1/neoart/flod/fasttracker/F2Row.as new file mode 100644 index 0000000..738bf3d --- /dev/null +++ b/Flod 4.1/neoart/flod/fasttracker/F2Row.as @@ -0,0 +1,28 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.fasttracker { + + public final class F2Row { + internal var + note : int, + instrument : int, + volume : int, + effect : int, + param : int; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/fasttracker/F2Sample.as b/Flod 4.1/neoart/flod/fasttracker/F2Sample.as new file mode 100644 index 0000000..c8184f2 --- /dev/null +++ b/Flod 4.1/neoart/flod/fasttracker/F2Sample.as @@ -0,0 +1,27 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.fasttracker { + import neoart.flod.core.*; + + public final class F2Sample extends SBSample { + public var + finetune : int, + panning : int, + relative : int; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/fasttracker/F2Voice.as b/Flod 4.1/neoart/flod/fasttracker/F2Voice.as new file mode 100644 index 0000000..6d755ba --- /dev/null +++ b/Flod 4.1/neoart/flod/fasttracker/F2Voice.as @@ -0,0 +1,255 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.fasttracker { + import neoart.flod.core.*; + + public final class F2Voice { + internal var + index : int, + next : F2Voice, + flags : int, + delay : int, + channel : SBChannel, + patternLoop : int, + patternLoopRow : int, + playing : F2Instrument, + note : int, + keyoff : int, + period : int, + finetune : int, + arpDelta : int, + vibDelta : int, + instrument : F2Instrument, + autoVibratoPos : int, + autoSweep : int, + autoSweepPos : int, + sample : F2Sample, + sampleOffset : int, + volume : int, + volEnabled : int, + volEnvelope : F2Envelope, + volDelta : int, + volSlide : int, + volSlideMaster : int, + fineSlideU : int, + fineSlideD : int, + fadeEnabled : int, + fadeDelta : int, + fadeVolume : int, + panning : int, + panEnabled : int, + panEnvelope : F2Envelope, + panSlide : int, + portaU : int, + portaD : int, + finePortaU : int, + finePortaD : int, + xtraPortaU : int, + xtraPortaD : int, + portaPeriod : int, + portaSpeed : int, + glissando : int, + glissPeriod : int, + vibratoPos : int, + vibratoSpeed : int, + vibratoDepth : int, + vibratoReset : int, + tremoloPos : int, + tremoloSpeed : int, + tremoloDepth : int, + waveControl : int, + tremorPos : int, + tremorOn : int, + tremorOff : int, + tremorVolume : int, + retrigx : int, + retrigy : int; + + public function F2Voice(index:int) { + this.index = index; + volEnvelope = new F2Envelope(); + panEnvelope = new F2Envelope(); + } + + internal function reset():void { + volume = sample.volume; + panning = sample.panning; + finetune = (sample.finetune >> 3) << 2; + keyoff = 0; + volDelta = 0; + + fadeEnabled = 0; + fadeDelta = 0; + fadeVolume = 65536; + + autoVibratoPos = 0; + autoSweep = 1; + autoSweepPos = 0; + vibDelta = 0; + portaPeriod = 0; + vibratoReset = 0; + + if ((waveControl & 15) < 4) vibratoPos = 0; + if ((waveControl >> 4) < 4) tremoloPos = 0; + } + + internal function autoVibrato():int { + var delta:int; + + autoVibratoPos = (autoVibratoPos + playing.vibratoSpeed) & 255; + + switch (playing.vibratoType) { + case 0: + delta = AUTOVIBRATO[autoVibratoPos]; + break; + case 1: + if (autoVibratoPos < 128) delta = -64; + else delta = 64; + break; + case 2: + delta = ((64 + (autoVibratoPos >> 1)) & 127) - 64; + break; + case 3: + delta = ((64 - (autoVibratoPos >> 1)) & 127) - 64; + break; + } + + delta *= playing.vibratoDepth; + + if (autoSweep) { + if (!playing.vibratoSweep) { + autoSweep = 0; + } else { + if (autoSweepPos > playing.vibratoSweep) { + if (autoSweepPos & 2) delta *= (autoSweepPos / playing.vibratoSweep); + autoSweep = 0; + } else { + delta *= (++autoSweepPos / playing.vibratoSweep); + } + } + } + + flags |= F2Player.UPDATE_PERIOD; + return (delta >> 6); + } + + internal function tonePortamento():void { + if (!glissPeriod) glissPeriod = period; + + if (period < portaPeriod) { + glissPeriod += portaSpeed << 2; + + if (!glissando) period = glissPeriod; + else period = Math.round(glissPeriod / 64) << 6; + + if (period >= portaPeriod) { + period = portaPeriod; + glissPeriod = portaPeriod = 0; + } + } else if (period > portaPeriod) { + glissPeriod -= portaSpeed << 2; + + if (!glissando) period = glissPeriod; + else period = Math.round(glissPeriod / 64) << 6; + + if (period <= portaPeriod) { + period = portaPeriod; + glissPeriod = portaPeriod = 0; + } + } + + flags |= F2Player.UPDATE_PERIOD; + } + + internal function tremolo():void { + var delta:int = 255, position:int = tremoloPos & 31; + + switch ((waveControl >> 4) & 3) { + case 0: + delta = VIBRATO[position]; + break; + case 1: + delta = position << 3; + break; + } + + volDelta = (delta * tremoloDepth) >> 6; + if (tremoloPos > 31) volDelta = -volDelta; + tremoloPos = (tremoloPos + tremoloSpeed) & 63; + + flags |= F2Player.UPDATE_VOLUME; + } + + internal function tremor():void { + if (tremorPos == tremorOn) { + tremorVolume = volume; + volume = 0; + flags |= F2Player.UPDATE_VOLUME; + } else if (tremorPos == tremorOff) { + tremorPos = 0; + volume = tremorVolume; + flags |= F2Player.UPDATE_VOLUME; + } + + ++tremorPos; + } + + internal function vibrato():void { + var delta:int = 255, position:int = vibratoPos & 31; + + switch (waveControl & 3) { + case 0: + delta = VIBRATO[position]; + break; + case 1: + delta = position << 3; + if (vibratoPos > 31) delta = 255 - delta; + break; + } + + vibDelta = (delta * vibratoDepth) >> 7; + if (vibratoPos > 31) vibDelta = -vibDelta; + vibratoPos = (vibratoPos + vibratoSpeed) & 63; + + flags |= F2Player.UPDATE_PERIOD; + } + + private static const + AUTOVIBRATO : Vector. = Vector.([ + 0, -2, -3, -5, -6, -8, -9,-11,-12,-14,-16,-17,-19,-20,-22,-23, + -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44, + -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59, + -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64, + -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60, + -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46, + -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26, + -24,-23,-22,-20,-19,-17,-16,-14,-12,-11, -9, -8, -6, -5, -3, -2, + 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23, + 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, + 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60, + 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, + 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26, + 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2]), + + VIBRATO : Vector. = Vector.([ + 0, 24, 49, 74, 97,120,141,161,180,197,212,224,235,244,250,253, + 255,253,250,244,235,224,212,197,180,161,141,120, 97, 74, 49, 24]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/fred/FEPlayer.as b/Flod 4.1/neoart/flod/fred/FEPlayer.as new file mode 100644 index 0000000..3f07c7d --- /dev/null +++ b/Flod 4.1/neoart/flod/fred/FEPlayer.as @@ -0,0 +1,599 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/24 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.fred { + import flash.utils.*; + import neoart.flod.core.*; + + public final class FEPlayer extends AmigaPlayer { + private var + songs : Vector., + samples : Vector., + patterns : ByteArray, + song : FESong, + voices : Vector., + complete : int, + sampFlag : int; + + public function FEPlayer(amiga:Amiga = null) { + super(amiga); + voices = new Vector.(4, true); + + voices[3] = new FEVoice(3,8); + voices[3].next = voices[2] = new FEVoice(2,4); + voices[2].next = voices[1] = new FEVoice(1,2); + voices[1].next = voices[0] = new FEVoice(0,1); + } + + override public function process():void { + var chan:AmigaChannel, i:int, j:int, len:int, loop:int, pos:int, sample:FESample, value:int, voice:FEVoice = voices[3]; + + while (voice) { + chan = voice.channel; + loop = 0; + + do { + patterns.position = voice.patternPos; + sample = voice.sample; + sampFlag = 0; + + if (!voice.busy) { + voice.busy = 1; + + if (sample.loopPtr == 0) { + chan.pointer = amiga.loopPtr; + chan.length = amiga.loopLen; + } else if (sample.loopPtr > 0) { + chan.pointer = (sample.type) ? voice.synth : sample.pointer + sample.loopPtr; + chan.length = sample.length - sample.loopPtr; + } + } + + if (--voice.tick == 0) { + loop = 2; + + while (loop > 1) { + value = patterns.readByte(); + + if (value < 0) { + switch (value) { + case -125: + voice.sample = sample = samples[patterns.readUnsignedByte()]; + sampFlag = 1; + voice.patternPos = patterns.position; + break; + case -126: + speed = patterns.readUnsignedByte(); + voice.patternPos = patterns.position; + break; + case -127: + value = (sample) ? sample.relative : 428; + voice.portaSpeed = patterns.readUnsignedByte() * speed; + voice.portaNote = patterns.readUnsignedByte(); + voice.portaLimit = (PERIODS[voice.portaNote] * value) >> 10; + voice.portamento = 0; + voice.portaDelay = patterns.readUnsignedByte() * speed; + voice.portaFlag = 1; + voice.patternPos = patterns.position; + break; + case -124: + chan.enabled = 0; + voice.tick = speed; + voice.busy = 1; + voice.patternPos = patterns.position; + loop = 0; + break; + case -128: + voice.trackPos++; + + while (1) { + value = song.tracks[voice.index][voice.trackPos]; + + if (value == 65535) { + amiga.complete = 1; + } else if (value > 32767) { + voice.trackPos = (value ^ 32768) >> 1; + + if (!loopSong) { + complete &= ~(voice.bitFlag); + if (!complete) amiga.complete = 1; + } + } else { + voice.patternPos = value; + voice.tick = 1; + loop = 1; + break; + } + } + break; + default: + voice.tick = speed * -value; + voice.patternPos = patterns.position; + loop = 0; + break; + } + } else { + loop = 0; + voice.patternPos = patterns.position; + + voice.note = value; + voice.arpeggioPos = 0; + voice.vibratoFlag = -1; + voice.vibrato = 0; + + voice.arpeggioSpeed = sample.arpeggioSpeed; + voice.vibratoDelay = sample.vibratoDelay; + voice.vibratoSpeed = sample.vibratoSpeed; + voice.vibratoDepth = sample.vibratoDepth; + + if (sample.type == 1) { + if (sampFlag || (sample.synchro & 2)) { + voice.pulseCounter = sample.pulseCounter; + voice.pulseDelay = sample.pulseDelay; + voice.pulseDir = 0; + voice.pulsePos = sample.pulsePosL; + voice.pulseSpeed = sample.pulseSpeed; + + i = voice.synth; + len = i + sample.pulsePosL; + for (; i < len; ++i) amiga.memory[i] = sample.pulseRateNeg; + len += (sample.length - sample.pulsePosL); + for (; i < len; ++i) amiga.memory[i] = sample.pulseRatePos; + } + + chan.pointer = voice.synth; + } else if (sample.type == 2) { + voice.blendCounter = sample.blendCounter; + voice.blendDelay = sample.blendDelay; + voice.blendDir = 0; + voice.blendPos = 1; + + i = sample.pointer; + j = voice.synth; + len = i + 31; + for (; i < len; ++i) amiga.memory[j++] = amiga.memory[i]; + + chan.pointer = voice.synth; + } else { + chan.pointer = sample.pointer; + } + + voice.tick = speed; + voice.busy = 0; + voice.period = (PERIODS[voice.note] * sample.relative) >> 10; + + voice.volume = 0; + voice.envelopePos = 0; + voice.sustainTime = sample.sustainTime; + + chan.length = sample.length; + chan.period = voice.period; + chan.volume = 0; + chan.enabled = 1; + + if (voice.portaFlag) { + if (!voice.portamento) { + voice.portamento = voice.period; + voice.portaCounter = 1; + voice.portaPeriod = voice.portaLimit - voice.period; + } + } + } + } + } else if (voice.tick == 1) { + value = (patterns[voice.patternPos] - 160) & 255; + if (value > 127) chan.enabled = 0; + } + } while (loop > 0); + + if (!chan.enabled) { + voice = voice.next; + continue; + } + + value = voice.note + sample.arpeggio[voice.arpeggioPos]; + + if (--voice.arpeggioSpeed == 0) { + voice.arpeggioSpeed = sample.arpeggioSpeed; + + if (++voice.arpeggioPos == sample.arpeggioLimit) + voice.arpeggioPos = 0; + } + + voice.period = (PERIODS[value] * sample.relative) >> 10; + + if (voice.portaFlag) { + if (voice.portaDelay) { + voice.portaDelay--; + } else { + voice.period += ((voice.portaCounter * voice.portaPeriod) / voice.portaSpeed); + + if (++voice.portaCounter > voice.portaSpeed) { + voice.note = voice.portaNote; + voice.portaFlag = 0; + } + } + } + + if (voice.vibratoDelay) { + voice.vibratoDelay--; + } else { + if (voice.vibratoFlag) { + if (voice.vibratoFlag < 0) { + voice.vibrato += voice.vibratoSpeed; + + if (voice.vibrato == voice.vibratoDepth) + voice.vibratoFlag ^= 0x80000000; + } else { + voice.vibrato -= voice.vibratoSpeed; + + if (voice.vibrato == 0) + voice.vibratoFlag ^= 0x80000000; + } + + if (voice.vibrato == 0) voice.vibratoFlag ^= 1; + + if (voice.vibratoFlag & 1) { + voice.period += voice.vibrato; + } else { + voice.period -= voice.vibrato; + } + } + } + + chan.period = voice.period; + + switch (voice.envelopePos) { + case 4: break; + case 0: + voice.volume += sample.attackSpeed; + + if (voice.volume >= sample.attackVol) { + voice.volume = sample.attackVol; + voice.envelopePos = 1; + } + break; + case 1: + voice.volume -= sample.decaySpeed; + + if (voice.volume <= sample.decayVol) { + voice.volume = sample.decayVol; + voice.envelopePos = 2; + } + break; + case 2: + if (voice.sustainTime) { + voice.sustainTime--; + } else { + voice.envelopePos = 3; + } + break; + case 3: + voice.volume -= sample.releaseSpeed; + + if (voice.volume <= sample.releaseVol) { + voice.volume = sample.releaseVol; + voice.envelopePos = 4; + } + break; + } + + value = sample.envelopeVol << 12; + value >>= 8; + value >>= 4; + value *= voice.volume; + value >>= 8; + value >>= 1; + chan.volume = value; + + if (sample.type == 1) { + if (voice.pulseDelay) { + voice.pulseDelay--; + } else { + if (voice.pulseSpeed) { + voice.pulseSpeed--; + } else { + if (voice.pulseCounter || !(sample.synchro & 1)) { + voice.pulseSpeed = sample.pulseSpeed; + + if (voice.pulseDir & 4) { + while (1) { + if (voice.pulsePos >= sample.pulsePosL) { + loop = 1; + break; + } + + voice.pulseDir &= -5; + voice.pulsePos++; + voice.pulseCounter--; + + if (voice.pulsePos <= sample.pulsePosH) { + loop = 2; + break; + } + + voice.pulseDir |= 4; + voice.pulsePos--; + voice.pulseCounter--; + } + } else { + while (1) { + if (voice.pulsePos <= sample.pulsePosH) { + loop = 2; + break; + } + + voice.pulseDir |= 4; + voice.pulsePos--; + voice.pulseCounter--; + + if (voice.pulsePos >= sample.pulsePosL) { + loop = 1; + break; + } + + voice.pulseDir &= -5; + voice.pulsePos++; + voice.pulseCounter++; + } + } + + pos = voice.synth + voice.pulsePos; + + if (loop == 1) { + amiga.memory[pos] = sample.pulseRatePos; + voice.pulsePos--; + } else { + amiga.memory[pos] = sample.pulseRateNeg; + voice.pulsePos++; + } + } + } + } + } else if (sample.type == 2) { + if (voice.blendDelay) { + voice.blendDelay--; + } else { + if (voice.blendCounter || !(sample.synchro & 4)) { + if (voice.blendDir) { + if (voice.blendPos != 1) { + voice.blendPos--; + } else { + voice.blendDir ^= 1; + voice.blendCounter--; + } + } else { + if (voice.blendPos != (sample.blendRate << 1)) { + voice.blendPos++; + } else { + voice.blendDir ^= 1; + voice.blendCounter--; + } + } + + i = sample.pointer; + j = voice.synth; + len = i + 31; + pos = len + 1; + + for (; i < len; ++i) { + value = (voice.blendPos * amiga.memory[pos++]) >> sample.blendRate; + amiga.memory[pos++] = value + amiga.memory[i]; + } + } + } + } + + voice = voice.next; + } + } + + override protected function initialize():void { + var i:int, len:int, voice:FEVoice = voices[3]; + super.initialize(); + + song = songs[playSong]; + speed = song.speed; + + complete = 15; + + while (voice) { + voice.initialize(); + voice.channel = amiga.channels[voice.index]; + voice.patternPos = song.tracks[voice.index][0]; + + i = voice.synth; + len = i + 64; + for (; i < len; ++i) amiga.memory[i] = 0; + + voice = voice.next; + } + } + + override protected function loader(stream:ByteArray):void { + var basePtr:int, dataPtr:int, i:int, j:int, len:int, pos:int, ptr:int, sample:FESample, size:int, song:FESong, tracksLen:int, value:int; + + while (stream.position < 16) { + value = stream.readUnsignedShort(); + stream.position += 2; + if (value != 0x4efa) return; //jmp + } + + while (stream.position < 1024) { + value = stream.readUnsignedShort(); + + if (value == 0x123a) { //move.b $x,d1 + stream.position += 2; + value = stream.readUnsignedShort(); + + if (value == 0xb001) { //cmp.b d1,d0 + stream.position -= 4; + dataPtr = (stream.position + stream.readUnsignedShort()) - 0x895; + } + } else if (value == 0x214a) { //move.l a2,(a0) + stream.position += 2; + value = stream.readUnsignedShort(); + + if (value == 0x47fa) { //lea $x,a3 + basePtr = stream.position + stream.readShort(); + version = 1; + break; + } + } + } + + if (!version) return; + + stream.position = dataPtr + 0x8a2; + pos = stream.readUnsignedInt(); + stream.position = basePtr + pos; + samples = new Vector.(); + pos = 0x7fffffff; + + while (pos > stream.position) { + value = stream.readUnsignedInt(); + + if (value) { + if ((value < stream.position) || (value >= stream.length)) { + stream.position -= 4; + break; + } + + if (value < pos) pos = basePtr + value; + } + + sample = new FESample(); + sample.pointer = value; + sample.loopPtr = stream.readShort(); + sample.length = stream.readUnsignedShort() << 1; + sample.relative = stream.readUnsignedShort(); + + sample.vibratoDelay = stream.readUnsignedByte(); + stream.position++; + sample.vibratoSpeed = stream.readUnsignedByte(); + sample.vibratoDepth = stream.readUnsignedByte(); + sample.envelopeVol = stream.readUnsignedByte(); + sample.attackSpeed = stream.readUnsignedByte(); + sample.attackVol = stream.readUnsignedByte(); + sample.decaySpeed = stream.readUnsignedByte(); + sample.decayVol = stream.readUnsignedByte(); + sample.sustainTime = stream.readUnsignedByte(); + sample.releaseSpeed = stream.readUnsignedByte(); + sample.releaseVol = stream.readUnsignedByte(); + + for (i = 0; i < 16; ++i) sample.arpeggio[i] = stream.readByte(); + + sample.arpeggioSpeed = stream.readUnsignedByte(); + sample.type = stream.readByte(); + sample.pulseRateNeg = stream.readByte(); + sample.pulseRatePos = stream.readUnsignedByte(); + sample.pulseSpeed = stream.readUnsignedByte(); + sample.pulsePosL = stream.readUnsignedByte(); + sample.pulsePosH = stream.readUnsignedByte(); + sample.pulseDelay = stream.readUnsignedByte(); + sample.synchro = stream.readUnsignedByte(); + sample.blendRate = stream.readUnsignedByte(); + sample.blendDelay = stream.readUnsignedByte(); + sample.pulseCounter = stream.readUnsignedByte(); + sample.blendCounter = stream.readUnsignedByte(); + sample.arpeggioLimit = stream.readUnsignedByte(); + + stream.position += 12; + samples.push(sample); + if (!stream.bytesAvailable) break; + } + + samples.fixed = true; + + if (pos != 0x7fffffff) { + amiga.store(stream, stream.length - pos); + len = samples.length; + + for (i = 0; i < len; ++i) { + sample = samples[i]; + if (sample.pointer) sample.pointer -= (basePtr + pos); + } + } + + pos = amiga.memory.length; + amiga.memory.length += 256; + amiga.loopLen = 100; + + for (i = 0; i < 4; ++i) { + voices[i].synth = pos; + pos += 64; + } + + patterns = new ByteArray(); + stream.position = dataPtr + 0x8a2; + len = stream.readUnsignedInt(); + pos = stream.readUnsignedInt(); + stream.position = basePtr + pos; + stream.readBytes(patterns, 0, (len - pos)); + pos += basePtr; + + stream.position = dataPtr + 0x895; + lastSong = len = stream.readUnsignedByte(); + + songs = new Vector.(++len, true); + basePtr = dataPtr + 0xb0e; + tracksLen = pos - basePtr; + pos = 0; + + for (i = 0; i < len; ++i) { + song = new FESong(); + + for (j = 0; j < 4; ++j) { + stream.position = basePtr + pos; + value = stream.readUnsignedShort(); + + if (j == 3 && (i == (len - 1))) size = tracksLen; + else size = stream.readUnsignedShort(); + + size = (size - value) >> 1; + if (size > song.length) song.length = size; + + song.tracks[j] = new Vector.(size, true); + stream.position = basePtr + value; + + for (ptr = 0; ptr < size; ++ptr) + song.tracks[j][ptr] = stream.readUnsignedShort(); + + pos += 2; + } + + stream.position = dataPtr + 0x897 + i; + song.speed = stream.readUnsignedByte(); + songs[i] = song; + } + + stream.clear(); + stream = null; + } + + private const + PERIODS : Vector. = Vector.([ + 8192,7728,7296,6888,6504,6136,5792,5464,5160, + 4872,4600,4336,4096,3864,3648,3444,3252,3068, + 2896,2732,2580,2436,2300,2168,2048,1932,1824, + 1722,1626,1534,1448,1366,1290,1218,1150,1084, + 1024, 966, 912, 861, 813, 767, 724, 683, 645, + 609, 575, 542, 512, 483, 456, 430, 406, 383, + 362, 341, 322, 304, 287, 271, 256, 241, 228, + 215, 203, 191, 181, 170, 161, 152, 143, 135]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/fred/FESample.as b/Flod 4.1/neoart/flod/fred/FESample.as new file mode 100644 index 0000000..09cf0a1 --- /dev/null +++ b/Flod 4.1/neoart/flod/fred/FESample.as @@ -0,0 +1,57 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/02/16 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.fred { + + public final class FESample { + internal var + pointer : int, + loopPtr : int, + length : int, + relative : int, + type : int, + synchro : int, + envelopeVol : int, + attackSpeed : int, + attackVol : int, + decaySpeed : int, + decayVol : int, + sustainTime : int, + releaseSpeed : int, + releaseVol : int, + arpeggio : Vector., + arpeggioLimit : int, + arpeggioSpeed : int, + vibratoDelay : int, + vibratoDepth : int, + vibratoSpeed : int, + pulseCounter : int, + pulseDelay : int, + pulsePosL : int, + pulsePosH : int, + pulseSpeed : int, + pulseRateNeg : int, + pulseRatePos : int, + blendCounter : int, + blendDelay : int, + blendRate : int; + + public function FESample() { + arpeggio = new Vector.(16, true); + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/fred/FESong.as b/Flod 4.1/neoart/flod/fred/FESong.as new file mode 100644 index 0000000..b5f77ff --- /dev/null +++ b/Flod 4.1/neoart/flod/fred/FESong.as @@ -0,0 +1,30 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/02/16 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.fred { + + public final class FESong { + internal var + speed : int, + length : int, + tracks : Vector.>; + + public function FESong() { + tracks = new Vector.>(4, true); + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/fred/FEVoice.as b/Flod 4.1/neoart/flod/fred/FEVoice.as new file mode 100644 index 0000000..af8a30a --- /dev/null +++ b/Flod 4.1/neoart/flod/fred/FEVoice.as @@ -0,0 +1,106 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/02/16 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.fred { + import neoart.flod.core.*; + + public final class FEVoice { + internal var + index : int, + bitFlag : int, + next : FEVoice, + channel : AmigaChannel, + sample : FESample, + trackPos : int, + patternPos : int, + tick : int, + busy : int, + synth : int, + note : int, + period : int, + volume : int, + envelopePos : int, + sustainTime : int, + arpeggioPos : int, + arpeggioSpeed : int, + portamento : int, + portaCounter : int, + portaDelay : int, + portaFlag : int, + portaLimit : int, + portaNote : int, + portaPeriod : int, + portaSpeed : int, + vibrato : int, + vibratoDelay : int, + vibratoDepth : int, + vibratoFlag : int, + vibratoSpeed : int, + pulseCounter : int, + pulseDelay : int, + pulseDir : int, + pulsePos : int, + pulseSpeed : int, + blendCounter : int, + blendDelay : int, + blendDir : int, + blendPos : int; + + public function FEVoice(index:int, bitFlag:int) { + this.index = index; + this.bitFlag = bitFlag; + } + + internal function initialize():void { + channel = null; + sample = null; + trackPos = 0; + patternPos = 0; + tick = 1; + busy = 1; + note = 0; + period = 0; + volume = 0; + envelopePos = 0; + sustainTime = 0; + arpeggioPos = 0; + arpeggioSpeed = 0; + portamento = 0; + portaCounter = 0; + portaDelay = 0; + portaFlag = 0; + portaLimit = 0; + portaNote = 0; + portaPeriod = 0; + portaSpeed = 0; + vibrato = 0; + vibratoDelay = 0; + vibratoDepth = 0; + vibratoFlag = 0; + vibratoSpeed = 0; + pulseCounter = 0; + pulseDelay = 0; + pulseDir = 0; + pulsePos = 0; + pulseSpeed = 0; + blendCounter = 0; + blendDelay = 0; + blendDir = 0; + blendPos = 0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/futurecomposer/FCPlayer.as b/Flod 4.1/neoart/flod/futurecomposer/FCPlayer.as new file mode 100644 index 0000000..de046de --- /dev/null +++ b/Flod 4.1/neoart/flod/futurecomposer/FCPlayer.as @@ -0,0 +1,615 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/11 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.futurecomposer { + import flash.utils.*; + import neoart.flod.core.*; + + public final class FCPlayer extends AmigaPlayer { + private var + seqs : ByteArray, + pats : ByteArray, + vols : ByteArray, + frqs : ByteArray, + length : int, + samples : Vector., + voices : Vector.; + + public function FCPlayer(amiga:Amiga = null) { + super(amiga); + PERIODS.fixed = true; + WAVES.fixed = true; + + voices = new Vector.(4, true); + + voices[0] = new FCVoice(0); + voices[0].next = voices[1] = new FCVoice(1); + voices[1].next = voices[2] = new FCVoice(2); + voices[2].next = voices[3] = new FCVoice(3); + } + + override public function process():void { + var base:int, chan:AmigaChannel, delta:int, i:int, info:int, loopEffect:int, loopSustain:int, period:int, sample:AmigaSample, temp:int, voice:FCVoice = voices[0]; + + if (--tick == 0) { + base = seqs.position; + + while (voice) { + chan = voice.channel; + + pats.position = voice.pattern + voice.patStep; + temp = pats.readUnsignedByte(); + + if (voice.patStep >= 64 || temp == 0x49) { + if (seqs.position == length) { + seqs.position = 0; + amiga.complete = 1; + } + + voice.patStep = 0; + voice.pattern = seqs.readUnsignedByte() << 6; + voice.transpose = seqs.readByte(); + voice.soundTranspose = seqs.readByte(); + + pats.position = voice.pattern; + temp = pats.readUnsignedByte(); + } + info = pats.readUnsignedByte(); + frqs.position = 0; + vols.position = 0; + + if (temp != 0) { + voice.note = temp & 0x7f; + voice.pitch = 0; + voice.portamento = 0; + voice.enabled = chan.enabled = 0; + + temp = 8 + (((info & 0x3f) + voice.soundTranspose) << 6); + if (temp >= 0 && temp < vols.length) vols.position = temp; + + voice.volStep = 0; + voice.volSpeed = voice.volCtr = vols.readUnsignedByte(); + voice.volSustain = 0; + + voice.frqPos = 8 + (vols.readUnsignedByte() << 6); + voice.frqStep = 0; + voice.frqSustain = 0; + + voice.vibratoFlag = 0; + voice.vibratoSpeed = vols.readUnsignedByte(); + voice.vibratoDepth = voice.vibrato = vols.readUnsignedByte(); + voice.vibratoDelay = vols.readUnsignedByte(); + voice.volPos = vols.position; + } + + if (info & 0x40) { + voice.portamento = 0; + } else if (info & 0x80) { + voice.portamento = pats[int(pats.position + 1)]; + if (version == FUTURECOMP_10) voice.portamento <<= 1; + } + voice.patStep += 2; + voice = voice.next; + } + + if (seqs.position != base) { + temp = seqs.readUnsignedByte(); + if (temp) speed = temp; + } + tick = speed; + } + voice = voices[0]; + + while (voice) { + chan = voice.channel; + + do { + loopSustain = 0; + + if (voice.frqSustain) { + voice.frqSustain--; + break; + } + frqs.position = voice.frqPos + voice.frqStep; + + do { + loopEffect = 0; + if (!frqs.bytesAvailable) break; + info = frqs.readUnsignedByte(); + if (info == 0xe1) break; + + if (info == 0xe0) { + voice.frqStep = frqs.readUnsignedByte() & 0x3f; + frqs.position = voice.frqPos + voice.frqStep; + info = frqs.readUnsignedByte(); + } + + switch (info) { + case 0xe2: //set wave + chan.enabled = 0; + voice.enabled = 1 + voice.volCtr = 1; + voice.volStep = 0; + case 0xe4: //change wave: + sample = samples[frqs.readUnsignedByte()]; + if (sample) { + chan.pointer = sample.pointer; + chan.length = sample.length; + } else { + voice.enabled = 0; + } + voice.sample = sample; + voice.frqStep += 2; + break; + case 0xe9: //set pack + temp = 100 + (frqs.readUnsignedByte() * 10); + sample = samples[int(temp + frqs.readUnsignedByte())]; + + if (sample) { + chan.enabled = 0; + chan.pointer = sample.pointer; + chan.length = sample.length; + voice.enabled = 1; + } + + voice.sample = sample; + voice.volCtr = 1; + voice.volStep = 0; + voice.frqStep += 3; + break; + case 0xe7: //new sequence + loopEffect = 1; + voice.frqPos = 8 + (frqs.readUnsignedByte() << 6); + if (voice.frqPos >= frqs.length) voice.frqPos = 0; + voice.frqStep = 0; + frqs.position = voice.frqPos; + break; + case 0xea: //pitch bend + voice.pitchBendSpeed = frqs.readByte(); + voice.pitchBendTime = frqs.readUnsignedByte(); + voice.frqStep += 3; + break; + case 0xe8: //sustain + loopSustain = 1; + voice.frqSustain = frqs.readUnsignedByte(); + voice.frqStep += 2; + break; + case 0xe3: //new vibrato + voice.vibratoSpeed = frqs.readUnsignedByte(); + voice.vibratoDepth = frqs.readUnsignedByte(); + voice.frqStep += 3; + break; + } + + if (!loopSustain && !loopEffect) { + frqs.position = voice.frqPos + voice.frqStep; + voice.frqTranspose = frqs.readByte(); + voice.frqStep++; + } + } while (loopEffect); + } while (loopSustain); + + if (voice.volSustain) { + voice.volSustain--; + } else { + if (voice.volBendTime) { + voice.volumeBend(); + } else { + if (--voice.volCtr == 0) { + voice.volCtr = voice.volSpeed; + + do { + loopEffect = 0; + vols.position = voice.volPos + voice.volStep; + if (!vols.bytesAvailable) break; + info = vols.readUnsignedByte(); + if (info == 0xe1) break; + + switch (info) { + case 0xea: //volume slide + voice.volBendSpeed = vols.readByte(); + voice.volBendTime = vols.readUnsignedByte(); + voice.volStep += 3; + voice.volumeBend(); + break; + case 0xe8: //volume sustain + voice.volSustain = vols.readUnsignedByte(); + voice.volStep += 2; + break; + case 0xe0: //volume loop + loopEffect = 1; + temp = vols.readUnsignedByte() & 0x3f; + voice.volStep = temp - 5; + break; + default: + voice.volume = info; + voice.volStep++; + break; + } + } while (loopEffect); + } + } + } + info = voice.frqTranspose; + if (info >= 0) info += (voice.note + voice.transpose); + info &= 0x7f; + period = PERIODS[info]; + + if (voice.vibratoDelay) { + voice.vibratoDelay--; + } else { + temp = voice.vibrato; + + if (voice.vibratoFlag) { + delta = voice.vibratoDepth << 1; + temp += voice.vibratoSpeed; + + if (temp > delta) { + temp = delta; + voice.vibratoFlag = 0; + } + } else { + temp -= voice.vibratoSpeed; + + if (temp < 0) { + temp = 0; + voice.vibratoFlag = 1; + } + } + voice.vibrato = temp; + temp -= voice.vibratoDepth; + base = (info << 1) + 160; + + while (base < 256) { + temp <<= 1; + base += 24; + } + period += temp; + } + voice.portamentoFlag ^= 1; + + if (voice.portamentoFlag && voice.portamento) { + if (voice.portamento > 0x1f) + voice.pitch += voice.portamento & 0x1f; + else + voice.pitch -= voice.portamento; + } + voice.pitchBendFlag ^= 1; + + if (voice.pitchBendFlag && voice.pitchBendTime) { + voice.pitchBendTime--; + voice.pitch -= voice.pitchBendSpeed; + } + period += voice.pitch; + + if (period < 113) period = 113; + else if (period > 3424) period = 3424; + + chan.period = period; + chan.volume = voice.volume; + + if (voice.sample) { + sample = voice.sample; + chan.enabled = voice.enabled; + chan.pointer = sample.loopPtr; + chan.length = sample.repeat; + } + voice = voice.next; + } + } + + override protected function initialize():void { + var voice:FCVoice = voices[0]; + super.initialize(); + + seqs.position = 0; + pats.position = 0; + vols.position = 0; + frqs.position = 0; + + while (voice) { + voice.initialize(); + voice.channel = amiga.channels[voice.index]; + + voice.pattern = seqs.readUnsignedByte() << 6; + voice.transpose = seqs.readByte(); + voice.soundTranspose = seqs.readByte(); + + voice = voice.next; + } + + speed = seqs.readUnsignedByte(); + if (!speed) speed = 3; + tick = speed; + } + + override protected function loader(stream:ByteArray):void { + var i:int = 0, id:String, j:int, len:int, offset:int, position:int, sample:AmigaSample, size:int, temp:int, total:int; + id = stream.readMultiByte(4, ENCODING); + + if (id == "SMOD") version = FUTURECOMP_10; + else if (id == "FC14") version = FUTURECOMP_14; + else return; + + stream.position = 4; + length = stream.readUnsignedInt(); + stream.position = version == FUTURECOMP_10 ? 100 : 180; + seqs = new ByteArray(); + stream.readBytes(seqs, 0, length); + length /= 13; + + stream.position = 12; + len = stream.readUnsignedInt(); + stream.position = 8; + stream.position = stream.readUnsignedInt(); + pats = new ByteArray(); + stream.readBytes(pats, 0, len); + + pats.position = pats.length; + pats.writeByte(0); + pats.position = 0; + + stream.position = 20; + len = stream.readUnsignedInt(); + stream.position = 16; + stream.position = stream.readUnsignedInt(); + frqs = new ByteArray(); + frqs.writeInt(0x01000000); + frqs.writeInt(0x000000e1); + stream.readBytes(frqs, 8, len); + + frqs.position = frqs.length; + frqs.writeByte(0xe1); + frqs.position = 0; + + stream.position = 28; + len = stream.readUnsignedInt(); + stream.position = 24; + stream.position = stream.readUnsignedInt(); + vols = new ByteArray(); + vols.writeInt(0x01000000); + vols.writeInt(0x000000e1); + stream.readBytes(vols, 8, len); + + stream.position = 32; + size = stream.readUnsignedInt(); + stream.position = 40; + + if (version == FUTURECOMP_10) { + samples = new Vector.(57, true); + offset = 0; + } else { + samples = new Vector.(200, true); + offset = 2; + } + + for (i = 0; i < 10; ++i) { + len = stream.readUnsignedShort() << 1; + + if (len > 0) { + position = stream.position; + stream.position = size; + id = stream.readMultiByte(4, ENCODING); + + if (id == "SSMP") { + temp = len; + + for (j = 0; j < 10; ++j) { + stream.readInt(); + len = stream.readUnsignedShort() << 1; + + if (len > 0) { + sample = new AmigaSample(); + sample.length = len + 2; + sample.loop = stream.readUnsignedShort(); + sample.repeat = stream.readUnsignedShort() << 1; + + if ((sample.loop + sample.repeat) > sample.length) + sample.repeat = sample.length - sample.loop; + + if ((size + sample.length) > stream.length) + sample.length = stream.length - size; + + sample.pointer = amiga.store(stream, sample.length, size + total); + sample.loopPtr = sample.pointer + sample.loop; + samples[int(100 + (i * 10) + j)] = sample; + total += sample.length; + stream.position += 6; + } else { + stream.position += 10; + } + } + + size += (temp + 2); + stream.position = position + 4; + } else { + stream.position = position; + sample = new AmigaSample(); + sample.length = len + offset; + sample.loop = stream.readUnsignedShort(); + sample.repeat = stream.readUnsignedShort() << 1; + + if ((sample.loop + sample.repeat) > sample.length) + sample.repeat = sample.length - sample.loop; + + if ((size + sample.length) > stream.length) + sample.length = stream.length - size; + + sample.pointer = amiga.store(stream, sample.length, size); + sample.loopPtr = sample.pointer + sample.loop; + samples[i] = sample; + size += sample.length; + } + } else { + stream.position += 4; + } + } + + if (version == FUTURECOMP_10) { + offset = 0; temp = 47; + + for (i = 10; i < 57; ++i) { + sample = new AmigaSample(); + sample.length = WAVES[offset++] << 1; + sample.loop = 0; + sample.repeat = sample.length; + + position = amiga.memory.length; + sample.pointer = position; + sample.loopPtr = position; + samples[i] = sample; + + len = position + sample.length; + + for (j = position; j < len; ++j) + amiga.memory[j] = WAVES[temp++]; + } + } else { + stream.position = 36; + size = stream.readUnsignedInt(); + stream.position = 100; + + for (i = 10; i < 90; ++i) { + len = stream.readUnsignedByte() << 1; + if (len < 2) continue; + + sample = new AmigaSample(); + sample.length = len; + sample.loop = 0; + sample.repeat = sample.length; + + if ((size + sample.length) > stream.length) + sample.length = stream.length - size; + + sample.pointer = amiga.store(stream, sample.length, size); + sample.loopPtr = sample.pointer; + samples[i] = sample; + size += sample.length; + } + } + + length *= 13; + } + + public static const + FUTURECOMP_10 = 1, + FUTURECOMP_14 = 2; + + private const + PERIODS: Vector. = Vector.([ + 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016, 960, 906, + 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453, + 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226, + 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 3424,3232,3048,2880,2712,2560,2416,2280,2152,2032,1920,1812, + 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016, 960, 906, + 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453, + 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226, + 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113]), + + WAVES: Vector. = Vector.([ + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 8, 8, 8, 8, 8, 8, 8, 8, 16, 8, 16, 16, 8, 8, 24, -64, + -64, -48, -40, -32, -24, -16, -8, 0, -8, -16, -24, -32, -40, -48, -56, 63, + 55, 47, 39, 31, 23, 15, 7, -1, 7, 15, 23, 31, 39, 47, 55, -64, + -64, -48, -40, -32, -24, -16, -8, 0, -8, -16, -24, -32, -40, -48, -56, -64, + 55, 47, 39, 31, 23, 15, 7, -1, 7, 15, 23, 31, 39, 47, 55, -64, + -64, -48, -40, -32, -24, -16, -8, 0, -8, -16, -24, -32, -40, -48, -56, -64, + -72, 47, 39, 31, 23, 15, 7, -1, 7, 15, 23, 31, 39, 47, 55, -64, + -64, -48, -40, -32, -24, -16, -8, 0, -8, -16, -24, -32, -40, -48, -56, -64, + -72, -80, 39, 31, 23, 15, 7, -1, 7, 15, 23, 31, 39, 47, 55, -64, + -64, -48, -40, -32, -24, -16, -8, 0, -8, -16, -24, -32, -40, -48, -56, -64, + -72, -80, -88, 31, 23, 15, 7, -1, 7, 15, 23, 31, 39, 47, 55, -64, + -64, -48, -40, -32, -24, -16, -8, 0, -8, -16, -24, -32, -40, -48, -56, -64, + -72, -80, -88, -96, 23, 15, 7, -1, 7, 15, 23, 31, 39, 47, 55, -64, + -64, -48, -40, -32, -24, -16, -8, 0, -8, -16, -24, -32, -40, -48, -56, -64, + -72, -80, -88, -96,-104, 15, 7, -1, 7, 15, 23, 31, 39, 47, 55, -64, + -64, -48, -40, -32, -24, -16, -8, 0, -8, -16, -24, -32, -40, -48, -56, -64, + -72, -80, -88, -96,-104,-112, 7, -1, 7, 15, 23, 31, 39, 47, 55, -64, + -64, -48, -40, -32, -24, -16, -8, 0, -8, -16, -24, -32, -40, -48, -56, -64, + -72, -80, -88, -96,-104,-112,-120, -1, 7, 15, 23, 31, 39, 47, 55, -64, + -64, -48, -40, -32, -24, -16, -8, 0, -8, -16, -24, -32, -40, -48, -56, -64, + -72, -80, -88, -96,-104,-112,-120,-128, 7, 15, 23, 31, 39, 47, 55, -64, + -64, -48, -40, -32, -24, -16, -8, 0, -8, -16, -24, -32, -40, -48, -56, -64, + -72, -80, -88, -96,-104,-112,-120,-128,-120, 15, 23, 31, 39, 47, 55, -64, + -64, -48, -40, -32, -24, -16, -8, 0, -8, -16, -24, -32, -40, -48, -56, -64, + -72, -80, -88, -96,-104,-112,-120,-128,-120,-112, 23, 31, 39, 47, 55, -64, + -64, -48, -40, -32, -24, -16, -8, 0, -8, -16, -24, -32, -40, -48, -56, -64, + -72, -80, -88, -96,-104,-112,-120,-128,-120,-112,-104, 31, 39, 47, 55, -64, + -64, -48, -40, -32, -24, -16, -8, 0, -8, -16, -24, -32, -40, -48, -56, -64, + -72, -80, -88, -96,-104,-112,-120,-128,-120,-112,-104, -96, 39, 47, 55, -64, + -64, -48, -40, -32, -24, -16, -8, 0, -8, -16, -24, -32, -40, -48, -56, -64, + -72, -80, -88, -96,-104,-112,-120,-128,-120,-112,-104, -96, -88, 47, 55, -64, + -64, -48, -40, -32, -24, -16, -8, 0, -8, -16, -24, -32, -40, -48, -56, -64, + -72, -80, -88, -96,-104,-112,-120,-128,-120,-112,-104, -96, -88, -80, 55,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127, + -127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127, + -127,-127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127, + -127,-127,-127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127, + -127,-127,-127,-127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127, + -127,-127,-127,-127,-127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127, + -127,-127,-127,-127,-127,-127, 127, 127, 127, 127, 127, 127, 127, 127, 127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127, + -127,-127,-127,-127,-127,-127,-127, 127, 127, 127, 127, 127, 127, 127, 127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127, + -127,-127,-127,-127,-127,-127,-127,-127, 127, 127, 127, 127, 127, 127, 127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127, 127, 127, 127, 127, 127, 127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127, 127, 127, 127, 127, 127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127, 127, 127, 127, 127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127, + -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127, 127, 127, 127,-128, + -128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128, + -128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128, 127, 127,-128, + -128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128, + -128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128, 127,-128, + -128,-128,-128,-128,-128,-128,-128, 127, 127, 127, 127, 127, 127, 127, 127,-128, + -128,-128,-128,-128,-128,-128, 127, 127, 127, 127, 127, 127, 127, 127, 127,-128, + -128,-128,-128,-128,-128, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,-128, + -128,-128,-128,-128, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,-128, + -128,-128,-128, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,-128, + -128,-128, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,-128, + -128, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,-128, + -128, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,-128, + -128,-112,-104, -96, -88, -80, -72, -64, -56, -48, -40, -32, -24, -16, -8, 0, + 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 127,-128, + -128, -96, -80, -64, -48, -32, -16, 0, 16, 32, 48, 64, 80, 96, 112, 69, + 69, 121, 125, 122, 119, 112, 102, 97, 88, 83, 77, 44, 32, 24, 18, 4, + -37, -45, -51, -58, -68, -75, -82, -88, -93, -99,-103,-109,-114,-117,-118, 69, + 69, 121, 125, 122, 119, 112, 102, 91, 75, 67, 55, 44, 32, 24, 18, 4, + -8, -24, -37, -49, -58, -66, -80, -88, -92, -98,-102,-107,-108,-115,-125, 0, + 0, 64, 96, 127, 96, 64, 32, 0, -32, -64, -96,-128, -96, -64, -32, 0, + 0, 64, 96, 127, 96, 64, 32, 0, -32, -64, -96,-128, -96, -64, -32,-128, + -128,-112,-104, -96, -88, -80, -72, -64, -56, -48, -40, -32, -24, -16, -8, 0, + 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 127,-128, + -128, -96, -80, -64, -48, -32, -16, 0, 16, 32, 48, 64, 80, 96, 112]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/futurecomposer/FCVoice.as b/Flod 4.1/neoart/flod/futurecomposer/FCVoice.as new file mode 100644 index 0000000..168eb68 --- /dev/null +++ b/Flod 4.1/neoart/flod/futurecomposer/FCVoice.as @@ -0,0 +1,106 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.futurecomposer { + import neoart.flod.core.*; + + public final class FCVoice { + internal var + index : int, + next : FCVoice, + channel : AmigaChannel, + sample : AmigaSample, + enabled : int, + pattern : int, + soundTranspose : int, + transpose : int, + patStep : int, + frqStep : int, + frqPos : int, + frqSustain : int, + frqTranspose : int, + volStep : int, + volPos : int, + volCtr : int, + volSpeed : int, + volSustain : int, + note : int, + pitch : int, + volume : int, + pitchBendFlag : int, + pitchBendSpeed : int, + pitchBendTime : int, + portamentoFlag : int, + portamento : int, + volBendFlag : int, + volBendSpeed : int, + volBendTime : int, + vibratoFlag : int, + vibratoSpeed : int, + vibratoDepth : int, + vibratoDelay : int, + vibrato : int; + + public function FCVoice(index:int) { + this.index = index; + } + + internal function initialize():void { + sample = null; + enabled = 0; + pattern = 0; + soundTranspose = 0; + transpose = 0; + patStep = 0; + frqStep = 0; + frqPos = 0; + frqSustain = 0; + frqTranspose = 0; + volStep = 0; + volPos = 0; + volCtr = 1; + volSpeed = 1; + volSustain = 0; + note = 0; + pitch = 0; + volume = 0; + pitchBendFlag = 0; + pitchBendSpeed = 0; + pitchBendTime = 0; + portamentoFlag = 0; + portamento = 0; + volBendFlag = 0; + volBendSpeed = 0; + volBendTime = 0; + vibratoFlag = 0; + vibratoSpeed = 0; + vibratoDepth = 0; + vibratoDelay = 0; + vibrato = 0; + } + + internal function volumeBend():void { + volBendFlag ^= 1; + + if (volBendFlag) { + volBendTime--; + volume += volBendSpeed; + if (volume < 0 || volume > 64) volBendTime = 0; + } + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/hippel/JHPlayer.as b/Flod 4.1/neoart/flod/hippel/JHPlayer.as new file mode 100644 index 0000000..8211592 --- /dev/null +++ b/Flod 4.1/neoart/flod/hippel/JHPlayer.as @@ -0,0 +1,849 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/11 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.hippel { + import flash.utils.*; + import neoart.flod.core.*; + + public final class JHPlayer extends AmigaPlayer { + private var + songs : Vector., + samples : Vector., + stream : ByteArray, + base : int, + patterns : int, + patternLen : int, + periods : int, + frqseqs : int, + volseqs : int, + samplesData : int, + song : JHSong, + voices : Vector., + coso : int; + + public function JHPlayer(amiga:Amiga = null) { + super(amiga); + voices = new Vector.(4, true); + + voices[0] = new JHVoice(0); + voices[0].next = voices[1] = new JHVoice(1); + voices[1].next = voices[2] = new JHVoice(2); + voices[2].next = voices[3] = new JHVoice(3); + } + + override public function process():void { + var chan:AmigaChannel, loop:int, period:int, pos1:int, pos2:int, sample:AmigaSample, value:int, voice:JHVoice = voices[0]; + + if (--tick == 0) { + tick = speed; + + while (voice) { + chan = voice.channel; + + if (coso) { + if (--voice.cosoCounter < 0) { + voice.cosoCounter = voice.cosoSpeed; + + do { + stream.position = voice.patternPos; + + do { + loop = 0; + value = stream.readByte(); + + if (value == -1) { + if (voice.trackPos == song.length) { + voice.trackPos = 0; + amiga.complete = 1; + } + + stream.position = voice.trackPtr + voice.trackPos; + value = stream.readUnsignedByte(); + voice.trackTransp = stream.readByte(); + pos1 = stream[stream.position]; + + if ((variant > 3) && (pos1 > 127)) { + pos2 = (pos1 >> 4) & 15; + pos1 &= 15; + + if (pos2 == 15) { + pos2 = 100; + + if (pos1) { + pos2 = (15 - pos1) + 1; + pos2 <<= 1; + pos1 = pos2; + pos2 <<= 1; + pos2 += pos1; + } + + voice.volFade = pos2; + } else if (pos2 == 8) { + amiga.complete = 1; + } else if (pos2 == 14) { + speed = pos1; + } + } else { + voice.volTransp = stream.readByte(); + } + + stream.position = patterns + (value << 1); + voice.patternPos = stream.readUnsignedShort(); + voice.trackPos += 12; + loop = 1; + } else if (value == -2) { + voice.cosoCounter = voice.cosoSpeed = stream.readUnsignedByte(); + loop = 3; + } else if (value == -3) { + voice.cosoCounter = voice.cosoSpeed = stream.readUnsignedByte(); + voice.patternPos = stream.position; + } else { + voice.note = value; + voice.info = stream.readByte(); + + if (voice.info & 224) voice.infoPrev = stream.readByte(); + + voice.patternPos = stream.position; + voice.portaDelta = 0; + + if (value >= 0) { + if (variant == 1) chan.enabled = 0; + value = (voice.info & 31) + voice.volTransp; + stream.position = volseqs + (value << 1); + stream.position = stream.readUnsignedShort(); + + voice.volCounter = voice.volSpeed = stream.readUnsignedByte(); + voice.volSustain = 0; + value = stream.readByte(); + + voice.vibSpeed = stream.readByte(); + voice.vibrato = 64; + voice.vibDepth = voice.vibDelta = stream.readByte(); + voice.vibDelay = stream.readUnsignedByte(); + + voice.volseqPtr = stream.position; + voice.volseqPos = 0; + + if (value != -128) { + if (variant > 1 && (voice.info & 64)) value = voice.infoPrev; + stream.position = frqseqs + (value << 1); + + voice.frqseqPtr = stream.readUnsignedShort(); + voice.frqseqPos = 0; + + voice.tick = 0; + } + } + } + } while (loop > 2); + } while (loop > 0); + } + } else { + stream.position = voice.patternPtr + voice.patternPos; + value = stream.readByte(); + + if (voice.patternPos == patternLen || (value & 127) == 1) { + if (voice.trackPos == song.length) { + voice.trackPos = 0; + amiga.complete = 1; + } + + stream.position = voice.trackPtr + voice.trackPos; + value = stream.readUnsignedByte(); + voice.trackTransp = stream.readByte(); + voice.volTransp = stream.readByte(); + + if (voice.volTransp == -128) amiga.complete = 1; + + voice.patternPtr = patterns + (value * patternLen); + voice.patternPos = 0; + voice.trackPos += 12; + + stream.position = voice.patternPtr; + value = stream.readByte(); + } + + if (value & 127) { + voice.note = value & 127; + voice.portaDelta = 0; + + pos1 = stream.position; + if (!voice.patternPos) stream.position += patternLen; + stream.position -= 2; + + voice.infoPrev = stream.readByte(); + stream.position = pos1; + voice.info = stream.readByte(); + + if (value >= 0) { + if (variant == 1) chan.enabled = 0; + value = (voice.info & 31) + voice.volTransp; + stream.position = volseqs + (value << 6); + + voice.volCounter = voice.volSpeed = stream.readUnsignedByte(); + voice.volSustain = 0; + value = stream.readByte(); + + voice.vibSpeed = stream.readByte(); + voice.vibrato = 64; + voice.vibDepth = voice.vibDelta = stream.readByte(); + voice.vibDelay = stream.readUnsignedByte(); + + voice.volseqPtr = stream.position; + voice.volseqPos = 0; + + if (variant > 1 && (voice.info & 64)) value = voice.infoPrev; + + voice.frqseqPtr = frqseqs + (value << 6); + voice.frqseqPos = 0; + + voice.tick = 0; + } + } + voice.patternPos += 2; + } + voice = voice.next; + } + voice = voices[0]; + } + + while (voice) { + chan = voice.channel; + voice.enabled = 0; + + do { + loop = 0; + + if (voice.tick) { + voice.tick--; + } else { + stream.position = voice.frqseqPtr + voice.frqseqPos; + + do { + value = stream.readByte(); + if (value == -31) break; + loop = 3; + + if (variant == 3 && coso) { + if (value == -27) { + value = -30; + } else if (value == -26) { + value = -28; + } + } + + switch (value) { + case -32: + voice.frqseqPos = (stream.readUnsignedByte() & 63); + stream.position = voice.frqseqPtr + voice.frqseqPos; + break; + case -30: + sample = samples[stream.readUnsignedByte()]; + voice.sample = -1; + + voice.loopPtr = sample.loopPtr; + voice.repeat = sample.repeat; + voice.enabled = 1; + + chan.enabled = 0; + chan.pointer = sample.pointer; + chan.length = sample.length; + + voice.volseqPos = 0; + voice.volCounter = 1; + voice.slide = 0; + voice.frqseqPos += 2; + break; + case -29: + voice.vibSpeed = stream.readByte(); + voice.vibDepth = stream.readByte(); + voice.frqseqPos += 3; + break; + case -28: + sample = samples[stream.readUnsignedByte()]; + voice.loopPtr = sample.loopPtr; + voice.repeat = sample.repeat; + + chan.pointer = sample.pointer; + chan.length = sample.length; + + voice.slide = 0; + voice.frqseqPos += 2; + break; + case -27: + if (variant < 2) break; + sample = samples[stream.readUnsignedByte()]; + chan.enabled = 0; + voice.enabled = 1; + + if (variant == 2) { + pos1 = stream.readUnsignedByte() * sample.length; + + voice.loopPtr = sample.loopPtr + pos1; + voice.repeat = sample.repeat; + + chan.pointer = sample.pointer + pos1; + chan.length = sample.length; + + voice.frqseqPos += 3; + } else { + voice.sldPointer = sample.pointer; + voice.sldEnd = sample.pointer + sample.length; + value = stream.readUnsignedShort(); + + if (value == 0xffff) { + voice.sldLoopPtr = sample.length; + } else { + voice.sldLoopPtr = value << 1; + } + + voice.sldLen = stream.readUnsignedShort() << 1; + voice.sldDelta = stream.readShort() << 1; + voice.sldActive = 0; + voice.sldCounter = 0; + voice.sldSpeed = stream.readUnsignedByte(); + voice.slide = 1; + voice.sldDone = 0; + + voice.frqseqPos += 9; + } + voice.volseqPos = 0; + voice.volCounter = 1; + break; + case -26: + if (variant < 3) break; + + voice.sldLen = stream.readUnsignedShort() << 1; + voice.sldDelta = stream.readShort() << 1; + voice.sldActive = 0; + voice.sldCounter = 0; + voice.sldSpeed = stream.readUnsignedByte(); + voice.sldDone = 0; + + voice.frqseqPos += 6; + break; + case -25: + if (variant == 1) { + voice.frqseqPtr = frqseqs + (stream.readUnsignedByte() << 6); + voice.frqseqPos = 0; + + stream.position = voice.frqseqPtr; + loop = 3; + } else { + value = stream.readUnsignedByte(); + + if (value != voice.sample) { + sample = samples[value]; + voice.sample = value; + + voice.loopPtr = sample.loopPtr; + voice.repeat = sample.repeat; + voice.enabled = 1; + + chan.enabled = 0; + chan.pointer = sample.pointer; + chan.length = sample.length; + } + + voice.volseqPos = 0; + voice.volCounter = 1; + voice.slide = 0; + voice.frqseqPos += 2; + } + break; + case -24: + voice.tick = stream.readUnsignedByte(); + voice.frqseqPos += 2; + loop = 1; + break; + case -23: + if (variant < 2) break; + sample = samples[stream.readUnsignedByte()]; + voice.sample = -1; + voice.enabled = 1; + + pos2 = stream.readUnsignedByte(); + pos1 = stream.position; + chan.enabled = 0; + + stream.position = samplesData + sample.pointer + 4; + value = (stream.readUnsignedShort() * 24) + (stream.readUnsignedShort() << 2); + stream.position += (pos2 * 24); + + voice.loopPtr = stream.readUnsignedInt() & 0xfffffffe; + chan.length = (stream.readUnsignedInt() & 0xfffffffe) - voice.loopPtr; + voice.loopPtr += (sample.pointer + value + 8); + chan.pointer = voice.loopPtr; + voice.repeat = 2; + + stream.position = pos1; + pos1 = voice.loopPtr + 1; + amiga.memory[pos1] = amiga.memory[voice.loopPtr]; + + voice.volseqPos = 0; + voice.volCounter = 1; + voice.slide = 0; + voice.frqseqPos += 3; + break; + default: + voice.transpose = value; + voice.frqseqPos++; + loop = 0; + } + } while (loop > 2); + } + } while (loop > 0); + + if (voice.slide) { + if (!voice.sldDone) { + if (--voice.sldCounter < 0) { + voice.sldCounter = voice.sldSpeed; + + if (voice.sldActive) { + value = voice.sldLoopPtr + voice.sldDelta; + + if (value < 0) { + voice.sldDone = 1; + value = voice.sldLoopPtr - voice.sldDelta; + } else { + pos1 = voice.sldPointer + voice.sldLen + value; + + if (pos1 > voice.sldEnd) { + voice.sldDone = 1; + value = voice.sldLoopPtr - voice.sldDelta; + } + } + voice.sldLoopPtr = value; + } else { + voice.sldActive = 1; + } + + voice.loopPtr = voice.sldPointer + voice.sldLoopPtr; + voice.repeat = voice.sldLen; + chan.pointer = voice.loopPtr; + chan.length = voice.repeat; + } + } + } + + do { + loop = 0; + + if (voice.volSustain) { + voice.volSustain--; + } else { + if (--voice.volCounter) break; + voice.volCounter = voice.volSpeed; + + do { + stream.position = voice.volseqPtr + voice.volseqPos; + value = stream.readByte(); + if (value <= -25 && value >= -31) break; + + switch (value) { + case -24: + voice.volSustain = stream.readUnsignedByte(); + voice.volseqPos += 2; + loop = 1; + break; + case -32: + voice.volseqPos = (stream.readUnsignedByte() & 63) - 5; + loop = 3; + break; + default: + voice.volume = value; + voice.volseqPos++; + loop = 0; + } + } while (loop > 2); + } + } while (loop > 0); + + value = voice.transpose; + if (value >= 0) value += (voice.note + voice.trackTransp); + value &= 127; + + if (coso) { + if (value > 83) value = 0; + period = PERIODS[value]; + value <<= 1; + } else { + value <<= 1; + stream.position = periods + value; + period = stream.readUnsignedShort(); + } + + if (voice.vibDelay) { + voice.vibDelay--; + } else { + if (variant > 3) { + if (voice.vibrato & 32) { + value = voice.vibDelta + voice.vibSpeed; + + if (value > voice.vibDepth) { + voice.vibrato &= ~32; + value = voice.vibDepth; + } + } else { + value = voice.vibDelta - voice.vibSpeed; + + if (value < 0) { + voice.vibrato |= 32; + value = 0; + } + } + + voice.vibDelta = value; + value = (value - (voice.vibDepth >> 1)) * period; + period += (value >> 10); + } else if (variant > 2) { + value = voice.vibSpeed; + + if (value < 0) { + value &= 127; + voice.vibrato ^= 1; + } + + if (!(voice.vibrato & 1)) { + if (voice.vibrato & 32) { + voice.vibDelta += value; + pos1 = voice.vibDepth << 1; + + if (voice.vibDelta > pos1) { + voice.vibrato &= ~32; + voice.vibDelta = pos1; + } + } else { + voice.vibDelta -= value; + + if (voice.vibDelta < 0) { + voice.vibrato |= 32; + voice.vibDelta = 0; + } + } + } + + period += (value - voice.vibDepth); + } else { + if (voice.vibrato >= 0 || !(voice.vibrato & 1)) { + if (voice.vibrato & 32) { + voice.vibDelta += voice.vibSpeed; + pos1 = voice.vibDepth << 1; + + if (voice.vibDelta >= pos1) { + voice.vibrato &= ~32; + voice.vibDelta = pos1; + } + } else { + voice.vibDelta -= voice.vibSpeed; + + if (voice.vibDelta < 0) { + voice.vibrato |= 32; + voice.vibDelta = 0; + } + } + } + + pos1 = voice.vibDelta - voice.vibDepth; + + if (pos1) { + value += 160; + + while (value < 256) { + pos1 += pos1; + value += 24; + } + + period += pos1; + } + } + } + + if (variant < 3) voice.vibrato ^= 1; + + if (voice.info & 32) { + value = voice.infoPrev; + + if (variant > 3) { + if (value < 0) { + voice.portaDelta += (-value); + value = voice.portaDelta * period; + period += (value >> 10); + } else { + voice.portaDelta += value; + value = voice.portaDelta * period; + period -= (value >> 10); + } + } else { + if (value < 0) { + voice.portaDelta += (-value << 11); + period += (voice.portaDelta >> 16); + } else { + voice.portaDelta += (value << 11); + period -= (voice.portaDelta >> 16); + } + } + } + + if (variant > 3) { + value = (voice.volFade * voice.volume) / 100; + } else { + value = voice.volume; + } + + chan.period = period; + chan.volume = value; + + if (voice.enabled) { + chan.enabled = 1; + chan.pointer = voice.loopPtr; + chan.length = voice.repeat; + } + + voice = voice.next; + } + } + + override protected function initialize():void { + var voice:JHVoice = voices[0]; + super.initialize(); + + song = songs[playSong]; + speed = song.speed; + tick = (coso || variant > 1) ? 1 : speed; + + while (voice) { + voice.initialize(); + voice.channel = amiga.channels[voice.index]; + voice.trackPtr = song.pointer + (voice.index * 3); + + if (coso) { + voice.trackPos = 0; + voice.patternPos = 8; + } else { + stream.position = voice.trackPtr; + voice.patternPtr = patterns + (stream.readUnsignedByte() * patternLen); + voice.trackTransp = stream.readByte(); + voice.volTransp = stream.readByte(); + + voice.frqseqPtr = base; + voice.volseqPtr = base; + } + + voice = voice.next; + } + } + + override protected function loader(stream:ByteArray):void { + var headers:int, i:int, id:int, len:int, pos:int, sample:AmigaSample, song:JHSong, songsData:int, tracks:int, value:int; + + base = periods = 0; + coso = int(stream.readMultiByte(4, ENCODING) == "COSO"); + + if (coso) { + for (i = 0; i < 7; ++i) value += stream.readInt(); + + if (value == 16942) { + stream.position = 47; + value += stream.readUnsignedByte(); + } + + switch (value) { + case 22666: + case 18842: + case 30012: + case 22466: + case 3546: + variant = 1; + break; + case 16948: + case 18332: + case 13698: + variant = 2; + break; + case 18546: //Wings of Death + case 13926: + case 8760: + case 17242: + case 11394: + case 14494: + case 14392: + case 13576: //Dragonflight + case 6520: + variant = 3; + break; + default: + variant = 4; + } + + version = 2; + stream.position = 4; + + frqseqs = stream.readUnsignedInt(); + volseqs = stream.readUnsignedInt(); + patterns = stream.readUnsignedInt(); + tracks = stream.readUnsignedInt(); + songsData = stream.readUnsignedInt(); + headers = stream.readUnsignedInt(); + samplesData = stream.readUnsignedInt(); + + stream.position = 0; + stream.writeInt(0x1000000); + stream.writeInt(0xe1); + stream.writeShort(0xffff); + + len = ((samplesData - headers) / 10) - 1; + lastSong = (headers - songsData) / 6; + } else { + while (stream.bytesAvailable > 12) { + value = stream.readUnsignedShort(); + + switch (value) { + case 0x0240: //andi.w #x,d0 + value = stream.readUnsignedShort(); + + if (value == 0x007f) { //andi.w #$7f,d0 + stream.position += 2; + periods = stream.position + stream.readUnsignedShort(); + } + break; + case 0x7002: //moveq #2,d0 + case 0x7003: //moveq #3,d0 + channels = value & 0xff; + value = stream.readUnsignedShort(); + if (value == 0x7600) value = stream.readUnsignedShort(); //moveq #0,d3 + + if (value == 0x41fa) { //lea x,a0 + stream.position += 4; + base = stream.position + stream.readUnsignedShort(); + } + break; + case 0x5446: //"TF" + value = stream.readUnsignedShort(); + + if (value == 0x4d58) { //"MX" + id = stream.position - 4; + stream.position = stream.length; + } + break; + } + } + + if (!id || !base || !periods) return; + version = 1; + + stream.position = id + 4; + frqseqs = pos = id + 32; + value = stream.readUnsignedShort(); + volseqs = (pos += (++value << 6)); + + value = stream.readUnsignedShort(); + patterns = (pos += (++value << 6)); + value = stream.readUnsignedShort(); + stream.position += 2; + patternLen = stream.readUnsignedShort(); + tracks = (pos += (++value * patternLen)); + + stream.position -= 4; + value = stream.readUnsignedShort(); + songsData = (pos += (++value * 12)); + + stream.position = id + 16; + lastSong = stream.readUnsignedShort(); + headers = (pos += (++lastSong * 6)); + + len = stream.readUnsignedShort(); + samplesData = pos + (len * 30); + } + + stream.position = headers; + samples = new Vector.(len, true); + value = 0; + + for (i = 0; i < len; ++i) { + sample = new AmigaSample(); + if (!coso) sample.name = stream.readMultiByte(18, ENCODING); + + sample.pointer = stream.readUnsignedInt(); + sample.length = stream.readUnsignedShort() << 1; + if (!coso) sample.volume = stream.readUnsignedShort(); + sample.loopPtr = stream.readUnsignedShort() + sample.pointer; + sample.repeat = stream.readUnsignedShort() << 1; + + if (sample.loopPtr & 1) sample.loopPtr--; + value += sample.length; + samples[i] = sample; + } + + stream.position = samplesData; + amiga.store(stream, value); + + stream.position = songsData; + songs = new Vector.(); + value = 0; + + for (i = 0; i < lastSong; ++i) { + song = new JHSong(); + song.pointer = stream.readUnsignedShort(); + song.length = stream.readUnsignedShort() - song.pointer + 1; + song.speed = stream.readUnsignedShort(); + + song.pointer = (song.pointer * 12) + tracks; + song.length *= 12; + if (song.length > 12) songs[value++] = song; + } + + songs.fixed = true; + lastSong = songs.length - 1; + + if (!coso) { + stream.position = 0; + variant = 1; + + while (stream.position < id) { + value = stream.readUnsignedShort(); + + if (value == 0xb03c || value == 0x0c00) { //cmp.b #x,d0 | cmpi.b #x,d0 + value = stream.readUnsignedShort(); + + if (value == 0x00e5 || value == 0x00e6 || value == 0x00e9) { //effects + variant = 2; + break; + } + } else if (value == 0x4efb) { //jmp $(pc,d0.w) + variant = 3; + break; + } + } + } + + this.stream = stream; + } + + private const + PERIODS : Vector. = Vector.([ + 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016, + 960, 906, 856, 808, 762, 720, 678, 640, 604, 570, + 538, 508, 480, 453, 428, 404, 381, 360, 339, 320, + 302, 285, 269, 254, 240, 226, 214, 202, 190, 180, + 170, 160, 151, 143, 135, 127, 120, 113, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 3424,3232,3048,2880,2712,2560,2416,2280,2152,2032, + 1920,1812,6848,6464,6096,5760,5424,5120,4832,4560, + 4304,4064,3840,3624]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/hippel/JHSong.as b/Flod 4.1/neoart/flod/hippel/JHSong.as new file mode 100644 index 0000000..3ba8ed0 --- /dev/null +++ b/Flod 4.1/neoart/flod/hippel/JHSong.as @@ -0,0 +1,26 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.hippel { + + public final class JHSong { + internal var + pointer : int, + speed : int, + length : int; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/hippel/JHVoice.as b/Flod 4.1/neoart/flod/hippel/JHVoice.as new file mode 100644 index 0000000..be8d17a --- /dev/null +++ b/Flod 4.1/neoart/flod/hippel/JHVoice.as @@ -0,0 +1,119 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.hippel { + import neoart.flod.core.*; + + public final class JHVoice { + internal var + index : int, + next : JHVoice, + channel : AmigaChannel, + enabled : int, + cosoCounter : int, + cosoSpeed : int, + trackPtr : int, + trackPos : int, + trackTransp : int, + patternPtr : int, + patternPos : int, + frqseqPtr : int, + frqseqPos : int, + volseqPtr : int, + volseqPos : int, + sample : int, + loopPtr : int, + repeat : int, + tick : int, + note : int, + transpose : int, + info : int, + infoPrev : int, + volume : int, + volCounter : int, + volSpeed : int, + volSustain : int, + volTransp : int, + volFade : int, + portaDelta : int, + vibrato : int, + vibDelay : int, + vibDelta : int, + vibDepth : int, + vibSpeed : int, + slide : int, + sldActive : int, + sldDone : int, + sldCounter : int, + sldSpeed : int, + sldDelta : int, + sldPointer : int, + sldLen : int, + sldEnd : int, + sldLoopPtr : int; + + public function JHVoice(index:int) { + this.index = index; + } + + internal function initialize():void { + channel = null; + enabled = 0; + cosoCounter = 0; + cosoSpeed = 0; + trackPtr = 0 + trackPos = 12; + trackTransp = 0; + patternPtr = 0; + patternPos = 0; + frqseqPtr = 0; + frqseqPos = 0; + volseqPtr = 0; + volseqPos = 0; + sample = -1; + loopPtr = 0; + repeat = 0; + tick = 0; + note = 0; + transpose = 0; + info = 0; + infoPrev = 0; + volume = 0; + volCounter = 1; + volSpeed = 1; + volSustain = 0; + volTransp = 0; + volFade = 100; + portaDelta = 0; + vibrato = 0; + vibDelay = 0; + vibDelta = 0; + vibDepth = 0; + vibSpeed = 0; + slide = 0; + sldActive = 0; + sldDone = 0; + sldCounter = 0; + sldSpeed = 0; + sldDelta = 0; + sldPointer = 0; + sldLen = 0; + sldEnd = 0; + sldLoopPtr = 0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/hubbard/RHPlayer.as b/Flod 4.1/neoart/flod/hubbard/RHPlayer.as new file mode 100644 index 0000000..e211929 --- /dev/null +++ b/Flod 4.1/neoart/flod/hubbard/RHPlayer.as @@ -0,0 +1,410 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/09 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.hubbard { + import flash.utils.*; + import neoart.flod.core.*; + + public final class RHPlayer extends AmigaPlayer { + private var + songs : Vector., + samples : Vector., + song : RHSong, + periods : int, + vibrato : int, + voices : Vector., + stream : ByteArray, + complete : int; + + public function RHPlayer(amiga:Amiga = null) { + super(amiga); + voices = new Vector.(4, true); + + voices[3] = new RHVoice(3,8); + voices[3].next = voices[2] = new RHVoice(2,4); + voices[2].next = voices[1] = new RHVoice(1,2); + voices[1].next = voices[0] = new RHVoice(0,1); + } + + override public function process():void { + var chan:AmigaChannel, loop:int, sample:RHSample, value:int, voice:RHVoice = voices[3]; + + while (voice) { + chan = voice.channel; + stream.position = voice.patternPos; + sample = voice.sample; + + if (!voice.busy) { + voice.busy = 1; + + if (sample.loopPtr == 0) { + chan.pointer = amiga.loopPtr; + chan.length = amiga.loopLen; + } else if (sample.loopPtr > 0) { + chan.pointer = sample.pointer + sample.loopPtr; + chan.length = sample.length - sample.loopPtr; + } + } + + if (--voice.tick == 0) { + voice.flags = 0; + loop = 1; + + while (loop) { + value = stream.readByte(); + + if (value < 0) { + switch (value) { + case -121: + if (variant == 3) voice.volume = stream.readUnsignedByte(); + break; + case -122: + if (variant == 4) voice.volume = stream.readUnsignedByte(); + break; + case -123: + if (variant > 1) amiga.complete = 1; + break; + case -124: + stream.position = voice.trackPtr + voice.trackPos; + value = stream.readUnsignedInt(); + voice.trackPos += 4; + + if (!value) { + stream.position = voice.trackPtr; + value = stream.readUnsignedInt(); + voice.trackPos = 4; + + if (!loopSong) { + complete &= ~(voice.bitFlag); + if (!complete) amiga.complete = 1; + } + } + + stream.position = value; + break; + case -125: + if (variant == 4) voice.flags |= 4; + break; + case -126: + voice.tick = song.speed * stream.readByte(); + voice.patternPos = stream.position; + + chan.pointer = amiga.loopPtr; + chan.length = amiga.loopLen; + loop = 0; + break; + case -127: + voice.portaSpeed = stream.readByte(); + voice.flags |= 1; + break; + case -128: + value = stream.readByte(); + if (value < 0) value = 0; + voice.sample = sample = samples[value]; + voice.vibratoPtr = vibrato + sample.vibrato; + voice.vibratoPos = voice.vibratoPtr; + break; + } + } else { + voice.tick = song.speed * value; + voice.note = stream.readByte(); + voice.patternPos = stream.position; + + voice.synthPos = sample.loPos; + voice.vibratoPos = voice.vibratoPtr; + + chan.pointer = sample.pointer; + chan.length = sample.length; + chan.volume = (voice.volume) ? voice.volume : sample.volume; + + stream.position = periods + (voice.note << 1); + value = stream.readUnsignedShort() * sample.relative; + chan.period = voice.period = (value >> 10); + + chan.enabled = 1; + voice.busy = loop = 0; + } + } + } else { + if (voice.tick == 1) { + if (variant != 4 || !(voice.flags & 4)) + chan.enabled = 0; + } + + if (voice.flags & 1) + chan.period = (voice.period += voice.portaSpeed); + + if (sample.divider) { + stream.position = voice.vibratoPos; + value = stream.readByte(); + + if (value == -124) { + stream.position = voice.vibratoPtr; + value = stream.readByte(); + } + + voice.vibratoPos = stream.position; + value = (voice.period / sample.divider) * value; + chan.period = voice.period + value; + } + } + + if (sample.hiPos) { + value = 0; + + if (voice.flags & 2) { + voice.synthPos--; + + if (voice.synthPos <= sample.loPos) { + voice.flags &= -3; + value = 60; + } + } else { + voice.synthPos++; + + if (voice.synthPos > sample.hiPos) { + voice.flags |= 2; + value = 60; + } + } + + amiga.memory[int(sample.pointer + voice.synthPos)] = value; + } + + voice = voice.next; + } + } + + override protected function initialize():void { + var i:int, j:int, sample:RHSample, voice:RHVoice = voices[3]; + super.initialize(); + + song = songs[playSong]; + complete = 15; + + for (i = 0; i < samples.length; ++i) { + sample = samples[i]; + + if (sample.wave) { + for (j = 0; j < sample.length; ++j) + amiga.memory[int(sample.pointer + j)] = sample.wave[j]; + } + } + + while (voice) { + voice.initialize(); + voice.channel = amiga.channels[voice.index]; + + voice.trackPtr = song.tracks[voice.index]; + voice.trackPos = 4; + + stream.position = voice.trackPtr; + voice.patternPos = stream.readUnsignedInt(); + + voice = voice.next; + } + } + + override protected function loader(stream:ByteArray):void { + var i:int, j:int, len:int, pos:int, sample:RHSample, samplesData:int, samplesHeaders:int, samplesLen:int, song:RHSong, songsHeaders:int, wavesHeaders:int, wavesPointers:int, value:int; + stream.position = 44; + + while (stream.position < 1024) { + value = stream.readUnsignedShort(); + + if (value == 0x7e10 || value == 0x7e20) { //moveq #16,d7 || moveq #32,d7 + value = stream.readUnsignedShort(); + + if (value == 0x41fa) { //lea $x,a0 + i = stream.position + stream.readUnsignedShort(); + value = stream.readUnsignedShort(); + + if (value == 0xd1fc) { //adda.l + samplesData = i + stream.readUnsignedInt(); + amiga.loopLen = 64; + stream.position += 2; + } else { + samplesData = i; + amiga.loopLen = 512; + } + + samplesHeaders = stream.position + stream.readUnsignedShort(); + value = stream.readUnsignedByte(); + if (value == 0x72) samplesLen = stream.readUnsignedByte(); //moveq #x,d1 + } + } else if (value == 0x51c9) { //dbf d1,x + stream.position += 2; + value = stream.readUnsignedShort(); + + if (value == 0x45fa) { //lea $x,a2 + wavesPointers = stream.position + stream.readUnsignedShort(); + stream.position += 2; + + while (1) { + value = stream.readUnsignedShort(); + + if (value == 0x4bfa) { //lea $x,a5 + wavesHeaders = stream.position + stream.readUnsignedShort(); + break; + } + } + } + } else if (value == 0xc0fc) { //mulu.w #x,d0 + stream.position += 2; + value = stream.readUnsignedShort(); + + if (value == 0x41eb) //lea $x(a3),a0 + songsHeaders = stream.readUnsignedShort(); + } else if (value == 0x346d) { //movea.w x(a5),a2 + stream.position += 2; + value = stream.readUnsignedShort(); + + if (value == 0x49fa) //lea $x,a4 + vibrato = stream.position + stream.readUnsignedShort(); + } else if (value == 0x4240) { //clr.w d0 + value = stream.readUnsignedShort(); + + if (value == 0x45fa) { //lea $x,a2 + periods = stream.position + stream.readUnsignedShort(); + break; + } + } + } + + if (!samplesHeaders || !samplesData || !samplesLen || !songsHeaders) return; + + stream.position = samplesData; + samples = new Vector.(); + samplesLen++; + + for (i = 0; i < samplesLen; ++i) { + sample = new RHSample(); + sample.length = stream.readUnsignedInt(); + sample.relative = 3579545 / stream.readUnsignedShort(); + sample.pointer = amiga.store(stream, sample.length); + samples[i] = sample; + } + + stream.position = samplesHeaders; + + for (i = 0; i < samplesLen; ++i) { + sample = samples[i]; + stream.position += 4; + sample.loopPtr = stream.readInt(); + stream.position += 6; + sample.volume = stream.readUnsignedShort(); + + if (wavesHeaders) { + sample.divider = stream.readUnsignedShort(); + sample.vibrato = stream.readUnsignedShort(); + sample.hiPos = stream.readUnsignedShort(); + sample.loPos = stream.readUnsignedShort(); + stream.position += 8; + } + } + + if (wavesHeaders) { + stream.position = wavesHeaders; + i = (wavesHeaders - samplesHeaders) >> 5; + len = i + 3; + variant = 1; + + if (i >= samplesLen) { + for (j = samplesLen; j < i; ++j) + samples[j] = new RHSample(); + } + + for (; i < len; ++i) { + sample = new RHSample(); + stream.position += 4; + sample.loopPtr = stream.readInt(); + sample.length = stream.readUnsignedShort(); + sample.relative = stream.readUnsignedShort(); + + stream.position += 2; + sample.volume = stream.readUnsignedShort(); + sample.divider = stream.readUnsignedShort(); + sample.vibrato = stream.readUnsignedShort(); + sample.hiPos = stream.readUnsignedShort(); + sample.loPos = stream.readUnsignedShort(); + + pos = stream.position; + stream.position = wavesPointers; + stream.position = stream.readInt(); + + sample.pointer = amiga.memory.length; + amiga.memory.length += sample.length; + sample.wave = new Vector.(sample.length, true); + + for (j = 0; j < sample.length; ++j) + sample.wave[j] = stream.readByte(); + + samples[i] = sample; + wavesPointers += 4; + stream.position = pos; + } + } + + samples.fixed = true; + + stream.position = songsHeaders; + songs = new Vector.(); + value = 65536; + + while (1) { + song = new RHSong(); + stream.position++; + song.tracks = new Vector.(4, true); + song.speed = stream.readUnsignedByte(); + + for (i = 0; i < 4; ++i) { + j = stream.readUnsignedInt(); + if (j < value) value = j; + song.tracks[i] = j; + } + + songs.push(song); + if ((value - stream.position) < 18) break; + } + + songs.fixed = true; + lastSong = songs.length - 1; + + stream.length = samplesData; + stream.position = 0x160; + + while (stream.position < 0x200) { + value = stream.readUnsignedShort(); + + if (value == 0xb03c) { //cmp.b #x,d0 + value = stream.readUnsignedShort(); + + if (value == 0x0085) { //-123 + variant = 2; + } else if (value == 0x0086) { //-122 + variant = 4; + } else if (value == 0x0087) { //-121 + variant = 3; + } + } + } + + this.stream = stream; + version = 1; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/hubbard/RHSample.as b/Flod 4.1/neoart/flod/hubbard/RHSample.as new file mode 100644 index 0000000..35c5a2b --- /dev/null +++ b/Flod 4.1/neoart/flod/hubbard/RHSample.as @@ -0,0 +1,30 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/02/12 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.hubbard { + import neoart.flod.core.*; + + public final class RHSample extends AmigaSample { + internal var + relative : int, + divider : int, + vibrato : int, + hiPos : int, + loPos : int, + wave : Vector.; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/hubbard/RHSong.as b/Flod 4.1/neoart/flod/hubbard/RHSong.as new file mode 100644 index 0000000..370efc5 --- /dev/null +++ b/Flod 4.1/neoart/flod/hubbard/RHSong.as @@ -0,0 +1,25 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/02/12 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.hubbard { + + public final class RHSong { + internal var + speed : int, + tracks : Vector.; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/hubbard/RHVoice.as b/Flod 4.1/neoart/flod/hubbard/RHVoice.as new file mode 100644 index 0000000..5690940 --- /dev/null +++ b/Flod 4.1/neoart/flod/hubbard/RHVoice.as @@ -0,0 +1,65 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/02/12 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.hubbard { + import neoart.flod.core.*; + + public final class RHVoice { + internal var + index : int, + bitFlag : int, + next : RHVoice, + channel : AmigaChannel, + sample : RHSample, + trackPtr : int, + trackPos : int, + patternPos : int, + tick : int, + busy : int, + flags : int, + note : int, + period : int, + volume : int, + portaSpeed : int, + vibratoPtr : int, + vibratoPos : int, + synthPos : int; + + public function RHVoice(index:int, bitFlag:int) { + this.index = index; + this.bitFlag = bitFlag; + } + + internal function initialize():void { + channel = null; + sample = null; + trackPtr = 0; + trackPos = 0; + patternPos = 0; + tick = 1; + busy = 1; + flags = 0; + note = 0; + period = 0; + volume = 0; + portaSpeed = 0; + vibratoPtr = 0; + vibratoPos = 0; + synthPos = 0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/sidmon/S1Player.as b/Flod 4.1/neoart/flod/sidmon/S1Player.as new file mode 100644 index 0000000..d7798ee --- /dev/null +++ b/Flod 4.1/neoart/flod/sidmon/S1Player.as @@ -0,0 +1,710 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.sidmon { + import flash.utils.*; + import neoart.flod.core.*; + + public final class S1Player extends AmigaPlayer { + private var + tracksPtr : Vector., + tracks : Vector., + patternsPtr : Vector., + patterns : Vector., + samples : Vector., + waveLists : Vector., + speedDef : int, + trackLen : int, + patternDef : int, + mix1Speed : int, + mix2Speed : int, + mix1Dest : int, + mix2Dest : int, + mix1Source1 : int, + mix1Source2 : int, + mix2Source1 : int, + mix2Source2 : int, + doFilter : int, + doReset : int, + voices : Vector., + trackPos : int, + trackEnd : int, + patternPos : int, + patternEnd : int, + patternLen : int, + mix1Ctr : int, + mix2Ctr : int, + mix1Pos : int, + mix2Pos : int, + audPtr : int, + audLen : int, + audPer : int, + audVol : int; + + public function S1Player(amiga:Amiga = null) { + super(amiga); + PERIODS.fixed = true; + + tracksPtr = new Vector.(4, true); + voices = new Vector.(4, true); + + voices[0] = new S1Voice(0); + voices[0].next = voices[1] = new S1Voice(1); + voices[1].next = voices[2] = new S1Voice(2); + voices[2].next = voices[3] = new S1Voice(3); + } + + override public function process():void { + var chan:AmigaChannel, dst:int, i:int, index:int, memory:Vector. = amiga.memory, row:SMRow, sample:S1Sample, src1:int, src2:int, step:AmigaStep, value:int, voice:S1Voice = voices[0]; + + while (voice) { + chan = voice.channel; + audPtr = -1; + audLen = audPer = audVol = 0; + + if (tick == 0) { + if (patternEnd) { + if (trackEnd) voice.step = tracksPtr[voice.index]; + else voice.step++; + + step = tracks[voice.step]; + voice.row = patternsPtr[step.pattern]; + if (doReset) voice.noteTimer = 0; + } + + if (voice.noteTimer == 0) { + row = patterns[voice.row]; + + if (row.sample == 0) { + if (row.note) { + voice.noteTimer = row.speed; + + if (voice.waitCtr) { + sample = samples[voice.sample]; + audPtr = sample.pointer; + audLen = sample.length; + voice.samplePtr = sample.loopPtr; + voice.sampleLen = sample.repeat; + voice.waitCtr = 1; + chan.enabled = 0; + } + } + } else { + sample = samples[row.sample]; + if (voice.waitCtr) chan.enabled = voice.waitCtr = 0; + + if (sample.waveform > 15) { + audPtr = sample.pointer; + audLen = sample.length; + voice.samplePtr = sample.loopPtr; + voice.sampleLen = sample.repeat; + voice.waitCtr = 1; + } else { + voice.wavePos = 0; + voice.waveList = sample.waveform; + index = voice.waveList << 4; + audPtr = waveLists[index] << 5; + audLen = 32; + voice.waveTimer = waveLists[++index]; + } + + voice.noteTimer = row.speed; + voice.sample = row.sample; + voice.envelopeCtr = voice.pitchCtr = voice.pitchFallCtr = 0; + } + + if (row.note) { + voice.noteTimer = row.speed; + + if (row.note != 0xff) { + sample = samples[voice.sample]; + step = tracks[voice.step]; + + voice.note = row.note + step.transpose; + voice.period = audPer = PERIODS[int(1 + sample.finetune + voice.note)]; + voice.phaseSpeed = sample.phaseSpeed; + + voice.bendSpeed = voice.volume = 0; + voice.envelopeCtr = voice.pitchCtr = voice.pitchFallCtr = 0; + + switch (row.effect) { + case 0: + if (row.param == 0) break; + sample.attackSpeed = row.param; + sample.attackMax = row.param; + voice.waveTimer = 0; + break; + case 2: + this.speed = row.param; + voice.waveTimer = 0; + break; + case 3: + this.patternLen = row.param; + voice.waveTimer = 0; + break; + default: + voice.bendTo = row.effect + step.transpose; + voice.bendSpeed = row.param; + break; + } + } + } + voice.row++; + } else { + voice.noteTimer--; + } + } + sample = samples[voice.sample]; + audVol = voice.volume; + + switch (voice.envelopeCtr) { + case 8: + break; + case 0: //attack + audVol += sample.attackSpeed; + + if (audVol > sample.attackMax) { + audVol = sample.attackMax; + voice.envelopeCtr += 2; + } + break; + case 2: //decay + audVol -= sample.decaySpeed; + + if (audVol <= sample.decayMin || audVol < -256) { + audVol = sample.decayMin; + voice.envelopeCtr += 2; + voice.sustainCtr = sample.sustain; + } + break; + case 4: //sustain + voice.sustainCtr--; + if (voice.sustainCtr == 0 || voice.sustainCtr == -256) voice.envelopeCtr += 2; + break; + case 6: //release + this.audVol -= sample.releaseSpeed; + + if (audVol <= sample.releaseMin || audVol < -256) { + audVol = sample.releaseMin; + voice.envelopeCtr = 8; + } + break; + } + + voice.volume = audVol; + voice.arpeggioCtr = ++voice.arpeggioCtr & 15; + index = sample.finetune + sample.arpeggio[voice.arpeggioCtr] + voice.note; + voice.period = audPer = PERIODS[index]; + + if (voice.bendSpeed) { + value = PERIODS[int(sample.finetune + voice.bendTo)]; + index = ~voice.bendSpeed + 1; + if (index < -128) index &= 255; + voice.pitchCtr += index; + voice.period += voice.pitchCtr; + + if ((index < 0 && voice.period <= value) || (index > 0 && voice.period >= value)) { + voice.note = voice.bendTo; + voice.period = value; + voice.bendSpeed = 0; + voice.pitchCtr = 0; + } + } + + if (sample.phaseShift) { + if (voice.phaseSpeed) { + voice.phaseSpeed--; + } else { + voice.phaseTimer = ++voice.phaseTimer & 31; + index = (sample.phaseShift << 5) + voice.phaseTimer; + voice.period += memory[index] >> 2; + } + } + voice.pitchFallCtr -= sample.pitchFall; + if (voice.pitchFallCtr < -256) voice.pitchFallCtr += 256; + voice.period += voice.pitchFallCtr; + + if (voice.waitCtr == 0) { + if (voice.waveTimer) { + voice.waveTimer--; + } else { + if (voice.wavePos < 16) { + index = (voice.waveList << 4) + voice.wavePos; + value = waveLists[index++]; + + if (value == 0xff) { + voice.wavePos = waveLists[index] & 254; + } else { + audPtr = value << 5; + voice.waveTimer = waveLists[index]; + voice.wavePos += 2; + } + } + } + } + if (audPtr > -1) chan.pointer = audPtr; + if (audPer != 0) chan.period = voice.period; + if (audLen != 0) chan.length = audLen; + + if (sample.volume) chan.volume = sample.volume; + else chan.volume = audVol >> 2; + + chan.enabled = 1; + voice = voice.next; + } + + trackEnd = patternEnd = 0; + + if (++tick > speed) { + tick = 0; + + if (++patternPos == patternLen) { + patternPos = 0; + patternEnd = 1; + + if (++trackPos == trackLen) + trackPos = trackEnd = amiga.complete = 1; + } + } + + if (mix1Speed) { + if (mix1Ctr == 0) { + mix1Ctr = mix1Speed; + index = mix1Pos = ++mix1Pos & 31; + dst = (mix1Dest << 5) + 31; + src1 = (mix1Source1 << 5) + 31; + src2 = mix1Source2 << 5; + + for (i = 31; i > -1; --i) { + memory[dst--] = (memory[src1--] + memory[int(src2 + index)]) >> 1; + index = --index & 31; + } + } + mix1Ctr--; + } + + if (mix2Speed) { + if (mix2Ctr == 0) { + mix2Ctr = mix2Speed; + index = mix2Pos = ++mix2Pos & 31; + dst = (mix2Dest << 5) + 31; + src1 = (mix2Source1 << 5) + 31; + src2 = mix2Source2 << 5; + + for (i = 31; i > -1; --i) { + memory[dst--] = (memory[src1--] + memory[int(src2 + index)]) >> 1; + index = --index & 31; + } + } + mix2Ctr--; + } + + if (doFilter) { + index = mix1Pos + 32; + memory[index] = ~memory[index] + 1; + } + voice = voices[0]; + + while (voice) { + chan = voice.channel; + + if (voice.waitCtr == 1) { + voice.waitCtr++; + } else if (voice.waitCtr == 2) { + voice.waitCtr++; + chan.pointer = voice.samplePtr; + chan.length = voice.sampleLen; + } + voice = voice.next; + } + } + + override protected function initialize():void { + var chan:AmigaChannel, step:AmigaStep, voice:S1Voice = voices[0]; + super.initialize(); + + speed = speedDef; + tick = speedDef; + trackPos = 1; + trackEnd = 0; + patternPos = -1; + patternEnd = 0; + patternLen = patternDef; + + mix1Ctr = mix1Pos = 0; + mix2Ctr = mix2Pos = 0; + + while (voice) { + voice.initialize(); + chan = amiga.channels[voice.index]; + + voice.channel = chan; + voice.step = tracksPtr[voice.index]; + step = tracks[voice.step]; + voice.row = patternsPtr[step.pattern]; + voice.sample = patterns[voice.row].sample; + + chan.length = 32; + chan.period = voice.period; + chan.enabled = 1; + + voice = voice.next; + } + } + + override protected function loader(stream:ByteArray):void { + var data:int, i:int, id:String, j:int, headers:int, len:int, position:int, row:SMRow, sample:S1Sample, start:int, step:AmigaStep, totInstruments:int, totPatterns:int, totSamples:int, totWaveforms:int, ver:int; + + while (stream.bytesAvailable > 8) { + start = stream.readUnsignedShort(); + if (start != 0x41fa) continue; + j = stream.readUnsignedShort(); + + start = stream.readUnsignedShort(); + if (start != 0xd1e8) continue; + start = stream.readUnsignedShort(); + + if (start == 0xffd4) { + if (j == 0x0fec) ver = SIDMON_0FFA; + else if (j == 0x1466) ver = SIDMON_1444; + else ver = j; + + position = j + stream.position - 6; + break; + } + } + if (!position) return; + stream.position = position; + + id = stream.readMultiByte(32, ENCODING); + if (id != " SID-MON BY R.v.VLIET (c) 1988 ") return; + + stream.position = position - 44; + start = stream.readUnsignedInt(); + + for (i = 1; i < 4; ++i) + tracksPtr[i] = (stream.readUnsignedInt() - start) / 6; + + stream.position = position - 8; + start = stream.readUnsignedInt(); + len = stream.readUnsignedInt(); + if (len < start) len = stream.length - position; + + totPatterns = (len - start) >> 2; + patternsPtr = new Vector.(totPatterns); + stream.position = position + start + 4; + + for (i = 1; i < totPatterns; ++i) { + start = stream.readUnsignedInt() / 5; + + if (start == 0) { + totPatterns = i; + break; + } + patternsPtr[i] = start; + } + + patternsPtr.length = totPatterns; + patternsPtr.fixed = true; + + stream.position = position - 44; + start = stream.readUnsignedInt(); + stream.position = position - 28; + len = (stream.readUnsignedInt() - start) / 6; + + tracks = new Vector.(len, true); + stream.position = position + start; + + for (i = 0; i < len; ++i) { + step = new AmigaStep(); + step.pattern = stream.readUnsignedInt(); + if (step.pattern >= totPatterns) step.pattern = 0; + stream.readByte(); + step.transpose = stream.readByte(); + if (step.transpose < -99 || step.transpose > 99) step.transpose = 0; + tracks[i] = step; + } + + stream.position = position - 24; + start = stream.readUnsignedInt(); + totWaveforms = stream.readUnsignedInt() - start; + + amiga.memory.length = 32; + amiga.store(stream, totWaveforms, position + start); + totWaveforms >>= 5; + + stream.position = position - 16; + start = stream.readUnsignedInt(); + len = (stream.readUnsignedInt() - start) + 16; + j = (totWaveforms + 2) << 4; + + waveLists = new Vector.(len < j ? j : len, true); + stream.position = position + start; + i = 0; + + while (i < j) { + waveLists[i++] = i >> 4; + waveLists[i++] = 0xff; + waveLists[i++] = 0xff; + waveLists[i++] = 0x10; + i += 12; + } + + for (i = 16; i < len; ++i) + waveLists[i] = stream.readUnsignedByte(); + + stream.position = position - 20; + stream.position = position + stream.readUnsignedInt(); + + mix1Source1 = stream.readUnsignedInt(); + mix2Source1 = stream.readUnsignedInt(); + mix1Source2 = stream.readUnsignedInt(); + mix2Source2 = stream.readUnsignedInt(); + mix1Dest = stream.readUnsignedInt(); + mix2Dest = stream.readUnsignedInt(); + patternDef = stream.readUnsignedInt(); + trackLen = stream.readUnsignedInt(); + speedDef = stream.readUnsignedInt(); + mix1Speed = stream.readUnsignedInt(); + mix2Speed = stream.readUnsignedInt(); + + if (mix1Source1 > totWaveforms) mix1Source1 = 0; + if (mix2Source1 > totWaveforms) mix2Source1 = 0; + if (mix1Source2 > totWaveforms) mix1Source2 = 0; + if (mix2Source2 > totWaveforms) mix2Source2 = 0; + if (mix1Dest > totWaveforms) mix1Speed = 0; + if (mix2Dest > totWaveforms) mix2Speed = 0; + if (speedDef == 0) speedDef = 4; + + stream.position = position - 28; + j = stream.readUnsignedInt(); + totInstruments = (stream.readUnsignedInt() - j) >> 5; + if (totInstruments > 63) totInstruments = 63; + len = totInstruments + 1; + + stream.position = position - 4; + start = stream.readUnsignedInt(); + + if (start == 1) { + stream.position = 0x71c; + start = stream.readUnsignedShort(); + + if (start != 0x4dfa) { + stream.position = 0x6fc; + start = stream.readUnsignedShort(); + + if (start != 0x4dfa) { + version = 0; + return; + } + } + stream.position += stream.readUnsignedShort(); + samples = new Vector.(len + 3, true); + + for (i = 0; i < 3; ++i) { + sample = new S1Sample(); + sample.waveform = 16 + i; + sample.length = EMBEDDED[i]; + sample.pointer = amiga.store(stream, sample.length); + sample.loop = sample.loopPtr = 0; + sample.repeat = 4; + sample.volume = 64; + samples[int(len + i)] = sample; + stream.position += sample.length; + } + } else { + samples = new Vector.(len, true); + + stream.position = position + start; + data = stream.readUnsignedInt(); + totSamples = (data >> 5) + 15; + headers = stream.position; + data += headers; + } + + sample = new S1Sample(); + samples[0] = sample; + stream.position = position + j; + + for (i = 1; i < len; ++i) { + sample = new S1Sample(); + sample.waveform = stream.readUnsignedInt(); + for (j = 0; j < 16; ++j) sample.arpeggio[j] = stream.readUnsignedByte(); + + sample.attackSpeed = stream.readUnsignedByte(); + sample.attackMax = stream.readUnsignedByte(); + sample.decaySpeed = stream.readUnsignedByte(); + sample.decayMin = stream.readUnsignedByte(); + sample.sustain = stream.readUnsignedByte(); + stream.readByte(); + sample.releaseSpeed = stream.readUnsignedByte(); + sample.releaseMin = stream.readUnsignedByte(); + sample.phaseShift = stream.readUnsignedByte(); + sample.phaseSpeed = stream.readUnsignedByte(); + sample.finetune = stream.readUnsignedByte(); + sample.pitchFall = stream.readByte(); + + if (ver == SIDMON_1444) { + sample.pitchFall = sample.finetune; + sample.finetune = 0; + } else { + if (sample.finetune > 15) sample.finetune = 0; + sample.finetune *= 67; + } + + if (sample.phaseShift > totWaveforms) { + sample.phaseShift = 0; + sample.phaseSpeed = 0; + } + + if (sample.waveform > 15) { + if ((totSamples > 15) && (sample.waveform > totSamples)) { + sample.waveform = 0; + } else { + start = headers + ((sample.waveform - 16) << 5); + if (start >= stream.length) continue; + j = stream.position; + + stream.position = start; + sample.pointer = stream.readUnsignedInt(); + sample.loop = stream.readUnsignedInt(); + sample.length = stream.readUnsignedInt(); + sample.name = stream.readMultiByte(20, ENCODING); + + if (sample.loop == 0 || + sample.loop == 99999 || + sample.loop == 199999 || + sample.loop >= sample.length) { + + sample.loop = 0; + sample.repeat = ver == SIDMON_0FFA ? 2 : 4; + } else { + sample.repeat = sample.length - sample.loop; + sample.loop -= sample.pointer; + } + + sample.length -= sample.pointer; + if (sample.length < (sample.loop + sample.repeat)) + sample.length = sample.loop + sample.repeat; + + sample.pointer = amiga.store(stream, sample.length, data + sample.pointer); + if (sample.repeat < 6 || sample.loop == 0) sample.loopPtr = 0; + else sample.loopPtr = sample.pointer + sample.loop; + + stream.position = j; + } + } else if (sample.waveform > totWaveforms) { + sample.waveform = 0; + } + samples[i] = sample; + } + + stream.position = position - 12; + start = stream.readUnsignedInt(); + len = (stream.readUnsignedInt() - start) / 5; + patterns = new Vector.(len, true); + stream.position = position + start; + + for (i = 0; i < len; ++i) { + row = new SMRow(); + row.note = stream.readUnsignedByte(); + row.sample = stream.readUnsignedByte(); + row.effect = stream.readUnsignedByte(); + row.param = stream.readUnsignedByte(); + row.speed = stream.readUnsignedByte(); + + if (ver == SIDMON_1444) { + if (row.note > 0 && row.note < 255) row.note += 469; + if (row.effect > 0 && row.effect < 255) row.effect += 469; + if (row.sample > 59) row.sample = totInstruments + (row.sample - 60); + } else if (row.sample > totInstruments) { + row.sample = 0; + } + patterns[i] = row; + } + + if (ver == SIDMON_1170 || ver == SIDMON_11C6 || ver == SIDMON_1444) { + if (ver == SIDMON_1170) mix1Speed = mix2Speed = 0; + doReset = doFilter = 0; + } else { + doReset = doFilter = 1; + } + version = 1; + } + + private const + SIDMON_0FFA = 0x0ffa, + SIDMON_1170 = 0x1170, + SIDMON_11C6 = 0x11c6, + SIDMON_11DC = 0x11dc, + SIDMON_11E0 = 0x11e0, + SIDMON_125A = 0x125a, + SIDMON_1444 = 0x1444, + + EMBEDDED: Vector. = Vector.([1166, 408, 908]), + + PERIODS: Vector. = Vector.([0, + 5760,5424,5120,4832,4560,4304,4064,3840,3616,3424,3232,3048, + 2880,2712,2560,2416,2280,2152,2032,1920,1808,1712,1616,1524, + 1440,1356,1280,1208,1140,1076,1016, 960, 904, 856, 808, 762, + 720, 678, 640, 604, 570, 538, 508, 480, 452, 428, 404, 381, + 360, 339, 320, 302, 285, 269, 254, 240, 226, 214, 202, 190, + 180, 170, 160, 151, 143, 135, 127, + 0,0,0,0,0,0,0, + 4028,3806,3584,3394,3204,3013,2855,2696,2538,2395,2268,2141, + 2014,1903,1792,1697,1602,1507,1428,1348,1269,1198,1134,1071, + 1007, 952, 896, 849, 801, 754, 714, 674, 635, 599, 567, 536, + 504, 476, 448, 425, 401, 377, 357, 337, 310, 300, 284, 268, + 252, 238, 224, 213, 201, 189, 179, 169, 159, 150, 142, 134, + 0,0,0,0,0,0,0, + 3993,3773,3552,3364,3175,2987,2830,2672,2515,2374,2248,2122, + 1997,1887,1776,1682,1588,1494,1415,1336,1258,1187,1124,1061, + 999, 944, 888, 841, 794, 747, 708, 668, 629, 594, 562, 531, + 500, 472, 444, 421, 397, 374, 354, 334, 315, 297, 281, 266, + 250, 236, 222, 211, 199, 187, 177, 167, 158, 149, 141, 133, + 0,0,0,0,0,0,0, + 3957,3739,3521,3334,3147,2960,2804,2648,2493,2353,2228,2103, + 1979,1870,1761,1667,1574,1480,1402,1324,1247,1177,1114,1052, + 990, 935, 881, 834, 787, 740, 701, 662, 624, 589, 557, 526, + 495, 468, 441, 417, 394, 370, 351, 331, 312, 295, 279, 263, + 248, 234, 221, 209, 197, 185, 176, 166, 156, 148, 140, 132, + 0,0,0,0,0,0,0, + 3921,3705,3489,3304,3119,2933,2779,2625,2470,2331,2208,2084, + 1961,1853,1745,1652,1560,1467,1390,1313,1235,1166,1104,1042, + 981, 927, 873, 826, 780, 734, 695, 657, 618, 583, 552, 521, + 491, 464, 437, 413, 390, 367, 348, 329, 309, 292, 276, 261, + 246, 232, 219, 207, 195, 184, 174, 165, 155, 146, 138, 131, + 0,0,0,0,0,0,0, + 3886,3671,3457,3274,3090,2907,2754,2601,2448,2310,2188,2065, + 1943,1836,1729,1637,1545,1454,1377,1301,1224,1155,1094,1033, + 972, 918, 865, 819, 773, 727, 689, 651, 612, 578, 547, 517, + 486, 459, 433, 410, 387, 364, 345, 326, 306, 289, 274, 259, + 243, 230, 217, 205, 194, 182, 173, 163, 153, 145, 137, 130, + 0,0,0,0,0,0,0, + 3851,3638,3426,3244,3062,2880,2729,2577,2426,2289,2168,2047, + 1926,1819,1713,1622,1531,1440,1365,1289,1213,1145,1084,1024, + 963, 910, 857, 811, 766, 720, 683, 645, 607, 573, 542, 512, + 482, 455, 429, 406, 383, 360, 342, 323, 304, 287, 271, 256, + 241, 228, 215, 203, 192, 180, 171, 162, 152, 144, 136, 128, + 6848,6464,6096,5760,5424,5120,4832,4560,4304,4064,3840,3616, + 3424,3232,3048,2880,2712,2560,2416,2280,2152,2032,1920,1808, + 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016, 960, 904, + 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 452, + 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226, + 214, 202, 190, 180, 170, 160, 151, 143, 135, 127]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/sidmon/S1Sample.as b/Flod 4.1/neoart/flod/sidmon/S1Sample.as new file mode 100644 index 0000000..87f974e --- /dev/null +++ b/Flod 4.1/neoart/flod/sidmon/S1Sample.as @@ -0,0 +1,41 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.sidmon { + import neoart.flod.core.*; + + public final class S1Sample extends AmigaSample { + internal var + waveform : int, + arpeggio : Vector., + attackSpeed : int, + attackMax : int, + decaySpeed : int, + decayMin : int, + sustain : int, + releaseSpeed : int, + releaseMin : int, + phaseShift : int, + phaseSpeed : int, + finetune : int, + pitchFall : int; + + public function S1Sample() { + arpeggio = new Vector.(16, true); + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/sidmon/S1Voice.as b/Flod 4.1/neoart/flod/sidmon/S1Voice.as new file mode 100644 index 0000000..0e3e308 --- /dev/null +++ b/Flod 4.1/neoart/flod/sidmon/S1Voice.as @@ -0,0 +1,78 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.sidmon { + import neoart.flod.core.*; + + public final class S1Voice { + internal var + index : int, + next : S1Voice, + channel : AmigaChannel, + step : int, + row : int, + sample : int, + samplePtr : int, + sampleLen : int, + note : int, + noteTimer : int, + period : int, + volume : int, + bendTo : int, + bendSpeed : int, + arpeggioCtr : int, + envelopeCtr : int, + pitchCtr : int, + pitchFallCtr : int, + sustainCtr : int, + phaseTimer : int, + phaseSpeed : int, + wavePos : int, + waveList : int, + waveTimer : int, + waitCtr : int; + + public function S1Voice(index:int) { + this.index = index; + } + + internal function initialize():void { + step = 0; + row = 0; + sample = 0; + samplePtr = -1; + sampleLen = 0; + note = 0; + noteTimer = 0; + period = 0x9999; + volume = 0; + bendTo = 0; + bendSpeed = 0; + arpeggioCtr = 0; + envelopeCtr = 0; + pitchCtr = 0; + pitchFallCtr = 0; + sustainCtr = 0; + phaseTimer = 0; + phaseSpeed = 0; + wavePos = 0; + waveList = 0; + waveTimer = 0; + waitCtr = 0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/sidmon/S2Instrument.as b/Flod 4.1/neoart/flod/sidmon/S2Instrument.as new file mode 100644 index 0000000..af54ad7 --- /dev/null +++ b/Flod 4.1/neoart/flod/sidmon/S2Instrument.as @@ -0,0 +1,45 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.sidmon { + import neoart.flod.core.*; + + public final class S2Instrument { + internal var + wave : int, + waveLen : int, + waveDelay : int, + waveSpeed : int, + arpeggio : int, + arpeggioLen : int, + arpeggioDelay : int, + arpeggioSpeed : int, + vibrato : int, + vibratoLen : int, + vibratoDelay : int, + vibratoSpeed : int, + pitchBend : int, + pitchBendDelay : int, + attackMax : int, + attackSpeed : int, + decayMin : int, + decaySpeed : int, + sustain : int, + releaseMin : int, + releaseSpeed : int; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/sidmon/S2Player.as b/Flod 4.1/neoart/flod/sidmon/S2Player.as new file mode 100644 index 0000000..84c06a1 --- /dev/null +++ b/Flod 4.1/neoart/flod/sidmon/S2Player.as @@ -0,0 +1,559 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/31 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.sidmon { + import flash.utils.*; + import neoart.flod.core.*; + + public final class S2Player extends AmigaPlayer { + private var + tracks : Vector., + patterns : Vector., + instruments : Vector., + samples : Vector., + arpeggios : Vector., + vibratos : Vector., + waves : Vector., + length : int, + speedDef : int, + voices : Vector., + trackPos : int, + patternPos : int, + patternLen : int, + arpeggioFx : Vector., + arpeggioPos : int; + + public function S2Player(amiga:Amiga = null) { + super(amiga); + PERIODS.fixed = true; + + arpeggioFx = new Vector.(4, true); + voices = new Vector.(4, true); + + voices[0] = new S2Voice(0); + voices[0].next = voices[1] = new S2Voice(1); + voices[1].next = voices[2] = new S2Voice(2); + voices[2].next = voices[3] = new S2Voice(3); + } + + override public function process():void { + var chan:AmigaChannel, instr:S2Instrument, row:SMRow, sample:S2Sample, value:int, voice:S2Voice = voices[0]; + arpeggioPos = ++arpeggioPos & 3; + + if (++tick >= speed) { + tick = 0; + + while (voice) { + chan = voice.channel; + voice.enabled = voice.note = 0; + + if (!patternPos) { + voice.step = tracks[int(trackPos + voice.index * length)]; + voice.pattern = voice.step.pattern; + voice.speed = 0; + } + if (--voice.speed < 0) { + voice.row = row = patterns[voice.pattern++]; + voice.speed = row.speed; + + if (row.note) { + voice.enabled = 1; + voice.note = row.note + voice.step.transpose; + chan.enabled = 0; + } + } + voice.pitchBend = 0; + + if (voice.note) { + voice.waveCtr = voice.sustainCtr = 0; + voice.arpeggioCtr = voice.arpeggioPos = 0; + voice.vibratoCtr = voice.vibratoPos = 0; + voice.pitchBendCtr = voice.noteSlideSpeed = 0; + voice.adsrPos = 4; + voice.volume = 0; + + if (row.sample) { + voice.instrument = row.sample; + voice.instr = instruments[int(voice.instrument + voice.step.soundTranspose)]; + voice.sample = samples[waves[voice.instr.wave]]; + } + voice.original = voice.note + arpeggios[voice.instr.arpeggio]; + chan.period = voice.period = PERIODS[voice.original]; + + sample = voice.sample; + chan.pointer = sample.pointer; + chan.length = sample.length; + chan.enabled = voice.enabled; + chan.pointer = sample.loopPtr; + chan.length = sample.repeat; + } + voice = voice.next; + } + + if (++patternPos == patternLen) { + patternPos = 0; + + if (++trackPos == length) { + trackPos = 0; + amiga.complete = 1; + } + } + } + voice = voices[0]; + + while (voice) { + if (!voice.sample) { + voice = voice.next; + continue; + } + chan = voice.channel; + sample = voice.sample; + + if (sample.negToggle) { + voice = voice.next; + continue; + } + sample.negToggle = 1; + + if (sample.negCtr) { + sample.negCtr = --sample.negCtr & 31; + } else { + sample.negCtr = sample.negSpeed; + if (!sample.negDir) { + voice = voice.next; + continue; + } + + value = sample.negStart + sample.negPos; + amiga.memory[value] = ~amiga.memory[value]; + sample.negPos += sample.negOffset; + value = sample.negLen - 1; + + if (sample.negPos < 0) { + if (sample.negDir == 2) { + sample.negPos = value; + } else { + sample.negOffset = -sample.negOffset; + sample.negPos += sample.negOffset; + } + } else if (value < sample.negPos) { + if (sample.negDir == 1) { + sample.negPos = 0; + } else { + sample.negOffset = -sample.negOffset; + sample.negPos += sample.negOffset; + } + } + } + voice = voice.next; + } + voice = voices[0]; + + while (voice) { + if (!voice.sample) { + voice = voice.next; + continue; + } + voice.sample.negToggle = 0; + voice = voice.next; + } + voice = voices[0]; + + while (voice) { + chan = voice.channel; + instr = voice.instr; + + switch (voice.adsrPos) { + case 0: + break; + case 4: //attack + voice.volume += instr.attackSpeed; + if (instr.attackMax <= voice.volume) { + voice.volume = instr.attackMax; + voice.adsrPos--; + } + break; + case 3: //decay + if (!instr.decaySpeed) { + voice.adsrPos--; + } else { + voice.volume -= instr.decaySpeed; + if (instr.decayMin >= voice.volume) { + voice.volume = instr.decayMin; + voice.adsrPos--; + } + } + break; + case 2: //sustain + if (voice.sustainCtr == instr.sustain) voice.adsrPos--; + else voice.sustainCtr++; + break; + case 1: //release + voice.volume -= instr.releaseSpeed; + if (instr.releaseMin >= voice.volume) { + voice.volume = instr.releaseMin; + voice.adsrPos--; + } + break; + } + chan.volume = voice.volume >> 2; + + if (instr.waveLen) { + if (voice.waveCtr == instr.waveDelay) { + voice.waveCtr = instr.waveDelay - instr.waveSpeed; + if (voice.wavePos == instr.waveLen) voice.wavePos = 0; + else voice.wavePos++; + + voice.sample = sample = samples[waves[int(instr.wave + voice.wavePos)]]; + chan.pointer = sample.pointer; + chan.length = sample.length; + } else + voice.waveCtr++; + } + + if (instr.arpeggioLen) { + if (voice.arpeggioCtr == instr.arpeggioDelay) { + voice.arpeggioCtr = instr.arpeggioDelay - instr.arpeggioSpeed; + if (voice.arpeggioPos == instr.arpeggioLen) voice.arpeggioPos = 0; + else voice.arpeggioPos++; + + value = voice.original + arpeggios[int(instr.arpeggio + voice.arpeggioPos)]; + voice.period = PERIODS[value]; + } else + voice.arpeggioCtr++; + } + row = voice.row; + + if (tick) { + switch (row.effect) { + case 0: + break; + case 0x70: //arpeggio + arpeggioFx[0] = row.param >> 4; + arpeggioFx[2] = row.param & 15; + value = voice.original + arpeggioFx[arpeggioPos]; + voice.period = PERIODS[value]; + break; + case 0x71: //pitch up + voice.pitchBend = -row.param; + break; + case 0x72: //pitch down + voice.pitchBend = row.param; + break; + case 0x73: //volume up + if (voice.adsrPos != 0) break; + if (voice.instrument != 0) voice.volume = instr.attackMax; + voice.volume += row.param << 2; + if (voice.volume >= 256) voice.volume = -1; + break; + case 0x74: //volume down + if (voice.adsrPos != 0) break; + if (voice.instrument != 0) voice.volume = instr.attackMax; + voice.volume -= row.param << 2; + if (voice.volume < 0) voice.volume = 0; + break; + } + } + + switch (row.effect) { + case 0: + break; + case 0x75: //set adsr attack + instr.attackMax = row.param; + instr.attackSpeed = row.param; + break; + case 0x76: //set pattern length + patternLen = row.param; + break; + case 0x7c: //set volume + chan.volume = row.param; + voice.volume = row.param << 2; + if (voice.volume >= 255) voice.volume = 255; + break; + case 0x7f: //set speed + value = row.param & 15; + if (value) speed = value; + break; + } + + if (instr.vibratoLen) { + if (voice.vibratoCtr == instr.vibratoDelay) { + voice.vibratoCtr = instr.vibratoDelay - instr.vibratoSpeed; + if (voice.vibratoPos == instr.vibratoLen) voice.vibratoPos = 0; + else voice.vibratoPos++; + + voice.period += vibratos[int(instr.vibrato + voice.vibratoPos)]; + } else + voice.vibratoCtr++; + } + + if (instr.pitchBend) { + if (voice.pitchBendCtr == instr.pitchBendDelay) { + voice.pitchBend += instr.pitchBend; + } else + voice.pitchBendCtr++; + } + + if (row.param) { + if (row.effect && row.effect < 0x70) { + voice.noteSlideTo = PERIODS[int(row.effect + voice.step.transpose)]; + value = row.param; + if ((voice.noteSlideTo - voice.period) < 0) value = -value; + voice.noteSlideSpeed = value; + } + } + + if (voice.noteSlideTo && voice.noteSlideSpeed) { + voice.period += voice.noteSlideSpeed; + + if ((voice.noteSlideSpeed < 0 && voice.period < voice.noteSlideTo) || + (voice.noteSlideSpeed > 0 && voice.period > voice.noteSlideTo)) { + voice.noteSlideSpeed = 0; + voice.period = voice.noteSlideTo; + } + } + + voice.period += voice.pitchBend; + + if (voice.period < 95) voice.period = 95; + else if (voice.period > 5760) voice.period = 5760; + + chan.period = voice.period; + voice = voice.next; + } + } + + override protected function initialize():void { + var voice:S2Voice = voices[0]; + super.initialize(); + + speed = speedDef; + tick = speedDef; + trackPos = 0; + patternPos = 0; + patternLen = 64; + + while (voice) { + voice.initialize(); + voice.channel = amiga.channels[voice.index]; + voice.instr = instruments[0]; + + arpeggioFx[voice.index] = 0; + voice = voice.next; + } + } + + override protected function loader(stream:ByteArray):void { + var higher:int, i:int = 0, id:String, instr:S2Instrument, j:int, len:int, pointers:Vector., position:int, pos:int, row:SMRow, step:S2Step, sample:S2Sample, sampleData:int, value:int; + stream.position = 58; + id = stream.readMultiByte(28, ENCODING); + if (id != "SIDMON II - THE MIDI VERSION") return; + + stream.position = 2; + length = stream.readUnsignedByte(); + speedDef = stream.readUnsignedByte(); + samples = new Vector.(stream.readUnsignedShort() >> 6, true); + + stream.position = 14; + len = stream.readUnsignedInt(); + tracks = new Vector.(len, true); + stream.position = 90; + + for (; i < len; ++i) { + step = new S2Step(); + step.pattern = stream.readUnsignedByte(); + if (step.pattern > higher) higher = step.pattern; + tracks[i] = step; + } + + for (i = 0; i < len; ++i) { + step = tracks[i]; + step.transpose = stream.readByte(); + } + + for (i = 0; i < len; ++i) { + step = tracks[i]; + step.soundTranspose = stream.readByte(); + } + + position = stream.position; + stream.position = 26; + len = stream.readUnsignedInt() >> 5; + instruments = new Vector.(++len, true); + stream.position = position; + + instruments[0] = new S2Instrument(); + + for (i = 0; ++i < len;) { + instr = new S2Instrument(); + instr.wave = stream.readUnsignedByte() << 4; + instr.waveLen = stream.readUnsignedByte(); + instr.waveSpeed = stream.readUnsignedByte(); + instr.waveDelay = stream.readUnsignedByte(); + instr.arpeggio = stream.readUnsignedByte() << 4; + instr.arpeggioLen = stream.readUnsignedByte(); + instr.arpeggioSpeed = stream.readUnsignedByte(); + instr.arpeggioDelay = stream.readUnsignedByte(); + instr.vibrato = stream.readUnsignedByte() << 4; + instr.vibratoLen = stream.readUnsignedByte(); + instr.vibratoSpeed = stream.readUnsignedByte(); + instr.vibratoDelay = stream.readUnsignedByte(); + instr.pitchBend = stream.readByte(); + instr.pitchBendDelay = stream.readUnsignedByte(); + stream.readByte(); + stream.readByte(); + instr.attackMax = stream.readUnsignedByte(); + instr.attackSpeed = stream.readUnsignedByte(); + instr.decayMin = stream.readUnsignedByte(); + instr.decaySpeed = stream.readUnsignedByte(); + instr.sustain = stream.readUnsignedByte(); + instr.releaseMin = stream.readUnsignedByte(); + instr.releaseSpeed = stream.readUnsignedByte(); + instruments[i] = instr; + stream.position += 9; + } + + position = stream.position; + stream.position = 30; + len = stream.readUnsignedInt(); + waves = new Vector.(len, true); + stream.position = position; + + for (i = 0; i < len; ++i) waves[i] = stream.readUnsignedByte(); + + position = stream.position; + stream.position = 34; + len = stream.readUnsignedInt(); + arpeggios = new Vector.(len, true); + stream.position = position; + + for (i = 0; i < len; ++i) arpeggios[i] = stream.readByte(); + + position = stream.position; + stream.position = 38; + len = stream.readUnsignedInt(); + vibratos = new Vector.(len, true); + stream.position = position; + + for (i = 0; i < len; ++i) vibratos[i] = stream.readByte(); + + len = samples.length; + position = 0; + + for (i = 0; i < len; ++i) { + sample = new S2Sample(); + stream.readUnsignedInt(); + sample.length = stream.readUnsignedShort() << 1; + sample.loop = stream.readUnsignedShort() << 1; + sample.repeat = stream.readUnsignedShort() << 1; + sample.negStart = position + (stream.readUnsignedShort() << 1); + sample.negLen = stream.readUnsignedShort() << 1; + sample.negSpeed = stream.readUnsignedShort(); + sample.negDir = stream.readUnsignedShort(); + sample.negOffset = stream.readShort(); + sample.negPos = stream.readUnsignedInt(); + sample.negCtr = stream.readUnsignedShort(); + stream.position += 6; + sample.name = stream.readMultiByte(32, ENCODING); + + sample.pointer = position; + sample.loopPtr = position + sample.loop; + position += sample.length; + samples[i] = sample; + } + + sampleData = position; + len = ++higher; + pointers = new Vector.(++higher, true); + for (i = 0; i < len; ++i) pointers[i] = stream.readUnsignedShort(); + + position = stream.position; + stream.position = 50; + len = stream.readUnsignedInt(); + patterns = new Vector.(); + stream.position = position; + j = 1; + + for (i = 0; i < len; ++i) { + row = new SMRow(); + value = stream.readByte(); + + if (!value) { + row.effect = stream.readByte(); + row.param = stream.readUnsignedByte(); + i += 2; + } else if (value < 0) { + row.speed = ~value; + } else if (value < 112) { + row.note = value; + value = stream.readByte(); + i++; + + if (value < 0) { + row.speed = ~value; + } else if (value < 112) { + row.sample = value; + value = stream.readByte(); + i++; + + if (value < 0) { + row.speed = ~value; + } else { + row.effect = value; + row.param = stream.readUnsignedByte(); + i++; + } + } else { + row.effect = value; + row.param = stream.readUnsignedByte(); + i++; + } + } else { + row.effect = value; + row.param = stream.readUnsignedByte(); + i++; + } + + patterns[pos++] = row; + if ((position + pointers[j]) == stream.position) pointers[j++] = pos; + } + pointers[j] = patterns.length; + patterns.fixed = true; + + if ((stream.position & 1) != 0) stream.position++; + amiga.store(stream, sampleData); + len = tracks.length; + + for (i = 0; i < len; ++i) { + step = tracks[i]; + step.pattern = pointers[step.pattern]; + } + + length++; + version = 2; + } + + private const + PERIODS: Vector. = Vector.([0, + 5760,5424,5120,4832,4560,4304,4064,3840,3616,3424,3232,3048, + 2880,2712,2560,2416,2280,2152,2032,1920,1808,1712,1616,1524, + 1440,1356,1280,1208,1140,1076,1016, 960, 904, 856, 808, 762, + 720, 678, 640, 604, 570, 538, 508, 480, 453, 428, 404, 381, + 360, 339, 320, 302, 285, 269, 254, 240, 226, 214, 202, 190, + 180, 170, 160, 151, 143, 135, 127, 120, 113, 107, 101, 95]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/sidmon/S2Sample.as b/Flod 4.1/neoart/flod/sidmon/S2Sample.as new file mode 100644 index 0000000..1bd263c --- /dev/null +++ b/Flod 4.1/neoart/flod/sidmon/S2Sample.as @@ -0,0 +1,32 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.sidmon { + import neoart.flod.core.*; + + public final class S2Sample extends AmigaSample { + internal var + negStart : int, + negLen : int, + negSpeed : int, + negDir : int, + negOffset : int, + negPos : int, + negCtr : int, + negToggle : int; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/sidmon/S2Step.as b/Flod 4.1/neoart/flod/sidmon/S2Step.as new file mode 100644 index 0000000..681ba07 --- /dev/null +++ b/Flod 4.1/neoart/flod/sidmon/S2Step.as @@ -0,0 +1,25 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.sidmon { + import neoart.flod.core.*; + + public final class S2Step extends AmigaStep { + internal var + soundTranspose : int; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/sidmon/S2Voice.as b/Flod 4.1/neoart/flod/sidmon/S2Voice.as new file mode 100644 index 0000000..388962a --- /dev/null +++ b/Flod 4.1/neoart/flod/sidmon/S2Voice.as @@ -0,0 +1,82 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.sidmon { + import neoart.flod.core.*; + + public final class S2Voice { + internal var + index : int, + next : S2Voice, + channel : AmigaChannel, + step : S2Step, + row : SMRow, + instr : S2Instrument, + sample : S2Sample, + enabled : int, + pattern : int, + instrument : int, + note : int, + period : int, + volume : int, + original : int, + adsrPos : int, + sustainCtr : int, + pitchBend : int, + pitchBendCtr : int, + noteSlideTo : int, + noteSlideSpeed : int, + waveCtr : int, + wavePos : int, + arpeggioCtr : int, + arpeggioPos : int, + vibratoCtr : int, + vibratoPos : int, + speed : int; + + public function S2Voice(index:int) { + this.index = index; + } + + internal function initialize():void { + step = null; + row = null; + instr = null; + sample = null; + enabled = 0; + pattern = 0; + instrument = 0; + note = 0; + period = 0; + volume = 0; + original = 0; + adsrPos = 0; + sustainCtr = 0; + pitchBend = 0; + pitchBendCtr = 0; + noteSlideTo = 0; + noteSlideSpeed = 0; + waveCtr = 0; + wavePos = 0; + arpeggioCtr = 0; + arpeggioPos = 0; + vibratoCtr = 0; + vibratoPos = 0; + speed = 0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/sidmon/SMRow.as b/Flod 4.1/neoart/flod/sidmon/SMRow.as new file mode 100644 index 0000000..a50d1c2 --- /dev/null +++ b/Flod 4.1/neoart/flod/sidmon/SMRow.as @@ -0,0 +1,25 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.sidmon { + import neoart.flod.core.*; + + public final class SMRow extends AmigaRow { + internal var + speed : int; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/soundfx/FXPlayer.as b/Flod 4.1/neoart/flod/soundfx/FXPlayer.as new file mode 100644 index 0000000..4879072 --- /dev/null +++ b/Flod 4.1/neoart/flod/soundfx/FXPlayer.as @@ -0,0 +1,441 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.1 - 2012/04/14 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.soundfx { + import flash.utils.*; + import neoart.flod.core.*; + + public final class FXPlayer extends AmigaPlayer { + private var + track : Vector., + patterns : Vector., + samples : Vector., + length : int, + voices : Vector., + trackPos : int, + patternPos : int, + jumpFlag : int, + delphine : int; + + public function FXPlayer(amiga:Amiga = null) { + super(amiga); + PERIODS.fixed = true; + + track = new Vector.(128, true); + voices = new Vector.(4, true); + + voices[0] = new FXVoice(0); + voices[0].next = voices[1] = new FXVoice(1); + voices[1].next = voices[2] = new FXVoice(2); + voices[2].next = voices[3] = new FXVoice(3); + } + + override public function set force(value:int):void { + if (value < SOUNDFX_10) + value = SOUNDFX_10; + else if (value > SOUNDFX_20) + value = SOUNDFX_20; + + version = value; + } + + override public function set ntsc(value:int):void { + super.ntsc = value; + + amiga.samplesTick = int((tempo / 122) * (value ? 7.5152005551 : 7.58437970472)); + } + + override public function process():void { + var chan:AmigaChannel, index:int, period:int, row:AmigaRow, sample:AmigaSample, value:int, voice:FXVoice = voices[0]; + + if (!tick) { + value = track[trackPos] + patternPos; + + while (voice) { + chan = voice.channel; + voice.enabled = 0; + + row = patterns[int(value + voice.index)]; + voice.period = row.note; + voice.effect = row.effect; + voice.param = row.param; + + if (row.note == -3) { + voice.effect = 0; + voice = voice.next; + continue; + } + + if (row.sample) { + sample = voice.sample = samples[row.sample]; + voice.volume = sample.volume; + + if (voice.effect == 5) + voice.volume += voice.param; + else if (voice.effect == 6) + voice.volume -= voice.param; + + chan.volume = voice.volume; + } else { + sample = voice.sample; + } + + if (voice.period) { + voice.last = voice.period; + voice.slideSpeed = 0; + voice.stepSpeed = 0; + + voice.enabled = 1; + chan.enabled = 0; + + switch (voice.period) { + case -2: + chan.volume = 0; + break; + case -4: + this.jumpFlag = 1; + break; + case -5: + break; + default: + chan.pointer = sample.pointer; + chan.length = sample.length; + + if (delphine) chan.period = voice.period << 1; + else chan.period = voice.period; + break; + } + + if (voice.enabled) chan.enabled = 1; + chan.pointer = sample.loopPtr; + chan.length = sample.repeat; + } + voice = voice.next; + } + } else { + while (voice) { + chan = voice.channel; + + if (version == SOUNDFX_18 && voice.period == -3) { + voice = voice.next; + continue; + } + + if (voice.stepSpeed) { + voice.stepPeriod += voice.stepSpeed; + + if (voice.stepSpeed < 0) { + if (voice.stepPeriod < voice.stepWanted) { + voice.stepPeriod = voice.stepWanted; + if (version > SOUNDFX_18) voice.stepSpeed = 0; + } + } else { + if (voice.stepPeriod > voice.stepWanted) { + voice.stepPeriod = voice.stepWanted; + if (version > SOUNDFX_18) voice.stepSpeed = 0; + } + } + + if (version > SOUNDFX_18) voice.last = voice.stepPeriod; + chan.period = voice.stepPeriod; + } else { + if (voice.slideSpeed) { + value = voice.slideParam & 0x0f; + + if (value) { + if (++voice.slideCtr == value) { + voice.slideCtr = 0; + value = (voice.slideParam << 4) << 3; + + if (!voice.slideDir) { + voice.slidePeriod += 8; + chan.period = voice.slidePeriod; + value += voice.slideSpeed; + if (value == voice.slidePeriod) voice.slideDir = 1; + } else { + voice.slidePeriod -= 8; + chan.period = voice.slidePeriod; + value -= voice.slideSpeed; + if (value == voice.slidePeriod) voice.slideDir = 0; + } + } else { + voice = voice.next; + continue; + } + } + } + + value = 0; + + switch (voice.effect) { + case 0: + break; + case 1: //arpeggio + value = tick % 3; + index = 0; + + if (value == 2) { + chan.period = voice.last; + voice = voice.next; + continue; + } + + if (value == 1) value = voice.param & 0x0f; + else value = voice.param >> 4; + + while (voice.last != PERIODS[index]) index++; + chan.period = PERIODS[int(index + value)]; + break; + case 2: //pitchbend + value = voice.param >> 4; + if (value) voice.period += value; + else voice.period -= voice.param & 0x0f; + chan.period = voice.period; + break; + case 3: //filter on + amiga.filter.active = 1; + break; + case 4: //filter off + amiga.filter.active = 0; + break; + case 8: //step down + value = -1; + case 7: //step up + voice.stepSpeed = voice.param & 0x0f; + voice.stepPeriod = version > SOUNDFX_18 ? voice.last : voice.period; + if (value < 0) voice.stepSpeed = -voice.stepSpeed; + index = 0; + + while (true) { + period = PERIODS[index]; + if (period == voice.stepPeriod) break; + if (period < 0) { + index = -1; + break; + } else + index++; + } + + if (index > -1) { + period = voice.param >> 4; + if (value > -1) period = -period; + index += period; + if (index < 0) index = 0; + voice.stepWanted = PERIODS[index]; + } else + voice.stepWanted = voice.period; + break; + case 9: //auto slide + voice.slideSpeed = voice.slidePeriod = voice.period; + voice.slideParam = voice.param; + voice.slideDir = 0; + voice.slideCtr = 0; + break; + } + } + voice = voice.next; + } + } + + if (++tick == speed) { + tick = 0; + patternPos += 4; + + if (patternPos == 256 || jumpFlag) { + patternPos = jumpFlag = 0; + + if (++trackPos == length) { + trackPos = 0; + amiga.complete = 1; + } + } + } + } + + override protected function initialize():void { + var voice:FXVoice = voices[0]; + super.initialize(); + ntsc = standard; + + speed = 6; + trackPos = 0; + patternPos = 0; + jumpFlag = 0; + + while (voice) { + voice.initialize(); + voice.channel = amiga.channels[voice.index]; + voice.sample = samples[0]; + voice = voice.next; + } + } + + override protected function loader(stream:ByteArray):void { + var higher:int, i:int, id:String, j:int, len:int, offset:int, row:AmigaRow, sample:AmigaSample, size:int, value:int; + if (stream.length < 1686) return; + + stream.position = 60; + id = stream.readMultiByte(4, ENCODING); + + if (id != "SONG") { + stream.position = 124; + id = stream.readMultiByte(4, ENCODING); + if (id != "SO31") return; + if (stream.length < 2350) return; + + offset = 544; + len = 32; + version = SOUNDFX_20; + } else { + offset = 0; + len = 16; + version = SOUNDFX_10; + } + + samples = new Vector.(len, true); + tempo = stream.readUnsignedShort(); + stream.position = 0; + + for (i = 1; i < len; ++i) { + value = stream.readUnsignedInt(); + + if (value) { + sample = new AmigaSample(); + sample.pointer = size; + size += value; + samples[i] = sample; + } else + samples[i] = null; + } + stream.position += 20; + + for (i = 1; i < len; ++i) { + sample = samples[i]; + if (sample == null) { + stream.position += 30; + continue; + } + + sample.name = stream.readMultiByte(22, ENCODING); + sample.length = stream.readUnsignedShort() << 1; + sample.volume = stream.readUnsignedShort(); + sample.loop = stream.readUnsignedShort(); + sample.repeat = stream.readUnsignedShort() << 1; + } + + stream.position = 530 + offset; + length = len = stream.readUnsignedByte(); + stream.position++; + + for (i = 0; i < len; ++i) { + value = stream.readUnsignedByte() << 8; + track[i] = value; + if (value > higher) higher = value; + } + + if (offset) offset += 4; + stream.position = 660 + offset; + higher += 256; + patterns = new Vector.(higher, true); + + len = samples.length; + + for (i = 0; i < higher; ++i) { + row = new AmigaRow(); + row.note = stream.readShort(); + value = stream.readUnsignedByte(); + row.param = stream.readUnsignedByte(); + row.effect = value & 0x0f; + row.sample = value >> 4; + + patterns[i] = row; + + if (version == SOUNDFX_20) { + if (row.note & 0x1000) { + row.sample += 16; + if (row.note > 0) row.note &= 0xefff; + } + } else { + if (row.effect == 9 || row.note > 856) + version = SOUNDFX_18; + + if (row.note < -3) + version = SOUNDFX_19; + } + if (row.sample >= len || samples[row.sample] == null) row.sample = 0; + } + + amiga.store(stream, size); + + for (i = 1; i < len; ++i) { + sample = samples[i]; + if (sample == null) continue; + + if (sample.loop) + sample.loopPtr = sample.pointer + sample.loop; + else { + sample.loopPtr = amiga.memory.length; + sample.repeat = 2; + } + size = sample.pointer + 4; + for (j = sample.pointer; j < size; ++j) amiga.memory[j] = 0; + } + + sample = new AmigaSample(); + sample.pointer = sample.loopPtr = amiga.memory.length; + sample.length = sample.repeat = 2; + samples[0] = sample; + + stream.position = higher = delphine = 0; + for (i = 0; i < 265; ++i) higher += stream.readUnsignedShort(); + + switch (higher) { + case 172662: + case 1391423: + case 1458300: + case 1706977: + case 1920077: + case 1920694: + case 1677853: + case 1931956: + case 1926836: + case 1385071: + case 1720635: + case 1714491: + case 1731874: + case 1437490: + delphine = 1; + break; + } + } + + public static const + SOUNDFX_10 = 1, + SOUNDFX_18 = 2, + SOUNDFX_19 = 3, + SOUNDFX_20 = 4; + + private const + PERIODS: Vector. = Vector.([ + 1076,1016,960,906,856,808,762,720,678,640,604,570, + 538, 508,480,453,428,404,381,360,339,320,302,285, + 269, 254,240,226,214,202,190,180,170,160,151,143, + 135, 127,120,113,113,113,113,113,113,113,113,113, + 113, 113,113,113,113,113,113,113,113,113,113,113, + 113, 113,113,113,113,113,-1]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/soundfx/FXVoice.as b/Flod 4.1/neoart/flod/soundfx/FXVoice.as new file mode 100644 index 0000000..cf8777e --- /dev/null +++ b/Flod 4.1/neoart/flod/soundfx/FXVoice.as @@ -0,0 +1,65 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.soundfx { + import neoart.flod.core.*; + + public final class FXVoice { + internal var + index : int, + next : FXVoice, + channel : AmigaChannel, + sample : AmigaSample, + enabled : int, + period : int, + effect : int, + param : int, + volume : int, + last : int, + slideCtr : int, + slideDir : int, + slideParam : int, + slidePeriod : int, + slideSpeed : int, + stepPeriod : int, + stepSpeed : int, + stepWanted : int; + + public function FXVoice(index:int) { + this.index = index; + } + + internal function initialize():void { + channel = null; + sample = null; + enabled = 0; + period = 0; + effect = 0; + param = 0; + volume = 0; + last = 0; + slideCtr = 0; + slideDir = 0; + slideParam = 0; + slidePeriod = 0; + slideSpeed = 0; + stepPeriod = 0; + stepSpeed = 0; + stepWanted = 0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/soundmon/BPPlayer.as b/Flod 4.1/neoart/flod/soundmon/BPPlayer.as new file mode 100644 index 0000000..7435679 --- /dev/null +++ b/Flod 4.1/neoart/flod/soundmon/BPPlayer.as @@ -0,0 +1,622 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/11 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.soundmon { + import flash.utils.*; + import neoart.flod.core.*; + + public final class BPPlayer extends AmigaPlayer { + private var + tracks : Vector., + patterns : Vector., + samples : Vector., + length : int, + buffer : Vector., + voices : Vector., + trackPos : int, + patternPos : int, + nextPos : int, + jumpFlag : int, + repeatCtr : int, + arpeggioCtr : int, + vibratoPos : int; + + public function BPPlayer(amiga:Amiga = null) { + super(amiga); + PERIODS.fixed = true; + VIBRATO.fixed = true; + + buffer = new Vector.(128, true); + samples = new Vector.(16, true); + voices = new Vector.(4, true); + + voices[0] = new BPVoice(0); + voices[0].next = voices[1] = new BPVoice(1); + voices[1].next = voices[2] = new BPVoice(2); + voices[2].next = voices[3] = new BPVoice(3); + } + + override public function process():void { + var chan:AmigaChannel, data:int, dst:int, instr:int, len:int, memory:Vector. = amiga.memory, note:int, option:int, row:AmigaRow, sample:BPSample, src:int, step:BPStep, voice:BPVoice = voices[0]; + arpeggioCtr = --arpeggioCtr & 3; + vibratoPos = ++vibratoPos & 7; + + while (voice) { + chan = voice.channel; + voice.period += voice.autoSlide; + + if (voice.vibrato) chan.period = voice.period + (VIBRATO[vibratoPos] / voice.vibrato); + else chan.period = voice.period; + + chan.pointer = voice.samplePtr; + chan.length = voice.sampleLen; + + if (voice.arpeggio || voice.autoArpeggio) { + note = voice.note; + + if (!arpeggioCtr) + note += ((voice.arpeggio & 0xf0) >> 4) + ((voice.autoArpeggio & 0xf0) >> 4); + else if (arpeggioCtr == 1) + note += (voice.arpeggio & 0x0f) + (voice.autoArpeggio & 0x0f); + + chan.period = voice.period = PERIODS[int(note + 35)]; + voice.restart = 0; + } + + if (!voice.synth || voice.sample < 0) { + voice = voice.next; + continue; + } + sample = samples[voice.sample]; + + if (voice.adsrControl) { + if (--voice.adsrCtr == 0) { + voice.adsrCtr = sample.adsrSpeed; + data = (128 + memory[int(sample.adsrTable + voice.adsrPtr)]) >> 2; + chan.volume = (data * voice.volume) >> 6; + + if (++voice.adsrPtr == sample.adsrLen) { + voice.adsrPtr = 0; + if (voice.adsrControl == 1) voice.adsrControl = 0; + } + } + } + + if (voice.lfoControl) { + if (--voice.lfoCtr == 0) { + voice.lfoCtr = sample.lfoSpeed; + data = memory[int(sample.lfoTable + voice.lfoPtr)]; + if (sample.lfoDepth) data = (data / sample.lfoDepth) >> 0; + chan.period = voice.period + data; + + if (++voice.lfoPtr == sample.lfoLen) { + voice.lfoPtr = 0; + if (voice.lfoControl == 1) voice.lfoControl = 0; + } + } + } + + if (voice.synthPtr < 0) { + voice = voice.next; + continue; + } + + if (voice.egControl) { + if (--voice.egCtr == 0) { + voice.egCtr = sample.egSpeed; + data = voice.egValue; + voice.egValue = (128 + memory[int(sample.egTable + voice.egPtr)]) >> 3; + + if (voice.egValue != data) { + src = (voice.index << 5) + data; + dst = voice.synthPtr + data; + + if (voice.egValue < data) { + data -= voice.egValue; + len = dst - data; + for (; dst > len;) memory[--dst] = buffer[--src]; + } else { + data = voice.egValue - data; + len = dst + data; + for (; dst < len;) memory[dst++] = ~buffer[src++] + 1 + } + } + + if (++voice.egPtr == sample.egLen) { + voice.egPtr = 0; + if (voice.egControl == 1) voice.egControl = 0; + } + } + } + + switch (voice.fxControl) { + case 0: + break; + case 1: //averaging + if (--voice.fxCtr == 0) { + voice.fxCtr = sample.fxSpeed; + dst = voice.synthPtr; + len = voice.synthPtr + 32; + data = dst > 0 ? memory[int(dst - 1)] : 0; + + for (; dst < len;) { + data = (data + memory[int(dst + 1)]) >> 1; + memory[dst++] = data; + } + } + break; + case 2: //inversion + src = (voice.index << 5) + 31; + len = voice.synthPtr + 32; + data = sample.fxSpeed; + + for (dst = voice.synthPtr; dst < len; ++dst) { + if (buffer[src] < memory[dst]) { + memory[dst] -= data; + } else if (buffer[src] > memory[dst]) { + memory[dst] += data; + } + src--; + } + break; + case 3: //backward inversion + case 5: //backward transform + src = voice.index << 5; + len = voice.synthPtr + 32; + data = sample.fxSpeed; + + for (dst = voice.synthPtr; dst < len; ++dst) { + if (buffer[src] < memory[dst]) { + memory[dst] -= data; + } else if (buffer[src] > memory[dst]) { + memory[dst] += data; + } + src++; + } + break; + case 4: //transform + src = voice.synthPtr + 64; + len = voice.synthPtr + 32; + data = sample.fxSpeed; + + for (dst = voice.synthPtr; dst < len; ++dst) { + if (memory[src] < memory[dst]) { + memory[dst] -= data; + } else if (memory[src] > memory[dst]) { + memory[dst] += data; + } + src++; + } + break; + case 6: //wave change + if (--voice.fxCtr == 0) { + voice.fxControl = 0; + voice.fxCtr = 1; + src = voice.synthPtr + 64; + len = voice.synthPtr + 32; + for (dst = voice.synthPtr; dst < len; ++dst) memory[dst] = memory[src++]; + } + break; + } + + if (voice.modControl) { + if (--voice.modCtr == 0) { + voice.modCtr = sample.modSpeed; + memory[voice.synthPtr + 32] = memory[int(sample.modTable + voice.modPtr)]; + + if (++voice.modPtr == sample.modLen) { + voice.modPtr = 0; + if (voice.modControl == 1) voice.modControl = 0; + } + } + } + voice = voice.next; + } + + if (--tick == 0) { + tick = speed; + voice = voices[0]; + + while (voice) { + chan = voice.channel; + voice.enabled = 0; + + step = tracks[int((trackPos << 2) + voice.index)]; + row = patterns[int(patternPos + ((step.pattern - 1) << 4))]; + note = row.note; + option = row.effect; + data = row.param; + + if (note) { + voice.autoArpeggio = voice.autoSlide = voice.vibrato = 0; + if (option != 10 || (data & 0xf0) == 0) note += step.transpose; + voice.note = note; + voice.period = PERIODS[int(note + 35)]; + + if (option < 13) voice.restart = voice.volumeDef = 1; + else voice.restart = 0; + + instr = row.sample; + if (instr == 0) instr = voice.sample; + if (option != 10 || (data & 0x0f) == 0) instr += step.soundTranspose; + + if (option < 13 && (!voice.synth || (voice.sample != instr))) { + voice.sample = instr; + voice.enabled = 1; + } + } + + switch (option) { + case 0: //arpeggio once + voice.arpeggio = data; + break; + case 1: //set volume + voice.volume = data; + voice.volumeDef = 0; + + if (version < BPSOUNDMON_V3 || !voice.synth) + chan.volume = voice.volume; + break; + case 2: //set speed + tick = speed = data; + break; + case 3: //set filter + amiga.filter.active = data; + break; + case 4: //portamento up + voice.period -= data; + voice.arpeggio = 0; + break; + case 5: //portamento down + voice.period += data; + voice.arpeggio = 0; + break; + case 6: //set vibrato + if (version == BPSOUNDMON_V3) voice.vibrato = data; + else repeatCtr = data; + break; + case 7: //step jump + if (version == BPSOUNDMON_V3) { + nextPos = data; + jumpFlag = 1; + } else if (repeatCtr == 0) { + trackPos = data; + } + break; + case 8: //set auto slide + voice.autoSlide = data; + break; + case 9: //set auto arpeggio + voice.autoArpeggio = data; + if (version == BPSOUNDMON_V3) { + voice.adsrPtr = 0; + if (voice.adsrControl == 0) voice.adsrControl = 1; + } + break; + case 11: //change effect + voice.fxControl = data; + break; + case 13: //change inversion + voice.autoArpeggio = data; + voice.fxControl ^= 1; + voice.adsrPtr = 0; + if (voice.adsrControl == 0) voice.adsrControl = 1; + break; + case 14: //no eg reset + voice.autoArpeggio = data; + voice.adsrPtr = 0; + if (voice.adsrControl == 0) voice.adsrControl = 1; + break; + case 15: //no eg and no adsr reset + voice.autoArpeggio = data; + break; + } + voice = voice.next; + } + + if (jumpFlag) { + trackPos = nextPos; + patternPos = jumpFlag = 0; + } else if (++patternPos == 16) { + patternPos = 0; + + if (++trackPos == length) { + trackPos = 0; + amiga.complete = 1; + } + } + voice = voices[0]; + + while (voice) { + chan = voice.channel; + if (voice.enabled) chan.enabled = voice.enabled = 0; + if (voice.restart == 0) { + voice = voice.next; + continue; + } + + if (voice.synthPtr > -1) { + src = voice.index << 5; + len = voice.synthPtr + 32; + for (dst = voice.synthPtr; dst < len; ++dst) memory[dst] = buffer[src++]; + voice.synthPtr = -1; + } + voice = voice.next; + } + voice = voices[0]; + + while (voice) { + if (voice.restart == 0 || voice.sample < 0) { + voice = voice.next; + continue; + } + chan = voice.channel; + + chan.period = voice.period; + voice.restart = 0; + sample = samples[voice.sample]; + + if (sample.synth) { + voice.synth = 1; + voice.egValue = 0; + voice.adsrPtr = voice.lfoPtr = voice.egPtr = voice.modPtr = 0; + + voice.adsrCtr = 1; + voice.lfoCtr = sample.lfoDelay + 1; + voice.egCtr = sample.egDelay + 1; + voice.fxCtr = sample.fxDelay + 1; + voice.modCtr = sample.modDelay + 1; + + voice.adsrControl = sample.adsrControl; + voice.lfoControl = sample.lfoControl; + voice.egControl = sample.egControl; + voice.fxControl = sample.fxControl; + voice.modControl = sample.modControl; + + chan.pointer = voice.samplePtr = sample.pointer; + chan.length = voice.sampleLen = sample.length; + + if (voice.adsrControl) { + data = (128 + memory[sample.adsrTable]) >> 2; + + if (voice.volumeDef) { + voice.volume = sample.volume; + voice.volumeDef = 0; + } + + chan.volume = (data * voice.volume) >> 6; + } else { + chan.volume = voice.volumeDef ? sample.volume : voice.volume; + } + + if (voice.egControl || voice.fxControl || voice.modControl) { + voice.synthPtr = sample.pointer; + dst = voice.index << 5; + len = voice.synthPtr + 32; + for (src = voice.synthPtr; src < len; ++src) buffer[dst++] = memory[src]; + } + } else { + voice.synth = voice.lfoControl = 0; + + if (sample.pointer < 0) { + voice.samplePtr = amiga.loopPtr; + voice.sampleLen = 2; + } else { + chan.pointer = sample.pointer; + chan.volume = voice.volumeDef ? sample.volume : voice.volume; + + if (sample.repeat != 2) { + voice.samplePtr = sample.loopPtr; + chan.length = voice.sampleLen = sample.repeat; + } else { + voice.samplePtr = amiga.loopPtr; + voice.sampleLen = 2; + chan.length = sample.length; + } + } + } + chan.enabled = voice.enabled = 1; + voice = voice.next; + } + } + } + + override protected function initialize():void { + var i:int, voice:BPVoice = voices[0]; + super.initialize(); + + speed = 6; + tick = 1; + trackPos = 0; + patternPos = 0; + nextPos = 0; + jumpFlag = 0; + repeatCtr = 0; + arpeggioCtr = 1; + vibratoPos = 0; + + for (i = 0; i < 128; ++i) buffer[i] = 0; + + while (voice) { + voice.initialize(); + voice.channel = amiga.channels[voice.index]; + voice.samplePtr = amiga.loopPtr; + voice = voice.next; + } + } + + override protected function reset():void { + var i:int, len:int, pos:int, voice:BPVoice = voices[0]; + + while (voice) { + if (voice.synthPtr > -1) { + pos = voice.index << 5; + len = voice.synthPtr + 32; + + for (i = voice.synthPtr; i < len; ++i) + amiga.memory[i] = buffer[pos++]; + } + + voice = voice.next; + } + } + + override protected function loader(stream:ByteArray):void { + var higher:int, i:int = 0, id:String, len:int, row:AmigaRow, sample:BPSample, step:BPStep, tables:int; + title = stream.readMultiByte(26, ENCODING); + + id = stream.readMultiByte(4, ENCODING); + if (id == "BPSM") { + version = BPSOUNDMON_V1; + } else { + id = id.substr(0, 3); + if (id == "V.2") version = BPSOUNDMON_V2; + else if (id == "V.3") version = BPSOUNDMON_V3; + else return; + + stream.position = 29; + tables = stream.readUnsignedByte(); + } + + length = stream.readUnsignedShort(); + + for (; ++i < 16;) { + sample = new BPSample(); + + if (stream.readUnsignedByte() == 0xff) { + sample.synth = 1; + sample.table = stream.readUnsignedByte(); + sample.pointer = sample.table << 6; + sample.length = stream.readUnsignedShort() << 1; + + sample.adsrControl = stream.readUnsignedByte(); + sample.adsrTable = stream.readUnsignedByte() << 6; + sample.adsrLen = stream.readUnsignedShort(); + sample.adsrSpeed = stream.readUnsignedByte(); + sample.lfoControl = stream.readUnsignedByte(); + sample.lfoTable = stream.readUnsignedByte() << 6; + sample.lfoDepth = stream.readUnsignedByte(); + sample.lfoLen = stream.readUnsignedShort(); + + if (version < BPSOUNDMON_V3) { + stream.readByte(); + sample.lfoDelay = stream.readUnsignedByte(); + sample.lfoSpeed = stream.readUnsignedByte(); + sample.egControl = stream.readUnsignedByte(); + sample.egTable = stream.readUnsignedByte() << 6; + stream.readByte(); + sample.egLen = stream.readUnsignedShort(); + stream.readByte(); + sample.egDelay = stream.readUnsignedByte(); + sample.egSpeed = stream.readUnsignedByte(); + sample.fxSpeed = 1; + sample.modSpeed = 1; + sample.volume = stream.readUnsignedByte(); + stream.position += 6; + } else { + sample.lfoDelay = stream.readUnsignedByte(); + sample.lfoSpeed = stream.readUnsignedByte(); + sample.egControl = stream.readUnsignedByte(); + sample.egTable = stream.readUnsignedByte() << 6; + sample.egLen = stream.readUnsignedShort(); + sample.egDelay = stream.readUnsignedByte(); + sample.egSpeed = stream.readUnsignedByte(); + sample.fxControl = stream.readUnsignedByte(); + sample.fxSpeed = stream.readUnsignedByte(); + sample.fxDelay = stream.readUnsignedByte(); + sample.modControl = stream.readUnsignedByte(); + sample.modTable = stream.readUnsignedByte() << 6; + sample.modSpeed = stream.readUnsignedByte(); + sample.modDelay = stream.readUnsignedByte(); + sample.volume = stream.readUnsignedByte(); + sample.modLen = stream.readUnsignedShort(); + } + } else { + stream.position--; + sample.synth = 0; + sample.name = stream.readMultiByte(24, ENCODING); + sample.length = stream.readUnsignedShort() << 1; + + if (sample.length) { + sample.loop = stream.readUnsignedShort(); + sample.repeat = stream.readUnsignedShort() << 1; + sample.volume = stream.readUnsignedShort(); + + if ((sample.loop + sample.repeat) >= sample.length) + sample.repeat = sample.length - sample.loop; + } else { + sample.pointer--; + sample.repeat = 2; + stream.position += 6; + } + } + samples[i] = sample; + } + + len = length << 2; + tracks = new Vector.(len, true); + + for (i = 0; i < len; ++i) { + step = new BPStep(); + step.pattern = stream.readUnsignedShort(); + step.soundTranspose = stream.readByte(); + step.transpose = stream.readByte(); + if (step.pattern > higher) higher = step.pattern; + tracks[i] = step; + } + + len = higher << 4; + patterns = new Vector.(len, true); + + for (i = 0; i < len; ++i) { + row = new AmigaRow(); + row.note = stream.readByte(); + row.sample = stream.readUnsignedByte(); + row.effect = row.sample & 0x0f; + row.sample = (row.sample & 0xf0) >> 4; + row.param = stream.readByte(); + patterns[i] = row; + } + + amiga.store(stream, tables << 6); + + for (i = 0; ++i < 16;) { + sample = samples[i]; + if (sample.synth || !sample.length) continue; + sample.pointer = amiga.store(stream, sample.length); + sample.loopPtr = sample.pointer + sample.loop; + } + } + + public static const + BPSOUNDMON_V1 = 1, + BPSOUNDMON_V2 = 2, + BPSOUNDMON_V3 = 3; + + private const + PERIODS: Vector. = Vector.([ + 6848,6464,6080,5760,5440,5120,4832,4576,4320,4064,3840,3616, + 3424,3232,3040,2880,2720,2560,2416,2288,2160,2032,1920,1808, + 1712,1616,1520,1440,1360,1280,1208,1144,1080,1016, 960, 904, + 856, 808, 760, 720, 680, 640, 604, 572, 540, 508, 480, 452, + 428, 404, 380, 360, 340, 320, 302, 286, 270, 254, 240, 226, + 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113, + 107, 101, 95, 90, 85, 80, 76, 72, 68, 64, 60, 57]), + + VIBRATO: Vector. = Vector.([0,64,128,64,0,-64,-128,-64]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/soundmon/BPSample.as b/Flod 4.1/neoart/flod/soundmon/BPSample.as new file mode 100644 index 0000000..b32b32e --- /dev/null +++ b/Flod 4.1/neoart/flod/soundmon/BPSample.as @@ -0,0 +1,49 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.soundmon { + import neoart.flod.core.*; + + public final class BPSample extends AmigaSample { + internal var + synth : int, + table : int, + adsrControl : int, + adsrTable : int, + adsrLen : int, + adsrSpeed : int, + lfoControl : int, + lfoTable : int, + lfoDepth : int, + lfoLen : int, + lfoDelay : int, + lfoSpeed : int, + egControl : int, + egTable : int, + egLen : int, + egDelay : int, + egSpeed : int, + fxControl : int, + fxDelay : int, + fxSpeed : int, + modControl : int, + modTable : int, + modLen : int, + modDelay : int, + modSpeed : int; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/soundmon/BPStep.as b/Flod 4.1/neoart/flod/soundmon/BPStep.as new file mode 100644 index 0000000..bf19282 --- /dev/null +++ b/Flod 4.1/neoart/flod/soundmon/BPStep.as @@ -0,0 +1,25 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.soundmon { + import neoart.flod.core.*; + + public final class BPStep extends AmigaStep { + internal var + soundTranspose : int; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/soundmon/BPVoice.as b/Flod 4.1/neoart/flod/soundmon/BPVoice.as new file mode 100644 index 0000000..212c89a --- /dev/null +++ b/Flod 4.1/neoart/flod/soundmon/BPVoice.as @@ -0,0 +1,95 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.soundmon { + import neoart.flod.core.*; + + public final class BPVoice { + internal var + index : int, + next : BPVoice, + channel : AmigaChannel, + enabled : int, + restart : int, + note : int, + period : int, + sample : int, + samplePtr : int, + sampleLen : int, + synth : int, + synthPtr : int, + arpeggio : int, + autoArpeggio : int, + autoSlide : int, + vibrato : int, + volume : int, + volumeDef : int, + adsrControl : int, + adsrPtr : int, + adsrCtr : int, + lfoControl : int, + lfoPtr : int, + lfoCtr : int, + egControl : int, + egPtr : int, + egCtr : int, + egValue : int, + fxControl : int, + fxCtr : int, + modControl : int, + modPtr : int, + modCtr : int; + + public function BPVoice(index:int) { + this.index = index; + } + + internal function initialize():void { + channel = null, + enabled = 0; + restart = 0; + note = 0; + period = 0; + sample = 0; + samplePtr = 0; + sampleLen = 2; + synth = 0; + synthPtr = -1; + arpeggio = 0; + autoArpeggio = 0; + autoSlide = 0; + vibrato = 0; + volume = 0; + volumeDef = 0; + adsrControl = 0; + adsrPtr = 0; + adsrCtr = 0; + lfoControl = 0; + lfoPtr = 0; + lfoCtr = 0; + egControl = 0; + egPtr = 0; + egCtr = 0; + egValue = 0; + fxControl = 0; + fxCtr = 0; + modControl = 0; + modPtr = 0; + modCtr = 0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/trackers/HMPlayer.as b/Flod 4.1/neoart/flod/trackers/HMPlayer.as new file mode 100644 index 0000000..67dd91e --- /dev/null +++ b/Flod 4.1/neoart/flod/trackers/HMPlayer.as @@ -0,0 +1,471 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.1 - 2012/04/17 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.trackers { + import flash.utils.*; + import neoart.flod.core.*; + + public final class HMPlayer extends AmigaPlayer { + private var + track : Vector., + patterns : Vector., + samples : Vector., + length : int, + restart : int, + voices : Vector., + trackPos : int, + patternPos : int, + jumpFlag : int; + + public function HMPlayer(amiga:Amiga = null) { + super(amiga); + MEGARPEGGIO.fixed = true; + PERIODS.fixed = true; + VIBRATO.fixed = true; + + track = new Vector.(128, true); + samples = new Vector.(32, true); + voices = new Vector.(4, true); + + voices[0] = new HMVoice(0); + voices[0].next = voices[1] = new HMVoice(1); + voices[1].next = voices[2] = new HMVoice(2); + voices[2].next = voices[3] = new HMVoice(3); + } + + override public function process():void { + var chan:AmigaChannel, pattern:int, row:AmigaRow, sample:HMSample, value:int, voice:HMVoice = voices[0]; + + if (!this.tick) { + pattern = track[trackPos] + patternPos; + + while (voice) { + chan = voice.channel; + voice.enabled = 0; + + row = patterns[int(pattern + voice.index)]; + voice.effect = row.effect; + voice.param = row.param; + + if (row.sample) { + sample = voice.sample = samples[row.sample]; + voice.volume2 = sample.volume; + + if (sample.name == "Mupp") { + sample.loopPtr = sample.pointer + sample.waves[0]; + voice.handler = 1; + voice.volume1 = sample.volumes[0]; + } else { + voice.handler = 0; + voice.volume1 = 64; + } + } else { + sample = voice.sample; + } + + if (row.note) { + if (voice.effect == 3 || voice.effect == 5) { + if (row.note < voice.period) { + voice.portaDir = 1; + voice.portaPeriod = row.note; + } else if (row.note > voice.period) { + voice.portaDir = 0; + voice.portaPeriod = row.note; + } else { + voice.portaPeriod = 0; + } + } else { + voice.period = row.note; + voice.vibratoPos = 0; + voice.wavePos = 0; + voice.enabled = 1; + + chan.enabled = 0; + value = (voice.period * sample.finetune) >> 8; + chan.period = voice.period + value; + + if (voice.handler) { + chan.pointer = sample.loopPtr; + chan.length = sample.repeat; + } else { + chan.pointer = sample.pointer; + chan.length = sample.length; + } + } + } + + switch (voice.effect) { + case 11: //position jump + trackPos = voice.param - 1; + jumpFlag = 1; + break; + case 12: //set volume + voice.volume2 = voice.param; + if (voice.volume2 > 64) voice.volume2 = 64; + break; + case 13: //pattern break + jumpFlag = 1; + break; + case 14: //set filter + amiga.filter.active = voice.param ^ 1; + break; + case 15: //set speed + value = voice.param; + + if (value < 1) value = 1; + else if (value > 31) value = 31; + + speed = value; + tick = 0; + break; + } + + if (!row.note) effects(voice); + handler(voice); + + if (voice.enabled) chan.enabled = 1; + chan.pointer = sample.loopPtr; + chan.length = sample.repeat; + + voice = voice.next; + } + } else { + while (voice) { + effects(voice); + handler(voice); + + sample = voice.sample; + voice.channel.pointer = sample.loopPtr; + voice.channel.length = sample.repeat; + + voice = voice.next; + } + } + + if (++tick == speed) { + tick = 0; + patternPos += 4; + + if (patternPos == 256 || jumpFlag) { + patternPos = jumpFlag = 0; + trackPos = (++trackPos & 127); + + if (trackPos == length) { + trackPos = restart; + amiga.complete = 1; + } + } + } + } + + override protected function initialize():void { + var voice:HMVoice = voices[0]; + super.initialize(); + + speed = 6; + trackPos = 0; + patternPos = 0; + jumpFlag = 0; + + amiga.samplesTick = 884; + + while (voice) { + voice.initialize(); + voice.channel = amiga.channels[voice.index]; + voice.sample = samples[0]; + voice = voice.next; + } + } + + override protected function loader(stream:ByteArray):void { + var count:int, higher:int, i:int, id:String, j:int, mupp:int, position:int, row:AmigaRow, sample:HMSample, size:int, value:int; + if (stream.length < 2106) return; + + stream.position = 1080; + id = stream.readMultiByte(4, ENCODING); + if (id != "FEST") return; + + stream.position = 950; + length = stream.readUnsignedByte(); + restart = stream.readUnsignedByte(); + + for (i = 0; i < 128; ++i) + track[i] = stream.readUnsignedByte(); + + stream.position = 0; + title = stream.readMultiByte(20, ENCODING); + version = 1; + + for (i = 1; i < 32; ++i) { + samples[i] = null; + id = stream.readMultiByte(4, ENCODING); + + if (id == "Mupp") { + value = stream.readUnsignedByte(); + count = value - higher++; + for (j = 0; j < 128; ++j) + if (track[j] && track[j] >= count) track[j]--; + + sample = new HMSample(); + sample.name = id; + sample.length = sample.repeat = 32; + sample.restart = stream.readUnsignedByte(); + sample.waveLen = stream.readUnsignedByte(); + stream.position += 17; + sample.finetune = stream.readByte(); + sample.volume = stream.readUnsignedByte(); + + position = stream.position + 4; + value = 1084 + (value << 10); + stream.position = value; + + sample.pointer = amiga.memory.length; + sample.waves = new Vector.(64, true); + sample.volumes = new Vector.(64, true); + amiga.store(stream, 896); + + for (j = 0; j < 64; ++j) + sample.waves[j] = stream.readUnsignedByte() << 5; + for (j = 0; j < 64; ++j) + sample.volumes[j] = stream.readUnsignedByte() & 127; + + stream.position = value; + stream.writeInt(0x666c6f64); + stream.position = position; + mupp += 896; + } else { + id = id.substr(0, 2); + if (id == "El") + stream.position += 18; + else { + stream.position -= 4; + id = stream.readMultiByte(22, ENCODING); + } + + value = stream.readUnsignedShort(); + if (!value) { + stream.position += 6; + continue; + } + + sample = new HMSample(); + sample.name = id; + sample.pointer = size; + sample.length = value << 1; + sample.finetune = stream.readByte(); + sample.volume = stream.readUnsignedByte(); + sample.loop = stream.readUnsignedShort() << 1; + sample.repeat = stream.readUnsignedShort() << 1; + size += sample.length; + } + samples[i] = sample; + } + + for (i = 0; i < 128; ++i) { + value = track[i] << 8; + track[i] = value; + if (value > higher) higher = value; + } + + stream.position = 1084; + higher += 256; + patterns = new Vector.(higher, true); + + for (i = 0; i < higher; ++i) { + value = stream.readUnsignedInt(); + while (value == 0x666c6f64) { + stream.position += 1020; + value = stream.readUnsignedInt(); + } + + row = new AmigaRow(); + row.note = (value >> 16) & 0x0fff; + row.sample = (value >> 24) & 0xf0 | (value >> 12) & 0x0f; + row.effect = (value >> 8) & 0x0f; + row.param = value & 0xff; + + if (row.sample > 31 || !samples[row.sample]) row.sample = 0; + + patterns[i] = row; + } + + amiga.store(stream, size); + + for (i = 1; i < 32; ++i) { + sample = samples[i]; + if (!sample || sample.name == "Mupp") continue; + sample.pointer += mupp; + + if (sample.loop) { + sample.loopPtr = sample.pointer + sample.loop; + sample.length = sample.loop + sample.repeat; + } else { + sample.loopPtr = amiga.memory.length; + sample.repeat = 2; + } + size = sample.pointer + 4; + for (j = sample.pointer; j < size; ++j) amiga.memory[j] = 0; + } + + sample = new HMSample(); + sample.pointer = sample.loopPtr = amiga.memory.length; + sample.length = sample.repeat = 2; + samples[0] = sample; + } + + private function effects(voice:HMVoice):void { + var chan:AmigaChannel = voice.channel, i:int, len:int, period:int = voice.period & 0x0fff, slide:int, value:int; + + if (voice.effect || voice.param) { + switch (voice.effect) { + case 0: //arpeggio + value = tick % 3; + if (!value) break; + if (value == 1) value = voice.param >> 4; + else value = voice.param & 0x0f; + + len = 37 - value; + + for (i = 0; i < len; ++i) { + if (period >= PERIODS[i]) { + period = PERIODS[int(i + value)]; + break; + } + } + break; + case 1: //portamento up + voice.period -= voice.param; + if (voice.period < 113) voice.period = 113; + period = voice.period; + break; + case 2: //portamento down + voice.period += voice.param; + if (voice.period > 856) voice.period = 856; + period = voice.period; + break; + case 3: //tone portamento + case 5: //tone portamento + volume slide + if (voice.effect == 5) slide = 1; + else if (voice.param) { + voice.portaSpeed = voice.param; + voice.param = 0; + } + + if (voice.portaPeriod) { + if (voice.portaDir) { + voice.period -= voice.portaSpeed; + if (voice.period < voice.portaPeriod) { + voice.period = voice.portaPeriod; + voice.portaPeriod = 0; + } + } else { + voice.period += voice.portaSpeed; + if (voice.period > voice.portaPeriod) { + voice.period = voice.portaPeriod; + voice.portaPeriod = 0; + } + } + } + period = voice.period; + break; + case 4: //vibrato + case 6: //vibrato + volume slide; + if (voice.effect == 6) slide = 1; + else if (voice.param) voice.vibratoSpeed = voice.param; + + value = VIBRATO[int((voice.vibratoPos >> 2) & 31)]; + value = ((voice.vibratoSpeed & 0x0f) * value) >> 7; + + if (voice.vibratoPos > 127) period -= value; + else period += value; + + value = (voice.vibratoSpeed >> 2) & 60; + voice.vibratoPos = (voice.vibratoPos + value) & 255; + break; + case 7: //mega arpeggio + value = MEGARPEGGIO[int((voice.vibratoPos & 0x0f) + ((voice.param & 0x0f) << 4))]; + voice.vibratoPos++; + for (i = 0; i < 37; ++i) if (period >= PERIODS[i]) break; + + value += i; + if (value > 35) value -= 12; + period = PERIODS[value]; + break; + case 10: //volume slide + slide = 1; + break; + } + } + + chan.period = period + ((period * voice.sample.finetune) >> 8); + + if (slide) { + value = voice.param >> 4; + + if (value) voice.volume2 += value; + else voice.volume2 -= voice.param & 0x0f; + + if (voice.volume2 > 64) voice.volume2 = 64; + else if (voice.volume2 < 0) voice.volume2 = 0; + } + } + + private function handler(voice:HMVoice):void { + var sample:HMSample; + + if (voice.handler) { + sample = voice.sample; + sample.loopPtr = sample.pointer + sample.waves[voice.wavePos]; + + voice.volume1 = sample.volumes[voice.wavePos]; + + if (++voice.wavePos > sample.waveLen) + voice.wavePos = sample.restart; + } + voice.channel.volume = (voice.volume1 * voice.volume2) >> 6; + } + + private const + MEGARPEGGIO: Vector. = Vector.([ + 0, 3, 7,12,15,12, 7, 3, 0, 3, 7,12,15,12, 7, 3, + 0, 4, 7,12,16,12, 7, 4, 0, 4, 7,12,16,12, 7, 4, + 0, 3, 8,12,15,12, 8, 3, 0, 3, 8,12,15,12, 8, 3, + 0, 4, 8,12,16,12, 8, 4, 0, 4, 8,12,16,12, 8, 4, + 0, 5, 8,12,17,12, 8, 5, 0, 5, 8,12,17,12, 8, 5, + 0, 5, 9,12,17,12, 9, 5, 0, 5, 9,12,17,12, 9, 5, + 12, 0, 7, 0, 3, 0, 7, 0,12, 0, 7, 0, 3, 0, 7, 0, + 12, 0, 7, 0, 4, 0, 7, 0,12, 0, 7, 0, 4, 0, 7, 0, + 0, 3, 7, 3, 7,12, 7,12,15,12, 7,12, 7, 3, 7, 3, + 0, 4, 7, 4, 7,12, 7,12,16,12, 7,12, 7, 4, 7, 4, + 31,27,24,19,15,12, 7, 3, 0, 3, 7,12,15,19,24,27, + 31,28,24,19,16,12, 7, 4, 0, 4, 7,12,16,19,24,28, + 0,12, 0,12, 0,12, 0,12, 0,12, 0,12, 0,12, 0,12, + 0,12,24,12, 0,12,24,12, 0,12,24,12, 0,12,24,12, + 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, + 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4]), + + PERIODS: Vector. = Vector.([ + 856,808,762,720,678,640,604,570,538,508,480,453, + 428,404,381,360,339,320,302,285,269,254,240,226, + 214,202,190,180,170,160,151,143,135,127,120,113,0]), + + VIBRATO: Vector. = Vector.([ + 0, 24, 49, 74, 97,120,141,161,180,197,212,224, + 235,244,250,253,255,253,250,244,235,224,212,197, + 180,161,141,120, 97, 74, 49, 24]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/trackers/HMSample.as b/Flod 4.1/neoart/flod/trackers/HMSample.as new file mode 100644 index 0000000..e5cc8ab --- /dev/null +++ b/Flod 4.1/neoart/flod/trackers/HMSample.as @@ -0,0 +1,29 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.trackers { + import neoart.flod.core.*; + + public final class HMSample extends AmigaSample { + internal var + finetune : int, + restart : int, + waveLen : int, + waves : Vector., + volumes : Vector.; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/trackers/HMVoice.as b/Flod 4.1/neoart/flod/trackers/HMVoice.as new file mode 100644 index 0000000..96bbe1e --- /dev/null +++ b/Flod 4.1/neoart/flod/trackers/HMVoice.as @@ -0,0 +1,63 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.trackers { + import neoart.flod.core.*; + + public final class HMVoice { + internal var + index : int, + next : HMVoice, + channel : AmigaChannel, + sample : HMSample, + enabled : int, + period : int, + effect : int, + param : int, + volume1 : int, + volume2 : int, + handler : int, + portaDir : int, + portaPeriod : int, + portaSpeed : int, + vibratoPos : int, + vibratoSpeed : int, + wavePos : int; + + public function HMVoice(index:int) { + this.index = index; + } + + internal function initialize():void { + channel = null; + sample = null; + enabled = 0; + period = 0; + effect = 0; + param = 0; + volume1 = 0; + volume2 = 0; + handler = 0; + portaDir = 0; + portaPeriod = 0; + portaSpeed = 0; + vibratoPos = 0; + vibratoSpeed = 0; + wavePos = 0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/trackers/MKPlayer.as b/Flod 4.1/neoart/flod/trackers/MKPlayer.as new file mode 100644 index 0000000..09595a7 --- /dev/null +++ b/Flod 4.1/neoart/flod/trackers/MKPlayer.as @@ -0,0 +1,420 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.1 - 2012/04/16 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.trackers { + import flash.utils.*; + import neoart.flod.core.*; + + public final class MKPlayer extends AmigaPlayer { + private var + track : Vector., + patterns : Vector., + samples : Vector., + length : int, + restart : int, + voices : Vector., + trackPos : int, + patternPos : int, + jumpFlag : int, + vibratoDepth : int, + restartSave : int; + + public function MKPlayer(amiga:Amiga = null) { + super(amiga); + PERIODS.fixed = true; + VIBRATO.fixed = true; + + track = new Vector.(128, true); + samples = new Vector.(32, true); + voices = new Vector.(4, true); + + voices[0] = new MKVoice(0); + voices[0].next = voices[1] = new MKVoice(1); + voices[1].next = voices[2] = new MKVoice(2); + voices[2].next = voices[3] = new MKVoice(3); + } + + override public function set force(value:int):void { + if (value < SOUNDTRACKER_23) + value = SOUNDTRACKER_23; + else if (value > NOISETRACKER_20) + value = NOISETRACKER_20; + + version = value; + + if (value == NOISETRACKER_20) vibratoDepth = 6; + else vibratoDepth = 7; + + if (value == NOISETRACKER_10) { + restartSave = restart; + restart = 0; + } else { + restart = restartSave; + restartSave = 0; + } + } + + override public function process():void { + var chan:AmigaChannel, i:int, len:int, pattern:int, period:int, row:AmigaRow, sample:AmigaSample, slide:int, value:int, voice:MKVoice = voices[0]; + + if (!tick) { + pattern = track[trackPos] + patternPos; + + while (voice) { + chan = voice.channel; + voice.enabled = 0; + + row = patterns[int(pattern + voice.index)]; + voice.effect = row.effect; + voice.param = row.param; + + if (row.sample) { + sample = voice.sample = samples[row.sample]; + chan.volume = voice.volume = sample.volume; + } else { + sample = voice.sample; + } + + if (row.note) { + if (voice.effect == 3 || voice.effect == 5) { + if (row.note < voice.period) { + voice.portaDir = 1; + voice.portaPeriod = row.note; + } else if (row.note > voice.period) { + voice.portaDir = 0; + voice.portaPeriod = row.note; + } else { + voice.portaPeriod = 0; + } + } else { + voice.enabled = 1; + voice.vibratoPos = 0; + + chan.enabled = 0; + chan.pointer = sample.pointer; + chan.length = sample.length; + chan.period = voice.period = row.note; + } + } + + switch (voice.effect) { + case 11: //position jump + trackPos = voice.param - 1; + jumpFlag ^= 1; + break; + case 12: //set volume + chan.volume = voice.param; + + if (version == NOISETRACKER_20) + voice.volume = voice.param; + break; + case 13: //pattern break + jumpFlag ^= 1; + break; + case 14: //set filter + amiga.filter.active = voice.param ^ 1; + break; + case 15: //set speed + value = voice.param; + + if (value < 1) value = 1; + else if (value > 31) value = 31; + + speed = value; + tick = 0; + break; + } + + if (voice.enabled) chan.enabled = 1; + chan.pointer = sample.loopPtr; + chan.length = sample.repeat; + + voice = voice.next; + } + } else { + while (voice) { + chan = voice.channel; + + if (!voice.effect && !voice.param) { + chan.period = voice.period; + voice = voice.next; + continue; + } + + switch (voice.effect) { + case 0: //arpeggio + value = tick % 3; + + if (!value) { + chan.period = voice.period; + voice = voice.next; + continue; + } + + if (value == 1) value = voice.param >> 4; + else value = voice.param & 0x0f; + + period = voice.period & 0x0fff; + len = 37 - value; + + for (i = 0; i < len; ++i) { + if (period >= PERIODS[i]) { + chan.period = PERIODS[int(i + value)]; + break; + } + } + break; + case 1: //portamento up + voice.period -= voice.param; + if (voice.period < 113) voice.period = 113; + chan.period = voice.period; + break; + case 2: //portamento down + voice.period += voice.param; + if (voice.period > 856) voice.period = 856; + chan.period = voice.period; + break; + case 3: //tone portamento + case 5: //tone portamento + volume slide + if (voice.effect == 5) { + slide = 1; + } else if (voice.param) { + voice.portaSpeed = voice.param; + voice.param = 0; + } + + if (voice.portaPeriod) { + if (voice.portaDir) { + voice.period -= voice.portaSpeed; + + if (voice.period <= voice.portaPeriod) { + voice.period = voice.portaPeriod; + voice.portaPeriod = 0; + } + } else { + voice.period += voice.portaSpeed; + + if (voice.period >= voice.portaPeriod) { + voice.period = voice.portaPeriod; + voice.portaPeriod = 0; + } + } + } + chan.period = voice.period; + break; + case 4: //vibrato + case 6: //vibrato + volume slide + if (voice.effect == 6) { + slide = 1 + } else if (voice.param) { + voice.vibratoSpeed = voice.param; + } + + value = (voice.vibratoPos >> 2) & 31; + value = ((voice.vibratoSpeed & 0x0f) * VIBRATO[value]) >> vibratoDepth; + + if (voice.vibratoPos > 127) chan.period = voice.period - value; + else chan.period = voice.period + value; + + value = (voice.vibratoSpeed >> 2) & 60; + voice.vibratoPos = (voice.vibratoPos + value) & 255; + break; + case 10: //volume slide + slide = 1; + break; + } + + if (slide) { + value = voice.param >> 4; + slide = 0; + + if (value) voice.volume += value; + else voice.volume -= voice.param & 0x0f; + + if (voice.volume < 0) voice.volume = 0; + else if (voice.volume > 64) voice.volume = 64; + + chan.volume = voice.volume; + } + voice = voice.next; + } + } + + if (++tick == speed) { + tick = 0; + patternPos += 4; + + if (patternPos == 256 || jumpFlag) { + patternPos = jumpFlag = 0; + trackPos = (++trackPos & 127); + + if (trackPos == length) { + trackPos = restart; + amiga.complete = 1; + } + } + } + } + + override protected function initialize():void { + var voice:MKVoice = voices[0]; + super.initialize(); + force = version; + + speed = 6; + trackPos = 0; + patternPos = 0; + jumpFlag = 0; + + while (voice) { + voice.initialize(); + voice.channel = amiga.channels[voice.index]; + voice.sample = samples[0]; + voice = voice.next; + } + } + + override protected function loader(stream:ByteArray):void { + var higher:int, i:int, id:String, j:int, row:AmigaRow, sample:AmigaSample, size:int, value:int; + if (stream.length < 2106) return; + + stream.position = 1080; + id = stream.readMultiByte(4, ENCODING); + if (id != "M.K." && id != "FLT4") return; + + stream.position = 0; + title = stream.readMultiByte(20, ENCODING); + version = SOUNDTRACKER_23; + stream.position += 22; + + for (i = 1; i < 32; ++i) { + value = stream.readUnsignedShort(); + + if (!value) { + samples[i] = null; + stream.position += 28; + continue; + } + + sample = new AmigaSample(); + stream.position -= 24; + + sample.name = stream.readMultiByte(22, ENCODING); + sample.length = value << 1; + stream.position += 3; + + sample.volume = stream.readUnsignedByte(); + sample.loop = stream.readUnsignedShort() << 1; + sample.repeat = stream.readUnsignedShort() << 1; + + stream.position += 22; + sample.pointer = size; + size += sample.length; + samples[i] = sample; + + if (sample.length > 32768) + version = SOUNDTRACKER_24; + } + + stream.position = 950; + length = stream.readUnsignedByte(); + value = stream.readUnsignedByte(); + restart = value < length ? value : 0; + + for (i = 0; i < 128; ++i) { + value = stream.readUnsignedByte() << 8; + track[i] = value; + if (value > higher) higher = value; + } + + stream.position = 1084; + higher += 256; + patterns = new Vector.(higher, true); + + for (i = 0; i < higher; ++i) { + row = new AmigaRow(); + value = stream.readUnsignedInt(); + + row.note = (value >> 16) & 0x0fff; + row.effect = (value >> 8) & 0x0f; + row.sample = (value >> 24) & 0xf0 | (value >> 12) & 0x0f; + row.param = value & 0xff; + + patterns[i] = row; + + if (row.sample > 31 || !samples[row.sample]) row.sample = 0; + + if (row.effect == 3 || row.effect == 4) + version = NOISETRACKER_10; + + if (row.effect == 5 || row.effect == 6) + version = NOISETRACKER_20; + + if (row.effect > 6 && row.effect < 10) { + version = 0; + return; + } + } + + amiga.store(stream, size); + + for (i = 1; i < 32; ++i) { + sample = samples[i]; + if (!sample) continue; + + if (sample.name.indexOf("2.0") > -1) + version = NOISETRACKER_20; + + if (sample.loop) { + sample.loopPtr = sample.pointer + sample.loop; + sample.length = sample.loop + sample.repeat; + } else { + sample.loopPtr = amiga.memory.length; + sample.repeat = 2; + } + size = sample.pointer + 4; + for (j = sample.pointer; j < size; ++j) amiga.memory[j] = 0; + } + + sample = new AmigaSample(); + sample.pointer = sample.loopPtr = amiga.memory.length; + sample.length = sample.repeat = 2; + samples[0] = sample; + + if (version < NOISETRACKER_20 && restart != 127) + version = NOISETRACKER_11; + } + + public static const + SOUNDTRACKER_23 : int = 1, + SOUNDTRACKER_24 : int = 2, + NOISETRACKER_10 : int = 3, + NOISETRACKER_11 : int = 4, + NOISETRACKER_20 : int = 5; + + private const + PERIODS: Vector. = Vector.([ + 856,808,762,720,678,640,604,570,538,508,480,453, + 428,404,381,360,339,320,302,285,269,254,240,226, + 214,202,190,180,170,160,151,143,135,127,120,113,0]), + + VIBRATO: Vector. = Vector.([ + 0, 24, 49, 74, 97,120,141,161,180,197,212,224, + 235,244,250,253,255,253,250,244,235,224,212,197, + 180,161,141,120, 97, 74, 49, 24]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/trackers/MKVoice.as b/Flod 4.1/neoart/flod/trackers/MKVoice.as new file mode 100644 index 0000000..98322af --- /dev/null +++ b/Flod 4.1/neoart/flod/trackers/MKVoice.as @@ -0,0 +1,57 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.trackers { + import neoart.flod.core.*; + + public final class MKVoice { + internal var + index : int, + next : MKVoice, + channel : AmigaChannel, + sample : AmigaSample, + enabled : int, + period : int, + effect : int, + param : int, + volume : int, + portaDir : int, + portaPeriod : int, + portaSpeed : int, + vibratoPos : int, + vibratoSpeed : int; + + public function MKVoice(index:int) { + this.index = index; + } + + internal function initialize():void { + channel = null; + sample = null; + enabled = 0; + period = 0; + effect = 0; + param = 0; + volume = 0; + portaDir = 0; + portaPeriod = 0; + portaSpeed = 0; + vibratoPos = 0; + vibratoSpeed = 0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/trackers/PTPlayer.as b/Flod 4.1/neoart/flod/trackers/PTPlayer.as new file mode 100644 index 0000000..44d0632 --- /dev/null +++ b/Flod 4.1/neoart/flod/trackers/PTPlayer.as @@ -0,0 +1,741 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.1 - 2012/04/16 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.trackers { + import flash.utils.*; + import neoart.flod.core.*; + + public final class PTPlayer extends AmigaPlayer { + private var + track : Vector., + patterns : Vector., + samples : Vector., + length : int, + voices : Vector., + trackPos : int, + patternPos : int, + patternBreak : int, + patternDelay : int, + breakPos : int, + jumpFlag : int, + vibratoDepth : int; + + public function PTPlayer(amiga:Amiga = null) { + super(amiga); + PERIODS.fixed = true; + VIBRATO.fixed = true; + FUNKREP.fixed = true; + + track = new Vector.(128, true); + samples = new Vector.(32, true); + voices = new Vector.(4, true); + + voices[0] = new PTVoice(0); + voices[0].next = voices[1] = new PTVoice(1); + voices[1].next = voices[2] = new PTVoice(2); + voices[2].next = voices[3] = new PTVoice(3); + } + + override public function set force(value:int):void { + if (value < PROTRACKER_10) + value = PROTRACKER_10; + else if (value > PROTRACKER_12) + value = PROTRACKER_12; + + version = value; + + if (value < PROTRACKER_11) vibratoDepth = 6; + else vibratoDepth = 7; + } + + override public function process():void { + var chan:AmigaChannel, i:int, pattern:int, row:PTRow, sample:PTSample, value:int, voice:PTVoice = voices[0]; + + if (!tick) { + if (patternDelay) { + effects(); + } else { + pattern = track[trackPos] + patternPos; + + while (voice) { + chan = voice.channel; + voice.enabled = 0; + + if (!voice.step) chan.period = voice.period; + + row = patterns[int(pattern + voice.index)]; + voice.step = row.step; + voice.effect = row.effect; + voice.param = row.param; + + if (row.sample) { + sample = voice.sample = samples[row.sample]; + + voice.pointer = sample.pointer; + voice.length = sample.length; + voice.loopPtr = voice.funkWave = sample.loopPtr; + voice.repeat = sample.repeat; + voice.finetune = sample.finetune; + + chan.volume = voice.volume = sample.volume; + } else { + sample = voice.sample; + } + + if (!row.note) { + moreEffects(voice); + voice = voice.next; + continue; + } else { + if ((voice.step & 0x0ff0) == 0x0e50) { + voice.finetune = (voice.param & 0x0f) * 37; + } else if (voice.effect == 3 || voice.effect == 5) { + if (row.note == voice.period) { + voice.portaPeriod = 0; + } else { + i = voice.finetune; + value = i + 37; + + for (i; i < value; ++i) + if (row.note >= PERIODS[i]) break; + + if (i == value) value--; + + if (i > 0) { + value = (voice.finetune / 37) & 8; + if (value) i--; + } + + voice.portaPeriod = PERIODS[i]; + voice.portaDir = row.note > voice.portaPeriod ? 0 : 1; + } + } else if (voice.effect == 9) { + moreEffects(voice); + } + } + + for (i = 0; i < 37; ++i) + if (row.note >= PERIODS[i]) break; + + voice.period = PERIODS[int(voice.finetune + i)]; + + if ((voice.step & 0x0ff0) == 0x0ed0) { + if (voice.funkSpeed) updateFunk(voice); + extended(voice); + voice = voice.next; + continue; + } + + if (voice.vibratoWave < 4) voice.vibratoPos = 0; + if (voice.tremoloWave < 4) voice.tremoloPos = 0; + + chan.enabled = 0; + chan.pointer = voice.pointer; + chan.length = voice.length; + chan.period = voice.period; + + voice.enabled = 1; + moreEffects(voice); + voice = voice.next; + } + voice = voices[0]; + + while (voice) { + chan = voice.channel; + if (voice.enabled) chan.enabled = 1; + + chan.pointer = voice.loopPtr; + chan.length = voice.repeat; + + voice = voice.next; + } + } + } else { + effects(); + } + + if (++tick == speed) { + tick = 0; + patternPos += 4; + + if (patternDelay) + if (--patternDelay) patternPos -= 4; + + if (patternBreak) { + patternBreak = 0; + patternPos = breakPos; + breakPos = 0; + } + + if (patternPos == 256 || jumpFlag) { + patternPos = breakPos; + breakPos = 0; + jumpFlag = 0; + + if (++trackPos == length) { + trackPos = 0; + amiga.complete = 1; + } + } + } + } + + override protected function initialize():void { + var voice:PTVoice = voices[0]; + + tempo = 125; + speed = 6; + trackPos = 0; + patternPos = 0; + patternBreak = 0; + patternDelay = 0; + breakPos = 0; + jumpFlag = 0; + + super.initialize(); + force = version; + + while (voice) { + voice.initialize(); + voice.channel = amiga.channels[voice.index]; + voice.sample = samples[0]; + voice = voice.next; + } + } + + override protected function loader(stream:ByteArray):void { + var higher:int, i:int, id:String, j:int, row:PTRow, sample:PTSample, size:int, value:int; + if (stream.length < 2106) return; + + stream.position = 1080; + id = stream.readMultiByte(4, ENCODING); + if (id != "M.K." && id != "M!K!") return; + + stream.position = 0; + title = stream.readMultiByte(20, ENCODING); + version = PROTRACKER_10; + stream.position += 22; + + for (i = 1; i < 32; ++i) { + value = stream.readUnsignedShort(); + + if (!value) { + samples[i] = null; + stream.position += 28; + continue; + } + + sample = new PTSample(); + stream.position -= 24; + + sample.name = stream.readMultiByte(22, ENCODING); + sample.length = sample.realLen = value << 1; + stream.position += 2; + + sample.finetune = stream.readUnsignedByte() * 37; + sample.volume = stream.readUnsignedByte(); + sample.loop = stream.readUnsignedShort() << 1; + sample.repeat = stream.readUnsignedShort() << 1; + + stream.position += 22; + sample.pointer = size; + size += sample.length; + samples[i] = sample; + } + + stream.position = 950; + length = stream.readUnsignedByte(); + stream.position++; + + for (i = 0; i < 128; ++i) { + value = stream.readUnsignedByte() << 8; + track[i] = value; + if (value > higher) higher = value; + } + + stream.position = 1084; + higher += 256; + patterns = new Vector.(higher, true); + + for (i = 0; i < higher; ++i) { + row = new PTRow(); + row.step = value = stream.readUnsignedInt(); + + row.note = (value >> 16) & 0x0fff; + row.effect = (value >> 8) & 0x0f; + row.sample = (value >> 24) & 0xf0 | (value >> 12) & 0x0f; + row.param = value & 0xff; + + patterns[i] = row; + + if (row.sample > 31 || !samples[row.sample]) row.sample = 0; + + if (row.effect == 15 && row.param > 31) + version = PROTRACKER_11; + + if (row.effect == 8) + version = PROTRACKER_12; + } + + amiga.store(stream, size); + + for (i = 1; i < 32; ++i) { + sample = samples[i]; + if (!sample) continue; + + if (sample.loop || sample.repeat > 4) { + sample.loopPtr = sample.pointer + sample.loop; + sample.length = sample.loop + sample.repeat; + } else { + sample.loopPtr = amiga.memory.length; + sample.repeat = 2; + } + + size = sample.pointer + 2; + for (j = sample.pointer; j < size; ++j) amiga.memory[j] = 0; + } + + sample = new PTSample(); + sample.pointer = sample.loopPtr = amiga.memory.length; + sample.length = sample.repeat = 2; + samples[0] = sample; + } + + private function effects():void { + var chan:AmigaChannel, i:int, position:int, slide:int, value:int, voice:PTVoice = voices[0], wave:int; + + while (voice) { + chan = voice.channel; + if (voice.funkSpeed) updateFunk(voice); + + if ((voice.step & 0x0fff) == 0) { + chan.period = voice.period; + voice = voice.next; + continue; + } + + switch (voice.effect) { + case 0: //arpeggio + value = tick % 3; + + if (!value) { + chan.period = voice.period; + voice = voice.next; + continue; + } + + if (value == 1) value = voice.param >> 4; + else value = voice.param & 0x0f; + + i = voice.finetune; + position = i + 37; + + for (i; i < position; ++i) + if (voice.period >= PERIODS[i]) { + chan.period = PERIODS[int(i + value)]; + break; + } + break; + case 1: //portamento up + voice.period -= voice.param; + if (voice.period < 113) voice.period = 113; + chan.period = voice.period; + break; + case 2: //portamento down + voice.period += voice.param; + if (voice.period > 856) voice.period = 856; + chan.period = voice.period; + break; + case 3: //tone portamento + case 5: //tone portamento + volume slide + if (voice.effect == 5) { + slide = 1; + } else { + voice.portaSpeed = voice.param; + voice.param = 0; + } + + if (voice.portaPeriod) { + if (voice.portaDir) { + voice.period -= voice.portaSpeed; + + if (voice.period <= voice.portaPeriod) { + voice.period = voice.portaPeriod; + voice.portaPeriod = 0; + } + } else { + voice.period += voice.portaSpeed; + + if (voice.period >= voice.portaPeriod) { + voice.period = voice.portaPeriod; + voice.portaPeriod = 0; + } + } + + if (voice.glissando) { + i = voice.finetune; + value = i + 37; + + for (i; i < value; ++i) + if (voice.period >= PERIODS[i]) break; + + if (i == value) i--; + chan.period = PERIODS[i]; + } else { + chan.period = voice.period; + } + } + break; + case 4: //vibrato + case 6: //vibrato + volume slide + if (voice.effect == 6) { + slide = 1; + } else if (voice.param) { + value = voice.param & 0x0f; + if (value) voice.vibratoParam = (voice.vibratoParam & 0xf0) | value; + value = voice.param & 0xf0; + if (value) voice.vibratoParam = (voice.vibratoParam & 0x0f) | value; + } + + position = (voice.vibratoPos >> 2) & 31; + wave = voice.vibratoWave & 3; + + if (wave) { + value = 255; + position <<= 3; + + if (wave == 1) { + if (voice.vibratoPos > 127) value -= position; + else value = position; + } + } else { + value = VIBRATO[position]; + } + + value = ((voice.vibratoParam & 0x0f) * value) >> vibratoDepth; + + if (voice.vibratoPos > 127) chan.period = voice.period - value; + else chan.period = voice.period + value; + + value = (voice.vibratoParam >> 2) & 60; + voice.vibratoPos = (voice.vibratoPos + value) & 255; + break; + case 7: //tremolo + chan.period = voice.period; + + if (voice.param) { + value = voice.param & 0x0f; + if (value) voice.tremoloParam = (voice.tremoloParam & 0xf0) | value; + value = voice.param & 0xf0; + if (value) voice.tremoloParam = (voice.tremoloParam & 0x0f) | value; + } + + position = (voice.tremoloPos >> 2) & 31; + wave = voice.tremoloWave & 3; + + if (wave) { + value = 255; + position <<= 3; + + if (wave == 1) { + if (voice.tremoloPos > 127) value -= position; + else value = position; + } + } else { + value = VIBRATO[position]; + } + + value = ((voice.tremoloParam & 0x0f) * value) >> 6; + + if (voice.tremoloPos > 127) chan.volume = voice.volume - value; + else chan.volume = voice.volume + value; + + value = (voice.tremoloParam >> 2) & 60; + voice.tremoloPos = (voice.tremoloPos + value) & 255; + break; + case 10: //volume slide + slide = 1; + break; + case 14: //extended effects + extended(voice); + break; + } + + if (slide) { + slide = 0; + value = voice.param >> 4; + + if (value) voice.volume += value; + else voice.volume -= voice.param & 0x0f; + + if (voice.volume < 0) voice.volume = 0; + else if (voice.volume > 64) voice.volume = 64; + + chan.volume = voice.volume; + } + voice = voice.next; + } + } + + private function moreEffects(voice:PTVoice):void { + var chan:AmigaChannel = voice.channel, value:int; + if (voice.funkSpeed) updateFunk(voice); + + switch (voice.effect) { + case 9: //sample offset + if (voice.param) voice.offset = voice.param; + value = voice.offset << 8; + + if (value >= voice.length) { + voice.length = 2; + } else { + voice.pointer += value; + voice.length -= value; + } + break; + case 11: //position jump + trackPos = voice.param - 1; + breakPos = 0; + jumpFlag = 1; + break; + case 12: //set volume + voice.volume = voice.param; + if (voice.volume > 64) voice.volume = 64; + chan.volume = voice.volume; + break; + case 13: //pattern break + breakPos = ((voice.param >> 4) * 10) + (voice.param & 0x0f); + + if (breakPos > 63) breakPos = 0; + else breakPos <<= 2; + + jumpFlag = 1; + break; + case 14: //extended effects + extended(voice); + break; + case 15: //set speed + if (!voice.param) return; + + if (voice.param < 32) speed = voice.param; + else amiga.samplesTick = 110250 / voice.param; + + tick = 0; + break; + } + } + + private function extended(voice:PTVoice):void { + var chan:AmigaChannel = voice.channel, effect:int = voice.param >> 4, i:int, len:int, memory:Vector., param:int = voice.param & 0x0f; + + switch (effect) { + case 0: //set filter + amiga.filter.active = param; + break; + case 1: //fine portamento up + if (tick) return; + voice.period -= param; + if (voice.period < 113) voice.period = 113; + chan.period = voice.period; + break; + case 2: //fine portamento down + if (tick) return; + voice.period += param; + if (voice.period > 856) voice.period = 856; + chan.period = voice.period; + break; + case 3: //glissando control + voice.glissando = param; + break; + case 4: //vibrato control + voice.vibratoWave = param; + break; + case 5: //set finetune + voice.finetune = param * 37; + break; + case 6: //pattern loop + if (tick) return; + + if (param) { + if (voice.loopCtr) voice.loopCtr--; + else voice.loopCtr = param; + + if (voice.loopCtr) { + breakPos = voice.loopPos << 2; + patternBreak = 1; + } + } else { + voice.loopPos = patternPos >> 2; + } + break; + case 7: //tremolo control + voice.tremoloWave = param; + break; + case 8: //karplus strong + len = voice.length - 2; + memory = amiga.memory; + + for (i = voice.loopPtr; i < len;) + memory[i] = (memory[i] + memory[++i]) * 0.5; + + memory[++i] = (memory[i] + memory[0]) * 0.5; + break; + case 9: //retrig note + if (tick || !param || !voice.period) return; + if (tick % param) return; + + chan.enabled = 0; + chan.pointer = voice.pointer; + chan.length = voice.length; + chan.delay = 30; + + chan.enabled = 1; + chan.pointer = voice.loopPtr; + chan.length = voice.repeat; + chan.period = voice.period; + break; + case 10: //fine volume up + if (tick) return; + voice.volume += param; + if (voice.volume > 64) voice.volume = 64; + chan.volume = voice.volume; + break; + case 11: //fine volume down + if (tick) return; + voice.volume -= param; + if (voice.volume < 0) voice.volume = 0; + chan.volume = voice.volume; + break; + case 12: //note cut + if (tick == param) chan.volume = voice.volume = 0; + break; + case 13: //note delay + if (tick != param || !voice.period) return; + + chan.enabled = 0; + chan.pointer = voice.pointer; + chan.length = voice.length; + chan.delay = 30; + + chan.enabled = 1; + chan.pointer = voice.loopPtr; + chan.length = voice.repeat; + chan.period = voice.period; + break; + case 14: //pattern delay + if (tick || patternDelay) return; + patternDelay = ++param; + break; + case 15: //funk repeat or invert loop + if (tick) return; + voice.funkSpeed = param; + if (param) updateFunk(voice); + break; + } + } + + private function updateFunk(voice:PTVoice):void { + var chan:AmigaChannel = voice.channel, p1:int, p2:int, value:int = FUNKREP[voice.funkSpeed]; + + voice.funkPos += value; + if (voice.funkPos < 128) return; + voice.funkPos = 0; + + if (version == PROTRACKER_10) { + p1 = voice.pointer + voice.sample.realLen - voice.repeat; + p2 = voice.funkWave + voice.repeat; + + if (p2 > p1) { + p2 = voice.loopPtr; + chan.length = voice.repeat; + } + chan.pointer = voice.funkWave = p2; + } else { + p1 = voice.loopPtr + voice.repeat; + p2 = voice.funkWave + 1; + + if (p2 >= p1) p2 = voice.loopPtr; + + amiga.memory[p2] = -amiga.memory[p2]; + } + } + + public static const + PROTRACKER_10 : int = 1, + PROTRACKER_11 : int = 2, + PROTRACKER_12 : int = 3; + + private const + PERIODS : Vector. = Vector.([ + 856,808,762,720,678,640,604,570,538,508,480,453, + 428,404,381,360,339,320,302,285,269,254,240,226, + 214,202,190,180,170,160,151,143,135,127,120,113,0, + 850,802,757,715,674,637,601,567,535,505,477,450, + 425,401,379,357,337,318,300,284,268,253,239,225, + 213,201,189,179,169,159,150,142,134,126,119,113,0, + 844,796,752,709,670,632,597,563,532,502,474,447, + 422,398,376,355,335,316,298,282,266,251,237,224, + 211,199,188,177,167,158,149,141,133,125,118,112,0, + 838,791,746,704,665,628,592,559,528,498,470,444, + 419,395,373,352,332,314,296,280,264,249,235,222, + 209,198,187,176,166,157,148,140,132,125,118,111,0, + 832,785,741,699,660,623,588,555,524,495,467,441, + 416,392,370,350,330,312,294,278,262,247,233,220, + 208,196,185,175,165,156,147,139,131,124,117,110,0, + 826,779,736,694,655,619,584,551,520,491,463,437, + 413,390,368,347,328,309,292,276,260,245,232,219, + 206,195,184,174,164,155,146,138,130,123,116,109,0, + 820,774,730,689,651,614,580,547,516,487,460,434, + 410,387,365,345,325,307,290,274,258,244,230,217, + 205,193,183,172,163,154,145,137,129,122,115,109,0, + 814,768,725,684,646,610,575,543,513,484,457,431, + 407,384,363,342,323,305,288,272,256,242,228,216, + 204,192,181,171,161,152,144,136,128,121,114,108,0, + 907,856,808,762,720,678,640,604,570,538,508,480, + 453,428,404,381,360,339,320,302,285,269,254,240, + 226,214,202,190,180,170,160,151,143,135,127,120,0, + 900,850,802,757,715,675,636,601,567,535,505,477, + 450,425,401,379,357,337,318,300,284,268,253,238, + 225,212,200,189,179,169,159,150,142,134,126,119,0, + 894,844,796,752,709,670,632,597,563,532,502,474, + 447,422,398,376,355,335,316,298,282,266,251,237, + 223,211,199,188,177,167,158,149,141,133,125,118,0, + 887,838,791,746,704,665,628,592,559,528,498,470, + 444,419,395,373,352,332,314,296,280,264,249,235, + 222,209,198,187,176,166,157,148,140,132,125,118,0, + 881,832,785,741,699,660,623,588,555,524,494,467, + 441,416,392,370,350,330,312,294,278,262,247,233, + 220,208,196,185,175,165,156,147,139,131,123,117,0, + 875,826,779,736,694,655,619,584,551,520,491,463, + 437,413,390,368,347,328,309,292,276,260,245,232, + 219,206,195,184,174,164,155,146,138,130,123,116,0, + 868,820,774,730,689,651,614,580,547,516,487,460, + 434,410,387,365,345,325,307,290,274,258,244,230, + 217,205,193,183,172,163,154,145,137,129,122,115,0, + 862,814,768,725,684,646,610,575,543,513,484,457, + 431,407,384,363,342,323,305,288,272,256,242,228, + 216,203,192,181,171,161,152,144,136,128,121,114,0]), + + VIBRATO: Vector. = Vector.([ + 0, 24, 49, 74, 97,120,141,161,180,197,212,224, + 235,244,250,253,255,253,250,244,235,224,212,197, + 180,161,141,120, 97, 74, 49, 24]), + + FUNKREP: Vector. = Vector.([ + 0,5,6,7,8,10,11,13,16,19,22,26,32,43,64,128]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/trackers/PTRow.as b/Flod 4.1/neoart/flod/trackers/PTRow.as new file mode 100644 index 0000000..df1b89f --- /dev/null +++ b/Flod 4.1/neoart/flod/trackers/PTRow.as @@ -0,0 +1,25 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.trackers { + import neoart.flod.core.*; + + public final class PTRow extends AmigaRow { + internal var + step : int; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/trackers/PTSample.as b/Flod 4.1/neoart/flod/trackers/PTSample.as new file mode 100644 index 0000000..b431fba --- /dev/null +++ b/Flod 4.1/neoart/flod/trackers/PTSample.as @@ -0,0 +1,26 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.trackers { + import neoart.flod.core.*; + + public final class PTSample extends AmigaSample { + internal var + finetune : int, + realLen : int; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/trackers/PTVoice.as b/Flod 4.1/neoart/flod/trackers/PTVoice.as new file mode 100644 index 0000000..7569f82 --- /dev/null +++ b/Flod 4.1/neoart/flod/trackers/PTVoice.as @@ -0,0 +1,91 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.trackers { + import neoart.flod.core.*; + + public final class PTVoice { + internal var + index : int, + next : PTVoice, + channel : AmigaChannel, + sample : PTSample, + enabled : int, + loopCtr : int, + loopPos : int, + step : int, + period : int, + effect : int, + param : int, + volume : int, + pointer : int, + length : int, + loopPtr : int, + repeat : int, + finetune : int, + offset : int, + portaDir : int, + portaPeriod : int, + portaSpeed : int, + glissando : int, + tremoloParam : int, + tremoloPos : int, + tremoloWave : int, + vibratoParam : int, + vibratoPos : int, + vibratoWave : int, + funkPos : int, + funkSpeed : int, + funkWave : int; + + public function PTVoice(index:int) { + this.index = index; + } + + internal function initialize():void { + channel = null; + sample = null; + enabled = 0; + loopCtr = 0; + loopPos = 0; + step = 0; + period = 0; + effect = 0; + param = 0; + volume = 0; + pointer = 0; + length = 0; + loopPtr = 0; + repeat = 0; + finetune = 0; + offset = 0; + portaDir = 0; + portaPeriod = 0; + portaSpeed = 0; + glissando = 0; + tremoloParam = 0; + tremoloPos = 0; + tremoloWave = 0; + vibratoParam = 0; + vibratoPos = 0; + vibratoWave = 0; + funkPos = 0; + funkSpeed = 0; + funkWave = 0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/trackers/STPlayer.as b/Flod 4.1/neoart/flod/trackers/STPlayer.as new file mode 100644 index 0000000..d0e98c2 --- /dev/null +++ b/Flod 4.1/neoart/flod/trackers/STPlayer.as @@ -0,0 +1,369 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.1 - 2012/04/13 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.trackers { + import flash.utils.*; + import neoart.flod.core.*; + + public final class STPlayer extends AmigaPlayer { + private var + track : Vector., + patterns : Vector., + samples : Vector., + length : int, + voices : Vector., + trackPos : int, + patternPos : int, + jumpFlag : int; + + public function STPlayer(amiga:Amiga = null) { + super(amiga); + PERIODS.fixed = true; + + track = new Vector.(128, true); + samples = new Vector.(16, true); + voices = new Vector.(4, true); + + voices[0] = new STVoice(0); + voices[0].next = voices[1] = new STVoice(1); + voices[1].next = voices[2] = new STVoice(2); + voices[2].next = voices[3] = new STVoice(3); + } + + override public function set force(value:int):void { + if (value < ULTIMATE_SOUNDTRACKER) + value = ULTIMATE_SOUNDTRACKER; + else if (value > DOC_SOUNDTRACKER_20) + value = DOC_SOUNDTRACKER_20; + + version = value; + } + + override public function set ntsc(value:int):void { + super.ntsc = value; + + if (version < DOC_SOUNDTRACKER_9) + amiga.samplesTick = int((240 - tempo) * (value ? 7.5152005551 : 7.58437970472)); + } + + override public function process():void { + var chan:AmigaChannel, row:AmigaRow, sample:AmigaSample, value:int, voice:STVoice = voices[0]; + + if (!tick) { + value = track[trackPos] + patternPos; + + while (voice) { + chan = voice.channel; + voice.enabled = 0; + + row = patterns[int(value + voice.index)]; + voice.period = row.note; + voice.effect = row.effect; + voice.param = row.param; + + if (row.sample) { + sample = voice.sample = samples[row.sample]; + + if (((version & 2) == 2) && voice.effect == 12) chan.volume = voice.param; + else chan.volume = sample.volume; + } else { + sample = voice.sample; + } + + if (voice.period) { + voice.enabled = 1; + + chan.enabled = 0; + chan.pointer = sample.pointer; + chan.length = sample.length; + chan.period = voice.last = voice.period; + } + + if (voice.enabled) chan.enabled = 1; + chan.pointer = sample.loopPtr; + chan.length = sample.repeat; + + if (version < DOC_SOUNDTRACKER_20) { + voice = voice.next; + continue; + } + + switch (voice.effect) { + case 11: //position jump + trackPos = voice.param - 1; + jumpFlag ^= 1; + break; + case 12: //set volume + chan.volume = voice.param; + break; + case 13: //pattern break + jumpFlag ^= 1; + break; + case 14: //set filter + amiga.filter.active = voice.param ^ 1; + break; + case 15: //set speed + if (!voice.param) break; + speed = voice.param & 0x0f; + tick = 0; + break; + } + voice = voice.next; + } + } else { + while (voice) { + if (!voice.param) { + voice = voice.next; + continue; + } + chan = voice.channel; + + if (version == ULTIMATE_SOUNDTRACKER) { + if (voice.effect == 1) { + arpeggio(voice); + } else if (voice.effect == 2) { + value = voice.param >> 4; + + if (value) voice.period += value; + else voice.period -= (voice.param & 0x0f); + + chan.period = voice.period; + } + } else { + switch (voice.effect) { + case 0: //arpeggio + arpeggio(voice); + break; + case 1: //portamento up + voice.last -= voice.param & 0x0f; + if (voice.last < 113) voice.last = 113; + chan.period = voice.last; + break; + case 2: //portamento down + voice.last += voice.param & 0x0f; + if (voice.last > 856) voice.last = 856; + chan.period = voice.last; + break; + } + + if ((version & 2) != 2) { + voice = voice.next; + continue; + } + + switch (voice.effect) { + case 12: //set volume + chan.volume = voice.param; + break; + case 14: //set filter + amiga.filter.active = 0; + break; + case 15: //set speed + speed = voice.param & 0x0f; + break; + } + } + voice = voice.next; + } + } + + if (++tick == speed) { + tick = 0; + patternPos += 4; + + if (patternPos == 256 || jumpFlag) { + patternPos = jumpFlag = 0; + + if (++trackPos == length) { + trackPos = 0; + amiga.complete = 1; + } + } + } + } + + override protected function initialize():void { + var voice:STVoice = voices[0]; + super.initialize(); + ntsc = standard; + + speed = 6; + trackPos = 0; + patternPos = 0; + jumpFlag = 0; + + while (voice) { + voice.initialize(); + voice.channel = amiga.channels[voice.index]; + voice.sample = samples[0]; + voice = voice.next; + } + } + + override protected function loader(stream:ByteArray):void { + var higher:int, i:int, j:int, row:AmigaRow, sample:AmigaSample, score:int, size:int, value:int; + if (stream.length < 1626) return; + + title = stream.readMultiByte(20, ENCODING); + score += isLegal(title); + + version = ULTIMATE_SOUNDTRACKER; + stream.position = 42; + + for (i = 1; i < 16; ++i) { + value = stream.readUnsignedShort(); + + if (!value) { + samples[i] = null; + stream.position += 28; + continue; + } + + sample = new AmigaSample(); + stream.position -= 24; + + sample.name = stream.readMultiByte(22, ENCODING); + sample.length = value << 1; + stream.position += 3; + + sample.volume = stream.readUnsignedByte(); + sample.loop = stream.readUnsignedShort(); + sample.repeat = stream.readUnsignedShort() << 1; + + stream.position += 22; + sample.pointer = size; + size += sample.length; + samples[i] = sample; + + score += isLegal(sample.name); + if (sample.length > 9999) version = MASTER_SOUNDTRACKER; + } + + stream.position = 470; + length = stream.readUnsignedByte(); + tempo = stream.readUnsignedByte(); + + for (i = 0; i < 128; ++i) { + value = stream.readUnsignedByte() << 8; + if (value > 16384) score--; + track[i] = value; + if (value > higher) higher = value; + } + + stream.position = 600; + higher += 256; + patterns = new Vector.(higher, true); + + i = (stream.length - size - 600) >> 2; + if (higher > i) higher = i; + + for (i = 0; i < higher; ++i) { + row = new AmigaRow(); + + row.note = stream.readUnsignedShort(); + value = stream.readUnsignedByte(); + row.param = stream.readUnsignedByte(); + row.effect = value & 0x0f; + row.sample = value >> 4; + + patterns[i] = row; + + if (row.effect > 2 && row.effect < 11) score--; + if (row.note) { + if (row.note < 113 || row.note > 856) score--; + } + + if (row.sample) + if (row.sample > 15 || !samples[row.sample]) { + if (row.sample > 15) score--; + row.sample = 0; + } + + if (row.effect > 2 || (!row.effect && row.param != 0)) + version = DOC_SOUNDTRACKER_9; + + if (row.effect == 11 || row.effect == 13) + version = DOC_SOUNDTRACKER_20; + } + + amiga.store(stream, size); + + for (i = 1; i < 16; ++i) { + sample = samples[i]; + if (!sample) continue; + + if (sample.loop) { + sample.loopPtr = sample.pointer + sample.loop; + sample.pointer = sample.loopPtr; + sample.length = sample.repeat; + } else { + sample.loopPtr = amiga.memory.length; + sample.repeat = 2; + } + + size = sample.pointer + 4; + for (j = sample.pointer; j < size; ++j) amiga.memory[j] = 0; + } + + sample = new AmigaSample(); + sample.pointer = sample.loopPtr = amiga.memory.length; + sample.length = sample.repeat = 2; + samples[0] = sample; + + if (score < 1) version = 0; + } + + private function arpeggio(voice:STVoice):void { + var chan:AmigaChannel = voice.channel, i:int = 0, param:int = tick % 3; + + if (!param) { + chan.period = voice.last; + return; + } + + if (param == 1) param = voice.param >> 4; + else param = voice.param & 0x0f; + + while (voice.last != PERIODS[i]) i++; + chan.period = PERIODS[int(i + param)]; + } + + private function isLegal(text:String):int { + var ascii:int, i:int = 0, len:int = text.length; + if (!len) return 0; + + for (; i < len; ++i) { + ascii = text.charCodeAt(i); + if (ascii && (ascii < 32 || ascii > 127)) return 0; + } + return 1; + } + + public static const + ULTIMATE_SOUNDTRACKER : int = 1, + DOC_SOUNDTRACKER_9 : int = 2, + MASTER_SOUNDTRACKER : int = 3, + DOC_SOUNDTRACKER_20 : int = 4; + + private const + PERIODS: Vector. = Vector.([ + 856,808,762,720,678,640,604,570,538,508,480,453, + 428,404,381,360,339,320,302,285,269,254,240,226, + 214,202,190,180,170,160,151,143,135,127,120,113, + 0,0,0]); + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/trackers/STVoice.as b/Flod 4.1/neoart/flod/trackers/STVoice.as new file mode 100644 index 0000000..f8cefbb --- /dev/null +++ b/Flod 4.1/neoart/flod/trackers/STVoice.as @@ -0,0 +1,47 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 3.0 - 2012/02/08 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.trackers { + import neoart.flod.core.*; + + public final class STVoice { + internal var + index : int, + next : STVoice, + channel : AmigaChannel, + sample : AmigaSample, + enabled : int, + period : int, + last : int, + effect : int, + param : int; + + public function STVoice(index:int) { + this.index = index; + } + + internal function initialize():void { + channel = null; + sample = null; + enabled = 0; + period = 0; + last = 0; + effect = 0; + param = 0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/whittaker/DWPlayer.as b/Flod 4.1/neoart/flod/whittaker/DWPlayer.as new file mode 100644 index 0000000..6e5bf9a --- /dev/null +++ b/Flod 4.1/neoart/flod/whittaker/DWPlayer.as @@ -0,0 +1,794 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/03/24 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.whittaker { + import flash.utils.*; + import neoart.flod.core.*; + + public final class DWPlayer extends AmigaPlayer { + private var + songs : Vector., + samples : Vector., + stream : ByteArray, + song : DWSong, + songvol : int, + master : int, + periods : int, + frqseqs : int, + volseqs : int, + transpose : int, + slower : int, + slowerCounter : int, + delaySpeed : int, + delayCounter : int, + fadeSpeed : int, + fadeCounter : int, + wave : DWSample, + waveCenter : int, + waveLo : int, + waveHi : int, + waveDir : int, + waveLen : int, + wavePos : int, + waveRateNeg : int, + waveRatePos : int, + voices : Vector., + active : int, + complete : int, + base : int, + com2 : int, + com3 : int, + com4 : int, + readMix : String, + readLen : int; + + public function DWPlayer(amiga:Amiga = null) { + super(amiga); + voices = new Vector.(4, true); + + voices[0] = new DWVoice(0,1); + voices[1] = new DWVoice(1,2); + voices[2] = new DWVoice(2,4); + voices[3] = new DWVoice(3,8); + } + + override public function process():void { + var chan:AmigaChannel, loop:int, pos:int, sample:DWSample, value:int, voice:DWVoice = voices[active], volume:int; + + if (slower) { + if (--slowerCounter == 0) { + slowerCounter = 6; + return; + } + } + + if ((delayCounter += delaySpeed) > 255) { + delayCounter -= 256; + return; + } + + if (fadeSpeed) { + if (--fadeCounter == 0) { + fadeCounter = fadeSpeed; + songvol--; + } + + if (!songvol) { + if (!loopSong) { + amiga.complete = 1; + return; + } else { + initialize(); + } + } + } + + if (wave) { + if (waveDir) { + amiga.memory[wavePos++] = waveRatePos; + if (waveLen > 1) amiga.memory[wavePos++] = waveRatePos; + if ((wavePos -= (waveLen << 1)) == waveLo) waveDir = 0; + } else { + amiga.memory[wavePos++] = waveRateNeg; + if (waveLen > 1) amiga.memory[wavePos++] = waveRateNeg; + if (wavePos == waveHi) waveDir = 1; + } + } + + while (voice) { + chan = voice.channel; + stream.position = voice.patternPos; + sample = voice.sample; + + if (!voice.busy) { + voice.busy = 1; + + if (sample.loopPtr < 0) { + chan.pointer = amiga.loopPtr; + chan.length = amiga.loopLen; + } else { + chan.pointer = sample.pointer + sample.loopPtr; + chan.length = sample.length - sample.loopPtr; + } + } + + if (--voice.tick == 0) { + voice.flags = 0; + loop = 1; + + while (loop > 0) { + value = stream.readByte(); + + if (value < 0) { + if (value >= -32) { + voice.speed = speed * (value + 33); + } else if (value >= com2) { + value -= com2; + voice.sample = sample = samples[value]; + } else if (value >= com3) { + pos = stream.position; + + stream.position = volseqs + ((value - com3) << 1); + stream.position = base + stream.readUnsignedShort(); + voice.volseqPtr = stream.position; + + stream.position--; + voice.volseqSpeed = stream.readUnsignedByte(); + + stream.position = pos; + } else if (value >= com4) { + pos = stream.position; + + stream.position = frqseqs + ((value - com4) << 1); + voice.frqseqPtr = base + stream.readUnsignedShort(); + voice.frqseqPos = voice.frqseqPtr; + + stream.position = pos; + } else { + switch (value) { + case -128: + stream.position = voice.trackPtr + voice.trackPos; + value = stream[readMix](); + + if (value) { + stream.position = base + value; + voice.trackPos += readLen; + } else { + stream.position = voice.trackPtr; + stream.position = base + stream[readMix](); + voice.trackPos = readLen; + + if (!loopSong) { + complete &= ~(voice.bitFlag); + if (!complete) amiga.complete = 1; + } + } + break; + case -127: + if (variant > 0) voice.portaDelta = 0; + voice.portaSpeed = stream.readByte(); + voice.portaDelay = stream.readUnsignedByte(); + voice.flags |= 2; + break; + case -126: + voice.tick = voice.speed; + voice.patternPos = stream.position; + + if (variant == 41) { + voice.busy = 1; + chan.enabled = 0; + } else { + chan.pointer = amiga.loopPtr; + chan.length = amiga.loopLen; + } + + loop = 0; + break; + case -125: + if (variant > 0) { + voice.tick = voice.speed; + voice.patternPos = stream.position; + chan.enabled = 1; + loop = 0; + } + break; + case -124: + amiga.complete = 1; + break; + case -123: + if (variant > 0) transpose = stream.readByte(); + break; + case -122: + voice.vibrato = -1; + voice.vibratoSpeed = stream.readUnsignedByte(); + voice.vibratoDepth = stream.readUnsignedByte(); + voice.vibratoDelta = 0; + break; + case -121: + voice.vibrato = 0; + break; + case -120: + if (variant == 21) { + voice.halve = 1; + } else if (variant == 11) { + fadeSpeed = stream.readUnsignedByte(); + } else { + voice.transpose = stream.readByte(); + } + break; + case -119: + if (variant == 21) { + voice.halve = 0; + } else { + voice.trackPtr = base + stream.readUnsignedShort(); + voice.trackPos = 0; + } + break; + case -118: + if (variant == 31) { + delaySpeed = stream.readUnsignedByte(); + } else { + speed = stream.readUnsignedByte(); + } + break; + case -117: + fadeSpeed = stream.readUnsignedByte(); + fadeCounter = fadeSpeed; + break; + case -116: + value = stream.readUnsignedByte(); + if (variant != 32) songvol = value; + break; + } + } + } else { + voice.patternPos = stream.position; + voice.note = (value += sample.finetune); + voice.tick = voice.speed; + voice.busy = 0; + + if (variant >= 20) { + value = (value + transpose + voice.transpose) & 0xff; + stream.position = voice.volseqPtr; + volume = stream.readUnsignedByte(); + + voice.volseqPos = stream.position; + voice.volseqCounter = voice.volseqSpeed; + + if (voice.halve) volume >>= 1; + volume = (volume * songvol) >> 6; + } else { + volume = sample.volume; + } + + chan.pointer = sample.pointer; + chan.length = sample.length; + chan.volume = volume; + + stream.position = periods + (value << 1); + value = (stream.readUnsignedShort() * sample.relative) >> 10; + if (variant < 10) voice.portaDelta = value; + + chan.period = value; + chan.enabled = 1; + loop = 0; + } + } + } else if (voice.tick == 1) { + if (variant < 30) { + chan.enabled = 0; + } else { + value = stream.readUnsignedByte(); + + if (value != 131) { + if (variant < 40 || value < 224 || (stream.readUnsignedByte() != 131)) + chan.enabled = 0; + } + } + } else if (variant == 0) { + if (voice.flags & 2) { + if (voice.portaDelay) { + voice.portaDelay--; + } else { + voice.portaDelta -= voice.portaSpeed; + chan.period = voice.portaDelta; + } + } + } else { + stream.position = voice.frqseqPos; + value = stream.readByte(); + + if (value < 0) { + value &= 0x7f; + stream.position = voice.frqseqPtr; + } + + voice.frqseqPos = stream.position; + + value = (value + voice.note + transpose + voice.transpose) & 0xff; + stream.position = periods + (value << 1); + value = (stream.readUnsignedShort() * sample.relative) >> 10; + + if (voice.flags & 2) { + if (voice.portaDelay) { + voice.portaDelay--; + } else { + voice.portaDelta += voice.portaSpeed; + value -= voice.portaDelta; + } + } + + if (voice.vibrato) { + if (voice.vibrato > 0) { + voice.vibratoDelta -= voice.vibratoSpeed; + if (!voice.vibratoDelta) voice.vibrato ^= 0x80000000; + } else { + voice.vibratoDelta += voice.vibratoSpeed; + if (voice.vibratoDelta == voice.vibratoDepth) voice.vibrato ^= 0x80000000; + } + + if (!voice.vibratoDelta) voice.vibrato ^= 1; + + if (voice.vibrato & 1) { + value += voice.vibratoDelta; + } else { + value -= voice.vibratoDelta; + } + } + + chan.period = value; + + if (variant >= 20) { + if (--voice.volseqCounter < 0) { + stream.position = voice.volseqPos; + volume = stream.readByte(); + + if (volume >= 0) voice.volseqPos = stream.position; + voice.volseqCounter = voice.volseqSpeed; + volume &= 0x7f; + + if (voice.halve) volume >>= 1; + chan.volume = (volume * songvol) >> 6; + } + } + } + + voice = voice.next; + } + } + + override protected function initialize():void { + var i:int, len:int, voice:DWVoice = voices[active]; + super.initialize(); + + song = songs[playSong]; + songvol = master; + speed = song.speed; + + transpose = 0; + slowerCounter = 6; + delaySpeed = song.delay; + delayCounter = 0; + fadeSpeed = 0; + fadeCounter = 0; + + if (wave) { + waveDir = 0; + wavePos = wave.pointer + waveCenter; + i = wave.pointer; + + len = wavePos; + for (; i < len; ++i) amiga.memory[i] = waveRateNeg; + + len += waveCenter; + for (; i < len; ++i) amiga.memory[i] = waveRatePos; + } + + while (voice) { + voice.initialize(); + voice.channel = amiga.channels[voice.index]; + voice.sample = samples[0]; + complete += voice.bitFlag; + + voice.trackPtr = song.tracks[voice.index]; + voice.trackPos = readLen; + stream.position = voice.trackPtr; + voice.patternPos = base + stream[readMix](); + + if (frqseqs) { + stream.position = frqseqs; + voice.frqseqPtr = base + stream.readUnsignedShort(); + voice.frqseqPos = voice.frqseqPtr; + } + + voice = voice.next; + } + } + + override protected function loader(stream:ByteArray):void { + var flag:int, headers:int, i:int, index:int, info:int, lower:int, pos:int, sample:DWSample, size:int = 10, song:DWSong, total:int, value:int; + + master = 64; + readMix = "readUnsignedShort"; + readLen = 2; + variant = 0; + + if (stream.readUnsignedShort() == 0x48e7) { //movem.l + stream.position = 4; + if (stream.readUnsignedShort() != 0x6100) return; //bsr.w + + stream.position += stream.readUnsignedShort(); + variant = 30; + } else { + stream.position = 0; + } + + while (value != 0x4e75) { //rts + value = stream.readUnsignedShort(); + + switch (value) { + case 0x47fa: //lea x,a3 + base = stream.position + stream.readShort(); + break; + case 0x6100: //bsr.w + stream.position += 2; + info = stream.position; + + if (stream.readUnsignedShort() == 0x6100) //bsr.w + info = stream.position + stream.readUnsignedShort(); + break; + case 0xc0fc: //mulu.w #x,d0 + size = stream.readUnsignedShort(); + + if (size == 18) { + readMix = "readUnsignedInt"; + readLen = 4; + } else { + variant = 10; + } + + if (stream.readUnsignedShort() == 0x41fa) + headers = stream.position + stream.readUnsignedShort(); + + if (stream.readUnsignedShort() == 0x1230) flag = 1; + break; + case 0x1230: //move.b (a0,d0.w),d1 + stream.position -= 6; + + if (stream.readUnsignedShort() == 0x41fa) { + headers = stream.position + stream.readUnsignedShort(); + flag = 1; + } + + stream.position += 4; + break; + case 0xbe7c: //cmp.w #x,d7 + channels = stream.readUnsignedShort(); + stream.position += 2; + + if (stream.readUnsignedShort() == 0x377c) + master = stream.readUnsignedShort(); + break; + } + + if (stream.bytesAvailable < 20) return; + } + + index = stream.position; + songs = new Vector.(); + lower = 0x7fffffff; + total = 0; + stream.position = headers; + + while (1) { + song = new DWSong(); + song.tracks = new Vector.(channels, true); + + if (flag) { + song.speed = stream.readUnsignedByte(); + song.delay = stream.readUnsignedByte(); + } else { + song.speed = stream.readUnsignedShort(); + } + + if (song.speed > 255) break; + + for (i = 0; i < channels; ++i) { + value = base + stream[readMix](); + if (value < lower) lower = value; + song.tracks[i] = value; + } + + songs[total++] = song; + if ((lower - stream.position) < size) break; + } + + if (!total) return; + songs.fixed = true; + lastSong = songs.length - 1; + + stream.position = info; + if (stream.readUnsignedShort() != 0x4a2b) return; //tst.b x(a3) + headers = size = 0; + wave = null; + + while (value != 0x4e75) { //rts + value = stream.readUnsignedShort(); + + switch (value) { + case 0x4bfa: + if (headers) break; + info = stream.position + stream.readShort(); + stream.position++; + total = stream.readUnsignedByte(); + + stream.position -= 10; + value = stream.readUnsignedShort(); + pos = stream.position; + + if (value == 0x41fa || value == 0x207a) { //lea x,a0 | movea.l x,a0 + headers = stream.position + stream.readUnsignedShort(); + } else if (value == 0xd0fc) { //adda.w #x,a0 + headers = (64 + stream.readUnsignedShort()); + stream.position -= 18; + headers += (stream.position + stream.readUnsignedShort()); + } + + stream.position = pos; + break; + case 0x84c3: //divu.w d3,d2 + if (size) break; + stream.position += 4; + value = stream.readUnsignedShort(); + + if (value == 0xdafc) { //adda.w #x,a5 + size = stream.readUnsignedShort(); + } else if (value == 0xdbfc) { //adda.l #x,a5 + size = stream.readUnsignedInt(); + } + + if (size == 12 && variant < 30) variant = 20; + + pos = stream.position; + samples = new Vector.(++total, true); + stream.position = headers; + + for (i = 0; i < total; ++i) { + sample = new DWSample(); + sample.length = stream.readUnsignedInt(); + sample.relative = 3579545 / stream.readUnsignedShort(); + sample.pointer = amiga.store(stream, sample.length); + + value = stream.position; + stream.position = info + (i * size) + 4; + sample.loopPtr = stream.readInt(); + + if (variant == 0) { + stream.position += 6; + sample.volume = stream.readUnsignedShort(); + } else if (variant == 10) { + stream.position += 4; + sample.volume = stream.readUnsignedShort(); + sample.finetune = stream.readByte(); + } + + stream.position = value; + samples[i] = sample; + } + + amiga.loopLen = 64; + stream.length = headers; + stream.position = pos; + break; + case 0x207a: //movea.l x,a0 + value = stream.position + stream.readShort(); + + if (stream.readUnsignedShort() != 0x323c) { //move.w #x,d1 + stream.position -= 2; + break; + } + + wave = samples[int((value - info) / size)]; + waveCenter = (stream.readUnsignedShort() + 1) << 1; + + stream.position += 2; + waveRateNeg = stream.readByte(); + stream.position += 12; + waveRatePos = stream.readByte(); + break; + case 0x046b: //subi.w #x,x(a3) + case 0x066b: //addi.w #x,x(a3) + total = stream.readUnsignedShort(); + sample = samples[int((stream.readUnsignedShort() - info) / size)]; + + if (value == 0x066b) { + sample.relative += total; + } else { + sample.relative -= total; + } + break; + } + } + + if (!samples.length) return; + stream.position = index; + + periods = 0; + frqseqs = 0; + volseqs = 0; + slower = 0; + + com2 = 0xb0; + com3 = 0xa0; + com4 = 0x90; + + while (stream.bytesAvailable > 16) { + value = stream.readUnsignedShort(); + + switch (value) { + case 0x47fa: //lea x,a3 + stream.position += 2; + if (stream.readUnsignedShort() != 0x4a2b) break; //tst.b x(a3) + + pos = stream.position; + stream.position += 4; + value = stream.readUnsignedShort(); + + if (value == 0x103a) { //move.b x,d0 + stream.position += 4; + + if (stream.readUnsignedShort() == 0xc0fc) { //mulu.w #x,d0 + value = stream.readUnsignedShort(); + total = songs.length; + for (i = 0; i < total; ++i) songs[i].delay *= value; + stream.position += 6; + } + } else if (value == 0x532b) { //subq.b #x,x(a3) + stream.position -= 8; + } + + value = stream.readUnsignedShort(); + + if (value == 0x4a2b) { //tst.b x(a3) + stream.position = base + stream.readUnsignedShort(); + slower = stream.readByte(); + } + + stream.position = pos; + break; + case 0x0c6b: //cmpi.w #x,x(a3) + stream.position -= 6; + value = stream.readUnsignedShort(); + + if (value == 0x546b || value == 0x526b) { //addq.w #2,x(a3) | addq.w #1,x(a3) + stream.position += 4; + waveHi = wave.pointer + stream.readUnsignedShort(); + } else if (value == 0x556b || value == 0x536b) { //subq.w #2,x(a3) | subq.w #1,x(a3) + stream.position += 4; + waveLo = wave.pointer + stream.readUnsignedShort(); + } + + waveLen = (value < 0x546b) ? 1 : 2; + break; + case 0x7e00: //moveq #0,d7 + case 0x7e01: //moveq #1,d7 + case 0x7e02: //moveq #2,d7 + case 0x7e03: //moveq #3,d7 + active = value & 0xf; + total = channels - 1; + + if (active) { + voices[0].next = null; + for (i = total; i > 0;) voices[i].next = voices[--i]; + } else { + voices[total].next = null; + for (i = 0; i < total;) voices[i].next = voices[++i]; + } + break; + case 0x0c68: //cmpi.w #x,x(a0) + stream.position += 22; + if (stream.readUnsignedShort() == 0x0c11) variant = 40; + break; + case 0x322d: //move.w x(a5),d1 + pos = stream.position; + value = stream.readUnsignedShort(); + + if (value == 0x000a || value == 0x000c) { //10 | 12 + stream.position -= 8; + + if (stream.readUnsignedShort() == 0x45fa) //lea x,a2 + periods = stream.position + stream.readUnsignedShort(); + } + + stream.position = pos + 2; + break; + case 0x0400: //subi.b #x,d0 + case 0x0440: //subi.w #x,d0 + case 0x0600: //addi.b #x,d0 + value = stream.readUnsignedShort(); + + if (value == 0x00c0 || value == 0x0040) { //192 | 64 + com2 = 0xc0; + com3 = 0xb0; + com4 = 0xa0; + } else if (value == com3) { + stream.position += 2; + + if (stream.readUnsignedShort() == 0x45fa) { //lea x,a2 + volseqs = stream.position + stream.readUnsignedShort(); + if (variant < 40) variant = 30; + } + } else if (value == com4) { + stream.position += 2; + + if (stream.readUnsignedShort() == 0x45fa) //lea x,a2 + frqseqs = stream.position + stream.readUnsignedShort(); + } + break; + case 0x4ef3: //jmp (a3,a2.w) + stream.position += 2; + case 0x4ed2: //jmp a2 + lower = stream.position; + stream.position -= 10; + stream.position += stream.readUnsignedShort(); + pos = stream.position; //jump table address + + stream.position = pos + 2; //effect -126 + stream.position = base + stream.readUnsignedShort() + 10; + if (stream.readUnsignedShort() == 0x4a14) variant = 41; //tst.b (a4) + + stream.position = pos + 16; //effect -120 + value = base + stream.readUnsignedShort(); + + if (value > lower && value < pos) { + stream.position = value; + value = stream.readUnsignedShort(); + + if (value == 0x50e8) { //st x(a0) + variant = 21; + } else if (value == 0x1759) { //move.b (a1)+,x(a3) + variant = 11; + } + } + + stream.position = pos + 20; //effect -118 + value = base + stream.readUnsignedShort(); + + if (value > lower && value < pos) { + stream.position = value + 2; + if (stream.readUnsignedShort() != 0x4880) variant = 31; //ext.w d0 + } + + stream.position = pos + 26; //effect -115 + value = stream.readUnsignedShort(); + if (value > lower && value < pos) variant = 32; + + if (frqseqs) stream.position = stream.length; + break; + } + } + + if (!periods) return; + com2 -= 256; + com3 -= 256; + com4 -= 256; + + this.stream = stream; + version = 1; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/whittaker/DWSample.as b/Flod 4.1/neoart/flod/whittaker/DWSample.as new file mode 100644 index 0000000..a829489 --- /dev/null +++ b/Flod 4.1/neoart/flod/whittaker/DWSample.as @@ -0,0 +1,26 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/02/22 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.whittaker { + import neoart.flod.core.*; + + public final class DWSample extends AmigaSample { + internal var + relative : int, + finetune : int; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/whittaker/DWSong.as b/Flod 4.1/neoart/flod/whittaker/DWSong.as new file mode 100644 index 0000000..ed4adbb --- /dev/null +++ b/Flod 4.1/neoart/flod/whittaker/DWSong.as @@ -0,0 +1,26 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/02/22 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.whittaker { + + public final class DWSong { + internal var + speed : int, + delay : int, + tracks : Vector.; + } +} \ No newline at end of file diff --git a/Flod 4.1/neoart/flod/whittaker/DWVoice.as b/Flod 4.1/neoart/flod/whittaker/DWVoice.as new file mode 100644 index 0000000..e608725 --- /dev/null +++ b/Flod 4.1/neoart/flod/whittaker/DWVoice.as @@ -0,0 +1,87 @@ +/* + Flod 4.1 + 2012/04/30 + Christian Corti + Neoart Costa Rica + + Last Update: Flod 4.0 - 2012/02/22 + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. + To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to + Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. +*/ +package neoart.flod.whittaker { + import neoart.flod.core.*; + + public final class DWVoice { + internal var + index : int, + bitFlag : int, + next : DWVoice, + channel : AmigaChannel, + sample : DWSample, + trackPtr : int, + trackPos : int, + patternPos : int, + frqseqPtr : int, + frqseqPos : int, + volseqPtr : int, + volseqPos : int, + volseqSpeed : int, + volseqCounter : int, + halve : int, + speed : int, + tick : int, + busy : int, + flags : int, + note : int, + period : int, + transpose : int, + portaDelay : int, + portaDelta : int, + portaSpeed : int, + vibrato : int, + vibratoDelta : int, + vibratoSpeed : int, + vibratoDepth : int; + + public function DWVoice(index:int, bitFlag:int) { + this.index = index; + this.bitFlag = bitFlag; + } + + internal function initialize():void { + channel = null; + sample = null; + trackPtr = 0; + trackPos = 0; + patternPos = 0; + frqseqPtr = 0; + frqseqPos = 0; + volseqPtr = 0; + volseqPos = 0; + volseqSpeed = 0; + volseqCounter = 0; + halve = 0; + speed = 0; + tick = 1; + busy = -1; + flags = 0; + note = 0; + period = 0; + transpose = 0; + portaDelay = 0; + portaDelta = 0; + portaSpeed = 0; + vibrato = 0; + vibratoDelta = 0; + vibratoSpeed = 0; + vibratoDepth = 0; + } + } +} \ No newline at end of file diff --git a/Flod 4.1/readme.txt b/Flod 4.1/readme.txt new file mode 100644 index 0000000..6e92fe3 --- /dev/null +++ b/Flod 4.1/readme.txt @@ -0,0 +1,74 @@ +Flod version 4.1 +Flod JS version 2.1 +Flip version 1.2 + + 2012/04/30 + Christian Corti + Neoart Costa Rica + + E-Mail: flod@neoartcr.com + +This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. +To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to +Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. + +Flod is free for non commercial user, to use it in any commercial production I'll ask you to +mention the proper credits and to make a donation to: chreil@hotmail.com via PayPal, thank you. + +Special thanks to Richard Davey, Mathew Nolan and Andreas Argirakis :) + +What's new: +4.1/2.1: + - some small modules (less than 2150 bytes) were not recognized as valid + - His Master's Noisetracker, fixed Peggy Go Home null sample pointer + - His Master's Noisetracker, fixed Ikke Advanced wrong patterns pointers + - SoundFX, fixed effect 9 + - SoundFX, added support for untouched Operation Stealth modules + - Soundtrackers, fixed period overflow, portamento up/down + - FastTracker II, fixed not working master volume +4.0/2.0: + - new David Whittaker player + - new FredEd player + - new Jochen Hippel player (regular and COSO formats, 4 voices only) + - new Rob Hubbard player + - added DigiBooster Pro 2.18 detection to the XM player + - Delta Music 1.0, fixed wrong sustain value + - Delta Music 2.0, fixed Warfalcons-Intromusik 2 crash + - Delta Music 2.0, fixed wrong restart pointer + - Digital Mugician, fixed sample loop pointer (fixes Hoi Level 4) + - Future Composer (Flod only), 1.0/1.3 was using the wrong waves + - SoundFX, fixed effect 7/8 [step down/up] (fixes Forever Tonight) + - SidMON 2, fixed effect C/F [volume and speed] (fixes Cool Module) + - SidMON 2 was processing effects at tick 0, it shouldn't :) + - SidMON 2, fixed adsr sustain volume + - SoundMon, fixed buffer restore, most modules didn't play at all + - ProTracker/NoiseTracker fixed vibrato depth value not set at the beginning + - Fixed and updated Flip/Unzip +3.0/1.0: + - Flod XM is now part of Flod base code + - Lots of bugs fixed + - Flod JS source code released + +Supported Formats: + - Brian Postma's SoundMon 1.0/2.0/3.0 + - David Whittaker + - Delta Music 1.0 + - Delta Music 2.0/2.2 + - Digital Mugician + - Digital Mugician 7 voices + - D.O.C. Soundtracker 9/2.0 + - FastTracker II XM (PC) + - FredEd + - Future Composer 1.0/1.3 + - Future Composer 1.4 + - His Master's NoiseTracker + - Jochen Hippel + - Jochen Hippel COSO + - NoiseTracker 1.0/1.1/2.0 + - ProTracker 1.0/1.1/1.2 + - Rob Hubbard + - SidMON + - SidMON II + - SoundFX 1.0/1.8/1.9/2.0 + - Soundtracker 2.3/2.5 + - Ultimate Soundtracker, The (Karsten Obarski) \ No newline at end of file diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..b547faf --- /dev/null +++ b/license.txt @@ -0,0 +1,18 @@ +Flod version 4.1 +Flod JS version 2.1 +Flip version 1.2 + + 2012/04/30 + Christian Corti + Neoart Costa Rica + + E-Mail: flod@neoartcr.com + +This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. +To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to +Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. + +Flod is free for non commercial user, to use it in any commercial production I'll ask you to +mention the proper credits and to make a donation to: chreil@hotmail.com via PayPal, thank you. + +Special thanks to Richard Davey, Mathew Nolan and Andreas Argirakis :) \ No newline at end of file diff --git a/readme.md b/readme.md index dedaa1e..a93fa5b 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,16 @@ -Flod 4.0 for ActionScript 3 +Flod 4.1 for ActionScript 3 =========================== +What's new in 4.1: + +* some small modules (less than 2150 bytes) were not recognized as valid +* His Master's Noisetracker, fixed Peggy Go Home null sample pointer +* His Master's Noisetracker, fixed Ikke Advanced wrong patterns pointers +* SoundFX, fixed effect 9 +* SoundFX, added support for untouched Operation Stealth modules +* Soundtrackers, fixed period overflow, portamento up/down +* FastTracker II, fixed not working master volume + What's new in 4.0: * new David Whittaker player @@ -52,7 +62,7 @@ This version will replay the following music formats: Author ------ -1st April 2012, Christian Corti +30th April 2012, Christian Corti Neoart Costa Rica E-Mail: flod@neoartcr.com