summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <wakeroid@gmail.com>2010-05-31 20:01:59 +0200
committerGravatar Alexey Yakovenko <wakeroid@gmail.com>2010-05-31 20:01:59 +0200
commit9beeeadca3d347fefd46da2ef190d3be9653a4ff (patch)
tree8e219ada509eef6de7162704e975c08811b3578a
parent24c83bd204883f3847aecd3cbed8ee3b8ed2169e (diff)
wildmidi plugin
-rw-r--r--plugins/wildmidi/COPYING340
-rw-r--r--plugins/wildmidi/Makefile.am13
-rw-r--r--plugins/wildmidi/README82
-rw-r--r--plugins/wildmidi/include/wildmidi_lib.h56
-rw-r--r--plugins/wildmidi/src/wildmidi.c1128
-rw-r--r--plugins/wildmidi/src/wildmidi_lib.c5072
-rw-r--r--plugins/wildmidi/wildmidiplug.c170
7 files changed, 6861 insertions, 0 deletions
diff --git a/plugins/wildmidi/COPYING b/plugins/wildmidi/COPYING
new file mode 100644
index 00000000..45645b4b
--- /dev/null
+++ b/plugins/wildmidi/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/wildmidi/Makefile.am b/plugins/wildmidi/Makefile.am
new file mode 100644
index 00000000..e12e95a7
--- /dev/null
+++ b/plugins/wildmidi/Makefile.am
@@ -0,0 +1,13 @@
+if HAVE_WILDMIDI
+wildmidipath=@top_srcdir@/plugins/wildmidi
+
+EXTRA_DIST = $(wildmidipath)/README
+
+pkglib_LTLIBRARIES = wildmidi.la
+
+wildmidi_la_SOURCES = wildmidiplug.c src/wildmidi.c src/wildmidi_lib.c include/wildmidi_lib.h
+
+wildmidi_la_LDFLAGS = -module
+
+AM_CFLAGS = $(CFLAGS) -std=c99 -I$(wildmidipath)/include -DWILDMIDI_VERSION=\"0.2.2\" -DWILDMIDILIB_VERSION=\"0.2.2\" -DTIMIDITY_CFG=\"/etc/timidity.conf\" -fPIC
+endif
diff --git a/plugins/wildmidi/README b/plugins/wildmidi/README
new file mode 100644
index 00000000..b9f60e5a
--- /dev/null
+++ b/plugins/wildmidi/README
@@ -0,0 +1,82 @@
+WildMidi v0.2.0 Release
+
+Introduction
+==============
+
+WildMidi is a wave table player that uses gus pat sound sets to play midi file. The WildMidi player
+is the frontend, and is only designed to pass information to the core library and output any audio
+data the library returns.
+
+The core of the project, libWildMidi, is the work horse behind the player. Designed to be used in future
+and existing projects, like QuakeForge (http://www.quakeforge.net), its capable of multithreading and
+multiprocessing of midi files, allowing for the mixing of multiple midi file at any one time if someone
+had a desire to do so. This library is what turns the midi files into audio data using the gus pat sets.
+
+Not all midi events are supported by the core library at this stage, and more research is being done to
+improve performance and quality so that more events can be added.
+
+At the moment Wildmidi will only work in linux and cygwin. Native windows support is not available
+at this stage but is planned.
+
+
+Installation
+==============
+to compile and install wildmidi use the following proceedure
+
+./configure
+make
+make install
+
+This will work for both linux and cygwin
+
+FreeBSD users, use ./configure --with-timidity-cfg=/usr/local/share/timidity/timidity.cfg
+
+If you want to change the default timidity.cfg path and/or file use --with-timidity-cfg=/full/path_and_filename/of/new/config.cfg
+
+Running
+=============
+
+NOTE: it is assumed here that your system is setup correctly and that you have
+installed some gus pats. I personally recommend eawpats, but you may have your
+own favorates.
+
+If you have /etc/timidity.cfg, once installed you can simply do
+
+wildmidi <midi file name>
+
+if not, you can use the command line option -c to point wildmidi to the timidity.cfg
+
+example: wildmidi -c ~/guspats/timidity.cfg
+
+
+Once the program is running, you can quit from it by pressing q
+
+Cygwin users: Yes, I know about the screen roll. I am looking at a different interface
+ to corrct this.
+
+
+Further Information
+===================
+For further information feel free to contact myself at one of the following
+
+Email: wildcode@users.sourceforge.net
+IRC: #quakeforge on irc.oftc.net
+
+
+Known Bugs
+===========
+
+1) Reverb engine fails badly at rates below 22050
+2) Output in cygwin scrolls
+3) Surround options looses base on surround systems
+4) Some midi file lengths (total time) are reported wrong
+
+
+Thanks to
+==========
+Quakeforge .. http://www.quakeforge.net
+ irc: #quakeforge irc.oftc.net
+
+Eric A Welsh .. http://www.stardate.bc.ca/eawpatches/html/default.htm
+
+xmms .. http://www.xmms.org/
diff --git a/plugins/wildmidi/include/wildmidi_lib.h b/plugins/wildmidi/include/wildmidi_lib.h
new file mode 100644
index 00000000..b95eb392
--- /dev/null
+++ b/plugins/wildmidi/include/wildmidi_lib.h
@@ -0,0 +1,56 @@
+/*
+ wildmidi_lib.h
+
+ Midi Wavetable Processing library
+
+ Copyright (C)2001-2004 Chris Ison
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Email: cisos@bigpond.net.au
+ wildcode@users.sourceforge.net
+
+ $Id: wildmidi_lib.h,v 1.6 2004/01/26 02:24:33 wildcode Exp $
+*/
+
+#define WM_MO_LINEAR_VOLUME 0x0001
+#define WM_MO_EXPENSIVE_INTERPOLATION 0x0002
+#define WM_MO_REVERB 0x0004
+#define WM_MO_BIG_ENDIAN_OUTPUT 0x0020
+
+#define WM_GS_VERSION 0x0001
+
+struct _WM_Info {
+ unsigned long int current_sample;
+ unsigned long int approx_total_samples;
+ unsigned short int mixer_options;
+};
+
+typedef void midi;
+
+extern const char * WildMidi_GetString (unsigned short int info);
+extern int WildMidi_Init (const char * config_file, unsigned short int rate, unsigned short int options);
+extern int WildMidi_MasterVolume (unsigned char master_volume);
+extern midi * WildMidi_Open (const char *midifile);
+extern midi * WildMidi_OpenBuffer (unsigned char *midibuffer, unsigned long int size);
+extern int WildMidi_LoadSamples ( midi * handle);
+extern int WildMidi_GetOutput (midi * handle, char * buffer, unsigned long int size);
+extern int WildMidi_SetOption (midi * handle, unsigned short int options, unsigned short int setting);
+extern struct _WM_Info * WildMidi_GetInfo ( midi * handle );
+extern int WildMidi_FastSeek ( midi * handle, unsigned long int *sample_pos);
+extern int WildMidi_SampledSeek ( midi * handle, unsigned long int *sample_pos);
+extern int WildMidi_Close (midi * handle);
+extern int WildMidi_Shutdown ( void );
+// extern void WildMidi_ReverbSet(midi * handle, float width, float wet, float dry, float damp, float roomsize);
diff --git a/plugins/wildmidi/src/wildmidi.c b/plugins/wildmidi/src/wildmidi.c
new file mode 100644
index 00000000..8baa53f5
--- /dev/null
+++ b/plugins/wildmidi/src/wildmidi.c
@@ -0,0 +1,1128 @@
+ /*
+ wildmidi.c
+
+ Midi Player using the WildMidi Midi Processing Library
+
+ Copyright (C)2001-2004 Chris Ison
+
+ 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
+
+ Email: cisos@bigpond.net.au
+ wildcode@users.sourceforge.net
+
+ $Id: wildmidi.c,v 1.21 2004/01/28 05:45:09 wildcode Exp $
+*/
+
+#include "config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef _WIN32
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#if (defined _WIN32) || (defined __CYGWIN__)
+# include <conio.h>
+# include <windows.h>
+# include <mmsystem.h>
+#else
+# ifdef HAVE_ALSA
+# include <alsa/asoundlib.h>
+# else
+# ifdef HAVE_SYS_SOUNDCARD_H
+# include <sys/soundcard.h>
+# elif defined HAVE_LINUX_SOUNDCARD_H
+# include <linux/soundcard.h>
+# elif HAVE_MACHINE_SOUNDCARD_H
+# include <machine/soundcard.h>
+# endif
+# endif
+#endif
+
+#include "wildmidi_lib.h"
+
+#ifndef FNONBLOCK
+#define FNONBLOCK _FNONBLOCK
+#endif
+
+
+struct _midi_test {
+ unsigned char *data;
+ unsigned long int size;
+};
+
+// scale test from 0 to 127
+/* test a
+ * offset 18-21 (0x12-0x15) - track size
+ * offset 25 (0x1A) = bank number
+ * offset 28 (0x1D) = patch number
+ */
+unsigned char midi_test_c_scale[] = {
+ 0x4d, 0x54, 0x68, 0x64, 0x00, 0x00, 0x00, 0x06, // 0x00
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x4d, 0x54, // 0x08
+ 0x72, 0x6b, 0x00, 0x00, 0x02, 0x63, 0x00, 0xb0, // 0x10
+ 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x90, 0x00, // 0x18 C
+ 0x64, 0x08, 0x80, 0x00, 0x00, 0x08, 0x90, 0x02, // 0x20 D
+ 0x64, 0x08, 0x80, 0x02, 0x00, 0x08, 0x90, 0x04, // 0x28 E
+ 0x64, 0x08, 0x80, 0x04, 0x00, 0x08, 0x90, 0x05, // 0x30 F
+ 0x64, 0x08, 0x80, 0x05, 0x00, 0x08, 0x90, 0x07, // 0x38 G
+ 0x64, 0x08, 0x80, 0x07, 0x00, 0x08, 0x90, 0x09, // 0x40 A
+ 0x64, 0x08, 0x80, 0x09, 0x00, 0x08, 0x90, 0x0b, // 0x48 B
+ 0x64, 0x08, 0x80, 0x0b, 0x00, 0x08, 0x90, 0x0c, // 0x50 C
+ 0x64, 0x08, 0x80, 0x0c, 0x00, 0x08, 0x90, 0x0e, // 0x58 D
+ 0x64, 0x08, 0x80, 0x0e, 0x00, 0x08, 0x90, 0x10, // 0x60 E
+ 0x64, 0x08, 0x80, 0x10, 0x00, 0x08, 0x90, 0x11, // 0x68 F
+ 0x64, 0x08, 0x80, 0x11, 0x00, 0x08, 0x90, 0x13, // 0x70 G
+ 0x64, 0x08, 0x80, 0x13, 0x00, 0x08, 0x90, 0x15, // 0x78 A
+ 0x64, 0x08, 0x80, 0x15, 0x00, 0x08, 0x90, 0x17, // 0x80 B
+ 0x64, 0x08, 0x80, 0x17, 0x00, 0x08, 0x90, 0x18, // 0x88 C
+ 0x64, 0x08, 0x80, 0x18, 0x00, 0x08, 0x90, 0x1a, // 0x90 D
+ 0x64, 0x08, 0x80, 0x1a, 0x00, 0x08, 0x90, 0x1c, // 0x98 E
+ 0x64, 0x08, 0x80, 0x1c, 0x00, 0x08, 0x90, 0x1d, // 0xA0 F
+ 0x64, 0x08, 0x80, 0x1d, 0x00, 0x08, 0x90, 0x1f, // 0xA8 G
+ 0x64, 0x08, 0x80, 0x1f, 0x00, 0x08, 0x90, 0x21, // 0xB0 A
+ 0x64, 0x08, 0x80, 0x21, 0x00, 0x08, 0x90, 0x23, // 0xB8 B
+ 0x64, 0x08, 0x80, 0x23, 0x00, 0x08, 0x90, 0x24, // 0xC0 C
+ 0x64, 0x08, 0x80, 0x24, 0x00, 0x08, 0x90, 0x26, // 0xC8 D
+ 0x64, 0x08, 0x80, 0x26, 0x00, 0x08, 0x90, 0x28, // 0xD0 E
+ 0x64, 0x08, 0x80, 0x28, 0x00, 0x08, 0x90, 0x29, // 0xD8 F
+ 0x64, 0x08, 0x80, 0x29, 0x00, 0x08, 0x90, 0x2b, // 0xE0 G
+ 0x64, 0x08, 0x80, 0x2b, 0x00, 0x08, 0x90, 0x2d, // 0xE8 A
+ 0x64, 0x08, 0x80, 0x2d, 0x00, 0x08, 0x90, 0x2f, // 0xF0 B
+ 0x64, 0x08, 0x80, 0x2f, 0x00, 0x08, 0x90, 0x30, // 0xF8 C
+ 0x64, 0x08, 0x80, 0x30, 0x00, 0x08, 0x90, 0x32, // 0x100 D
+ 0x64, 0x08, 0x80, 0x32, 0x00, 0x08, 0x90, 0x34, // 0x108 E
+ 0x64, 0x08, 0x80, 0x34, 0x00, 0x08, 0x90, 0x35, // 0x110 F
+ 0x64, 0x08, 0x80, 0x35, 0x00, 0x08, 0x90, 0x37, // 0x118 G
+ 0x64, 0x08, 0x80, 0x37, 0x00, 0x08, 0x90, 0x39, // 0x120 A
+ 0x64, 0x08, 0x80, 0x39, 0x00, 0x08, 0x90, 0x3b, // 0X128 B
+ 0x64, 0x08, 0x80, 0x3b, 0x00, 0x08, 0x90, 0x3c, // 0x130 C
+ 0x64, 0x08, 0x80, 0x3c, 0x00, 0x08, 0x90, 0x3e, // 0x138 D
+ 0x64, 0x08, 0x80, 0x3e, 0x00, 0x08, 0x90, 0x40, // 0X140 E
+ 0x64, 0x08, 0x80, 0x40, 0x00, 0x08, 0x90, 0x41, // 0x148 F
+ 0x64, 0x08, 0x80, 0x41, 0x00, 0x08, 0x90, 0x43, // 0x150 G
+ 0x64, 0x08, 0x80, 0x43, 0x00, 0x08, 0x90, 0x45, // 0x158 A
+ 0x64, 0x08, 0x80, 0x45, 0x00, 0x08, 0x90, 0x47, // 0x160 B
+ 0x64, 0x08, 0x80, 0x47, 0x00, 0x08, 0x90, 0x48, // 0x168 C
+ 0x64, 0x08, 0x80, 0x48, 0x00, 0x08, 0x90, 0x4a, // 0x170 D
+ 0x64, 0x08, 0x80, 0x4a, 0x00, 0x08, 0x90, 0x4c, // 0x178 E
+ 0x64, 0x08, 0x80, 0x4c, 0x00, 0x08, 0x90, 0x4d, // 0x180 F
+ 0x64, 0x08, 0x80, 0x4d, 0x00, 0x08, 0x90, 0x4f, // 0x188 G
+ 0x64, 0x08, 0x80, 0x4f, 0x00, 0x08, 0x90, 0x51, // 0x190 A
+ 0x64, 0x08, 0x80, 0x51, 0x00, 0x08, 0x90, 0x53, // 0x198 B
+ 0x64, 0x08, 0x80, 0x53, 0x00, 0x08, 0x90, 0x54, // 0x1A0 C
+ 0x64, 0x08, 0x80, 0x54, 0x00, 0x08, 0x90, 0x56, // 0x1A8 D
+ 0x64, 0x08, 0x80, 0x56, 0x00, 0x08, 0x90, 0x58, // 0x1B0 E
+ 0x64, 0x08, 0x80, 0x58, 0x00, 0x08, 0x90, 0x59, // 0x1B8 F
+ 0x64, 0x08, 0x80, 0x59, 0x00, 0x08, 0x90, 0x5b, // 0x1C0 G
+ 0x64, 0x08, 0x80, 0x5b, 0x00, 0x08, 0x90, 0x5d, // 0x1C8 A
+ 0x64, 0x08, 0x80, 0x5d, 0x00, 0x08, 0x90, 0x5f, // 0x1D0 B
+ 0x64, 0x08, 0x80, 0x5f, 0x00, 0x08, 0x90, 0x60, // 0x1D8 C
+ 0x64, 0x08, 0x80, 0x60, 0x00, 0x08, 0x90, 0x62, // 0x1E0 D
+ 0x64, 0x08, 0x80, 0x62, 0x00, 0x08, 0x90, 0x64, // 0x1E8 E
+ 0x64, 0x08, 0x80, 0x64, 0x00, 0x08, 0x90, 0x65, // 0x1F0 F
+ 0x64, 0x08, 0x80, 0x65, 0x00, 0x08, 0x90, 0x67, // 0x1F8 G
+ 0x64, 0x08, 0x80, 0x67, 0x00, 0x08, 0x90, 0x69, // 0x200 A
+ 0x64, 0x08, 0x80, 0x69, 0x00, 0x08, 0x90, 0x6b, // 0x208 B
+ 0x64, 0x08, 0x80, 0x6b, 0x00, 0x08, 0x90, 0x6c, // 0x210 C
+ 0x64, 0x08, 0x80, 0x6c, 0x00, 0x08, 0x90, 0x6e, // 0x218 D
+ 0x64, 0x08, 0x80, 0x6e, 0x00, 0x08, 0x90, 0x70, // 0x220 E
+ 0x64, 0x08, 0x80, 0x70, 0x00, 0x08, 0x90, 0x71, // 0x228 F
+ 0x64, 0x08, 0x80, 0x71, 0x00, 0x08, 0x90, 0x73, // 0x230 G
+ 0x64, 0x08, 0x80, 0x73, 0x00, 0x08, 0x90, 0x75, // 0x238 A
+ 0x64, 0x08, 0x80, 0x75, 0x00, 0x08, 0x90, 0x77, // 0x240 B
+ 0x64, 0x08, 0x80, 0x77, 0x00, 0x08, 0x90, 0x78, // 0x248 C
+ 0x64, 0x08, 0x80, 0x78, 0x00, 0x08, 0x90, 0x7a, // 0x250 D
+ 0x64, 0x08, 0x80, 0x7a, 0x00, 0x08, 0x90, 0x7c, // 0x258 E
+ 0x64, 0x08, 0x80, 0x7c, 0x00, 0x08, 0x90, 0x7d, // 0x260 F
+ 0x64, 0x08, 0x80, 0x7d, 0x00, 0x08, 0x90, 0x7f, // 0x268 G
+ 0x64, 0x08, 0x80, 0x7f, 0x00, 0x08, 0xff, 0x2f, // 0x270
+ 0x00 // 0x278
+};
+
+struct _midi_test midi_test[]= {
+ {midi_test_c_scale, 663},
+ {NULL, 0}
+};
+
+int midi_test_max = 1;
+
+/*
+ ==============================
+ Audio Output Functions
+ ------------------------------
+ ==============================
+*/
+
+unsigned int rate = 32072;
+char *pcmname = NULL;
+
+int (*send_output) (char * output_data, int output_size);
+void (*close_output) ( void );
+int audio_fd;
+
+inline void
+shutdown_output ( void ) {
+ printf("Shutting Down Sound System\n");
+ if (audio_fd != -1)
+ close(audio_fd);
+}
+
+/*
+ Wav Output Functions
+*/
+
+static char wav_file[1024] = "\0";
+unsigned long int wav_size;
+
+int write_wav_output (char * output_data, int output_size);
+void close_wav_output ( void );
+
+int
+open_wav_output ( void ) {
+
+ char wav_hdr[] = { 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00,
+ 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74, 0x20,
+ 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
+ 0x44, 0xAC, 0x00, 0x00, 0x10, 0xB1, 0x02, 0x00,
+ 0x04, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61,
+ 0x00, 0x00, 0x00, 0x00 };
+
+ if (wav_file[0] == '\0')
+ return -1;
+#ifdef _WIN32
+ if ((audio_fd = open(wav_file, (O_RDWR | O_CREAT | O_TRUNC | O_BINARY))) < 0) {
+#else
+ if ((audio_fd = open(wav_file, (O_RDWR | O_CREAT | O_TRUNC), (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH))) < 0) {
+#endif
+ return -1;
+ } else {
+ unsigned long int bytes_per_sec;
+
+ wav_hdr[24] = (rate) & 0xFF;
+ wav_hdr[25] = (rate >> 8) & 0xFF;
+
+ bytes_per_sec = rate * 4;
+ wav_hdr[28] = (bytes_per_sec) & 0xFF;
+ wav_hdr[29] = (bytes_per_sec >> 8) & 0xFF;
+ wav_hdr[30] = (bytes_per_sec >> 16) & 0xFF;
+ wav_hdr[31] = (bytes_per_sec >> 24) & 0xFF;
+ }
+
+ if (write(audio_fd, &wav_hdr, 44) < 0) {
+ printf("ERROR: Writing Header %s\n", strerror(errno));
+ shutdown_output();
+ return -1;
+ }
+
+ wav_size = 0;
+ send_output = write_wav_output;
+ close_output = close_wav_output;
+ return 0;
+}
+
+int
+write_wav_output (char * output_data, int output_size) {
+ if (write(audio_fd, output_data, output_size) < 0) {
+ printf("ERROR: Writing Wav %s\n", strerror(errno));
+ shutdown_output();
+ return -1;
+ }
+
+ wav_size += output_size;
+ return 0;
+}
+
+void
+close_wav_output ( void ) {
+ char wav_count[4];
+ if (audio_fd == -1)
+ return;
+
+ wav_count[0] = (wav_size) & 0xFF;
+ wav_count[1] = (wav_size >> 8) & 0xFF;
+ wav_count[2] = (wav_size >> 16) & 0xFF;
+ wav_count[3] = (wav_size >> 24) & 0xFF;
+ lseek(audio_fd,40,SEEK_SET);
+ write(audio_fd,&wav_count,4);
+
+ wav_size += 36;
+ wav_count[0] = (wav_size) & 0xFF;
+ wav_count[1] = (wav_size >> 8) & 0xFF;
+ wav_count[2] = (wav_size >> 16) & 0xFF;
+ wav_count[3] = (wav_size >> 24) & 0xFF;
+ lseek(audio_fd,4,SEEK_SET);
+ write(audio_fd,&wav_count,4);
+
+ shutdown_output();
+}
+
+
+#if (defined _WIN32) || (defined __CYGWIN__)
+
+HWAVEOUT hWaveOut;
+WAVEHDR header;
+unsigned long int mm_buffer_count;
+static CRITICAL_SECTION waveCriticalSection;
+
+int write_mm_output (char * output_data, int output_size);
+void close_mm_output ( void );
+
+WAVEHDR *mm_blocks;
+#define MM_BLOCK_SIZE 16384
+#define MM_BLOCK_COUNT 3
+
+unsigned long int mm_free_blocks = MM_BLOCK_COUNT;
+unsigned long int mm_current_block = 0;
+
+static void CALLBACK mmOutProc( HWAVEOUT hWaveOut, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) {
+ int* freeBlockCounter = (int*)dwInstance;
+ if(uMsg != WOM_DONE)
+ return;
+ EnterCriticalSection(&waveCriticalSection);
+ (*freeBlockCounter)++;
+ LeaveCriticalSection(&waveCriticalSection);
+}
+
+
+int
+open_mm_output ( void ) {
+ WAVEFORMATEX wfx;
+ char *mm_buffer;
+ int i;
+
+ InitializeCriticalSection(&waveCriticalSection);
+
+ if((mm_buffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, ((MM_BLOCK_SIZE + sizeof(WAVEHDR)) * MM_BLOCK_COUNT))) == NULL) {
+ printf("Memory allocation error\n");
+ return -1;
+ }
+
+ mm_blocks = (WAVEHDR*)mm_buffer;
+ mm_buffer += sizeof(WAVEHDR) * MM_BLOCK_COUNT;
+
+ for(i = 0; i < MM_BLOCK_COUNT; i++) {
+ mm_blocks[i].dwBufferLength = MM_BLOCK_SIZE;
+ mm_blocks[i].lpData = mm_buffer;
+ mm_buffer += MM_BLOCK_SIZE;
+ }
+
+ wfx.nSamplesPerSec = rate;
+ wfx.wBitsPerSample = 16;
+ wfx.nChannels = 2;
+ wfx.cbSize = 0;
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
+ wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
+
+ if(waveOutOpen( &hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)mmOutProc, (DWORD_PTR)&mm_free_blocks, CALLBACK_FUNCTION ) != MMSYSERR_NOERROR) {
+ printf("unable to open WAVE_MAPPER device\n");
+ return -1;
+ }
+
+
+ send_output = write_mm_output;
+ close_output = close_mm_output;
+ return 0;
+}
+
+int
+write_mm_output (char * output_data, int output_size) {
+ WAVEHDR* current;
+ int free_size = 0;
+ int data_read = 0;
+ current = &mm_blocks[mm_current_block];
+
+ while (output_size) {
+ if(current->dwFlags & WHDR_PREPARED)
+ waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR));
+ free_size = MM_BLOCK_SIZE - current->dwUser;
+ if (free_size > output_size)
+ free_size = output_size;
+
+ memcpy(current->lpData + current->dwUser, &output_data[data_read], free_size);
+ current->dwUser += free_size;
+ output_size -= free_size;
+ data_read += free_size;
+
+ if (current->dwUser < MM_BLOCK_SIZE) {
+ return 0;
+ }
+
+ current->dwBufferLength = MM_BLOCK_SIZE;
+ waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR));
+ waveOutWrite(hWaveOut, current, sizeof(WAVEHDR));
+ EnterCriticalSection(&waveCriticalSection);
+ mm_free_blocks--;
+ LeaveCriticalSection(&waveCriticalSection);
+ while(!mm_free_blocks)
+ Sleep(10);
+ mm_current_block++;
+ mm_current_block %= MM_BLOCK_COUNT;
+ current = &mm_blocks[mm_current_block];
+ current->dwUser = 0;
+ }
+ return 0;
+}
+
+void
+close_mm_output ( void ) {
+ WAVEHDR* current;
+ int i, j;
+ current = &mm_blocks[mm_current_block];
+ i = MM_BLOCK_SIZE - current->dwUser;
+
+ for (j = i; i; i--) write_mm_output (0, 0);
+
+ waveOutClose (hWaveOut);
+ HeapFree(GetProcessHeap(), 0, mm_blocks);
+}
+
+#else
+#ifdef HAVE_ALSA
+
+void *buffer;
+int bps;
+int alsa_first_time = 1;
+static snd_pcm_t *pcm;
+static snd_pcm_uframes_t alsa_period_size;
+static snd_pcm_channel_area_t *areas;
+
+int write_alsa_output (char * output_data, int output_size);
+void close_alsa_output ( void );
+
+int
+open_alsa_output(void) {
+ snd_pcm_hw_params_t *hw;
+ snd_pcm_sw_params_t *sw;
+ int err;
+ int alsa_buffer_time, bits_per_sample;
+ unsigned int alsa_period_time;
+ snd_pcm_uframes_t alsa_buffer_size;
+
+ if (!pcmname)
+ pcmname = "default";
+
+ if ((err = snd_pcm_open (&pcm, pcmname, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
+ printf("Error: audio open error: %s\n", snd_strerror (-err));
+ return -1;
+ }
+
+ snd_pcm_hw_params_alloca (&hw);
+
+ if ((err = snd_pcm_hw_params_any(pcm, hw)) < 0) {
+ printf("ERROR: No configuration available for playback: %s\n", snd_strerror(-err));
+
+ return -1;
+ }
+
+ if ((err = snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) {
+ printf("Cannot set mmap'ed mode: %s.\n", snd_strerror(-err));
+ return -1;
+ }
+
+ if (snd_pcm_hw_params_set_format (pcm, hw, SND_PCM_FORMAT_S16) < 0) {
+ printf("ALSA does not support 16bit signed audio for your soundcard\n");
+ close_alsa_output();
+ return -1;
+ }
+
+ if (snd_pcm_hw_params_set_channels (pcm, hw, 2) < 0) {
+ printf("ALSA does not support stereo for your soundcard\n");
+ close_alsa_output();
+ return -1;
+ }
+#ifdef ALSA_NEW
+ if (snd_pcm_hw_params_set_rate_near(pcm, hw, &rate, 0) < 0) {
+#else
+ if (snd_pcm_hw_params_set_rate_near(pcm, hw, rate, 0) < 0) {
+#endif
+ printf("ALSA does not support %iHz for your soundcard\n",rate);
+ close_alsa_output();
+ return -1;
+ }
+
+ alsa_buffer_time = 500000;
+ alsa_period_time = 50000;
+#ifdef ALSA_NEW
+ if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm, hw, &alsa_buffer_time, 0)) < 0)
+#else
+ if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm, hw, alsa_buffer_time, 0)) < 0)
+#endif
+ {
+ printf("Set buffer time failed: %s.\n", snd_strerror(-err));
+ return -1;
+ }
+
+#ifdef ALSA_NEW
+ if ((err = snd_pcm_hw_params_set_period_time_near(pcm, hw, &alsa_period_time, 0)) < 0)
+#else
+ if ((err = snd_pcm_hw_params_set_period_time_near(pcm, hw, alsa_period_time, 0)) < 0)
+#endif
+ {
+ printf("Set period time failed: %s.\n", snd_strerror(-err));
+ return -1;
+ }
+
+ if (snd_pcm_hw_params(pcm, hw) < 0)
+ {
+ printf("Unable to install hw params\n");
+ return -1;
+ }
+
+#ifdef ALSA_NEW
+ if ((err = snd_pcm_hw_params_get_buffer_size(hw, &alsa_buffer_size)) < 0)
+#else
+ if ((err = snd_pcm_hw_params_get_buffer_size(hw)) < 0)
+#endif
+ {
+ printf ("snd_pcm_hw_params_get_buffer_size() failed: %s\n", snd_strerror(-err));
+ return -1;
+ }
+#ifdef ALSA_NEW
+ if ((err = snd_pcm_hw_params_get_period_size(hw, &alsa_period_size, 0)) < 0)
+#else
+ alsa_buffer_size = err;
+ if ((err = snd_pcm_hw_params_get_period_size(hw, 0)) < 0)
+#endif
+ {
+ printf ("snd_pcm_hw_params_get_period_size() failed: %s\n", snd_strerror(-err));
+ return -1;
+ }
+#ifndef ALSA_NEW
+ alsa_period_size = err;
+#endif
+ snd_pcm_sw_params_alloca(&sw);
+ snd_pcm_sw_params_current(pcm, sw);
+ if (snd_pcm_sw_params(pcm, sw) < 0)
+ {
+ printf("Unable to install sw params\n");
+ return -1;
+ }
+
+ bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16);
+ bps = (rate * bits_per_sample * 2) / 8000;
+
+ buffer = malloc(alsa_period_size * bits_per_sample / 8 * 2);
+ areas = malloc(2 * sizeof(snd_pcm_channel_area_t));
+
+ areas[0].addr = buffer;
+ areas[0].first = 0;
+ areas[0].step = 2 * bits_per_sample;
+ areas[1].addr = buffer;
+ areas[1].first = bits_per_sample;
+ areas[1].step = 2 * bits_per_sample;
+
+ send_output = write_alsa_output;
+ close_output = close_alsa_output;
+ return 0;
+}
+
+int
+write_alsa_output (char * output_data, int output_size) {
+ int cnt = 0, err;
+ snd_pcm_uframes_t offset, frames;
+ snd_pcm_sframes_t avail;
+ const snd_pcm_channel_area_t *chan_areas = areas;
+
+ while (output_size > 0) {
+ avail = snd_pcm_avail_update(pcm);
+ if (avail == -EPIPE) {
+ if (snd_pcm_state(pcm) == SND_PCM_STATE_XRUN) {
+ if ((err = snd_pcm_prepare(pcm)) < 0)
+ printf("snd_pcm_prepare() failed.\n");
+ alsa_first_time = 1;
+ }
+ } else if (avail < 0) {
+ printf("snd_pcm_avail_update() failed: %s\n", snd_strerror(-avail));
+ avail = 0;
+ }
+ if (avail < alsa_period_size) {
+ usleep(500);
+ continue;
+ }
+ frames = snd_pcm_bytes_to_frames(pcm, output_size);
+ if ((err = snd_pcm_mmap_begin(pcm, &chan_areas, &offset, &frames)) < 0) {
+ printf("snd_pcm_mmap_begin() failed: %s\n", snd_strerror(-err));
+ }
+ cnt = snd_pcm_frames_to_bytes(pcm, frames);
+ memcpy((char*) chan_areas[0].addr + snd_pcm_frames_to_bytes(pcm, offset), output_data, cnt);
+ if ((err = snd_pcm_mmap_commit(pcm, offset, frames)) < 0) {
+ if (snd_pcm_state(pcm) == SND_PCM_STATE_XRUN) {
+ if ((err = snd_pcm_prepare(pcm)) < 0)
+ printf("snd_pcm_prepare() failed.\n");
+ alsa_first_time = 1;
+ }
+ }
+ if (err != frames)
+ printf("snd_pcm_mmap_commit returned %d, expected %d\n", err, (int)frames);
+
+ output_size -= cnt;
+ output_data += cnt;
+ if (alsa_first_time) {
+ alsa_first_time = 0;
+ snd_pcm_start(pcm);
+ }
+ }
+ return 0;
+}
+
+void
+close_alsa_output ( void ) {
+ snd_pcm_close (pcm);
+ free(areas);
+ free(buffer);
+}
+
+#else
+/*
+ OSS Output Functions
+ --------------------
+ uses mmap'd audio
+*/
+
+char *buffer = NULL;
+unsigned long int max_buffer;
+unsigned long int buffer_delay;
+unsigned long int counter;
+struct audio_buf_info info;
+
+int write_oss_output (char * output_data, int output_size);
+void close_oss_output ( void );
+
+int
+open_oss_output( void ) {
+ int caps, rc, tmp;
+ unsigned long int omode = O_RDWR;
+ unsigned long int mmmode = PROT_WRITE | PROT_READ;
+ unsigned long int mmflags = MAP_FILE | MAP_SHARED;
+ unsigned long int sz = sysconf (_SC_PAGESIZE);
+
+ if (!pcmname)
+ pcmname = "/dev/dsp";
+ if ((audio_fd = open(pcmname, omode)) < 0) {
+ printf("ERROR: Unable to open /dev/dsp (%s)\n",strerror(errno));
+ return -1;
+ }
+ if (ioctl (audio_fd, SNDCTL_DSP_RESET, 0) < 0) {
+ printf("ERROR: Unable to reset /dev/dsp\n");
+ shutdown_output();
+ return -1;
+ }
+ if (ioctl (audio_fd, SNDCTL_DSP_GETCAPS, &caps) == -1) {
+ printf("ERROR: Driver Too Old\n");
+ shutdown_output();
+ return -1;
+ }
+ if (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP)) {
+ printf ("Sound device can't do memory-mapped I/O.\n");
+ shutdown_output();
+ return -1;
+ }
+ if (ioctl (audio_fd, SNDCTL_DSP_GETOSPACE, &info) == -1) {
+ printf ("Um, can't do GETOSPACE?\n");
+ shutdown_output();
+ return -1;
+ }
+ max_buffer = (info.fragstotal * info.fragsize + sz - 1) & ~(sz - 1);
+
+ rc = AFMT_S16_LE;
+ if (ioctl (audio_fd, SNDCTL_DSP_SETFMT, &rc) < 0 ) {
+ printf("Can't set 16bit\n");
+ shutdown_output();;
+ return -1;
+ }
+
+ tmp = 2;
+ if (ioctl (audio_fd, SNDCTL_DSP_CHANNELS, &tmp) < 0) {
+ printf("Can't set stereo\n");
+ shutdown_output();
+ return -1;
+ }
+
+ if (ioctl (audio_fd, SNDCTL_DSP_SPEED, &rate) < 0) {
+ printf("ERROR: /dev/dsp does not support %iHz output\n",rate);
+ shutdown_output();
+ return -1;
+ }
+
+ buffer = (unsigned char *) mmap(NULL, max_buffer, mmmode, mmflags, audio_fd, 0);
+ if (buffer == MAP_FAILED) {
+ printf("couldn't mmap %s\n",strerror(errno));
+ shutdown_output();
+ return -1;
+ }
+
+ tmp = 0;
+ if (ioctl (audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp) < 0) {
+ printf("Couldn't toggle\n");
+ munmap (buffer, info.fragstotal * info.fragsize);
+ shutdown_output();
+ return -1;
+ }
+
+ tmp = PCM_ENABLE_OUTPUT;
+ if (ioctl (audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp) < 0) {
+ printf("Couldn't toggle\n");
+ munmap (buffer, info.fragstotal * info.fragsize);
+ shutdown_output();
+ return -1;
+ }
+ buffer_delay = 1000000 / (rate / 4);
+ send_output = write_oss_output;
+ close_output = close_oss_output;
+ return 0;
+}
+
+int
+write_oss_output(char * output_data, int output_size) {
+ struct count_info count;
+ int data_read = 0;
+ int free_size = 0;
+ while (output_size != 0) {
+ while (1) {
+ if (ioctl (audio_fd, SNDCTL_DSP_GETOPTR, &count) == -1) {
+ printf("Dead Sound\n");
+ munmap (buffer, info.fragstotal * info.fragsize);
+ shutdown_output();
+ return -1;
+ }
+ if ((count.ptr < counter) || (count.ptr >= (counter+4))) {
+ break;
+ }
+ usleep(500);
+ }
+ if (count.ptr < counter) {
+ free_size = max_buffer - counter;
+ } else {
+ free_size = count.ptr - counter;
+ }
+ if (free_size > output_size)
+ free_size = output_size;
+
+ memcpy(&buffer[counter], &output_data[data_read], free_size);
+ data_read += free_size;
+ counter += free_size;
+ if (counter >= max_buffer)
+ counter = 0;
+ output_size -= free_size;
+ }
+ return 0;
+}
+
+void
+close_oss_output(void) {
+ shutdown_output();
+ if (buffer != NULL)
+ munmap (buffer, info.fragstotal * info.fragsize);
+ audio_fd = -1;
+}
+
+#endif // HAVE_ALSA
+#endif
+
+/*
+ ==============================
+ ==============================
+ ==============================
+*/
+
+
+static struct option const long_options[] = {
+ {"version",0,0,'v'},
+ {"help",0,0,'h'},
+ {"rate",1,0,'r'},
+ {"master_volume",1,0,'m'},
+ {"config_file",1,0,'c'},
+ {"wavout",1,0,'o'},
+ {"linear_vol",0,0,'l'},
+ {"reverb",0,0,'b'},
+ {"midi_test",0,0,'t'},
+ {"test_bank",1,0,'k'},
+ {"test_patch",1,0,'p'},
+ {"expensive",0,0,'e'},
+ {"device",1,0,'d'},
+ {NULL,0,NULL,0}
+};
+
+void
+do_help (void) {
+ printf(" -v --version Display version\n");
+ printf(" -h --help This help.\n");
+#ifndef _WIN32
+ printf(" -d D --device=D Use device D for audio output instead\n");
+ printf(" of the default\n");
+#endif
+ printf("Software Wavetable Options\n");
+ printf(" -o W --wavout=W Saves the output to W in wav format\n");
+ printf(" at 44100Hz 16 bit stereo\n");
+ printf(" -l --linear_vol Use linear volume adjustments\n");
+ printf(" -r N --rate=N output at N samples per second\n");
+ printf(" -c P --config_file=P P is the path and filename to your timidity.cfg\n");
+ printf(" Defaults to /etc/timidity.cfg\n\n");
+ printf(" -m V --master_volume=V Sets the master volumes, default is 100\n");
+ printf(" range is 0-127 with 127 being the loudest\n");
+}
+
+void
+do_version (void) {
+ printf("WildMidi %s Open Source Midi Sequencer\n",WILDMIDI_VERSION);
+ printf("Copyright (C) 2001-2004 Chris Ison wildcode@users.sourceforge.net\n\n");
+ printf("WildMidi comes with ABSOLUTELY NO WARRANTY\n");
+ printf("This is free software, and you are welcome to redistribute it\n");
+ printf("under the terms and conditions of the GNU General Public License version 2.\n");
+ printf("For more information see COPYING\n\n");
+}
+
+void
+do_syntax (void) {
+ printf("wildmidi [options] filename.mid\n\n");
+}
+
+int
+main (int argc, char **argv) {
+ struct _WM_Info * wm_info = NULL;
+ int i;
+ int option_index = 0;
+ unsigned long int mixer_options = 0;
+ static char *config_file = NULL;
+ void *midi_ptr = NULL;
+ unsigned char master_volume = 100;
+ int output_result = 0;
+ char * output_buffer = NULL;
+ unsigned long int perc_play = 0;
+ unsigned long int pro_mins = 0;
+ unsigned long int pro_secs = 0;
+ unsigned long int apr_mins = 0;
+ unsigned long int apr_secs = 0;
+ unsigned char modes[4] = {0};
+ unsigned long int count_diff;
+ unsigned char ch;
+ unsigned char test_midi = 0;
+ unsigned char test_count = 0;
+ unsigned char *test_data = NULL;
+ unsigned char test_bank = 0;
+ unsigned char test_patch = 0;
+ static char *spinner="|/-\\";
+ static int spinpoint = 0;
+
+#ifndef _WIN32
+ int my_tty;
+ struct termios _tty;
+ tcflag_t _res_oflg = _tty.c_oflag;
+ tcflag_t _res_lflg = _tty.c_lflag;
+
+#define raw() (_tty.c_lflag &= ~(ICANON | ICRNL | ISIG), \
+ _tty.c_oflag &= ~ONLCR, tcsetattr(my_tty, TCSANOW, &_tty))
+#define savetty() ((void) tcgetattr(my_tty, &_tty), \
+ _res_oflg = _tty.c_oflag, _res_lflg = _tty.c_lflag)
+#define resetty() (_tty.c_oflag = _res_oflg, _tty.c_lflag = _res_lflg,\
+ (void) tcsetattr(my_tty, TCSADRAIN, &_tty))
+#endif
+
+ do_version();
+ while (1) {
+ i = getopt_long (argc, argv, "vho:lr:c:m:btk:p:ed:", long_options, &option_index);
+ if (i == -1)
+ break;
+ switch (i) {
+ case 'v': // Version
+ return 0;
+ case 'h': // help
+ do_syntax();
+ do_help();
+ return 0;
+ case 'r': // SoundCard Rate
+ rate = atoi(optarg);
+ break;
+#ifdef EPERIMENT_626
+ case 'b': // Reverb
+ mixer_options ^= WM_MO_REVERB;
+ break;
+#endif
+ case 'm': // Master Volume
+ master_volume = (unsigned char)atoi(optarg);
+ break;
+ case 'o': // Wav Output
+ strcpy(wav_file,optarg);
+ break;
+ case 'c': // Config File
+ config_file = malloc (strlen(optarg)+1);
+ strcpy(config_file,optarg);
+ break;
+ case 'd': // Output device
+ pcmname = malloc (strlen(optarg)+1);
+ strcpy(pcmname,optarg);
+ break;
+ case 'e': // Expensive Interpolation
+ mixer_options |= WM_MO_EXPENSIVE_INTERPOLATION;
+ break;
+ case 'l': // linear volume
+ mixer_options |= WM_MO_LINEAR_VOLUME;
+ break;
+ case 't': // play test midis
+ test_midi = 1;
+ break;
+ case 'k': // set test bank
+ test_bank = (unsigned char)atoi(optarg);
+ break;
+ case 'p': // set test patch
+ test_patch = (unsigned char)atoi(optarg);
+ break;
+ default:
+ printf ("Unknown Option -%o ??\n", i);
+ return 0;
+ }
+ }
+
+ if (!config_file) {
+ config_file = malloc(sizeof(TIMIDITY_CFG)+1);
+ strncpy (config_file, TIMIDITY_CFG, sizeof(TIMIDITY_CFG));
+ config_file[sizeof(TIMIDITY_CFG)] = '\0';
+ }
+ if ((optind < argc) || (test_midi)) {
+ printf("Initializing Sound System\n");
+
+ if (wav_file[0] != '\0') {
+ if (open_wav_output() == -1) {
+ return 0;
+ }
+ } else {
+#if (defined _WIN32) || (defined __CYGWIN__)
+ if (open_mm_output() == -1) {
+#else
+#ifdef HAVE_ALSA
+ if (open_alsa_output() == -1) {
+#else
+ if (open_oss_output() == -1) {
+#endif
+#endif
+ return 0;
+ }
+ }
+ printf("Initializing %s\n\n", WildMidi_GetString(WM_GS_VERSION));
+ printf(" + Volume up e Better resampling n Next Midi\n");
+ printf(" - Volume down l Linear volume q Quit\n\n");
+
+ if (WildMidi_Init (config_file, rate, mixer_options) == -1) {
+ return 0;
+ }
+ WildMidi_MasterVolume(master_volume);
+
+ output_buffer = malloc(16384);
+ if (output_buffer == NULL) {
+ printf("Not enough ram, exiting\n");
+ WildMidi_Shutdown();
+ return 0;
+ }
+#ifndef _WIN32
+ my_tty = fileno(stdin);
+ if (isatty(my_tty)) {
+ savetty();
+ raw();
+ fcntl(0, F_SETFL, FNONBLOCK);
+ }
+#endif
+
+ while ((optind < argc) || (test_midi)) {
+ if (!test_midi) {
+ char * real_file = strrchr(argv[optind], '/');
+ if (real_file == NULL) {
+ real_file = strrchr(argv[optind], '\\');
+ }
+ midi_ptr = WildMidi_Open (argv[optind]);
+ if (midi_ptr == NULL) {
+ optind++;
+ continue;
+ }
+ wm_info = WildMidi_GetInfo(midi_ptr);
+
+ printf ("\rPlaying ");
+ if (real_file != NULL) {
+ printf("%s \n", (real_file+1));
+ } else {
+ printf("%s \n", argv[optind]);
+ }
+ optind++;
+ } else {
+ if (test_count == midi_test_max) {
+ break;
+ }
+ test_data = malloc(midi_test[test_count].size);
+ memcpy(test_data, midi_test[test_count].data, midi_test[test_count].size);
+ test_data[25] = test_bank;
+ test_data[28] = test_patch;
+ midi_ptr = WildMidi_OpenBuffer(test_data, 633);
+ wm_info = WildMidi_GetInfo(midi_ptr);
+ test_count++;
+ printf ("\rPlaying test midi no. %i\n", test_count);
+ }
+
+ apr_mins = wm_info->approx_total_samples / (rate * 60);
+ apr_secs = (wm_info->approx_total_samples % (rate * 60)) / rate;
+
+ if (midi_ptr == NULL) {
+ fprintf(stderr,"\rSkipping %s\n",argv[optind]);
+ optind++;
+ continue;
+ }
+ mixer_options = wm_info->mixer_options;
+ WildMidi_LoadSamples(midi_ptr);
+ while (1) {
+ count_diff = wm_info->approx_total_samples - wm_info->current_sample;
+ if (count_diff == 0)
+ break;
+
+ ch = 0;
+#ifdef _WIN32
+ if (_kbhit()) {
+ ch = _getch();
+ putch(ch);
+ }
+#else
+ if (read(my_tty, &ch, 1) != 1)
+ ch = 0;
+#endif
+ if (ch) {
+ switch (ch) {
+ case 'l':
+ WildMidi_SetOption(midi_ptr, WM_MO_LINEAR_VOLUME, ((mixer_options & WM_MO_LINEAR_VOLUME) ^ WM_MO_LINEAR_VOLUME));
+ mixer_options ^= WM_MO_LINEAR_VOLUME;
+ break;
+#ifdef EXPERIMENT_626
+ case 'r':
+ WildMidi_SetOption(midi_ptr, WM_MO_REVERB, ((mixer_options & WM_MO_REVERB) ^ WM_MO_REVERB));
+ mixer_options ^= WM_MO_REVERB;
+ break;
+#endif
+ case 'e':
+ WildMidi_SetOption(midi_ptr, WM_MO_EXPENSIVE_INTERPOLATION, ((mixer_options & WM_MO_EXPENSIVE_INTERPOLATION) ^ WM_MO_EXPENSIVE_INTERPOLATION));
+ mixer_options ^= WM_MO_EXPENSIVE_INTERPOLATION;
+ break;
+ case 'n':
+ goto NEXTMIDI;
+ case 'q':
+ printf("\n");
+ WildMidi_Close(midi_ptr);
+ WildMidi_Shutdown();
+ printf("Shutting down Sound System\n");
+ close_output();
+#ifndef _WIN32
+ if (isatty(my_tty))
+ resetty();
+#endif
+ printf("\r\n");
+ exit (0);
+ case '-':
+ if (master_volume > 0) {
+ master_volume--;
+ WildMidi_MasterVolume(master_volume);
+ }
+ break;
+ case '+':
+ if (master_volume < 127) {
+ master_volume++;
+ WildMidi_MasterVolume(master_volume);
+ }
+ break;
+ }
+ }
+
+ if (count_diff < 4096) {
+ output_result = WildMidi_GetOutput (midi_ptr, output_buffer, (count_diff * 4));
+ } else {
+ output_result = WildMidi_GetOutput (midi_ptr, output_buffer, 16384);
+ }
+
+ wm_info = WildMidi_GetInfo(midi_ptr);
+ perc_play = (wm_info->current_sample * 100) / wm_info->approx_total_samples;
+ pro_mins = wm_info->current_sample / (rate * 60);
+ pro_secs = (wm_info->current_sample % (rate * 60)) / rate;
+ {
+ int mode_count = 0;
+ if (mixer_options & WM_MO_LINEAR_VOLUME) {
+ modes[mode_count++] = 'l';
+ }
+ if (mixer_options & WM_MO_REVERB) {
+ modes[mode_count++] = 'r';
+ }
+ if (mixer_options & WM_MO_EXPENSIVE_INTERPOLATION) {
+ modes[mode_count++] = 'e';
+ }
+ if (mode_count !=3) {
+ do {
+ modes[mode_count++] = ' ';
+ } while (mode_count != 3);
+ }
+ modes[3] = '\0';
+ }
+ fprintf(stderr, "\r");
+ fprintf(stderr, "\t [Approx %2lum %2lus Total] [%s] [%3i] [%2lum %2lus Processed] [%2lu%%] %c ",
+ apr_mins, apr_secs, modes, master_volume,
+ pro_mins, pro_secs, perc_play, spinner[spinpoint++%4]);
+
+ if (output_result == 0)
+ break;
+ send_output (output_buffer, output_result);
+ }
+NEXTMIDI:
+ fprintf(stderr, "\n\r");
+ if (WildMidi_Close(midi_ptr) == -1) {
+ printf ("oops\n");
+ }
+ memset(output_buffer, 0, 16384);
+ send_output (output_buffer, 16384);
+ }
+ memset(output_buffer, 0, 16384);
+ send_output (output_buffer, 16384);
+ send_output (output_buffer, 16384);
+#ifdef _WIN32
+ Sleep(5);
+#else
+ usleep(5000);
+#endif
+ if (WildMidi_Shutdown() == -1)
+ printf("oops\n");
+ printf("Shutting down Sound System\n");
+ close_output();
+#ifndef _WIN32
+ if (isatty(my_tty))
+ resetty();
+#endif
+ } else {
+ printf("ERROR: No midi file given\n");
+ do_syntax();
+ return 0;
+ }
+
+ if (output_buffer != NULL)
+ free(output_buffer);
+ printf("\r");
+ return 0;
+}
+
+//============================
+//============================
+//============================
+
diff --git a/plugins/wildmidi/src/wildmidi_lib.c b/plugins/wildmidi/src/wildmidi_lib.c
new file mode 100644
index 00000000..315bf1a4
--- /dev/null
+++ b/plugins/wildmidi/src/wildmidi_lib.c
@@ -0,0 +1,5072 @@
+/*
+ wildmidi_lib.c
+
+ Midi Wavetable Processing library
+
+ Copyright (C)2001-2004 Chris Ison
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Email: cisos@bigpond.net.au
+ wildcode@users.sourceforge.net
+
+ $Id: wildmidi_lib.c,v 1.18 2004/01/28 05:45:09 wildcode Exp $
+
+ ========================================
+ Changelog
+ ----------------------------------------
+ Aug 3, 2003
+ - changed kill envelope from 6th to 5th
+ - changed data_length, loop_start, loop_end to 22:10 fixed point
+ - added fractional position to loop_start and loop_end
+ - added fake reverb
+
+ Aug 4, 2003
+ - added MIDI_EVENT_DEBUG to midi event functions
+ - fixed hold release killing off notes that hadn't been turned off
+ by note off
+ - sped up fake reverb by doing it outside the channel mixing loop
+
+ Aug 5, 2003
+ - removed note_table init from ParseNewMidi, entries are now fully reset
+ in do_note_on
+ - moved fast kill envelope setting to sample loading
+ - removed envelopes from notes, use ones from sample instead
+ - optimized do_amp_setup functions
+ - do_control_volume, do_control_expression, do_channel_pressure,
+ changed from setting note_table[] to note[] for performance.
+ - optimizations of sample conversion,
+
+ Aug 6, 2003
+ - removed changing sample volumes, the amp setting is now apart of
+ the midi volume maths.
+ - re-write conversion functions to make them more clearer and less bug prone
+
+ Aug 7, 2003
+ - fixed volume, expression and preasure changes effecting all notes.
+
+ Aug 8, 2003
+ - spead up midi processing by using an event index
+
+ Aug 9, 2003
+ - spead up sampling and mixing by using a seperate function depending on fixed
+ modes
+ - fixed data lock where it would sleep reguardless of lock state
+ - fixed memory leak ... oops, forgot a free
+ - removed track data storge, isn't required by the core functions
+
+ Aug 10, 2003
+ - created error function and changed all error messages to use it
+ - malloc, calloc, realloc audit ensuring all are error checked.
+ - fixed potential reading beyond end of midi bug
+
+ Aug 11, 2003
+ - fixed expensive interpolation over-running the sample buffer
+ - changed stereo option so that changing it worked right away
+
+ Aug 14, 2003
+ - optimizations for and to the frequency calc code
+ - removal of wide stereo (it sucked anyway)
+
+ Aug 15, 2003
+ - fixed volume levels for panning when non-linear volumes are used
+ - removed fake reberb, it sucked on better sound systems.
+
+ Aug 17, 2003
+ - fixed autoamp
+ - added env_time#= and env_level#= to timiidty.cfg parser.
+ - fixed bug where last event in the midi before the last eot would
+ have a large delta. This is a bug in the midi file itself.
+ - fixed some midi's having no sound cause they don't supply patch information.
+ Now defaulting all channels to bank 0, patch 0.
+
+ Aug 18, 2003
+ - preload samples
+ - optimized envelope checking and controler code
+ - fixed bug where some samples have an envelope rate setting that doesn't
+ actually mean anything .. ie: 0x00 0x40 0x80 0xC0
+ - fixed amp bug where initial left/right levels were set to 0
+ - added timidity's keep=[loop|env] support for drum patches,
+ now ignores loops and env settings for drum patches unless keep=[loop|env]
+ is in the patch line in the config.
+
+ Aug 21, 2003
+ - float to fixed point math conversions.
+ - frequency range locked to 100 steps between notes
+ NOTE:need to test slow pitchbends with this, fast ones are fine
+
+ Aug 24, 2003
+ - optimized sample conversions
+ - optimized note handling and sample/envelope position checks
+
+ Aug 28, 2003
+ - compile level optimizations
+ NOTE: gcc builtins used
+ - numerous bug fixes
+
+ Aug 30, 2003
+ - fixed sample inc calculation bug
+ - fixed panning volumes, now percieved volume of the sample is the same no matter
+ panning position.
+
+` Sep 2, 2003
+ - made noteoff/hold behaviour match midi standard
+ - added remove=sustain to patch line
+ - added all sound off controller
+ - fixed all notes off to only effect notes that aren't being held
+ - changed envelope behaviour so that only non-sustaned samples hit envelope 4
+ while note is on.
+ - Added all controllers off event
+
+
+ Sep 4, 2003
+ - added master sample data lock
+ - improved performance of the resampling algo
+
+ ========================================
+*/
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#ifndef _WIN32
+#include <pwd.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#ifdef _WIN32
+# include <windows.h>
+#endif
+#include "config.h"
+#include "wildmidi_lib.h"
+
+/*
+ * =========================
+ * Global Data and Data Structs
+ * =========================
+ */
+
+int WM_Initialized = 0;
+signed short int WM_MasterVolume = 948;
+unsigned short int WM_SampleRate = 0;
+unsigned short int WM_MixerOptions = 0;
+
+char WM_Version[] = "WildMidi Processing Library " WILDMIDILIB_VERSION;
+
+struct _lowpass {
+ signed long int in[2];
+ signed long int out[2];
+};
+
+struct _filter {
+ signed long int *delay[4][2];
+ unsigned long int delay_pos[4][2];
+ struct _lowpass lowpass[4][2];
+ signed long int in[2][2];
+ signed long int out[2][2];
+};
+
+struct _env {
+ float time;
+ float level;
+ unsigned char set;
+};
+
+struct _sample {
+ unsigned long int data_length;
+ unsigned long int loop_start;
+ unsigned long int loop_end;
+ unsigned long int loop_size;
+ unsigned char loop_fraction;
+ unsigned short int rate;
+ unsigned long int freq_low;
+ unsigned long int freq_high;
+ unsigned long int freq_root;
+ unsigned char modes;
+ unsigned long int env_rate[7];
+ unsigned long int env_target[7];
+ unsigned long int inc_div;
+ signed short *data;
+ signed short max_peek;
+ signed short min_peek;
+ signed long int peek_adjust;
+ struct _sample *next;
+};
+
+struct _patch {
+ unsigned short patchid;
+ unsigned char loaded;
+ char *filename;
+ signed short int amp;
+ unsigned char keep;
+ unsigned char remove;
+ struct _env env[6];
+ unsigned char note;
+ unsigned long int inuse_count;
+ struct _sample *first_sample;
+ struct _patch *next;
+};
+
+struct _patch *patch[128];
+
+int patch_lock;
+
+struct _channel {
+ unsigned char bank;
+ struct _patch *patch;
+ unsigned char hold;
+ unsigned char volume;
+ unsigned char pressure;
+ unsigned char expression;
+ signed char balance;
+ signed char pan;
+ signed short int left_adjust;
+ signed short int right_adjust;
+ signed short int pitch;
+ signed short int pitch_range;
+ signed long int pitch_adjust;
+ unsigned short reg_data;
+};
+
+#define HOLD_OFF 0x02
+
+struct _note {
+ unsigned short noteid;
+ unsigned char velocity;
+ struct _patch *patch;
+ struct _sample *sample;
+ unsigned long int sample_pos;
+ unsigned long int sample_inc;
+ signed long int env_inc;
+ unsigned char env;
+ unsigned long int env_level;
+ unsigned char modes;
+ unsigned char hold;
+ unsigned char active;
+ struct _note *next;
+ signed short int vol_lvl;
+};
+
+struct _miditrack {
+ unsigned long int length;
+ unsigned long int ptr;
+ unsigned long int delta;
+ unsigned char running_event;
+ unsigned char EOT;
+};
+
+struct _mdi_patches {
+ struct _patch *patch;
+ struct _mdi_patch *next;
+};
+
+struct _mdi_index {
+ unsigned long int offset;
+ unsigned char event;
+ unsigned long int delta;
+};
+
+struct _mdi {
+ int lock;
+ unsigned char *data;
+ unsigned long int size;
+ unsigned short int divisions ;
+ unsigned short midi_master_vol;
+ unsigned long int samples_per_delta;
+ unsigned long int samples_to_mix;
+ struct _mdi_index * index;
+ unsigned long int index_count;
+ unsigned long int index_size;
+ struct _WM_Info info;
+ struct _WM_Info *tmp_info;
+ unsigned char recalc_samples;
+ struct _channel channel[16];
+ struct _note *note[128];
+ struct _note **last_note;
+ struct _note note_table[2][16][128];
+
+ struct _patch **patches;
+ unsigned long int patch_count;
+ unsigned long int sample_count;
+ signed short int amp;
+
+// setup data for auto amp
+ signed long int log_cur_vol;
+ signed long int lin_cur_vol;
+ signed long int log_max_vol;
+ signed long int lin_max_vol;
+
+ unsigned char ch_vol[16];
+ unsigned char ch_exp[16];
+ unsigned char note_vel[16][128];
+
+ struct _filter filter;
+};
+
+/* Gauss Interpolation code adapted from code supplied by Eric. A. Welsh */
+
+double newt_coeffs[58][58]; /* for start/end of samples */
+float *gauss_table[(1<<10)] = {0}; /* don't need doubles */
+int gauss_window[35] = {0};
+int gauss_n = 34; /* do not set this value higher than 34 */
+ /* 34 is as high as we can go before errors crop up */
+
+void init_gauss (void) {
+ /* init gauss table */
+ int n = 34;
+ int m, i, k, n_half = (n>>1);
+ int j;
+ int sign;
+ double ck;
+ double x, x_inc, xz;
+ double z[35];
+ float *gptr;
+
+ newt_coeffs[0][0] = 1;
+
+ for (i = 0; i <= n; i++) {
+ newt_coeffs[i][0] = 1;
+ newt_coeffs[i][i] = 1;
+
+ if (i > 1) {
+ newt_coeffs[i][0] = newt_coeffs[i-1][0] / i;
+ newt_coeffs[i][i] = newt_coeffs[i-1][0] / i;
+ }
+
+ for (j = 1; j < i; j++) {
+ newt_coeffs[i][j] = newt_coeffs[i-1][j-1] + newt_coeffs[i-1][j];
+ if (i > 1)
+ newt_coeffs[i][j] /= i;
+ }
+ z[i] = i / (4*M_PI);
+ }
+
+ for (i = 0; i <= n; i++)
+ for (j = 0, sign = pow(-1, i); j <= i; j++, sign *= -1)
+ newt_coeffs[i][j] *= sign;
+
+
+ x_inc = 1.0 / (1<<10);
+ for (m = 0, x = 0.0; m < (1<<10); m++, x += x_inc) {
+ xz = (x + n_half) / (4*M_PI);
+ gptr = gauss_table[m] = realloc(gauss_table[m], (n+1)*sizeof(float));
+
+ for (k = 0; k <= n; k++) {
+ ck = 1.0;
+
+ for (i = 0; i <= n; i++) {
+ if (i == k)
+ continue;
+
+ ck *= (sin(xz - z[i])) / (sin(z[k] - z[i]));
+ }
+ *gptr++ = ck;
+ }
+ }
+}
+
+unsigned long int delay_size[4][2];
+signed long int a[5][2];
+signed long int b[5][2];
+signed long int gain_in[4];
+signed long int gain_out[4];
+
+void init_lowpass (void) {
+ float c = 0;
+ int i;
+ float f[] = { 512.0, 1024.0, 2048.0, 4096.0 , 8192.0};
+ float aa, ab, ba, bb;
+
+ for (i = 0; i < 5; i++) {
+ c = 1.0 / tan(3.141592654 * f[i] / WM_SampleRate);
+ aa = 1.0 / (1.0 + 1.4 * c + c * c);
+ ab = 2.0 * aa;
+ ba = 2.0 * (1.0 - c * c) * aa;
+ bb = (1.0 - 1.4 * c + c * c) * aa;
+ a[i][0] = (signed long int)(aa * 1024.0);
+ a[i][1] = (signed long int)(ab * 1024.0);
+ b[i][0] = (signed long int)(ba * 1024.0);
+ b[i][1] = (signed long int)(bb * 1024.0);
+ }
+ gain_in[0] = 772;
+ gain_out[0] = 772;
+ gain_in[1] = 570;
+ gain_out[1] = 570;
+ gain_in[2] = 520;
+ gain_out[2] = 520;
+ gain_in[3] = 512;
+ gain_out[3] = 512;
+
+ delay_size[0][0] = 2191 * WM_SampleRate / 44100;
+ delay_size[0][1] = (2191 + 19) * WM_SampleRate / 44100;
+ delay_size[1][0] = (2971 + 19) * WM_SampleRate / 44100;
+ delay_size[1][1] = 2971 * WM_SampleRate / 44100;
+ delay_size[2][0] = 3253 * WM_SampleRate / 44100;
+ delay_size[2][1] = (3253 + 19) * WM_SampleRate / 44100;
+ delay_size[3][0] = (3307 + 19) * WM_SampleRate / 44100;
+ delay_size[3][1] = 3307 * WM_SampleRate / 44100;
+
+}
+
+struct _hndl {
+ void * handle;
+ struct _hndl *next;
+ struct _hndl *prev;
+};
+
+struct _hndl * first_handle = NULL;
+
+//f: ( VOLUME / 127 )
+//f: pow(( VOLUME / 127 ), 1.660964047 )
+//f: pow(( VOLUME / 127 ), 2.0 )
+//f: pow(( VOLUME / 127 ), 0.602059991 )
+//f: pow(( VOLUME / 127 ), 0.5 )
+
+signed short int lin_volume[] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 129, 137, 145, 153, 161, 169, 177, 185, 193, 201, 209, 217, 225, 233, 241, 249, 258, 266, 274, 282, 290, 298, 306, 314, 322, 330, 338, 346, 354, 362, 370, 378, 387, 395, 403, 411, 419, 427, 435, 443, 451, 459, 467, 475, 483, 491, 499, 507, 516, 524, 532, 540, 548, 556, 564, 572, 580, 588, 596, 604, 612, 620, 628, 636, 645, 653, 661, 669, 677, 685, 693, 701, 709, 717, 725, 733, 741, 749, 757, 765, 774, 782, 790, 798, 806, 814, 822, 830, 838, 846, 854, 862, 870, 878, 886, 894, 903, 911, 919, 927, 935, 943, 951, 959, 967, 975, 983, 991, 999, 1007, 1015, 1024 };
+signed short int log_volume[] = { 0, 0, 1, 2, 3, 4, 6, 8, 10, 12, 15, 17, 20, 23, 26, 29, 32, 36, 39, 43, 47, 51, 55, 59, 64, 68, 73, 78, 83, 88, 93, 98, 103, 109, 114, 120, 126, 132, 138, 144, 150, 156, 162, 169, 176, 182, 189, 196, 203, 210, 217, 224, 232, 239, 247, 255, 262, 270, 278, 286, 294, 302, 311, 319, 328, 336, 345, 353, 362, 371, 380, 389, 398, 408, 417, 426, 436, 446, 455, 465, 475, 485, 495, 505, 515, 525, 535, 546, 556, 567, 577, 588, 599, 610, 621, 632, 643, 654, 665, 677, 688, 699, 711, 723, 734, 746, 758, 770, 782, 794, 806, 818, 831, 843, 855, 868, 880, 893, 906, 919, 931, 944, 957, 970, 984, 997, 1010, 1024 };
+signed short int sqr_volume[] = { 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 14, 16, 18, 20, 22, 25, 27, 30, 33, 36, 39, 42, 46, 49, 53, 57, 61, 65, 69, 73, 77, 82, 86, 91, 96, 101, 106, 111, 117, 122, 128, 134, 140, 146, 152, 158, 165, 171, 178, 185, 192, 199, 206, 213, 221, 228, 236, 244, 251, 260, 268, 276, 284, 293, 302, 311, 320, 329, 338, 347, 357, 366, 376, 386, 396, 406, 416, 426, 437, 447, 458, 469, 480, 491, 502, 514, 525, 537, 549, 560, 572, 585, 597, 609, 622, 634, 647, 660, 673, 686, 699, 713, 726, 740, 754, 768, 782, 796, 810, 825, 839, 854, 869, 884, 899, 914, 929, 944, 960, 976, 992, 1007, 1024 };
+//signed short int pan_volume[] = { 0, 55, 84, 107, 127, 146, 162, 178, 193, 208, 221, 234, 247, 259, 271, 282, 294, 305, 315, 326, 336, 346, 356, 366, 375, 384, 394, 403, 412, 420, 429, 438, 446, 454, 463, 471, 479, 487, 495, 503, 510, 518, 525, 533, 540, 548, 555, 562, 570, 577, 584, 591, 598, 605, 611, 618, 625, 632, 638, 645, 651, 658, 664, 671, 677, 684, 690, 696, 703, 709, 715, 721, 727, 733, 739, 745, 751, 757, 763, 769, 775, 781, 786, 792, 798, 804, 809, 815, 821, 826, 832, 837, 843, 848, 854, 859, 865, 870, 876, 881, 886, 892, 897, 902, 907, 913, 918, 923, 928, 933, 939, 944, 949, 954, 959, 964, 969, 974, 979, 984, 989, 994, 999, 1004, 1009, 1014, 1019, 1024 };
+signed short int pan_volume[] = { 0, 90, 128, 157, 181, 203, 222, 240, 257, 272, 287, 301, 314, 327, 339, 351, 363, 374, 385, 396, 406, 416, 426, 435, 445, 454, 463, 472, 480, 489, 497, 505, 514, 521, 529, 537, 545, 552, 560, 567, 574, 581, 588, 595, 602, 609, 616, 622, 629, 636, 642, 648, 655, 661, 667, 673, 679, 686, 692, 697, 703, 709, 715, 721, 726, 732, 738, 743, 749, 754, 760, 765, 771, 776, 781, 786, 792, 797, 802, 807, 812, 817, 822, 827, 832, 837, 842, 847, 852, 857, 862, 866, 871, 876, 880, 885, 890, 894, 899, 904, 908, 913, 917, 922, 926, 931, 935, 939, 944, 948, 953, 957, 961, 965, 970, 974, 978, 982, 987, 991, 995, 999, 1003, 1007, 1011, 1015, 1019, 1024 };
+
+unsigned long int reverb_val = 92;
+unsigned long int comb_size[8][2];
+unsigned long int allpass_size[2][2];
+
+float env_time_table[] = {
+ 0.0, 0.092857143, 0.046428571, 0.030952381, 0.023214286, 0.018571429, 0.015476190, 0.013265306, 0.011607143, 0.010317460, 0.009285714, 0.008441558, 0.007738095, 0.007142857, 0.006632653, 0.006190476, 0.005803571, 0.005462185, 0.005158730, 0.004887218, 0.004642857, 0.004421769, 0.004220779, 0.004037267, 0.003869048, 0.003714286, 0.003571429, 0.003439153, 0.003316327, 0.003201970, 0.003095238, 0.002995392, 0.002901786, 0.002813853, 0.002731092, 0.002653061, 0.002579365, 0.002509653, 0.002443609, 0.002380952, 0.002321429, 0.002264808, 0.002210884, 0.002159468, 0.002110390, 0.002063492, 0.002018634, 0.001975684, 0.001934524, 0.001895044, 0.001857143, 0.001820728, 0.001785714, 0.001752022, 0.001719577, 0.001688312, 0.001658163, 0.001629073, 0.001600985, 0.001573850, 0.001547619, 0.001522248, 0.001497696, 0.001473923,
+ 0.0, 0.742857143, 0.371428571, 0.247619048, 0.185714286, 0.148571429, 0.123809524, 0.106122449, 0.092857143, 0.082539683, 0.074285714, 0.067532468, 0.061904762, 0.057142857, 0.053061224, 0.049523810, 0.046428571, 0.043697479, 0.041269841, 0.039097744, 0.037142857, 0.035374150, 0.033766234, 0.032298137, 0.030952381, 0.029714286, 0.028571429, 0.027513228, 0.026530612, 0.025615764, 0.024761905, 0.023963134, 0.023214286, 0.022510823, 0.021848739, 0.021224490, 0.020634921, 0.020077220, 0.019548872, 0.019047619, 0.018571429, 0.018118467, 0.017687075, 0.017275748, 0.016883117, 0.016507937, 0.016149068, 0.015805471, 0.015476190, 0.015160350, 0.014857143, 0.014565826, 0.014285714, 0.014016173, 0.013756614, 0.013506494, 0.013265306, 0.013032581, 0.012807882, 0.012590799, 0.012380952, 0.012177986, 0.011981567, 0.011791383,
+ 0.0, 5.942857143, 2.971428571, 1.980952381, 1.485714286, 1.188571429, 0.990476190, 0.848979592, 0.742857143, 0.660317460, 0.594285714, 0.540259740, 0.495238095, 0.457142857, 0.424489796, 0.396190476, 0.371428571, 0.349579832, 0.330158730, 0.312781955, 0.297142857, 0.282993197, 0.270129870, 0.258385093, 0.247619048, 0.237714286, 0.228571429, 0.220105820, 0.212244898, 0.204926108, 0.198095238, 0.191705069, 0.185714286, 0.180086580, 0.174789916, 0.169795918, 0.165079365, 0.160617761, 0.156390977, 0.152380952, 0.148571429, 0.144947735, 0.141496599, 0.138205980, 0.135064935, 0.132063492, 0.129192547, 0.126443769, 0.123809524, 0.121282799, 0.118857143, 0.116526611, 0.114285714, 0.112129380, 0.110052910, 0.108051948, 0.106122449, 0.104260652, 0.102463054, 0.100726392, 0.099047619, 0.097423888, 0.095852535, 0.094331066,
+ 0.0, 47.542857143, 23.771428571, 15.847619048, 11.885714286, 9.508571429, 7.923809524, 6.791836735, 5.942857143, 5.282539683, 4.754285714, 4.322077922, 3.961904762, 3.657142857, 3.395918367, 3.169523810, 2.971428571, 2.796638655, 2.641269841, 2.502255639, 2.377142857, 2.263945578, 2.161038961, 2.067080745, 1.980952381, 1.901714286, 1.828571429, 1.760846561, 1.697959184, 1.639408867, 1.584761905, 1.533640553, 1.485714286, 1.440692641, 1.398319328, 1.358367347, 1.320634921, 1.284942085, 1.251127820, 1.219047619, 1.188571429, 1.159581882, 1.131972789, 1.105647841, 1.080519481, 1.056507937, 1.033540373, 1.011550152, 0.990476190, 0.970262391, 0.950857143, 0.932212885, 0.914285714, 0.897035040, 0.880423280, 0.864415584, 0.848979592, 0.834085213, 0.819704433, 0.805811138, 0.792380952, 0.779391101, 0.766820276, 0.754648526
+};
+
+#if 0
+unsigned long int freq_table[] = {
+ 8372018, 8376855, 8381695, 8386538, 8391384, 8396232, 8401084, 8405938, 8410795, 8415654, 8420517, 8425382, 8430250, 8435121, 8439995, 8444871, 8449751, 8454633, 8459518, 8464406, 8469296, 8474190, 8479086, 8483985, 8488887, 8493792, 8498700, 8503610, 8508523, 8513439, 8518358, 8523280, 8528205, 8533132, 8538063, 8542996, 8547932, 8552871, 8557813, 8562757, 8567705, 8572655, 8577608, 8582564, 8587523, 8592485, 8597450, 8602417, 8607387, 8612361, 8617337, 8622316, 8627298, 8632282, 8637270, 8642261, 8647254, 8652250, 8657250, 8662252, 8667257, 8672264, 8677275, 8682289, 8687305, 8692325, 8697347, 8702372, 8707400, 8712431, 8717465, 8722502, 8727542, 8732585, 8737630, 8742679, 8747730, 8752785, 8757842, 8762902, 8767965, 8773031, 8778100, 8783172, 8788247, 8793325, 8798405, 8803489, 8808575, 8813665, 8818757, 8823853, 8828951, 8834052, 8839157, 8844264, 8849374, 8854487, 8859603, 8864722, 8869844, 8874969, 8880097, 8885227, 8890361, 8895498, 8900638, 8905780, 8910926, 8916075, 8921226, 8926381, 8931538, 8936699, 8941863, 8947029, 8952199, 8957371, 8962546, 8967725, 8972906, 8978091, 8983278, 8988469, 8993662, 8998859, 9004058, 9009260, 9014466, 9019674, 9024886, 9030100, 9035318, 9040538, 9045762, 9050988, 9056218, 9061451, 9066686, 9071925, 9077166, 9082411, 9087659, 9092910, 9098163, 9103420, 9108680, 9113943, 9119209, 9124478, 9129750, 9135025, 9140303, 9145584, 9150868, 9156156, 9161446, 9166739, 9172036, 9177335, 9182638, 9187944, 9193252, 9198564, 9203879, 9209197, 9214518, 9219842, 9225169, 9230499, 9235832, 9241169, 9246508, 9251851, 9257196, 9262545, 9267897, 9273252, 9278610, 9283971, 9289335, 9294702, 9300073, 9305446, 9310823, 9316202, 9321585, 9326971, 9332360, 9337752, 9343147, 9348546, 9353947, 9359352, 9364760, 9370171, 9375585, 9381002, 9386422, 9391845, 9397272, 9402701, 9408134, 9413570, 9419009, 9424451, 9429897, 9435345, 9440797, 9446252, 9451710, 9457171, 9462635, 9468102, 9473573, 9479047, 9484524, 9490004, 9495487, 9500973, 9506463, 9511955, 9517451, 9522950, 9528453, 9533958, 9539467, 9544979, 9550494, 9556012, 9561533, 9567058, 9572585, 9578116, 9583650, 9589188, 9594728, 9600272, 9605819, 9611369, 9616922, 9622479, 9628039, 9633602, 9639168, 9644737, 9650310, 9655886, 9661465, 9667047, 9672633, 9678221, 9683813, 9689409, 9695007, 9700609, 9706214, 9711822, 9717433, 9723048, 9728666, 9734287, 9739911, 9745539, 9751170, 9756804, 9762441, 9768082, 9773726, 9779373, 9785023, 9790677, 9796334, 9801994, 9807657, 9813324, 9818994, 9824667, 9830344, 9836024, 9841707, 9847394, 9853083, 9858776, 9864473, 9870172, 9875875, 9881581, 9887291, 9893003, 9898719, 9904439, 9910162, 9915887, 9921617, 9927349, 9933085, 9938825, 9944567, 9950313, 9956062, 9961815, 9967570, 9973330, 9979092, 9984858, 9990627, 9996399, 10002175, 10007954, 10013737, 10019523, 10025312, 10031104, 10036900, 10042700, 10048502, 10054308, 10060117, 10065930, 10071746, 10077565, 10083388, 10089214, 10095043, 10100876, 10106712, 10112552, 10118395, 10124241, 10130091, 10135944, 10141800, 10147660, 10153523, 10159390, 10165260, 10171133, 10177010, 10182890, 10188774, 10194661, 10200551, 10206445, 10212342, 10218243, 10224147, 10230054, 10235965, 10241879, 10247797, 10253718, 10259642, 10265570, 10271502, 10277436, 10283374, 10289316, 10295261, 10301210, 10307162, 10313117, 10319076, 10325038, 10331004, 10336973, 10342945, 10348921, 10354901, 10360884, 10366870, 10372860, 10378853, 10384850, 10390850, 10396854, 10402861, 10408872, 10414886, 10420904, 10426925, 10432949, 10438977, 10445009, 10451044, 10457083, 10463124, 10469170, 10475219, 10481271, 10487327, 10493387, 10499450, 10505516, 10511586, 10517660, 10523737, 10529817, 10535901, 10541989, 10548080, 10554174, 10560273, 10566374, 10572480, 10578589, 10584701, 10590817, 10596936, 10603059, 10609186, 10615316, 10621449, 10627586, 10633727, 10639871, 10646019, 10652170, 10658325, 10664483, 10670645, 10676811, 10682980, 10689153, 10695329, 10701509, 10707692, 10713879, 10720069, 10726264, 10732461, 10738662, 10744867, 10751076, 10757288, 10763503, 10769722, 10775945, 10782172, 10788402, 10794635, 10800872, 10807113, 10813357, 10819605, 10825857, 10832112, 10838371, 10844634, 10850900, 10857169, 10863443, 10869720, 10876000, 10882284, 10888572, 10894864, 10901159, 10907457, 10913760, 10920066, 10926375, 10932689, 10939006, 10945326, 10951650, 10957978, 10964310, 10970645, 10976984, 10983326, 10989673, 10996022, 11002376, 11008733, 11015094, 11021459, 11027827, 11034199, 11040574, 11046954, 11053337, 11059723, 11066114, 11072508, 11078905, 11085307, 11091712, 11098121, 11104533, 11110949, 11117369, 11123793, 11130220, 11136651, 11143086, 11149525, 11155967, 11162413, 11168863, 11175316, 11181773, 11188234, 11194699, 11201167, 11207639, 11214115, 11220594, 11227078, 11233565, 11240055, 11246550, 11253048, 11259550, 11266056, 11272566, 11279079, 11285596, 11292117, 11298642, 11305170, 11311702, 11318238, 11324778, 11331321, 11337868, 11344420, 11350974, 11357533, 11364095, 11370662, 11377232, 11383805, 11390383, 11396964, 11403550, 11410139, 11416731, 11423328, 11429928, 11436533, 11443141, 11449753, 11456368, 11462988, 11469611, 11476238, 11482869, 11489504, 11496143, 11502785, 11509432, 11516082, 11522736, 11529394, 11536056, 11542721, 11549390, 11556064, 11562741, 11569422, 11576107, 11582795, 11589488, 11596184, 11602885, 11609589, 11616297, 11623009, 11629725, 11636444, 11643168, 11649895, 11656627, 11663362, 11670101, 11676844, 11683591, 11690342, 11697097, 11703855, 11710618, 11717384, 11724154, 11730929, 11737707, 11744489, 11751275, 11758065, 11764859, 11771656, 11778458, 11785264, 11792073, 11798887, 11805704, 11812526, 11819351, 11826180, 11833013, 11839851, 11846692, 11853537, 11860386, 11867239, 11874096, 11880956, 11887821, 11894690, 11901563, 11908440, 11915320, 11922205, 11929094, 11935986, 11942883, 11949784, 11956688, 11963597, 11970510, 11977426, 11984347, 11991271, 11998200, 12005133, 12012069, 12019010, 12025954, 12032903, 12039856, 12046812, 12053773, 12060738, 12067706, 12074679, 12081656, 12088637, 12095622, 12102610, 12109603, 12116600, 12123601, 12130606, 12137615, 12144629, 12151646, 12158667, 12165692, 12172722, 12179755, 12186793, 12193834, 12200880, 12207930, 12214983, 12222041, 12229103, 12236169, 12243239, 12250313, 12257392, 12264474, 12271561, 12278651, 12285746, 12292844, 12299947, 12307054, 12314165, 12321280, 12328400, 12335523, 12342651, 12349782, 12356918, 12364058, 12371202, 12378350, 12385502, 12392658, 12399819, 12406984, 12414152, 12421325, 12428502, 12435684, 12442869, 12450059, 12457252, 12464450, 12471652, 12478858, 12486069, 12493283, 12500502, 12507725, 12514952, 12522183, 12529418, 12536658, 12543901, 12551149, 12558401, 12565658, 12572918, 12580183, 12587452, 12594725, 12602002, 12609283, 12616569, 12623859, 12631153, 12638451, 12645754, 12653061, 12660372, 12667687, 12675006, 12682330, 12689658, 12696990, 12704326, 12711667, 12719012, 12726361, 12733714, 12741072, 12748433, 12755800, 12763170, 12770544, 12777923, 12785306, 12792694, 12800085, 12807481, 12814882, 12822286, 12829695, 12837108, 12844525, 12851947, 12859373, 12866803, 12874237, 12881676, 12889119, 12896567, 12904018, 12911474, 12918934, 12926399, 12933868, 12941341, 12948819, 12956301, 12963787, 12971277, 12978772, 12986271, 12993775, 13001283, 13008795, 13016311, 13023832, 13031357, 13038887, 13046421, 13053959, 13061502, 13069049, 13076600, 13084156, 13091716, 13099280, 13106849, 13114422, 13122000, 13129582, 13137168, 13144759, 13152354, 13159953, 13167557, 13175165, 13182778, 13190395, 13198016, 13205642, 13213273, 13220907, 13228546, 13236190, 13243838, 13251490, 13259147, 13266808, 13274474, 13282144, 13289818, 13297497, 13305180, 13312868, 13320560, 13328257, 13335958, 13343663, 13351373, 13359088, 13366807, 13374530, 13382258, 13389990, 13397727, 13405468, 13413214, 13420964, 13428719, 13436478, 13444241, 13452010, 13459782, 13467559, 13475341, 13483127, 13490918, 13498713, 13506512, 13514316, 13522125, 13529938, 13537756, 13545578, 13553405, 13561236, 13569071, 13576912, 13584756, 13592606, 13600460, 13608318, 13616181, 13624048, 13631920, 13639797, 13647678, 13655564, 13663454, 13671349, 13679248, 13687152, 13695060, 13702974, 13710891, 13718813, 13726740, 13734671, 13742607, 13750548, 13758493, 13766443, 13774397, 13782356, 13790319, 13798287, 13806260, 13814237, 13822219, 13830206, 13838197, 13846193, 13854193, 13862198, 13870208, 13878222, 13886241, 13894264, 13902292, 13910325, 13918363, 13926405, 13934451, 13942503, 13950559, 13958619, 13966685, 13974755, 13982829, 13990909, 13998993, 14007081, 14015175, 14023273, 14031375, 14039483, 14047595, 14055712, 14063833, 14071959, 14080090, 14088225, 14096366, 14104511, 14112660, 14120815, 14128974, 14137137, 14145306, 14153479, 14161657, 14169840, 14178027, 14186219, 14194416, 14202618, 14210824, 14219035, 14227251, 14235471, 14243697, 14251927, 14260161, 14268401, 14276645, 14284894, 14293148, 14301407, 14309670, 14317938, 14326211, 14334489, 14342772, 14351059, 14359351, 14367648, 14375949, 14384256, 14392567, 14400883, 14409204, 14417530, 14425860, 14434196, 14442536, 14450881, 14459230, 14467585, 14475944, 14484309, 14492678, 14501052, 14509430, 14517814, 14526202, 14534596, 14542994, 14551397, 14559805, 14568217, 14576635, 14585057, 14593485, 14601917, 14610354, 14618796, 14627242, 14635694, 14644151, 14652612, 14661078, 14669550, 14678026, 14686507, 14694993, 14703483, 14711979, 14720480, 14728985, 14737496, 14746011, 14754531, 14763057, 14771587, 14780122, 14788662, 14797207, 14805757, 14814311, 14822871, 14831436, 14840005, 14848580, 14857160, 14865744, 14874334, 14882928, 14891527, 14900132, 14908741, 14917355, 14925975, 14934599, 14943228, 14951862, 14960502, 14969146, 14977795, 14986449, 14995109, 15003773, 15012442, 15021116, 15029795, 15038480, 15047169, 15055863, 15064563, 15073267, 15081976, 15090691, 15099410, 15108135, 15116864, 15125599, 15134338, 15143083, 15151833, 15160587, 15169347, 15178112, 15186882, 15195657, 15204437, 15213222, 15222013, 15230808, 15239608, 15248414, 15257224, 15266040, 15274861, 15283687, 15292518, 15301354, 15310195, 15319041, 15327893, 15336749, 15345611, 15354477, 15363349, 15372226, 15381108, 15389996, 15398888, 15407786, 15416688, 15425596, 15434509, 15443427, 15452350, 15461279, 15470212, 15479151, 15488095, 15497044, 15505998, 15514958, 15523922, 15532892, 15541867, 15550847, 15559832, 15568823, 15577819, 15586820, 15595826, 15604837, 15613853, 15622875, 15631902, 15640934, 15649972, 15659014, 15668062, 15677115, 15686173, 15695237, 15704306, 15713380, 15722459, 15731543, 15740633, 15749728, 15758828, 15767934, 15777045, 15786161, 15795282, 15804408, 15813540, 15822677, 15831820, 15840967, 15850120, 15859279, 15868442, 15877611, 15886785, 15895965, 15905149, 15914339, 15923535, 15932735, 15941941, 15951153, 15960369, 15969591, 15978818, 15988051, 15997289, 16006532, 16015781, 16025035, 16034294, 16043559, 16052829, 16062104, 16071385, 16080671, 16089962, 16099259, 16108561, 16117869, 16127182, 16136500, 16145824, 16155153, 16164488, 16173828, 16183173, 16192523, 16201880, 16211241, 16220608, 16229980, 16239358, 16248741, 16258130, 16267524, 16276923, 16286328, 16295738, 16305154, 16314575, 16324002, 16333434, 16342871, 16352314, 16361763, 16371217, 16380676, 16390141, 16399611, 16409087, 16418568, 16428055, 16437547, 16447044, 16456548, 16466056, 16475570, 16485090, 16494615, 16504146, 16513682, 16523224, 16532771, 16542323, 16551882, 16561445, 16571015, 16580589, 16590170, 16599755, 16609347, 16618944, 16628546, 16638154, 16647768, 16657387, 16667012, 16676642, 16686278, 16695919, 16705566, 16715219, 16724877, 16734540
+};
+#endif
+
+unsigned long int freq_table[] = {
+ 837201792, 837685632, 838169728, 838653568, 839138240, 839623232, 840108480, 840593984, 841079680, 841565184, 842051648, 842538240, 843025152, 843512320, 843999232, 844486976, 844975040, 845463360, 845951936, 846440320, 846929536, 847418944, 847908608, 848398656, 848888960, 849378944, 849869824, 850361024, 850852416, 851344192, 851835584, 852327872, 852820480, 853313280, 853806464, 854299328, 854793024, 855287040, 855781312, 856275904, 856770752, 857265344, 857760704, 858256448, 858752448, 859248704, 859744768, 860241600, 860738752, 861236160, 861733888, 862231360, 862729600, 863228160, 863727104, 864226176, 864725696, 865224896, 865724864, 866225152, 866725760, 867226688, 867727296, 868228736, 868730496, 869232576, 869734912, 870236928, 870739904, 871243072, 871746560, 872250368, 872754496, 873258240, 873762880, 874267840, 874773184, 875278720, 875783936, 876290112, 876796480, 877303232, 877810176, 878317504, 878824512, 879332416, 879840576, 880349056, 880857792, 881366272, 881875712, 882385280, 882895296, 883405440, 883915456, 884426304, 884937408, 885448832, 885960512, 886472512,
+ 886984192, 887496768, 888009728, 888522944, 889036352, 889549632, 890063680, 890578048, 891092736, 891607680, 892122368, 892637952, 893153792, 893670016, 894186496, 894703232, 895219648, 895737024, 896254720, 896772672, 897290880, 897808896, 898327744, 898846912, 899366336, 899886144, 900405568, 900925952, 901446592, 901967552, 902488768, 903010368, 903531584, 904053760, 904576256, 905099008, 905622016, 906144896, 906668480, 907192512, 907716800, 908241408, 908765632, 909290816, 909816256, 910342144, 910868160, 911394624, 911920768, 912447680, 912975104, 913502720, 914030592, 914558208, 915086784, 915615552, 916144768, 916674176, 917203968, 917733440, 918263744, 918794496, 919325440, 919856704, 920387712, 920919616, 921451840, 921984320, 922517184, 923049728, 923583168, 924116928, 924651008, 925185344, 925720000, 926254336, 926789696, 927325312, 927861120, 928397440, 928933376, 929470208, 930007296, 930544768, 931082560, 931619968, 932158464, 932697152, 933236160, 933775488, 934315072, 934854464, 935394688, 935935296, 936476224, 937017344, 937558208, 938100160, 938642304, 939184640,
+ 939727488, 940269888, 940813312, 941357056, 941900992, 942445440, 942990016, 943534400, 944079680, 944625280, 945171200, 945717440, 946263360, 946810176, 947357376, 947904832, 948452672, 949000192, 949548608, 950097280, 950646400, 951195776, 951745472, 952294912, 952845184, 953395904, 953946880, 954498176, 955049216, 955601088, 956153408, 956705920, 957258816, 957812032, 958364928, 958918848, 959472960, 960027456, 960582272, 961136768, 961692224, 962248000, 962804032, 963360448, 963916608, 964473600, 965031040, 965588736, 966146816, 966705152, 967263168, 967822144, 968381440, 968941120, 969501056, 970060736, 970621376, 971182272, 971743488, 972305088, 972866368, 973428608, 973991104, 974554048, 975117312, 975680768, 976243968, 976808192, 977372736, 977937536, 978502656, 979067584, 979633344, 980199488, 980765888, 981332736, 981899200, 982466688, 983034432, 983602624, 984171008, 984739776, 985308160, 985877632, 986447360, 987017472, 987587904, 988157952, 988729088, 989300416, 989872192, 990444224, 991016000, 991588672, 992161728, 992735168, 993308864, 993882880, 994456576, 995031296,
+ 995606336, 996181696, 996757440, 997332800, 997909184, 998485888, 999062912, 999640256, 1000217984, 1000795392, 1001373696, 1001952448, 1002531520, 1003110848, 1003689920, 1004270016, 1004850304, 1005431040, 1006012160, 1006592832, 1007174592, 1007756608, 1008339008, 1008921792, 1009504768, 1010087552, 1010671296, 1011255360, 1011839808, 1012424576, 1013009024, 1013594368, 1014180160, 1014766272, 1015352768, 1015938880, 1016526016, 1017113472, 1017701248, 1018289408, 1018877824, 1019465984, 1020055104, 1020644672, 1021234496, 1021824768, 1022414528, 1023005440, 1023596608, 1024188160, 1024780096, 1025371584, 1025964160, 1026557120, 1027150336, 1027744000, 1028337920, 1028931520, 1029526144, 1030121152, 1030716480, 1031312128, 1031907456, 1032503808, 1033100480, 1033697536, 1034294912, 1034892032, 1035490048, 1036088512, 1036687232, 1037286336, 1037885824, 1038484928, 1039085056, 1039685632, 1040286464, 1040887680, 1041488448, 1042090368, 1042692608, 1043295168, 1043898176, 1044501440, 1045104384, 1045708288, 1046312640, 1046917376, 1047522368, 1048127040, 1048732800, 1049338816, 1049945280, 1050552128, 1051158528, 1051765952, 1052373824, 1052982016, 1053590592, 1054199424,
+ 1054807936, 1055417600, 1056027456, 1056637760, 1057248448, 1057858752, 1058470016, 1059081728, 1059693824, 1060306304, 1060918336, 1061531392, 1062144896, 1062758656, 1063372928, 1063987392, 1064601664, 1065216896, 1065832448, 1066448448, 1067064704, 1067680704, 1068297728, 1068915136, 1069532864, 1070150976, 1070768640, 1071387520, 1072006720, 1072626240, 1073246080, 1073866368, 1074486272, 1075107200, 1075728512, 1076350208, 1076972160, 1077593856, 1078216704, 1078839680, 1079463296, 1080087040, 1080710528, 1081335168, 1081960064, 1082585344, 1083211008, 1083836928, 1084462592, 1085089280, 1085716352, 1086343936, 1086971648, 1087599104, 1088227712, 1088856576, 1089485824, 1090115456, 1090745472, 1091375104, 1092005760, 1092636928, 1093268352, 1093900160, 1094531584, 1095164160, 1095796992, 1096430336, 1097064064, 1097697280, 1098331648, 1098966400, 1099601536, 1100237056, 1100872832, 1101508224, 1102144768, 1102781824, 1103419136, 1104056832, 1104694144, 1105332608, 1105971328, 1106610432, 1107249920, 1107889152, 1108529408, 1109170048, 1109811072, 1110452352, 1111094144, 1111735552, 1112377984, 1113020928, 1113664128, 1114307712, 1114950912, 1115595264, 1116240000, 1116885120,
+ 1117530624, 1118175744, 1118821888, 1119468416, 1120115456, 1120762752, 1121410432, 1122057856, 1122706176, 1123355136, 1124004224, 1124653824, 1125303040, 1125953408, 1126604160, 1127255168, 1127906560, 1128557696, 1129209984, 1129862528, 1130515456, 1131168768, 1131822592, 1132475904, 1133130368, 1133785216, 1134440448, 1135096064, 1135751296, 1136407680, 1137064448, 1137721472, 1138379008, 1139036800, 1139694336, 1140353024, 1141012096, 1141671424, 1142331264, 1142990592, 1143651200, 1144312192, 1144973440, 1145635200, 1146296448, 1146958976, 1147621760, 1148285056, 1148948608, 1149612672, 1150276224, 1150940928, 1151606144, 1152271616, 1152937600, 1153603072, 1154269824, 1154936832, 1155604352, 1156272128, 1156939648, 1157608192, 1158277248, 1158946560, 1159616384, 1160286464, 1160956288, 1161627264, 1162298624, 1162970240, 1163642368, 1164314112, 1164987008, 1165660160, 1166333824, 1167007872, 1167681536, 1168356352, 1169031552, 1169707136, 1170383104, 1171059584, 1171735552, 1172412672, 1173090304, 1173768192, 1174446592, 1175124480, 1175803648, 1176483072, 1177163008, 1177843328, 1178523264, 1179204352, 1179885824, 1180567680, 1181249920, 1181932544, 1182614912, 1183298304,
+ 1183982208, 1184666368, 1185351040, 1186035328, 1186720640, 1187406464, 1188092672, 1188779264, 1189466368, 1190152960, 1190840832, 1191528960, 1192217600, 1192906624, 1193595136, 1194285056, 1194975232, 1195665792, 1196356736, 1197047296, 1197739136, 1198431360, 1199123968, 1199816960, 1200510336, 1201203328, 1201897600, 1202592128, 1203287040, 1203982464, 1204677504, 1205373696, 1206070272, 1206767232, 1207464704, 1208161664, 1208859904, 1209558528, 1210257536, 1210956928, 1211656832, 1212356224, 1213056768, 1213757952, 1214459392, 1215161216, 1215862656, 1216565376, 1217268352, 1217971840, 1218675712, 1219379200, 1220083840, 1220788992, 1221494528, 1222200448, 1222906752, 1223612672, 1224319872, 1225027456, 1225735424, 1226443648, 1227151616, 1227860864, 1228570496, 1229280512, 1229990912, 1230700928, 1231412096, 1232123776, 1232835840, 1233548288, 1234261248, 1234973696, 1235687424, 1236401536, 1237116032, 1237831040, 1238545536, 1239261312, 1239977472, 1240694144, 1241411072, 1242128512, 1242845568, 1243563776, 1244282496, 1245001600, 1245721088, 1246440192, 1247160448, 1247881216, 1248602368, 1249324032, 1250045184, 1250767616, 1251490432, 1252213632, 1252937344, 1253661440,
+ 1254385152, 1255110016, 1255835392, 1256561152, 1257287424, 1258013184, 1258740096, 1259467648, 1260195456, 1260923648, 1261651584, 1262380800, 1263110272, 1263840256, 1264570624, 1265301504, 1266031872, 1266763520, 1267495552, 1268227968, 1268961024, 1269693440, 1270427264, 1271161472, 1271896064, 1272631168, 1273365760, 1274101632, 1274838016, 1275574784, 1276311808, 1277049472, 1277786624, 1278525056, 1279264000, 1280003328, 1280743040, 1281482368, 1282222976, 1282963968, 1283705344, 1284447232, 1285188736, 1285931392, 1286674560, 1287418240, 1288162176, 1288906624, 1289650688, 1290395904, 1291141760, 1291887872, 1292634496, 1293380608, 1294128128, 1294875904, 1295624320, 1296373120, 1297122304, 1297870976, 1298621056, 1299371520, 1300122496, 1300873856, 1301624832, 1302376960, 1303129600, 1303882752, 1304636288, 1305389312, 1306143872, 1306898688, 1307654016, 1308409600, 1309165696, 1309921536, 1310678528, 1311435904, 1312193920, 1312952192, 1313710080, 1314469248, 1315228928, 1315988992, 1316749568, 1317509632, 1318271104, 1319032960, 1319795200, 1320557952, 1321321088, 1322083840, 1322847872, 1323612416, 1324377216, 1325142656, 1325907584, 1326673920, 1327440512, 1328207744,
+ 1328975360, 1329742464, 1330510976, 1331279872, 1332049152, 1332819072, 1333589248, 1334359168, 1335130240, 1335901824, 1336673920, 1337446400, 1338218368, 1338991744, 1339765632, 1340539904, 1341314560, 1342088832, 1342864512, 1343640576, 1344417024, 1345193984, 1345971456, 1346748416, 1347526656, 1348305408, 1349084672, 1349864320, 1350643456, 1351424000, 1352205056, 1352986496, 1353768448, 1354550784, 1355332608, 1356115968, 1356899712, 1357683840, 1358468480, 1359252608, 1360038144, 1360824192, 1361610624, 1362397440, 1363183872, 1363971712, 1364760064, 1365548672, 1366337792, 1367127424, 1367916672, 1368707200, 1369498240, 1370289664, 1371081472, 1371873024, 1372665856, 1373459072, 1374252800, 1375047040, 1375840768, 1376635904, 1377431552, 1378227584, 1379024000, 1379820928, 1380617472, 1381415296, 1382213760, 1383012480, 1383811840, 1384610560, 1385410816, 1386211456, 1387012480, 1387814144, 1388615168, 1389417728, 1390220672, 1391024128, 1391827968, 1392632320, 1393436288, 1394241536, 1395047296, 1395853568, 1396660224, 1397466368, 1398274048, 1399082112, 1399890688, 1400699648, 1401508224, 1402318080, 1403128576, 1403939456, 1404750848, 1405562624, 1406374016, 1407186816,
+ 1408000000, 1408813696, 1409627904, 1410441728, 1411256704, 1412072320, 1412888320, 1413704960, 1414521856, 1415338368, 1416156288, 1416974720, 1417793664, 1418612992, 1419431808, 1420252160, 1421072896, 1421894144, 1422715904, 1423537280, 1424359808, 1425183104, 1426006784, 1426830848, 1427655296, 1428479488, 1429305088, 1430131072, 1430957568, 1431784576, 1432611072, 1433438976, 1434267392, 1435096192, 1435925632, 1436754432, 1437584768, 1438415616, 1439246848, 1440078720, 1440910848, 1441742720, 1442575872, 1443409664, 1444243584, 1445078400, 1445912576, 1446748032, 1447584256, 1448420864, 1449257856, 1450094464, 1450932480, 1451771008, 1452609920, 1453449472, 1454289408, 1455128960, 1455969920, 1456811264, 1457653248, 1458495616, 1459337600, 1460180864, 1461024768, 1461869056, 1462713984, 1463558272, 1464404096, 1465250304, 1466097152, 1466944384, 1467792128, 1468639488, 1469488256, 1470337408, 1471187200, 1472037376, 1472887168, 1473738368, 1474589952, 1475442304, 1476294912, 1477148160, 1478000768, 1478854912, 1479709696, 1480564608, 1481420288, 1482275456, 1483132160, 1483989248, 1484846976, 1485704960, 1486562688, 1487421696, 1488281344, 1489141504, 1490002048, 1490863104,
+ 1491723776, 1492585856, 1493448448, 1494311424, 1495175040, 1496038144, 1496902656, 1497767808, 1498633344, 1499499392, 1500365056, 1501232128, 1502099712, 1502967808, 1503836416, 1504705536, 1505574016, 1506444032, 1507314688, 1508185856, 1509057408, 1509928576, 1510801280, 1511674240, 1512547840, 1513421952, 1514295680, 1515170816, 1516046464, 1516922624, 1517799296, 1518676224, 1519552896, 1520431104, 1521309824, 1522188928, 1523068800, 1523948032, 1524828672, 1525709824, 1526591616, 1527473792, 1528355456, 1529238784, 1530122496, 1531006720, 1531891712, 1532776832, 1533661824, 1534547968, 1535434880, 1536322304, 1537210112, 1538097408, 1538986368, 1539875840, 1540765696, 1541656192, 1542547072, 1543437440, 1544329472, 1545221888, 1546114944, 1547008384, 1547901440, 1548796032, 1549691136, 1550586624, 1551482752, 1552378368, 1553275520, 1554173184, 1555071232, 1555970048, 1556869248, 1557767936, 1558668288, 1559568896, 1560470272, 1561372032, 1562273408, 1563176320, 1564079616, 1564983424, 1565888000, 1566791808, 1567697408, 1568603392, 1569509760, 1570416896, 1571324416, 1572231424, 1573140096, 1574049152, 1574958976, 1575869184, 1576778752, 1577689984, 1578601728, 1579514112,
+ 1580426880, 1581339264, 1582253056, 1583167488, 1584082432, 1584997888, 1585913984, 1586829440, 1587746304, 1588663936, 1589582080, 1590500736, 1591418880, 1592338560, 1593258752, 1594179584, 1595100928, 1596021632, 1596944000, 1597866880, 1598790272, 1599714304, 1600638848, 1601562752, 1602488320, 1603414272, 1604340992, 1605268224, 1606194816, 1607123072, 1608051968, 1608981120, 1609911040, 1610841344, 1611771264, 1612702848, 1613634688, 1614567168, 1615500288, 1616432896, 1617367040, 1618301824, 1619237120, 1620172800, 1621108096, 1622044928, 1622982272, 1623920128, 1624858752, 1625797632, 1626736256, 1627676416, 1628616960, 1629558272, 1630499968, 1631441152, 1632384000, 1633327232, 1634271232, 1635215744, 1636159744, 1637105152, 1638051328, 1638998016, 1639945088, 1640892928, 1641840128, 1642788992, 1643738368, 1644688384, 1645638784, 1646588672, 1647540352, 1648492416, 1649445120, 1650398464, 1651351168, 1652305408, 1653260288, 1654215808, 1655171712, 1656128256, 1657084288, 1658041856, 1659000064, 1659958784, 1660918272, 1661876992, 1662837376, 1663798400, 1664759936, 1665721984, 1666683520, 1667646720, 1668610560, 1669574784, 1670539776, 1671505024, 1672470016, 1673436544,
+};
+
+#define SAMPLE_16BIT 0x01
+#define SAMPLE_UNSIGNED 0x02
+#define SAMPLE_LOOP 0x04
+#define SAMPLE_PINGPONG 0x08
+#define SAMPLE_REVERSE 0x10
+#define SAMPLE_SUSTAIN 0x20
+#define SAMPLE_ENVELOPE 0x40
+
+#ifdef DEBUG_SAMPLES
+#define SAMPLE_CONVERT_DEBUG(dx) printf("\r%s\n",dx)
+#else
+#define SAMPLE_CONVERT_DEBUG(dx)
+#endif
+
+#ifdef DEBUG_MIDI
+#define MIDI_EVENT_DEBUG(dx,dy) printf("\r%s, %x\n",dx,dy)
+#else
+#define MIDI_EVENT_DEBUG(dx,dy)
+#endif
+
+#define WM_ERR_MEM 0
+#define WM_ERR_STAT 1
+#define WM_ERR_LOAD 2
+#define WM_ERR_OPEN 3
+#define WM_ERR_READ 4
+#define WM_ERR_INVALID 5
+#define WM_ERR_CORUPT 6
+#define WM_ERR_NOT_INIT 7
+#define WM_ERR_INVALID_ARG 8
+
+#define MAX_AUTO_AMP 2.0
+
+#define FPBITS 10
+#define FPMASK ((1L<<FPBITS)-1L)
+
+
+void do_note_off (unsigned char ch, struct _mdi *mdi, unsigned long int ptr);
+void do_note_on (unsigned char ch, struct _mdi *mdi, unsigned long int ptr);
+void do_aftertouch (unsigned char ch, struct _mdi *mdi, unsigned long int ptr);
+void do_control (unsigned char ch, struct _mdi *mdi, unsigned long int ptr);
+void do_patch (unsigned char ch, struct _mdi *mdi, unsigned long int ptr);
+void do_channel_pressure (unsigned char ch, struct _mdi *mdi, unsigned long int ptr);
+void do_pitch (unsigned char ch, struct _mdi *mdi, unsigned long int ptr);
+void do_message (unsigned char ch, struct _mdi *mdi, unsigned long int ptr);
+
+void (*do_event[])(unsigned char ch, struct _mdi *midifile, unsigned long int ptr) = {
+ *do_note_off,
+ *do_note_on,
+ *do_aftertouch,
+ *do_control,
+ *do_patch,
+ *do_channel_pressure,
+ *do_pitch,
+ *do_message
+};
+
+/*
+ * =========================
+ * Internal Functions
+ * =========================
+ */
+
+
+void
+WM_ERROR( const char * func, unsigned long int lne, int wmerno, const char * wmfor, int error) {
+ const char * errors[] = {
+ "Unable to obtain memory\0",
+ "Unable to stat\0",
+ "Unable to load\0",
+ "Unable to open\0",
+ "Unable to read\0",
+ "Invalid or Unsuported file format\0",
+ "File corrupt\0",
+ "Library not Initialized\0",
+ "Invalid argument\0"
+ };
+ if (wmfor != NULL) {
+ if (error != 0) {
+ fprintf(stderr,"\rlibWildMidi(%s:%lu): ERROR %s %s (%s)\n",func, lne, errors[wmerno], wmfor, strerror(error));
+ } else {
+ fprintf(stderr,"\rlibWildMidi(%s:%lu): ERROR %s %s\n",func, lne, errors[wmerno], wmfor);
+ }
+ } else {
+ if (error != 0) {
+ fprintf(stderr,"\rlibWildMidi(%s:%lu): ERROR %s (%s)\n",func, lne, errors[wmerno], strerror(error));
+ } else {
+ fprintf(stderr,"\rlibWildMidi(%s:%lu): ERROR %s\n",func, lne, errors[wmerno]);
+ }
+ }
+
+}
+
+unsigned char *
+WM_BufferFile (const char *filename, unsigned long int *size) {
+ int buffer_fd;
+ char *data;
+ struct stat buffer_stat;
+#ifndef _WIN32
+ char *home = NULL;
+ struct passwd *pwd_ent;
+ char buffer_dir[1024];
+#endif
+
+ char *buffer_file = malloc(strlen(filename) + 1);
+
+ if (buffer_file == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno);
+ return NULL;
+ }
+
+ strcpy (buffer_file, filename);
+#ifndef _WIN32
+ if (strncmp(buffer_file,"~/",2) == 0) {
+ if ((pwd_ent = getpwuid (getuid ()))) {
+ home = pwd_ent->pw_dir;
+ } else {
+ home = getenv ("HOME");
+ }
+ if (home) {
+ buffer_file = realloc(buffer_file,(strlen(buffer_file) + strlen(home) + 1));
+ if (buffer_file == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno);
+ free(buffer_file);
+ return NULL;
+ }
+ memmove((buffer_file + strlen(home)), (buffer_file + 1), (strlen(buffer_file)));
+ strncpy (buffer_file, home,strlen(home));
+ }
+ } else if (buffer_file[0] != '/') {
+ getcwd(buffer_dir,1024);
+ if (buffer_dir[strlen(buffer_dir)-1] != '/') {
+ buffer_dir[strlen(buffer_dir)+1] = '\0';
+ buffer_dir[strlen(buffer_dir)] = '/';
+ }
+ buffer_file = realloc(buffer_file,(strlen(buffer_file) + strlen(buffer_dir) + 1));
+ if (buffer_file == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno);
+ free(buffer_file);
+ return NULL;
+ }
+ memmove((buffer_file + strlen(buffer_dir)), buffer_file, strlen(buffer_file)+1);
+ strncpy (buffer_file,buffer_dir,strlen(buffer_dir));
+ }
+#endif
+ if (stat(buffer_file,&buffer_stat)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_STAT, filename, errno);
+ free(buffer_file);
+ return NULL;
+ }
+ *size = buffer_stat.st_size;
+ data = malloc(*size);
+ if (data == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno);
+ free(buffer_file);
+ return NULL;
+ }
+#ifdef _WIN32
+ if ((buffer_fd = open(buffer_file,(O_RDONLY | O_BINARY))) == -1) {
+#else
+ if ((buffer_fd = open(buffer_file,O_RDONLY)) == -1) {
+#endif
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_OPEN, filename, errno);
+ free(buffer_file);
+ free(data);
+ return NULL;
+ }
+ if (read(buffer_fd,data,*size) != buffer_stat.st_size) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_READ, filename, errno);
+ free(buffer_file);
+ free(data);
+ close(buffer_fd);
+ return NULL;
+ }
+ close(buffer_fd);
+ free(buffer_file);
+ return data;
+}
+
+inline void
+WM_Lock (int * wmlock) {
+ LOCK_START:
+ if (__builtin_expect(((*wmlock) == 0),1)) {
+ (*wmlock)++;
+ if (__builtin_expect(((*wmlock) == 1), 1)) {
+ return;
+ }
+ (*wmlock)--;
+ }
+#ifdef _WIN32
+ Sleep(10);
+#else
+ usleep(500);
+#endif
+ goto LOCK_START;
+}
+
+inline void
+WM_Unlock (int *wmlock) {
+ (*wmlock)--;
+}
+
+void
+WM_InitPatches ( void ) {
+ int i;
+ for (i = 0; i < 128; i++) {
+ patch[i] = NULL;
+ }
+}
+
+void
+WM_FreePatches ( void ) {
+ int i;
+ struct _patch * tmp_patch;
+ struct _sample * tmp_sample;
+
+ WM_Lock(&patch_lock);
+ for (i = 0; i < 128; i++) {
+ if (patch[i] != NULL) {
+ while (patch[i] != NULL) {
+ if (patch[i]->filename != NULL) {
+ if (patch[i]->first_sample != NULL) {
+ while (patch[i]->first_sample != NULL) {
+ tmp_sample = patch[i]->first_sample->next;
+ if (patch[i]->first_sample->data != NULL)
+ free (patch[i]->first_sample->data);
+ free (patch[i]->first_sample);
+ patch[i]->first_sample = tmp_sample;
+ }
+ }
+ free (patch[i]->filename);
+ }
+ tmp_patch = patch[i]->next;
+ free(patch[i]);
+ patch[i] = tmp_patch;
+ }
+ }
+ }
+ WM_Unlock(&patch_lock);
+}
+
+int
+WM_LoadConfig (const char *config_file) {
+ unsigned long int config_size = 0;
+ unsigned char *config_buffer = NULL;
+ char * dir_end = NULL;
+ char * config_dir = NULL;
+ unsigned long int config_ptr = 0;
+ unsigned long int line_start_ptr = 0;
+ char * line_buffer = NULL;
+ unsigned long int line_ptr = 0;
+ char * chr_ptr = NULL;
+ unsigned short int patchid = 0;
+ char * new_config = NULL;
+ struct _patch * tmp_patch;
+
+ if ((config_buffer = WM_BufferFile(config_file, &config_size)) == NULL) {
+ return -1;
+ }
+ if (config_buffer == NULL) {
+ WM_FreePatches();
+ return -1;
+ }
+
+ dir_end = strrchr(config_file,'/');
+ if (dir_end != NULL) {
+ config_dir = malloc((dir_end - config_file + 2));
+ if (config_dir == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse config", errno);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
+ WM_FreePatches();
+ free (config_buffer);
+ return -1;
+ }
+ strncpy(config_dir, config_file, (dir_end - config_file + 1));
+ config_dir[dir_end - config_file + 1] = '\0';
+ }
+ config_ptr = 0;
+ line_start_ptr = 0;
+ while (config_ptr < config_size) {
+ // find end of line
+ if (config_buffer[config_ptr] != '\n') {
+ // remove unwanted crud
+ if (config_buffer[config_ptr] == '\t') {
+ config_buffer[config_ptr] = ' ';
+ } else if (config_buffer[config_ptr] == '\r') {
+ config_buffer[config_ptr] = ' ';
+ }
+ if ((config_buffer[config_ptr] == ' ') && (config_ptr == line_start_ptr)) {
+ line_start_ptr++;
+ }
+
+ config_ptr++;
+ continue;
+ }
+ config_buffer[config_ptr] = '\0';
+ if (config_ptr == line_start_ptr) {
+ config_ptr++;
+ line_start_ptr++;
+ continue;
+ }
+ if (config_buffer[line_start_ptr] == '#') {
+ config_ptr++;
+ line_start_ptr = config_ptr;
+ continue;
+ }
+
+ // copy line into a workable buffer
+ line_buffer = realloc(line_buffer, (config_ptr - line_start_ptr + 1));
+ if (line_buffer == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse config", errno);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
+ WM_FreePatches();
+ if (config_dir != NULL)
+ free(config_dir);
+ free (config_buffer);
+ return -1;
+ }
+ strcpy(line_buffer, &config_buffer[line_start_ptr]);
+ config_ptr++;
+ line_start_ptr = config_ptr;
+ // remove unwnted crud from line for easier parsing
+ if ((chr_ptr = strstr(line_buffer," ")) != NULL) {
+ while ((chr_ptr = strstr(line_buffer," ")) != NULL) {
+ memmove(chr_ptr, &chr_ptr[1], strlen(chr_ptr));
+ }
+ }
+ if ((chr_ptr = strchr(line_buffer, '#')) != NULL) {
+ *chr_ptr = '\0';
+ }
+ if (line_buffer[strlen(line_buffer) -1] == ' ') {
+ while (line_buffer[strlen(line_buffer) -1] == ' ') {
+ line_buffer[strlen(line_buffer) -1] = '\0';
+ }
+ }
+
+ // now parse line
+ if (strncasecmp(line_buffer, "dir ", 4) == 0) {
+ if (line_buffer[strlen(line_buffer) - 1] == '/') {
+ config_dir = realloc(config_dir, strlen(&line_buffer[4]) + 1);
+ if (config_dir == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse config", errno);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
+ WM_FreePatches();
+ free (line_buffer);
+ free (config_buffer);
+ return -1;
+ }
+ strcpy(config_dir, &line_buffer[4]);
+ } else {
+ config_dir = realloc(config_dir, strlen(&line_buffer[4]) + 2);
+ if (config_dir == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse config", errno);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
+ WM_FreePatches();
+ free (line_buffer);
+ free (config_buffer);
+ return -1;
+ }
+ strcpy(config_dir, &line_buffer[4]);
+ strcat(config_dir,"/");
+ }
+ printf ("wildmidi config_dir: %s\n", config_dir);
+ continue;
+ } else if (strncasecmp(line_buffer, "source ", 7) == 0) {
+ if (config_dir != NULL, 0) {
+ new_config = malloc(strlen(config_dir) + strlen(&line_buffer[7]) + 1);
+ if (new_config == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse config", errno);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
+ WM_FreePatches();
+ free (config_dir);
+ free (line_buffer);
+ free (config_buffer);
+ return -1;
+ }
+ strcpy(new_config,config_dir);
+ strcpy(&new_config[strlen(config_dir)], &line_buffer[7]);
+ } else {
+ new_config = malloc(strlen(&line_buffer[7]) + 1);
+ if (new_config == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse config", errno);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
+ WM_FreePatches();
+ free (line_buffer);
+ free (config_buffer);
+ return -1;
+ }
+ strcpy(new_config, &line_buffer[7]);
+ }
+ printf ("wildmidi load new_config: %s\n", new_config);
+ if (WM_LoadConfig(new_config) == -1) {
+ free (new_config);
+ free (line_buffer);
+ free (config_buffer);
+ //if (config_dir != NULL)
+ // free (config_dir);
+ return -1;
+ }
+ free (new_config);
+ continue;
+ } else if (strncasecmp(line_buffer, "bank ", 5) == 0) {
+ printf ("loading bank, config_dir: %s\n", config_dir);
+ if (!isdigit(line_buffer[5])) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in bank line)", 0);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
+ WM_FreePatches();
+ if (config_dir != NULL)
+ free (config_dir);
+ free (line_buffer);
+ free (config_buffer);
+ return -1;
+ }
+ patchid = (atoi(&line_buffer[5]) & 0xFF ) << 8;
+ continue;
+ } else if (strncasecmp(line_buffer, "drumset ", 8) == 0) {
+ if (!isdigit(line_buffer[8])) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in drumset line)", 0);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
+ WM_FreePatches();
+ if (config_dir != NULL)
+ free (config_dir);
+ free (line_buffer);
+ free (config_buffer);
+ return -1;
+ }
+ patchid = ((atoi(&line_buffer[8]) & 0xFF ) << 8) | 0x80;
+ continue;
+ } else if (isdigit(line_buffer[0])) {
+ patchid = (patchid & 0xFF80) | (atoi(line_buffer) & 0x7F);
+ if (patch[(patchid & 0x7F)] == NULL) {
+ patch[(patchid & 0x7F)] = malloc (sizeof(struct _patch));
+ if (patch[(patchid & 0x7F)] == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
+ WM_FreePatches();
+ if (config_dir != NULL)
+ free (config_dir);
+ free (line_buffer);
+ free (config_buffer);
+ return -1;
+ }
+ tmp_patch = patch[(patchid & 0x7F)];
+ tmp_patch->patchid = patchid;
+ tmp_patch->filename = NULL;
+ tmp_patch->amp = 1024;
+ tmp_patch->note = 0;
+ tmp_patch->next = NULL;
+ tmp_patch->first_sample = NULL;
+ tmp_patch->loaded = 0;
+ tmp_patch->inuse_count = 0;
+ } else {
+ tmp_patch = patch[(patchid & 0x7F)];
+ if (tmp_patch->patchid == patchid) {
+ free (tmp_patch->filename);
+ tmp_patch->filename = NULL;
+ tmp_patch->amp = 1024;
+ tmp_patch->note = 0;
+ } else {
+ if (tmp_patch->next != NULL) {
+ while (tmp_patch->next != NULL) {
+ if (tmp_patch->next->patchid == patchid)
+ break;
+ tmp_patch = tmp_patch->next;
+ }
+ if (tmp_patch->next == NULL) {
+ tmp_patch->next = malloc (sizeof(struct _patch));
+ if (tmp_patch->next == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
+ WM_FreePatches();
+ if (config_dir != NULL)
+ free (config_dir);
+ free (line_buffer);
+ free (config_buffer);
+ return -1;
+ }
+ tmp_patch = tmp_patch->next;
+ tmp_patch->patchid = patchid;
+ tmp_patch->filename = NULL;
+ tmp_patch->amp = 1024;
+ tmp_patch->note = 0;
+ tmp_patch->next = NULL;
+ tmp_patch->first_sample = NULL;
+ tmp_patch->loaded = 0;
+ tmp_patch->inuse_count = 0;
+ } else {
+ tmp_patch = tmp_patch->next;
+ free (tmp_patch->filename);
+ tmp_patch->filename = NULL;
+ tmp_patch->amp = 1024;
+ tmp_patch->note = 0;
+ }
+ } else {
+ tmp_patch->next = malloc (sizeof(struct _patch));
+ if (tmp_patch->next == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
+ WM_FreePatches();
+ if (config_dir != NULL)
+ free (config_dir);
+ free (line_buffer);
+ free (config_buffer);
+ return -1;
+ }
+ tmp_patch = tmp_patch->next;
+ tmp_patch->patchid = patchid;
+ tmp_patch->filename = NULL;
+ tmp_patch->amp = 1024;
+ tmp_patch->note = 0;
+ tmp_patch->next = NULL;
+ tmp_patch->first_sample = NULL;
+ tmp_patch->loaded = 0;
+ tmp_patch->inuse_count = 0;
+ }
+ }
+ }
+
+ chr_ptr = strchr(line_buffer,' ') + 1;
+ if (chr_ptr == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
+ WM_FreePatches();
+ if (config_dir != NULL)
+ free (config_dir);
+ free (line_buffer);
+ free (config_buffer);
+ return -1;
+ }
+ line_ptr = chr_ptr - line_buffer;
+ chr_ptr = strchr(&line_buffer[line_ptr],' ');
+ if (chr_ptr != NULL) {
+ *chr_ptr = '\0';
+ }
+ if (strncasecmp(&line_buffer[(line_ptr + strlen(&line_buffer[line_ptr]) - 5)], ".pat", 4) != 0, 0) {
+ if (config_dir != NULL) {
+ tmp_patch->filename = malloc(strlen(config_dir) + strlen(&line_buffer[line_ptr]) + 5);
+ if (tmp_patch->filename == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
+ WM_FreePatches();
+ if (config_dir != NULL)
+ free (config_dir);
+ free (line_buffer);
+ free (config_buffer);
+ return -1;
+ }
+ strcpy(tmp_patch->filename, config_dir);
+ strcat(tmp_patch->filename, &line_buffer[line_ptr]);
+ } else {
+ tmp_patch->filename = malloc(strlen(&line_buffer[line_ptr]) + 5);
+ if (tmp_patch->filename == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
+ WM_FreePatches();
+ free (line_buffer);
+ free (config_buffer);
+ return -1;
+ }
+ strcpy(tmp_patch->filename, &line_buffer[line_ptr]);
+ }
+ strcat(tmp_patch->filename, ".pat");
+ } else {
+ if (config_dir != NULL) {
+ tmp_patch->filename = malloc(strlen(config_dir) + strlen(&line_buffer[line_ptr]) + 1);
+ if (tmp_patch->filename == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
+ WM_FreePatches();
+ if (config_dir != NULL)
+ free (config_dir);
+ free (line_buffer);
+ free (config_buffer);
+ return -1;
+ }
+ strcpy(tmp_patch->filename, config_dir);
+ strcat(tmp_patch->filename, &line_buffer[line_ptr]);
+ } else {
+ tmp_patch->filename = malloc(strlen(&line_buffer[line_ptr]) + 1);
+ if (tmp_patch->filename == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0);
+ WM_FreePatches();
+ free (line_buffer);
+ free (config_buffer);
+ return -1;
+ }
+ strcpy(tmp_patch->filename, &line_buffer[line_ptr]);
+ }
+ }
+
+ tmp_patch->env[0].set = 0x00;
+ tmp_patch->env[1].set = 0x00;
+ tmp_patch->env[2].set = 0x00;
+ tmp_patch->env[3].set = 0x00;
+ tmp_patch->env[4].set = 0x00;
+ tmp_patch->env[5].set = 0x00;
+ tmp_patch->keep = 0;
+ tmp_patch->remove = 0;
+
+ if (chr_ptr != NULL) {
+ line_ptr = chr_ptr - line_buffer + 1;
+ chr_ptr = strstr(&line_buffer[line_ptr], "amp=");
+ if (chr_ptr != NULL) {
+ if (!isdigit(chr_ptr[4])) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0);
+ } else {
+ tmp_patch->amp = ((atoi(&chr_ptr[4]) << 10) / 100);
+ }
+ }
+ chr_ptr = strstr(&line_buffer[line_ptr], "note=");
+ if (chr_ptr != NULL) {
+ if (!isdigit(chr_ptr[5])) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0);
+ } else {
+ tmp_patch->note = atoi(&chr_ptr[5]);
+ }
+ }
+ chr_ptr = strstr(&line_buffer[line_ptr], "keep=loop");
+ if (chr_ptr != NULL) {
+ tmp_patch->keep |= SAMPLE_LOOP;
+ }
+ chr_ptr = strstr(&line_buffer[line_ptr], "keep=env");
+ if (chr_ptr != NULL) {
+ tmp_patch->keep |= SAMPLE_ENVELOPE;
+ }
+ chr_ptr = strstr(&line_buffer[line_ptr], "remove=sustain");
+ if (chr_ptr != NULL) {
+ tmp_patch->remove |= SAMPLE_SUSTAIN;
+ }
+ chr_ptr = strstr(&line_buffer[line_ptr], "env_time0=");
+ if (chr_ptr != NULL) {
+ if (!isdigit(chr_ptr[10])) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0);
+ } else {
+ tmp_patch->env[0].time = atof(&chr_ptr[10]);
+ if ((tmp_patch->env[0].time > 45000.0) || (tmp_patch->env[0].time < 1.47)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0);
+ tmp_patch->env[0].set &= 0xFE;
+ } else {
+ tmp_patch->env[0].set |= 0x01;
+ }
+ }
+ }
+
+ chr_ptr = strstr(&line_buffer[line_ptr], "env_time1=");
+ if (chr_ptr != NULL) {
+ if (!isdigit(chr_ptr[10])) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0);
+ } else {
+ tmp_patch->env[1].time = atof(&chr_ptr[10]);
+ if ((tmp_patch->env[1].time > 45000.0) || (tmp_patch->env[1].time < 1.47)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0);
+ tmp_patch->env[1].set &= 0xFE;
+ } else {
+ tmp_patch->env[1].set |= 0x01;
+ }
+ }
+ }
+ chr_ptr = strstr(&line_buffer[line_ptr], "env_time2=");
+ if (chr_ptr != NULL) {
+ if (!isdigit(chr_ptr[10])) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0);
+ } else {
+ tmp_patch->env[2].time = atof(&chr_ptr[10]);
+ if ((tmp_patch->env[2].time > 45000.0) || (tmp_patch->env[2].time < 1.47)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0);
+ tmp_patch->env[2].set &= 0xFE;
+ } else {
+ tmp_patch->env[2].set |= 0x01;
+ }
+ }
+ }
+ chr_ptr = strstr(&line_buffer[line_ptr], "env_time3=");
+ if (chr_ptr != NULL) {
+ if (!isdigit(chr_ptr[10])) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0);
+ } else {
+ tmp_patch->env[3].time = atof(&chr_ptr[10]);
+ if ((tmp_patch->env[3].time > 45000.0) || (tmp_patch->env[3].time < 1.47)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0);
+ tmp_patch->env[3].set &= 0xFE;
+ } else {
+ tmp_patch->env[3].set |= 0x01;
+ }
+ }
+ }
+ chr_ptr = strstr(&line_buffer[line_ptr], "env_time4=");
+ if (chr_ptr != NULL) {
+ if (!isdigit(chr_ptr[10])) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0);
+ } else {
+ tmp_patch->env[4].time = atof(&chr_ptr[10]);
+ if ((tmp_patch->env[4].time > 45000.0) || (tmp_patch->env[4].time < 1.47)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0);
+ tmp_patch->env[4].set &= 0xFE;
+ } else {
+ tmp_patch->env[4].set |= 0x01;
+ }
+ }
+ }
+ chr_ptr = strstr(&line_buffer[line_ptr], "env_time5=");
+ if (chr_ptr != NULL) {
+ if (!isdigit(chr_ptr[10])) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0);
+ } else {
+ tmp_patch->env[5].time = atof(&chr_ptr[10]);
+ if ((tmp_patch->env[5].time > 45000.0) || (tmp_patch->env[5].time < 1.47)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0);
+ tmp_patch->env[5].set &= 0xFE;
+ } else {
+ tmp_patch->env[5].set |= 0x01;
+ }
+ }
+ }
+ chr_ptr = strstr(&line_buffer[line_ptr], "env_level0=");
+ if (chr_ptr != NULL) {
+ if (!isdigit(chr_ptr[11])) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0);
+ } else {
+ tmp_patch->env[0].level = atof(&chr_ptr[10]);
+ if ((tmp_patch->env[0].level > 1.0) || (tmp_patch->env[0].level < 0.0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0);
+ tmp_patch->env[0].set &= 0xFD;
+ } else {
+ tmp_patch->env[0].set |= 0x02;
+ }
+ }
+ }
+
+ chr_ptr = strstr(&line_buffer[line_ptr], "env_level1=");
+ if (chr_ptr != NULL) {
+ if (!isdigit(chr_ptr[11])) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0);
+ } else {
+ tmp_patch->env[1].level = atof(&chr_ptr[10]);
+ if ((tmp_patch->env[1].level > 1.0) || (tmp_patch->env[1].level < 0.0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0);
+ tmp_patch->env[1].set &= 0xFD;
+ } else {
+ tmp_patch->env[1].set |= 0x02;
+ }
+ }
+ }
+ chr_ptr = strstr(&line_buffer[line_ptr], "env_level2=");
+ if (chr_ptr != NULL) {
+ if (!isdigit(chr_ptr[11])) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0);
+ } else {
+ tmp_patch->env[2].level = atof(&chr_ptr[10]);
+ if ((tmp_patch->env[2].level > 1.0) || (tmp_patch->env[2].level < 0.0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0);
+ tmp_patch->env[2].set &= 0xFD;
+ } else {
+ tmp_patch->env[2].set |= 0x02;
+ }
+ }
+ }
+ chr_ptr = strstr(&line_buffer[line_ptr], "env_level3=");
+ if (chr_ptr != NULL) {
+ if (!isdigit(chr_ptr[11])) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0);
+ } else {
+ tmp_patch->env[3].level = atof(&chr_ptr[10]);
+ if ((tmp_patch->env[3].level > 1.0) || (tmp_patch->env[3].level < 0.0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0);
+ tmp_patch->env[3].set &= 0xFD;
+ } else {
+ tmp_patch->env[3].set |= 0x02;
+ }
+ }
+ }
+ chr_ptr = strstr(&line_buffer[line_ptr], "env_level4=");
+ if (chr_ptr != NULL) {
+ if (!isdigit(chr_ptr[11])) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0);
+ } else {
+ tmp_patch->env[4].level = atof(&chr_ptr[10]);
+ if ((tmp_patch->env[4].level > 1.0) || (tmp_patch->env[4].level < 0.0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0);
+ tmp_patch->env[4].set &= 0xFD;
+ } else {
+ tmp_patch->env[4].set |= 0x02;
+ }
+ }
+ }
+ chr_ptr = strstr(&line_buffer[line_ptr], "env_level5=");
+ if (chr_ptr != NULL) {
+ if (!isdigit(chr_ptr[11])) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0);
+ } else {
+ tmp_patch->env[5].level = atof(&chr_ptr[10]);
+ if ((tmp_patch->env[5].level > 1.0) || (tmp_patch->env[5].level < 0.0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0);
+ tmp_patch->env[5].set &= 0xFD;
+ } else {
+ tmp_patch->env[5].set |= 0x02;
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ if (line_buffer != NULL)
+ free (line_buffer);
+
+ free (config_buffer);
+
+ if (config_dir != NULL)
+ free (config_dir);
+
+ return 0;
+}
+
+/*
+ * sample data conversion functions
+ * convert data to signed shorts
+ */
+
+/* 8bit signed */
+int
+convert_8s (unsigned char *data, struct _sample *gus_sample ) {
+ unsigned char *read_data = data;
+ unsigned char *read_end = data + gus_sample->data_length;
+ signed short int *write_data = NULL;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ gus_sample->data = calloc((gus_sample->data_length + 1), sizeof(signed short int));
+ if (__builtin_expect((gus_sample->data != NULL),1)) {
+ write_data = gus_sample->data;
+ do {
+ *write_data = (*read_data++) << 8;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data != read_end);
+ return 0;
+ }
+
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
+ return -1;
+}
+
+/* 8bit signed ping pong */
+int
+convert_8sp (unsigned char *data, struct _sample *gus_sample ) {
+ unsigned long int loop_length = gus_sample->loop_end - gus_sample->loop_start;
+ unsigned long int dloop_length = loop_length * 2;
+ unsigned long int new_length = gus_sample->data_length + dloop_length;
+ unsigned char *read_data = data;
+ unsigned char *read_end = data + gus_sample->loop_start;
+ signed short int *write_data = NULL;
+ signed short int *write_data_a = NULL;
+ signed short int *write_data_b = NULL;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ gus_sample->data = calloc((new_length + 1), sizeof(signed short int));
+ if (__builtin_expect((gus_sample->data != NULL),1)) {
+ write_data = gus_sample->data;
+ do {
+ *write_data = (*read_data++) << 8;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data != read_end);
+
+ *write_data = (*read_data++ << 8);
+ write_data_a = write_data + dloop_length;
+ *write_data_a-- = *write_data;
+ write_data++;
+ write_data_b = write_data + dloop_length;
+ read_end = data + gus_sample->loop_end;
+ do {
+ *write_data = (*read_data++) << 8;
+ *write_data_a-- = *write_data;
+ *write_data_b++ = *write_data;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data != read_end);
+
+ *write_data = (*read_data++ << 8);
+ *write_data_b++ = *write_data;
+ read_end = data + gus_sample->data_length;
+ if (__builtin_expect((read_data != read_end),1)) {
+ do {
+ *write_data_b = (*read_data++) << 8;
+ if (*write_data_b > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data_b;
+ } else if (*write_data_b < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data_b;
+ }
+ write_data_b++;
+ } while (read_data != read_end);
+ }
+ gus_sample->loop_start += loop_length;
+ gus_sample->loop_end += dloop_length;
+ gus_sample->data_length = new_length;
+ gus_sample->modes ^= SAMPLE_PINGPONG;
+ return 0;
+ }
+
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
+ return -1;
+}
+
+/* 8bit signed reverse */
+int
+convert_8sr (unsigned char *data, struct _sample *gus_sample ) {
+ unsigned char *read_data = data;
+ unsigned char *read_end = data + gus_sample->data_length;
+ signed short int *write_data = NULL;
+ unsigned long int tmp_loop = 0;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ gus_sample->data = calloc((gus_sample->data_length + 1), sizeof(signed short int));
+ if (__builtin_expect((gus_sample->data != NULL),1)) {
+ write_data = gus_sample->data + gus_sample->data_length - 1;
+ do {
+ *write_data = (*read_data++) << 8;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data--;
+ } while (read_data != read_end);
+ tmp_loop = gus_sample->loop_end;
+ gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start;
+ gus_sample->loop_start = gus_sample->data_length - tmp_loop;
+ gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) | ((gus_sample->loop_fraction & 0xf0) >> 4);
+ gus_sample->modes ^= SAMPLE_REVERSE;
+ return 0;
+ }
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
+ return -1;
+}
+
+
+/* 8bit signed reverse ping pong */
+int
+convert_8srp (unsigned char *data, struct _sample *gus_sample ) {
+ unsigned long int loop_length = gus_sample->loop_end - gus_sample->loop_start;
+ unsigned long int dloop_length = loop_length * 2;
+ unsigned long int new_length = gus_sample->data_length + dloop_length;
+ unsigned char *read_data = data + gus_sample->data_length - 1;
+ unsigned char *read_end = data + gus_sample->loop_end;
+ signed short int *write_data = NULL;
+ signed short int *write_data_a = NULL;
+ signed short int *write_data_b = NULL;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ gus_sample->data = calloc((new_length + 1), sizeof(signed short int));
+ if (__builtin_expect((gus_sample->data != NULL),1)) {
+ write_data = gus_sample->data;
+ do {
+ *write_data = (*read_data--) << 8;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data != read_end);
+
+ *write_data = (*read_data-- << 8);
+ write_data_a = write_data + dloop_length;
+ *write_data_a-- = *write_data;
+ write_data++;
+ write_data_b = write_data + dloop_length;
+ read_end = data + gus_sample->loop_start;
+ do {
+ *write_data = (*read_data--) << 8;
+ *write_data_a-- = *write_data;
+ *write_data_b++ = *write_data;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data != read_end);
+
+ *write_data = (*read_data-- << 8);
+ *write_data_b++ = *write_data;
+ read_end = data - 1;
+ do {
+ *write_data_b = (*read_data--) << 8;
+ if (*write_data_b > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data_b;
+ } else if (*write_data_b < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data_b;
+ }
+ write_data_b++;
+ } while (read_data != read_end);
+ gus_sample->loop_start += loop_length;
+ gus_sample->loop_end += dloop_length;
+ gus_sample->data_length = new_length;
+ gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE;
+ return 0;
+ }
+
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
+ return -1;
+}
+
+/* 8bit unsigned */
+int
+convert_8u (unsigned char *data, struct _sample *gus_sample ) {
+ unsigned char *read_data = data;
+ unsigned char *read_end = data + gus_sample->data_length;
+ signed short int *write_data = NULL;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ gus_sample->data = calloc((gus_sample->data_length + 1), sizeof(signed short int));
+ if (__builtin_expect((gus_sample->data != NULL),1)) {
+ write_data = gus_sample->data;
+ do {
+ *write_data = ((*read_data++) ^ 0x80) << 8;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data != read_end);
+ gus_sample->modes ^= SAMPLE_UNSIGNED;
+ return 0;
+ }
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
+ return -1;
+}
+
+/* 8bit unsigned ping pong */
+int
+convert_8up (unsigned char *data, struct _sample *gus_sample ) {
+ unsigned long int loop_length = gus_sample->loop_end - gus_sample->loop_start;
+ unsigned long int dloop_length = loop_length * 2;
+ unsigned long int new_length = gus_sample->data_length + dloop_length;
+ unsigned char *read_data = data;
+ unsigned char *read_end = data + gus_sample->loop_start;
+ signed short int *write_data = NULL;
+ signed short int *write_data_a = NULL;
+ signed short int *write_data_b = NULL;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ gus_sample->data = calloc((new_length + 1), sizeof(signed short int));
+ if (__builtin_expect((gus_sample->data != NULL),1)) {
+ write_data = gus_sample->data;
+ do {
+ *write_data = ((*read_data++) ^ 0x80) << 8;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data != read_end);
+
+ *write_data = ((*read_data++) ^ 0x80) << 8;
+ write_data_a = write_data + dloop_length;
+ *write_data_a-- = *write_data;
+ write_data++;
+ write_data_b = write_data + dloop_length;
+ read_end = data + gus_sample->loop_end;
+ do {
+ *write_data = ((*read_data++) ^ 0x80) << 8;
+ *write_data_a-- = *write_data;
+ *write_data_b++ = *write_data;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data != read_end);
+
+ *write_data = ((*read_data++) ^ 0x80) << 8;
+ *write_data_b++ = *write_data;
+ read_end = data + gus_sample->data_length;
+ if (__builtin_expect((read_data != read_end),1)) {
+ do {
+ *write_data_b = ((*read_data++) ^ 0x80) << 8;
+ if (*write_data_b > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data_b;
+ } else if (*write_data_b < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data_b;
+ }
+ write_data_b++;
+ } while (read_data != read_end);
+ }
+ gus_sample->loop_start += loop_length;
+ gus_sample->loop_end += dloop_length;
+ gus_sample->data_length = new_length;
+ gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_UNSIGNED;
+ return 0;
+ }
+
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
+ return -1;
+}
+
+/* 8bit unsigned reverse */
+int
+convert_8ur (unsigned char *data, struct _sample *gus_sample ) {
+ unsigned char *read_data = data;
+ unsigned char *read_end = data + gus_sample->data_length;
+ signed short int *write_data = NULL;
+ unsigned long int tmp_loop = 0;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ gus_sample->data = calloc((gus_sample->data_length + 1), sizeof(signed short int));
+ if (__builtin_expect((gus_sample->data != NULL),1)) {
+ write_data = gus_sample->data + gus_sample->data_length - 1;
+ do {
+ *write_data = ((*read_data++) ^ 0x80) << 8;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data--;
+ } while (read_data != read_end);
+ tmp_loop = gus_sample->loop_end;
+ gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start;
+ gus_sample->loop_start = gus_sample->data_length - tmp_loop;
+ gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) | ((gus_sample->loop_fraction & 0xf0) >> 4);
+ gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED;
+ return 0;
+ }
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
+ return -1;
+}
+
+/* 8bit unsigned reverse ping pong */
+int
+convert_8urp (unsigned char *data, struct _sample *gus_sample ) {
+ unsigned long int loop_length = gus_sample->loop_end - gus_sample->loop_start;
+ unsigned long int dloop_length = loop_length * 2;
+ unsigned long int new_length = gus_sample->data_length + dloop_length;
+ unsigned char *read_data = data + gus_sample->data_length - 1;
+ unsigned char *read_end = data + gus_sample->loop_end;
+ signed short int *write_data = NULL;
+ signed short int *write_data_a = NULL;
+ signed short int *write_data_b = NULL;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ gus_sample->data = calloc((new_length + 1), sizeof(signed short int));
+ if (__builtin_expect((gus_sample->data != NULL),1)) {
+ write_data = gus_sample->data;
+ do {
+ *write_data = ((*read_data--) ^ 0x80) << 8;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data != read_end);
+
+ *write_data = ((*read_data--) ^ 0x80) << 8;
+ write_data_a = write_data + dloop_length;
+ *write_data_a-- = *write_data;
+ write_data++;
+ write_data_b = write_data + dloop_length;
+ read_end = data + gus_sample->loop_start;
+ do {
+ *write_data = ((*read_data--) ^ 0x80) << 8;
+ *write_data_a-- = *write_data;
+ *write_data_b++ = *write_data;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data != read_end);
+
+ *write_data = ((*read_data--) ^ 0x80) << 8;
+ *write_data_b++ = *write_data;
+ read_end = data - 1;
+ do {
+ *write_data_b = ((*read_data--) ^ 0x80) << 8;
+ if (*write_data_b > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data_b;
+ } else if (*write_data_b < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data_b;
+ }
+ write_data_b++;
+ } while (read_data != read_end);
+ gus_sample->loop_start += loop_length;
+ gus_sample->loop_end += dloop_length;
+ gus_sample->data_length = new_length;
+ gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED;
+ return 0;
+ }
+
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
+ return -1;
+}
+
+/* 16bit signed */
+int
+convert_16s (unsigned char *data, struct _sample *gus_sample ) {
+ unsigned char *read_data = data;
+ unsigned char *read_end = data + gus_sample->data_length;
+ signed short int *write_data = NULL;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ gus_sample->data = calloc(((gus_sample->data_length >> 1) + 1),sizeof(signed short int));
+ if (__builtin_expect((gus_sample->data != NULL),1)) {
+ write_data = gus_sample->data;
+ do {
+ *write_data = *read_data++;
+ *write_data |= (*read_data++) << 8;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data < read_end);
+
+ gus_sample->loop_start >>= 1;
+ gus_sample->loop_end >>= 1;
+ gus_sample->data_length >>= 1;
+ return 0;
+ }
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
+ return -1;
+}
+
+/* 16bit signed ping pong */
+int
+convert_16sp (unsigned char *data, struct _sample *gus_sample ) {
+ unsigned long int loop_length = gus_sample->loop_end - gus_sample->loop_start;
+ unsigned long int dloop_length = loop_length * 2;
+ unsigned long int new_length = gus_sample->data_length + dloop_length;
+ unsigned char *read_data = data;
+ unsigned char *read_end = data + gus_sample->loop_start;
+ signed short int *write_data = NULL;
+ signed short int *write_data_a = NULL;
+ signed short int *write_data_b = NULL;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ gus_sample->data = calloc(((new_length >> 1) + 1), sizeof(signed short int));
+ if (__builtin_expect((gus_sample->data != NULL),1)) {
+ write_data = gus_sample->data;
+ do {
+ *write_data = (*read_data++);
+ *write_data |= (*read_data++) << 8;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data < read_end);
+
+ *write_data = (*read_data++);
+ *write_data |= (*read_data++) << 8;
+ write_data_a = write_data + (dloop_length >> 1);
+ *write_data_a-- = *write_data;
+ write_data++;
+ write_data_b = write_data + (dloop_length >> 1);
+ read_end = data + gus_sample->loop_end;
+ do {
+ *write_data = (*read_data++);
+ *write_data |= (*read_data++) << 8;
+ *write_data_a-- = *write_data;
+ *write_data_b++ = *write_data;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data < read_end);
+
+ *write_data = *(read_data++);
+ *write_data |= (*read_data++) << 8;
+ *write_data_b++ = *write_data;
+ read_end = data + gus_sample->data_length;
+ if (__builtin_expect((read_data != read_end),1)) {
+ do {
+ *write_data_b = *(read_data++);
+ *write_data_b |= (*read_data++) << 8;
+ if (*write_data_b > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data_b;
+ } else if (*write_data_b < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data_b;
+ }
+ write_data_b++;
+ } while (read_data < read_end);
+ }
+ gus_sample->loop_start += loop_length;
+ gus_sample->loop_end += dloop_length;
+ gus_sample->data_length = new_length;
+ gus_sample->modes ^= SAMPLE_PINGPONG;
+ gus_sample->loop_start >>= 1;
+ gus_sample->loop_end >>= 1;
+ gus_sample->data_length >>= 1;
+ return 0;
+ }
+
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
+ return -1;
+}
+
+/* 16bit signed reverse */
+int
+convert_16sr (unsigned char *data, struct _sample *gus_sample ) {
+ unsigned char *read_data = data;
+ unsigned char *read_end = data + gus_sample->data_length;
+ signed short int *write_data = NULL;
+ unsigned long int tmp_loop = 0;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ gus_sample->data = calloc(((gus_sample->data_length >> 1) + 1), sizeof(signed short int));
+ if (__builtin_expect((gus_sample->data != NULL),1)) {
+ write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1;
+ do {
+ *write_data = *read_data++;
+ *write_data |= (*read_data++) << 8;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data--;
+ } while (read_data < read_end);
+ tmp_loop = gus_sample->loop_end;
+ gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start;
+ gus_sample->loop_start = gus_sample->data_length - tmp_loop;
+ gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) | ((gus_sample->loop_fraction & 0xf0) >> 4);
+ gus_sample->loop_start >>= 1;
+ gus_sample->loop_end >>= 1;
+ gus_sample->data_length >>= 1;
+ gus_sample->modes ^= SAMPLE_REVERSE;
+ return 0;
+ }
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
+ return -1;
+}
+
+
+/* 16bit signed reverse ping pong */
+int
+convert_16srp (unsigned char *data, struct _sample *gus_sample ) {
+ unsigned long int loop_length = gus_sample->loop_end - gus_sample->loop_start;
+ unsigned long int dloop_length = loop_length * 2;
+ unsigned long int new_length = gus_sample->data_length + dloop_length;
+ unsigned char *read_data = data + gus_sample->data_length - 1;
+ unsigned char *read_end = data + gus_sample->loop_end;
+ signed short int *write_data = NULL;
+ signed short int *write_data_a = NULL;
+ signed short int *write_data_b = NULL;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ gus_sample->data = calloc(((new_length >> 1) + 1), sizeof(signed short int));
+ if (__builtin_expect((gus_sample->data != NULL),1)) {
+ write_data = gus_sample->data;
+ do {
+
+ *write_data = (*read_data--) << 8;
+ *write_data |= *read_data--;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data < read_end);
+
+ *write_data = (*read_data-- << 8);
+ *write_data |= *read_data--;
+ write_data_a = write_data + (dloop_length >> 1);
+ *write_data_a-- = *write_data;
+ write_data++;
+ write_data_b = write_data + (dloop_length >> 1);
+ read_end = data + gus_sample->loop_start;
+ do {
+ *write_data = (*read_data--) << 8;
+ *write_data |= *read_data--;
+ *write_data_a-- = *write_data;
+ *write_data_b++ = *write_data;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data < read_end);
+
+ *write_data = ((*read_data--) << 8);
+ *write_data |= *read_data--;
+ *write_data_b++ = *write_data;
+ read_end = data - 1;
+ do {
+ *write_data_b = (*read_data--) << 8;
+ *write_data_b |= *read_data--;
+ if (*write_data_b > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data_b;
+ } else if (*write_data_b < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data_b;
+ }
+ write_data_b++;
+ } while (read_data < read_end);
+ gus_sample->loop_start += loop_length;
+ gus_sample->loop_end += dloop_length;
+ gus_sample->data_length = new_length;
+ gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE;
+ return 0;
+ }
+
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
+ return -1;
+}
+
+/* 16bit unsigned */
+int
+convert_16u (unsigned char *data, struct _sample *gus_sample ) {
+ unsigned char *read_data = data;
+ unsigned char *read_end = data + gus_sample->data_length;
+ signed short int *write_data = NULL;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ gus_sample->data = calloc(((gus_sample->data_length >> 1) + 1),sizeof(signed short int));
+ if (__builtin_expect((gus_sample->data != NULL),1)) {
+ write_data = gus_sample->data;
+ do {
+ *write_data = *read_data++;
+ *write_data |= ((*read_data++) ^ 0x80) << 8;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data < read_end);
+ gus_sample->loop_start >>= 1;
+ gus_sample->loop_end >>= 1;
+ gus_sample->data_length >>= 1;
+ gus_sample->modes ^= SAMPLE_UNSIGNED;
+ return 0;
+ }
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
+ return -1;
+}
+
+/* 16bit unsigned ping pong */
+int
+convert_16up (unsigned char *data, struct _sample *gus_sample ) {
+ unsigned long int loop_length = gus_sample->loop_end - gus_sample->loop_start;
+ unsigned long int dloop_length = loop_length * 2;
+ unsigned long int new_length = gus_sample->data_length + dloop_length;
+ unsigned char *read_data = data;
+ unsigned char *read_end = data + gus_sample->loop_start;
+ signed short int *write_data = NULL;
+ signed short int *write_data_a = NULL;
+ signed short int *write_data_b = NULL;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ gus_sample->data = calloc(((new_length >> 1) + 1), sizeof(signed short int));
+ if (__builtin_expect((gus_sample->data != NULL),1)) {
+ write_data = gus_sample->data;
+ do {
+ *write_data = (*read_data++);
+ *write_data |= ((*read_data++) ^ 0x80) << 8;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data < read_end);
+
+ *write_data = (*read_data++);
+ *write_data |= ((*read_data++) ^ 0x80) << 8;
+ write_data_a = write_data + (dloop_length >> 1);
+ *write_data_a-- = *write_data;
+ write_data++;
+ write_data_b = write_data + (dloop_length >> 1);
+ read_end = data + gus_sample->loop_end;
+ do {
+ *write_data = (*read_data++);
+ *write_data |= ((*read_data++) ^ 0x80) << 8;
+ *write_data_a-- = *write_data;
+ *write_data_b++ = *write_data;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data < read_end);
+
+ *write_data = (*read_data++);
+ *write_data |= ((*read_data++) ^ 0x80) << 8;
+ *write_data_b++ = *write_data;
+ read_end = data + gus_sample->data_length;
+ if (__builtin_expect((read_data != read_end),1)) {
+ do {
+ *write_data_b = (*read_data++);
+ *write_data_b |= ((*read_data++) ^ 0x80) << 8;
+ if (*write_data_b > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data_b;
+ } else if (*write_data_b < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data_b;
+ }
+ write_data_b++;
+ } while (read_data < read_end);
+ }
+ gus_sample->loop_start += loop_length;
+ gus_sample->loop_end += dloop_length;
+ gus_sample->data_length = new_length;
+ gus_sample->modes ^= SAMPLE_PINGPONG;
+ gus_sample->loop_start >>= 1;
+ gus_sample->loop_end >>= 1;
+ gus_sample->data_length >>= 1;
+ return 0;
+ }
+
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
+ return -1;
+}
+
+/* 16bit unsigned reverse */
+int
+convert_16ur (unsigned char *data, struct _sample *gus_sample ) {
+ unsigned char *read_data = data;
+ unsigned char *read_end = data + gus_sample->data_length;
+ signed short int *write_data = NULL;
+ unsigned long int tmp_loop = 0;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ gus_sample->data = calloc(((gus_sample->data_length >> 1) + 1), sizeof(signed short int));
+ if (__builtin_expect((gus_sample->data != NULL),1)) {
+ write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1;
+ do {
+ *write_data = *read_data++;
+ *write_data |= ((*read_data++) ^ 0x80) << 8;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data--;
+ } while (read_data < read_end);
+ tmp_loop = gus_sample->loop_end;
+ gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start;
+ gus_sample->loop_start = gus_sample->data_length - tmp_loop;
+ gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) | ((gus_sample->loop_fraction & 0xf0) >> 4);
+ gus_sample->loop_start >>= 1;
+ gus_sample->loop_end >>= 1;
+ gus_sample->data_length >>= 1;
+ gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED;
+ return 0;
+ }
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
+ return -1;
+}
+
+/* 16bit unsigned reverse ping pong */
+int
+convert_16urp (unsigned char *data, struct _sample *gus_sample ) {
+ unsigned long int loop_length = gus_sample->loop_end - gus_sample->loop_start;
+ unsigned long int dloop_length = loop_length * 2;
+ unsigned long int new_length = gus_sample->data_length + dloop_length;
+ unsigned char *read_data = data + gus_sample->data_length - 1;
+ unsigned char *read_end = data + gus_sample->loop_end;
+ signed short int *write_data = NULL;
+ signed short int *write_data_a = NULL;
+ signed short int *write_data_b = NULL;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ gus_sample->data = calloc(((new_length >> 1) + 1), sizeof(signed short int));
+ if (__builtin_expect((gus_sample->data != NULL),1)) {
+ write_data = gus_sample->data;
+ do {
+ *write_data = ((*read_data--) ^ 0x80) << 8;
+ *write_data |= *read_data--;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data < read_end);
+
+ *write_data = ((*read_data--) ^ 0x80) << 8;
+ *write_data |= *read_data--;
+ write_data_a = write_data + (dloop_length >> 1);
+ *write_data_a-- = *write_data;
+ write_data++;
+ write_data_b = write_data + (dloop_length >> 1);
+ read_end = data + gus_sample->loop_start;
+ do {
+ *write_data = ((*read_data--) ^ 0x80) << 8;
+ *write_data |= *read_data--;
+ *write_data_a-- = *write_data;
+ *write_data_b++ = *write_data;
+ if (*write_data > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data;
+ } else if (*write_data < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data;
+ }
+ write_data++;
+ } while (read_data < read_end);
+
+ *write_data = ((*read_data--) ^ 0x80) << 8;
+ *write_data |= *read_data--;
+ *write_data_b++ = *write_data;
+ read_end = data - 1;
+ do {
+ *write_data_b = ((*read_data--) ^ 0x80) << 8;
+ *write_data_b |= *read_data--;
+ if (*write_data_b > gus_sample->max_peek) {
+ gus_sample->max_peek = *write_data_b;
+ } else if (*write_data_b < gus_sample->min_peek) {
+ gus_sample->min_peek = *write_data_b;
+ }
+ write_data_b++;
+ } while (read_data < read_end);
+ gus_sample->loop_start += loop_length;
+ gus_sample->loop_end += dloop_length;
+ gus_sample->data_length = new_length;
+ gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED;
+ return 0;
+ }
+
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
+ return -1;
+}
+
+
+/* sample loading */
+
+int
+load_sample (struct _patch *sample_patch) {
+ unsigned char *gus_patch;
+ unsigned long int gus_size;
+ unsigned long int gus_ptr;
+ unsigned char no_of_samples;
+ struct _sample *gus_sample = NULL;
+ unsigned long int i = 0;
+
+ int (*do_convert[])(unsigned char *data, struct _sample *gus_sample ) = {
+ convert_8s,
+ convert_16s,
+ convert_8u,
+ convert_16u,
+ convert_8sp,
+ convert_16sp,
+ convert_8up,
+ convert_16up,
+ convert_8sr,
+ convert_16sr,
+ convert_8ur,
+ convert_16ur,
+ convert_8srp,
+ convert_16srp,
+ convert_8urp,
+ convert_16urp
+ };
+ unsigned long int tmp_loop;
+
+ SAMPLE_CONVERT_DEBUG(__FUNCTION__);
+ SAMPLE_CONVERT_DEBUG(sample_patch->filename);
+ sample_patch->loaded = 1;
+ if ((gus_patch = WM_BufferFile(sample_patch->filename,&gus_size)) == NULL) {
+ return -1;
+ }
+ if (gus_size < 239) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, sample_patch->filename, 0);
+ free(gus_patch);
+ return -1;
+ }
+ if (memcmp(gus_patch, "GF1PATCH110\0ID#000002", 22) && memcmp(gus_patch, "GF1PATCH100\0ID#000002", 22)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID,"(unsupported format)", 0);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, sample_patch->filename, 0);
+ free(gus_patch);
+ return -1;
+ }
+ if (gus_patch[82] > 1) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID,"(unsupported format)", 0);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, sample_patch->filename, 0);
+ free(gus_patch);
+ return -1;
+ }
+ if (gus_patch[151] > 1) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID,"(unsupported format)", 0);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, sample_patch->filename, 0);
+ free(gus_patch);
+ return -1;
+ }
+
+ no_of_samples = gus_patch[198];
+ sample_patch->first_sample = NULL;
+ gus_ptr = 239;
+ while (no_of_samples) {
+ unsigned long int tmp_cnt;
+ if (sample_patch->first_sample == NULL) {
+ sample_patch->first_sample = malloc(sizeof(struct _sample));
+ gus_sample = sample_patch->first_sample;
+ } else {
+ gus_sample->next = malloc(sizeof(struct _sample));
+ gus_sample = gus_sample->next;
+ }
+ if (gus_sample == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0);
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, sample_patch->filename, 0);
+ return -1;
+ }
+
+ gus_sample->next = NULL;
+ gus_sample->loop_fraction = gus_patch[gus_ptr+7];
+ gus_sample->data_length = (gus_patch[gus_ptr+11] << 24) | (gus_patch[gus_ptr+10] << 16) | (gus_patch[gus_ptr+9] << 8) | gus_patch[gus_ptr+8];
+ gus_sample->loop_start = (gus_patch[gus_ptr+15] << 24) | (gus_patch[gus_ptr+14] << 16) | (gus_patch[gus_ptr+13] << 8) | gus_patch[gus_ptr+12];
+ gus_sample->loop_end = (gus_patch[gus_ptr+19] << 24) | (gus_patch[gus_ptr+18] << 16) | (gus_patch[gus_ptr+17] << 8) | gus_patch[gus_ptr+16];
+ gus_sample->rate = (gus_patch[gus_ptr+21] << 8) | gus_patch[gus_ptr+20];
+ gus_sample->freq_low = ((gus_patch[gus_ptr+25] << 24) | (gus_patch[gus_ptr+24] << 16) | (gus_patch[gus_ptr+23] << 8) | gus_patch[gus_ptr+22]);
+ gus_sample->freq_high = ((gus_patch[gus_ptr+29] << 24) | (gus_patch[gus_ptr+28] << 16) | (gus_patch[gus_ptr+27] << 8) | gus_patch[gus_ptr+26]);
+ gus_sample->freq_root = ((gus_patch[gus_ptr+33] << 24) | (gus_patch[gus_ptr+32] << 16) | (gus_patch[gus_ptr+31] << 8) | gus_patch[gus_ptr+30]);
+
+ /* This is done this way instead of ((freq * 1024) / rate) to avoid 32bit overflow. */
+ /* Result is 0.001% inacurate */
+ gus_sample->inc_div = ((gus_sample->freq_root * 512) / gus_sample->rate) * 2;
+
+#if 0
+ printf("\rTremolo Sweep: %i, Rate: %i, Depth %i\n",
+ gus_patch[gus_ptr+49], gus_patch[gus_ptr+50], gus_patch[gus_ptr+51]);
+ printf("\rVibrato Sweep: %i, Rate: %i, Depth %i\n",
+ gus_patch[gus_ptr+52], gus_patch[gus_ptr+53], gus_patch[gus_ptr+54]);
+#endif
+ gus_sample->modes = gus_patch[gus_ptr+55] & 0x7F;
+ if ((sample_patch->remove & SAMPLE_SUSTAIN) && (gus_sample->modes & SAMPLE_SUSTAIN)) {
+ gus_sample->modes ^= SAMPLE_SUSTAIN;
+ }
+ if (sample_patch->patchid & 0x0080) {
+ if (!(sample_patch->keep & SAMPLE_LOOP)) {
+ gus_sample->modes &= 0xFB;
+ }
+ if (!(sample_patch->keep & SAMPLE_ENVELOPE)) {
+ gus_sample->modes &= 0xBF;
+ }
+ }
+
+
+ if (gus_sample->loop_start > gus_sample->loop_end) {
+ tmp_loop = gus_sample->loop_end;
+ gus_sample->loop_end = gus_sample->loop_start;
+ gus_sample->loop_start = tmp_loop;
+ gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) | ((gus_sample->loop_fraction & 0xf0) >> 4);
+ }
+ for (i = 0; i < 6; i++) {
+ if (gus_sample->modes & SAMPLE_ENVELOPE) {
+ unsigned char env_rate = gus_patch[gus_ptr+37+i];
+ if (sample_patch->env[i].set & 0x02) {
+ gus_sample->env_target[i] = 16448 * (unsigned long int)(255.0 * sample_patch->env[i].level);
+ } else {
+ gus_sample->env_target[i] = 16448 * gus_patch[gus_ptr+43+i];
+ }
+
+ if (sample_patch->env[i].set & 0x01) {
+ gus_sample->env_rate[i] = (unsigned long int)(4194303.0 / ((float)WM_SampleRate * (sample_patch->env[i].time / 1000.0)));
+ } else {
+ gus_sample->env_rate[i] = (unsigned long int)(4194303.0 / ((float)WM_SampleRate * env_time_table[env_rate]));
+ if (gus_sample->env_rate[i] == 0) {
+ fprintf(stderr,"\rWarning: libWildMidi %s found invalid envelope(%lu) rate setting in %s. Using %f instead.\n",__FUNCTION__, i, sample_patch->filename, env_time_table[63]);
+ gus_sample->env_rate[i] = (unsigned long int)(4194303.0 / ((float)WM_SampleRate * env_time_table[63]));
+ }
+ }
+ } else {
+ gus_sample->env_target[i] = 4194303;
+ gus_sample->env_rate[i] = (unsigned long int)(4194303.0 / ((float)WM_SampleRate * env_time_table[63]));
+ }
+ }
+
+ gus_sample->env_target[6] = 0;
+ gus_sample->env_rate[6] = (unsigned long int)(4194303.0 / ((float)WM_SampleRate * env_time_table[63]));
+
+ if ((sample_patch->patchid == 47) && (!(gus_sample->modes & SAMPLE_LOOP))) {
+ for (i = 3; i < 6; i++) {
+ gus_sample->env_target[i] = gus_sample->env_target[2];
+ gus_sample->env_rate[i] = gus_sample->env_rate[2];
+ }
+ }
+
+ gus_ptr += 96;
+ tmp_cnt = gus_sample->data_length;
+
+/* convert to float */
+ gus_sample->min_peek = 0;
+ gus_sample->max_peek = 0;
+
+ if (do_convert[(((gus_sample->modes & 0x18) >> 1)| (gus_sample->modes & 0x03))](&gus_patch[gus_ptr], gus_sample) == -1) {
+ return -1;
+
+ };
+
+ if (gus_sample->max_peek > (-gus_sample->min_peek)) {
+ gus_sample->peek_adjust = 33553408 / gus_sample->max_peek;
+ } else {
+ gus_sample->peek_adjust = 33554432 / (-gus_sample->min_peek);
+ }
+ gus_sample->peek_adjust = (gus_sample->peek_adjust * sample_patch->amp) >> 10;
+
+ gus_ptr += tmp_cnt;
+ gus_sample->loop_start = (gus_sample->loop_start << 10) | (((gus_sample->loop_fraction & 0x0f) << 10) / 16);
+ gus_sample->loop_end = (gus_sample->loop_end << 10) | (((gus_sample->loop_fraction & 0xf0) << 6) / 16);
+ gus_sample->loop_size = gus_sample->loop_end - gus_sample->loop_start;
+ gus_sample->data_length = gus_sample->data_length << 10;
+ no_of_samples--;
+ }
+ free(gus_patch);
+ return 0;
+}
+
+
+struct _patch *
+get_patch_data(struct _mdi *mdi, unsigned short patchid) {
+ struct _patch *search_patch;
+
+ WM_Lock(&patch_lock);
+
+ search_patch = patch[patchid & 0x007F];
+
+ if (search_patch == NULL) {
+ WM_Unlock(&patch_lock);
+ return NULL;
+ }
+
+ while(search_patch != NULL) {
+ if (search_patch->patchid == patchid) {
+ WM_Unlock(&patch_lock);
+ return search_patch;
+ }
+ search_patch = search_patch->next;
+ }
+ if ((patchid >> 8) != 0) {
+ WM_Unlock(&patch_lock);
+ return (get_patch_data(mdi, patchid & 0x00FF));
+ }
+ WM_Unlock(&patch_lock);
+ return NULL;
+}
+
+void
+load_patch (struct _mdi *mdi, unsigned short patchid) {
+ int i;
+ struct _patch *tmp_patch = NULL;
+
+ for (i = 0; i < mdi->patch_count; i++) {
+ if (mdi->patches[i]->patchid == patchid) {
+ return;
+ }
+ }
+
+ tmp_patch = get_patch_data(mdi, patchid);
+ if (tmp_patch == NULL) {
+ return;
+ }
+
+ WM_Lock(&patch_lock);
+ if (!tmp_patch->loaded) {
+ if (load_sample(tmp_patch) == -1) {
+ WM_Unlock(&patch_lock);
+ return;
+ }
+ }
+
+ if (tmp_patch->first_sample == NULL) {
+ WM_Unlock(&patch_lock);
+ return;
+ }
+
+ mdi->patch_count++;
+ mdi->patches = realloc(mdi->patches, (sizeof(struct _patch) * mdi->patch_count));
+ mdi->patches[mdi->patch_count -1] = tmp_patch;
+ tmp_patch->inuse_count++;
+ WM_Unlock(&patch_lock);
+ return;
+}
+
+
+struct _sample *
+get_sample_data (struct _patch *sample_patch, unsigned long int freq) {
+ struct _sample *last_sample = NULL;
+ struct _sample *return_sample = NULL;
+
+ WM_Lock(&patch_lock);
+ if (sample_patch == NULL) {
+ WM_Unlock(&patch_lock);
+ return NULL;
+ }
+ if (sample_patch->first_sample == NULL) {
+ WM_Unlock(&patch_lock);
+ return NULL;
+ }
+ if (freq == 0) {
+ WM_Unlock(&patch_lock);
+ return sample_patch->first_sample;
+ }
+
+ return_sample = sample_patch->first_sample;
+ last_sample = sample_patch->first_sample;
+ while (last_sample != NULL) {
+ if (freq > last_sample->freq_low) {
+ if (freq < last_sample->freq_high) {
+ WM_Unlock(&patch_lock);
+ return last_sample;
+ } else {
+ return_sample = last_sample;
+ }
+ }
+ last_sample = last_sample->next;
+ }
+ WM_Unlock(&patch_lock);
+ return return_sample;
+}
+
+unsigned long int
+read_var_length (struct _mdi *mdi, struct _miditrack *track) {
+ unsigned long int var_data = 0;
+ if (mdi->data[track->ptr] > 0x7f) {
+ while(mdi->data[track->ptr] > 0x7f) {
+ var_data |= mdi->data[track->ptr] & 0x7f;
+ track->ptr++;
+ if (track->ptr > mdi->size) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);
+ return 0xFFFFFFFF;
+ }
+ var_data = (var_data << 7);
+ }
+ }
+ var_data |= mdi->data[track->ptr] & 0x7f;
+ track->ptr++;
+
+ if (track->ptr > mdi->size) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);
+ return 0xFFFFFFFF;
+ }
+
+ return var_data;
+}
+
+void
+do_note_off (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) {
+ struct _note *nte;
+
+ MIDI_EVENT_DEBUG(__FUNCTION__,ch);
+
+ nte = &mdi->note_table[0][ch][mdi->data[ptr]];
+ if (!nte->active)
+ nte = &mdi->note_table[1][ch][mdi->data[ptr]];
+ if (!nte->active) {
+ return;
+ }
+
+ if ((ch == 9) && (!(nte->modes & SAMPLE_LOOP))) {
+ return;
+ }
+
+ if (nte->hold) {
+ nte->hold |= HOLD_OFF;
+ } else {
+#if 0
+ if (nte->modes & SAMPLE_SUSTAIN) {
+ nte->env = 3;
+ if (nte->env_level > nte->sample->env_target[3]) {
+ nte->env_inc = -nte->sample->env_rate[3];
+ } else {
+ nte->env_inc = nte->sample->env_rate[3];
+ }
+ } else
+#endif
+ {
+ if (nte->env < 4) {
+ nte->env = 4;
+ if (nte->env_level > nte->sample->env_target[4]) {
+ nte->env_inc = -nte->sample->env_rate[4];
+ } else {
+ nte->env_inc = nte->sample->env_rate[4];
+ }
+ }
+ }
+ }
+ return;
+}
+
+inline unsigned long int
+get_inc (struct _mdi *mdi, struct _note *nte) {
+ int ch = nte->noteid >> 8;
+ signed long int note_f;
+ unsigned long int freq;
+
+ if (__builtin_expect((nte->patch->note != 0),0)) {
+ note_f = nte->patch->note * 100;
+ } else {
+ note_f = (nte->noteid & 0x7f) * 100;
+ }
+ note_f += mdi->channel[ch].pitch_adjust;
+ if (__builtin_expect((note_f < 0), 0)) {
+ note_f = 0;
+ } else if (__builtin_expect((note_f > 12700), 0)) {
+ note_f = 12700;
+ }
+ freq = freq_table[(note_f % 1200)] >> (10 - (note_f / 1200));
+ return (((freq / ((WM_SampleRate * 100) / 1024)) * 1024 / nte->sample->inc_div));
+}
+
+inline signed short int
+get_volume(struct _mdi *mdi, unsigned char ch, struct _note *nte) {
+ signed long int volume;
+
+ if (mdi->info.mixer_options & WM_MO_LINEAR_VOLUME) {
+ volume = (lin_volume[mdi->channel[ch].volume] *
+ lin_volume[mdi->channel[ch].expression] *
+ lin_volume[nte->velocity]) / 1048576;
+ } else {
+ volume = (sqr_volume[mdi->channel[ch].volume] *
+ sqr_volume[mdi->channel[ch].expression] *
+ sqr_volume[nte->velocity]) / 1048576;
+ }
+ return ((volume * nte->sample->peek_adjust) >> 10);
+}
+
+void
+do_note_on (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) {
+ struct _note *nte;
+ unsigned long int freq = 0;
+ struct _patch *patch;
+ struct _sample *sample;
+
+ if (mdi->data[ptr+1] == 0x00) {
+ do_note_off(ch, mdi, ptr);
+ return;
+ }
+
+ MIDI_EVENT_DEBUG(__FUNCTION__,ch);
+
+ if (ch != 9) {
+ patch = mdi->channel[ch].patch;
+ if (patch == NULL) {
+ return;
+ }
+ freq = freq_table[(mdi->data[ptr] % 12) * 100] >> (10 -(mdi->data[ptr] / 12));
+ } else {
+ patch = get_patch_data(mdi, ((mdi->channel[ch].bank << 8) | mdi->data[ptr] | 0x80));
+ if (patch == NULL) {
+ return;
+ }
+ if (patch->note) {
+ freq = freq_table[(patch->note % 12) * 100] >> (10 -(patch->note / 12));
+ } else {
+ freq = freq_table[(mdi->data[ptr] % 12) * 100] >> (10 -(mdi->data[ptr] / 12));
+ }
+ }
+
+ sample = get_sample_data(patch, (freq / 100));
+
+ if (sample == NULL) {
+ return;
+ }
+
+ nte = &mdi->note_table[0][ch][mdi->data[ptr]];
+
+ if (nte->active) {
+ if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env < 3) && (!(nte->hold & HOLD_OFF)))
+ return;
+ nte->next = &mdi->note_table[1][ch][mdi->data[ptr]];
+ nte->env = 6;
+ nte->env_inc = -nte->sample->env_rate[6];
+ nte = &mdi->note_table[1][ch][mdi->data[ptr]];
+ } else {
+ if (mdi->note_table[1][ch][mdi->data[ptr]].active) {
+ if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env < 3) && (!(nte->hold & HOLD_OFF)))
+ return;
+ mdi->note_table[1][ch][mdi->data[ptr]].next = nte;
+ mdi->note_table[1][ch][mdi->data[ptr]].env = 6;
+ mdi->note_table[1][ch][mdi->data[ptr]].env_inc = -mdi->note_table[1][ch][mdi->data[ptr]].sample->env_rate[6];
+ } else {
+ *mdi->last_note = nte;
+ mdi->last_note++;
+ nte->active = 1;
+ }
+ }
+ nte->noteid = (ch << 8) | mdi->data[ptr];
+ nte->patch = patch;
+ nte->sample = sample;
+ nte->sample_pos = 0;
+ nte->sample_inc = get_inc (mdi, nte);
+ nte->velocity = mdi->data[ptr+1];
+ nte->env = 0;
+ nte->env_inc = nte->sample->env_rate[0];
+ nte->env_level = 0;
+ nte->modes = sample->modes;
+ nte->hold = mdi->channel[ch].hold;
+ nte->vol_lvl = get_volume(mdi, ch, nte);
+ nte->next = NULL;
+}
+
+void
+do_aftertouch (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) {
+ struct _note *nte;
+
+ MIDI_EVENT_DEBUG(__FUNCTION__,ch);
+
+ nte = &mdi->note_table[0][ch][mdi->data[ptr]];
+ if (!nte->active) {
+ nte = &mdi->note_table[1][ch][mdi->data[ptr]];
+ if (!nte->active) {
+ return;
+ }
+ }
+
+ nte->velocity = mdi->data[ptr+1];
+ nte->vol_lvl = get_volume(mdi, ch, nte);
+
+ if (nte->next) {
+ nte->next->velocity = mdi->data[ptr+1];
+ nte->next->vol_lvl = get_volume(mdi, ch, nte->next);
+ }
+}
+
+
+void
+do_pan_adjust (struct _mdi *mdi, unsigned char ch) {
+ signed short int pan_adjust = mdi->channel[ch].balance + mdi->channel[ch].pan;
+ signed long int left, right;
+
+ if (pan_adjust > 63) {
+ pan_adjust = 63;
+ } else if (pan_adjust < -64) {
+ pan_adjust = -64;
+ }
+
+ pan_adjust += 64;
+
+ if (mdi->info.mixer_options & WM_MO_LINEAR_VOLUME) {
+ left = (lin_volume[127 - pan_adjust] * WM_MasterVolume * mdi->amp) / 1048576;
+ right= (lin_volume[pan_adjust] * WM_MasterVolume * mdi->amp) / 1048576;
+ } else {
+ left = (pan_volume[127 - pan_adjust] * WM_MasterVolume * mdi->amp) / 1048576;
+ right = (pan_volume[pan_adjust] * WM_MasterVolume * mdi->amp) / 1048576;
+ }
+
+ mdi->channel[ch].left_adjust = left;
+ mdi->channel[ch].right_adjust = right;
+}
+
+void
+do_control (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) {
+ struct _note **note_data = mdi->note;
+
+ switch (mdi->data[ptr]) {
+ case 0: // Bank Select
+ mdi->channel[ch].bank = mdi->data[ptr+1];
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ break;
+ case 6: // Data Entry Course
+ if (mdi->channel[ch].reg_data == 0x0000) { // Pitch Bend Range
+ int data_tmp;
+ data_tmp = mdi->channel[ch].pitch_range % 100;
+ mdi->channel[ch].pitch_range = mdi->data[ptr+1] * 100 + data_tmp;
+ }
+ break;
+ case 7: // Channel Volume
+ mdi->channel[ch].volume = mdi->data[ptr+1];
+
+ if (note_data != mdi->last_note) {
+ do {
+ if (((*note_data)->noteid >> 8) == ch) {
+ (*note_data)->vol_lvl = get_volume(mdi, ch, *note_data);
+ if ((*note_data)->next)
+ (*note_data)->next->vol_lvl = get_volume(mdi, ch, (*note_data)->next);
+ }
+ note_data++;
+ } while (note_data != mdi->last_note);
+ }
+ break;
+ case 8: // Channel Balance
+ mdi->channel[ch].balance = mdi->data[ptr+1] - 64;
+ do_pan_adjust(mdi, ch);
+ break;
+ case 9:
+ break;
+ case 10: // Channel Pan
+ mdi->channel[ch].pan = mdi->data[ptr+1] - 64;
+ do_pan_adjust(mdi, ch);
+ break;
+ case 11: // Channel Expression
+ mdi->channel[ch].expression = mdi->data[ptr+1];
+
+ if (note_data != mdi->last_note) {
+ do {
+ if (((*note_data)->noteid >> 8) == ch) {
+ (*note_data)->vol_lvl = get_volume(mdi, ch, *note_data);
+ if ((*note_data)->next)
+ (*note_data)->next->vol_lvl = get_volume(mdi, ch, (*note_data)->next);
+ }
+ note_data++;
+ } while (note_data != mdi->last_note);
+ }
+ break;
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ break;
+ case 38: // Data Entry Fine
+ if (mdi->channel[ch].reg_data == 0x0000) { // Pitch Bend Range
+ int data_tmp;
+ data_tmp = mdi->channel[ch].pitch_range / 100;
+ mdi->channel[ch].pitch_range = (data_tmp * 100) + mdi->data[ptr+1];
+ }
+ break;
+ case 39:
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ printf("\rController %i used\n",mdi->data[ptr]);
+ break;
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ case 55:
+ case 56:
+ case 57:
+ case 58:
+ case 59:
+ case 60:
+ case 61:
+ case 62:
+ case 63:
+ break;
+ case 64: // Channel Hold
+ if (mdi->data[ptr+1] > 63) {
+ mdi->channel[ch].hold = 1;
+ } else {
+ mdi->channel[ch].hold = 0;
+ if (note_data != mdi->last_note) {
+ do {
+ if (((*note_data)->noteid >> 8) == ch) {
+ if ((*note_data)->hold & HOLD_OFF) {
+ if ((*note_data)->modes & SAMPLE_ENVELOPE) {
+#if 0
+ if ((*note_data)->modes & SAMPLE_SUSTAIN) {
+ (*note_data)->env = 3;
+ if ((*note_data)->env_level > (*note_data)->sample->env_target[3]) {
+ (*note_data)->env_inc = -(*note_data)->sample->env_rate[3];
+ } else {
+ (*note_data)->env_inc = (*note_data)->sample->env_rate[3];
+ }
+ } else
+#endif
+ {
+ if ((*note_data)->env < 4) {
+ (*note_data)->env = 4;
+ if ((*note_data)->env_level > (*note_data)->sample->env_target[4]) {
+ (*note_data)->env_inc = -(*note_data)->sample->env_rate[4];
+ } else {
+ (*note_data)->env_inc = (*note_data)->sample->env_rate[4];
+ }
+ }
+ }
+ }
+ }
+ (*note_data)->hold = 0x00;
+ }
+ note_data++;
+ } while (note_data != mdi->last_note);
+ }
+ }
+ break;
+ case 65:
+ case 66:
+ case 67:
+ case 68:
+ case 69:
+ case 70:
+ case 71:
+ case 72:
+ case 73:
+ case 74:
+ case 75:
+ case 76:
+ case 77:
+ case 78:
+ case 79:
+ case 80:
+ case 81:
+ case 82:
+ case 83:
+ case 84:
+ case 85:
+ case 86:
+ case 87:
+ case 88:
+ case 89:
+ case 90:
+ case 91:
+ case 92:
+ case 93:
+ case 94:
+ case 95:
+ case 96:
+ case 97:
+ case 98:
+ case 99:
+ break;
+ case 100: // Registered Param Fine
+ mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0xFF00) | mdi->data[ptr+1];
+ break;
+ case 101: // Registered Param Course
+ mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0xFF) | (mdi->data[ptr+1] << 8);
+ break;
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 106:
+ case 107:
+ case 108:
+ case 109:
+ case 110:
+ case 111:
+ case 112:
+ case 113:
+ case 114:
+ case 115:
+ case 116:
+ case 117:
+ case 118:
+ case 119:
+ break;
+ case 120: // All Channel Sound Off
+ if (note_data != mdi->last_note) {
+ do {
+ if (((*note_data)->noteid >> 8) == ch) {
+ (*note_data)->active = 0;
+ if ((*note_data)->next) {
+ (*note_data)->next = NULL;
+ }
+ }
+ note_data++;
+ } while (note_data != mdi->last_note);
+ mdi->last_note = mdi->note;
+ }
+ break;
+ case 121: // All Controlers Off
+ mdi->channel[ch].expression = 127;
+ mdi->channel[ch].pressure = 0;
+ mdi->channel[ch].volume = 100;
+ mdi->channel[ch].pan = 0;
+ mdi->channel[ch].balance = 0;
+ mdi->channel[ch].reg_data = 0xffff;
+ mdi->channel[ch].pitch_range = 200;
+ mdi->channel[ch].pitch = 0;
+ mdi->channel[ch].pitch_adjust = 0;
+ mdi->channel[ch].hold = 0;
+ do_pan_adjust(mdi, ch);
+
+ if (note_data != mdi->last_note) {
+ do {
+ if (((*note_data)->noteid >> 8 ) == ch) {
+ (*note_data)->sample_inc = get_inc (mdi, *note_data);
+ (*note_data)->velocity = 0;
+ (*note_data)->vol_lvl = get_volume(mdi, ch, *note_data);
+ (*note_data)->hold = 0;
+
+ if ((*note_data)->next) {
+ (*note_data)->next->velocity = mdi->data[ptr];
+ (*note_data)->next->vol_lvl = get_volume(mdi, ch, (*note_data)->next);
+ }
+
+ }
+ note_data++;
+ } while (note_data != mdi->last_note);
+ }
+ break;
+ case 122:
+ break;
+ case 123: // All Channel Notes Off
+ if (ch == 9)
+ return;
+ if (note_data != mdi->last_note) {
+ do {
+ if (((*note_data)->noteid >> 8) == ch) {
+ if (!(*note_data)->hold){
+ if ((*note_data)->modes & SAMPLE_ENVELOPE) {
+ if ((*note_data)->env < 5) {
+ if ((*note_data)->env_level > (*note_data)->sample->env_target[5]) {
+ (*note_data)->env_inc = -(*note_data)->sample->env_rate[5];
+ } else {
+ (*note_data)->env_inc = (*note_data)->sample->env_rate[5];
+ }
+ (*note_data)->env = 5;
+ }
+ }
+ } else {
+ (*note_data)->hold |= HOLD_OFF;
+ }
+ }
+ note_data++;
+ } while (note_data != mdi->last_note);
+ }
+ break;
+ case 124:
+ case 125:
+ case 126:
+ case 127:
+ break;
+ }
+}
+
+void
+do_patch (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) {
+ MIDI_EVENT_DEBUG(__FUNCTION__,ch);
+ if (ch != 9) {
+ mdi->channel[ch].patch = get_patch_data(mdi, ((mdi->channel[ch].bank << 8) | mdi->data[ptr]));
+ } else {
+ mdi->channel[ch].bank = mdi->data[ptr];
+ }
+}
+
+void
+do_channel_pressure (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) {
+ struct _note **note_data = mdi->note;
+ MIDI_EVENT_DEBUG(__FUNCTION__,ch);
+
+ if (note_data != mdi->last_note) {
+ do {
+ if (((*note_data)->noteid >> 8 ) == ch) {
+ (*note_data)->velocity = mdi->data[ptr];
+ (*note_data)->vol_lvl = get_volume(mdi, ch, *note_data);
+
+ if ((*note_data)->next) {
+ (*note_data)->next->velocity = mdi->data[ptr];
+ (*note_data)->next->vol_lvl = get_volume(mdi, ch, (*note_data)->next);
+ }
+ }
+ note_data++;
+ } while (note_data != mdi->last_note);
+ }
+}
+
+void
+do_pitch (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) {
+ struct _note **note_data = mdi->note;
+
+ MIDI_EVENT_DEBUG(__FUNCTION__,ch);
+ mdi->channel[ch].pitch = ((mdi->data[ptr+1] << 7) | mdi->data[ptr]) - 0x2000;
+
+ if (mdi->channel[ch].pitch < 0) {
+ mdi->channel[ch].pitch_adjust = mdi->channel[ch].pitch_range * mdi->channel[ch].pitch / 8192;
+ } else {
+ mdi->channel[ch].pitch_adjust = mdi->channel[ch].pitch_range * mdi->channel[ch].pitch / 8191;
+ }
+
+ if (note_data != mdi->last_note) {
+ do {
+ if (((*note_data)->noteid >> 8 ) == ch) {
+ (*note_data)->sample_inc = get_inc (mdi, *note_data);
+ }
+ note_data++;
+ } while (note_data != mdi->last_note);
+ }
+}
+
+void
+do_message (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) {
+ unsigned char event_type = 0xF0 | ch;
+ static unsigned long int tempo = 500000;
+
+ MIDI_EVENT_DEBUG(__FUNCTION__,ch);
+ if (event_type == 0xFF) {
+ if ((mdi->data[ptr] == 0x51) && (mdi->data[ptr+1] == 3)) {
+ tempo = (mdi->data[ptr+2] << 16) | (mdi->data[ptr+3] << 8) | mdi->data[ptr+4];
+ if (tempo == 0)
+ mdi->samples_per_delta = (WM_SampleRate << 10) / (2 * mdi->divisions);
+ else
+ mdi->samples_per_delta = (WM_SampleRate << 10) / ((1000000 * mdi->divisions) / tempo);
+ }
+ }
+}
+
+
+void
+do_null (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) {
+ MIDI_EVENT_DEBUG(__FUNCTION__,ch);
+};
+
+
+void
+WM_ResetToStart(midi * handle) {
+ struct _mdi *mdi = (struct _mdi *)handle;
+ int i;
+
+ mdi->index_count = 0;
+ mdi->samples_per_delta = (WM_SampleRate << 10) / (2 * mdi->divisions);
+ mdi->samples_to_mix = 0;
+ mdi->info.current_sample= 0;
+
+ for (i=0; i<16; i++) {
+ mdi->channel[i].bank = 0;
+ mdi->channel[i].patch = NULL;
+ mdi->channel[i].hold = 0;
+ mdi->channel[i].volume = 100;
+ mdi->channel[i].pressure = 127;
+ mdi->channel[i].expression = 127;
+ mdi->channel[i].balance = 0;
+ mdi->channel[i].pan = 0;
+ mdi->channel[i].left_adjust = 1.0;
+ mdi->channel[i].right_adjust = 1.0;
+ mdi->channel[i].pitch = 0;
+ mdi->channel[i].pitch_range = 200;
+ mdi->channel[i].reg_data = 0xFFFF;
+ }
+}
+
+void
+WM_RecalcSamples (midi * handle) {
+ struct _mdi *mdi = (struct _mdi *)handle;
+ struct _note **note_data = mdi->note;
+ unsigned long int total_samples = 0;
+ unsigned long int count_a;
+ unsigned long int count_b;
+ unsigned long int env_level;
+
+ if (note_data != mdi->last_note) {
+ do {
+ env_level = (*note_data)->env_level;
+ count_a = 0;
+ count_b = 0;
+ if ((*note_data)->env < 4) {
+ if (env_level > (*note_data)->sample->env_target[3]) {
+ count_a += (env_level - (*note_data)->sample->env_target[3] + (*note_data)->sample->env_rate[3] - 1) / (*note_data)->sample->env_rate[3];
+ } else {
+ count_a += ((*note_data)->sample->env_target[3] - env_level + (*note_data)->sample->env_rate[3] - 1) / (*note_data)->sample->env_rate[3];
+ }
+ env_level = (*note_data)->sample->env_target[3];
+ }
+ if ((*note_data)->env < 5) {
+ if (env_level > (*note_data)->sample->env_target[4]) {
+ count_a += (env_level - (*note_data)->sample->env_target[4] + (*note_data)->sample->env_rate[4] - 1) / (*note_data)->sample->env_rate[4];
+ } else {
+ count_a += ((*note_data)->sample->env_target[4] - env_level + (*note_data)->sample->env_rate[4] - 1) / (*note_data)->sample->env_rate[4];
+ }
+ env_level = (*note_data)->sample->env_target[4];
+ }
+ if ((*note_data)->env < 6) {
+ if (env_level > (*note_data)->sample->env_target[5]) {
+ count_a += (env_level - (*note_data)->sample->env_target[5] + (*note_data)->sample->env_rate[5] - 1) / (*note_data)->sample->env_rate[5];
+ } else {
+ count_a += ((*note_data)->sample->env_target[5] - env_level + (*note_data)->sample->env_rate[5] - 1) / (*note_data)->sample->env_rate[5];
+ }
+ env_level = (*note_data)->sample->env_target[5];
+ }
+ if ((*note_data)->env == 6) {
+ count_a = (env_level + (*note_data)->sample->env_rate[6] - 1) / (*note_data)->sample->env_rate[6];
+ env_level = (*note_data)->sample->env_target[6];
+ }
+ if (env_level != 0) {
+ if ((*note_data)->modes & SAMPLE_LOOP) {
+ unsigned long int smpl_pos = (*note_data)->sample_pos + (count_a * (*note_data)->sample_inc);
+ if (smpl_pos > ((*note_data)->sample->loop_end << 10)) {
+ while (smpl_pos > ((*note_data)->sample->loop_end << 10)) {
+ smpl_pos -= ((*note_data)->sample->loop_end - (*note_data)->sample->loop_start) << 10;
+ }
+ count_a += (((*note_data)->sample->data_length << 10) - smpl_pos + (*note_data)->sample_inc - 1) / (*note_data)->sample_inc;
+ }
+ } else {
+ count_b = (((*note_data)->sample->data_length << 10) - (*note_data)->sample_pos + (*note_data)->sample_inc - 1) / (*note_data)->sample_inc;
+ }
+ if (count_b != 0) {
+ if (count_b < count_a) {
+ if (total_samples < count_b)
+ total_samples = count_b;
+ } else {
+ if (total_samples < count_a)
+ total_samples = count_a;
+ }
+ } else {
+ if (total_samples < count_a)
+ total_samples = count_a;
+ }
+ } else {
+ if (!((*note_data)->modes & SAMPLE_LOOP)) {
+ count_b = (((*note_data)->sample->data_length << 10) - (*note_data)->sample_pos) / (*note_data)->sample_inc;
+ if (count_b < count_a) {
+ if (total_samples < count_b)
+ total_samples = count_b;
+ } else {
+ if (total_samples < count_a)
+ total_samples = count_a;
+ }
+ } else {
+ if (total_samples < count_a)
+ total_samples = count_a;
+ }
+ }
+ note_data++;
+ } while (note_data != mdi->last_note);
+ }
+ mdi->info.approx_total_samples += total_samples;
+ mdi->recalc_samples = 0;
+}
+
+void
+do_amp_setup_note_off (unsigned char ch, struct _mdi *mdi, struct _miditrack *track) {
+ MIDI_EVENT_DEBUG(__FUNCTION__,ch);
+
+ mdi->lin_cur_vol -= (lin_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] *
+ lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->ch_vol[ch]]) / 1048576;
+ mdi->log_cur_vol -= (sqr_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] *
+ log_volume[mdi->ch_exp[ch]] * log_volume[mdi->ch_vol[ch]]) / 1048576;
+
+ mdi->note_vel[ch][mdi->data[track->ptr]] = 0;
+
+ track->running_event = 0x80 | ch;
+ track->ptr += 2;
+ return;
+}
+
+void
+do_amp_setup_note_on (unsigned char ch, struct _mdi *mdi, struct _miditrack *track) {
+ MIDI_EVENT_DEBUG(__FUNCTION__,ch);
+ if (mdi->data[track->ptr+1] == 0x00) {
+ do_amp_setup_note_off(ch, mdi, track);
+ track->running_event = 0x90 | ch;
+ return;
+ }
+
+ if (mdi->note_vel[ch][mdi->data[track->ptr]]) {
+ mdi->lin_cur_vol -= (lin_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] *
+ lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->ch_vol[ch]]) / 1048576;
+ mdi->log_cur_vol -= (sqr_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] *
+ log_volume[mdi->ch_exp[ch]] * log_volume[mdi->ch_vol[ch]]) / 1048576;
+ }
+
+ mdi->note_vel[ch][mdi->data[track->ptr]] = mdi->data[track->ptr+1];
+
+ mdi->lin_cur_vol += (lin_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] *
+ lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->ch_vol[ch]]) / 1048576;
+ mdi->log_cur_vol += (sqr_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] *
+ log_volume[mdi->ch_exp[ch]] * log_volume[mdi->ch_vol[ch]]) / 1048576;
+
+ if (mdi->lin_cur_vol > mdi->lin_max_vol) {
+ mdi->lin_max_vol = mdi->lin_cur_vol;
+ }
+ if (mdi->log_cur_vol > mdi->log_max_vol) {
+ mdi->log_max_vol = mdi->log_cur_vol;
+ }
+ if (ch == 9) {
+ load_patch(mdi, ((mdi->channel[ch].bank << 8) | (mdi->data[track->ptr] | 0x80)));
+ }
+
+ track->running_event = 0x90 | ch;
+ track->ptr += 2;
+ return;
+}
+
+void
+do_amp_setup_aftertouch (unsigned char ch, struct _mdi *mdi, struct _miditrack *track) {
+ unsigned char pres = mdi->data[track->ptr+1];
+
+ MIDI_EVENT_DEBUG(__FUNCTION__,ch);
+
+ if (pres == 0)
+ pres = 1;
+
+ if (mdi->note_vel[ch][mdi->data[track->ptr]] != 0) {
+ mdi->lin_cur_vol -= (lin_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] *
+ lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->ch_vol[ch]]) / 1048576;
+ mdi->log_cur_vol -= (sqr_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] *
+ log_volume[mdi->ch_exp[ch]] * log_volume[mdi->ch_vol[ch]]) / 1048576;
+
+ mdi->note_vel[ch][mdi->data[track->ptr]] = pres;
+
+ mdi->lin_cur_vol += (lin_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] *
+ lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->ch_vol[ch]]) / 1048576;
+ mdi->log_cur_vol += (sqr_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] *
+ log_volume[mdi->ch_exp[ch]] * log_volume[mdi->ch_vol[ch]]) / 1048576;
+
+ if (mdi->lin_cur_vol > mdi->lin_max_vol) {
+ mdi->lin_max_vol = mdi->lin_cur_vol;
+ }
+ if (mdi->log_cur_vol > mdi->log_max_vol) {
+ mdi->log_max_vol = mdi->log_cur_vol;
+ }
+ }
+ track->running_event = 0xA0 | ch;
+ track->ptr += 2;
+ return;
+}
+
+
+void
+do_amp_setup_control (unsigned char ch, struct _mdi *mdi, struct _miditrack *track) {
+ int i;
+
+ MIDI_EVENT_DEBUG(__FUNCTION__,ch);
+ if (mdi->data[track->ptr] == 0x00) {
+ mdi->channel[ch].bank = mdi->data[track->ptr + 1];
+ } else if (mdi->data[track->ptr] == 0x07) {
+ for (i=0; i < 128; i++) {
+ if (mdi->note_vel[ch][i] == 0)
+ continue;
+ mdi->lin_cur_vol -= (lin_volume[mdi->note_vel[ch][i]] *
+ lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->ch_vol[ch]]) / 1048576;
+ mdi->log_cur_vol -= (sqr_volume[mdi->note_vel[ch][i]] *
+ log_volume[mdi->ch_exp[ch]] * log_volume[mdi->ch_vol[ch]]) / 1048576;
+
+ mdi->lin_cur_vol += (lin_volume[mdi->note_vel[ch][i]] *
+ lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->data[track->ptr + 1]]) / 1048576;
+ mdi->log_cur_vol += (sqr_volume[mdi->note_vel[ch][i]] *
+ log_volume[mdi->ch_exp[ch]] * log_volume[mdi->data[track->ptr + 1]]) / 1048576;
+
+ }
+ mdi->ch_vol[ch] = mdi->data[track->ptr + 1];
+ if (mdi->lin_cur_vol > mdi->lin_max_vol) {
+ mdi->lin_max_vol = mdi->lin_cur_vol;
+ }
+ if (mdi->log_cur_vol > mdi->log_max_vol) {
+ mdi->log_max_vol = mdi->log_cur_vol;
+ }
+ } else if (mdi->data[track->ptr] == 0x0B) {
+ for (i=0; i < 128; i++) {
+ if (mdi->note_vel[ch][i] == 0)
+ continue;
+ mdi->lin_cur_vol -= (lin_volume[mdi->note_vel[ch][i]] *
+ lin_volume[mdi->ch_vol[ch]] * lin_volume[mdi->ch_exp[ch]]) / 1048576;
+ mdi->log_cur_vol -= (sqr_volume[mdi->note_vel[ch][i]] *
+ log_volume[mdi->ch_vol[ch]] * log_volume[mdi->ch_exp[ch]]) / 1048576;
+
+ mdi->lin_cur_vol += (lin_volume[mdi->note_vel[ch][i]] *
+ lin_volume[mdi->ch_vol[ch]] * lin_volume[mdi->data[track->ptr + 1]]) / 1048576;
+ mdi->log_cur_vol += (sqr_volume[mdi->note_vel[ch][i]] *
+ log_volume[mdi->ch_vol[ch]] * log_volume[mdi->data[track->ptr + 1]]) / 1048576;
+
+ }
+ mdi->ch_exp[ch] = mdi->data[track->ptr + 1];
+ if (mdi->lin_cur_vol > mdi->lin_max_vol) {
+ mdi->lin_max_vol = mdi->lin_cur_vol;
+ }
+ if (mdi->log_cur_vol > mdi->log_max_vol) {
+ mdi->log_max_vol = mdi->log_cur_vol;
+ }
+ }
+
+ track->running_event = 0xB0 | ch;
+ track->ptr += 2;
+ return;
+}
+
+void
+do_amp_setup_patch (unsigned char ch, struct _mdi *mdi, struct _miditrack *track) {
+ if (ch == 9) {
+ mdi->channel[ch].bank = mdi->data[track->ptr];
+ } else {
+ load_patch(mdi, ((mdi->channel[ch].bank << 8) | mdi->data[track->ptr]));
+ }
+ track->running_event = 0xC0 | ch;
+ track->ptr++;
+ return;
+}
+
+void
+do_amp_setup_channel_pressure (unsigned char ch, struct _mdi *mdi, struct _miditrack *track) {
+ int i;
+ unsigned char pres = mdi->data[track->ptr];
+
+ MIDI_EVENT_DEBUG(__FUNCTION__,ch);
+
+ if (pres == 0)
+ pres = 1;
+
+ for (i=0; i < 128; i++) {
+ if (mdi->note_vel[ch][i] == 0)
+ continue;
+ mdi->lin_cur_vol -= (lin_volume[mdi->note_vel[ch][i]] *
+ lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->ch_vol[ch]]) / 1048576;
+ mdi->log_cur_vol -= (sqr_volume[mdi->note_vel[ch][i]] *
+ log_volume[mdi->ch_exp[ch]] * log_volume[mdi->ch_vol[ch]]) / 1048576;
+
+ mdi->note_vel[ch][i] = pres;
+
+ mdi->lin_cur_vol += (lin_volume[mdi->note_vel[ch][i]] *
+ lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->ch_vol[ch]]) / 1048576;
+ mdi->log_cur_vol += (sqr_volume[mdi->note_vel[ch][i]] *
+ log_volume[mdi->ch_exp[ch]] * log_volume[mdi->ch_vol[ch]]) / 1048576;
+
+ }
+ if (mdi->lin_cur_vol > mdi->lin_max_vol) {
+ mdi->lin_max_vol = mdi->lin_cur_vol;
+ }
+ if (mdi->log_cur_vol > mdi->log_max_vol) {
+ mdi->log_max_vol = mdi->log_cur_vol;
+ }
+ track->running_event = 0xD0 | ch;
+ track->ptr++;
+ return;
+}
+
+void
+do_amp_setup_pitch (unsigned char ch, struct _mdi *mdi, struct _miditrack *track) {
+ MIDI_EVENT_DEBUG(__FUNCTION__,ch);
+ track->running_event = 0xE0 | ch;
+ track->ptr += 2;
+ return;
+}
+
+void
+do_amp_setup_message (unsigned char ch, struct _mdi *mdi, struct _miditrack *track) {
+ unsigned long int event_length;
+ unsigned char event_type = 0xF0 | ch;
+ unsigned char event_data = mdi->data[track->ptr];
+ static unsigned long int tempo = 500000;
+
+ MIDI_EVENT_DEBUG(__FUNCTION__,ch);
+ if (event_type == 0xF0) {
+ track->running_event = 0x00;
+ do {
+ track->ptr++;
+ } while ( mdi->data[track->ptr] != 0xF7);
+ track->ptr++;
+ } else {
+ track->ptr += 1;
+ event_length = read_var_length(mdi, track);
+ if (event_length == 0xFFFFFFFF) {
+ track->delta = 0xFFFFFFFF;
+ return;
+ }
+ if (event_type == 0xFF) {
+ if ((event_data == 0x2F) && (event_length == 0)) { // Track End
+ track->EOT = 1;
+ return;
+ } else if ((event_data == 0x51) && (event_length == 3)) { // Tempo Change
+ tempo = (mdi->data[track->ptr] << 16) | (mdi->data[track->ptr+1] << 8) | mdi->data[track->ptr+2];
+ if (tempo == 0)
+ mdi->samples_per_delta = (WM_SampleRate << 10) / (2 * mdi->divisions);
+ else
+ mdi->samples_per_delta = (WM_SampleRate << 10) / ((1000000 * mdi->divisions) / tempo);
+ }
+ }
+ track->ptr += event_length;
+ }
+}
+
+
+struct _mdi *
+WM_ParseNewMidi(unsigned char *mididata, unsigned long int midisize ) {
+ int i;
+ unsigned char eot[] = { 0xff, 0x2f, 0x00};
+ unsigned long int index_count = 0;
+ unsigned long int temp_delta = 0xffffff00;
+ struct _mdi *mdi = NULL;
+ void (*do_event[])(unsigned char ch, struct _mdi *midifile, struct _miditrack *track) = {
+ *do_amp_setup_note_off,
+ *do_amp_setup_note_on,
+ *do_amp_setup_aftertouch,
+ *do_amp_setup_control,
+ *do_amp_setup_patch,
+ *do_amp_setup_channel_pressure,
+ *do_amp_setup_pitch,
+ *do_amp_setup_message
+ };
+ unsigned long int midiofs = 0;
+ unsigned long int midi_track_counter = 0;
+ unsigned long int last_delta;
+ unsigned long int minus_delta = 0;
+ unsigned char current_event = 0;
+ unsigned short int no_tracks;
+ unsigned long int EOT_count = 0;
+ struct _miditrack *tmp_trackdata;
+ struct _hndl *tmp_handle = NULL;
+
+ mdi = malloc(sizeof(struct _mdi));
+ if (mdi == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM," to parse midi data", errno);
+ free (mididata);
+ return NULL;
+ }
+
+ // Initialize data
+ memset(mdi, 0, sizeof(struct _mdi));
+ mdi->lock = 0;
+ mdi->data = mididata;
+ mdi->size = midisize;
+ mdi->info.mixer_options = WM_MixerOptions;
+
+ mdi->index = malloc(((midisize / 2) + 1)* sizeof(struct _mdi_index));
+ if (mdi->index == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM," to parse midi data", errno);
+ free(mdi);
+ return NULL;
+ }
+
+ load_patch(mdi, 0x0000);
+
+ for (i=0; i<16; i++) {
+ mdi->channel[i].volume = 100;
+ mdi->channel[i].pressure = 127;
+ mdi->channel[i].expression = 127;
+ mdi->channel[i].pitch_range = 200;
+ mdi->channel[i].reg_data = 0xFFFF;
+ mdi->ch_vol[i] = 100;
+ mdi->ch_exp[i] = 127;
+ mdi->channel[i].patch = get_patch_data(mdi, 0x0000);
+ }
+
+ midiofs = 0;
+ if (strncmp(mididata,"RIFF",4) == 0)
+ midiofs = 20;
+
+ if (strncmp(&mididata[midiofs],"MThd",4) != 0) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID,"(not a midi file)", 0);
+ free(mdi->index);
+ free(mdi);
+ return NULL;
+ }
+
+ if ((midiofs + 25) > midisize) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT,"(too short)", 0);
+ free(mdi->index);
+ free(mdi);
+ return NULL;
+ }
+
+ midiofs += 9;
+ if (mididata[midiofs] > 1) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, NULL, 0);
+ free(mdi->index);
+ free(mdi);
+ return NULL;
+ }
+ midiofs++;
+
+ no_tracks = mididata[midiofs] << 8 | mididata[midiofs+1];
+ midiofs += 2;
+
+ mdi->divisions = mididata[midiofs] << 8 | mididata[midiofs+1];
+ mdi->samples_per_delta = (WM_SampleRate << 10) / (2 * mdi->divisions);
+ midiofs += 2;
+
+ tmp_trackdata = calloc(no_tracks, sizeof(struct _miditrack));
+
+ if (first_handle == NULL) {
+ first_handle = malloc(sizeof(struct _hndl));
+ if (first_handle == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM," to parse midi data", errno);
+ free(mdi->data);
+ free(mdi);
+ return NULL;
+ }
+ first_handle->handle = (void *)mdi;
+ first_handle->prev = NULL;
+ first_handle->next = NULL;
+ } else {
+ tmp_handle = first_handle;
+ if (tmp_handle->next != NULL) {
+ while (tmp_handle->next != NULL)
+ tmp_handle = tmp_handle->next;
+ }
+ tmp_handle->next = malloc(sizeof(struct _hndl));
+ if (tmp_handle->next == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM," to parse midi data", errno);
+ free(tmp_trackdata);
+ free(mdi->data);
+ free(mdi);
+ return NULL;
+ }
+ tmp_handle->next->prev = tmp_handle;
+ tmp_handle = tmp_handle->next;
+ tmp_handle->next = NULL;
+ tmp_handle->handle = (void *)mdi;
+ }
+
+
+ // grab track offsets;
+
+ midi_track_counter = 0;
+ while (midi_track_counter != no_tracks) {
+ if ((midiofs + 12) > midisize) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);
+ WildMidi_Close(mdi);
+ free(tmp_trackdata);
+ return NULL;
+ }
+ if (strncmp(&mididata[midiofs],"MTrk",4) != 0) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(Expected track header)", 0);
+ WildMidi_Close(mdi);
+ free(tmp_trackdata);
+ return NULL;
+ }
+ midiofs += 4;
+ tmp_trackdata[midi_track_counter].length = mididata[midiofs] << 24 | mididata[midiofs+1] << 16 | mididata[midiofs+2] << 8 | mididata[midiofs+3];
+ midiofs += 4;
+
+ if (midisize < (midiofs + tmp_trackdata[midi_track_counter].length)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);
+ WildMidi_Close(mdi);
+ free(tmp_trackdata);
+ return NULL;
+ }
+ tmp_trackdata[midi_track_counter].ptr = midiofs;
+ tmp_trackdata[midi_track_counter].EOT = 0;
+ tmp_trackdata[midi_track_counter].running_event = 0;
+ tmp_trackdata[midi_track_counter].delta = read_var_length(mdi, &tmp_trackdata[midi_track_counter]);
+ if (tmp_trackdata[midi_track_counter].delta == 0xFFFFFFFF) {
+ WildMidi_Close(mdi);
+ free(tmp_trackdata);
+ return NULL;
+ }
+ midiofs += tmp_trackdata[midi_track_counter].length;
+
+ if (memcmp(&mididata[midiofs-3], eot,3) != 0) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(Expected EOT)", 0);
+ WildMidi_Close(mdi);
+ free(tmp_trackdata);
+ return NULL;
+ }
+ if (tmp_trackdata[midi_track_counter].delta < temp_delta) {
+ temp_delta = tmp_trackdata[midi_track_counter].delta;
+ }
+ midi_track_counter++;
+ }
+
+// set midi info
+ mdi->index[0].offset = 0;
+ mdi->index[0].delta = temp_delta;
+
+ while (EOT_count != no_tracks) {
+ last_delta = 0;
+ for (i = 0; i < no_tracks; i++) {
+ if (tmp_trackdata[i].EOT) {
+ continue;
+ }
+ if (tmp_trackdata[i].delta) {
+ tmp_trackdata[i].delta -= minus_delta;
+ if (tmp_trackdata[i].delta) {
+ if ((last_delta == 0) || (last_delta > tmp_trackdata[i].delta)) {
+ last_delta = tmp_trackdata[i].delta;
+ }
+ continue;
+ }
+ }
+ do {
+ if (mdi->data[tmp_trackdata[i].ptr] < 0x80) {
+ current_event = tmp_trackdata[i].running_event;
+ if (current_event < 0x80) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(expected event)", 0);
+ WildMidi_Close(mdi);
+ free(tmp_trackdata);
+ return NULL;
+ }
+ } else {
+ current_event = mdi->data[tmp_trackdata[i].ptr];
+ tmp_trackdata[i].ptr++;
+ }
+
+
+ index_count++;
+ mdi->index[index_count].offset = tmp_trackdata[i].ptr;
+ mdi->index[index_count].delta = 0;
+ mdi->index[index_count].event = current_event;
+
+ do_event[((current_event & 0xF0) >> 4) - 8]((current_event & 0x0F), mdi, &tmp_trackdata[i]);
+ if (tmp_trackdata[i].delta == 0xFFFFFFFF) {
+ WildMidi_Close(mdi);
+ free(tmp_trackdata);
+ return NULL;
+ }
+ if (tmp_trackdata[i].EOT) {
+ EOT_count++;
+ break;
+ }
+ tmp_trackdata[i].delta = read_var_length(mdi, &tmp_trackdata[i]);
+ if (tmp_trackdata[i].delta == 0xFFFFFFFF) {
+ WildMidi_Close(mdi);
+ free(tmp_trackdata);
+ return NULL;
+ }
+ } while (!(tmp_trackdata[i].delta));
+ if ((last_delta == 0) || (last_delta > tmp_trackdata[i].delta)) {
+ if (tmp_trackdata[i].delta != 0) {
+ last_delta = tmp_trackdata[i].delta;
+ }
+ }
+ }
+// printf("\rLast Delta %lu\n",last_delta);
+ mdi->index[index_count].delta = last_delta;
+ mdi->samples_to_mix += last_delta * mdi->samples_per_delta;
+ mdi->sample_count += mdi->samples_to_mix >> 10;
+ mdi->samples_to_mix %= 1024;
+ minus_delta = last_delta;
+ }
+ mdi->sample_count -= (mdi->index[index_count - 1].delta * mdi->samples_per_delta) >> 10;
+ mdi->index[index_count - 1].delta = 0;
+ mdi->index_size = index_count;
+ mdi->index = realloc(mdi->index, (sizeof(struct _mdi_index) * mdi->index_size));
+ if (mdi->index == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno);
+ WildMidi_Close(mdi);
+ free(tmp_trackdata);
+ return NULL;
+ }
+ mdi->info.approx_total_samples = mdi->sample_count + 1;
+ mdi->samples_to_mix = 0;
+ mdi->sample_count = 0;
+ mdi->info.current_sample = 0;
+ mdi->samples_per_delta = (WM_SampleRate << 10) / (2 * mdi->divisions);
+ mdi->recalc_samples = 1;
+ mdi->last_note = mdi->note;
+ if (mdi->info.mixer_options & WM_MO_LINEAR_VOLUME) {
+ mdi->amp = 281;
+ } else {
+ mdi->amp = 281 * mdi->lin_max_vol / mdi->log_max_vol;
+ }
+
+ for (i = 0; i < 16; i++) {
+ mdi->channel[i].bank = 0;
+ do_pan_adjust(mdi, i);
+ }
+
+ for (i = 0; i < 4; i++) {
+ mdi->filter.lowpass[i][0].in[0] = 0;
+ mdi->filter.lowpass[i][0].in[1] = 0;
+ mdi->filter.lowpass[i][1].in[0] = 0;
+ mdi->filter.lowpass[i][1].in[1] = 0;
+
+ mdi->filter.lowpass[i][0].out[0] = 0;
+ mdi->filter.lowpass[i][0].out[1] = 0;
+ mdi->filter.lowpass[i][1].out[0] = 0;
+ mdi->filter.lowpass[i][1].out[1] = 0;
+
+ mdi->filter.delay_pos[i][0] = 0;
+ mdi->filter.delay_pos[i][1] = 0;
+
+ mdi->filter.delay[i][0] = malloc(delay_size[i][0] * sizeof(signed long int));
+ mdi->filter.delay[i][1] = malloc(delay_size[i][1] * sizeof(signed long int));
+ memset (mdi->filter.delay[i][0], 0, (delay_size[i][0] * sizeof(signed long int)));
+ memset (mdi->filter.delay[i][1], 0, (delay_size[i][1] * sizeof(signed long int)));
+
+ }
+ mdi->filter.in[0][0] = 0;
+ mdi->filter.in[0][1] = 0;
+ mdi->filter.in[1][0] = 0;
+ mdi->filter.in[1][1] = 0;
+ mdi->filter.out[0][0] = 0;
+ mdi->filter.out[0][1] = 0;
+ mdi->filter.out[1][0] = 0;
+ mdi->filter.out[1][1] = 0;
+
+ free(tmp_trackdata);
+ return (mdi);
+}
+
+/*
+ * =========================
+ * External Functions
+ * =========================
+ */
+
+const char *
+WildMidi_GetString (unsigned short int info) {
+ switch (info) {
+ case WM_GS_VERSION:
+ return WM_Version;
+ }
+ return NULL;
+}
+
+int
+WildMidi_Init (const char * config_file, unsigned short int rate, unsigned short int options) {
+ if (WM_Initialized) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
+ return -1;
+ }
+
+ if (config_file == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL config file pointer)", 0);
+ return -1;
+ }
+ WM_InitPatches();
+ if (WM_LoadConfig(config_file) == -1) {
+ return -1;
+ }
+
+ if (options & 0xFFD8) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid option)", 0);
+ WM_FreePatches();
+ return -1;
+ }
+ WM_MixerOptions = options;
+
+ if ((rate < 11000) || (rate > 65000)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(rate out of bounds, range is 11000 - 65000)", 0);
+ WM_FreePatches();
+ return -1;
+ }
+ WM_SampleRate = rate;
+ WM_Initialized = 1;
+ patch_lock = 0;
+
+ init_gauss();
+ init_lowpass();
+ return 0;
+}
+
+int
+WildMidi_MasterVolume (unsigned char master_volume) {
+ struct _mdi *mdi = NULL;
+ struct _hndl * tmp_handle = first_handle;
+ int i = 0;
+
+ if (!WM_Initialized) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
+ return -1;
+ }
+ if (master_volume > 127) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(master volume out of range, range is 0-127)", 0);
+ return -1;
+ }
+
+ WM_MasterVolume = lin_volume[master_volume];
+
+ if (tmp_handle != NULL) {
+ while(tmp_handle != NULL) {
+ mdi = (struct _mdi *)tmp_handle->handle;
+ for (i = 0; i < 16; i++) {
+ do_pan_adjust(mdi, i);
+ }
+ tmp_handle = tmp_handle->next;
+ }
+ }
+
+ return 0;
+}
+
+int
+WildMidi_Close (midi * handle) {
+ struct _mdi *mdi = (struct _mdi *)handle;
+ struct _hndl * tmp_handle;
+ struct _sample *tmp_sample;
+ int i;
+
+ if (!WM_Initialized) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
+ return -1;
+ }
+ if (handle == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0);
+ return -1;
+ }
+ if (first_handle == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(no midi's open)", 0);
+ return -1;
+ }
+ WM_Lock(&mdi->lock);
+ if (first_handle->handle == handle) {
+ tmp_handle = first_handle->next;
+ free (first_handle);
+ first_handle = tmp_handle;
+ if (first_handle != NULL)
+ first_handle->prev = NULL;
+ } else {
+ tmp_handle = first_handle;
+ while (tmp_handle->handle != handle) {
+ tmp_handle = tmp_handle->next;
+ if (tmp_handle == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(handle does not exist)", 0);
+ return -1;
+ }
+ }
+ tmp_handle->prev->next = tmp_handle->next;
+ if (tmp_handle->next != NULL) {
+ tmp_handle->next->prev = tmp_handle->prev;
+ }
+ free (tmp_handle);
+ }
+
+ if (mdi->patch_count != 0) {
+ WM_Lock(&patch_lock);
+ for (i = 0; i < mdi->patch_count; i++) {
+ mdi->patches[i]->inuse_count--;
+ if (mdi->patches[i]->inuse_count == 0) {
+ //free samples here
+ if (mdi->patches[i]->first_sample != NULL) {
+ while (mdi->patches[i]->first_sample != NULL) {
+ tmp_sample = mdi->patches[i]->first_sample->next;
+ if (mdi->patches[i]->first_sample->data)
+ free(mdi->patches[i]->first_sample->data);
+ free(mdi->patches[i]->first_sample);
+ mdi->patches[i]->first_sample = tmp_sample;
+ }
+ mdi->patches[i]->loaded = 0;
+ }
+ }
+ }
+ WM_Unlock(&patch_lock);
+ free (mdi->patches);
+ }
+ if (mdi->data != NULL) {
+ free (mdi->data);
+ }
+ if (mdi->tmp_info != NULL) {
+ free (mdi->tmp_info);
+ }
+ if (mdi->index != NULL)
+ free (mdi->index);
+ free (mdi);
+ // no need to unlock cause the struct containing the lock no-longer exists;
+ return 0;
+}
+
+midi *
+WildMidi_Open (const char *midifile) {
+ unsigned char *mididata = NULL;
+ unsigned long int midisize = 0;
+
+ if (!WM_Initialized) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
+ return NULL;
+ }
+ if (midifile == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL filename)", 0);
+ return NULL;
+ }
+
+ if ((mididata = WM_BufferFile(midifile, &midisize)) == NULL) {
+ return NULL;
+ }
+
+ return (void *)WM_ParseNewMidi(mididata,midisize);
+}
+
+midi *
+WildMidi_OpenBuffer (unsigned char *midibuffer, unsigned long int size) {
+ if (!WM_Initialized) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
+ return NULL;
+ }
+ if (midibuffer == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL midi data buffer)", 0);
+ return NULL;
+ }
+
+ return (void *)WM_ParseNewMidi(midibuffer,size);
+}
+
+int
+WildMidi_LoadSamples( midi * handle) {
+ return 0;
+}
+
+int
+WildMidi_FastSeek ( midi * handle, unsigned long int *sample_pos) {
+ struct _mdi *mdi = (struct _mdi *)handle;
+ struct _note **note_data = mdi->note;
+ void (*do_event[])(unsigned char ch, struct _mdi *midifile, unsigned long int ptr) = {
+ *do_null,
+ *do_null,
+ *do_aftertouch,
+ *do_control,
+ *do_patch,
+ *do_channel_pressure,
+ *do_pitch,
+ *do_message
+ };
+ unsigned long int real_samples_to_mix = 0;
+
+ if (!WM_Initialized) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
+ return -1;
+ }
+ if (handle == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0);
+ return -1;
+ }
+ WM_Lock(&mdi->lock);
+ if (sample_pos == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL seek position pointer)", 0);
+ WM_Unlock(&mdi->lock);
+ return -1;
+ }
+
+ if (*sample_pos == mdi->info.current_sample) {
+ WM_Unlock(&mdi->lock);
+ return 0;
+ }
+
+ if (*sample_pos > mdi->info.current_sample) {
+ if ((mdi->sample_count == 0) && (mdi->index_count == mdi->index_size) && (mdi->last_note == 0)) {
+ *sample_pos = mdi->info.current_sample;
+ WM_Unlock(&mdi->lock);
+ return 0;
+ }
+ } else {
+ WM_ResetToStart(handle);
+ }
+
+ //reset all notes
+ if (note_data != mdi->last_note) {
+ do {
+ (*note_data)->active = 0;
+ *note_data = NULL;
+ note_data++;
+ } while (note_data != mdi->last_note);
+ mdi->last_note = mdi->note;
+ }
+
+ while (*sample_pos != mdi->info.current_sample) {
+ if (!mdi->sample_count) {
+ if (mdi->index_count != mdi->index_size) {
+
+ do {
+ if (mdi->index_count == mdi->index_size) {
+ break;
+ }
+
+ if (mdi->index_count != 0) {
+ do_event[((mdi->index[mdi->index_count].event & 0xF0) >> 4) - 8]((mdi->index[mdi->index_count].event & 0x0F), mdi, mdi->index[mdi->index_count].offset);
+ }
+ } while (mdi->index[mdi->index_count++].delta == 0);
+
+ mdi->samples_to_mix += mdi->index[mdi->index_count-1].delta * mdi->samples_per_delta;
+ mdi->sample_count = mdi->samples_to_mix >> 10;
+ mdi->samples_to_mix %= 1024;
+ } else {
+ mdi->sample_count = WM_SampleRate;
+ }
+ }
+
+ if (mdi->sample_count <= (*sample_pos - mdi->info.current_sample)) {
+ real_samples_to_mix = mdi->sample_count;
+ if (real_samples_to_mix == 0) {
+ continue;
+ }
+ } else {
+ real_samples_to_mix = (*sample_pos - mdi->info.current_sample);
+ }
+
+ mdi->info.current_sample += real_samples_to_mix;
+ mdi->sample_count -= real_samples_to_mix;
+ if ((mdi->index_count == mdi->index_size) && (mdi->last_note == 0)) {
+ mdi->sample_count = 0;
+ *sample_pos = mdi->info.current_sample;
+ WM_Unlock(&mdi->lock);
+ return 0;
+ }
+ }
+ WM_Unlock(&mdi->lock);
+ return 0;
+}
+
+int
+WildMidi_SampledSeek ( midi * handle, unsigned long int *sample_pos) {
+ struct _mdi *mdi = (struct _mdi *)handle;
+ struct _note **note_data = mdi->note;
+ unsigned long int real_samples_to_mix = 0;
+ unsigned long int tmp_samples_to_mix = 0;
+
+ if (!WM_Initialized) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
+ return -1;
+ }
+ if (handle == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0);
+ return -1;
+ }
+ WM_Lock(&mdi->lock);
+ if (sample_pos == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL seek position pointer)", 0);
+ WM_Unlock(&mdi->lock);
+ return -1;
+ }
+
+ if (*sample_pos == mdi->info.current_sample) {
+ WM_Unlock(&mdi->lock);
+ return 0;
+ }
+
+ if (*sample_pos > mdi->info.current_sample) {
+ if ((mdi->sample_count == 0) && (mdi->index_count == mdi->index_size) && (mdi->last_note == 0)) {
+ *sample_pos = mdi->info.current_sample;
+ WM_Unlock(&mdi->lock);
+ return 0;
+ }
+ } else {
+ WM_ResetToStart(handle);
+ if (note_data != mdi->last_note) {
+ do {
+ (*note_data)->active = 0;
+ *note_data = NULL;
+ note_data++;
+ } while (note_data != mdi->last_note);
+ mdi->last_note = mdi->note;
+ }
+ }
+
+ while (*sample_pos != mdi->info.current_sample) {
+ if (!mdi->sample_count) {
+ if (mdi->index_count != mdi->index_size) {
+
+ do {
+ if (mdi->index_count == mdi->index_size) {
+ break;
+ }
+
+ if (mdi->index_count != 0) {
+ do_event[((mdi->index[mdi->index_count].event & 0xF0) >> 4) - 8]((mdi->index[mdi->index_count].event & 0x0F), mdi, mdi->index[mdi->index_count].offset);
+ }
+ } while (mdi->index[mdi->index_count++].delta == 0);
+
+ mdi->samples_to_mix += mdi->index[mdi->index_count-1].delta * mdi->samples_per_delta;
+ mdi->sample_count = mdi->samples_to_mix >> 10;
+ mdi->samples_to_mix %= 1024;
+ } else {
+ if (mdi->recalc_samples) {
+ WM_RecalcSamples(mdi);
+ }
+ mdi->sample_count = mdi->info.approx_total_samples - mdi->info.current_sample;
+ if (mdi->sample_count == 0) {
+ WM_Unlock(&mdi->lock);
+ return 0;
+ }
+ }
+ }
+
+ if (mdi->sample_count <= (*sample_pos - mdi->info.current_sample)) {
+ real_samples_to_mix = mdi->sample_count;
+ if (real_samples_to_mix == 0) {
+ continue;
+ }
+ } else {
+ real_samples_to_mix = (*sample_pos - mdi->info.current_sample);
+ }
+
+ // do mixing here
+ tmp_samples_to_mix = real_samples_to_mix;
+ do {
+
+ if (mdi->last_note != mdi->note) {
+ note_data = mdi->note;
+ while (note_data != mdi->last_note) {
+
+
+/*
+ * ========================
+ * sample position checking
+ * ========================
+ */
+ (*note_data)->sample_pos += (*note_data)->sample_inc;
+ if (__builtin_expect(((*note_data)->sample_pos > (*note_data)->sample->loop_end), 0)) {
+ if ((*note_data)->modes & SAMPLE_LOOP) {
+ (*note_data)->sample_pos = (*note_data)->sample->loop_start + (((*note_data)->sample_pos - (*note_data)->sample->loop_start) % (*note_data)->sample->loop_size);
+ } else if (__builtin_expect(((*note_data)->sample_pos >= (*note_data)->sample->data_length), 0)) {
+ if (__builtin_expect(((*note_data)->next == NULL), 1)) {
+ goto KILL_NOTE;
+ }
+ goto RESTART_NOTE;
+ }
+ }
+ if (__builtin_expect(((*note_data)->env_inc == 0), 0)) {
+ note_data++;
+ continue;
+ }
+ (*note_data)->env_level += (*note_data)->env_inc;
+ if (__builtin_expect(((*note_data)->env_level > 4194304), 0)) {
+ (*note_data)->env_level = (*note_data)->sample->env_target[(*note_data)->env];
+ }
+ if (__builtin_expect((((*note_data)->env_inc < 0) &&
+ ((*note_data)->env_level > (*note_data)->sample->env_target[(*note_data)->env])) ||
+ (((*note_data)->env_inc > 0) &&
+ ((*note_data)->env_level < (*note_data)->sample->env_target[(*note_data)->env])), 1)) {
+ note_data++;
+ continue;
+ }
+ (*note_data)->env_level = (*note_data)->sample->env_target[(*note_data)->env];
+ switch ((*note_data)->env) {
+ case 0:
+ if (!((*note_data)->modes & SAMPLE_ENVELOPE)) {
+ (*note_data)->env_inc = 0;
+ note_data++;
+ continue;
+ }
+ break;
+ case 2:
+ if ((*note_data)->modes & SAMPLE_SUSTAIN) {
+ (*note_data)->env_inc = 0;
+ note_data++;
+ continue;
+ }
+ break;
+ case 5:
+ if (__builtin_expect(((*note_data)->env_level == 0), 1)) {
+ goto KILL_NOTE;
+ }
+ // sample release
+ if ((*note_data)->modes & SAMPLE_LOOP)
+ (*note_data)->modes ^= SAMPLE_LOOP;
+ (*note_data)->env_inc = 0;
+ note_data++;
+ continue;
+ case 6:
+ if (__builtin_expect(((*note_data)->next != NULL), 1)) {
+ RESTART_NOTE:
+ (*note_data)->active = 0;
+ *note_data = (*note_data)->next;
+ (*note_data)->active = 1;
+ note_data++;
+
+ } else {
+ KILL_NOTE:
+ (*note_data)->active = 0;
+ mdi->last_note--;
+ if (note_data != mdi->last_note) {
+ *note_data = *mdi->last_note;
+ }
+ }
+ continue;
+ }
+ (*note_data)->env++;
+ if ((*note_data)->env_level > (*note_data)->sample->env_target[(*note_data)->env]) {
+ (*note_data)->env_inc = -(*note_data)->sample->env_rate[(*note_data)->env];
+ } else {
+ (*note_data)->env_inc = (*note_data)->sample->env_rate[(*note_data)->env];
+ }
+ note_data++;
+ continue;
+ }
+ } else {
+ break;
+ }
+ } while (--tmp_samples_to_mix);
+ mdi->info.current_sample += real_samples_to_mix;
+ mdi->sample_count -= real_samples_to_mix;
+ if (mdi->index_count == mdi->index_size) {
+ if (mdi->last_note == 0) {
+ mdi->sample_count = 0;
+ *sample_pos = mdi->info.current_sample;
+ WM_Unlock(&mdi->lock);
+ return 0;
+ }
+ }
+ }
+ WM_Unlock(&mdi->lock);
+ return 0;
+}
+
+int
+WildMidi_GetOutput_Linear (midi * handle, char * buffer, unsigned long int size) {
+ unsigned long int buffer_used = 0;
+ struct _mdi *mdi = (struct _mdi *)handle;
+ unsigned long int real_samples_to_mix = 0;
+ unsigned long int data_pos;
+ signed long int premix, left_mix, right_mix;
+ signed long int vol_mul;
+ struct _note **note_data = NULL;
+ unsigned long int count;
+
+ if (__builtin_expect((!WM_Initialized),0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
+ return -1;
+ }
+ if (__builtin_expect((handle == NULL),0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0);
+ return -1;
+ }
+ if (__builtin_expect((buffer == NULL),0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL buffer pointer)", 0);
+ return -1;
+ }
+
+ if (__builtin_expect((size == 0),0)) {
+ return 0;
+ }
+
+ if (__builtin_expect((size % 4),0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(size not a multiple of 4)", 0);
+ return -1;
+ }
+
+ WM_Lock(&mdi->lock);
+ if (__builtin_expect(((mdi->index_count == mdi->index_size) && (mdi->last_note == 0)), 0)) {
+ WM_Unlock(&mdi->lock);
+ return 0;
+ }
+
+ buffer_used = 0;
+ memset(buffer, 0, size);
+
+ do {
+ if (__builtin_expect((!mdi->sample_count),0)) {
+ if (__builtin_expect((mdi->index_count != mdi->index_size),1)) {
+ do {
+ if (__builtin_expect((mdi->index_count == mdi->index_size), 0)) {
+ break;
+ }
+
+ if (__builtin_expect((mdi->index_count != 0), 1)) {
+ do_event[((mdi->index[mdi->index_count].event & 0xF0) >> 4) - 8]((mdi->index[mdi->index_count].event & 0x0F), mdi, mdi->index[mdi->index_count].offset);
+ }
+ } while (mdi->index[mdi->index_count++].delta == 0);
+
+ mdi->samples_to_mix += mdi->index[mdi->index_count-1].delta * mdi->samples_per_delta;
+ mdi->sample_count = mdi->samples_to_mix >> 10;
+ mdi->samples_to_mix %= 1024;
+ } else {
+ if (mdi->recalc_samples) {
+ WM_RecalcSamples(mdi);
+ }
+ mdi->sample_count = mdi->info.approx_total_samples - mdi->info.current_sample;
+ if (mdi->sample_count == 0) {
+ WM_Unlock(&mdi->lock);
+ return buffer_used;
+ }
+ }
+ }
+ if (__builtin_expect((mdi->sample_count > (size >> 2)),1)) {
+ real_samples_to_mix = size >> 2;
+ } else {
+ real_samples_to_mix = mdi->sample_count;
+ if (real_samples_to_mix == 0) {
+ continue;
+ }
+ }
+
+ // do mixing here
+ count = real_samples_to_mix;
+ do {
+ note_data = mdi->note;
+ left_mix = right_mix = 0;
+ if (__builtin_expect((mdi->last_note != mdi->note),1)) {
+ while (note_data != mdi->last_note) {
+/*
+ * ===================
+ * resample the sample
+ * ===================
+ */
+ data_pos = (*note_data)->sample_pos >> FPBITS;
+ vol_mul = (((*note_data)->vol_lvl * ((*note_data)->env_level >> 12)) >> FPBITS);
+
+ premix = ((*note_data)->sample->data[data_pos] +
+ (((*note_data)->sample->data[data_pos + 1] - (*note_data)->sample->data[data_pos]) *
+ (signed long int)((*note_data)->sample_pos & FPMASK) >> FPBITS)) * vol_mul / 1024;
+
+ left_mix += premix * mdi->channel[(*note_data)->noteid >> 8].left_adjust;
+ right_mix += premix * mdi->channel[(*note_data)->noteid >> 8].right_adjust;
+
+/*
+ * ========================
+ * sample position checking
+ * ========================
+ */
+ (*note_data)->sample_pos += (*note_data)->sample_inc;
+ if (__builtin_expect(((*note_data)->sample_pos > (*note_data)->sample->loop_end), 0)) {
+ if ((*note_data)->modes & SAMPLE_LOOP) {
+ (*note_data)->sample_pos = (*note_data)->sample->loop_start + (((*note_data)->sample_pos - (*note_data)->sample->loop_start) % (*note_data)->sample->loop_size);
+ } else if (__builtin_expect(((*note_data)->sample_pos >= (*note_data)->sample->data_length), 0)) {
+ if (__builtin_expect(((*note_data)->next == NULL), 1)) {
+ goto KILL_NOTE;
+
+ }
+ goto RESTART_NOTE;
+ }
+ }
+
+ if (__builtin_expect(((*note_data)->env_inc == 0), 0)) {
+ note_data++;
+ continue;
+ }
+
+ (*note_data)->env_level += (*note_data)->env_inc;
+ if (__builtin_expect(((*note_data)->env_level > 4194304), 0)) {
+ (*note_data)->env_level = (*note_data)->sample->env_target[(*note_data)->env];
+ }
+ if (__builtin_expect((((*note_data)->env_inc < 0) &&
+ ((*note_data)->env_level > (*note_data)->sample->env_target[(*note_data)->env])) ||
+ (((*note_data)->env_inc > 0) &&
+ ((*note_data)->env_level < (*note_data)->sample->env_target[(*note_data)->env])), 1)) {
+ note_data++;
+ continue;
+ }
+
+ (*note_data)->env_level = (*note_data)->sample->env_target[(*note_data)->env];
+ switch ((*note_data)->env) {
+ case 0:
+ if (!((*note_data)->modes & SAMPLE_ENVELOPE)) {
+ (*note_data)->env_inc = 0;
+ note_data++;
+ continue;
+ }
+ break;
+ case 2:
+ if ((*note_data)->modes & SAMPLE_SUSTAIN) {
+ (*note_data)->env_inc = 0;
+ note_data++;
+ continue;
+ }
+ break;
+ case 5:
+ if (__builtin_expect(((*note_data)->env_level == 0), 1)) {
+ goto KILL_NOTE;
+ }
+ // sample release
+ if ((*note_data)->modes & SAMPLE_LOOP)
+ (*note_data)->modes ^= SAMPLE_LOOP;
+ (*note_data)->env_inc = 0;
+ note_data++;
+ continue;
+ case 6:
+ if (__builtin_expect(((*note_data)->next != NULL), 1)) {
+ RESTART_NOTE:
+ (*note_data)->active = 0;
+ *note_data = (*note_data)->next;
+ (*note_data)->active = 1;
+ note_data++;
+
+ } else {
+ KILL_NOTE:
+ (*note_data)->active = 0;
+ mdi->last_note--;
+ if (note_data != mdi->last_note) {
+ *note_data = *mdi->last_note;
+ }
+ }
+ continue;
+ }
+ (*note_data)->env++;
+ if ((*note_data)->env_level > (*note_data)->sample->env_target[(*note_data)->env]) {
+ (*note_data)->env_inc = -(*note_data)->sample->env_rate[(*note_data)->env];
+ } else {
+ (*note_data)->env_inc = (*note_data)->sample->env_rate[(*note_data)->env];
+ }
+ note_data++;
+ continue;
+ }
+/*
+ * =========================
+ * mix the channels together
+ * =========================
+ */
+
+ left_mix /= 1024;
+ right_mix /= 1024;
+ }
+
+#ifdef EXPERIMENT_626
+/*
+ * ==========================
+ * Experimental Reverb Engine
+ * ==========================
+ */
+
+ if (mdi->info.mixer_options & WM_MO_REVERB) {
+ signed long int filteral = mdi->filter.delay[0][0][mdi->filter.delay_pos[0][0]];
+ signed long int filterar = mdi->filter.delay[0][1][mdi->filter.delay_pos[0][1]];
+ signed long int filterbl = mdi->filter.delay[1][0][mdi->filter.delay_pos[1][0]];
+ signed long int filterbr = mdi->filter.delay[1][1][mdi->filter.delay_pos[1][1]];
+ signed long int filtercl = mdi->filter.delay[2][0][mdi->filter.delay_pos[2][0]];
+ signed long int filtercr = mdi->filter.delay[2][1][mdi->filter.delay_pos[2][1]];
+ signed long int filterdl = mdi->filter.delay[3][0][mdi->filter.delay_pos[3][0]];
+ signed long int filterdr = mdi->filter.delay[3][1][mdi->filter.delay_pos[3][1]];
+ signed long int tfal = (a[0][0] * filteral + a[0][1] * mdi->filter.lowpass[0][0].in[0] + a[0][0] * mdi->filter.lowpass[0][0].in[1] - b[0][0] * mdi->filter.lowpass[0][0].out[0] - b[0][1] * mdi->filter.lowpass[0][0].out[1]) / 1024;
+ signed long int tfar = (a[0][0] * filterar + a[0][1] * mdi->filter.lowpass[0][1].in[0] + a[0][0] * mdi->filter.lowpass[0][1].in[1] - b[0][0] * mdi->filter.lowpass[0][1].out[0] - b[0][1] * mdi->filter.lowpass[0][1].out[1]) / 1024;
+ signed long int tfbl = (a[1][0] * filterbl + a[1][1] * mdi->filter.lowpass[1][0].in[0] + a[1][0] * mdi->filter.lowpass[1][0].in[1] - b[1][0] * mdi->filter.lowpass[1][0].out[0] - b[1][1] * mdi->filter.lowpass[1][0].out[1]) / 1024;
+ signed long int tfbr = (a[1][0] * filterbr + a[1][1] * mdi->filter.lowpass[1][1].in[0] + a[1][0] * mdi->filter.lowpass[1][1].in[1] - b[1][0] * mdi->filter.lowpass[1][1].out[0] - b[1][1] * mdi->filter.lowpass[1][1].out[1]) / 1024;
+ signed long int tfcl = (a[2][0] * filtercl + a[2][1] * mdi->filter.lowpass[2][0].in[0] + a[2][0] * mdi->filter.lowpass[2][0].in[1] - b[2][0] * mdi->filter.lowpass[2][0].out[0] - b[2][1] * mdi->filter.lowpass[2][0].out[1]) / 1024;
+ signed long int tfcr = (a[2][0] * filtercr + a[2][1] * mdi->filter.lowpass[2][1].in[0] + a[2][0] * mdi->filter.lowpass[2][1].in[1] - b[2][0] * mdi->filter.lowpass[2][1].out[0] - b[2][1] * mdi->filter.lowpass[2][1].out[1]) / 1024;
+ signed long int tfdl = (a[3][0] * filterdl + a[3][1] * mdi->filter.lowpass[3][0].in[0] + a[3][0] * mdi->filter.lowpass[3][0].in[1] - b[3][0] * mdi->filter.lowpass[3][0].out[0] - b[3][1] * mdi->filter.lowpass[3][0].out[1]) / 1024;
+ signed long int tfdr = (a[3][0] * filterdr + a[3][1] * mdi->filter.lowpass[3][1].in[0] + a[3][0] * mdi->filter.lowpass[3][1].in[1] - b[3][0] * mdi->filter.lowpass[3][1].out[0] - b[3][1] * mdi->filter.lowpass[3][1].out[1]) / 1024;
+ signed long int tfl, tflo;
+ signed long int tfr, tfro;
+
+ mdi->filter.lowpass[0][0].in[1] = mdi->filter.lowpass[0][0].in[0];
+ mdi->filter.lowpass[0][0].in[0] = filteral;
+ mdi->filter.lowpass[0][1].in[1] = mdi->filter.lowpass[0][1].in[0];
+ mdi->filter.lowpass[0][1].in[0] = filterar;
+ mdi->filter.lowpass[1][0].in[1] = mdi->filter.lowpass[1][0].in[0];
+ mdi->filter.lowpass[1][0].in[0] = filterbl;
+ mdi->filter.lowpass[1][1].in[1] = mdi->filter.lowpass[1][1].in[0];
+ mdi->filter.lowpass[1][1].in[0] = filterbr;
+ mdi->filter.lowpass[2][0].in[1] = mdi->filter.lowpass[2][0].in[0];
+ mdi->filter.lowpass[2][0].in[0] = filtercl;
+ mdi->filter.lowpass[2][1].in[1] = mdi->filter.lowpass[2][1].in[0];
+ mdi->filter.lowpass[2][1].in[0] = filtercr;
+ mdi->filter.lowpass[3][0].in[1] = mdi->filter.lowpass[3][0].in[0];
+ mdi->filter.lowpass[3][0].in[0] = filterdl;
+ mdi->filter.lowpass[3][1].in[1] = mdi->filter.lowpass[3][1].in[0];
+ mdi->filter.lowpass[3][1].in[0] = filterdr;
+
+ mdi->filter.lowpass[0][0].out[1] = mdi->filter.lowpass[0][0].out[0];
+ mdi->filter.lowpass[0][0].out[0] = tfal;
+ mdi->filter.lowpass[0][1].out[1] = mdi->filter.lowpass[0][1].out[0];
+ mdi->filter.lowpass[0][1].out[0] = tfar;
+ mdi->filter.lowpass[1][0].out[1] = mdi->filter.lowpass[1][0].out[0];
+ mdi->filter.lowpass[1][0].out[0] = tfbl;
+ mdi->filter.lowpass[1][1].out[1] = mdi->filter.lowpass[1][1].out[0];
+ mdi->filter.lowpass[1][1].out[0] = tfbr;
+ mdi->filter.lowpass[2][0].out[1] = mdi->filter.lowpass[2][0].out[0];
+ mdi->filter.lowpass[2][0].out[0] = tfcl;
+ mdi->filter.lowpass[2][1].out[1] = mdi->filter.lowpass[2][1].out[0];
+ mdi->filter.lowpass[2][1].out[0] = tfcr;
+ mdi->filter.lowpass[3][0].out[1] = mdi->filter.lowpass[3][0].out[0];
+ mdi->filter.lowpass[3][0].out[0] = tfdl;
+ mdi->filter.lowpass[3][1].out[1] = mdi->filter.lowpass[3][1].out[0];
+ mdi->filter.lowpass[3][1].out[0] = tfdr;
+
+ mdi->filter.delay[0][0][mdi->filter.delay_pos[0][0]] = (tfbr * 405 + tfcr * 368) / 1024 + (left_mix * gain_in[0] / 1024);
+ mdi->filter.delay[0][1][mdi->filter.delay_pos[0][1]] = (tfbl * 402 + tfcl * 370) / 1024 + (right_mix * gain_in[0] / 1024);
+ mdi->filter.delay[1][0][mdi->filter.delay_pos[1][0]] = (tfar * -545 + tfdr * -364) / 1024 + (left_mix * gain_in[1] / 1024);
+ mdi->filter.delay[1][1][mdi->filter.delay_pos[1][1]] = (tfal * -550 + tfdl * -362) / 1024 + (right_mix * gain_in[1] / 1024);
+ mdi->filter.delay[2][0][mdi->filter.delay_pos[2][0]] = (tfar * 545 + tfdr * -364) / 1024 + (left_mix * gain_in[2] / 1024);
+ mdi->filter.delay[2][1][mdi->filter.delay_pos[2][1]] = (tfal * 550 + tfdl * 362) / 1024 + (right_mix * gain_in[2] / 1024);
+ mdi->filter.delay[3][0][mdi->filter.delay_pos[3][0]] = (tfbr * 405 + tfcr * -368) / 1024 + (left_mix * gain_in[3] / 1024);
+ mdi->filter.delay[3][1][mdi->filter.delay_pos[3][1]] = (tfbl * 402 + tfcl * -370) / 1024 + (right_mix * gain_in[3] / 1024);
+
+ tfl = ((tfal * gain_out[0] / 1024) + (tfbl * gain_out[1] / 1024) + (tfcl * gain_out[2] / 1024) + (tfdl * gain_out[3] / 1024));
+ tfr = ((tfar * gain_out[0] / 1024) + (tfbr * gain_out[1] / 1024) + (tfcr * gain_out[2] / 1024) + (tfdr * gain_out[3] / 1024));
+
+ tflo = (a[4][0] * tfl + a[4][1] * mdi->filter.in[0][0] + a[4][0] * mdi->filter.in[1][0] - b[4][0] * mdi->filter.out[0][0] - b[4][1] * mdi->filter.out[1][0]) / 1024;
+ tfro = (a[4][0] * tfr + a[4][1] * mdi->filter.in[0][1] + a[4][0] * mdi->filter.in[1][1] - b[4][0] * mdi->filter.out[0][1] - b[4][1] * mdi->filter.out[1][1]) / 1024;
+
+ mdi->filter.in[1][0] = mdi->filter.in[0][0];
+ mdi->filter.in[0][0] = tfl;
+ mdi->filter.in[1][1] = mdi->filter.in[0][1];
+ mdi->filter.in[0][1] = tfr;
+ mdi->filter.out[1][0] = mdi->filter.out[0][0];
+ mdi->filter.out[0][0] = tflo;
+ mdi->filter.out[1][1] = mdi->filter.out[0][1];
+ mdi->filter.out[0][1] = tfro;
+
+ left_mix += tflo;
+ right_mix += tfro;
+
+ mdi->filter.delay_pos[0][0]++;
+ mdi->filter.delay_pos[0][1]++;
+ mdi->filter.delay_pos[1][0]++;
+ mdi->filter.delay_pos[1][1]++;
+ mdi->filter.delay_pos[2][0]++;
+ mdi->filter.delay_pos[2][1]++;
+ mdi->filter.delay_pos[3][0]++;
+ mdi->filter.delay_pos[3][1]++;
+
+ if (mdi->filter.delay_pos[0][0] == delay_size[0][0]) mdi->filter.delay_pos[0][0] = 0;
+ if (mdi->filter.delay_pos[0][1] == delay_size[0][1]) mdi->filter.delay_pos[0][1] = 0;
+ if (mdi->filter.delay_pos[1][0] == delay_size[1][0]) mdi->filter.delay_pos[1][0] = 0;
+ if (mdi->filter.delay_pos[1][1] == delay_size[1][1]) mdi->filter.delay_pos[1][1] = 0;
+ if (mdi->filter.delay_pos[2][0] == delay_size[2][0]) mdi->filter.delay_pos[2][0] = 0;
+ if (mdi->filter.delay_pos[2][1] == delay_size[2][1]) mdi->filter.delay_pos[2][1] = 0;
+ if (mdi->filter.delay_pos[3][0] == delay_size[3][0]) mdi->filter.delay_pos[3][0] = 0;
+ if (mdi->filter.delay_pos[3][1] == delay_size[3][1]) mdi->filter.delay_pos[3][1] = 0;
+
+ }
+#endif
+ if (left_mix > 32767) {
+ left_mix = 32767;
+ } else if (left_mix < -32768) {
+ left_mix = -32768;
+ }
+
+ if (right_mix > 32767) {
+ right_mix = 32767;
+ } else if (right_mix < -32768) {
+ right_mix = -32768;
+ }
+
+
+/*
+ * ===================
+ * Write to the buffer
+ * ===================
+ */
+ (*buffer++) = left_mix & 0xff;
+ (*buffer++) = (left_mix >> 8) & 0xff;
+ (*buffer++) = right_mix & 0xff;
+ (*buffer++) = (right_mix >> 8) & 0xff;
+ } while (--count);
+
+ buffer_used += real_samples_to_mix * 4;
+ size -= (real_samples_to_mix << 2);
+ mdi->info.current_sample += real_samples_to_mix;
+ mdi->sample_count -= real_samples_to_mix;
+ if (mdi->index_count == mdi->index_size) {
+ if (mdi->last_note == 0) {
+ mdi->sample_count = 0;
+ WM_Unlock(&mdi->lock);
+ return buffer_used;
+ }
+ }
+ } while (size);
+
+ if ((mdi->index_count == mdi->index_size) && (mdi->recalc_samples)) {
+ WM_RecalcSamples(mdi);
+ mdi->sample_count = mdi->info.approx_total_samples - mdi->info.current_sample;
+ }
+ WM_Unlock(&mdi->lock);
+ return buffer_used;
+}
+
+int
+WildMidi_GetOutput_Gauss (midi * handle, char * buffer, unsigned long int size) {
+ unsigned long int buffer_used = 0;
+ struct _mdi *mdi = (struct _mdi *)handle;
+ unsigned long int real_samples_to_mix = 0;
+ unsigned long int data_pos;
+ signed long int premix, left_mix, right_mix;
+ signed long int vol_mul;
+ struct _note **note_data = NULL;
+ unsigned long int count;
+ signed short int *sptr;
+ double y, xd;
+ float *gptr, *gend;
+ int left, right, temp_n;
+ int ii, jj;
+
+
+ if (__builtin_expect((!WM_Initialized),0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
+ return -1;
+ }
+ if (__builtin_expect((handle == NULL),0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0);
+ return -1;
+ }
+ if (__builtin_expect((buffer == NULL),0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL buffer pointer)", 0);
+ return -1;
+ }
+
+ if (__builtin_expect((size == 0),0)) {
+ return 0;
+ }
+
+ if (__builtin_expect((size % 4),0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(size not a multiple of 4)", 0);
+ return -1;
+ }
+
+ WM_Lock(&mdi->lock);
+ if (__builtin_expect(((mdi->index_count == mdi->index_size) && (mdi->last_note == 0)), 0)) {
+ WM_Unlock(&mdi->lock);
+ return 0;
+ }
+
+ buffer_used = 0;
+ memset(buffer, 0, size);
+
+ do {
+ if (__builtin_expect((!mdi->sample_count),0)) {
+ if (__builtin_expect((mdi->index_count != mdi->index_size),1)) {
+ do {
+ if (__builtin_expect((mdi->index_count == mdi->index_size), 0)) {
+ break;
+ }
+
+ if (__builtin_expect((mdi->index_count != 0), 1)) {
+ do_event[((mdi->index[mdi->index_count].event & 0xF0) >> 4) - 8]((mdi->index[mdi->index_count].event & 0x0F), mdi, mdi->index[mdi->index_count].offset);
+ }
+ } while (mdi->index[mdi->index_count++].delta == 0);
+
+ mdi->samples_to_mix += mdi->index[mdi->index_count-1].delta * mdi->samples_per_delta;
+ mdi->sample_count = mdi->samples_to_mix >> 10;
+ mdi->samples_to_mix %= 1024;
+ } else {
+ if (mdi->recalc_samples) {
+ WM_RecalcSamples(mdi);
+ }
+ mdi->sample_count = mdi->info.approx_total_samples - mdi->info.current_sample;
+ if (mdi->sample_count == 0) {
+ WM_Unlock(&mdi->lock);
+ return buffer_used;
+ }
+ }
+ }
+ if (__builtin_expect((mdi->sample_count > (size >> 2)),1)) {
+ real_samples_to_mix = size >> 2;
+ } else {
+ real_samples_to_mix = mdi->sample_count;
+ if (real_samples_to_mix == 0) {
+ continue;
+ }
+ }
+
+ // do mixing here
+ count = real_samples_to_mix;
+ do {
+ note_data = mdi->note;
+ left_mix = right_mix = 0;
+ if (__builtin_expect((mdi->last_note != mdi->note),1)) {
+ while (note_data != mdi->last_note) {
+/*
+ * ===================
+ * resample the sample
+ * ===================
+ */
+ data_pos = (*note_data)->sample_pos >> FPBITS;
+ vol_mul = (((*note_data)->vol_lvl * ((*note_data)->env_level >> 12)) >> FPBITS);
+
+ /* check to see if we're near one of the ends */
+ left = data_pos;
+ right = ((*note_data)->sample->data_length>>FPBITS)- left -1;
+ temp_n = (right<<1)-1;
+ if (temp_n <= 0)
+ temp_n = 1;
+ if (temp_n > (left<<1)+1)
+ temp_n = (left<<1)+1;
+
+ /* use Newton if we can't fill the window */
+ if (temp_n < gauss_n) {
+ xd = (*note_data)->sample_pos & FPMASK;
+ xd /= (1L<<FPBITS);
+ xd += temp_n>>1;
+ y = 0;
+ sptr = (*note_data)->sample->data + ((*note_data)->sample_pos>>FPBITS) - (temp_n>>1);
+ for (ii = temp_n; ii;) {
+ for (jj = 0; jj <= ii; jj++)
+ y += sptr[jj] * newt_coeffs[ii][jj];
+ y *= xd - --ii;
+ }
+ y += *sptr;
+ } else { /* otherwise, use Gauss as usual */
+ y = 0;
+ gptr = gauss_table[(*note_data)->sample_pos & FPMASK];
+ gend = gptr + gauss_n;
+ sptr = (*note_data)->sample->data + ((*note_data)->sample_pos >> FPBITS) - (gauss_n>>1);
+ do {
+ y += *(sptr++) * *(gptr++);
+ } while (gptr <= gend);
+ }
+
+ premix = y * vol_mul / 1024;
+
+ left_mix += premix * mdi->channel[(*note_data)->noteid >> 8].left_adjust;
+ right_mix += premix * mdi->channel[(*note_data)->noteid >> 8].right_adjust;
+
+/*
+ * ========================
+ * sample position checking
+ * ========================
+ */
+ (*note_data)->sample_pos += (*note_data)->sample_inc;
+ if (__builtin_expect(((*note_data)->sample_pos > (*note_data)->sample->loop_end), 0)) {
+ if ((*note_data)->modes & SAMPLE_LOOP) {
+ (*note_data)->sample_pos = (*note_data)->sample->loop_start + (((*note_data)->sample_pos - (*note_data)->sample->loop_start) % (*note_data)->sample->loop_size);
+ } else if (__builtin_expect(((*note_data)->sample_pos >= (*note_data)->sample->data_length), 0)) {
+ if (__builtin_expect(((*note_data)->next == NULL), 1)) {
+ goto KILL_NOTE;
+
+ }
+ goto RESTART_NOTE;
+ }
+ }
+
+ if (__builtin_expect(((*note_data)->env_inc == 0), 0)) {
+ note_data++;
+ continue;
+ }
+
+ (*note_data)->env_level += (*note_data)->env_inc;
+ if (__builtin_expect(((*note_data)->env_level > 4194304), 0)) {
+ (*note_data)->env_level = (*note_data)->sample->env_target[(*note_data)->env];
+ }
+ if (__builtin_expect((((*note_data)->env_inc < 0) &&
+ ((*note_data)->env_level > (*note_data)->sample->env_target[(*note_data)->env])) ||
+ (((*note_data)->env_inc > 0) &&
+ ((*note_data)->env_level < (*note_data)->sample->env_target[(*note_data)->env])), 1)) {
+ note_data++;
+ continue;
+ }
+
+ (*note_data)->env_level = (*note_data)->sample->env_target[(*note_data)->env];
+ switch ((*note_data)->env) {
+ case 0:
+ if (!((*note_data)->modes & SAMPLE_ENVELOPE)) {
+ (*note_data)->env_inc = 0;
+ note_data++;
+ continue;
+ }
+ break;
+ case 2:
+ if ((*note_data)->modes & SAMPLE_SUSTAIN) {
+ (*note_data)->env_inc = 0;
+ note_data++;
+ continue;
+ }
+ break;
+ case 5:
+ if (__builtin_expect(((*note_data)->env_level == 0), 1)) {
+ goto KILL_NOTE;
+ }
+ // sample release
+ if ((*note_data)->modes & SAMPLE_LOOP)
+ (*note_data)->modes ^= SAMPLE_LOOP;
+ (*note_data)->env_inc = 0;
+ note_data++;
+ continue;
+ case 6:
+ if (__builtin_expect(((*note_data)->next != NULL), 1)) {
+ RESTART_NOTE:
+ (*note_data)->active = 0;
+ *note_data = (*note_data)->next;
+ (*note_data)->active = 1;
+ note_data++;
+
+ } else {
+ KILL_NOTE:
+ (*note_data)->active = 0;
+ mdi->last_note--;
+ if (note_data != mdi->last_note) {
+ *note_data = *mdi->last_note;
+ }
+ }
+ continue;
+ }
+ (*note_data)->env++;
+ if ((*note_data)->env_level > (*note_data)->sample->env_target[(*note_data)->env]) {
+ (*note_data)->env_inc = -(*note_data)->sample->env_rate[(*note_data)->env];
+ } else {
+ (*note_data)->env_inc = (*note_data)->sample->env_rate[(*note_data)->env];
+ }
+ note_data++;
+ continue;
+ }
+/*
+ * =========================
+ * mix the channels together
+ * =========================
+ */
+
+ left_mix /= 1024;
+ right_mix /= 1024;
+ }
+
+#ifdef EXPERIMENT_626
+/*
+ * ==========================
+ * Experimental Reverb Engine
+ * ==========================
+ */
+
+ if (mdi->info.mixer_options & WM_MO_REVERB) {
+ signed long int filteral = mdi->filter.delay[0][0][mdi->filter.delay_pos[0][0]];
+ signed long int filterar = mdi->filter.delay[0][1][mdi->filter.delay_pos[0][1]];
+ signed long int filterbl = mdi->filter.delay[1][0][mdi->filter.delay_pos[1][0]];
+ signed long int filterbr = mdi->filter.delay[1][1][mdi->filter.delay_pos[1][1]];
+ signed long int filtercl = mdi->filter.delay[2][0][mdi->filter.delay_pos[2][0]];
+ signed long int filtercr = mdi->filter.delay[2][1][mdi->filter.delay_pos[2][1]];
+ signed long int filterdl = mdi->filter.delay[3][0][mdi->filter.delay_pos[3][0]];
+ signed long int filterdr = mdi->filter.delay[3][1][mdi->filter.delay_pos[3][1]];
+ signed long int tfal = (a[0][0] * filteral + a[0][1] * mdi->filter.lowpass[0][0].in[0] + a[0][0] * mdi->filter.lowpass[0][0].in[1] - b[0][0] * mdi->filter.lowpass[0][0].out[0] - b[0][1] * mdi->filter.lowpass[0][0].out[1]) / 1024;
+ signed long int tfar = (a[0][0] * filterar + a[0][1] * mdi->filter.lowpass[0][1].in[0] + a[0][0] * mdi->filter.lowpass[0][1].in[1] - b[0][0] * mdi->filter.lowpass[0][1].out[0] - b[0][1] * mdi->filter.lowpass[0][1].out[1]) / 1024;
+ signed long int tfbl = (a[1][0] * filterbl + a[1][1] * mdi->filter.lowpass[1][0].in[0] + a[1][0] * mdi->filter.lowpass[1][0].in[1] - b[1][0] * mdi->filter.lowpass[1][0].out[0] - b[1][1] * mdi->filter.lowpass[1][0].out[1]) / 1024;
+ signed long int tfbr = (a[1][0] * filterbr + a[1][1] * mdi->filter.lowpass[1][1].in[0] + a[1][0] * mdi->filter.lowpass[1][1].in[1] - b[1][0] * mdi->filter.lowpass[1][1].out[0] - b[1][1] * mdi->filter.lowpass[1][1].out[1]) / 1024;
+ signed long int tfcl = (a[2][0] * filtercl + a[2][1] * mdi->filter.lowpass[2][0].in[0] + a[2][0] * mdi->filter.lowpass[2][0].in[1] - b[2][0] * mdi->filter.lowpass[2][0].out[0] - b[2][1] * mdi->filter.lowpass[2][0].out[1]) / 1024;
+ signed long int tfcr = (a[2][0] * filtercr + a[2][1] * mdi->filter.lowpass[2][1].in[0] + a[2][0] * mdi->filter.lowpass[2][1].in[1] - b[2][0] * mdi->filter.lowpass[2][1].out[0] - b[2][1] * mdi->filter.lowpass[2][1].out[1]) / 1024;
+ signed long int tfdl = (a[3][0] * filterdl + a[3][1] * mdi->filter.lowpass[3][0].in[0] + a[3][0] * mdi->filter.lowpass[3][0].in[1] - b[3][0] * mdi->filter.lowpass[3][0].out[0] - b[3][1] * mdi->filter.lowpass[3][0].out[1]) / 1024;
+ signed long int tfdr = (a[3][0] * filterdr + a[3][1] * mdi->filter.lowpass[3][1].in[0] + a[3][0] * mdi->filter.lowpass[3][1].in[1] - b[3][0] * mdi->filter.lowpass[3][1].out[0] - b[3][1] * mdi->filter.lowpass[3][1].out[1]) / 1024;
+ signed long int tfl, tflo;
+ signed long int tfr, tfro;
+
+ mdi->filter.lowpass[0][0].in[1] = mdi->filter.lowpass[0][0].in[0];
+ mdi->filter.lowpass[0][0].in[0] = filteral;
+ mdi->filter.lowpass[0][1].in[1] = mdi->filter.lowpass[0][1].in[0];
+ mdi->filter.lowpass[0][1].in[0] = filterar;
+ mdi->filter.lowpass[1][0].in[1] = mdi->filter.lowpass[1][0].in[0];
+ mdi->filter.lowpass[1][0].in[0] = filterbl;
+ mdi->filter.lowpass[1][1].in[1] = mdi->filter.lowpass[1][1].in[0];
+ mdi->filter.lowpass[1][1].in[0] = filterbr;
+ mdi->filter.lowpass[2][0].in[1] = mdi->filter.lowpass[2][0].in[0];
+ mdi->filter.lowpass[2][0].in[0] = filtercl;
+ mdi->filter.lowpass[2][1].in[1] = mdi->filter.lowpass[2][1].in[0];
+ mdi->filter.lowpass[2][1].in[0] = filtercr;
+ mdi->filter.lowpass[3][0].in[1] = mdi->filter.lowpass[3][0].in[0];
+ mdi->filter.lowpass[3][0].in[0] = filterdl;
+ mdi->filter.lowpass[3][1].in[1] = mdi->filter.lowpass[3][1].in[0];
+ mdi->filter.lowpass[3][1].in[0] = filterdr;
+
+ mdi->filter.lowpass[0][0].out[1] = mdi->filter.lowpass[0][0].out[0];
+ mdi->filter.lowpass[0][0].out[0] = tfal;
+ mdi->filter.lowpass[0][1].out[1] = mdi->filter.lowpass[0][1].out[0];
+ mdi->filter.lowpass[0][1].out[0] = tfar;
+ mdi->filter.lowpass[1][0].out[1] = mdi->filter.lowpass[1][0].out[0];
+ mdi->filter.lowpass[1][0].out[0] = tfbl;
+ mdi->filter.lowpass[1][1].out[1] = mdi->filter.lowpass[1][1].out[0];
+ mdi->filter.lowpass[1][1].out[0] = tfbr;
+ mdi->filter.lowpass[2][0].out[1] = mdi->filter.lowpass[2][0].out[0];
+ mdi->filter.lowpass[2][0].out[0] = tfcl;
+ mdi->filter.lowpass[2][1].out[1] = mdi->filter.lowpass[2][1].out[0];
+ mdi->filter.lowpass[2][1].out[0] = tfcr;
+ mdi->filter.lowpass[3][0].out[1] = mdi->filter.lowpass[3][0].out[0];
+ mdi->filter.lowpass[3][0].out[0] = tfdl;
+ mdi->filter.lowpass[3][1].out[1] = mdi->filter.lowpass[3][1].out[0];
+ mdi->filter.lowpass[3][1].out[0] = tfdr;
+
+ mdi->filter.delay[0][0][mdi->filter.delay_pos[0][0]] = (tfbr * 405 + tfcr * 368) / 1024 + (left_mix * gain_in[0] / 1024);
+ mdi->filter.delay[0][1][mdi->filter.delay_pos[0][1]] = (tfbl * 402 + tfcl * 370) / 1024 + (right_mix * gain_in[0] / 1024);
+ mdi->filter.delay[1][0][mdi->filter.delay_pos[1][0]] = (tfar * -545 + tfdr * -364) / 1024 + (left_mix * gain_in[1] / 1024);
+ mdi->filter.delay[1][1][mdi->filter.delay_pos[1][1]] = (tfal * -550 + tfdl * -362) / 1024 + (right_mix * gain_in[1] / 1024);
+ mdi->filter.delay[2][0][mdi->filter.delay_pos[2][0]] = (tfar * 545 + tfdr * -364) / 1024 + (left_mix * gain_in[2] / 1024);
+ mdi->filter.delay[2][1][mdi->filter.delay_pos[2][1]] = (tfal * 550 + tfdl * 362) / 1024 + (right_mix * gain_in[2] / 1024);
+ mdi->filter.delay[3][0][mdi->filter.delay_pos[3][0]] = (tfbr * 405 + tfcr * -368) / 1024 + (left_mix * gain_in[3] / 1024);
+ mdi->filter.delay[3][1][mdi->filter.delay_pos[3][1]] = (tfbl * 402 + tfcl * -370) / 1024 + (right_mix * gain_in[3] / 1024);
+
+ tfl = ((tfal * gain_out[0] / 1024) + (tfbl * gain_out[1] / 1024) + (tfcl * gain_out[2] / 1024) + (tfdl * gain_out[3] / 1024));
+ tfr = ((tfar * gain_out[0] / 1024) + (tfbr * gain_out[1] / 1024) + (tfcr * gain_out[2] / 1024) + (tfdr * gain_out[3] / 1024));
+
+ tflo = (a[4][0] * tfl + a[4][1] * mdi->filter.in[0][0] + a[4][0] * mdi->filter.in[1][0] - b[4][0] * mdi->filter.out[0][0] - b[4][1] * mdi->filter.out[1][0]) / 1024;
+ tfro = (a[4][0] * tfr + a[4][1] * mdi->filter.in[0][1] + a[4][0] * mdi->filter.in[1][1] - b[4][0] * mdi->filter.out[0][1] - b[4][1] * mdi->filter.out[1][1]) / 1024;
+
+ mdi->filter.in[1][0] = mdi->filter.in[0][0];
+ mdi->filter.in[0][0] = tfl;
+ mdi->filter.in[1][1] = mdi->filter.in[0][1];
+ mdi->filter.in[0][1] = tfr;
+ mdi->filter.out[1][0] = mdi->filter.out[0][0];
+ mdi->filter.out[0][0] = tflo;
+ mdi->filter.out[1][1] = mdi->filter.out[0][1];
+ mdi->filter.out[0][1] = tfro;
+
+ left_mix += tflo;
+ right_mix += tfro;
+
+ mdi->filter.delay_pos[0][0]++;
+ mdi->filter.delay_pos[0][1]++;
+ mdi->filter.delay_pos[1][0]++;
+ mdi->filter.delay_pos[1][1]++;
+ mdi->filter.delay_pos[2][0]++;
+ mdi->filter.delay_pos[2][1]++;
+ mdi->filter.delay_pos[3][0]++;
+ mdi->filter.delay_pos[3][1]++;
+
+ if (mdi->filter.delay_pos[0][0] == delay_size[0][0]) mdi->filter.delay_pos[0][0] = 0;
+ if (mdi->filter.delay_pos[0][1] == delay_size[0][1]) mdi->filter.delay_pos[0][1] = 0;
+ if (mdi->filter.delay_pos[1][0] == delay_size[1][0]) mdi->filter.delay_pos[1][0] = 0;
+ if (mdi->filter.delay_pos[1][1] == delay_size[1][1]) mdi->filter.delay_pos[1][1] = 0;
+ if (mdi->filter.delay_pos[2][0] == delay_size[2][0]) mdi->filter.delay_pos[2][0] = 0;
+ if (mdi->filter.delay_pos[2][1] == delay_size[2][1]) mdi->filter.delay_pos[2][1] = 0;
+ if (mdi->filter.delay_pos[3][0] == delay_size[3][0]) mdi->filter.delay_pos[3][0] = 0;
+ if (mdi->filter.delay_pos[3][1] == delay_size[3][1]) mdi->filter.delay_pos[3][1] = 0;
+
+ }
+#endif
+ if (left_mix > 32767) {
+ left_mix = 32767;
+ } else if (left_mix < -32768) {
+ left_mix = -32768;
+ }
+
+ if (right_mix > 32767) {
+ right_mix = 32767;
+ } else if (right_mix < -32768) {
+ right_mix = -32768;
+ }
+
+
+/*
+ * ===================
+ * Write to the buffer
+ * ===================
+ */
+ (*buffer++) = left_mix & 0xff;
+ (*buffer++) = (left_mix >> 8) & 0xff;
+ (*buffer++) = right_mix & 0xff;
+ (*buffer++) = (right_mix >> 8) & 0xff;
+ } while (--count);
+
+ buffer_used += real_samples_to_mix * 4;
+ size -= (real_samples_to_mix << 2);
+ mdi->info.current_sample += real_samples_to_mix;
+ mdi->sample_count -= real_samples_to_mix;
+ if (mdi->index_count == mdi->index_size) {
+ if (mdi->last_note == 0) {
+ mdi->sample_count = 0;
+ WM_Unlock(&mdi->lock);
+ return buffer_used;
+ }
+ }
+ } while (size);
+
+ if ((mdi->index_count == mdi->index_size) && (mdi->recalc_samples)) {
+ WM_RecalcSamples(mdi);
+ mdi->sample_count = mdi->info.approx_total_samples - mdi->info.current_sample;
+ }
+ WM_Unlock(&mdi->lock);
+ return buffer_used;
+}
+
+int
+WildMidi_GetOutput (midi * handle, char * buffer, unsigned long int size) {
+ struct _mdi *mdi = (struct _mdi *)handle;
+
+ if (__builtin_expect((!WM_Initialized),0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
+ return -1;
+ }
+ if (__builtin_expect((handle == NULL),0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0);
+ return -1;
+ }
+ if (__builtin_expect((buffer == NULL),0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL buffer pointer)", 0);
+ return -1;
+ }
+
+ if (__builtin_expect((size == 0),0)) {
+ return 0;
+ }
+
+ if (__builtin_expect((size % 4),0)) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(size not a multiple of 4)", 0);
+ return -1;
+ }
+ if (mdi->info.mixer_options & WM_MO_EXPENSIVE_INTERPOLATION) {
+ return WildMidi_GetOutput_Gauss (handle, buffer,size);
+ } else {
+ return WildMidi_GetOutput_Linear (handle, buffer, size);
+ }
+}
+
+int
+WildMidi_SetOption (midi * handle, unsigned short int options, unsigned short int setting) {
+ struct _mdi *mdi = (struct _mdi *)handle;
+ struct _note **note_data = mdi->note;
+ int i;
+
+ if (!WM_Initialized) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
+ return -1;
+ }
+ if (handle == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0);
+ return -1;
+ }
+ WM_Lock(&mdi->lock);
+ if ((!(options & 0x0007)) || (options & 0xFFF8)){
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid option)", 0);
+ WM_Unlock(&mdi->lock);
+ return -1;
+ }
+ if (setting & 0xFFF8) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid setting)", 0);
+ WM_Unlock(&mdi->lock);
+ return -1;
+ }
+
+ mdi->info.mixer_options = ((mdi->info.mixer_options & (0x00FF ^ options)) | (options & setting));
+
+ if (options & WM_MO_LINEAR_VOLUME) {
+ if (mdi->info.mixer_options & WM_MO_LINEAR_VOLUME) {
+ mdi->amp = 281;
+ } else {
+ mdi->amp = 281 * mdi->lin_max_vol / mdi->log_max_vol;
+ }
+ for (i = 0; i < 16; i++) {
+ do_pan_adjust(mdi, i);
+ }
+ if (note_data != mdi->last_note) {
+ do {
+ (*note_data)->vol_lvl = get_volume(mdi, ((*note_data)->noteid >> 8), *note_data);
+ if ((*note_data)->next)
+ (*note_data)->next->vol_lvl = get_volume(mdi, ((*note_data)->noteid >> 8), (*note_data)->next);
+ note_data++;
+ } while (note_data != mdi->last_note);
+ }
+ }
+
+ if (options & WM_MO_REVERB) {
+ for (i = 0; i < 4; i++) {
+ mdi->filter.lowpass[i][0].in[0] = 0;
+ mdi->filter.lowpass[i][0].in[1] = 0;
+ mdi->filter.lowpass[i][1].in[0] = 0;
+ mdi->filter.lowpass[i][1].in[1] = 0;
+
+ mdi->filter.lowpass[i][0].out[0] = 0;
+ mdi->filter.lowpass[i][0].out[1] = 0;
+ mdi->filter.lowpass[i][1].out[0] = 0;
+ mdi->filter.lowpass[i][1].out[1] = 0;
+
+ mdi->filter.delay_pos[i][0] = 0;
+ mdi->filter.delay_pos[i][1] = 0;
+
+ memset (mdi->filter.delay[i][0], 0, (delay_size[i][0] * sizeof(signed long int)));
+ memset (mdi->filter.delay[i][1], 0, (delay_size[i][1] * sizeof(signed long int)));
+ }
+ }
+ WM_Unlock(&mdi->lock);
+ return 0;
+}
+
+struct _WM_Info *
+WildMidi_GetInfo (midi * handle) {
+ struct _mdi *mdi = (struct _mdi *)handle;
+ if (!WM_Initialized) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
+ return NULL;
+ }
+ if (handle == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0);
+ return NULL;
+ }
+ WM_Lock(&mdi->lock);
+ if (mdi->tmp_info == NULL) {
+ mdi->tmp_info = malloc(sizeof(struct _WM_Info));
+ if (mdi->tmp_info == NULL) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to set info", 0);
+ WM_Unlock(&mdi->lock);
+ return NULL;
+ }
+ }
+ mdi->tmp_info->current_sample = mdi->info.current_sample;
+ mdi->tmp_info->approx_total_samples = mdi->info.approx_total_samples;
+ mdi->tmp_info->mixer_options = mdi->info.mixer_options;
+ WM_Unlock(&mdi->lock);
+ return mdi->tmp_info;
+}
+
+int
+WildMidi_Shutdown ( void ) {
+ struct _hndl * tmp_hdle;
+
+ if (!WM_Initialized) {
+ WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0);
+ return -1;
+ }
+ if (first_handle != NULL) {
+ while (first_handle != NULL) {
+ tmp_hdle = first_handle->next;
+ WildMidi_Close((struct _mdi *)first_handle->handle);
+ free (first_handle);
+ first_handle = tmp_hdle;
+ }
+ }
+ WM_FreePatches();
+ WM_Initialized = 0;
+ return 0;
+}
+
diff --git a/plugins/wildmidi/wildmidiplug.c b/plugins/wildmidi/wildmidiplug.c
new file mode 100644
index 00000000..3c5e4d81
--- /dev/null
+++ b/plugins/wildmidi/wildmidiplug.c
@@ -0,0 +1,170 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ 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 "wildmidi_lib.h"
+
+extern DB_decoder_t wmidi_plugin;
+
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+//#define trace(fmt,...)
+
+static DB_functions_t *deadbeef;
+
+#define min(x,y) ((x)<(y)?(x):(y))
+#define max(x,y) ((x)>(y)?(x):(y))
+
+typedef struct {
+ DB_fileinfo_t info;
+ midi *m;
+} wmidi_info_t;
+
+DB_fileinfo_t *
+wmidi_open (void) {
+ DB_fileinfo_t *_info = (DB_fileinfo_t *)malloc (sizeof (wmidi_info_t));
+ memset (_info, 0, sizeof (wmidi_info_t));
+ return _info;
+}
+
+int
+wmidi_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
+ wmidi_info_t *info = (wmidi_info_t *)_info;
+
+ info->m = WildMidi_Open (it->fname);
+ if (!info->m) {
+ fprintf (stderr, "wmidi: failed to open %s\n", it->fname);
+ return -1;
+ }
+
+ _info->plugin = &wmidi_plugin;
+ _info->channels = 2;
+ _info->bps = 16;
+ _info->samplerate = 44100;
+ _info->readpos = 0;
+
+ return 0;
+}
+
+void
+wmidi_free (DB_fileinfo_t *_info) {
+ wmidi_info_t *info = (wmidi_info_t *)_info;
+ if (info) {
+ if (info->m) {
+ WildMidi_Close (info->m);
+ info->m = NULL;
+ }
+ free (info);
+ }
+}
+
+int
+wmidi_read (DB_fileinfo_t *_info, char *bytes, int size) {
+ wmidi_info_t *info = (wmidi_info_t *)_info;
+ int bufferused = WildMidi_GetOutput (info->m, (char *)bytes, size);
+ if (bufferused < 0) {
+ fprintf (stderr, "WildMidi_GetOutput returned %d\n", bufferused);
+ return 0;
+ }
+
+ return bufferused;
+}
+
+int
+wmidi_seek_sample (DB_fileinfo_t *_info, int sample) {
+ wmidi_info_t *info = (wmidi_info_t *)_info;
+ unsigned long int s = sample;
+ WildMidi_SampledSeek (info->m, &s);
+ return 0;
+}
+
+int
+wmidi_seek (DB_fileinfo_t *_info, float time) {
+ return wmidi_seek_sample (_info, time * 44100);
+}
+
+DB_playItem_t *
+wmidi_insert (DB_playItem_t *after, const char *fname) {
+ DB_playItem_t *it = NULL;
+
+ midi *m = WildMidi_Open (fname);
+ if (!m) {
+ fprintf (stderr, "wmidi: failed to open %s\n", fname);
+ return NULL;
+ }
+
+ struct _WM_Info *inf = WildMidi_GetInfo (m);
+ it = deadbeef->pl_item_alloc ();
+ it->decoder_id = deadbeef->plug_get_decoder_id (wmidi_plugin.plugin.id);
+ it->fname = strdup (fname);
+ deadbeef->pl_add_meta (it, "title", NULL);
+ deadbeef->pl_set_item_duration (it, inf->approx_total_samples / 44100.f);
+ it->filetype = "MID";
+ after = deadbeef->pl_insert_item (after, it);
+ deadbeef->pl_item_unref (it);
+ WildMidi_Close (m);
+ return after;
+}
+
+int
+wmidi_start (void) {
+ WildMidi_Init ("/etc/timidity++/timidity-freepats.cfg", 44100, 0);
+ return 0;
+}
+
+int
+wmidi_stop (void) {
+ WildMidi_Shutdown ();
+ return 0;
+}
+
+DB_plugin_t *
+wildmidi_load (DB_functions_t *api) {
+ deadbeef = api;
+ return DB_PLUGIN (&wmidi_plugin);
+}
+
+static const char *exts[] = { "mid",NULL };
+const char *filetypes[] = { "MID", NULL };
+
+// define plugin interface
+DB_decoder_t wmidi_plugin = {
+ DB_PLUGIN_SET_API_VERSION
+ .plugin.type = DB_PLUGIN_DECODER,
+ .plugin.version_major = 0,
+ .plugin.version_minor = 1,
+ .plugin.name = "WildMidi player",
+ .plugin.descr = "MIDI player based on WildMidi library",
+ .plugin.author = "Alexey Yakovenko",
+ .plugin.email = "waker@users.sourceforge.net",
+ .plugin.website = "http://deadbeef.sf.net",
+ .plugin.start = wmidi_start,
+ .plugin.stop = wmidi_stop,
+ .plugin.id = "wmidi",
+ .open = wmidi_open,
+ .init = wmidi_init,
+ .free = wmidi_free,
+ .read_int16 = wmidi_read,
+ .seek = wmidi_seek,
+ .seek_sample = wmidi_seek_sample,
+ .insert = wmidi_insert,
+ .exts = exts,
+ .filetypes = filetypes,
+};