From 8968d2aab754943741ce3456ccd3ffe7b7d101fc Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 11 May 2001 07:43:52 +0000 Subject: [PATCH] Initial CVS version --- seq/sbiload/COPYING | 340 ++++++++++++++++++++++ seq/sbiload/Makefile | 27 ++ seq/sbiload/README | 83 ++++++ seq/sbiload/drums.o3 | Bin 0 -> 7680 bytes seq/sbiload/drums.sb | Bin 0 -> 6656 bytes seq/sbiload/make.conf | 12 + seq/sbiload/sbiload.c | 641 ++++++++++++++++++++++++++++++++++++++++++ seq/sbiload/std.o3 | Bin 0 -> 7680 bytes seq/sbiload/std.sb | Bin 0 -> 6656 bytes 9 files changed, 1103 insertions(+) create mode 100644 seq/sbiload/COPYING create mode 100644 seq/sbiload/Makefile create mode 100644 seq/sbiload/README create mode 100644 seq/sbiload/drums.o3 create mode 100644 seq/sbiload/drums.sb create mode 100644 seq/sbiload/make.conf create mode 100644 seq/sbiload/sbiload.c create mode 100644 seq/sbiload/std.o3 create mode 100644 seq/sbiload/std.sb diff --git a/seq/sbiload/COPYING b/seq/sbiload/COPYING new file mode 100644 index 0000000..eeb586b --- /dev/null +++ b/seq/sbiload/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. + + + Copyright (C) 19yy + + 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) 19yy 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. + + , 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/seq/sbiload/Makefile b/seq/sbiload/Makefile new file mode 100644 index 0000000..2121d1a --- /dev/null +++ b/seq/sbiload/Makefile @@ -0,0 +1,27 @@ +TOP = . +include $(TOP)/make.conf + +CFLAGS = $(COPTS) $(INCLUDES) +LIBS = $(ASOUND) + +OBJS = sbiload.o + + +# Build all the targets. +# +all: $(OBJS) + $(CC) -o sbiload $(CFLAGS) $(OBJS) $(LIBS) + +install: all + $(INSTALL) sbiload $(INSTDIR) + +# Remove all object files and exectutables +# +clean: + rm -f sbiload $(OBJS) core a.out + +# Remove all generated and built files. +# +clobber: clean + +sbiload.o : sbiload.c diff --git a/seq/sbiload/README b/seq/sbiload/README new file mode 100644 index 0000000..a44d4e8 --- /dev/null +++ b/seq/sbiload/README @@ -0,0 +1,83 @@ +This is sbiload - an OPL2/3 FM instrument loader for ALSA sequencer + +Written by Uros Bizjak +Web: http://www.kss-loka.si/~uros/sbiload.html + +See the file COPYING for licence details. + +Build and install +----------------- + +You should be able to just type 'make'. All configuration variables +are in make.conf if you need to change anything. + +By default it will install into /usr/local/bin, change INSTDIR in +make.conf to change this. + +Before use +---------- + +Please check that the correct sequencer modules are loaded for your +sound card. You need to load snd-synth-opl3 module. + +Usage +----- + + loadsbi [-p client:port] [-l] [-v level] instfile drumfile + + -p, --port=client:port - An ALSA client and port number to use + -4 --opl3 - Four operators (OPL3) file type + -l, --list - List possible output ports + -v, --verbose=level - Verbose level + +Because you may have more than one sound card and each sound +card may have several MIDI connections, you have to tell sbiload +which one to use. + +First find out what the possibilities are for your system: + +If you run: + + sbiload -l + +it will give you a list of the devices. On my system I get: + + Port Client name Port name + 64:0 0: MIDI Synth MIDI 0-0 + 65:0 OPL3 FM Synth OPL3 FM Synth port + + +Only OPLx FM Synth port can be used with sbiload. In the example above +the first one is the external Midi port, and the second is the internal +four-operator FM synthesizer (OPL3). + +If you don't see anything listed then check that the correct ALSA +modules are loaded as in the section "Before use". + +Running sbiload +--------------- + +You specify the port to use with the -p option, or by setting the +environment variable ALSA_OUT_PORT. + +For example to use port 0 on client 65 to load four-operator FM +instrument + + sbiload -p 65:0 --opl3 std.o3 drums.o3 + +or + + export ALSA_OUT_PORT=65:0 + sbiload --opl3 std.o3 drums.o3 + + +Acknowledgements +---------------- + +sbiload includes work from Steve Ratcliffe (pmidi-1.4.1.tar.gz) and +Jaroslav Kysela (alsamod-1999-09-01.tar.gz). + +Where to report bugs and feedback +--------------------------------- + +Please report any problems to uros@kss-loka.si diff --git a/seq/sbiload/drums.o3 b/seq/sbiload/drums.o3 new file mode 100644 index 0000000000000000000000000000000000000000..524f7a15924161a2c344486f8240941ce6b298cf GIT binary patch literal 7680 zcmeH}PiP!<6vyAp{%dRsJ1xW*OC3wae`%Xd7L>Y}O(uW#keJY2+oPG?9kPRyoj9{o z@#dlG)l|InDCFQVLG&O>6+MbtOb|iPL&1ZGZPQI{5%j&^?#yp?_NShOnL`Pb58wAb zzxQ4O5Pz|O*g$L`HV_+#4a5fi+rZ??>ex(8oz-1eopZbm6~BNg;+KLm7nMh$v42ua z!5F~wbnxHAaxh0|KbwZ9iqa^uk1WV=YJe@9bwe$;%-X9A?Pp~u$jJ;m`03Nn0Y>}S zJgeFETtwA!Q+JF|Zegxil;GLp(hWE`Y#(OeR5m*d?JY_oC@AWIpC0AiM!uqa+tmf!$L)G5csG>4l zhkzwl5)_7HDBixC)8xoJvzera4ao}F30Cvuztwz^_K3&w+&p6o)47Mx)$U!9E3IKR z4L86!OEqJ?1tkS;b@x3H%W`K8%Zlz1vDokEi50kWM{h;yU$-Ji9a>vqI5L@%owB80mzqG$0l;?I`o$ax2iP&YYWpwvf!*HFmR5R@$ z9D@({=jTN%-~9+nyO5xJbrjjT1rbX%cPT-??8Y)yn9E#MOj=(ymEeC=a}vh3lq{?{ zH}_=0T(Min(f)o@FtVj6$bPpkVp;CYx;^+tY!{|_p5I9b?gr(CP@YS7Qi5|nE80O# zuj;Pe^+f;r?E-mD!gIU11n%Gm`=T9O)*Zd3y8+DERmy#NPPqy{cdlL$vE_#CwA9ND z(`_-)0ZX1UusAh&941~#rlP-p>256HG=)%JGqJ<4c;@sGsN0v)lE76rchNJQ?lSb{ zrXm02X@G6>>r4Vp4(vY5&-`yOP)in(&<50 zY=8fW9flVk&w;#c-pZuYgSVaKRvc4ruJ_Ld%_QFEBSSaf_Mhz$(S2sQA~uhEgzRwU iTVj)P#Bf=?k(O3>lLe(NW_Bl=tdJP##`b7ucZclYWGBw- zR=f#TJ-6beN1+E#l28;8MWvoZEX4#V2zn4acu1OVV~e2g_ulTj-;7Jaqd0SzJ-qqw zeZTMT_kC{x9`G23@qpFgO9=yzc#wF2=}6`v@gSK4aZmgQvrsF)Fj;EoWh)5uS--og zvqu!e-dIl>j+d23ptW_hqQRql2^k6G5s5M*aKca~81wL)N|>6{wDnrYX}ro2$rP#v zs8Cc>8MuGzvo8Q9LY-2>>jn(bYi-N7iB66&%3IGJVPEe4vHc0vsaox(Zo1Z*kfA!y zGM$o=&cKx`AAd@jifcDI{t%tQ0_qfxXaGBVQJn?vb$!nDJYQe-&^W$ne4%d|99NV> z@Y~hj_W;KE68dJkUSK!%sE;`&b!G({(~vO?6BH

