summaryrefslogtreecommitdiff
path: root/plugins/vtx
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-12-18 23:54:30 +0100
committerGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-12-18 23:54:30 +0100
commit8674104981f0fc91ce504d8702572b8cd8b1fc25 (patch)
treed1e9ced526c40f51b2db20c0d96e58a3e531f65e /plugins/vtx
parent01740cc3f9dcfc8e95aae03003757e2b085ef70f (diff)
vxt plugin WIP
Diffstat (limited to 'plugins/vtx')
-rw-r--r--plugins/vtx/COPYING340
-rw-r--r--plugins/vtx/Makefile.am6
-rw-r--r--plugins/vtx/ay8912.c494
-rw-r--r--plugins/vtx/ayemu.h84
-rw-r--r--plugins/vtx/ayemu_8912.h156
-rw-r--r--plugins/vtx/ayemu_vtxfile.h73
-rw-r--r--plugins/vtx/lh5dec.c304
-rw-r--r--plugins/vtx/vtx.c162
-rw-r--r--plugins/vtx/vtxfile.c283
9 files changed, 1902 insertions, 0 deletions
diff --git a/plugins/vtx/COPYING b/plugins/vtx/COPYING
new file mode 100644
index 00000000..d60c31a9
--- /dev/null
+++ b/plugins/vtx/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/plugins/vtx/Makefile.am b/plugins/vtx/Makefile.am
new file mode 100644
index 00000000..abfa8c98
--- /dev/null
+++ b/plugins/vtx/Makefile.am
@@ -0,0 +1,6 @@
+vtxdir = $(libdir)/$(PACKAGE)
+pkglib_LTLIBRARIES = vtx.la
+vtx_la_SOURCES = vtx.c ay8912.c ayemu_8912.h ayemu.h ayemu_vtxfile.h lh5dec.c vtxfile.c
+vtx_la_LDFLAGS = -module
+
+AM_CFLAGS = $(CFLAGS) -std=c99
diff --git a/plugins/vtx/ay8912.c b/plugins/vtx/ay8912.c
new file mode 100644
index 00000000..bf79f95c
--- /dev/null
+++ b/plugins/vtx/ay8912.c
@@ -0,0 +1,494 @@
+/* AY/YM emulator implementation. */
+
+#include "ayemu.h"
+
+#define debuglog stderr;
+
+char *ayemu_err;
+
+static const char VERSION[] = "libayemu 0.9";
+
+const int MAGIC1 = 0xcdef; /* for check ayemu_t structure inited */
+
+enum {
+/* Max amplitude value for stereo signal for avoiding for possible
+ folowwing SSRC for clipping */
+ AYEMU_MAX_AMP = 24575,
+ AYEMU_DEFAULT_CHIP_FREQ = 1773400
+};
+
+/* sound chip volume envelops (will calculated by gen_env()) */
+static int bEnvGenInit = 0;
+static int Envelope [16][128];
+
+
+/* AY volume table (c) by V_Soft and Lion 17 */
+static int Lion17_AY_table [16] =
+ { 0, 513, 828, 1239, 1923, 3238, 4926, 9110,
+ 10344, 17876, 24682, 30442, 38844, 47270, 56402, 65535};
+
+/* YM volume table (c) by V_Soft and Lion 17 */
+static int Lion17_YM_table [32] =
+ { 0, 0, 190, 286, 375, 470, 560, 664,
+ 866, 1130, 1515, 1803, 2253, 2848, 3351, 3862,
+ 4844, 6058, 7290, 8559, 10474, 12878, 15297, 17787,
+ 21500, 26172, 30866, 35676, 42664, 50986, 58842, 65535};
+
+/* AY volume table (c) by Hacker KAY */
+static int KAY_AY_table [16] =
+ { 0, 836, 1212, 1773, 2619, 3875, 5397, 8823,
+ 10392, 16706, 23339, 29292, 36969, 46421, 55195, 65535};
+
+/* YM volume table (c) by Hacker KAY */
+static int KAY_YM_table [32] =
+ { 0, 0, 248, 450, 670, 826, 1010, 1239,
+ 1552, 1919, 2314, 2626, 3131, 3778, 4407, 5031,
+ 5968, 7161, 8415, 9622, 11421, 13689, 15957, 18280,
+ 21759, 26148, 30523, 34879, 41434, 49404, 57492, 65535};
+
+/* default equlaizer (layout) settings for AY and YM, 7 stereo types */
+static const int default_layout [2][7][6] = {
+ {
+ /* A_l, A_r, B_l, B_r, C_l, C_r */
+
+ /* for AY */
+ {100, 100, 100, 100, 100, 100}, // _MONO
+ {100, 33, 70, 70, 33, 100}, // _ABC
+ {100, 33, 33, 100, 70, 70}, // _ACB
+ {70, 70, 100, 33, 33, 100}, // _BAC
+ {33, 100, 100, 33, 70, 70}, // _BCA
+ {70, 70, 33, 100, 100, 33}, // _CAB
+ {33, 100, 70, 70, 100, 33}}, // _CBA
+ {
+ /* for YM */
+ {100, 100, 100, 100, 100, 100}, // _MONO
+ {100, 5, 70, 70, 5, 100}, // _ABC
+ {100, 5, 5, 100, 70, 70}, // _ACB
+ {70, 70, 100, 5, 5, 100}, // _BAC
+ {5, 100, 100, 5, 70, 70}, // _BCA
+ {70, 70, 5, 100, 100, 5}, // _CAB
+ {5, 100, 70, 70, 100, 5}} // _CBA
+};
+
+
+static int check_magic(ayemu_ay_t *ay)
+{
+ if (ay->magic == MAGIC1)
+ return 1;
+ fprintf(stderr, "libayemu: passed pointer %p to uninitialized ayemu_ay_t structure\n", ay);
+ return 0;
+}
+
+
+/* make chip hardware envelop tables.
+ Will execute once before first use. */
+static void gen_env()
+{
+ int env;
+ int pos;
+ int hold;
+ int dir;
+ int vol;
+
+ for (env = 0; env < 16; env++) {
+ hold = 0;
+ dir = (env & 4)? 1 : -1;
+ vol = (env & 4)? -1 : 32;
+ for (pos = 0; pos < 128; pos++) {
+ if (!hold) {
+ vol += dir;
+ if (vol < 0 || vol >= 32) {
+ if ( env & 8 ) {
+ if ( env & 2 ) dir = -dir;
+ vol = (dir > 0 )? 0:31;
+ if ( env & 1 ) {
+ hold = 1;
+ vol = ( dir > 0 )? 31:0;
+ }
+ } else {
+ vol = 0;
+ hold = 1;
+ }
+ }
+ }
+ Envelope[env][pos] = vol;
+ }
+ }
+ bEnvGenInit = 1;
+}
+
+
+/**
+ * \retval ayemu_init none.
+ *
+*/
+void ayemu_init(ayemu_ay_t *ay)
+{
+ ay->default_chip_flag = 1;
+ ay->ChipFreq = AYEMU_DEFAULT_CHIP_FREQ;
+ ay->default_stereo_flag = 1;
+ ay->default_sound_format_flag = 1;
+ ay->dirty = 1;
+ ay->magic = MAGIC1;
+
+ ayemu_reset(ay);
+}
+
+/** Reset AY/YM chip.
+ *
+ * \arg \c ay - pointer to ayemu_ay_t structure.
+ * \return none.
+ */
+void ayemu_reset(ayemu_ay_t *ay)
+{
+ if (!check_magic(ay)) return;
+
+ ay->cnt_a = ay->cnt_b = ay->cnt_c = ay->cnt_n = ay->cnt_e = 0;
+ ay->bit_a = ay->bit_b = ay->bit_c = ay->bit_n = 0;
+ ay->env_pos = ay->EnvNum = 0;
+ ay->Cur_Seed = 0xffff;
+}
+
+
+static void set_table_ay (ayemu_ay_t *ay, int tbl[16])
+{
+ int n;
+ for (n = 0; n < 32; n++)
+ ay->table[n] = tbl[n/2];
+ ay->type = AYEMU_AY;
+}
+
+static void set_table_ym (ayemu_ay_t *ay, int tbl[32])
+{
+ int n;
+ for (n = 0; n < 32; n++)
+ ay->table[n] = tbl[n];
+ ay->type = AYEMU_YM;
+}
+
+
+/** Set chip type. */
+int ayemu_set_chip_type(ayemu_ay_t *ay, ayemu_chip_t type, int *custom_table)
+{
+if (!check_magic(ay))
+ return 0;
+
+ if (!(type == AYEMU_AY_CUSTOM || type == AYEMU_YM_CUSTOM) && custom_table != NULL) {
+ ayemu_err = "For non-custom chip type 'custom_table' param must be NULL";
+ return 0;
+ }
+
+ switch(type) {
+ case AYEMU_AY:
+ case AYEMU_AY_LION17:
+ set_table_ay(ay, Lion17_AY_table);
+ break;
+ case AYEMU_YM:
+ case AYEMU_YM_LION17:
+ set_table_ym(ay, Lion17_YM_table);
+ break;
+ case AYEMU_AY_KAY:
+ set_table_ay(ay, KAY_AY_table);
+ break;
+ case AYEMU_YM_KAY:
+ set_table_ym(ay, KAY_YM_table);
+ break;
+ case AYEMU_AY_CUSTOM:
+ set_table_ay(ay, custom_table);
+ break;
+ case AYEMU_YM_CUSTOM:
+ set_table_ym(ay, custom_table);
+ break;
+ default:
+ ayemu_err = "Incorrect chip type";
+ return 0;
+ }
+
+ ay->default_chip_flag = 0;
+ ay->dirty = 1;
+ return 1;
+}
+
+
+/** Set chip frequency. */
+void ayemu_set_chip_freq(ayemu_ay_t *ay, int chipfreq)
+{
+ if (!check_magic(ay)) return;
+
+ ay->ChipFreq = chipfreq;
+ ay->dirty = 1;
+}
+
+/*! Set output sound format
+ * \arg \c ay - pointer to ayemu_t structure
+ * \arg \c freq - sound freq (44100 for example)
+ * \arg \c chans - number of channels (1-mono, 2-stereo)
+ * \arg \c bits - now supported only 16 and 8.
+ * \retval \b 1 on success, \b 0 if error occure
+ */
+int ayemu_set_sound_format (ayemu_ay_t *ay, int freq, int chans, int bits)
+{
+ if (!check_magic(ay))
+ return 0;
+
+ if (!(bits == 16 || bits == 8)) {
+ ayemu_err = "Incorrect bits value";
+ return 0;
+ }
+ else if (!(chans == 1 || chans == 2)) {
+ ayemu_err = "Incorrect number of channels";
+ return 0;
+ }
+ else if (freq < 50) {
+ ayemu_err = "Incorrect output sound freq";
+ return 0;
+ }
+ else {
+ ay->sndfmt.freq = freq;
+ ay->sndfmt.channels = chans;
+ ay->sndfmt.bpc = bits;
+ }
+
+ ay->default_sound_format_flag = 0;
+ ay->dirty = 1;
+ return 1;
+}
+
+
+/*! Set amplitude factor for each of channels (A,B anc C, tone and noise).
+ * Factor's value must be from (-100) to 100.
+ * \arg ay - pointer to ayemu_t structure
+ * \arg stereo_type - type of stereo
+ * \arg custom_eq - NULL or pointer to custom table of mixer layout.
+ * \retval 1 if OK, 0 if error occures.
+ */
+int ayemu_set_stereo(ayemu_ay_t *ay, ayemu_stereo_t stereo_type, int *custom_eq)
+{
+ int i;
+ int chip;
+
+ if (!check_magic(ay))
+ return 0;
+
+ if (stereo_type != AYEMU_STEREO_CUSTOM && custom_eq != NULL) {
+ ayemu_err = "Stereo type not custom, 'custom_eq' parametr must be NULL";
+ return 0;
+ }
+
+ chip = (ay->type == AYEMU_AY)? 0 : 1;
+
+ switch(stereo_type) {
+ case AYEMU_MONO:
+ case AYEMU_ABC:
+ case AYEMU_ACB:
+ case AYEMU_BAC:
+ case AYEMU_BCA:
+ case AYEMU_CAB:
+ case AYEMU_CBA:
+ for (i = 0 ; i < 6 ; i++)
+ ay->eq[i] = default_layout[chip][stereo_type][i];
+ break;
+ case AYEMU_STEREO_CUSTOM:
+ for (i = 0 ; i < 6 ; i++)
+ ay->eq[i] = custom_eq[i];
+ break;
+ default:
+ ayemu_err = "Incorrect stereo type";
+ return 0;
+ }
+
+ ay->default_stereo_flag = 0;
+ ay->dirty = 1;
+ return 1;
+}
+
+
+#define WARN_IF_REGISTER_GREAT_THAN(r,m) \
+if (*(regs + r) > m) \
+ fprintf(stderr, "ayemu_set_regs: warning: possible bad register data- R%d > %d\n", r, m)
+
+
+/** Assign values for AY registers.
+ *
+ * You must pass array of char [14] to this function
+ */
+void ayemu_set_regs(ayemu_ay_t *ay, ayemu_ay_reg_frame_t regs)
+{
+ if (!check_magic(ay)) return;
+
+ WARN_IF_REGISTER_GREAT_THAN(1,15);
+ WARN_IF_REGISTER_GREAT_THAN(3,15);
+ WARN_IF_REGISTER_GREAT_THAN(5,15);
+ WARN_IF_REGISTER_GREAT_THAN(8,31);
+ WARN_IF_REGISTER_GREAT_THAN(9,31);
+ WARN_IF_REGISTER_GREAT_THAN(10,31);
+
+ ay->regs.tone_a = regs[0] + ((regs[1]&0x0f) << 8);
+ ay->regs.tone_b = regs[2] + ((regs[3]&0x0f) << 8);
+ ay->regs.tone_c = regs[4] + ((regs[5]&0x0f) << 8);
+
+ ay->regs.noise = regs[6] & 0x1f;
+
+ ay->regs.R7_tone_a = ! (regs[7] & 0x01);
+ ay->regs.R7_tone_b = ! (regs[7] & 0x02);
+ ay->regs.R7_tone_c = ! (regs[7] & 0x04);
+
+ ay->regs.R7_noise_a = ! (regs[7] & 0x08);
+ ay->regs.R7_noise_b = ! (regs[7] & 0x10);
+ ay->regs.R7_noise_c = ! (regs[7] & 0x20);
+
+ ay->regs.vol_a = regs[8] & 0x0f;
+ ay->regs.vol_b = regs[9] & 0x0f;
+ ay->regs.vol_c = regs[10] & 0x0f;
+ ay->regs.env_a = regs[8] & 0x10;
+ ay->regs.env_b = regs[9] & 0x10;
+ ay->regs.env_c = regs[10] & 0x10;
+ ay->regs.env_freq = regs[11] + (regs[12] << 8);
+
+ if (regs[13] != 0xff) { /* R13 = 255 means continue curent envelop */
+ ay->regs.env_style = regs[13] & 0x0f;
+ ay->env_pos = ay->cnt_e = 0;
+ }
+}
+
+
+static void prepare_generation(ayemu_ay_t *ay)
+{
+ int vol, max_l, max_r;
+
+ if (!ay->dirty) return;
+
+ if (!bEnvGenInit) gen_env ();
+
+ if (ay->default_chip_flag) ayemu_set_chip_type(ay, AYEMU_AY, NULL);
+
+ if (ay->default_stereo_flag) ayemu_set_stereo(ay, AYEMU_ABC, NULL);
+
+ if (ay->default_sound_format_flag) ayemu_set_sound_format(ay, 44100, 2, 16);
+
+ ay->ChipTacts_per_outcount = ay->ChipFreq / ay->sndfmt.freq / 8;
+
+ { /* GenVols */
+ int n, m;
+ int vol;
+ for (n = 0; n < 32; n++) {
+ vol = ay->table[n];
+ for (m=0; m < 6; m++)
+ ay->vols[m][n] = (int) (((double) vol * ay->eq[m]) / 100);
+ }
+ }
+
+ /* динамическая настройка глобального коэффициента усиления
+ подразумевается, что в vols [x][31] лежит самая большая громкость
+ TODO: Сделать проверку на это ;-)
+ */
+ max_l = ay->vols[0][31] + ay->vols[2][31] + ay->vols[3][31];
+ max_r = ay->vols[1][31] + ay->vols[3][31] + ay->vols[5][31];
+ vol = (max_l > max_r) ? max_l : max_r; // =157283 on all defaults
+ ay->Amp_Global = ay->ChipTacts_per_outcount *vol / AYEMU_MAX_AMP;
+
+ ay->dirty = 0;
+}
+
+
+/*! Generate sound.
+ * Fill sound buffer with current register data
+ * Return value: pointer to next data in output sound buffer
+ * \retval \b 1 if OK, \b 0 if error occures.
+ */
+void *ayemu_gen_sound(ayemu_ay_t *ay, void *buff, size_t sound_bufsize)
+{
+ int mix_l, mix_r;
+ int tmpvol;
+ int m;
+ int snd_numcount;
+ unsigned char *sound_buf = buff;
+
+ if (!check_magic(ay))
+ return 0;
+
+ prepare_generation(ay);
+
+ snd_numcount = sound_bufsize / (ay->sndfmt.channels * (ay->sndfmt.bpc >> 3));
+ while (snd_numcount-- > 0) {
+ mix_l = mix_r = 0;
+
+ for (m = 0 ; m < ay->ChipTacts_per_outcount ; m++) {
+ if (++ay->cnt_a >= ay->regs.tone_a) {
+ ay->cnt_a = 0;
+ ay->bit_a = ! ay->bit_a;
+ }
+ if (++ay->cnt_b >= ay->regs.tone_b) {
+ ay->cnt_b = 0;
+ ay->bit_b = ! ay->bit_b;
+ }
+ if (++ay->cnt_c >= ay->regs.tone_c) {
+ ay->cnt_c = 0;
+ ay->bit_c = ! ay->bit_c;
+ }
+
+ /* GenNoise (c) Hacker KAY & Sergey Bulba */
+ if (++ay->cnt_n >= (ay->regs.noise * 2)) {
+ ay->cnt_n = 0;
+ ay->Cur_Seed = (ay->Cur_Seed * 2 + 1) ^ \
+ (((ay->Cur_Seed >> 16) ^ (ay->Cur_Seed >> 13)) & 1);
+ ay->bit_n = ((ay->Cur_Seed >> 16) & 1);
+ }
+
+ if (++ay->cnt_e >= ay->regs.env_freq) {
+ ay->cnt_e = 0;
+ if (++ay->env_pos > 127)
+ ay->env_pos = 64;
+ }
+
+#define ENVVOL Envelope [ay->regs.env_style][ay->env_pos]
+
+ if ((ay->bit_a | !ay->regs.R7_tone_a) & (ay->bit_n | !ay->regs.R7_noise_a)) {
+ tmpvol = (ay->regs.env_a)? ENVVOL : ay->regs.vol_a * 2 + 1;
+ mix_l += ay->vols[0][tmpvol];
+ mix_r += ay->vols[1][tmpvol];
+ }
+
+ if ((ay->bit_b | !ay->regs.R7_tone_b) & (ay->bit_n | !ay->regs.R7_noise_b)) {
+ tmpvol =(ay->regs.env_b)? ENVVOL : ay->regs.vol_b * 2 + 1;
+ mix_l += ay->vols[2][tmpvol];
+ mix_r += ay->vols[3][tmpvol];
+ }
+
+ if ((ay->bit_c | !ay->regs.R7_tone_c) & (ay->bit_n | !ay->regs.R7_noise_c)) {
+ tmpvol = (ay->regs.env_c)? ENVVOL : ay->regs.vol_c * 2 + 1;
+ mix_l += ay->vols[4][tmpvol];
+ mix_r += ay->vols[5][tmpvol];
+ }
+ } /* end for (m=0; ...) */
+
+ mix_l /= ay->Amp_Global;
+ mix_r /= ay->Amp_Global;
+
+ if (ay->sndfmt.bpc == 8) {
+ mix_l = (mix_l >> 8) | 128; /* 8 bit sound */
+ mix_r = (mix_r >> 8) | 128;
+ *sound_buf++ = mix_l;
+ if (ay->sndfmt.channels != 1)
+ *sound_buf++ = mix_r;
+ } else {
+ *sound_buf++ = mix_l & 0x00FF; /* 16 bit sound */
+ *sound_buf++ = (mix_l >> 8);
+ if (ay->sndfmt.channels != 1) {
+ *sound_buf++ = mix_r & 0x00FF;
+ *sound_buf++ = (mix_r >> 8);
+ }
+ }
+ }
+ return sound_buf;
+}
+
+/** Free all data allocated by emulator
+ *
+ * For now it do nothing.
+ */
+void ayemu_free (ayemu_ay_t *ay)
+{
+ /* nothing to do here */
+ return;
+}
diff --git a/plugins/vtx/ayemu.h b/plugins/vtx/ayemu.h
new file mode 100644
index 00000000..637cea91
--- /dev/null
+++ b/plugins/vtx/ayemu.h
@@ -0,0 +1,84 @@
+/*
+ ayemu - AY/YM sound chip emulator and music file loader
+ Copyright (C) 2003-2004 Sashnov Alexander
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Sashnov
+ sashnov@ngs.ru
+*/
+
+/*!
+ * \mainpage libayemu library
+ *
+ * Homepage on sourceforge.net: http://sourceforge.net/projects/libayemu
+ *
+ * This library will help you to add AY/YM music in your own game, demos, etc.
+ *
+ * For example of how to use it see playvtx and xmms-vtx packages.
+ *
+ * Python wrapper and example comming soon.
+ *
+ */
+
+#ifndef _AYEMU_H
+#define _AYEMU_H
+
+#ifdef __cplusplus
+# define BEGIN_C_DECLS extern "C" {
+# define END_C_DECLS }
+#else /* !__cplusplus */
+# define BEGIN_C_DECLS
+# define END_C_DECLS
+#endif /* __cplusplus */
+
+/* Make sure the correct platform symbols are defined */
+#if !defined(WIN32) && defined(_WIN32)
+#define WIN32
+#endif /* Windows */
+
+/* Some compilers use a special export keyword */
+#ifndef DECLSPEC
+# ifdef __BEOS__
+# if defined(__GNUC__)
+# define DECLSPEC __declspec(dllexport)
+# else
+# define DECLSPEC __declspec(export)
+# endif
+# else
+# ifdef WIN32
+# ifdef __BORLANDC__
+# ifdef BUILD_SDL
+# define DECLSPEC
+# else
+# define DECLSPEC __declspec(dllimport)
+# endif
+# else
+# define DECLSPEC __declspec(dllexport)
+# endif
+# else
+# define DECLSPEC
+# endif
+# endif
+#endif
+
+#define EXTERN extern DECLSPEC
+
+
+/* include other library headers */
+#include "ayemu_8912.h"
+#include "ayemu_vtxfile.h"
+
+#endif
diff --git a/plugins/vtx/ayemu_8912.h b/plugins/vtx/ayemu_8912.h
new file mode 100644
index 00000000..e8e50e5a
--- /dev/null
+++ b/plugins/vtx/ayemu_8912.h
@@ -0,0 +1,156 @@
+/**
+ * AY/YM emulator include file
+ */
+
+#ifndef _AYEMU_ay8912_h
+#define _AYEMU_ay8912_h
+
+#include <stddef.h>
+
+BEGIN_C_DECLS
+
+// TODO: ayemu_ay_t - hide all private data, allocate it in init function.
+
+typedef unsigned char ayemu_ay_reg_frame_t[14];
+
+
+
+/** Types of stereo.
+ The codes of stereo types used for generage sound. */
+typedef enum
+{
+ AYEMU_MONO = 0,
+ AYEMU_ABC,
+ AYEMU_ACB,
+ AYEMU_BAC,
+ AYEMU_BCA,
+ AYEMU_CAB,
+ AYEMU_CBA,
+ AYEMU_STEREO_CUSTOM = 255
+} ayemu_stereo_t;
+
+/** Sound chip type.
+ Constant for identify used chip for emulation */
+typedef enum {
+ AYEMU_AY, /**< default AY chip (lion17 for now) */
+ AYEMU_YM, /**< default YM chip (lion17 for now) */
+ AYEMU_AY_LION17, /**< emulate AY with Lion17 table */
+ AYEMU_YM_LION17, /**< emulate YM with Lion17 table */
+ AYEMU_AY_KAY, /**< emulate AY with HACKER KAY table */
+ AYEMU_YM_KAY, /**< emulate YM with HACKER KAY table */
+ AYEMU_AY_LOG, /**< emulate AY with logariphmic table */
+ AYEMU_YM_LOG, /**< emulate YM with logariphmic table */
+ AYEMU_AY_CUSTOM, /**< use AY with custom table. */
+ AYEMU_YM_CUSTOM /**< use YM with custom table. */
+} ayemu_chip_t;
+
+/** parsed by #ayemu_set_regs() AY registers data \internal */
+typedef struct
+{
+ int tone_a; /**< R0, R1 */
+ int tone_b; /**< R2, R3 */
+ int tone_c; /**< R4, R5 */
+ int noise; /**< R6 */
+ int R7_tone_a; /**< R7 bit 0 */
+ int R7_tone_b; /**< R7 bit 1 */
+ int R7_tone_c; /**< R7 bit 2 */
+ int R7_noise_a; /**< R7 bit 3 */
+ int R7_noise_b; /**< R7 bit 4 */
+ int R7_noise_c; /**< R7 bit 5 */
+ int vol_a; /**< R8 bits 3-0 */
+ int vol_b; /**< R9 bits 3-0 */
+ int vol_c; /**< R10 bits 3-0 */
+ int env_a; /**< R8 bit 4 */
+ int env_b; /**< R9 bit 4 */
+ int env_c; /**< R10 bit 4 */
+ int env_freq; /**< R11, R12 */
+ int env_style; /**< R13 */
+}
+ayemu_regdata_t;
+
+
+/** Output sound format \internal */
+typedef struct
+{
+ int freq; /**< sound freq */
+ int channels; /**< channels (1-mono, 2-stereo) */
+ int bpc; /**< bits (8 or 16) */
+}
+ayemu_sndfmt_t;
+
+/**
+ * \defgroup libayemu Functions for emulate AY/YM chip
+ */
+/*@{*/
+
+/** Data structure for sound chip emulation \internal
+ *
+ */
+typedef struct
+{
+ /* emulator settings */
+ int table[32]; /**< table of volumes for chip */
+ ayemu_chip_t type; /**< general chip type (\b AYEMU_AY or \b AYEMU_YM) */
+ int ChipFreq; /**< chip emulator frequency */
+ int eq[6]; /**< volumes for channels.
+ Array contains 6 elements:
+ A left, A right, B left, B right, C left and C right;
+ range -100...100 */
+ ayemu_regdata_t regs; /**< parsed registers data */
+ ayemu_sndfmt_t sndfmt; /**< output sound format */
+
+ /* flags */
+ int magic; /**< structure initialized flag */
+ int default_chip_flag; /**< =1 after init, resets in #ayemu_set_chip_type() */
+ int default_stereo_flag; /**< =1 after init, resets in #ayemu_set_stereo() */
+ int default_sound_format_flag; /**< =1 after init, resets in #ayemu_set_sound_format() */
+ int dirty; /**< dirty flag. Sets if any emulator properties changed */
+
+ int bit_a; /**< state of channel A generator */
+ int bit_b; /**< state of channel B generator */
+ int bit_c; /**< state of channel C generator */
+ int bit_n; /**< current generator state */
+ int cnt_a; /**< back counter of A */
+ int cnt_b; /**< back counter of B */
+ int cnt_c; /**< back counter of C */
+ int cnt_n; /**< back counter of noise generator */
+ int cnt_e; /**< back counter of envelop generator */
+ int ChipTacts_per_outcount; /**< chip's counts per one sound signal count */
+ int Amp_Global; /**< scale factor for amplitude */
+ int vols[6][32]; /**< stereo type (channel volumes) and chip table.
+ This cache calculated by #table and #eq */
+ int EnvNum; /**< number of current envilopment (0...15) */
+ int env_pos; /**< current position in envelop (0...127) */
+ int Cur_Seed; /**< random numbers counter */
+}
+ayemu_ay_t;
+
+EXTERN void
+ayemu_init(ayemu_ay_t *ay);
+
+EXTERN void
+ayemu_reset(ayemu_ay_t *ay);
+
+EXTERN int
+ayemu_set_chip_type(ayemu_ay_t *ay, ayemu_chip_t chip, int *custom_table);
+
+EXTERN void
+ayemu_set_chip_freq(ayemu_ay_t *ay, int chipfreq);
+
+EXTERN int
+ayemu_set_stereo(ayemu_ay_t *ay, ayemu_stereo_t stereo, int *custom_eq);
+
+EXTERN int
+ayemu_set_sound_format (ayemu_ay_t *ay, int freq, int chans, int bits);
+
+EXTERN void
+ayemu_set_regs (ayemu_ay_t *ay, ayemu_ay_reg_frame_t regs);
+
+EXTERN void*
+ayemu_gen_sound (ayemu_ay_t *ay, void *buf, size_t bufsize);
+
+/*@}*/
+
+END_C_DECLS
+
+#endif
diff --git a/plugins/vtx/ayemu_vtxfile.h b/plugins/vtx/ayemu_vtxfile.h
new file mode 100644
index 00000000..3856b45d
--- /dev/null
+++ b/plugins/vtx/ayemu_vtxfile.h
@@ -0,0 +1,73 @@
+#ifndef _AYEMU_vtxfile_h
+#define _AYEMU_vtxfile_h
+
+#include <stdio.h>
+#include <stdint.h>
+
+#include "ayemu_8912.h"
+
+BEGIN_C_DECLS
+
+/**
+ * \defgroup vtxfile Functions for extract data from vtx files
+ */
+/*@{*/
+
+/** structure for VTX file format handler
+ * \internal
+ * It stores VTX file header and current state
+ * (open file pointer, extracted register data, etc).
+ */
+typedef struct
+{
+ ayemu_chip_t chiptype; /**< Type of sound chip */
+ int stereo; /**< Type of stereo: ABC, BCA,... */
+ int loop; /**< song loop */
+ int chipFreq; /**< AY chip freq (1773400 for ZX) */
+ int playerFreq; /**< 50 Hz for ZX, 60 Hz for yamaha */
+ int year; /**< year song composed */
+ char *title; /**< song title */
+ char *author; /**< song author */
+ char *from; /**< song from */
+ char *tracker; /**< tracker */
+ char *comment; /**< comment */
+ int regdata_size; /**< size of unpacked data (need for unpack). */
+ unsigned char *regdata; /**< unpacked song data */
+ size_t frames; /**< number of AY data frames */
+} ayemu_vtx_t;
+
+
+/*! Load only header (song info) from vtx file.
+ * Purpose: read tags in play list.
+ */
+EXTERN ayemu_vtx_t * ayemu_vtx_header(const char *buf, size_t size);
+
+/*! Load song (header and unpack data).
+ *
+ */
+EXTERN ayemu_vtx_t * ayemu_vtx_load(const char *buf, size_t size);
+
+EXTERN void ayemu_vtx_getframe(const ayemu_vtx_t *vtx, size_t frame_n,
+ ayemu_ay_reg_frame_t regs);
+
+/** Free all allocaded data and structure itself.
+ * You must call this for any ayemu_vtx_t pointer allocated by this lib
+ * by functions ayemu_vtx_header() and ayemu_vtx_load().
+ */
+EXTERN void ayemu_vtx_free(ayemu_vtx_t *vtx);
+
+/*! Load song header from file.
+ * Helper (non-all platform) function
+ */
+EXTERN ayemu_vtx_t * ayemu_vtx_header_from_file(const char *filename);
+
+/*! Load song header and data from file.
+ * Helper (non-all platform) function
+ */
+EXTERN ayemu_vtx_t * ayemu_vtx_load_from_file(const char *filename);
+
+/*@}*/
+
+END_C_DECLS
+
+#endif
diff --git a/plugins/vtx/lh5dec.c b/plugins/vtx/lh5dec.c
new file mode 100644
index 00000000..1b2456bb
--- /dev/null
+++ b/plugins/vtx/lh5dec.c
@@ -0,0 +1,304 @@
+/* extractiong lh5 module
+ (c) Haruhiko Okumura
+ (m) Roman Scherbakov
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h> /* memmove */
+#include <limits.h>
+
+static unsigned short bitbuf;
+
+#define BITBUFSIZ (CHAR_BIT * sizeof bitbuf)
+
+#define DICBIT 13 /* 12(-lh4-) or 13(-lh5-) */
+#define DICSIZ (1L << DICBIT)
+#define MATCHBIT 8 /* bits for MAXMATCH - THRESHOLD */
+#define MAXMATCH 256 /* formerly F (not more than unsigned char_MAX + 1) */
+#define THRESHOLD 3 /* choose optimal value */
+#define NC (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD)
+#define CBIT 9 /* $\lfloor \log_2 NC \rfloor + 1$ */
+#define CODE_BIT 16 /* codeword length */
+#define NP (DICBIT + 1)
+#define NT (CODE_BIT + 3)
+#define PBIT 4 /* smallest integer such that (1U << PBIT) > NP */
+#define TBIT 5 /* smallest integer such that (1U << TBIT) > NT */
+#if NT > NP
+#define NPT NT
+#else
+#define NPT NP
+#endif
+
+static unsigned long origsize, compsize;
+static const unsigned char *in_buf;
+static unsigned char *out_buf;
+
+static unsigned short subbitbuf;
+static int bitcount;
+
+static unsigned short left[2 * NC - 1], right[2 * NC - 1];
+static unsigned char c_len[NC], pt_len[NPT];
+static unsigned short blocksize;
+
+static unsigned short c_table[4096], pt_table[256];
+
+static int j; /* remaining bytes to copy */
+
+
+static void error(char *msg)
+{
+ fprintf(stderr, "libayemu: lh5dec.c: %s\n", msg);
+ exit(EXIT_FAILURE);
+}
+
+static void fillbuf(int n) /* Shift bitbuf n bits left, read n bits */
+{
+ bitbuf <<= n;
+ while (n > bitcount) {
+ bitbuf |= subbitbuf << (n -= bitcount);
+ if (compsize != 0) {
+ compsize--; subbitbuf = *in_buf++;
+ } else subbitbuf = 0;
+ bitcount = CHAR_BIT;
+ }
+ bitbuf |= subbitbuf >> (bitcount -= n);
+}
+
+static unsigned short getbits(int n)
+{
+ unsigned short x;
+
+ x = bitbuf >> (BITBUFSIZ - n); fillbuf(n);
+ return x;
+}
+
+// make table for decoding
+
+static void make_table(int nchar, unsigned char bitlen[], int tablebits, unsigned short table[])
+{
+ unsigned short count[17], weight[17], start[18], *p;
+ unsigned short i, k, len, ch, jutbits, avail, nextcode, mask;
+
+ for (i = 1; i <= 16; i++) count[i] = 0;
+ for (i = 0; i < nchar; i++) count[bitlen[i]]++;
+
+ start[1] = 0;
+ for (i = 1; i <= 16; i++)
+ start[i + 1] = start[i] + (count[i] << (16 - i));
+ if (start[17] != (unsigned short)(1U << 16)) error("Bad table");
+
+ jutbits = 16 - tablebits;
+ for (i = 1; i <= tablebits; i++) {
+ start[i] >>= jutbits;
+ weight[i] = 1U << (tablebits - i);
+ }
+ while (i <= 16) weight[i++] = 1U << (16 - i);
+
+ i = start[tablebits + 1] >> jutbits;
+ if (i != (unsigned short)(1U << 16)) {
+ k = 1U << tablebits;
+ while (i != k) table[i++] = 0;
+ }
+
+ avail = nchar;
+ mask = 1U << (15 - tablebits);
+ for (ch = 0; ch < nchar; ch++) {
+ if ((len = bitlen[ch]) == 0) continue;
+ nextcode = start[len] + weight[len];
+ if (len <= tablebits) {
+ for (i = start[len]; i < nextcode; i++) table[i] = ch;
+ } else {
+ k = start[len];
+ p = &table[k >> jutbits];
+ i = len - tablebits;
+ while (i != 0) {
+ if (*p == 0) {
+ right[avail] = left[avail] = 0;
+ *p = avail++;
+ }
+ if (k & mask) p = &right[*p];
+ else p = &left[*p];
+ k <<= 1; i--;
+ }
+ *p = ch;
+ }
+ start[len] = nextcode;
+ }
+}
+
+// static Huffman
+
+static void read_pt_len(int nn, int nbit, int i_special)
+{
+ int i, c, n;
+ unsigned short mask;
+
+ n = getbits(nbit);
+ if (n == 0) {
+ c = getbits(nbit);
+ for (i = 0; i < nn; i++) pt_len[i] = 0;
+ for (i = 0; i < 256; i++) pt_table[i] = c;
+ } else {
+ i = 0;
+ while (i < n) {
+ c = bitbuf >> (BITBUFSIZ - 3);
+ if (c == 7) {
+ mask = 1U << (BITBUFSIZ - 1 - 3);
+ while (mask & bitbuf) { mask >>= 1; c++; }
+ }
+ fillbuf((c < 7) ? 3 : c - 3);
+ pt_len[i++] = c;
+ if (i == i_special) {
+ c = getbits(2);
+ while (--c >= 0) pt_len[i++] = 0;
+ }
+ }
+ while (i < nn) pt_len[i++] = 0;
+ make_table(nn, pt_len, 8, pt_table);
+ }
+}
+
+static void read_c_len(void)
+{
+ int i, c, n;
+ unsigned short mask;
+
+ n = getbits(CBIT);
+ if (n == 0) {
+ c = getbits(CBIT);
+ for (i = 0; i < NC; i++) c_len[i] = 0;
+ for (i = 0; i < 4096; i++) c_table[i] = c;
+ } else {
+ i = 0;
+ while (i < n) {
+ c = pt_table[bitbuf >> (BITBUFSIZ - 8)];
+ if (c >= NT) {
+ mask = 1U << (BITBUFSIZ - 1 - 8);
+ do {
+ if (bitbuf & mask) c = right[c];
+ else c = left [c];
+ mask >>= 1;
+ } while (c >= NT);
+ }
+ fillbuf(pt_len[c]);
+ if (c <= 2) {
+ if (c == 0) c = 1;
+ else if (c == 1) c = getbits(4) + 3;
+ else c = getbits(CBIT) + 20;
+ while (--c >= 0) c_len[i++] = 0;
+ } else c_len[i++] = c - 2;
+ }
+ while (i < NC) c_len[i++] = 0;
+ make_table(NC, c_len, 12, c_table);
+ }
+}
+
+
+static unsigned short decode_c(void)
+{
+ unsigned short j, mask;
+
+ if (blocksize == 0) {
+ blocksize = getbits(16);
+ read_pt_len(NT, TBIT, 3);
+ read_c_len();
+ read_pt_len(NP, PBIT, -1);
+ }
+ blocksize--;
+ j = c_table[bitbuf >> (BITBUFSIZ - 12)];
+ if (j >= NC) {
+ mask = 1U << (BITBUFSIZ - 1 - 12);
+ do {
+ if (bitbuf & mask) j = right[j];
+ else j = left [j];
+ mask >>= 1;
+ } while (j >= NC);
+ }
+ fillbuf(c_len[j]);
+ return j;
+}
+
+
+static unsigned short decode_p(void)
+{
+ unsigned short j, mask;
+
+ j = pt_table[bitbuf >> (BITBUFSIZ - 8)];
+ if (j >= NP) {
+ mask = 1U << (BITBUFSIZ - 1 - 8);
+ do {
+ if (bitbuf & mask) j = right[j];
+ else j = left [j];
+ mask >>= 1;
+ } while (j >= NP);
+ }
+ fillbuf(pt_len[j]);
+ if (j != 0) j = (1U << (j - 1)) + getbits(j - 1);
+ return j;
+}
+
+
+static void decode(unsigned short count, unsigned char buffer[])
+{
+ static unsigned short i;
+ unsigned short r, c;
+
+ r = 0;
+ while (--j >= 0) {
+ buffer[r] = buffer[i];
+ i = (i + 1) & (DICSIZ - 1);
+ if (++r == count) return;
+ }
+ for ( ; ; ) {
+ c = decode_c();
+ if (c <= UCHAR_MAX) {
+ buffer[r] = c & UCHAR_MAX;
+ if (++r == count) return;
+ } else {
+ j = c - (UCHAR_MAX + 1 - THRESHOLD);
+ i = (r - decode_p() - 1) & (DICSIZ - 1);
+ while (--j >= 0) {
+ buffer[r] = buffer[i];
+ i = (i + 1) & (DICSIZ - 1);
+ if (++r == count) return;
+ }
+ }
+ }
+}
+
+void lh5_decode(const unsigned char *inp, unsigned char *outp, unsigned long original_size, unsigned long packed_size)
+{
+ unsigned short n;
+ unsigned char *buffer;
+
+ compsize = packed_size;
+ origsize = original_size;
+ in_buf = inp;
+ out_buf = outp;
+
+#if 0
+ fprintf(stderr, "DEBUG: compsize = %ld, origsize = %ld, first 8 bytes of packed data:\n", packed_size, original_size);
+ fprintf(stderr, " %02x %02x %02x %02x %02x %02x %02x %02x \n",
+ *(inp), *(inp+1),*(inp+2),*(inp+3),
+ *(inp+4),*(inp+5),*(inp+6),*(inp+7));
+#endif
+
+ buffer = (unsigned char *) malloc(DICSIZ);
+ if (!buffer) error ("Out of memory");
+
+ bitbuf = 0; subbitbuf = 0; bitcount = 0;
+ fillbuf(BITBUFSIZ);
+ blocksize = 0;
+ j = 0;
+
+ while (origsize != 0) {
+ n = (origsize > DICSIZ) ? DICSIZ : (unsigned short)origsize;
+ decode(n, buffer);
+ memmove(out_buf, buffer, n);
+ out_buf += n;
+ origsize -= n;
+ }
+
+ if (buffer) free (buffer);
+ buffer = NULL;
+}
diff --git a/plugins/vtx/vtx.c b/plugins/vtx/vtx.c
new file mode 100644
index 00000000..2014aee8
--- /dev/null
+++ b/plugins/vtx/vtx.c
@@ -0,0 +1,162 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009 Alexey Yakovenko
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#include <stdlib.h>
+#include <string.h>
+#include "../../deadbeef.h"
+#include "ayemu.h"
+
+#define min(x,y) ((x)<(y)?(x):(y))
+#define max(x,y) ((x)>(y)?(x):(y))
+
+#define trace(...) { fprintf (stderr, __VA_ARGS__); }
+//#define trace(fmt,...)
+
+static DB_decoder_t plugin;
+static DB_functions_t *deadbeef;
+
+static const char * exts[] = { "vtx", NULL };
+static const char *filetypes[] = { "VTX", NULL };
+
+static int
+vtx_init (DB_playItem_t *it) {
+ // prepare to decode the track
+ // return -1 on failure
+ return 0;
+}
+
+static void
+vtx_free (void) {
+ // free everything allocated in _init
+}
+
+static int
+vtx_read_int16 (char *bytes, int size) {
+ // try decode `size' bytes
+ // return number of decoded bytes
+ // return 0 on EOF
+ return 0;
+}
+
+static int
+vtx_seek_sample (int sample) {
+ // seek to specified sample (frame)
+ // return 0 on success
+ // return -1 on failure
+}
+
+static int
+vtx_seek (float time) {
+ // seek to specified time in seconds
+ // return 0 on success
+ // return -1 on failure
+ // e.g. return vtx_seek_sample (time * samplerate);
+ return 0;
+}
+
+static DB_playItem_t *
+vtx_insert (DB_playItem_t *after, const char *fname) {
+ // read information from the track
+ // load/process cuesheet if exists
+ // insert track into playlist
+ // return track pointer on success
+ // return NULL on failure
+
+ trace ("vtx_insert %s\n");
+ // load header
+ DB_FILE *fp = deadbeef->fopen (fname);
+ if (!fp) {
+ trace ("vtx: failed to open file\n");
+ return NULL;
+ }
+ char buf[0x4000];
+ size_t sz;
+ sz = deadbeef->fread (buf, 1, sizeof (buf), fp);
+ deadbeef->fclose (fp);
+ if (sz <= 0) {
+ trace ("vtx: failed to read header data from file\n");
+ return NULL;
+ }
+ ayemu_vtx_t *hdr = ayemu_vtx_header (buf, sz);
+ if (!hdr) {
+ trace ("vtx: failed to read header\n");
+ return NULL;
+ }
+
+ DB_playItem_t *it = deadbeef->pl_item_alloc ();
+
+ it->decoder = &plugin;
+ it->fname = strdup (fname);
+ it->filetype = filetypes[0];
+
+ int totalsamples = 44100*60*5;
+ deadbeef->pl_set_item_duration (it, (float)totalsamples/hdr->playerFreq);
+
+ // add metadata
+ deadbeef->pl_add_meta (it, "title", NULL);
+
+ ayemu_vtx_free (hdr);
+ after = deadbeef->pl_insert_item (after, it);
+ return after;
+}
+
+static int
+vtx_start (void) {
+ // do one-time plugin initialization here
+ // e.g. starting threads for background processing, subscribing to events, etc
+ // return 0 on success
+ // return -1 on failure
+ return 0;
+}
+static int
+vtx_stop (void) {
+ // undo everything done in _start here
+ // return 0 on success
+ // return -1 on failure
+ return 0;
+}
+// define plugin interface
+static DB_decoder_t plugin = {
+ DB_PLUGIN_SET_API_VERSION
+ .plugin.version_major = 0,
+ .plugin.version_minor = 1,
+ .plugin.type = DB_PLUGIN_DECODER,
+ .plugin.name = "VTX decoder",
+ .plugin.descr = "AY8910/12 chip emulator and vtx file player",
+ .plugin.author = "Alexey Yakovenko",
+ .plugin.email = "waker@users.sourceforge.net",
+ .plugin.website = "http://deadbeef.sf.net",
+ .plugin.start = vtx_start,
+ .plugin.stop = vtx_stop,
+ .init = vtx_init,
+ .free = vtx_free,
+ .read_int16 = vtx_read_int16,
+// .read_float32 = vtx_read_float32,
+ .seek = vtx_seek,
+ .seek_sample = vtx_seek_sample,
+ .insert = vtx_insert,
+ .exts = exts,
+ .id = "vtx",
+ .filetypes = filetypes
+};
+
+DB_plugin_t *
+vtx_load (DB_functions_t *api) {
+ deadbeef = api;
+ return DB_PLUGIN (&plugin);
+}
diff --git a/plugins/vtx/vtxfile.c b/plugins/vtx/vtxfile.c
new file mode 100644
index 00000000..9dbeb9f7
--- /dev/null
+++ b/plugins/vtx/vtxfile.c
@@ -0,0 +1,283 @@
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "ayemu.h"
+
+#define AYEMU_VTX_STRING_MAX 254
+
+typedef const char * data_ptr_t;
+
+
+/* LHA5 decoder, defined in lh5dec.c */
+extern void lh5_decode(unsigned const char *inp,
+ unsigned char *outp,
+ unsigned long original_size,
+ unsigned long packed_size);
+
+/* Read 8-bit integer from file.
+ */
+static data_ptr_t read_byte(data_ptr_t pos, int *p)
+{
+ const unsigned char *data = (const unsigned char*)pos;
+ *p = *data++;
+ return (data_ptr_t)data;
+}
+
+/* Read 16-bit little-endian 1234 integer from file.
+ */
+static data_ptr_t read_word16(data_ptr_t pos, int *p)
+{
+ const unsigned char *data = (const unsigned char*)pos;
+ *p = *data++;
+ *p += *data++ << 8;
+ return (data_ptr_t)data;
+}
+
+/* read 32-bit integer from file.
+ */
+static data_ptr_t read_word32(data_ptr_t pos, int *p)
+{
+ const unsigned char *data = (const unsigned char*)pos;
+ *p = *data++;
+ *p += *data++ << 8;
+ *p += *data++ << 16;
+ *p += *data++ << 24;
+ return (data_ptr_t)data;
+}
+
+/* read_string: max 254 chars len (+1 for null terminator).
+ */
+static data_ptr_t read_string(data_ptr_t pos, char **res)
+{
+ int len;
+
+ if (pos == NULL)
+ return NULL;
+
+ len = strlen(pos);
+
+ if (len > AYEMU_VTX_STRING_MAX) {
+ fprintf(stderr, "Error: string len more than %d (=%d)\n", AYEMU_VTX_STRING_MAX, len);
+ return NULL;
+ }
+
+ *res = calloc(1, len + 1);
+
+ strcpy(*res, pos);
+
+ return pos + len + 1;
+}
+
+static data_ptr_t read_header(data_ptr_t buf, ayemu_vtx_t **target, size_t size)
+{
+ char hdr[3];
+ ayemu_vtx_t *vtx;
+
+ hdr[0] = tolower(*buf++);
+ hdr[1] = tolower(*buf++);
+ hdr[2] = '\0';
+
+ if (size < 20) {
+ fprintf(stderr, "ayemu_vtx_open: file size < 20 bytes - it is impossible\n");
+ return NULL;
+ }
+
+ vtx = (ayemu_vtx_t*) calloc(1, sizeof(ayemu_vtx_t));
+
+ if (strncmp(hdr, "ay", 2) == 0)
+ vtx->chiptype = AYEMU_AY;
+ else if (strncmp (hdr, "ym", 2) == 0)
+ vtx->chiptype = AYEMU_YM;
+ else {
+ fprintf (stderr, "File is _not_ VORTEX format!\n"
+ "It not begins with 'ay' or 'ym' string.\n");
+ goto clean_and_ret_null;
+ }
+
+ buf = read_byte(buf, &vtx->stereo);
+ buf = read_word16(buf, &vtx->loop);
+ buf = read_word32(buf, &vtx->chipFreq);
+ buf = read_byte(buf, &vtx->playerFreq);
+ buf = read_word16(buf, &vtx->year);
+ buf = read_word32(buf, &vtx->regdata_size);
+
+ buf = read_string(buf, &vtx->title);
+ buf = read_string(buf, &vtx->author);
+ buf = read_string(buf, &vtx->from);
+ buf = read_string(buf, &vtx->tracker);
+ buf = read_string(buf, &vtx->comment);
+
+ *target = vtx;
+ return buf;
+
+ clean_and_ret_null:
+
+ ayemu_vtx_free(vtx);
+ return NULL;
+}
+
+
+ayemu_vtx_t * ayemu_vtx_header(data_ptr_t buf, size_t size)
+{
+ ayemu_vtx_t *vtx;
+
+ const char *data;
+
+ data = read_header(buf, &vtx, size);
+
+ return vtx;
+}
+
+
+ayemu_vtx_t * ayemu_vtx_load(data_ptr_t buf, size_t size)
+{
+ ayemu_vtx_t *vtx;
+
+ const char *data = read_header(buf, &vtx, size);
+
+ if (! data) {
+ fprintf(stderr, "ayemu_vtx_load: Cannot parse file header\n");
+ return NULL;
+ }
+
+ // unpack data
+ size -= (buf - data);
+
+ if ((vtx->regdata = (unsigned char *) malloc (vtx->regdata_size)) == NULL) {
+ fprintf (stderr, "ayemu_vtx_load_data: Can allocate %d bytes"
+ " for unpack register data\n", vtx->regdata_size);
+ return NULL;
+ }
+
+ lh5_decode ((unsigned char*)data, vtx->regdata, vtx->regdata_size, size);
+
+ vtx->frames = vtx->regdata_size / 14;
+
+ return vtx;
+}
+
+
+/** Get specified data frame by number.
+ *
+ */
+void ayemu_vtx_getframe(const ayemu_vtx_t *vtx, size_t frame_n, ayemu_ay_reg_frame_t regs)
+{
+ int n;
+
+ if (frame_n >= vtx->frames)
+ return;
+
+ // calculate begin of data
+ unsigned char *p = vtx->regdata + frame_n;
+
+ // step is data size / 14
+ for(n = 0 ; n < 14 ; n++) {
+ regs[n] = *p;
+ p += vtx->frames;
+ }
+}
+
+/** Free all allocaded resources.
+ *
+ */
+void ayemu_vtx_free(ayemu_vtx_t *vtx)
+{
+#define FREE_PTR(x) if (x) { free(x); x = NULL; }
+
+ FREE_PTR(vtx->title);
+ FREE_PTR(vtx->author);
+ FREE_PTR(vtx->from);
+ FREE_PTR(vtx->tracker);
+ FREE_PTR(vtx->comment);
+ FREE_PTR(vtx->regdata);
+}
+
+
+
+
+ayemu_vtx_t * ayemu_vtx_header_from_file(const char *filename)
+{
+ ayemu_vtx_t *ret;
+ size_t size;
+ const size_t page_size = (size_t) sysconf (_SC_PAGESIZE);
+ int fd;
+ struct stat st;
+
+ // printf("Page size is %d\n", page_size);
+
+ if (stat(filename, &st) != 0) {
+ fprintf(stderr, "Can't stat file %s: %s\n", filename, strerror(errno));
+ return NULL;
+ }
+ size = st.st_size;
+
+ fd = open(filename, O_RDONLY, 0);
+ if (fd == 0) {
+ fprintf(stderr, "Can't open file %s: %s\n", filename, strerror(errno));
+ return NULL;
+ }
+
+ size_t data_len = (size / page_size + 1) * page_size;
+
+ char *data = mmap(NULL, data_len, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (data == (void*)(-1)) {
+ fprintf(stderr, "Can't mmap file %s: %s\n", filename, strerror(errno));
+ return NULL;
+ }
+
+ ret = ayemu_vtx_header(data, size);
+
+ if (munmap(data, data_len) != 0) {
+ fprintf(stderr, "Can't munmmap file %s: %s\n", filename, strerror(errno));
+ }
+
+ return ret;
+}
+
+
+ayemu_vtx_t * ayemu_vtx_load_from_file(const char *filename)
+{
+ size_t size;
+ const size_t page_size = (size_t) sysconf (_SC_PAGESIZE);
+ int fd;
+ struct stat st;
+ ayemu_vtx_t *ret;
+
+ // printf("Page size is %d\n", page_size);
+
+ if (stat(filename, &st) != 0) {
+ fprintf(stderr, "Can't stat file %s: %s\n", filename, strerror(errno));
+ return NULL;
+ }
+ size = st.st_size;
+
+ fd = open(filename, O_RDONLY, 0);
+ if (fd == 0) {
+ fprintf(stderr, "Can't open file %s: %s\n", filename, strerror(errno));
+ return NULL;
+ }
+
+ size_t data_len = (size / page_size + 1) * page_size;
+
+ char *data = mmap(NULL, data_len, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (data == (void*)(-1)) {
+ fprintf(stderr, "Can't mmap file %s: %s\n", filename, strerror(errno));
+ return NULL;
+ }
+
+ ret = ayemu_vtx_load(data, size);
+
+ if (munmap(data, data_len) != 0) {
+ fprintf(stderr, "Can't munmmap file %s: %s\n", filename, strerror(errno));
+ }
+
+ return ret;
+}