├── .gitattributes ├── .gitignore ├── docs ├── screenshot.gif ├── newton │ └── index.html ├── wrecking │ └── index.html └── index.html ├── tsconfig.json ├── web_typings ├── gcc │ └── gcc.d.ts ├── sss │ └── sss.d.ts ├── ppe │ └── ppe.d.ts └── pag │ └── pag.d.ts ├── package.json ├── webpack.config.js ├── src ├── newton │ └── index.ts ├── wrecking │ └── index.ts └── lark-matter │ └── index.ts ├── LICENSE.txt ├── README.md └── web_modules ├── pag └── index.js ├── ppe └── index.js ├── gcc └── index.js └── sss └── index.js /.gitattributes: -------------------------------------------------------------------------------- 1 | web_modules/* linguist-vendored 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .vscode/ 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /docs/screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abagames/lark-matter/HEAD/docs/screenshot.gif -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs" 5 | }, 6 | "exclude": [ 7 | "node_modules", 8 | "web_modules" 9 | ] 10 | } -------------------------------------------------------------------------------- /docs/newton/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |setDelay(1000/fps).
404 | * @param fps
405 | * float frame rate (frames per second)
406 | */
407 |
408 | var setFrameRate = exports.setFrameRate = function setFrameRate(fps) {
409 | if (fps != 0xf) delay = Math.round(100 / fps);
410 | };
411 |
412 | /**
413 | * Sets quality of color quantization (conversion of images to the maximum 256
414 | * colors allowed by the GIF specification). Lower values (minimum = 1)
415 | * produce better colors, but slow processing significantly. 10 is the
416 | * default, and produces good color mapping at reasonable speeds. Values
417 | * greater than 20 do not yield significant improvements in speed.
418 | * @param quality
419 | * int greater than 0.
420 | * @return
421 | */
422 |
423 | var setQuality = exports.setQuality = function setQuality(quality) {
424 | if (quality < 1) quality = 1;
425 | sample = quality;
426 | };
427 |
428 | /**
429 | * Sets the GIF frame size. The default size is the size of the first frame
430 | * added if this method is not invoked.
431 | * @param w
432 | * int frame width.
433 | * @param h
434 | * int frame width.
435 | */
436 |
437 | var setSize = exports.setSize = function setSize(w, h) {
438 |
439 | if (started && !firstFrame) return;
440 | width = w;
441 | height = h;
442 | if (width < 1) width = 320;
443 | if (height < 1) height = 240;
444 | sizeSet = true;
445 | };
446 |
447 | /**
448 | * Initiates GIF file creation on the given stream.
449 | * @param os
450 | * OutputStream on which GIF images are written.
451 | * @return false if initial write failed.
452 | */
453 |
454 | var start = exports.start = function start() {
455 |
456 | reset();
457 | var ok = true;
458 | closeStream = false;
459 | out = new ByteArray();
460 | try {
461 | out.writeUTFBytes("GIF89a"); // header
462 | } catch (e) {
463 | ok = false;
464 | }
465 |
466 | return started = ok;
467 | };
468 |
469 | var cont = exports.cont = function cont() {
470 |
471 | reset();
472 | var ok = true;
473 | closeStream = false;
474 | out = new ByteArray();
475 |
476 | return started = ok;
477 | };
478 |
479 | /**
480 | * Analyzes image colors and creates color map.
481 | */
482 |
483 | var analyzePixels = function analyzePixels() {
484 |
485 | var len = pixels.length;
486 | var nPix = len / 3;
487 | indexedPixels = [];
488 | var nq = new NeuQuant(pixels, len, sample);
489 |
490 | // initialize quantizer
491 | colorTab = nq.process(); // create reduced palette
492 |
493 | // map image pixels to new palette
494 | var k = 0;
495 | for (var j = 0; j < nPix; j++) {
496 | var index = nq.map(pixels[k++] & 0xff, pixels[k++] & 0xff, pixels[k++] & 0xff);
497 | usedEntry[index] = true;
498 | indexedPixels[j] = index;
499 | }
500 |
501 | pixels = null;
502 | colorDepth = 8;
503 | palSize = 7;
504 |
505 | // get closest match to transparent color if specified
506 | if (transparent !== null) {
507 | transIndex = findClosest(transparent);
508 | }
509 | };
510 |
511 | /**
512 | * Returns index of palette color closest to c
513 | */
514 |
515 | var findClosest = function findClosest(c) {
516 |
517 | if (colorTab === null) return -1;
518 | var r = (c & 0xFF0000) >> 16;
519 | var g = (c & 0x00FF00) >> 8;
520 | var b = (c & 0x0000FF);
521 | var minpos = 0;
522 | var dmin = 256 * 256 * 256;
523 | var len = colorTab.length;
524 |
525 | for (var i = 0; i < len;) {
526 | var dr = r - (colorTab[i++] & 0xff);
527 | var dg = g - (colorTab[i++] & 0xff);
528 | var db = b - (colorTab[i] & 0xff);
529 | var d = dr * dr + dg * dg + db * db;
530 | var index = i / 3;
531 | if (usedEntry[index] && (d < dmin)) {
532 | dmin = d;
533 | minpos = index;
534 | }
535 | i++;
536 | }
537 | return minpos;
538 | };
539 |
540 | /**
541 | * Extracts image pixels into byte array "pixels
542 | */
543 |
544 | var getImagePixels = function getImagePixels() {
545 | var w = width;
546 | var h = height;
547 | pixels = [];
548 | var data = image;
549 | var count = 0;
550 |
551 | for (var i = 0; i < h; i++) {
552 |
553 | for (var j = 0; j < w; j++) {
554 |
555 | var b = (i * w * 4) + j * 4;
556 | pixels[count++] = data[b];
557 | pixels[count++] = data[b + 1];
558 | pixels[count++] = data[b + 2];
559 |
560 | }
561 |
562 | }
563 | };
564 |
565 | /**
566 | * Writes Graphic Control Extension
567 | */
568 |
569 | var writeGraphicCtrlExt = function writeGraphicCtrlExt() {
570 | out.writeByte(0x21); // extension introducer
571 | out.writeByte(0xf9); // GCE label
572 | out.writeByte(4); // data block size
573 | var transp;
574 | var disp;
575 | if (transparent === null) {
576 | transp = 0;
577 | disp = 0; // dispose = no action
578 | } else {
579 | transp = 1;
580 | disp = 2; // force clear if using transparent color
581 | }
582 | if (dispose >= 0) {
583 | disp = dispose & 7; // user override
584 | }
585 | disp <<= 2;
586 | // packed fields
587 | out.writeByte(0 | // 1:3 reserved
588 | disp | // 4:6 disposal
589 | 0 | // 7 user input - 0 = none
590 | transp); // 8 transparency flag
591 |
592 | WriteShort(delay); // delay x 1/100 sec
593 | out.writeByte(transIndex); // transparent color index
594 | out.writeByte(0); // block terminator
595 | };
596 |
597 | /**
598 | * Writes Comment Extention
599 | */
600 |
601 | var writeCommentExt = function writeCommentExt() {
602 | out.writeByte(0x21); // extension introducer
603 | out.writeByte(0xfe); // comment label
604 | out.writeByte(comment.length); // Block Size (s)
605 | out.writeUTFBytes(comment);
606 | out.writeByte(0); // block terminator
607 | };
608 |
609 |
610 | /**
611 | * Writes Image Descriptor
612 | */
613 |
614 | var writeImageDesc = function writeImageDesc() {
615 |
616 | out.writeByte(0x2c); // image separator
617 | WriteShort(0); // image position x,y = 0,0
618 | WriteShort(0);
619 | WriteShort(width); // image size
620 | WriteShort(height);
621 |
622 | // packed fields
623 | if (firstFrame) {
624 | // no LCT - GCT is used for first (or only) frame
625 | out.writeByte(0);
626 | } else {
627 | // specify normal LCT
628 | out.writeByte(0x80 | // 1 local color table 1=yes
629 | 0 | // 2 interlace - 0=no
630 | 0 | // 3 sorted - 0=no
631 | 0 | // 4-5 reserved
632 | palSize); // 6-8 size of color table
633 | }
634 | };
635 |
636 | /**
637 | * Writes Logical Screen Descriptor
638 | */
639 |
640 | var writeLSD = function writeLSD() {
641 |
642 | // logical screen size
643 | WriteShort(width);
644 | WriteShort(height);
645 | // packed fields
646 | out.writeByte((0x80 | // 1 : global color table flag = 1 (gct used)
647 | 0x70 | // 2-4 : color resolution = 7
648 | 0x00 | // 5 : gct sort flag = 0
649 | palSize)); // 6-8 : gct size
650 |
651 | out.writeByte(0); // background color index
652 | out.writeByte(0); // pixel aspect ratio - assume 1:1
653 | };
654 |
655 | /**
656 | * Writes Netscape application extension to define repeat count.
657 | */
658 |
659 | var writeNetscapeExt = function writeNetscapeExt() {
660 | out.writeByte(0x21); // extension introducer
661 | out.writeByte(0xff); // app extension label
662 | out.writeByte(11); // block size
663 | out.writeUTFBytes("NETSCAPE" + "2.0"); // app id + auth code
664 | out.writeByte(3); // sub-block size
665 | out.writeByte(1); // loop sub-block id
666 | WriteShort(repeat); // loop count (extra iterations, 0=repeat forever)
667 | out.writeByte(0); // block terminator
668 | };
669 |
670 | /**
671 | * Writes color table
672 | */
673 |
674 | var writePalette = function writePalette() {
675 | out.writeBytes(colorTab);
676 | var n = (3 * 256) - colorTab.length;
677 | for (var i = 0; i < n; i++) out.writeByte(0);
678 | };
679 |
680 | var WriteShort = function WriteShort(pValue) {
681 | out.writeByte(pValue & 0xFF);
682 | out.writeByte((pValue >> 8) & 0xFF);
683 | };
684 |
685 | /**
686 | * Encodes and writes pixel data
687 | */
688 |
689 | var writePixels = function writePixels() {
690 | var myencoder = new LZWEncoder(width, height, indexedPixels, colorDepth);
691 | myencoder.encode(out);
692 | };
693 |
694 | /**
695 | * Retrieves the GIF stream
696 | */
697 |
698 | var stream = exports.stream = function stream() {
699 | return out;
700 | };
701 |
702 | var setProperties = exports.setProperties = function setProperties(has_start, is_first) {
703 | started = has_start;
704 | firstFrame = is_first;
705 | };
706 |
707 | return exports;
708 |
709 | };
710 |
711 | module.exports = GIFEncoder;
712 |
713 | /**
714 | * This class handles LZW encoding
715 | * Adapted from Jef Poskanzer's Java port by way of J. M. G. Elliott.
716 | * @author Kevin Weiner (original Java version - kweiner@fmsware.com)
717 | * @author Thibault Imbert (AS3 version - bytearray.org)
718 | * @author Kevin Kwok (JavaScript version - https://github.com/antimatter15/jsgif)
719 | * @version 0.1 AS3 implementation
720 | */
721 |
722 | LZWEncoder = function () {
723 |
724 | var exports = {};
725 | var EOF = -1;
726 | var imgW;
727 | var imgH;
728 | var pixAry;
729 | var initCodeSize;
730 | var remaining;
731 | var curPixel;
732 |
733 | // GIFCOMPR.C - GIF Image compression routines
734 | // Lempel-Ziv compression based on 'compress'. GIF modifications by
735 | // David Rowley (mgardi@watdcsu.waterloo.edu)
736 | // General DEFINEs
737 |
738 | var BITS = 12;
739 | var HSIZE = 5003; // 80% occupancy
740 |
741 | // GIF Image compression - modified 'compress'
742 | // Based on: compress.c - File compression ala IEEE Computer, June 1984.
743 | // By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
744 | // Jim McKie (decvax!mcvax!jim)
745 | // Steve Davies (decvax!vax135!petsd!peora!srd)
746 | // Ken Turkowski (decvax!decwrl!turtlevax!ken)
747 | // James A. Woods (decvax!ihnp4!ames!jaw)
748 | // Joe Orost (decvax!vax135!petsd!joe)
749 |
750 | var n_bits; // number of bits/code
751 | var maxbits = BITS; // user settable max # bits/code
752 | var maxcode; // maximum code, given n_bits
753 | var maxmaxcode = 1 << BITS; // should NEVER generate this code
754 | var htab = [];
755 | var codetab = [];
756 | var hsize = HSIZE; // for dynamic table sizing
757 | var free_ent = 0; // first unused entry
758 |
759 | // block compression parameters -- after all codes are used up,
760 | // and compression rate changes, start over.
761 |
762 | var clear_flg = false;
763 |
764 | // Algorithm: use open addressing double hashing (no chaining) on the
765 | // prefix code / next character combination. We do a variant of Knuth's
766 | // algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
767 | // secondary probe. Here, the modular division first probe is gives way
768 | // to a faster exclusive-or manipulation. Also do block compression with
769 | // an adaptive reset, whereby the code table is cleared when the compression
770 | // ratio decreases, but after the table fills. The variable-length output
771 | // codes are re-sized at this point, and a special CLEAR code is generated
772 | // for the decompressor. Late addition: construct the table according to
773 | // file size for noticeable speed improvement on small files. Please direct
774 | // questions about this implementation to ames!jaw.
775 |
776 | var g_init_bits;
777 | var ClearCode;
778 | var EOFCode;
779 |
780 | // output
781 | // Output the given code.
782 | // Inputs:
783 | // code: A n_bits-bit integer. If == -1, then EOF. This assumes
784 | // that n_bits =< wordsize - 1.
785 | // Outputs:
786 | // Outputs code to the file.
787 | // Assumptions:
788 | // Chars are 8 bits long.
789 | // Algorithm:
790 | // Maintain a BITS character long buffer (so that 8 codes will
791 | // fit in it exactly). Use the VAX insv instruction to insert each
792 | // code in turn. When the buffer fills up empty it and start over.
793 |
794 | var cur_accum = 0;
795 | var cur_bits = 0;
796 | var masks = [0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF];
797 |
798 | // Number of characters so far in this 'packet'
799 | var a_count;
800 |
801 | // Define the storage for the packet accumulator
802 | var accum = [];
803 |
804 | var LZWEncoder = exports.LZWEncoder = function LZWEncoder(width, height, pixels, color_depth) {
805 | imgW = width;
806 | imgH = height;
807 | pixAry = pixels;
808 | initCodeSize = Math.max(2, color_depth);
809 | };
810 |
811 | // Add a character to the end of the current packet, and if it is 254
812 | // characters, flush the packet to disk.
813 | var char_out = function char_out(c, outs) {
814 | accum[a_count++] = c;
815 | if (a_count >= 254) flush_char(outs);
816 | };
817 |
818 | // Clear out the hash table
819 | // table clear for block compress
820 |
821 | var cl_block = function cl_block(outs) {
822 | cl_hash(hsize);
823 | free_ent = ClearCode + 2;
824 | clear_flg = true;
825 | output(ClearCode, outs);
826 | };
827 |
828 | // reset code table
829 | var cl_hash = function cl_hash(hsize) {
830 | for (var i = 0; i < hsize; ++i) htab[i] = -1;
831 | };
832 |
833 | var compress = exports.compress = function compress(init_bits, outs) {
834 |
835 | var fcode;
836 | var i; /* = 0 */
837 | var c;
838 | var ent;
839 | var disp;
840 | var hsize_reg;
841 | var hshift;
842 |
843 | // Set up the globals: g_init_bits - initial number of bits
844 | g_init_bits = init_bits;
845 |
846 | // Set up the necessary values
847 | clear_flg = false;
848 | n_bits = g_init_bits;
849 | maxcode = MAXCODE(n_bits);
850 |
851 | ClearCode = 1 << (init_bits - 1);
852 | EOFCode = ClearCode + 1;
853 | free_ent = ClearCode + 2;
854 |
855 | a_count = 0; // clear packet
856 |
857 | ent = nextPixel();
858 |
859 | hshift = 0;
860 | for (fcode = hsize; fcode < 65536; fcode *= 2)
861 | ++hshift;
862 | hshift = 8 - hshift; // set hash code range bound
863 |
864 | hsize_reg = hsize;
865 | cl_hash(hsize_reg); // clear hash table
866 |
867 | output(ClearCode, outs);
868 |
869 | outer_loop: while ((c = nextPixel()) != EOF) {
870 | fcode = (c << maxbits) + ent;
871 | i = (c << hshift) ^ ent; // xor hashing
872 |
873 | if (htab[i] == fcode) {
874 | ent = codetab[i];
875 | continue;
876 | }
877 |
878 | else if (htab[i] >= 0) { // non-empty slot
879 |
880 | disp = hsize_reg - i; // secondary hash (after G. Knott)
881 | if (i === 0) disp = 1;
882 |
883 | do {
884 | if ((i -= disp) < 0)
885 | i += hsize_reg;
886 |
887 | if (htab[i] == fcode) {
888 | ent = codetab[i];
889 | continue outer_loop;
890 | }
891 | } while (htab[i] >= 0);
892 | }
893 |
894 | output(ent, outs);
895 | ent = c;
896 | if (free_ent < maxmaxcode) {
897 | codetab[i] = free_ent++; // code -> hashtable
898 | htab[i] = fcode;
899 | }
900 | else cl_block(outs);
901 | }
902 |
903 | // Put out the final code.
904 | output(ent, outs);
905 | output(EOFCode, outs);
906 | };
907 |
908 | // ----------------------------------------------------------------------------
909 | var encode = exports.encode = function encode(os) {
910 | os.writeByte(initCodeSize); // write "initial code size" byte
911 | remaining = imgW * imgH; // reset navigation variables
912 | curPixel = 0;
913 | compress(initCodeSize + 1, os); // compress and write the pixel data
914 | os.writeByte(0); // write block terminator
915 | };
916 |
917 | // Flush the packet to disk, and reset the accumulator
918 | var flush_char = function flush_char(outs) {
919 | if (a_count > 0) {
920 | outs.writeByte(a_count);
921 | outs.writeBytes(accum, 0, a_count);
922 | a_count = 0;
923 | }
924 | };
925 |
926 | var MAXCODE = function MAXCODE(n_bits) {
927 | return (1 << n_bits) - 1;
928 | };
929 |
930 | // ----------------------------------------------------------------------------
931 | // Return the next pixel from the image
932 | // ----------------------------------------------------------------------------
933 |
934 | var nextPixel = function nextPixel() {
935 | if (remaining === 0) return EOF;
936 | --remaining;
937 | var pix = pixAry[curPixel++];
938 | return pix & 0xff;
939 | };
940 |
941 | var output = function output(code, outs) {
942 |
943 | cur_accum &= masks[cur_bits];
944 |
945 | if (cur_bits > 0) cur_accum |= (code << cur_bits);
946 | else cur_accum = code;
947 |
948 | cur_bits += n_bits;
949 |
950 | while (cur_bits >= 8) {
951 | char_out((cur_accum & 0xff), outs);
952 | cur_accum >>= 8;
953 | cur_bits -= 8;
954 | }
955 |
956 | // If the next entry is going to be too big for the code size,
957 | // then increase it, if possible.
958 |
959 | if (free_ent > maxcode || clear_flg) {
960 |
961 | if (clear_flg) {
962 |
963 | maxcode = MAXCODE(n_bits = g_init_bits);
964 | clear_flg = false;
965 |
966 | } else {
967 |
968 | ++n_bits;
969 | if (n_bits == maxbits) maxcode = maxmaxcode;
970 | else maxcode = MAXCODE(n_bits);
971 | }
972 | }
973 |
974 | if (code == EOFCode) {
975 |
976 | // At EOF, write the rest of the buffer.
977 | while (cur_bits > 0) {
978 | char_out((cur_accum & 0xff), outs);
979 | cur_accum >>= 8;
980 | cur_bits -= 8;
981 | }
982 |
983 | flush_char(outs);
984 | }
985 | };
986 |
987 | LZWEncoder.apply(this, arguments);
988 | return exports;
989 | };
990 |
991 | /*
992 | * NeuQuant Neural-Net Quantization Algorithm
993 | * ------------------------------------------
994 | *
995 | * Copyright (c) 1994 Anthony Dekker
996 | *
997 | * NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994. See
998 | * "Kohonen neural networks for optimal colour quantization" in "Network:
999 | * Computation in Neural Systems" Vol. 5 (1994) pp 351-367. for a discussion of
1000 | * the algorithm.
1001 | *
1002 | * Any party obtaining a copy of these files from the author, directly or
1003 | * indirectly, is granted, free of charge, a full and unrestricted irrevocable,
1004 | * world-wide, paid up, royalty-free, nonexclusive right and license to deal in
1005 | * this software and documentation files (the "Software"), including without
1006 | * limitation the rights to use, copy, modify, merge, publish, distribute,
1007 | * sublicense, and/or sell copies of the Software, and to permit persons who
1008 | * receive copies from any such party to do so, with the only requirement being
1009 | * that this copyright notice remain intact.
1010 | */
1011 |
1012 | /*
1013 | * This class handles Neural-Net quantization algorithm
1014 | * @author Kevin Weiner (original Java version - kweiner@fmsware.com)
1015 | * @author Thibault Imbert (AS3 version - bytearray.org)
1016 | * @author Kevin Kwok (JavaScript version - https://github.com/antimatter15/jsgif)
1017 | * @version 0.1 AS3 implementation
1018 | */
1019 |
1020 | NeuQuant = function () {
1021 |
1022 | var exports = {};
1023 | var netsize = 256; /* number of colours used */
1024 |
1025 | /* four primes near 500 - assume no image has a length so large */
1026 | /* that it is divisible by all four primes */
1027 |
1028 | var prime1 = 499;
1029 | var prime2 = 491;
1030 | var prime3 = 487;
1031 | var prime4 = 503;
1032 | var minpicturebytes = (3 * prime4); /* minimum size for input image */
1033 |
1034 | /*
1035 | * Program Skeleton ---------------- [select samplefac in range 1..30] [read
1036 | * image from input file] pic = (unsigned char*) malloc(3*width*height);
1037 | * initnet(pic,3*width*height,samplefac); learn(); unbiasnet(); [write output
1038 | * image header, using writecolourmap(f)] inxbuild(); write output image using
1039 | * inxsearch(b,g,r)
1040 | */
1041 |
1042 | /*
1043 | * Network Definitions -------------------
1044 | */
1045 |
1046 | var maxnetpos = (netsize - 1);
1047 | var netbiasshift = 4; /* bias for colour values */
1048 | var ncycles = 100; /* no. of learning cycles */
1049 |
1050 | /* defs for freq and bias */
1051 | var intbiasshift = 16; /* bias for fractions */
1052 | var intbias = (1 << intbiasshift);
1053 | var gammashift = 10; /* gamma = 1024 */
1054 | var gamma = (1 << gammashift);
1055 | var betashift = 10;
1056 | var beta = (intbias >> betashift); /* beta = 1/1024 */
1057 | var betagamma = (intbias << (gammashift - betashift));
1058 |
1059 | /* defs for decreasing radius factor */
1060 | var initrad = (netsize >> 3); /* for 256 cols, radius starts */
1061 | var radiusbiasshift = 6; /* at 32.0 biased by 6 bits */
1062 | var radiusbias = (1 << radiusbiasshift);
1063 | var initradius = (initrad * radiusbias); /* and decreases by a */
1064 | var radiusdec = 30; /* factor of 1/30 each cycle */
1065 |
1066 | /* defs for decreasing alpha factor */
1067 | var alphabiasshift = 10; /* alpha starts at 1.0 */
1068 | var initalpha = (1 << alphabiasshift);
1069 | var alphadec; /* biased by 10 bits */
1070 |
1071 | /* radbias and alpharadbias used for radpower calculation */
1072 | var radbiasshift = 8;
1073 | var radbias = (1 << radbiasshift);
1074 | var alpharadbshift = (alphabiasshift + radbiasshift);
1075 | var alpharadbias = (1 << alpharadbshift);
1076 |
1077 | /*
1078 | * Types and Global Variables --------------------------
1079 | */
1080 |
1081 | var thepicture; /* the input image itself */
1082 | var lengthcount; /* lengthcount = H*W*3 */
1083 | var samplefac; /* sampling factor 1..30 */
1084 |
1085 | // typedef int pixel[4]; /* BGRc */
1086 | var network; /* the network itself - [netsize][4] */
1087 | var netindex = [];
1088 |
1089 | /* for network lookup - really 256 */
1090 | var bias = [];
1091 |
1092 | /* bias and freq arrays for learning */
1093 | var freq = [];
1094 | var radpower = [];
1095 |
1096 | var NeuQuant = exports.NeuQuant = function NeuQuant(thepic, len, sample) {
1097 |
1098 | var i;
1099 | var p;
1100 |
1101 | thepicture = thepic;
1102 | lengthcount = len;
1103 | samplefac = sample;
1104 |
1105 | network = new Array(netsize);
1106 |
1107 | for (i = 0; i < netsize; i++) {
1108 |
1109 | network[i] = new Array(4);
1110 | p = network[i];
1111 | p[0] = p[1] = p[2] = (i << (netbiasshift + 8)) / netsize;
1112 | freq[i] = intbias / netsize; /* 1/netsize */
1113 | bias[i] = 0;
1114 | }
1115 | };
1116 |
1117 | var colorMap = function colorMap() {
1118 |
1119 | var map = [];
1120 | var index = new Array(netsize);
1121 |
1122 | for (var i = 0; i < netsize; i++)
1123 | index[network[i][3]] = i;
1124 |
1125 | var k = 0;
1126 | for (var l = 0; l < netsize; l++) {
1127 | var j = index[l];
1128 | map[k++] = (network[j][0]);
1129 | map[k++] = (network[j][1]);
1130 | map[k++] = (network[j][2]);
1131 | }
1132 |
1133 | return map;
1134 | };
1135 |
1136 | /*
1137 | * Insertion sort of network and building of netindex[0..255] (to do after
1138 | * unbias)
1139 | * -------------------------------------------------------------------------------
1140 | */
1141 |
1142 | var inxbuild = function inxbuild() {
1143 |
1144 | var i;
1145 | var j;
1146 | var smallpos;
1147 | var smallval;
1148 | var p;
1149 | var q;
1150 | var previouscol;
1151 | var startpos;
1152 |
1153 | previouscol = 0;
1154 | startpos = 0;
1155 | for (i = 0; i < netsize; i++) {
1156 |
1157 | p = network[i];
1158 | smallpos = i;
1159 | smallval = p[1]; /* index on g */
1160 |
1161 | /* find smallest in i..netsize-1 */
1162 | for (j = i + 1; j < netsize; j++) {
1163 |
1164 | q = network[j];
1165 | if (q[1] < smallval) { /* index on g */
1166 | smallpos = j;
1167 | smallval = q[1]; /* index on g */
1168 | }
1169 | }
1170 | q = network[smallpos];
1171 |
1172 | /* swap p (i) and q (smallpos) entries */
1173 | if (i != smallpos) {
1174 | j = q[0];
1175 | q[0] = p[0];
1176 | p[0] = j;
1177 | j = q[1];
1178 | q[1] = p[1];
1179 | p[1] = j;
1180 | j = q[2];
1181 | q[2] = p[2];
1182 | p[2] = j;
1183 | j = q[3];
1184 | q[3] = p[3];
1185 | p[3] = j;
1186 | }
1187 |
1188 | /* smallval entry is now in position i */
1189 |
1190 | if (smallval != previouscol) {
1191 |
1192 | netindex[previouscol] = (startpos + i) >> 1;
1193 |
1194 | for (j = previouscol + 1; j < smallval; j++) netindex[j] = i;
1195 |
1196 | previouscol = smallval;
1197 | startpos = i;
1198 | }
1199 | }
1200 |
1201 | netindex[previouscol] = (startpos + maxnetpos) >> 1;
1202 | for (j = previouscol + 1; j < 256; j++) netindex[j] = maxnetpos; /* really 256 */
1203 | };
1204 |
1205 | /*
1206 | * Main Learning Loop ------------------
1207 | */
1208 |
1209 | var learn = function learn() {
1210 |
1211 | var i;
1212 | var j;
1213 | var b;
1214 | var g;
1215 | var r;
1216 | var radius;
1217 | var rad;
1218 | var alpha;
1219 | var step;
1220 | var delta;
1221 | var samplepixels;
1222 | var p;
1223 | var pix;
1224 | var lim;
1225 |
1226 | if (lengthcount < minpicturebytes) samplefac = 1;
1227 |
1228 | alphadec = 30 + ((samplefac - 1) / 3);
1229 | p = thepicture;
1230 | pix = 0;
1231 | lim = lengthcount;
1232 | samplepixels = lengthcount / (3 * samplefac);
1233 | delta = (samplepixels / ncycles) | 0;
1234 | alpha = initalpha;
1235 | radius = initradius;
1236 |
1237 | rad = radius >> radiusbiasshift;
1238 | if (rad <= 1) rad = 0;
1239 |
1240 | for (i = 0; i < rad; i++) radpower[i] = alpha * (((rad * rad - i * i) * radbias) / (rad * rad));
1241 |
1242 | if (lengthcount < minpicturebytes) step = 3;
1243 |
1244 | else if ((lengthcount % prime1) !== 0) step = 3 * prime1;
1245 |
1246 | else {
1247 |
1248 | if ((lengthcount % prime2) !== 0) step = 3 * prime2;
1249 | else {
1250 | if ((lengthcount % prime3) !== 0) step = 3 * prime3;
1251 | else step = 3 * prime4;
1252 | }
1253 | }
1254 |
1255 | i = 0;
1256 | while (i < samplepixels) {
1257 |
1258 | b = (p[pix + 0] & 0xff) << netbiasshift;
1259 | g = (p[pix + 1] & 0xff) << netbiasshift;
1260 | r = (p[pix + 2] & 0xff) << netbiasshift;
1261 | j = contest(b, g, r);
1262 |
1263 | altersingle(alpha, j, b, g, r);
1264 | if (rad !== 0) alterneigh(rad, j, b, g, r); /* alter neighbours */
1265 |
1266 | pix += step;
1267 | if (pix >= lim) pix -= lengthcount;
1268 |
1269 | i++;
1270 |
1271 | if (delta === 0) delta = 1;
1272 |
1273 | if (i % delta === 0) {
1274 | alpha -= alpha / alphadec;
1275 | radius -= radius / radiusdec;
1276 | rad = radius >> radiusbiasshift;
1277 |
1278 | if (rad <= 1) rad = 0;
1279 |
1280 | for (j = 0; j < rad; j++) radpower[j] = alpha * (((rad * rad - j * j) * radbias) / (rad * rad));
1281 | }
1282 | }
1283 | };
1284 |
1285 | /*
1286 | ** Search for BGR values 0..255 (after net is unbiased) and return colour
1287 | * index
1288 | * ----------------------------------------------------------------------------
1289 | */
1290 |
1291 | var map = exports.map = function map(b, g, r) {
1292 |
1293 | var i;
1294 | var j;
1295 | var dist;
1296 | var a;
1297 | var bestd;
1298 | var p;
1299 | var best;
1300 |
1301 | bestd = 1000; /* biggest possible dist is 256*3 */
1302 | best = -1;
1303 | i = netindex[g]; /* index on g */
1304 | j = i - 1; /* start at netindex[g] and work outwards */
1305 |
1306 | while ((i < netsize) || (j >= 0)) {
1307 |
1308 | if (i < netsize) {
1309 | p = network[i];
1310 | dist = p[1] - g; /* inx key */
1311 |
1312 | if (dist >= bestd) i = netsize; /* stop iter */
1313 |
1314 | else {
1315 |
1316 | i++;
1317 | if (dist < 0) dist = -dist;
1318 | a = p[0] - b;
1319 | if (a < 0) a = -a;
1320 | dist += a;
1321 |
1322 | if (dist < bestd) {
1323 | a = p[2] - r;
1324 | if (a < 0) a = -a;
1325 | dist += a;
1326 |
1327 | if (dist < bestd) {
1328 | bestd = dist;
1329 | best = p[3];
1330 | }
1331 | }
1332 | }
1333 | }
1334 |
1335 | if (j >= 0) {
1336 |
1337 | p = network[j];
1338 | dist = g - p[1]; /* inx key - reverse dif */
1339 |
1340 | if (dist >= bestd) j = -1; /* stop iter */
1341 |
1342 | else {
1343 |
1344 | j--;
1345 | if (dist < 0) dist = -dist;
1346 | a = p[0] - b;
1347 | if (a < 0) a = -a;
1348 | dist += a;
1349 |
1350 | if (dist < bestd) {
1351 | a = p[2] - r;
1352 | if (a < 0) a = -a;
1353 | dist += a;
1354 | if (dist < bestd) {
1355 | bestd = dist;
1356 | best = p[3];
1357 | }
1358 | }
1359 | }
1360 | }
1361 | }
1362 |
1363 | return (best);
1364 | };
1365 |
1366 | var process = exports.process = function process() {
1367 | learn();
1368 | unbiasnet();
1369 | inxbuild();
1370 | return colorMap();
1371 | };
1372 |
1373 | /*
1374 | * Unbias network to give byte values 0..255 and record position i to prepare
1375 | * for sort
1376 | * -----------------------------------------------------------------------------------
1377 | */
1378 |
1379 | var unbiasnet = function unbiasnet() {
1380 |
1381 | var i;
1382 | var j;
1383 |
1384 | for (i = 0; i < netsize; i++) {
1385 | network[i][0] >>= netbiasshift;
1386 | network[i][1] >>= netbiasshift;
1387 | network[i][2] >>= netbiasshift;
1388 | network[i][3] = i; /* record colour no */
1389 | }
1390 | };
1391 |
1392 | /*
1393 | * Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in
1394 | * radpower[|i-j|]
1395 | * ---------------------------------------------------------------------------------
1396 | */
1397 |
1398 | var alterneigh = function alterneigh(rad, i, b, g, r) {
1399 |
1400 | var j;
1401 | var k;
1402 | var lo;
1403 | var hi;
1404 | var a;
1405 | var m;
1406 | var p;
1407 |
1408 | lo = i - rad;
1409 | if (lo < -1) lo = -1;
1410 |
1411 | hi = i + rad;
1412 | if (hi > netsize) hi = netsize;
1413 |
1414 | j = i + 1;
1415 | k = i - 1;
1416 | m = 1;
1417 |
1418 | while ((j < hi) || (k > lo)) {
1419 | a = radpower[m++];
1420 |
1421 | if (j < hi) {
1422 | p = network[j++];
1423 |
1424 | try {
1425 | p[0] -= (a * (p[0] - b)) / alpharadbias;
1426 | p[1] -= (a * (p[1] - g)) / alpharadbias;
1427 | p[2] -= (a * (p[2] - r)) / alpharadbias;
1428 | } catch (e) { } // prevents 1.3 miscompilation
1429 | }
1430 |
1431 | if (k > lo) {
1432 | p = network[k--];
1433 |
1434 | try {
1435 | p[0] -= (a * (p[0] - b)) / alpharadbias;
1436 | p[1] -= (a * (p[1] - g)) / alpharadbias;
1437 | p[2] -= (a * (p[2] - r)) / alpharadbias;
1438 | } catch (e) { }
1439 | }
1440 | }
1441 | };
1442 |
1443 | /*
1444 | * Move neuron i towards biased (b,g,r) by factor alpha
1445 | * ----------------------------------------------------
1446 | */
1447 |
1448 | var altersingle = function altersingle(alpha, i, b, g, r) {
1449 |
1450 | /* alter hit neuron */
1451 | var n = network[i];
1452 | n[0] -= (alpha * (n[0] - b)) / initalpha;
1453 | n[1] -= (alpha * (n[1] - g)) / initalpha;
1454 | n[2] -= (alpha * (n[2] - r)) / initalpha;
1455 | };
1456 |
1457 | /*
1458 | * Search for biased BGR values ----------------------------
1459 | */
1460 |
1461 | var contest = function contest(b, g, r) {
1462 |
1463 | /* finds closest neuron (min dist) and updates freq */
1464 | /* finds best neuron (min dist-bias) and returns position */
1465 | /* for frequently chosen neurons, freq[i] is high and bias[i] is negative */
1466 | /* bias[i] = gamma*((1/netsize)-freq[i]) */
1467 |
1468 | var i;
1469 | var dist;
1470 | var a;
1471 | var biasdist;
1472 | var betafreq;
1473 | var bestpos;
1474 | var bestbiaspos;
1475 | var bestd;
1476 | var bestbiasd;
1477 | var n;
1478 |
1479 | bestd = ~(1 << 31);
1480 | bestbiasd = bestd;
1481 | bestpos = -1;
1482 | bestbiaspos = bestpos;
1483 |
1484 | for (i = 0; i < netsize; i++) {
1485 | n = network[i];
1486 | dist = n[0] - b;
1487 | if (dist < 0) dist = -dist;
1488 | a = n[1] - g;
1489 | if (a < 0) a = -a;
1490 | dist += a;
1491 | a = n[2] - r;
1492 | if (a < 0) a = -a;
1493 | dist += a;
1494 |
1495 | if (dist < bestd) {
1496 | bestd = dist;
1497 | bestpos = i;
1498 | }
1499 |
1500 | biasdist = dist - ((bias[i]) >> (intbiasshift - netbiasshift));
1501 |
1502 | if (biasdist < bestbiasd) {
1503 | bestbiasd = biasdist;
1504 | bestbiaspos = i;
1505 | }
1506 |
1507 | betafreq = (freq[i] >> betashift);
1508 | freq[i] -= betafreq;
1509 | bias[i] += (betafreq << gammashift);
1510 | }
1511 |
1512 | freq[bestpos] += beta;
1513 | bias[bestpos] -= betagamma;
1514 | return (bestbiaspos);
1515 | };
1516 |
1517 | NeuQuant.apply(this, arguments);
1518 | return exports;
1519 | };
1520 |
1521 |
1522 | /***/ }
1523 | /******/ ])
1524 | });
1525 | ;
--------------------------------------------------------------------------------
/web_modules/sss/index.js:
--------------------------------------------------------------------------------
1 | (function webpackUniversalModuleDefinition(root, factory) {
2 | if(typeof exports === 'object' && typeof module === 'object')
3 | module.exports = factory();
4 | else if(typeof define === 'function' && define.amd)
5 | define([], factory);
6 | else if(typeof exports === 'object')
7 | exports["sss"] = factory();
8 | else
9 | root["sss"] = factory();
10 | })(this, function() {
11 | return /******/ (function(modules) { // webpackBootstrap
12 | /******/ // The module cache
13 | /******/ var installedModules = {};
14 |
15 | /******/ // The require function
16 | /******/ function __webpack_require__(moduleId) {
17 |
18 | /******/ // Check if module is in cache
19 | /******/ if(installedModules[moduleId])
20 | /******/ return installedModules[moduleId].exports;
21 |
22 | /******/ // Create a new module (and put it into the cache)
23 | /******/ var module = installedModules[moduleId] = {
24 | /******/ exports: {},
25 | /******/ id: moduleId,
26 | /******/ loaded: false
27 | /******/ };
28 |
29 | /******/ // Execute the module function
30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
31 |
32 | /******/ // Flag the module as loaded
33 | /******/ module.loaded = true;
34 |
35 | /******/ // Return the exports of the module
36 | /******/ return module.exports;
37 | /******/ }
38 |
39 |
40 | /******/ // expose the modules object (__webpack_modules__)
41 | /******/ __webpack_require__.m = modules;
42 |
43 | /******/ // expose the module cache
44 | /******/ __webpack_require__.c = installedModules;
45 |
46 | /******/ // __webpack_public_path__
47 | /******/ __webpack_require__.p = "/libs/";
48 |
49 | /******/ // Load entry module and return exports
50 | /******/ return __webpack_require__(0);
51 | /******/ })
52 | /************************************************************************/
53 | /******/ ([
54 | /* 0 */
55 | /***/ function(module, exports, __webpack_require__) {
56 |
57 | module.exports = __webpack_require__(2);
58 |
59 |
60 | /***/ },
61 | /* 1 */,
62 | /* 2 */
63 | /***/ function(module, exports, __webpack_require__) {
64 |
65 | "use strict";
66 | var __extends = (this && this.__extends) || function (d, b) {
67 | for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
68 | function __() { this.constructor = d; }
69 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
70 | };
71 | var jsfx = __webpack_require__(3);
72 | exports.Preset = jsfx.Preset;
73 | var live;
74 | var random;
75 | var buffers = {};
76 | var tracks = [];
77 | var schedulingInterval;
78 | var seed;
79 | var playPrefixes = {
80 | c: exports.Preset.Coin,
81 | l: exports.Preset.Laser,
82 | e: exports.Preset.Explosion,
83 | p: exports.Preset.Powerup,
84 | h: exports.Preset.Hit,
85 | j: exports.Preset.Jump,
86 | s: exports.Preset.Select,
87 | u: exports.Preset.Lucky,
88 | };
89 | var playprefixeArray = values(playPrefixes);
90 | var quantize = 0.5;
91 | var isEmptyPlayed = false;
92 | var prevPlayingFileName;
93 | function init(_seed, tempo, fps) {
94 | if (_seed === void 0) { _seed = 0; }
95 | if (tempo === void 0) { tempo = 120; }
96 | if (fps === void 0) { fps = 60; }
97 | live = jsfx.Live({});
98 | setVolume(0.1);
99 | seed = _seed;
100 | random = new Random();
101 | jsfx.setRandomFunc(random.get01);
102 | exports.playInterval = 60 / tempo;
103 | schedulingInterval = 1 / fps * 2;
104 | }
105 | exports.init = init;
106 | function setSeed(_seed) {
107 | if (_seed === void 0) { _seed = 0; }
108 | seed = _seed;
109 | }
110 | exports.setSeed = setSeed;
111 | function play(name, mult, params, volume) {
112 | if (name === void 0) { name = '0'; }
113 | if (mult === void 0) { mult = 2; }
114 | if (params === void 0) { params = null; }
115 | if (volume === void 0) { volume = null; }
116 | if (live == null) {
117 | return;
118 | }
119 | if (buffers[name] != null) {
120 | buffers[name].play(volume);
121 | return;
122 | }
123 | random.setSeed(seed + getHashFromString(name));
124 | if (params == null) {
125 | var p = playPrefixes[name[0]];
126 | if (typeof p === 'undefined') {
127 | p = random.sample(playprefixeArray);
128 | }
129 | params = nArray(mult, p);
130 | }
131 | buffers[name] = new Sound(params);
132 | buffers[name].play(volume);
133 | }
134 | exports.play = play;
135 | function setVolume(volume) {
136 | if (live == null) {
137 | return;
138 | }
139 | live._volume.gain.value = volume;
140 | }
141 | exports.setVolume = setVolume;
142 | function setQuantize(_quantize) {
143 | quantize = _quantize;
144 | }
145 | exports.setQuantize = setQuantize;
146 | function playBgm(name, interval, params, tracksNum, volume) {
147 | if (name === void 0) { name = '0'; }
148 | if (interval === void 0) { interval = 0.25; }
149 | if (params === void 0) { params = [exports.Preset.Laser, exports.Preset.Hit]; }
150 | if (tracksNum === void 0) { tracksNum = 8; }
151 | if (volume === void 0) { volume = null; }
152 | if (live == null) {
153 | return;
154 | }
155 | stopBgm();
156 | random.setSeed(seed + getHashFromString(name));
157 | tracks = [];
158 | times(tracksNum, function () { return addRandomTrack(interval, params); });
159 | forEach(tracks, function (t) { return t.play(volume); });
160 | }
161 | exports.playBgm = playBgm;
162 | function stopBgm() {
163 | if (live == null) {
164 | return;
165 | }
166 | forEach(tracks, function (t) { return t.stop(); });
167 | }
168 | exports.stopBgm = stopBgm;
169 | function update() {
170 | if (live == null) {
171 | return;
172 | }
173 | var currentTime = live._context.currentTime;
174 | var schedulingTime = currentTime + schedulingInterval;
175 | forOwn(buffers, function (b) { return b.update(currentTime, schedulingTime); });
176 | forEach(tracks, function (t) { return t.update(currentTime, schedulingTime); });
177 | return currentTime;
178 | }
179 | exports.update = update;
180 | function reset() {
181 | stopBgm();
182 | buffers = {};
183 | tracks = [];
184 | }
185 | exports.reset = reset;
186 | function playEmpty() {
187 | if (live == null) {
188 | return;
189 | }
190 | if (isEmptyPlayed) {
191 | return;
192 | }
193 | var eb = live._createEmptyBuffer();
194 | live._playBuffer(eb, 0);
195 | isEmptyPlayed = true;
196 | }
197 | exports.playEmpty = playEmpty;
198 | function playParam(param) {
199 | if (live == null) {
200 | return;
201 | }
202 | live._play(param);
203 | }
204 | exports.playParam = playParam;
205 | function addRandomTrack(interval, params) {
206 | addTrack(random.sample(params), createRandomPattern(), interval);
207 | }
208 | function createRandomPattern() {
209 | var len = 64;
210 | var pattern = nArray(len, false);
211 | var pi = 4;
212 | while (pi <= len) {
213 | pattern = reversePattern(pattern, pi);
214 | pi *= 2;
215 | }
216 | return pattern;
217 | }
218 | function reversePattern(pattern, interval) {
219 | var pt = nArray(interval, false);
220 | var pr = 0.5;
221 | for (var i = 0; i < interval / 2; i++) {
222 | if (random.f() < pr) {
223 | pt[random.i(interval - 1)] = true;
224 | }
225 | pr *= 0.5;
226 | }
227 | return map(pattern, function (p, i) { return pt[i % interval] ? !p : p; });
228 | }
229 | function addTrack(param, pattern, interval) {
230 | if (interval === void 0) { interval = 0.25; }
231 | var track = new Track(param);
232 | track.patternInterval = interval;
233 | if (typeof pattern === 'string') {
234 | track.pattern = mapString(pattern, function (p) { return p === '1'; });
235 | }
236 | else {
237 | track.pattern = pattern;
238 | }
239 | tracks.push(track);
240 | }
241 | exports.addTrack = addTrack;
242 | var Sound = (function () {
243 | function Sound(params) {
244 | this.isPlaying = false;
245 | this.playedTime = null;
246 | if (!Array.isArray(params)) {
247 | params = [params];
248 | }
249 | this.buffers = map(params, function (p) { return live._createBuffer(p); });
250 | this.gainNode = live._createGain();
251 | }
252 | Sound.prototype.play = function (volume) {
253 | if (volume === void 0) { volume = null; }
254 | this.isPlaying = true;
255 | this.volume = volume;
256 | };
257 | Sound.prototype.stop = function () {
258 | this.isPlaying = false;
259 | };
260 | Sound.prototype.update = function (currentTime, schedulingTime) {
261 | if (!this.isPlaying) {
262 | return;
263 | }
264 | this.isPlaying = false;
265 | var interval = exports.playInterval * quantize;
266 | var time = interval > 0 ?
267 | Math.ceil(currentTime / interval) * interval : currentTime;
268 | if (this.playedTime == null || time > this.playedTime) {
269 | this.playLater(time);
270 | this.playedTime = time;
271 | }
272 | };
273 | Sound.prototype.playLater = function (when) {
274 | var _this = this;
275 | if (this.volume == null) {
276 | forEach(this.buffers, function (b) { return live._playBuffer(b, when); });
277 | }
278 | else {
279 | this.gainNode.gain.value = this.volume;
280 | forEach(this.buffers, function (b) { return live._playBufferAndConnect(b, when, _this.gainNode); });
281 | }
282 | };
283 | return Sound;
284 | }());
285 | var Track = (function (_super) {
286 | __extends(Track, _super);
287 | function Track() {
288 | _super.apply(this, arguments);
289 | this.patternIndex = 0;
290 | this.patternInterval = 0.25;
291 | this.scheduledTime = null;
292 | }
293 | Track.prototype.update = function (currentTime, schedulingTime) {
294 | if (!this.isPlaying) {
295 | return;
296 | }
297 | if (this.scheduledTime == null) {
298 | this.calcFirstScheduledTime(currentTime);
299 | }
300 | for (var i = 0; i < 99; i++) {
301 | if (this.scheduledTime >= currentTime) {
302 | break;
303 | }
304 | this.calcNextScheduledTime();
305 | }
306 | if (this.scheduledTime < currentTime) {
307 | this.scheduledTime = null;
308 | }
309 | else {
310 | while (this.scheduledTime <= schedulingTime) {
311 | this.playLater(this.scheduledTime);
312 | this.calcNextScheduledTime();
313 | }
314 | }
315 | };
316 | Track.prototype.calcFirstScheduledTime = function (currentTime) {
317 | this.scheduledTime = Math.ceil(currentTime / exports.playInterval) * exports.playInterval -
318 | exports.playInterval * this.patternInterval;
319 | this.patternIndex = 0;
320 | this.calcNextScheduledTime();
321 | };
322 | Track.prototype.calcNextScheduledTime = function () {
323 | var pl = this.pattern.length;
324 | var pi = exports.playInterval * this.patternInterval;
325 | for (var i = 0; i < pl; i++) {
326 | this.scheduledTime += pi;
327 | var p = this.pattern[this.patternIndex];
328 | this.patternIndex++;
329 | if (this.patternIndex >= pl) {
330 | this.patternIndex = 0;
331 | }
332 | if (p) {
333 | break;
334 | }
335 | }
336 | };
337 | return Track;
338 | }(Sound));
339 | var Random = (function () {
340 | function Random() {
341 | this.setSeed();
342 | this.get01 = this.get01.bind(this);
343 | this.f = this.f.bind(this);
344 | this.i = this.i.bind(this);
345 | }
346 | Random.prototype.setSeed = function (v) {
347 | if (v === void 0) { v = -0x7fffffff; }
348 | if (v === -0x7fffffff) {
349 | v = Math.floor(Math.random() * 0x7fffffff);
350 | }
351 | this.x = v = 1812433253 * (v ^ (v >> 30));
352 | this.y = v = 1812433253 * (v ^ (v >> 30)) + 1;
353 | this.z = v = 1812433253 * (v ^ (v >> 30)) + 2;
354 | this.w = v = 1812433253 * (v ^ (v >> 30)) + 3;
355 | return this;
356 | };
357 | Random.prototype.f = function (minOrMax, max) {
358 | if (minOrMax === void 0) { minOrMax = null; }
359 | if (max === void 0) { max = null; }
360 | if (minOrMax == null) {
361 | return this.get01();
362 | }
363 | if (max == null) {
364 | return this.get01() * minOrMax;
365 | }
366 | return this.get01() * (max - minOrMax) + minOrMax;
367 | };
368 | Random.prototype.i = function (minOrMax, max) {
369 | if (minOrMax === void 0) { minOrMax = null; }
370 | if (max === void 0) { max = null; }
371 | return Math.floor(this.f(minOrMax, max + 1));
372 | };
373 | Random.prototype.sample = function (array) {
374 | return array[this.i(array.length - 1)];
375 | };
376 | Random.prototype.getInt = function () {
377 | var t = this.x ^ (this.x << 11);
378 | this.x = this.y;
379 | this.y = this.z;
380 | this.z = this.w;
381 | this.w = (this.w ^ (this.w >> 19)) ^ (t ^ (t >> 8));
382 | return this.w;
383 | };
384 | Random.prototype.get01 = function () {
385 | return this.getInt() / 0x7fffffff;
386 | };
387 | return Random;
388 | }());
389 | function getHashFromString(str) {
390 | var hash = 0;
391 | var len = str.length;
392 | for (var i = 0; i < len; i++) {
393 | var chr = str.charCodeAt(i);
394 | hash = ((hash << 5) - hash) + chr;
395 | hash |= 0;
396 | }
397 | return hash;
398 | }
399 | function values(obj) {
400 | var vs = [];
401 | for (var p in obj) {
402 | if (obj.hasOwnProperty(p)) {
403 | vs.push(obj[p]);
404 | }
405 | }
406 | return vs;
407 | }
408 | function nArray(n, v) {
409 | var a = [];
410 | for (var i = 0; i < n; i++) {
411 | a.push(v);
412 | }
413 | return a;
414 | }
415 | function times(n, func) {
416 | for (var i = 0; i < n; i++) {
417 | func();
418 | }
419 | }
420 | function forEach(array, func) {
421 | for (var i = 0; i < array.length; i++) {
422 | func(array[i]);
423 | }
424 | }
425 | function forOwn(obj, func) {
426 | for (var p in obj) {
427 | func(obj[p]);
428 | }
429 | }
430 | function map(array, func) {
431 | var result = [];
432 | for (var i = 0; i < array.length; i++) {
433 | result.push(func(array[i], i));
434 | }
435 | return result;
436 | }
437 | function mapString(str, func) {
438 | var result = [];
439 | for (var i = 0; i < str.length; i++) {
440 | result.push(func(str.charAt(i), i));
441 | }
442 | return result;
443 | }
444 |
445 |
446 | /***/ },
447 | /* 3 */
448 | /***/ function(module, exports) {
449 |
450 | // original ver.: https://github.com/loov/jsfx
451 | // these functions/variables are added by @abagames
452 | // - module.exports
453 | // - Live._createBuffer
454 | // - Live._createEmptyBuffer
455 | // - Live._playBuffer
456 | // - Live._playBufferAndConnect
457 | // - Live._createGain
458 | // - setRandomFunc
459 | // - webkitAudioContext
460 | var jsfx = {};
461 | (function (jsfx) {
462 | 'use strict';
463 |
464 | var chr = String.fromCharCode;
465 | var TAU = +Math.PI * 2;
466 | var bitsPerSample = 16 | 0;
467 | var numChannels = 1 | 0;
468 | var sin = Math.sin;
469 | var pow = Math.pow;
470 | var abs = Math.abs;
471 | var EPSILON = 0.000001;
472 |
473 | jsfx.SampleRate = 0 | 0;
474 | jsfx.Sec = 0 | 0;
475 |
476 | jsfx.SetSampleRate = function (sampleRate) {
477 | jsfx.SampleRate = sampleRate | 0;
478 | jsfx.Sec = sampleRate | 0;
479 | };
480 | jsfx.SetSampleRate(getDefaultSampleRate());
481 |
482 | // MAIN API
483 |
484 | // Creates a new Audio object based on the params
485 | // params can be a params generating function or the actual parameters
486 | jsfx.Sound = function (params) {
487 | var processor = new Processor(params, jsfx.DefaultModules);
488 | var block = createFloatArray(processor.getSamplesLeft());
489 | processor.generate(block);
490 | return CreateAudio(block);
491 | };
492 |
493 | // Same as Sounds, but avoids locking the browser for too long
494 | // in case you have a large amount of sounds to generate
495 | jsfx.Sounds = function (library, ondone, onprogress) {
496 | var audio = {};
497 | var player = {};
498 | player._audio = audio;
499 |
500 | var toLoad = [];
501 |
502 | // create playing functions
503 | map_object(library, function (_, name) {
504 | player[name] = function () {
505 | if (typeof audio[name] !== "undefined") {
506 | audio[name].currentTime = 0.0;
507 | audio[name].play();
508 | }
509 | };
510 | toLoad.push(name);
511 | });
512 |
513 | var loaded = 0, total = toLoad.length;
514 | function next() {
515 | if (toLoad.length == 0) {
516 | ondone && ondone(sounds);
517 | return;
518 | }
519 | var name = toLoad.shift();
520 | audio[name] = jsfx.Sound(library[name]);
521 | loaded++;
522 | onprogress && onprogress(name, loaded, total);
523 |
524 | window.setTimeout(next, 30);
525 | }
526 | next();
527 |
528 | return player;
529 | }
530 |
531 | // SoundsImmediate takes a named set of params, and generates multiple
532 | // sound objects at once.
533 | jsfx.SoundsImmediate = function (library) {
534 | var audio = {};
535 | var player = {};
536 | player._audio = audio;
537 | map_object(library, function (params, name) {
538 | audio[name] = jsfx.Sound(params);
539 | player[name] = function () {
540 | if (typeof audio[name] !== "undefined") {
541 | audio[name].currentTime = 0.0;
542 | audio[name].play();
543 | }
544 | };
545 | })
546 | return player;
547 | };
548 |
549 | var AudioContext = window.AudioContext || window.webkitAudioContext;
550 | if (typeof AudioContext !== "undefined") {
551 | // Node creates a new AudioContext ScriptProcessor that outputs the
552 | // sound. It will automatically disconnect, unless otherwise specified.
553 | jsfx.Node = function (audioContext, params, modules, bufferSize, stayConnected) {
554 | var node = audioContext.createScriptProcessor(bufferSize, 0, 1);
555 | var gen = new Processor(params, modules || jsfx.DefaultModules);
556 | node.onaudioprocess = function (ev) {
557 | var block = ev.outputBuffer.getChannelData(0);
558 | gen.generate(block);
559 | if (!stayConnected && gen.finished) {
560 | // we need to do an async disconnect, otherwise Chrome may
561 | // glitch
562 | setTimeout(function () { node.disconnect(); }, 30);
563 | }
564 | }
565 | return node;
566 | }
567 |
568 | // Live creates an managed AudioContext for playing.
569 | // This is useful, when you want to use procedurally generated sounds.
570 | jsfx.Live = function (library, modules, BufferSize) {
571 | //TODO: add limit for number of notes played at the same time
572 | BufferSize = BufferSize || 2048;
573 | var player = {};
574 |
575 | var context = new AudioContext();
576 | var volume = context.createGain();
577 | volume.connect(context.destination);
578 |
579 | player._context = context;
580 | player._volume = volume;
581 |
582 | map_object(library, function (params, name) {
583 | player[name] = function () {
584 | var node = jsfx.Node(context, params, modules, BufferSize);
585 | node.connect(volume);
586 | };
587 | });
588 |
589 | player._close = function () {
590 | context.close();
591 | };
592 |
593 | player._play = function (params) {
594 | var node = jsfx.Node(context, params, modules, BufferSize);
595 | node.connect(volume);
596 | };
597 |
598 | player._createBuffer = function (params) {
599 | var processor = new Processor(params, jsfx.DefaultModules);
600 | var block = createFloatArray(processor.getSamplesLeft());
601 | processor.generate(block);
602 | return player._createBufferFromBlock(block);
603 | }
604 |
605 | player._createEmptyBuffer = function () {
606 | return player._createBufferFromBlock([0]);
607 | }
608 |
609 | player._createBufferFromBlock = function (block) {
610 | var buffer = context.createBuffer(1, block.length, jsfx.SampleRate);
611 | var channelData = buffer.getChannelData(0);
612 | channelData.set(block);
613 | return buffer;
614 | }
615 |
616 | function createBufferSource(buffer, when) {
617 | var bufSrc = context.createBufferSource();
618 | bufSrc.buffer = buffer;
619 | bufSrc.start = bufSrc.start || bufSrc.noteOn;
620 | bufSrc.start(when);
621 | bufSrc.onended = function () {
622 | bufSrc.disconnect();
623 | };
624 | return bufSrc;
625 | }
626 |
627 | player._playBuffer = function (buffer, when) {
628 | var bufSrc = createBufferSource(buffer, when);
629 | bufSrc.connect(volume);
630 | }
631 |
632 | player._playBufferAndConnect = function (buffer, when, node) {
633 | var bufSrc = createBufferSource(buffer, when);
634 | bufSrc.connect(node);
635 | node.connect(volume);
636 | };
637 |
638 | player._createGain = function () {
639 | return context.createGain();
640 | }
641 |
642 | return player;
643 | }
644 | } else {
645 | //jsfx.Live = jsfx.Sounds;
646 | jsfx.Live = function (library, modules, BufferSize) {
647 | return null;
648 | };
649 | }
650 |
651 | // SOUND GENERATION
652 | jsfx.Module = {};
653 |
654 | // generators
655 | jsfx.G = {};
656 |
657 | var stage = jsfx.stage = {
658 | PhaseSpeed: 0,
659 | PhaseSpeedMod: 10,
660 | Generator: 20,
661 | SampleMod: 30,
662 | Volume: 40
663 | };
664 | function byStage(a, b) { return a.stage - b.stage; }
665 |
666 | jsfx.InitDefaultParams = InitDefaultParams;
667 | function InitDefaultParams(params, modules) {
668 | // setup modules
669 | for (var i = 0; i < modules.length; i += 1) {
670 | var M = modules[i];
671 | var P = params[M.name] || {};
672 |
673 | // add missing parameters
674 | map_object(M.params, function (def, name) {
675 | if (typeof P[name] === 'undefined') {
676 | P[name] = def.D;
677 | }
678 | });
679 |
680 | params[M.name] = P;
681 | }
682 | }
683 |
684 | // Generates a stateful sound effect processor
685 | // params can be a function that creates a parameter set
686 | jsfx.Processor = Processor;
687 | function Processor(params, modules) {
688 | params = params || {};
689 | modules = modules || jsfx.DefaultModules;
690 |
691 | if (typeof params === 'function') {
692 | params = params();
693 | } else {
694 | params = JSON.parse(JSON.stringify(params))
695 | }
696 | this.finished = false;
697 |
698 | this.state = {
699 | SampleRate: params.SampleRate || jsfx.SampleRate
700 | };
701 |
702 | // sort modules
703 | modules = modules.slice();
704 | modules.sort(byStage)
705 | this.modules = modules;
706 |
707 | // init missing params
708 | InitDefaultParams(params, modules);
709 |
710 | // setup modules
711 | for (var i = 0; i < this.modules.length; i += 1) {
712 | var M = this.modules[i];
713 | this.modules[i].setup(this.state, params[M.name]);
714 | }
715 | }
716 | Processor.prototype = {
717 | //TODO: see whether this can be converted to a module
718 | generate: function (block) {
719 | for (var i = 0 | 0; i < block.length; i += 1) {
720 | block[i] = 0;
721 | }
722 | if (this.finished) { return; }
723 |
724 | var $ = this.state,
725 | N = block.length | 0;
726 | for (var i = 0; i < this.modules.length; i += 1) {
727 | var M = this.modules[i];
728 | var n = M.process($, block.subarray(0, N)) | 0;
729 | N = Math.min(N, n);
730 | }
731 | if (N < block.length) {
732 | this.finished = true;
733 | }
734 | for (var i = N; i < block.length; i++) {
735 | block[i] = 0;
736 | }
737 | },
738 | getSamplesLeft: function () {
739 | var samples = 0;
740 | for (var i = 0; i < this.state.envelopes.length; i += 1) {
741 | samples += this.state.envelopes[i].N;
742 | }
743 | if (samples === 0) {
744 | samples = 3 * this.state.SampleRate;
745 | }
746 | return samples;
747 | }
748 | };
749 |
750 | // Frequency
751 | jsfx.Module.Frequency = {
752 | name: 'Frequency',
753 | params: {
754 | Start: { L: 30, H: 1800, D: 440 },
755 |
756 | Min: { L: 30, H: 1800, D: 30 },
757 | Max: { L: 30, H: 1800, D: 1800 },
758 |
759 | Slide: { L: -1, H: 1, D: 0 },
760 | DeltaSlide: { L: -1, H: 1, D: 0 },
761 |
762 | RepeatSpeed: { L: 0, H: 3.0, D: 0 },
763 |
764 | ChangeAmount: { L: -12, H: 12, D: 0 },
765 | ChangeSpeed: { L: 0, H: 1, D: 0 }
766 | },
767 | stage: stage.PhaseSpeed,
768 | setup: function ($, P) {
769 | var SR = $.SampleRate;
770 |
771 | $.phaseParams = P;
772 |
773 | $.phaseSpeed = P.Start * TAU / SR;
774 | $.phaseSpeedMax = P.Max * TAU / SR;
775 | $.phaseSpeedMin = P.Min * TAU / SR;
776 |
777 | $.phaseSpeedMin = Math.min($.phaseSpeedMin, $.phaseSpeed);
778 | $.phaseSpeedMax = Math.max($.phaseSpeedMax, $.phaseSpeed);
779 |
780 | $.phaseSlide = 1.0 + pow(P.Slide, 3.0) * 64.0 / SR;
781 | $.phaseDeltaSlide = pow(P.DeltaSlide, 3.0) / (SR * 1000);
782 |
783 | $.repeatTime = 0;
784 | $.repeatLimit = Infinity;
785 | if (P.RepeatSpeed > 0) {
786 | $.repeatLimit = P.RepeatSpeed * SR;
787 | }
788 |
789 | $.arpeggiatorTime = 0;
790 | $.arpeggiatorLimit = P.ChangeSpeed * SR;
791 | if (P.ChangeAmount == 0) {
792 | $.arpeggiatorLimit = Infinity;
793 | }
794 | $.arpeggiatorMod = 1 + P.ChangeAmount / 12.0;
795 | },
796 | process: function ($, block) {
797 | var speed = +$.phaseSpeed,
798 | min = +$.phaseSpeedMin,
799 | max = +$.phaseSpeedMax,
800 | slide = +$.phaseSlide,
801 | deltaSlide = +$.phaseDeltaSlide;
802 |
803 | var repeatTime = $.repeatTime,
804 | repeatLimit = $.repeatLimit;
805 |
806 | var arpTime = $.arpeggiatorTime,
807 | arpLimit = $.arpeggiatorLimit,
808 | arpMod = $.arpeggiatorMod;
809 |
810 | for (var i = 0; i < block.length; i++) {
811 | slide += deltaSlide;
812 | speed *= slide;
813 | speed = speed < min ? min : speed > max ? max : speed;
814 |
815 | if (repeatTime > repeatLimit) {
816 | this.setup($, $.phaseParams);
817 | return i + this.process($, block.subarray(i)) - 1;
818 | }
819 | repeatTime++;
820 |
821 | if (arpTime > arpLimit) {
822 | speed *= arpMod;
823 | arpTime = 0;
824 | arpLimit = Infinity;
825 | }
826 | arpTime++;
827 |
828 | block[i] += speed;
829 | }
830 |
831 | $.repeatTime = repeatTime;
832 | $.arpeggiatorTime = arpTime;
833 | $.arpeggiatorLimit = arpLimit;
834 |
835 | $.phaseSpeed = speed;
836 | $.phaseSlide = slide;
837 |
838 | return block.length;
839 | }
840 | };
841 |
842 | // Vibrato
843 | jsfx.Module.Vibrato = {
844 | name: 'Vibrato',
845 | params: {
846 | Depth: { L: 0, H: 1, D: 0 },
847 | DepthSlide: { L: -1, H: 1, D: 0 },
848 |
849 | Frequency: { L: 0.01, H: 48, D: 0 },
850 | FrequencySlide: { L: -1.00, H: 1, D: 0 }
851 | },
852 | stage: stage.PhaseSpeedMod,
853 | setup: function ($, P) {
854 | var SR = $.SampleRate;
855 | $.vibratoPhase = 0;
856 | $.vibratoDepth = P.Depth;
857 | $.vibratoPhaseSpeed = P.Frequency * TAU / SR;
858 |
859 | $.vibratoPhaseSpeedSlide = 1.0 + pow(P.FrequencySlide, 3.0) * 3.0 / SR;
860 | $.vibratoDepthSlide = P.DepthSlide / SR;
861 | },
862 | process: function ($, block) {
863 | var phase = +$.vibratoPhase,
864 | depth = +$.vibratoDepth,
865 | speed = +$.vibratoPhaseSpeed,
866 | slide = +$.vibratoPhaseSpeedSlide,
867 | depthSlide = +$.vibratoDepthSlide;
868 |
869 | if ((depth == 0) && (depthSlide <= 0)) {
870 | return block.length;
871 | }
872 |
873 | for (var i = 0; i < block.length; i++) {
874 | phase += speed;
875 | if (phase > TAU) { phase -= TAU };
876 | block[i] += block[i] * sin(phase) * depth;
877 |
878 | speed *= slide;
879 | depth += depthSlide;
880 | depth = clamp1(depth);
881 | }
882 |
883 | $.vibratoPhase = phase;
884 | $.vibratoDepth = depth;
885 | $.vibratoPhaseSpeed = speed;
886 | return block.length;
887 | }
888 | };
889 |
890 | // Generator
891 | jsfx.Module.Generator = {
892 | name: 'Generator',
893 | params: {
894 | // C = choose
895 | Func: { C: jsfx.G, D: 'square' },
896 |
897 | A: { L: 0, H: 1, D: 0 },
898 | B: { L: 0, H: 1, D: 0 },
899 |
900 | ASlide: { L: -1, H: 1, D: 0 },
901 | BSlide: { L: -1, H: 1, D: 0 }
902 | },
903 | stage: stage.Generator,
904 | setup: function ($, P) {
905 | $.generatorPhase = 0;
906 |
907 | if (typeof P.Func === 'string') {
908 | $.generator = jsfx.G[P.Func];
909 | } else {
910 | $.generator = P.Func;
911 | }
912 | if (typeof $.generator === 'object') {
913 | $.generator = $.generator.create();
914 | }
915 | assert(typeof $.generator === 'function', 'generator must be a function')
916 |
917 | $.generatorA = P.A;
918 | $.generatorASlide = P.ASlide;
919 | $.generatorB = P.B;
920 | $.generatorBSlide = P.BSlide;
921 | },
922 | process: function ($, block) {
923 | return $.generator($, block);
924 | }
925 | };
926 |
927 | // Karplus Strong algorithm for string sound
928 | var GuitarBufferSize = 1 << 16;
929 | jsfx.Module.Guitar = {
930 | name: 'Guitar',
931 | params: {
932 | A: { L: 0.0, H: 1.0, D: 1 },
933 | B: { L: 0.0, H: 1.0, D: 1 },
934 | C: { L: 0.0, H: 1.0, D: 1 },
935 | },
936 | stage: stage.Generator,
937 | setup: function ($, P) {
938 | $.guitarA = P.A;
939 | $.guitarB = P.B;
940 | $.guitarC = P.C;
941 |
942 | $.guitarBuffer = createFloatArray(GuitarBufferSize);
943 | $.guitarHead = 0;
944 | var B = $.guitarBuffer;
945 | for (var i = 0; i < B.length; i++) {
946 | B[i] = random() * 2 - 1;
947 | }
948 | },
949 | process: function ($, block) {
950 | var BS = GuitarBufferSize,
951 | BM = BS - 1;
952 |
953 | var A = +$.guitarA, B = +$.guitarB, C = +$.guitarC;
954 | var T = A + B + C;
955 | var h = $.guitarHead;
956 |
957 | var buffer = $.guitarBuffer;
958 | for (var i = 0; i < block.length; i++) {
959 | // buffer size
960 | var n = (TAU / block[i]) | 0;
961 | n = n > BS ? BS : n;
962 |
963 | // tail
964 | var t = ((h - n) + BS) & BM;
965 | buffer[h] =
966 | (buffer[(t - 0 + BS) & BM] * A +
967 | buffer[(t - 1 + BS) & BM] * B +
968 | buffer[(t - 2 + BS) & BM] * C) / T;
969 |
970 | block[i] = buffer[h];
971 | h = (h + 1) & BM;
972 | }
973 |
974 | $.guitarHead = h;
975 | return block.length;
976 | }
977 | }
978 |
979 | // Low/High-Pass Filter
980 | jsfx.Module.Filter = {
981 | name: 'Filter',
982 | params: {
983 | LP: { L: 0, H: 1, D: 1 },
984 | LPSlide: { L: -1, H: 1, D: 0 },
985 | LPResonance: { L: 0, H: 1, D: 0 },
986 | HP: { L: 0, H: 1, D: 0 },
987 | HPSlide: { L: -1, H: 1, D: 0 }
988 | },
989 | stage: stage.SampleMod + 0,
990 | setup: function ($, P) {
991 | $.FilterEnabled = (P.HP > EPSILON) || (P.LP < 1 - EPSILON);
992 |
993 | $.LPEnabled = P.LP < 1 - EPSILON;
994 | $.LP = pow(P.LP, 3.0) / 10;
995 | $.LPSlide = 1.0 + P.LPSlide * 100 / $.SampleRate;
996 | $.LPPos = 0;
997 | $.LPPosSlide = 0;
998 |
999 | $.LPDamping = 5.0 / (1.0 + pow(P.LPResonance, 2) * 20) * (0.01 + P.LP);
1000 | $.LPDamping = 1.0 - Math.min($.LPDamping, 0.8);
1001 |
1002 | $.HP = pow(P.HP, 2.0) / 10;
1003 | $.HPPos = 0;
1004 | $.HPSlide = 1.0 + P.HPSlide * 100 / $.SampleRate;
1005 | },
1006 | enabled: function ($) {
1007 | return $.FilterEnabled;
1008 | },
1009 | process: function ($, block) {
1010 | if (!this.enabled($)) { return block.length; }
1011 |
1012 | var lp = +$.LP;
1013 | var lpPos = +$.LPPos;
1014 | var lpPosSlide = +$.LPPosSlide;
1015 | var lpSlide = +$.LPSlide;
1016 | var lpDamping = +$.LPDamping;
1017 | var lpEnabled = +$.LPEnabled;
1018 |
1019 | var hp = +$.HP;
1020 | var hpPos = +$.HPPos;
1021 | var hpSlide = +$.HPSlide;
1022 |
1023 | for (var i = 0; i < block.length; i++) {
1024 | if ((hp > EPSILON) || (hp < -EPSILON)) {
1025 | hp *= hpSlide;
1026 | hp = hp < EPSILON ? EPSILON : hp > 0.1 ? 0.1 : hp;
1027 | }
1028 |
1029 | var lpPos_ = lpPos;
1030 |
1031 | lp *= lpSlide;
1032 | lp = lp < 0 ? lp = 0 : lp > 0.1 ? 0.1 : lp;
1033 |
1034 | var sample = block[i];
1035 | if (lpEnabled) {
1036 | lpPosSlide += (sample - lpPos) * lp;
1037 | lpPosSlide *= lpDamping;
1038 | } else {
1039 | lpPos = sample;
1040 | lpPosSlide = 0;
1041 | }
1042 | lpPos += lpPosSlide;
1043 |
1044 | hpPos += lpPos - lpPos_;
1045 | hpPos *= 1.0 - hp;
1046 |
1047 | block[i] = hpPos;
1048 | }
1049 |
1050 | $.LPPos = lpPos;
1051 | $.LPPosSlide = lpPosSlide;
1052 | $.LP = lp;
1053 | $.HP = hp;
1054 | $.HPPos = hpPos;
1055 |
1056 | return block.length;
1057 | }
1058 | };
1059 |
1060 | // Phaser Effect
1061 | var PhaserBufferSize = 1 << 10;
1062 | jsfx.Module.Phaser = {
1063 | name: 'Phaser',
1064 | params: {
1065 | Offset: { L: -1, H: 1, D: 0 },
1066 | Sweep: { L: -1, H: 1, D: 0 }
1067 | },
1068 | stage: stage.SampleMod + 1,
1069 | setup: function ($, P) {
1070 | $.phaserBuffer = createFloatArray(PhaserBufferSize);
1071 | $.phaserPos = 0;
1072 | $.phaserOffset = pow(P.Offset, 2.0) * (PhaserBufferSize - 4);
1073 | $.phaserOffsetSlide = pow(P.Sweep, 3.0) * 4000 / $.SampleRate;
1074 | },
1075 | enabled: function ($) {
1076 | return (abs($.phaserOffsetSlide) > EPSILON) ||
1077 | (abs($.phaserOffset) > EPSILON);
1078 | },
1079 | process: function ($, block) {
1080 | if (!this.enabled($)) { return block.length; }
1081 |
1082 | var BS = PhaserBufferSize,
1083 | BM = BS - 1;
1084 |
1085 | var buffer = $.phaserBuffer,
1086 | pos = $.phaserPos | 0,
1087 | offset = +$.phaserOffset,
1088 | offsetSlide = +$.phaserOffsetSlide;
1089 |
1090 | for (var i = 0; i < block.length; i++) {
1091 | offset += offsetSlide;
1092 | //TODO: check whether this is correct
1093 | if (offset < 0) {
1094 | offset = -offset;
1095 | offsetSlide = -offsetSlide;
1096 | }
1097 | if (offset > BM) {
1098 | offset = BM;
1099 | offsetSlide = 0;
1100 | }
1101 |
1102 | buffer[pos] = block[i];
1103 | var p = (pos - (offset | 0) + BS) & BM;
1104 | block[i] += buffer[p];
1105 |
1106 | pos = ((pos + 1) & BM) | 0;
1107 | }
1108 |
1109 | $.phaserPos = pos;
1110 | $.phaserOffset = offset;
1111 | return block.length;
1112 | }
1113 | };
1114 |
1115 | // Volume dynamic control with Attack-Sustain-Decay
1116 | // ATTACK | 0 - Volume + Punch
1117 | // SUSTAIN | Volume + Punch - Volume
1118 | // DECAY | Volume - 0
1119 | jsfx.Module.Volume = {
1120 | name: 'Volume',
1121 | params: {
1122 | Master: { L: 0, H: 1, D: 0.5 },
1123 | Attack: { L: 0.001, H: 1, D: 0.01 },
1124 | Sustain: { L: 0, H: 2, D: 0.3 },
1125 | Punch: { L: 0, H: 3, D: 1.0 },
1126 | Decay: { L: 0.001, H: 2, D: 1.0 }
1127 | },
1128 | stage: stage.Volume,
1129 | setup: function ($, P) {
1130 | var SR = $.SampleRate;
1131 | var V = P.Master;
1132 | var VP = V * (1 + P.Punch);
1133 | $.envelopes = [
1134 | // S = start volume, E = end volume, N = duration in samples
1135 | { S: 0, E: V, N: (P.Attack * SR) | 0 }, // Attack
1136 | { S: VP, E: V, N: (P.Sustain * SR) | 0 }, // Sustain
1137 | { S: V, E: 0, N: (P.Decay * SR) | 0 } // Decay
1138 | ];
1139 | // G = volume gradient
1140 | for (var i = 0; i < $.envelopes.length; i += 1) {
1141 | var e = $.envelopes[i];
1142 | e.G = (e.E - e.S) / e.N;
1143 | }
1144 | },
1145 | process: function ($, block) {
1146 | var i = 0;
1147 | while (($.envelopes.length > 0) && (i < block.length)) {
1148 | var E = $.envelopes[0];
1149 | var vol = E.S,
1150 | grad = E.G;
1151 |
1152 | var N = Math.min(block.length - i, E.N) | 0;
1153 | var end = (i + N) | 0;
1154 | for (; i < end; i += 1) {
1155 | block[i] *= vol;
1156 | vol += grad;
1157 | vol = clamp(vol, 0, 10);
1158 | }
1159 | E.S = vol;
1160 | E.N -= N;
1161 | if (E.N <= 0) {
1162 | $.envelopes.shift();
1163 | }
1164 | }
1165 | return i;
1166 | }
1167 | };
1168 |
1169 | // PRESETS
1170 |
1171 | jsfx.DefaultModules = [
1172 | jsfx.Module.Frequency,
1173 | jsfx.Module.Vibrato,
1174 | jsfx.Module.Generator,
1175 | jsfx.Module.Filter,
1176 | jsfx.Module.Phaser,
1177 | jsfx.Module.Volume
1178 | ];
1179 | jsfx.DefaultModules.sort(byStage);
1180 |
1181 | jsfx.EmptyParams = EmptyParams;
1182 | function EmptyParams() {
1183 | return map_object(jsfx.Module, function () { return {} });
1184 | }
1185 |
1186 | jsfx._RemoveEmptyParams = RemoveEmptyParams;
1187 | function RemoveEmptyParams(params) {
1188 | for (var name in params) {
1189 | if (Object_keys(params[name]).length == 0) {
1190 | delete params[name];
1191 | }
1192 | }
1193 | };
1194 |
1195 | jsfx.Preset = {
1196 | Reset: function () {
1197 | return EmptyParams();
1198 | },
1199 | Coin: function () {
1200 | var p = EmptyParams();
1201 | p.Frequency.Start = runif(880, 660);
1202 | p.Volume.Sustain = runif(0.1);
1203 | p.Volume.Decay = runif(0.4, 0.1);
1204 | p.Volume.Punch = runif(0.3, 0.3);
1205 | if (runif() < 0.5) {
1206 | p.Frequency.ChangeSpeed = runif(0.15, 0.1);
1207 | p.Frequency.ChangeAmount = runif(8, 4);
1208 | }
1209 | RemoveEmptyParams(p);
1210 | return p;
1211 | },
1212 | Laser: function () {
1213 | var p = EmptyParams();
1214 | p.Generator.Func = rchoose(['square', 'saw', 'sine']);
1215 |
1216 | if (runif() < 0.33) {
1217 | p.Frequency.Start = runif(880, 440);
1218 | p.Frequency.Min = runif(0.1);
1219 | p.Frequency.Slide = runif(0.3, -0.8);
1220 | } else {
1221 | p.Frequency.Start = runif(1200, 440);
1222 | p.Frequency.Min = p.Frequency.Start - runif(880, 440);
1223 | if (p.Frequency.Min < 110) { p.Frequency.Min = 110; }
1224 | p.Frequency.Slide = runif(0.3, -1);
1225 | }
1226 |
1227 | if (runif() < 0.5) {
1228 | p.Generator.A = runif(0.5);
1229 | p.Generator.ASlide = runif(0.2);
1230 | } else {
1231 | p.Generator.A = runif(0.5, 0.4);
1232 | p.Generator.ASlide = runif(0.7);
1233 | }
1234 |
1235 | p.Volume.Sustain = runif(0.2, 0.1);
1236 | p.Volume.Decay = runif(0.4);
1237 | if (runif() < 0.5) {
1238 | p.Volume.Punch = runif(0.3);
1239 | }
1240 | if (runif() < 0.33) {
1241 | p.Phaser.Offset = runif(0.2);
1242 | p.Phaser.Sweep = runif(0.2);
1243 | }
1244 | if (runif() < 0.5) {
1245 | p.Filter.HP = runif(0.3);
1246 | }
1247 | RemoveEmptyParams(p);
1248 | return p;
1249 | },
1250 | Explosion: function () {
1251 | var p = EmptyParams();
1252 | p.Generator.Func = 'noise';
1253 | if (runif() < 0.5) {
1254 | p.Frequency.Start = runif(440, 40);
1255 | p.Frequency.Slide = runif(0.4, -0.1);
1256 | } else {
1257 | p.Frequency.Start = runif(1600, 220);
1258 | p.Frequency.Slide = runif(-0.2, -0.2);
1259 | }
1260 |
1261 | if (runif() < 0.2) { p.Frequency.Slide = 0; }
1262 | if (runif() < 0.3) { p.Frequency.RepeatSpeed = runif(0.5, 0.3); }
1263 |
1264 | p.Volume.Sustain = runif(0.3, 0.1);
1265 | p.Volume.Decay = runif(0.5);
1266 | p.Volume.Punch = runif(0.6, 0.2);
1267 |
1268 | if (runif() < 0.5) {
1269 | p.Phaser.Offset = runif(0.9, -0.3);
1270 | p.Phaser.Sweep = runif(-0.3);
1271 | }
1272 |
1273 | if (runif() < 0.33) {
1274 | p.Frequency.ChangeSpeed = runif(0.3, 0.6);
1275 | p.Frequency.ChangeAmount = runif(24, -12);
1276 | }
1277 | RemoveEmptyParams(p);
1278 | return p;
1279 | },
1280 | Powerup: function () {
1281 | var p = EmptyParams();
1282 | if (runif() < 0.5) {
1283 | p.Generator.Func = 'saw';
1284 | } else {
1285 | p.Generator.A = runif(0.6);
1286 | }
1287 |
1288 | p.Frequency.Start = runif(220, 440);
1289 | if (runif() < 0.5) {
1290 | p.Frequency.Slide = runif(0.5, 0.2);
1291 | p.Frequency.RepeatSpeed = runif(0.4, 0.4);
1292 | } else {
1293 | p.Frequency.Slide = runif(0.2, 0.05);
1294 | if (runif() < 0.5) {
1295 | p.Vibrato.Depth = runif(0.6, 0.1);
1296 | p.Vibrato.Frequency = runif(30, 10);
1297 | }
1298 | }
1299 |
1300 | p.Volume.Sustain = runif(0.4);
1301 | p.Volume.Decay = runif(0.4, 0.1);
1302 |
1303 | RemoveEmptyParams(p);
1304 | return p;
1305 | },
1306 | Hit: function () {
1307 | var p = EmptyParams();
1308 | p.Generator.Func = rchoose(['square', 'saw', 'noise']);
1309 | p.Generator.A = runif(0.6);
1310 | p.Generator.ASlide = runif(1, -0.5);
1311 |
1312 | p.Frequency.Start = runif(880, 220);
1313 | p.Frequency.Slide = -runif(0.4, 0.3);
1314 |
1315 | p.Volume.Sustain = runif(0.1);
1316 | p.Volume.Decay = runif(0.2, 0.1);
1317 |
1318 | if (runif() < 0.5) {
1319 | p.Filter.HP = runif(0.3);
1320 | }
1321 |
1322 | RemoveEmptyParams(p);
1323 | return p;
1324 | },
1325 | Jump: function () {
1326 | var p = EmptyParams();
1327 | p.Generator.Func = 'square';
1328 | p.Generator.A = runif(0.6);
1329 |
1330 | p.Frequency.Start = runif(330, 330);
1331 | p.Frequency.Slide = runif(0.4, 0.2);
1332 |
1333 | p.Volume.Sustain = runif(0.3, 0.1);
1334 | p.Volume.Decay = runif(0.2, 0.1);
1335 |
1336 | if (runif() < 0.5) {
1337 | p.Filter.HP = runif(0.3);
1338 | }
1339 | if (runif() < 0.3) {
1340 | p.Filter.LP = runif(-0.6, 1);
1341 | }
1342 |
1343 | RemoveEmptyParams(p);
1344 | return p;
1345 | },
1346 | Select: function () {
1347 | var p = EmptyParams();
1348 | p.Generator.Func = rchoose(['square', 'saw']);
1349 | p.Generator.A = runif(0.6);
1350 |
1351 | p.Frequency.Start = runif(660, 220);
1352 |
1353 | p.Volume.Sustain = runif(0.1, 0.1);
1354 | p.Volume.Decay = runif(0.2);
1355 |
1356 | p.Filter.HP = 0.2;
1357 | RemoveEmptyParams(p);
1358 | return p;
1359 | },
1360 | Lucky: function () {
1361 | var p = EmptyParams();
1362 | map_object(p, function (out, moduleName) {
1363 | var defs = jsfx.Module[moduleName].params;
1364 | map_object(defs, function (def, name) {
1365 | if (def.C) {
1366 | var values = Object_keys(def.C);
1367 | out[name] = values[(values.length * random()) | 0];
1368 | } else {
1369 | out[name] = random() * (def.H - def.L) + def.L;
1370 | }
1371 | });
1372 | });
1373 | p.Volume.Master = 0.4;
1374 | p.Filter = {}; // disable filter, as it usually will clip everything
1375 | RemoveEmptyParams(p);
1376 | return p;
1377 | }
1378 | };
1379 |
1380 | // GENERATORS
1381 |
1382 | // uniform noise
1383 | jsfx.G.unoise = newGenerator("sample = Math.random();");
1384 | // sine wave
1385 | jsfx.G.sine = newGenerator("sample = Math.sin(phase);");
1386 | // saw wave
1387 | jsfx.G.saw = newGenerator("sample = 2*(phase/TAU - ((phase/TAU + 0.5)|0));");
1388 | // triangle wave
1389 | jsfx.G.triangle = newGenerator("sample = Math.abs(4 * ((phase/TAU - 0.25)%1) - 2) - 1;");
1390 | // square wave
1391 | jsfx.G.square = newGenerator("var s = Math.sin(phase); sample = s > A ? 1.0 : s < A ? -1.0 : A;");
1392 | // simple synth
1393 | jsfx.G.synth = newGenerator("sample = Math.sin(phase) + .5*Math.sin(phase/2) + .3*Math.sin(phase/4);");
1394 |
1395 | // STATEFUL
1396 | var __noiseLast = 0;
1397 | jsfx.G.noise = newGenerator("if(phase % TAU < 4){__noiseLast = Math.random() * 2 - 1;} sample = __noiseLast;");
1398 |
1399 | // Karplus-Strong string
1400 | jsfx.G.string = {
1401 | create: function () {
1402 | var BS = 1 << 16;
1403 | var BM = BS - 1;
1404 |
1405 | var buffer = createFloatArray(BS);
1406 | for (var i = 0; i < buffer.length; i++) {
1407 | buffer[i] = random() * 2 - 1;
1408 | }
1409 |
1410 | var head = 0;
1411 | return function ($, block) {
1412 | var TAU = Math.PI * 2;
1413 | var A = +$.generatorA, ASlide = +$.generatorASlide,
1414 | B = +$.generatorB, BSlide = +$.generatorBSlide;
1415 | var buf = buffer;
1416 |
1417 | for (var i = 0; i < block.length; i++) {
1418 | var phaseSpeed = block[i];
1419 | var n = (TAU / phaseSpeed) | 0;
1420 | A += ASlide; B += BSlide;
1421 | A = A < 0 ? 0 : A > 1 ? 1 : A;
1422 | B = B < 0 ? 0 : B > 1 ? 1 : B;
1423 |
1424 | var t = ((head - n) + BS) & BM;
1425 | var sample = (
1426 | buf[(t - 0 + BS) & BM] * 1 +
1427 | buf[(t - 1 + BS) & BM] * A +
1428 | buf[(t - 2 + BS) & BM] * B) / (1 + A + B);
1429 |
1430 | buf[head] = sample;
1431 | block[i] = buf[head];
1432 | head = (head + 1) & BM;
1433 | }
1434 |
1435 | $.generatorA = A;
1436 | $.generatorB = B;
1437 | return block.length;
1438 | }
1439 | }
1440 | };
1441 |
1442 | // Generates samples using given frequency and generator
1443 | function newGenerator(line) {
1444 | return new Function("$", "block", "" +
1445 | "var TAU = Math.PI * 2;\n" +
1446 | "var sample;\n" +
1447 | "var phase = +$.generatorPhase,\n" +
1448 | " A = +$.generatorA, ASlide = +$.generatorASlide,\n" +
1449 | " B = +$.generatorB, BSlide = +$.generatorBSlide;\n" +
1450 | "\n" +
1451 | "for(var i = 0; i < block.length; i++){\n" +
1452 | " var phaseSpeed = block[i];\n" +
1453 | " phase += phaseSpeed;\n" +
1454 | " if(phase > TAU){ phase -= TAU };\n" +
1455 | " A += ASlide; B += BSlide;\n" +
1456 | " A = A < 0 ? 0 : A > 1 ? 1 : A;\n" +
1457 | " B = B < 0 ? 0 : B > 1 ? 1 : B;\n" +
1458 | line +
1459 | " block[i] = sample;\n" +
1460 | "}\n" +
1461 | "\n" +
1462 | "$.generatorPhase = phase;\n" +
1463 | "$.generatorA = A;\n" +
1464 | "$.generatorB = B;\n" +
1465 | "return block.length;\n" +
1466 | "");
1467 | }
1468 |
1469 | // WAVE SUPPORT
1470 |
1471 | // Creates an Audio element from audio data [-1.0 .. 1.0]
1472 | jsfx.CreateAudio = CreateAudio;
1473 | function CreateAudio(data) {
1474 | if (typeof Float32Array !== "undefined") {
1475 | assert(data instanceof Float32Array, 'data must be an Float32Array');
1476 | }
1477 |
1478 | var blockAlign = numChannels * bitsPerSample >> 3;
1479 | var byteRate = jsfx.SampleRate * blockAlign;
1480 |
1481 | var output = createByteArray(8 + 36 + data.length * 2);
1482 | var p = 0;
1483 |
1484 | // emits string to output
1485 | function S(value) {
1486 | for (var i = 0; i < value.length; i += 1) {
1487 | output[p] = value.charCodeAt(i); p++;
1488 | }
1489 | }
1490 |
1491 | // emits integer value to output
1492 | function V(value, nBytes) {
1493 | if (nBytes <= 0) { return; }
1494 | output[p] = value & 0xFF; p++;
1495 | V(value >> 8, nBytes - 1);
1496 | }
1497 |
1498 | S('RIFF'); V(36 + data.length * 2, 4);
1499 |
1500 | S('WAVEfmt '); V(16, 4); V(1, 2);
1501 | V(numChannels, 2); V(jsfx.SampleRate, 4);
1502 | V(byteRate, 4); V(blockAlign, 2); V(bitsPerSample, 2);
1503 |
1504 | S('data'); V(data.length * 2, 4);
1505 | CopyFToU8(output.subarray(p), data);
1506 |
1507 | return new Audio('data:audio/wav;base64,' + U8ToB64(output));
1508 | };
1509 |
1510 | jsfx.DownloadAsFile = function (audio) {
1511 | assert(audio instanceof Audio, 'input must be an Audio object');
1512 | document.location.href = audio.src;
1513 | };
1514 |
1515 | // HELPERS
1516 | jsfx.Util = {};
1517 |
1518 | // Copies array of Floats to a Uint8Array with 16bits per sample
1519 | jsfx.Util.CopyFToU8 = CopyFToU8;
1520 | function CopyFToU8(into, floats) {
1521 | assert(into.length / 2 == floats.length,
1522 | 'the target buffer must be twice as large as the iinput');
1523 |
1524 | var k = 0;
1525 | for (var i = 0; i < floats.length; i++) {
1526 | var v = +floats[i];
1527 | var a = (v * 0x7FFF) | 0;
1528 | a = a < -0x8000 ? -0x8000 : 0x7FFF < a ? 0x7FFF : a;
1529 | a += a < 0 ? 0x10000 : 0;
1530 | into[k] = a & 0xFF; k++;
1531 | into[k] = a >> 8; k++;
1532 | }
1533 | }
1534 |
1535 | function U8ToB64(data) {
1536 | var CHUNK = 0x8000;
1537 | var result = '';
1538 | for (var start = 0; start < data.length; start += CHUNK) {
1539 | var end = Math.min(start + CHUNK, data.length);
1540 | result += String.fromCharCode.apply(null, data.subarray(start, end));
1541 | }
1542 | return btoa(result);
1543 | }
1544 |
1545 | // uses AudioContext sampleRate or 44100;
1546 | function getDefaultSampleRate() {
1547 | if (typeof AudioContext !== 'undefined') {
1548 | return (new AudioContext()).sampleRate;
1549 | }
1550 | return 44100;
1551 | }
1552 |
1553 | // for checking pre/post conditions
1554 | function assert(condition, message) {
1555 | if (!condition) { throw new Error(message); }
1556 | }
1557 |
1558 | function clamp(v, min, max) {
1559 | v = +v; min = +min; max = +max;
1560 | if (v < min) { return +min; }
1561 | if (v > max) { return +max; }
1562 | return +v;
1563 | }
1564 |
1565 | function clamp1(v) {
1566 | v = +v;
1567 | if (v < +0.0) { return +0.0; }
1568 | if (v > +1.0) { return +1.0; }
1569 | return +v;
1570 | }
1571 |
1572 | function map_object(obj, fn) {
1573 | var r = {};
1574 | for (var name in obj) {
1575 | if (obj.hasOwnProperty(name)) {
1576 | r[name] = fn(obj[name], name);
1577 | }
1578 | }
1579 | return r;
1580 | }
1581 |
1582 | // uniform random
1583 | function runif(scale, offset) {
1584 | var a = random();
1585 | if (scale !== undefined)
1586 | a *= scale;
1587 | if (offset !== undefined)
1588 | a += offset;
1589 | return a;
1590 | }
1591 |
1592 | function rchoose(gens) {
1593 | return gens[(gens.length * random()) | 0];
1594 | }
1595 |
1596 | function Object_keys(obj) {
1597 | var r = [];
1598 | for (var name in obj) { r.push(name); }
1599 | return r;
1600 | }
1601 |
1602 | jsfx._createFloatArray = createFloatArray;
1603 | function createFloatArray(N) {
1604 | if (typeof Float32Array === "undefined") {
1605 | var r = new Array(N);
1606 | for (var i = 0; i < r.length; i++) {
1607 | r[i] = 0.0;
1608 | }
1609 | }
1610 | return new Float32Array(N);
1611 | }
1612 |
1613 | function createByteArray(N) {
1614 | if (typeof Uint8Array === "undefined") {
1615 | var r = new Array(N);
1616 | for (var i = 0; i < r.length; i++) {
1617 | r[i] = 0 | 0;
1618 | }
1619 | }
1620 | return new Uint8Array(N);
1621 | }
1622 |
1623 | var randomFunc = Math.random;
1624 | jsfx.setRandomFunc = function (func) {
1625 | randomFunc = func;
1626 | }
1627 |
1628 | function random() {
1629 | return randomFunc();
1630 | }
1631 | })(jsfx = {});
1632 | module.exports = jsfx;
1633 |
1634 |
1635 | /***/ }
1636 | /******/ ])
1637 | });
1638 | ;
--------------------------------------------------------------------------------