`$SrSF>Wc(0`1RKOo#dQ7|X(I z_4SAcXPr8uhGZK((BSmXzhLH;-={N5`@>}9-UMS5^P{Xk>yiHOIVgMW6))x+GAUql zZ~*S#b>9I}59Ws;Q5^+N^_jORv)Jv}B0nY*vm{gC**>YjA^32sQlX5@T%2L^rr~*T zfHAXkl)=4;uVeL~4nM0n6VVY_a4WYB{Q%ui1}1i4pI zX?p)Gu + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Load a SBI FM instrument patch + * sbiload [-p client:port] [-4] [-l] [-v level] instfile drumfile + * + * -p client:port - An ALSA client and port number to load instrument to + * -4 - four operators file type + * -l - List possible output ports that could be used + * -v level - Verbose level + */ + +typedef struct sbi_header +{ + char key[4]; + char name[32]; +} +sbi_header_t; + +typedef struct sbi_inst +{ + sbi_header_t header; +#define DATA_LEN_2OP 16 +#define DATA_LEN_4OP 24 + char data[DATA_LEN_4OP]; +} +sbi_inst_t; + +/* offsets for SBI params */ +#define AM_VIB 0 +#define KSL_LEVEL 2 +#define ATTACK_DECAY 4 +#define SUSTAIN_RELEASE 6 +#define WAVE_SELECT 8 + +/* offset for SBI instrument */ +#define CONNECTION 10 +#define OFFSET_4OP 11 + +/* offsets in sbi_header.name for SBI extensions */ +#define ECHO_DELAY 25 +#define ECHO_ATTEN 26 +#define CHORUS_SPREAD 27 +#define TRNSPS 28 +#define FIX_DUR 29 +#define MODES 30 +#define FIX_KEY 31 + +/* Options for the command */ +#define HAS_ARG 1 +static struct option long_opts[] = { + {"port", HAS_ARG, NULL, 'p'}, + {"opl3", 0, NULL, '4'}, + {"list", 0, NULL, 'l'}, + {"verbose", HAS_ARG, NULL, 'v'}, + {0, 0, 0, 0}, +}; + +/* Number of elements in an array */ +#define NELEM(a) ( sizeof(a)/sizeof((a)[0]) ) + +#define ADDR_PARTS 4 /* Number of part in a port description addr 1:2:3:4 */ +#define SEP ", \t" /* Separators for port description */ + +#define SBI_FILE_TYPE_2OP 0 +#define SBI_FILE_TYPE_4OP 1 + +/* Default file type */ +int file_type = SBI_FILE_TYPE_2OP; + +/* Default verbose level */ +int verbose = 0; + +/* Global declarations */ +snd_seq_t *seq_handle; + +int seq_client; +int seq_port; +int seq_dest_client; +int seq_dest_port; + +/* Function prototypes */ +static void show_list (); +static void show_usage (); +static void show_op (fm_instrument_t * fm_instr); + +static int load_patch (fm_instrument_t * fm_instr, int bank, int prg, char *name); +static int load_file (int bank, char *filename); +static int parse_portdesc (char *portdesc); + +static int init_client (); + +static void +error_handler (const char *file, int line, const char *function, int err, const char *fmt, ...) +{ + /* ignore */ +} + +/* + * Show a list of possible output ports that midi could be sent to. + */ +static void +show_list () { + snd_seq_client_info_t cinfo; + snd_seq_port_info_t pinfo; + snd_seq_system_info_t sysinfo; + int client, port, err; + + snd_lib_error_set_handler (error_handler); + if ((err = snd_seq_open (&seq_handle, "hw", SND_SEQ_OPEN_DUPLEX, 0)) < 0) { + fprintf (stderr, "Could not open sequencer: %s\n", snd_strerror (err)); + return; + } + + if ((err = snd_seq_system_info (seq_handle, &sysinfo)) < 0) { + snd_seq_close (seq_handle); + fprintf (stderr, "Could not get sequencer information: %s\n", + snd_strerror (err)); + return; + } + + printf (" Port %-30.30s %s\n", "Client name", "Port name"); + for (client = 0; client < sysinfo.clients; client++) { + if (snd_seq_get_any_client_info (seq_handle, client, &cinfo) < 0) + continue; + + for (port = 0; port < sysinfo.ports; port++) { + int cap; + + if (snd_seq_get_any_port_info (seq_handle, client, port, &pinfo) < 0) + continue; + + cap = (SND_SEQ_PORT_CAP_SUBS_WRITE | SND_SEQ_PORT_CAP_WRITE); + if ((pinfo.capability & cap) == cap) { + printf ("%3d:%-3d %-30.30s %s\n", + pinfo.client, pinfo.port, cinfo.name, pinfo.name); + } + } + } + snd_seq_close (seq_handle); +} + +/* + * Show usage message + */ +static void +show_usage () { + char **cpp; + static char *msg[] = { + "Usage: sbiload [-p client:port] [-4] [-l] [-v level] instfile drumfile", + "", + " -p client:port - A alsa client and port number to send midi to", + " -4 - four operators file type (default = two ops)", + " -l - List possible output ports that could be used", + " -v level - Verbose level (default = 0)", + }; + + for (cpp = msg; cpp < msg + NELEM (msg); cpp++) { + fprintf (stderr, "%s\n", *cpp); + } +} + +/* + * Show instrument FM operators + */ +static void +show_op (fm_instrument_t * fm_instr) { + int i = 0; + + do { + printf (" OP%i: flags: %s %s %s %s\011OP%i: flags: %s %s %s %s\n", + i, + fm_instr->op[i].am_vib & (1 << 7) ? "AM" : " ", + fm_instr->op[i].am_vib & (1 << 6) ? "VIB" : " ", + fm_instr->op[i].am_vib & (1 << 5) ? "EGT" : " ", + fm_instr->op[i].am_vib & (1 << 4) ? "KSR" : " ", + i + 1, + fm_instr->op[i + 1].am_vib & (1 << 7) ? "AM" : " ", + fm_instr->op[i + 1].am_vib & (1 << 6) ? "VIB" : " ", + fm_instr->op[i + 1].am_vib & (1 << 5) ? "EGT" : " ", + fm_instr->op[i + 1].am_vib & (1 << 4) ? "KSR" : ""); + printf (" OP%i: MULT = 0x%x" "\011\011OP%i: MULT = 0x%x\n", + i, fm_instr->op[i].am_vib & 0x0f, + i + 1, fm_instr->op[i + 1].am_vib & 0x0f); + printf (" OP%i: KSL = 0x%x TL = 0x%.2x\011OP%i: KSL = 0x%x TL = 0x%.2x\n", + i, (fm_instr->op[i].ksl_level >> 6) & 0x03, fm_instr->op[i].ksl_level & 0x3f, + i + 1, (fm_instr->op[i + 1].ksl_level >> 6) & 0x03, fm_instr->op[i + 1].ksl_level & 0x3f); + printf (" OP%i: AR = 0x%x DL = 0x%x\011OP%i: AR = 0x%x DL = 0x%x\n", + i, (fm_instr->op[i].attack_decay >> 4) & 0x0f, fm_instr->op[i].attack_decay & 0x0f, + i + 1, (fm_instr->op[i + 1].attack_decay >> 4) & 0x0f, fm_instr->op[i + 1].attack_decay & 0x0f); + printf (" OP%i: SL = 0x%x RR = 0x%x\011OP%i: SL = 0x%x RR = 0x%x\n", + i, (fm_instr->op[i].sustain_release >> 4) & 0x0f, fm_instr->op[i].sustain_release & 0x0f, + i + 1, (fm_instr->op[i + 1].sustain_release >> 4) & 0x0f, fm_instr->op[i + 1].sustain_release & 0x0f); + printf (" OP%i: WS = 0x%x\011\011OP%i: WS = 0x%x\n", + i, fm_instr->op[i].wave_select & 0x07, + i + 1, fm_instr->op[i + 1].wave_select & 0x07); + printf (" FB = 0x%x, %s\n", + (fm_instr->feedback_connection[i / 2] >> 1) & 0x07, + fm_instr->feedback_connection[i / 2] & (1 << 0) ? "parallel" : "serial"); + i += 2; + } + while (i == (fm_instr->type == FM_PATCH_OPL3) << 1); + + printf (" Extended data:\n" + " ED = %.3i EA = %.3i CS = %.3i TR = %.3i\n" + " FD = %.3i MO = %.3i FK = %.3i\n", + fm_instr->echo_delay, fm_instr->echo_atten, fm_instr->chorus_spread, fm_instr->trnsps, + fm_instr->fix_dur, fm_instr->modes, fm_instr->fix_key); +} + +/* + * Check the result of the previous instr event + */ +static int +check_result (int evtype) { + snd_seq_event_t *pev; + int err; + + for (;;) { + if ((err = snd_seq_event_input (seq_handle, &pev)) < 0) { + fprintf (stderr, "Unable to read event input: %s\n", + snd_strerror (err)); + return -ENXIO; + } + if (pev->type == SND_SEQ_EVENT_RESULT && pev->data.result.event == evtype) + break; + snd_seq_free_event (pev); + } + err = pev->data.result.result; + snd_seq_free_event (pev); + + return err; +} + +/* + * Send patch to destination port + */ +static int +load_patch (fm_instrument_t * fm_instr, int bank, int prg, char *name) { + snd_seq_instr_put_t *put; + snd_seq_event_t ev; + + size_t size; + int err; + + if (verbose > 1) { + printf ("%.3i: [OPL%i] %s\n", prg, fm_instr->type == FM_PATCH_OPL3 ? 3 : 2, name); + show_op (fm_instr); + } + + if ((err = snd_instr_fm_convert_to_stream (fm_instr, name, &put, &size)) < 0) { + fprintf (stderr, "Unable to convert instrument %.3i to stream: %s\n", + prg, snd_strerror (err)); + return -1; + } + put->id.std = SND_SEQ_INSTR_TYPE2_OPL2_3; + put->id.prg = prg; + put->id.bank = bank; + + /* build event */ + memset (&ev, 0, sizeof (ev)); + ev.source.client = seq_client; + ev.source.port = seq_port; + ev.dest.client = seq_dest_client; + ev.dest.port = seq_dest_port; + + ev.flags = SND_SEQ_EVENT_LENGTH_VARUSR; + ev.queue = SND_SEQ_QUEUE_DIRECT; + +__again: + ev.type = SND_SEQ_EVENT_INSTR_PUT; + ev.data.ext.len = size; + ev.data.ext.ptr = put; + + if ((err = snd_seq_event_output (seq_handle, &ev)) < 0) { + fprintf (stderr, "Unable to write an instrument %.3i put event: %s\n", + prg, snd_strerror (err)); + return -1; + } + + if ((err = snd_seq_drain_output (seq_handle)) < 0) { + fprintf (stderr, "Unable to write instrument %.3i data: %s\n", prg, + snd_strerror (err)); + return -1; + } + + err = check_result (SND_SEQ_EVENT_INSTR_PUT); + if (err >= 0) { + if (verbose) + printf ("Loaded instrument %.3i, bank %.3i: %s\n", prg, bank, name); + return 0; + } else if (err == -EBUSY) { + snd_seq_instr_free_t remove; + + memset (&remove, 0, sizeof (remove)); + remove.cmd = SNDRV_SEQ_INSTR_FREE_CMD_SINGLE; + remove.data.instr = put->id; + + /* remove instrument */ + ev.type = SND_SEQ_EVENT_INSTR_FREE; + ev.data.ext.len = sizeof (remove); + ev.data.ext.ptr = &remove; + + if ((err = snd_seq_event_output (seq_handle, &ev)) < 0) { + fprintf (stderr, "Unable to write an instrument %.3i free event: %s\n", + prg, snd_strerror (err)); + return -1; + } + + if ((err = snd_seq_drain_output (seq_handle)) < 0) { + fprintf (stderr, "Unable to write instrument %.3i data: %s\n", prg, + snd_strerror (err)); + return -1; + } + + if ((err = check_result (SND_SEQ_EVENT_INSTR_FREE)) < 0) { + fprintf (stderr, "Instrument %.3i, bank %.3i - free error: %s\n", + prg, bank, snd_strerror (err)); + return -1; + } + goto __again; + } + + fprintf (stderr, "Instrument %.3i, bank %.3i - put error: %s\n", + prg, bank, snd_strerror (err)); + return -1; +} + +/* + * Parse standard .sb or .o3 file + */ +static void +load_sb (int bank, int fd) { + int len, i; + int prg; + + sbi_inst_t sbi_instr; + fm_instrument_t fm_instr; + int fm_instr_type; + + len = (file_type == SBI_FILE_TYPE_4OP) ? DATA_LEN_4OP : DATA_LEN_2OP; + for (prg = 0;; prg++) { + if (read (fd, &sbi_instr.header, sizeof (sbi_header_t)) < sizeof (sbi_header_t)) + break; + + if (!strncmp (sbi_instr.header.key, "SBI\032", 4) || !strncmp (sbi_instr.header.key, "2OP\032", 4)) { + fm_instr_type = FM_PATCH_OPL2; + } else if (!strncmp (sbi_instr.header.key, "4OP\032", 4)) { + fm_instr_type = FM_PATCH_OPL3; + } else { + fm_instr_type = 0; + if (verbose) + printf ("%.3i: wrong instrument key!\n", prg); + } + + if (read (fd, &sbi_instr.data, len) < len) + break; + + if (fm_instr_type == 0) + continue; + + memset (&fm_instr, 0, sizeof (fm_instr)); + fm_instr.type = fm_instr_type; + + for (i = 0; i < 2; i++) { + fm_instr.op[i].am_vib = sbi_instr.data[AM_VIB + i]; + fm_instr.op[i].ksl_level = sbi_instr.data[KSL_LEVEL + i]; + fm_instr.op[i].attack_decay = sbi_instr.data[ATTACK_DECAY + i]; + fm_instr.op[i].sustain_release = sbi_instr.data[SUSTAIN_RELEASE + i]; + fm_instr.op[i].wave_select = sbi_instr.data[WAVE_SELECT + i]; + } + fm_instr.feedback_connection[0] = sbi_instr.data[CONNECTION]; + + if (fm_instr_type == FM_PATCH_OPL3) { + for (i = 0; i < 2; i++) { + fm_instr.op[i + 2].am_vib = sbi_instr.data[OFFSET_4OP + AM_VIB + i]; + fm_instr.op[i + 2].ksl_level = sbi_instr.data[OFFSET_4OP + KSL_LEVEL + i]; + fm_instr.op[i + 2].attack_decay = sbi_instr.data[OFFSET_4OP + ATTACK_DECAY + i]; + fm_instr.op[i + 2].sustain_release = sbi_instr.data[OFFSET_4OP + SUSTAIN_RELEASE + i]; + fm_instr.op[i + 2].wave_select = sbi_instr.data[OFFSET_4OP + WAVE_SELECT + i]; + } + fm_instr.feedback_connection[1] = sbi_instr.data[OFFSET_4OP + CONNECTION]; + } + + fm_instr.echo_delay = sbi_instr.header.name[ECHO_DELAY]; + fm_instr.echo_atten = sbi_instr.header.name[ECHO_ATTEN]; + fm_instr.chorus_spread = sbi_instr.header.name[CHORUS_SPREAD]; + fm_instr.trnsps = sbi_instr.header.name[TRNSPS]; + fm_instr.fix_dur = sbi_instr.header.name[FIX_DUR]; + fm_instr.modes = sbi_instr.header.name[MODES]; + fm_instr.fix_key = sbi_instr.header.name[FIX_KEY]; + + if (load_patch (&fm_instr, bank, prg, sbi_instr.header.name) < 0) + break; + } + return; +} + +/* + * Load file + */ +static int +load_file (int bank, char *filename) { + int fd; + + fd = open (filename, O_RDONLY); + if (fd == -1) { + perror (filename); + return -1; + } + + load_sb(bank, fd); + + close (fd); + return 0; +} + +/* + * Parse port description + */ +static int +parse_portdesc (char *portdesc) { + char *astr; + char *cp; + int a[ADDR_PARTS]; + int count, naddr; + int i; + + if (portdesc == NULL) + return -1; + + for (astr = strtok (portdesc, SEP); astr; astr = strtok (NULL, SEP)) { + for (cp = astr, count = 0; cp && *cp; cp++) { + if (count < ADDR_PARTS) + a[count++] = atoi (cp); + cp = strchr (cp, ':'); + if (cp == NULL) + break; + } + + if (count == 2) { + seq_dest_client = a[0]; + seq_dest_port = a[1]; + } else { + printf ("Addresses in %d parts not supported yet\n", count); + return -1; + } + } + return 0; +} + +/* + * Open sequencer, create client port and + * subscribe client to destination port + */ +static int +init_client () { + snd_seq_client_info_t cinfo; + snd_seq_port_info_t port; + snd_seq_port_subscribe_t sub; + int err; + + if ((err = snd_seq_open (&seq_handle, "hw", SND_SEQ_OPEN_DUPLEX, 0)) < 0) { + fprintf (stderr, "Could not open sequencer: %s\n", snd_strerror (err)); + return -1; + } + + seq_client = snd_seq_client_id (seq_handle); + if (seq_client < 0) { + snd_seq_close (seq_handle); + fprintf (stderr, "Unable to determine my client number: %s\n", + snd_strerror (err)); + return -1; + } + + memset (&cinfo, 0, sizeof (cinfo)); + cinfo.client = seq_client; + cinfo.type = USER_CLIENT; + snprintf (cinfo.name, sizeof (cinfo.name), "sbiload - %i", getpid ()); + if ((err = snd_seq_set_client_info (seq_handle, &cinfo)) < 0) { + snd_seq_close (seq_handle); + fprintf (stderr, "Unable to set client info: %s\n", + snd_strerror (err)); + return -1; + } + + memset (&port, 0, sizeof (port)); + strcpy (port.name, "Output"); + port.capability |= SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_WRITE; + if ((err = snd_seq_create_port (seq_handle, &port)) < 0) { + snd_seq_close (seq_handle); + fprintf (stderr, "Unable to create a client port: %s\n", + snd_strerror (err)); + return -1; + } + + seq_port = port.port; + + memset (&sub, 0, sizeof (sub)); + sub.sender.client = seq_client; + sub.sender.port = seq_port; + sub.dest.client = seq_dest_client; + sub.dest.port = seq_dest_port; + sub.exclusive = 1; + + if ((err = snd_seq_subscribe_port (seq_handle, &sub)) < 0) { + snd_seq_close (seq_handle); + fprintf (stderr, "Unable to subscribe destination port: %s\n", + snd_strerror (errno)); + + return -1; + } + + if ((err = snd_seq_get_any_port_info (seq_handle, seq_dest_client, seq_dest_port, &port)) < 0) { + snd_seq_close (seq_handle); + fprintf (stderr, "Unable to get destination port: %s\n", + snd_strerror (err)); + return -1; + } + return 0; +} + +/* + * Load a .SBI FM instrument patch + * sbiload [-p client:port] [-l] [-v level] instfile drumfile + * + * -p, --port=client:port - An ALSA client and port number to use + * -4 --opl3 - four operators file type + * -l, --list - List possible output ports that could be used + * -v, --verbose=level - Verbose level + */ +int +main (int argc, char **argv) { + char opts[NELEM (long_opts) * 2 + 1]; + char *portdesc; + char *cp; + int c; + struct option *op; + + /* Build up the short option string */ + cp = opts; + for (op = long_opts; op < &long_opts[NELEM (long_opts)]; op++) { + *cp++ = op->val; + if (op->has_arg) + *cp++ = ':'; + } + + portdesc = NULL; + + /* Deal with the options */ + for (;;) { + c = getopt_long (argc, argv, opts, long_opts, NULL); + if (c == -1) + break; + + switch (c) { + case 'p': + portdesc = optarg; + break; + case '4': + file_type = SBI_FILE_TYPE_4OP; + break; + case 'v': + verbose = atoi (optarg); + break; + case 'l': + show_list (); + exit (0); + case '?': + show_usage (); + exit (1); + } + } + + if (portdesc == NULL) { + portdesc = getenv ("ALSA_OUT_PORT"); + if (portdesc == NULL) { + fprintf (stderr, "No client/port specified.\n" + "You must supply one with the -p option or with the\n" + "environment variable ALSA_OUT_PORT\n"); + exit (1); + } + } + + /* Parse port description to dest_client and dest_port */ + if (parse_portdesc (portdesc) < 0) { + return 1; + } + + /* Initialize client and subscribe to destination port */ + if (init_client () < 0) { + return 1; + } + + /* Process instrument and drum file */ + if (optind < argc) { + if (load_file (0, argv[optind++]) < 0) { + snd_seq_close (seq_handle); + return 1; + } + } + if (optind < argc) { + if (load_file (128, argv[optind]) < 0) { + snd_seq_close (seq_handle); + return 1; + } + } + + /* Unsubscribe destination port and close client */ + snd_seq_close (seq_handle); + + return 0; +} diff --git a/seq/sbiload/std.o3 b/seq/sbiload/std.o3 new file mode 100644 index 0000000000000000000000000000000000000000..b718dd646ce8c0d6708b9ba0f3630bd54ca114a8 GIT binary patch literal 7680 zcmZ{pU2GfIm4NRhht#DdJETlfmh8GSk}StngNic!v#_xGm#Nl{6^XW$07W$-hvdW* zhaHkqlom?LTR3skw2MV|lh{p~yvQW= z6DgMW+?hLfsGrV*bOhm>bMCq4@7@U?8EWW`X@y)~jfn?!ITIH}WId7n-|Pap2?xmC zr~YBqiM&qyZBi`nnMHyRp)jyLx|&SoMg9s4MT~XgeSEC9eBCB-5Y8QY&$VtJkG z9a80tX7J$wL$4DbCQGHGZwQqA9lYk~`<#tvnG@3wp*DjJ;^X9A=?4jfwpE{MCAUAiat0yB_NFwwkW=D}w%M+)8|()B z9a1ho4FK5u4k>VdJE3H9Syf3}nDKk4%Vg^w+3<(b$cVuXl6OnP!<;=_fYpv`kFDV7AK@XB z^*=)9VsoI(yVW;LZdU3&rjF}!Hl<~hRrLO-!9MfUBjkfSfpfq++;X?*X@Kthm?pO-gbEmq<^2|;bXGf>g+Ing&n~C!(SzI^JpU zEUtzWJyyu&)Jes}x!GTj7`_sk>&Wu_>q*L9@RKj*+*O<%hS0E-uE?Vf(O@r%+sQ93 z@1=TQ6&uL()I)~^OK)$gpvO|2=4w&YWOuySMDk-k*qGW^UbzWktxLdG{wk1vY_Ti! zj+tzu)Et?dbh{z19~NCC%lG=Om9@qBsD0LYqXDM>>`WGbI)^M9hp@0xDMf* zS;cpSjhK|AUqyL%j}v$(>rzs14xf(!P@L+0rIS}{4KLjH2Hf@M8a zf{o!US;-FQN*=mOj`5aOgra62#P~WXUVHRBqWkM3&lW$K;IT21ma`@oT46HZ-)c9x zyEyo?TcB|Tz5DeSjQyp)ve|Z9CzU$Pp3)*Uleyy4^N@qoSEbSmFE}h;jZA0qDW-S@ z++p?3g-W1?ttdM*NQV``-?N$l{8!ypvTb9y9eeOK*G6CR&2PhNWxXGl_)F zLf=no)WhuIYqshnetVn#oq;og5NwqGi%drMRSU{x2p<m_nR=tn|> zC~YILm`mWfe@s(jFluOPSk_Y{DM&6&C19xXiqaoRBDL3^ugn}Y-vArMmuuAxNvb7< zq`^wk17y6C<*^|~R2ZUdmYq`^coUh7hxb5Vz~}*zi0u*V*w70TStV~XmJ~JTc1da? zy8iqDO#6NlIsMO6WP23VwTbbyQ!M2E{j47~k=Qt6C6YT`$ri>dQ{OiFkm+ZP{bc+v z)vYd9P-@&vj_O-mxy@z|jjpx4&+H3W@@*L#U;3U4dWz(&8yi0WBG^o8EY$W4%w`cy zUsbetOg543Q$L{iWK?5xo!ABq(2?0X%PAz?1QL zcX=q={NLo{Nnov+pN<+D3|H*oZnpLaH*c;PJK1QmXSSR?>9W~gI9RQF{v9%Np*{2! za`B;Hi+~#1L;Ym==x~7N0?auv+K>L0-sX!UNh))+<}_d2MxIFSv}?{l8irBZQd?ra zYJ9Q9tC%&%A$`qzQLCs|!wQ}D72SrI6lJ*|@@@U6lu@tRL-pkS)Zf{9hhTa(bel%o zujnvqj(7nDrl!a!`7}dgH%4O*0r|OHs_Klm{qnnO8&aU z*uZOik494Ri9$+_rPN9gWVT-U#h@=abEbr=Qw zGo^*=V1n)E{UY4yg*&1u`VQ61hL;J%`4yEp|WcO#Lw$yPk$&=w*!j!@PY`aO}P zk$xVN!0r~aT6#K18ir{ERrs987M5(&=q-`Wc-mIi8WcZFfVVtWL7_lgrrp2lR1 zzZC?=N>UezwLQ5RSV^k$#JYa6*=5Zt)aHF+N@k_frkTxah>;MDW2!& z-yS*hDDT`WY-V$;i|i;bTv`%P06V;JkF@kAjPPb$K`)z7bIPhA7SyvDSg7*AT`sLx zekeO|&u|VtHL(5tmIia3{n$2J_Zw92;!8_{5Wsi~+_%rt&lINKZ^>zT|7_8 ziO9l2CPVKi&LB^DKKL1rs~$O-RiT%#$0FhG%bc%#?R1zcK?1;h^;S*S5X@JW%>!yY zzFzyaVxw7ntLA6tMhWyX5XqbR+527Axf^_yk=Hr?TI>qF@6?Qq!JVq5H>ze%(0K!{ z8>rb8Hk*4CtUm$=X5$+{z~4>oz&8T7)qlH_8r+MnxiN?Jn)f+%wTLXv9)~%{>#yx1 z^RvSbbJo1u?1MATs$5__h2XD}-=5wF-w1*(-+lKf!$%9;&&M?_K2E=F*w&g7+am{D zmVG(@hk2;&RnE?Pi?a_dBZSTUjmqi?O{98P!HjKagS*Yr@hHMRpEp9@cw_iD&!fXi zT8qOcuc)@FAu+bL4Z}CDmq%c|Uhh3pzBYWE+iae3s9qyFY~@{MoouZ}C;36l`w6-VKS#U;NqV zWyW2fBIn>^+1g|(MaMX^@2;B*li=ejBEQkzSQw` zuI*$&n%0(A2HRNKTBflNO9~yDkSLGBr%5pOM$^V)tkS*^s#e;kg}hqmSoc4Vd(N@j z`@wQ#|NMVH&PlZYTif~)PI13$W|I-y%sRS`yr;8gI1KN#`tA6==UU=E?Q8Utj*-Z= ze%GEz7X;}M2*vgclRql7@8Xq}wKe3gN9g|h5n%>1Rzi^@nLwB`Cce71w&quukdr+! zdshKosd5U_%b9=Tm1W69!Je_SleF?Ww??%mG~5Zl(6#Yn{L|-7#C?d_LzrONaf^8? z=}|&ZxD({~P(wY!i_axoAKF4cBKCw#HdchbTeOfHT)GXFMqy_5X1)_!VDBM3479VnG2Kv zJ*-3S+=jOLeqQs&($gPl+HHafnUj-FHmQ%e6J}PG6X~YDZZ$u~$IPlT6=)$l-N5W zsmdy^9}r(d{ea)>gqI0Ixp0`Y9n}1K6YgvG`zti&H)2oB%uYDEkR}k+%X)}md<{>h z{9F7={g5t|FF0!G0wT<|z<=`1Luge%IC)7=Ap#^IDzpE2}sPM@;Eo1fy-2$xU zG_4A+ukUR0Ymyn6w%nvk(v3MmFaxZQ8pgX&3yqt-_z-&r?0ms-q4$t1M~SMaBo)m*LCi>>8t-$WHqKRn-rulvnB)Tu{6EifNw+6H|7_^H$l{YDuXQq&ot ze$%vCyuAMWCDjMQZq1WC4v=#vT9|(yKR()c5c#&zkBFRz{ph36sR|w?8D`JtpW(T+ zuU>uy@%?}>BhYzaaJy!P)I(0n>F%NSH2Z4s$G_{`p`lxaoR~eCGqbbT`yfK(97Xl@ z2XWwRjlZHo>c;HQ2eWx=GM=$yF;E}uLh*%XLQ}!L7d2(hl`*myD03$=jTvzgjMdI-%o4}pxMACMOwAI)gQqXSKTFRy7#(~j-xeP)^rZFmF|A-m;+ zXyx6LxFgs*aM@fROQe1|0rs|7}u$O*BSetO{m9q{7lO;~*))N8U0!T;I`0}Z9FeBtFiMhqeoLKo3CPeH($e6zkN5?k7+?G2< z%ylN?-d3f`>1DbZ3)|+RW4GRikjw+vchr)Tx^Z6{hJh1L{9unN=RmOl!(M7A>=|G= zx_IGdcimBUq^=Vqq!G;+y?uOoZC?+ z2d5vXY?E!iLQpT8bDFOS=W-V>RVur3Uxu^-4yd~ES+8lE@X<0RW@Q~$LP8AkjKm$bjgzE?M=(9io~h)YarT+UYQ*;{B4;o= zk+JhKsDg>HxiEja4No0^>3J`&Nqopibi9pE5rf8AUTdw5cWIbQ*lk<|)nVw0WeMHWO)^2`ZP#f!RWx18GIars zv)nn+`25_ie&33hJ483ibm)0=rrwF(Os5WhOQpaMLJaC*`{)P1MELEeQdK^_Ukly3fH9#hOejz{lY^Q@ z@YGnefRwpFP5S zMvb5Ag>KzC9JtmsDL^9`6Kw?iK#vqa8?2n|oxn$gV(k`3i@jQQ<&^mx;tdj26y zhdu)*G$KV|=nO_^asD*UTF+K_@gccGn7w+=$;{@-rXa+i0NWFFt*-vPrPVdH<_JT= zLneNy9FjYS(C5E}xt-{Rc`Ele!gRqs#f+8A!Q1QXSzI`P*}fz95W?)!C#?cWo`gia zJ;X2ua3b&+%q(_hBEBZfy?Wa8T8}V@_v==pwQjaVV)QmSsiK=nAqY!dcMxE2t)aXG7tG2FKF zoBeQkM?WI=00Y(I&ca<1xf7BMx983Io1nkVfjuQmr*0M|oqR5Bxk}A(IW5M&pzoCW z0OUY;=mlYx9G%K_Yc-m0#O%{2oH!gbO7oh_xfH0aZCg4w=*?|z&%L?@xdWGdCH8RU zLM}4bwsaPl5_=##3Hz=TYoz76UHY`CCKs>1?ByGYPn6smPzj}CP=K8q+q8{!m#+jX z)%%csGy8~gmJwo551&79S+{!SOqZY3HlK6Rv^i<#EuIF_ZHUfo8~Lki>b|^k2KqI- zPb5Bgz=1tPd4!-|)_alGShu{|xTgB;0W+iCzezzM)~k@Vfiui+#0UN6M9zku%O4@e zn+pvcb#;F~x(s_2Fx;LYJDI%E`0;A4-Ux$I6Q`HTZuQVx$Ple1DH zCuV1lka-HnN1~o&_?^(^EhBin?5?wK!hw4v?`BY8y2G^Qwrqqm`r6@f&mQ9IXu*QZ z)B)J$%kqua4?;KNmp^%67-?*`B+OyQNyf=tY`Nn&(@{T+udH4Bo|kWgiJA5hhst4) zFsPU18s6GdjFC-v-(}jgtdTvpJ-RkJp7;Drq^E2zu>Eob0KP(dAN+fK1sQpSI_otm>-M6 zos?wyZMeLTLA&NR@?~;*Q1#t->Dx=7n`B~E#!~L0rEc5@7juo!LpEIV;zRrvvS92u zxq`P{mdbgQd=;l(`r8q8F7)Mc858~~aS!u?K)m|dy%XW%GdJCYDnU0MpZ&!w_`v)3 Sg5o!kqqX?Ub>~@6xBmkbVAkXS literal 0 HcmV?d00001 -- 2.47.1