# HG changeset patch # User hercules # Date 1064609518 0 # Node ID cbc2a4ffeeec4b06d0727a294f70c06d1bb48181 # Parent 6bd7ca7d218be064817b4966377eddcd42aeeda6 * Added support for loading DLS format instruments: Timidity_LoadDLS(), Timidity_FreeDLS(), Timidity_LoadDLSSong() * Added Timidity_Init_NoConfig() diff -r 6bd7ca7d218b -r cbc2a4ffeeec decoders/timidity/CHANGES --- a/decoders/timidity/CHANGES Sat Sep 13 20:46:09 2003 +0000 +++ b/decoders/timidity/CHANGES Fri Sep 26 20:51:58 2003 +0000 @@ -1,5 +1,5 @@ This version of TiMidity should contain all the fixes from the -December 13 2001 SDL_mixer CVS snapshot. In addition, I've made some +September 25 2003 SDL_mixer CVS snapshot. In addition, I've made some changes of my own, e.g.: * All file access is done through SDL_RWops. This means the MIDI @@ -70,3 +70,8 @@ * config.h has been renamed as options.h to avoid confusion with the automatically generated config.h for SDL_sound. + +* Added support for loading DLS format instruments: + Timidity_LoadDLS(), Timidity_FreeDLS(), Timidity_LoadDLSSong() + +* Added Timidity_Init_NoConfig() diff -r 6bd7ca7d218b -r cbc2a4ffeeec decoders/timidity/COPYING --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/decoders/timidity/COPYING Fri Sep 26 20:51:58 2003 +0000 @@ -0,0 +1,519 @@ +Please note that the included source from Timidity, the MIDI decoder, is also + licensed under the following terms (GNU LGPL), but can also be used + separately under the GNU GPL, or the Perl Artistic License. Those licensing + terms are not reprinted here, but can be found on the web easily. + +If you want to use SDL_sound under a closed-source license, please contact + Ryan (icculus@clutteredmind.org), and we can discuss an alternate license for + money to be distributed between the contributors to this work, but I'd + encourage you to abide by the LGPL, since the usual concern is whether you + can use this library without releasing your own source code (you can). + + +------------------- + + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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) + + 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 + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff -r 6bd7ca7d218b -r cbc2a4ffeeec decoders/timidity/Makefile.am --- a/decoders/timidity/Makefile.am Sat Sep 13 20:46:09 2003 +0000 +++ b/decoders/timidity/Makefile.am Fri Sep 26 20:51:58 2003 +0000 @@ -6,8 +6,12 @@ libtimidity_la_SOURCES = \ common.c \ common.h \ + dls1.h \ + dls2.h \ instrum.c \ instrum.h \ + instrum_dls.c \ + instrum_dls.h \ mix.c \ mix.h \ options.h \ diff -r 6bd7ca7d218b -r cbc2a4ffeeec decoders/timidity/dls1.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/decoders/timidity/dls1.h Fri Sep 26 20:51:58 2003 +0000 @@ -0,0 +1,266 @@ +/*==========================================================================; +// +// dls1.h +// +// +// Description: +// +// Interface defines and structures for the Instrument Collection Form +// RIFF DLS. +// +// +// Written by Sonic Foundry 1996. Released for public use. +// +//=========================================================================*/ + +#ifndef _INC_DLS1 +#define _INC_DLS1 + +/*////////////////////////////////////////////////////////////////////////// +// +// +// Layout of an instrument collection: +// +// +// RIFF [] 'DLS ' [dlid,colh,INSTLIST,WAVEPOOL,INFOLIST] +// +// INSTLIST +// LIST [] 'lins' +// LIST [] 'ins ' [dlid,insh,RGNLIST,ARTLIST,INFOLIST] +// LIST [] 'ins ' [dlid,insh,RGNLIST,ARTLIST,INFOLIST] +// LIST [] 'ins ' [dlid,insh,RGNLIST,ARTLIST,INFOLIST] +// +// RGNLIST +// LIST [] 'lrgn' +// LIST [] 'rgn ' [rgnh,wsmp,wlnk,ARTLIST] +// LIST [] 'rgn ' [rgnh,wsmp,wlnk,ARTLIST] +// LIST [] 'rgn ' [rgnh,wsmp,wlnk,ARTLIST] +// +// ARTLIST +// LIST [] 'lart' +// 'art1' level 1 Articulation connection graph +// 'art2' level 2 Articulation connection graph +// '3rd1' Possible 3rd party articulation structure 1 +// '3rd2' Possible 3rd party articulation structure 2 .... and so on +// +// WAVEPOOL +// ptbl [] [pool table] +// LIST [] 'wvpl' +// [path], +// [path], +// LIST [] 'wave' [dlid,RIFFWAVE] +// LIST [] 'wave' [dlid,RIFFWAVE] +// LIST [] 'wave' [dlid,RIFFWAVE] +// LIST [] 'wave' [dlid,RIFFWAVE] +// LIST [] 'wave' [dlid,RIFFWAVE] +// +// INFOLIST +// LIST [] 'INFO' +// 'icmt' 'One of those crazy comments.' +// 'icop' 'Copyright (C) 1996 Sonic Foundry' +// +/////////////////////////////////////////////////////////////////////////*/ + + +/*///////////////////////////////////////////////////////////////////////// +// FOURCC's used in the DLS file +/////////////////////////////////////////////////////////////////////////*/ + +#define FOURCC_DLS mmioFOURCC('D','L','S',' ') +#define FOURCC_DLID mmioFOURCC('d','l','i','d') +#define FOURCC_COLH mmioFOURCC('c','o','l','h') +#define FOURCC_WVPL mmioFOURCC('w','v','p','l') +#define FOURCC_PTBL mmioFOURCC('p','t','b','l') +#define FOURCC_PATH mmioFOURCC('p','a','t','h') +#define FOURCC_wave mmioFOURCC('w','a','v','e') +#define FOURCC_LINS mmioFOURCC('l','i','n','s') +#define FOURCC_INS mmioFOURCC('i','n','s',' ') +#define FOURCC_INSH mmioFOURCC('i','n','s','h') +#define FOURCC_LRGN mmioFOURCC('l','r','g','n') +#define FOURCC_RGN mmioFOURCC('r','g','n',' ') +#define FOURCC_RGNH mmioFOURCC('r','g','n','h') +#define FOURCC_LART mmioFOURCC('l','a','r','t') +#define FOURCC_ART1 mmioFOURCC('a','r','t','1') +#define FOURCC_WLNK mmioFOURCC('w','l','n','k') +#define FOURCC_WSMP mmioFOURCC('w','s','m','p') +#define FOURCC_VERS mmioFOURCC('v','e','r','s') + +/*///////////////////////////////////////////////////////////////////////// +// Articulation connection graph definitions +/////////////////////////////////////////////////////////////////////////*/ + +/* Generic Sources */ +#define CONN_SRC_NONE 0x0000 +#define CONN_SRC_LFO 0x0001 +#define CONN_SRC_KEYONVELOCITY 0x0002 +#define CONN_SRC_KEYNUMBER 0x0003 +#define CONN_SRC_EG1 0x0004 +#define CONN_SRC_EG2 0x0005 +#define CONN_SRC_PITCHWHEEL 0x0006 + +/* Midi Controllers 0-127 */ +#define CONN_SRC_CC1 0x0081 +#define CONN_SRC_CC7 0x0087 +#define CONN_SRC_CC10 0x008a +#define CONN_SRC_CC11 0x008b + +/* Generic Destinations */ +#define CONN_DST_NONE 0x0000 +#define CONN_DST_ATTENUATION 0x0001 +#define CONN_DST_PITCH 0x0003 +#define CONN_DST_PAN 0x0004 + +/* LFO Destinations */ +#define CONN_DST_LFO_FREQUENCY 0x0104 +#define CONN_DST_LFO_STARTDELAY 0x0105 + +/* EG1 Destinations */ +#define CONN_DST_EG1_ATTACKTIME 0x0206 +#define CONN_DST_EG1_DECAYTIME 0x0207 +#define CONN_DST_EG1_RELEASETIME 0x0209 +#define CONN_DST_EG1_SUSTAINLEVEL 0x020a + +/* EG2 Destinations */ +#define CONN_DST_EG2_ATTACKTIME 0x030a +#define CONN_DST_EG2_DECAYTIME 0x030b +#define CONN_DST_EG2_RELEASETIME 0x030d +#define CONN_DST_EG2_SUSTAINLEVEL 0x030e + +#define CONN_TRN_NONE 0x0000 +#define CONN_TRN_CONCAVE 0x0001 + +typedef struct _DLSID { + ULONG ulData1; + USHORT usData2; + USHORT usData3; + BYTE abData4[8]; +} DLSID, FAR *LPDLSID; + +typedef struct _DLSVERSION { + DWORD dwVersionMS; + DWORD dwVersionLS; +} DLSVERSION, FAR *LPDLSVERSION; + + +typedef struct _CONNECTION { + USHORT usSource; + USHORT usControl; + USHORT usDestination; + USHORT usTransform; + LONG lScale; +} CONNECTION, FAR *LPCONNECTION; + + +/* Level 1 Articulation Data */ + +typedef struct _CONNECTIONLIST { + ULONG cbSize; /* size of the connection list structure */ + ULONG cConnections; /* count of connections in the list */ +} CONNECTIONLIST, FAR *LPCONNECTIONLIST; + + + +/*///////////////////////////////////////////////////////////////////////// +// Generic type defines for regions and instruments +/////////////////////////////////////////////////////////////////////////*/ + +typedef struct _RGNRANGE { + USHORT usLow; + USHORT usHigh; +} RGNRANGE, FAR * LPRGNRANGE; + +#define F_INSTRUMENT_DRUMS 0x80000000 + +typedef struct _MIDILOCALE { + ULONG ulBank; + ULONG ulInstrument; +} MIDILOCALE, FAR *LPMIDILOCALE; + +/*///////////////////////////////////////////////////////////////////////// +// Header structures found in an DLS file for collection, instruments, and +// regions. +/////////////////////////////////////////////////////////////////////////*/ + +#define F_RGN_OPTION_SELFNONEXCLUSIVE 0x0001 + +typedef struct _RGNHEADER { + RGNRANGE RangeKey; /* Key range */ + RGNRANGE RangeVelocity; /* Velocity Range */ + USHORT fusOptions; /* Synthesis options for this range */ + USHORT usKeyGroup; /* Key grouping for non simultaneous play */ + /* 0 = no group, 1 up is group */ + /* for Level 1 only groups 1-15 are allowed */ +} RGNHEADER, FAR *LPRGNHEADER; + +typedef struct _INSTHEADER { + ULONG cRegions; /* Count of regions in this instrument */ + MIDILOCALE Locale; /* Intended MIDI locale of this instrument */ +} INSTHEADER, FAR *LPINSTHEADER; + +typedef struct _DLSHEADER { + ULONG cInstruments; /* Count of instruments in the collection */ +} DLSHEADER, FAR *LPDLSHEADER; + +/*//////////////////////////////////////////////////////////////////////////// +// definitions for the Wave link structure +////////////////////////////////////////////////////////////////////////////*/ + +/* **** For level 1 only WAVELINK_CHANNEL_MONO is valid **** */ +/* ulChannel allows for up to 32 channels of audio with each bit position */ +/* specifiying a channel of playback */ + +#define WAVELINK_CHANNEL_LEFT 0x0001l +#define WAVELINK_CHANNEL_RIGHT 0x0002l + +#define F_WAVELINK_PHASE_MASTER 0x0001 + +typedef struct _WAVELINK { /* any paths or links are stored right after struct */ + USHORT fusOptions; /* options flags for this wave */ + USHORT usPhaseGroup; /* Phase grouping for locking channels */ + ULONG ulChannel; /* channel placement */ + ULONG ulTableIndex; /* index into the wave pool table, 0 based */ +} WAVELINK, FAR *LPWAVELINK; + +#define POOL_CUE_NULL 0xffffffffl + +typedef struct _POOLCUE { + ULONG ulOffset; /* Offset to the entry in the list */ +} POOLCUE, FAR *LPPOOLCUE; + +typedef struct _POOLTABLE { + ULONG cbSize; /* size of the pool table structure */ + ULONG cCues; /* count of cues in the list */ +} POOLTABLE, FAR *LPPOOLTABLE; + +/*//////////////////////////////////////////////////////////////////////////// +// Structures for the "wsmp" chunk +////////////////////////////////////////////////////////////////////////////*/ + +#define F_WSMP_NO_TRUNCATION 0x0001l +#define F_WSMP_NO_COMPRESSION 0x0002l + + +typedef struct _rwsmp { + ULONG cbSize; + USHORT usUnityNote; /* MIDI Unity Playback Note */ + SHORT sFineTune; /* Fine Tune in log tuning */ + LONG lAttenuation; /* Overall Attenuation to be applied to data */ + ULONG fulOptions; /* Flag options */ + ULONG cSampleLoops; /* Count of Sample loops, 0 loops is one shot */ +} WSMPL, FAR *LPWSMPL; + + +/* This loop type is a normal forward playing loop which is continually */ +/* played until the envelope reaches an off threshold in the release */ +/* portion of the volume envelope */ + +#define WLOOP_TYPE_FORWARD 0 + +typedef struct _rloop { + ULONG cbSize; + ULONG ulType; /* Loop Type */ + ULONG ulStart; /* Start of loop in samples */ + ULONG ulLength; /* Length of loop in samples */ +} WLOOP, FAR *LPWLOOP; + +#endif /*_INC_DLS1 */ diff -r 6bd7ca7d218b -r cbc2a4ffeeec decoders/timidity/dls2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/decoders/timidity/dls2.h Fri Sep 26 20:51:58 2003 +0000 @@ -0,0 +1,130 @@ +/* + + dls2.h + + Description: + + Interface defines and structures for the DLS2 extensions of DLS. + + + Written by Microsoft 1998. Released for public use. + +*/ + +#ifndef _INC_DLS2 +#define _INC_DLS2 + +/* + FOURCC's used in the DLS2 file, in addition to DLS1 chunks +*/ + +#define FOURCC_RGN2 mmioFOURCC('r','g','n','2') +#define FOURCC_LAR2 mmioFOURCC('l','a','r','2') +#define FOURCC_ART2 mmioFOURCC('a','r','t','2') +#define FOURCC_CDL mmioFOURCC('c','d','l',' ') +#define FOURCC_DLID mmioFOURCC('d','l','i','d') + +/* + Articulation connection graph definitions. These are in addition to + the definitions in the DLS1 header. +*/ + +/* Generic Sources (in addition to DLS1 sources. */ +#define CONN_SRC_POLYPRESSURE 0x0007 /* Polyphonic Pressure */ +#define CONN_SRC_CHANNELPRESSURE 0x0008 /* Channel Pressure */ +#define CONN_SRC_VIBRATO 0x0009 /* Vibrato LFO */ +#define CONN_SRC_MONOPRESSURE 0x000a /* MIDI Mono pressure */ + + +/* Midi Controllers */ +#define CONN_SRC_CC91 0x00db /* Reverb Send */ +#define CONN_SRC_CC93 0x00dd /* Chorus Send */ + + +/* Generic Destinations */ +#define CONN_DST_GAIN 0x0001 /* Same as CONN_DST_ ATTENUATION, but more appropriate terminology. */ +#define CONN_DST_KEYNUMBER 0x0005 /* Key Number Generator */ + +/* Audio Channel Output Destinations */ +#define CONN_DST_LEFT 0x0010 /* Left Channel Send */ +#define CONN_DST_RIGHT 0x0011 /* Right Channel Send */ +#define CONN_DST_CENTER 0x0012 /* Center Channel Send */ +#define CONN_DST_LEFTREAR 0x0013 /* Left Rear Channel Send */ +#define CONN_DST_RIGHTREAR 0x0014 /* Right Rear Channel Send */ +#define CONN_DST_LFE_CHANNEL 0x0015 /* LFE Channel Send */ +#define CONN_DST_CHORUS 0x0080 /* Chorus Send */ +#define CONN_DST_REVERB 0x0081 /* Reverb Send */ + +/* Vibrato LFO Destinations */ +#define CONN_DST_VIB_FREQUENCY 0x0114 /* Vibrato Frequency */ +#define CONN_DST_VIB_STARTDELAY 0x0115 /* Vibrato Start Delay */ + +/* EG1 Destinations */ +#define CONN_DST_EG1_DELAYTIME 0x020B /* EG1 Delay Time */ +#define CONN_DST_EG1_HOLDTIME 0x020C /* EG1 Hold Time */ +#define CONN_DST_EG1_SHUTDOWNTIME 0x020D /* EG1 Shutdown Time */ + + +/* EG2 Destinations */ +#define CONN_DST_EG2_DELAYTIME 0x030F /* EG2 Delay Time */ +#define CONN_DST_EG2_HOLDTIME 0x0310 /* EG2 Hold Time */ + + +/* Filter Destinations */ +#define CONN_DST_FILTER_CUTOFF 0x0500 /* Filter Cutoff Frequency */ +#define CONN_DST_FILTER_Q 0x0501 /* Filter Resonance */ + + +/* Transforms */ +#define CONN_TRN_CONVEX 0x0002 /* Convex Transform */ +#define CONN_TRN_SWITCH 0x0003 /* Switch Transform */ + + +/* Conditional chunk operators */ + #define DLS_CDL_AND 0x0001 /* X = X & Y */ + #define DLS_CDL_OR 0x0002 /* X = X | Y */ + #define DLS_CDL_XOR 0x0003 /* X = X ^ Y */ + #define DLS_CDL_ADD 0x0004 /* X = X + Y */ + #define DLS_CDL_SUBTRACT 0x0005 /* X = X - Y */ + #define DLS_CDL_MULTIPLY 0x0006 /* X = X * Y */ + #define DLS_CDL_DIVIDE 0x0007 /* X = X / Y */ + #define DLS_CDL_LOGICAL_AND 0x0008 /* X = X && Y */ + #define DLS_CDL_LOGICAL_OR 0x0009 /* X = X || Y */ + #define DLS_CDL_LT 0x000A /* X = (X < Y) */ + #define DLS_CDL_LE 0x000B /* X = (X <= Y) */ + #define DLS_CDL_GT 0x000C /* X = (X > Y) */ + #define DLS_CDL_GE 0x000D /* X = (X >= Y) */ + #define DLS_CDL_EQ 0x000E /* X = (X == Y) */ + #define DLS_CDL_NOT 0x000F /* X = !X */ + #define DLS_CDL_CONST 0x0010 /* 32-bit constant */ + #define DLS_CDL_QUERY 0x0011 /* 32-bit value returned from query */ + #define DLS_CDL_QUERYSUPPORTED 0x0012 /* Test to see if query is supported by synth */ + +/* + Loop and release +*/ + +#define WLOOP_TYPE_RELEASE 1 + +/* + WaveLink chunk +*/ + +#define F_WAVELINK_MULTICHANNEL 0x0002 + + +/* + DLSID queries for +*/ + +DEFINE_GUID(DLSID_GMInHardware, 0x178f2f24, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); +DEFINE_GUID(DLSID_GSInHardware, 0x178f2f25, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); +DEFINE_GUID(DLSID_XGInHardware, 0x178f2f26, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); +DEFINE_GUID(DLSID_SupportsDLS1, 0x178f2f27, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); +DEFINE_GUID(DLSID_SupportsDLS2, 0xf14599e5, 0x4689, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6); +DEFINE_GUID(DLSID_SampleMemorySize, 0x178f2f28, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); +DEFINE_GUID(DLSID_ManufacturersID, 0xb03e1181, 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8); +DEFINE_GUID(DLSID_ProductID, 0xb03e1182, 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8); +DEFINE_GUID(DLSID_SamplePlaybackRate, 0x2a91f713, 0xa4bf, 0x11d2, 0xbb, 0xdf, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8); + +#endif /* _INC_DLS2 */ diff -r 6bd7ca7d218b -r cbc2a4ffeeec decoders/timidity/instrum.c --- a/decoders/timidity/instrum.c Sat Sep 13 20:46:09 2003 +0000 +++ b/decoders/timidity/instrum.c Fri Sep 26 20:51:58 2003 +0000 @@ -40,6 +40,7 @@ #include "options.h" #include "common.h" #include "instrum.h" +#include "instrum_dls.h" #include "resample.h" #include "tables.h" @@ -178,7 +179,7 @@ if (!name) return 0; /* Open patch file */ - if (!(rw=open_file(name))) + if ((rw=open_file(name)) == NULL) { noluck=1; /* Try with various extensions */ @@ -188,7 +189,7 @@ { strcpy(tmp, name); strcat(tmp, patch_ext[i]); - if ((rw=open_file(tmp))) + if ((rw=open_file(tmp)) != NULL) { noluck=0; break; @@ -273,6 +274,8 @@ READ_LONG(sp->low_freq); READ_LONG(sp->high_freq); READ_LONG(sp->root_freq); + sp->low_vel = 0; + sp->high_vel = 127; SDL_RWseek(rw, 2, SEEK_CUR); /* Why have a "root frequency" and then * "tuning"?? */ @@ -527,6 +530,11 @@ { if (bank->instrument[i]==MAGIC_LOAD_INSTRUMENT) { + bank->instrument[i]=load_instrument_dls(song, dr, b, i); + if (bank->instrument[i]) + { + continue; + } if (!(bank->tone[i].name)) { SNDDBG(("No instrument mapped to %s %d, program %d%s\n", diff -r 6bd7ca7d218b -r cbc2a4ffeeec decoders/timidity/instrum_dls.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/decoders/timidity/instrum_dls.c Fri Sep 26 20:51:58 2003 +0000 @@ -0,0 +1,1271 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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. + + instrum.h + + */ + +#include +#include + +#include "SDL.h" +#include "SDL_endian.h" +#include "SDL_rwops.h" + +#include "SDL_sound.h" + +#define __SDL_SOUND_INTERNAL__ +#include "SDL_sound_internal.h" + +#include "timidity.h" +#include "options.h" +#include "instrum.h" +#include "tables.h" +#include "common.h" + +/*-------------------------------------------------------------------------*/ +/* * * * * * * * * * * * * * * * * load_riff.h * * * * * * * * * * * * * * */ +/*-------------------------------------------------------------------------*/ +typedef struct _RIFF_Chunk { + Uint32 magic; + Uint32 length; + Uint32 subtype; + Uint8 *data; + struct _RIFF_Chunk *child; + struct _RIFF_Chunk *next; +} RIFF_Chunk; + +extern DECLSPEC RIFF_Chunk* SDLCALL LoadRIFF(SDL_RWops *src); +extern DECLSPEC void SDLCALL FreeRIFF(RIFF_Chunk *chunk); +extern DECLSPEC void SDLCALL PrintRIFF(RIFF_Chunk *chunk, int level); +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*-------------------------------------------------------------------------*/ +/* * * * * * * * * * * * * * * * * load_riff.c * * * * * * * * * * * * * * */ +/*-------------------------------------------------------------------------*/ +#define RIFF 0x46464952 /* "RIFF" */ +#define LIST 0x5453494c /* "LIST" */ + +static RIFF_Chunk *AllocRIFFChunk() +{ + RIFF_Chunk *chunk = (RIFF_Chunk *)malloc(sizeof(*chunk)); + if ( !chunk ) { + SDL_Error(SDL_ENOMEM); + return NULL; + } + memset(chunk, 0, sizeof(*chunk)); + return chunk; +} + +static void FreeRIFFChunk(RIFF_Chunk *chunk) +{ + if ( chunk->child ) { + FreeRIFFChunk(chunk->child); + } + while ( chunk->next ) { + RIFF_Chunk *freeable = chunk->next; + chunk->next = freeable->next; + FreeRIFFChunk(freeable); + } + free(chunk); +} + +static int ChunkHasSubType(Uint32 magic) +{ + static Uint32 chunk_list[] = { + RIFF, LIST + }; + int i; + for ( i = 0; i < SDL_TABLESIZE(chunk_list); ++i ) { + if ( magic == chunk_list[i] ) { + return 1; + } + } + return 0; +} + +static int ChunkHasSubChunks(Uint32 magic) +{ + static Uint32 chunk_list[] = { + RIFF, LIST + }; + int i; + for ( i = 0; i < SDL_TABLESIZE(chunk_list); ++i ) { + if ( magic == chunk_list[i] ) { + return 1; + } + } + return 0; +} + +static void LoadSubChunks(RIFF_Chunk *chunk, Uint8 *data, Uint32 left) +{ + Uint8 *subchunkData; + Uint32 subchunkDataLen; + + while ( left > 8 ) { + RIFF_Chunk *child = AllocRIFFChunk(); + RIFF_Chunk *next, *prev = NULL; + for ( next = chunk->child; next; next = next->next ) { + prev = next; + } + if ( prev ) { + prev->next = child; + } else { + chunk->child = child; + } + + child->magic = (data[0] << 0) | + (data[1] << 8) | + (data[2] << 16) | + (data[3] << 24); + data += 4; + left -= 4; + child->length = (data[0] << 0) | + (data[1] << 8) | + (data[2] << 16) | + (data[3] << 24); + data += 4; + left -= 4; + child->data = data; + + if ( child->length > left ) { + child->length = left; + } + + subchunkData = child->data; + subchunkDataLen = child->length; + if ( ChunkHasSubType(child->magic) && subchunkDataLen >= 4 ) { + child->subtype = (subchunkData[0] << 0) | + (subchunkData[1] << 8) | + (subchunkData[2] << 16) | + (subchunkData[3] << 24); + subchunkData += 4; + subchunkDataLen -= 4; + } + if ( ChunkHasSubChunks(child->magic) ) { + LoadSubChunks(child, subchunkData, subchunkDataLen); + } + + data += child->length; + left -= child->length; + } +} + +RIFF_Chunk *LoadRIFF(SDL_RWops *src) +{ + RIFF_Chunk *chunk; + Uint8 *subchunkData; + Uint32 subchunkDataLen; + + /* Allocate the chunk structure */ + chunk = AllocRIFFChunk(); + + /* Make sure the file is in RIFF format */ + chunk->magic = SDL_ReadLE32(src); + chunk->length = SDL_ReadLE32(src); + if ( chunk->magic != RIFF ) { + SDL_SetError("Not a RIFF file"); + FreeRIFFChunk(chunk); + return NULL; + } + chunk->data = (Uint8 *)malloc(chunk->length); + if ( chunk->data == NULL ) { + SDL_Error(SDL_ENOMEM); + FreeRIFFChunk(chunk); + return NULL; + } + if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) { + SDL_Error(SDL_EFREAD); + FreeRIFF(chunk); + return NULL; + } + subchunkData = chunk->data; + subchunkDataLen = chunk->length; + if ( ChunkHasSubType(chunk->magic) && subchunkDataLen >= 4 ) { + chunk->subtype = (subchunkData[0] << 0) | + (subchunkData[1] << 8) | + (subchunkData[2] << 16) | + (subchunkData[3] << 24); + subchunkData += 4; + subchunkDataLen -= 4; + } + if ( ChunkHasSubChunks(chunk->magic) ) { + LoadSubChunks(chunk, subchunkData, subchunkDataLen); + } + return chunk; +} + +void FreeRIFF(RIFF_Chunk *chunk) +{ + free(chunk->data); + FreeRIFFChunk(chunk); +} + +void PrintRIFF(RIFF_Chunk *chunk, int level) +{ + static char prefix[128]; + + if ( level == sizeof(prefix)-1 ) { + return; + } + if ( level > 0 ) { + prefix[(level-1)*2] = ' '; + prefix[(level-1)*2+1] = ' '; + } + prefix[level*2] = '\0'; + printf("%sChunk: %c%c%c%c (%d bytes)", prefix, + ((chunk->magic >> 0) & 0xFF), + ((chunk->magic >> 8) & 0xFF), + ((chunk->magic >> 16) & 0xFF), + ((chunk->magic >> 24) & 0xFF), chunk->length); + if ( chunk->subtype ) { + printf(" subtype: %c%c%c%c", + ((chunk->subtype >> 0) & 0xFF), + ((chunk->subtype >> 8) & 0xFF), + ((chunk->subtype >> 16) & 0xFF), + ((chunk->subtype >> 24) & 0xFF)); + } + printf("\n"); + if ( chunk->child ) { + printf("%s{\n", prefix); + PrintRIFF(chunk->child, level + 1); + printf("%s}\n", prefix); + } + if ( chunk->next ) { + PrintRIFF(chunk->next, level); + } + if ( level > 0 ) { + prefix[(level-1)*2] = '\0'; + } +} + +#ifdef TEST_MAIN_RIFF + +main(int argc, char *argv[]) +{ + int i; + for ( i = 1; i < argc; ++i ) { + RIFF_Chunk *chunk; + SDL_RWops *src = SDL_RWFromFile(argv[i], "rb"); + if ( !src ) { + fprintf(stderr, "Couldn't open %s: %s", argv[i], SDL_GetError()); + continue; + } + chunk = LoadRIFF(src); + if ( chunk ) { + PrintRIFF(chunk, 0); + FreeRIFF(chunk); + } else { + fprintf(stderr, "Couldn't load %s: %s\n", argv[i], SDL_GetError()); + } + SDL_RWclose(src); + } +} + +#endif // TEST_MAIN +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*-------------------------------------------------------------------------*/ +/* * * * * * * * * * * * * * * * * load_dls.h * * * * * * * * * * * * * * */ +/*-------------------------------------------------------------------------*/ +/* This code is based on the DLS spec version 1.1, available at: + http://www.midi.org/about-midi/dls/dlsspec.shtml +*/ + +/* Some typedefs so the public dls headers don't need to be modified */ +#define FAR +typedef Uint8 BYTE; +typedef Sint16 SHORT; +typedef Uint16 USHORT; +typedef Uint16 WORD; +typedef Sint32 LONG; +typedef Uint32 ULONG; +typedef Uint32 DWORD; +#define mmioFOURCC(A, B, C, D) \ + (((A) << 0) | ((B) << 8) | ((C) << 16) | ((D) << 24)) +#define DEFINE_GUID(A, B, C, E, F, G, H, I, J, K, L, M) + +#include "dls1.h" +#include "dls2.h" + +typedef struct _WaveFMT { + WORD wFormatTag; + WORD wChannels; + DWORD dwSamplesPerSec; + DWORD dwAvgBytesPerSec; + WORD wBlockAlign; + WORD wBitsPerSample; +} WaveFMT; + +typedef struct _DLS_Wave { + WaveFMT *format; + Uint8 *data; + Uint32 length; + WSMPL *wsmp; + WLOOP *wsmp_loop; +} DLS_Wave; + +typedef struct _DLS_Region { + RGNHEADER *header; + WAVELINK *wlnk; + WSMPL *wsmp; + WLOOP *wsmp_loop; + CONNECTIONLIST *art; + CONNECTION *artList; +} DLS_Region; + +typedef struct _DLS_Instrument { + const char *name; + INSTHEADER *header; + DLS_Region *regions; + CONNECTIONLIST *art; + CONNECTION *artList; +} DLS_Instrument; + +typedef struct _DLS_Data { + struct _RIFF_Chunk *chunk; + + Uint32 cInstruments; + DLS_Instrument *instruments; + + POOLTABLE *ptbl; + POOLCUE *ptblList; + DLS_Wave *waveList; + + const char *name; + const char *artist; + const char *copyright; + const char *comments; +} DLS_Data; + +extern DECLSPEC DLS_Data* SDLCALL LoadDLS(SDL_RWops *src); +extern DECLSPEC void SDLCALL FreeDLS(DLS_Data *chunk); +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*-------------------------------------------------------------------------*/ +/* * * * * * * * * * * * * * * * * load_dls.c * * * * * * * * * * * * * * */ +/*-------------------------------------------------------------------------*/ + +#define FOURCC_LIST 0x5453494c /* "LIST" */ +#define FOURCC_FMT 0x20746D66 /* "fmt " */ +#define FOURCC_DATA 0x61746164 /* "data" */ +#define FOURCC_INFO mmioFOURCC('I','N','F','O') +#define FOURCC_IARL mmioFOURCC('I','A','R','L') +#define FOURCC_IART mmioFOURCC('I','A','R','T') +#define FOURCC_ICMS mmioFOURCC('I','C','M','S') +#define FOURCC_ICMT mmioFOURCC('I','C','M','T') +#define FOURCC_ICOP mmioFOURCC('I','C','O','P') +#define FOURCC_ICRD mmioFOURCC('I','C','R','D') +#define FOURCC_IENG mmioFOURCC('I','E','N','G') +#define FOURCC_IGNR mmioFOURCC('I','G','N','R') +#define FOURCC_IKEY mmioFOURCC('I','K','E','Y') +#define FOURCC_IMED mmioFOURCC('I','M','E','D') +#define FOURCC_INAM mmioFOURCC('I','N','A','M') +#define FOURCC_IPRD mmioFOURCC('I','P','R','D') +#define FOURCC_ISBJ mmioFOURCC('I','S','B','J') +#define FOURCC_ISFT mmioFOURCC('I','S','F','T') +#define FOURCC_ISRC mmioFOURCC('I','S','R','C') +#define FOURCC_ISRF mmioFOURCC('I','S','R','F') +#define FOURCC_ITCH mmioFOURCC('I','T','C','H') + + +static void FreeRegions(DLS_Instrument *instrument) +{ + if ( instrument->regions ) { + free(instrument->regions); + } +} + +static void AllocRegions(DLS_Instrument *instrument) +{ + int datalen = (instrument->header->cRegions * sizeof(DLS_Region)); + FreeRegions(instrument); + instrument->regions = (DLS_Region *)malloc(datalen); + if ( instrument->regions ) { + memset(instrument->regions, 0, datalen); + } +} + +static void FreeInstruments(DLS_Data *data) +{ + if ( data->instruments ) { + Uint32 i; + for ( i = 0; i < data->cInstruments; ++i ) { + FreeRegions(&data->instruments[i]); + } + free(data->instruments); + } +} + +static void AllocInstruments(DLS_Data *data) +{ + int datalen = (data->cInstruments * sizeof(DLS_Instrument)); + FreeInstruments(data); + data->instruments = (DLS_Instrument *)malloc(datalen); + if ( data->instruments ) { + memset(data->instruments, 0, datalen); + } +} + +static void FreeWaveList(DLS_Data *data) +{ + if ( data->waveList ) { + free(data->waveList); + } +} + +static void AllocWaveList(DLS_Data *data) +{ + int datalen = (data->ptbl->cCues * sizeof(DLS_Wave)); + FreeWaveList(data); + data->waveList = (DLS_Wave *)malloc(datalen); + if ( data->waveList ) { + memset(data->waveList, 0, datalen); + } +} + +static void Parse_colh(DLS_Data *data, RIFF_Chunk *chunk) +{ + data->cInstruments = SDL_SwapLE32(*(Uint32 *)chunk->data); + AllocInstruments(data); +} + +static void Parse_insh(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument) +{ + INSTHEADER *header = (INSTHEADER *)chunk->data; + header->cRegions = SDL_SwapLE32(header->cRegions); + header->Locale.ulBank = SDL_SwapLE32(header->Locale.ulBank); + header->Locale.ulInstrument = SDL_SwapLE32(header->Locale.ulInstrument); + instrument->header = header; + AllocRegions(instrument); +} + +static void Parse_rgnh(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region) +{ + RGNHEADER *header = (RGNHEADER *)chunk->data; + header->RangeKey.usLow = SDL_SwapLE16(header->RangeKey.usLow); + header->RangeKey.usHigh = SDL_SwapLE16(header->RangeKey.usHigh); + header->RangeVelocity.usLow = SDL_SwapLE16(header->RangeVelocity.usLow); + header->RangeVelocity.usHigh = SDL_SwapLE16(header->RangeVelocity.usHigh); + header->fusOptions = SDL_SwapLE16(header->fusOptions); + header->usKeyGroup = SDL_SwapLE16(header->usKeyGroup); + region->header = header; +} + +static void Parse_wlnk(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region) +{ + WAVELINK *wlnk = (WAVELINK *)chunk->data; + wlnk->fusOptions = SDL_SwapLE16(wlnk->fusOptions); + wlnk->usPhaseGroup = SDL_SwapLE16(wlnk->usPhaseGroup); + wlnk->ulChannel = SDL_SwapLE16(wlnk->ulChannel); + wlnk->ulTableIndex = SDL_SwapLE16(wlnk->ulTableIndex); + region->wlnk = wlnk; +} + +static void Parse_wsmp(DLS_Data *data, RIFF_Chunk *chunk, WSMPL **wsmp_ptr, WLOOP **wsmp_loop_ptr) +{ + Uint32 i; + WSMPL *wsmp = (WSMPL *)chunk->data; + WLOOP *loop; + wsmp->cbSize = SDL_SwapLE32(wsmp->cbSize); + wsmp->usUnityNote = SDL_SwapLE16(wsmp->usUnityNote); + wsmp->sFineTune = SDL_SwapLE16(wsmp->sFineTune); + wsmp->lAttenuation = SDL_SwapLE32(wsmp->lAttenuation); + wsmp->fulOptions = SDL_SwapLE32(wsmp->fulOptions); + wsmp->cSampleLoops = SDL_SwapLE32(wsmp->cSampleLoops); + loop = (WLOOP *)((Uint8 *)chunk->data + wsmp->cbSize); + *wsmp_ptr = wsmp; + *wsmp_loop_ptr = loop; + for ( i = 0; i < wsmp->cSampleLoops; ++i ) { + loop->cbSize = SDL_SwapLE32(loop->cbSize); + loop->ulType = SDL_SwapLE32(loop->ulType); + loop->ulStart = SDL_SwapLE32(loop->ulStart); + loop->ulLength = SDL_SwapLE32(loop->ulLength); + ++loop; + } +} + +static void Parse_art(DLS_Data *data, RIFF_Chunk *chunk, CONNECTIONLIST **art_ptr, CONNECTION **artList_ptr) +{ + Uint32 i; + CONNECTIONLIST *art = (CONNECTIONLIST *)chunk->data; + CONNECTION *artList; + art->cbSize = SDL_SwapLE32(art->cbSize); + art->cConnections = SDL_SwapLE32(art->cConnections); + artList = (CONNECTION *)((Uint8 *)chunk->data + art->cbSize); + *art_ptr = art; + *artList_ptr = artList; + for ( i = 0; i < art->cConnections; ++i ) { + artList->usSource = SDL_SwapLE16(artList->usSource); + artList->usControl = SDL_SwapLE16(artList->usControl); + artList->usDestination = SDL_SwapLE16(artList->usDestination); + artList->usTransform = SDL_SwapLE16(artList->usTransform); + artList->lScale = SDL_SwapLE32(artList->lScale); + ++artList; + } +} + +static void Parse_lart(DLS_Data *data, RIFF_Chunk *chunk, CONNECTIONLIST **conn_ptr, CONNECTION **connList_ptr) +{ + /* FIXME: This only supports one set of connections */ + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_ART1: + case FOURCC_ART2: + Parse_art(data, chunk, conn_ptr, connList_ptr); + return; + } + } +} + +static void Parse_rgn(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region) +{ + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_RGNH: + Parse_rgnh(data, chunk, region); + break; + case FOURCC_WLNK: + Parse_wlnk(data, chunk, region); + break; + case FOURCC_WSMP: + Parse_wsmp(data, chunk, ®ion->wsmp, ®ion->wsmp_loop); + break; + case FOURCC_LART: + case FOURCC_LAR2: + Parse_lart(data, chunk, ®ion->art, ®ion->artList); + break; + } + } +} + +static void Parse_lrgn(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument) +{ + Uint32 region = 0; + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_RGN: + case FOURCC_RGN2: + if ( region < instrument->header->cRegions ) { + Parse_rgn(data, chunk, &instrument->regions[region++]); + } + break; + } + } +} + +static void Parse_INFO_INS(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument) +{ + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_INAM: /* Name */ + instrument->name = chunk->data; + break; + } + } +} + +static void Parse_ins(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument) +{ + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_INSH: + Parse_insh(data, chunk, instrument); + break; + case FOURCC_LRGN: + Parse_lrgn(data, chunk, instrument); + break; + case FOURCC_LART: + case FOURCC_LAR2: + Parse_lart(data, chunk, &instrument->art, &instrument->artList); + break; + case FOURCC_INFO: + Parse_INFO_INS(data, chunk, instrument); + break; + } + } +} + +static void Parse_lins(DLS_Data *data, RIFF_Chunk *chunk) +{ + Uint32 instrument = 0; + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_INS: + if ( instrument < data->cInstruments ) { + Parse_ins(data, chunk, &data->instruments[instrument++]); + } + break; + } + } +} + +static void Parse_ptbl(DLS_Data *data, RIFF_Chunk *chunk) +{ + Uint32 i; + POOLTABLE *ptbl = (POOLTABLE *)chunk->data; + ptbl->cbSize = SDL_SwapLE32(ptbl->cbSize); + ptbl->cCues = SDL_SwapLE32(ptbl->cCues); + data->ptbl = ptbl; + data->ptblList = (POOLCUE *)((Uint8 *)chunk->data + ptbl->cbSize); + for ( i = 0; i < ptbl->cCues; ++i ) { + data->ptblList[i].ulOffset = SDL_SwapLE32(data->ptblList[i].ulOffset); + } + AllocWaveList(data); +} + +static void Parse_fmt(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave) +{ + WaveFMT *fmt = (WaveFMT *)chunk->data; + fmt->wFormatTag = SDL_SwapLE16(fmt->wFormatTag); + fmt->wChannels = SDL_SwapLE16(fmt->wChannels); + fmt->dwSamplesPerSec = SDL_SwapLE32(fmt->dwSamplesPerSec); + fmt->dwAvgBytesPerSec = SDL_SwapLE32(fmt->dwAvgBytesPerSec); + fmt->wBlockAlign = SDL_SwapLE16(fmt->wBlockAlign); + fmt->wBitsPerSample = SDL_SwapLE16(fmt->wBitsPerSample); + wave->format = fmt; +} + +static void Parse_data(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave) +{ + wave->data = chunk->data; + wave->length = chunk->length; +} + +static void Parse_wave(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave) +{ + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_FMT: + Parse_fmt(data, chunk, wave); + break; + case FOURCC_DATA: + Parse_data(data, chunk, wave); + break; + case FOURCC_WSMP: + Parse_wsmp(data, chunk, &wave->wsmp, &wave->wsmp_loop); + break; + } + } +} + +static void Parse_wvpl(DLS_Data *data, RIFF_Chunk *chunk) +{ + Uint32 wave = 0; + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_wave: + if ( wave < data->ptbl->cCues ) { + Parse_wave(data, chunk, &data->waveList[wave++]); + } + break; + } + } +} + +static void Parse_INFO_DLS(DLS_Data *data, RIFF_Chunk *chunk) +{ + for ( chunk = chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_IARL: /* Archival Location */ + break; + case FOURCC_IART: /* Artist */ + data->artist = chunk->data; + break; + case FOURCC_ICMS: /* Commisioned */ + break; + case FOURCC_ICMT: /* Comments */ + data->comments = chunk->data; + break; + case FOURCC_ICOP: /* Copyright */ + data->copyright = chunk->data; + break; + case FOURCC_ICRD: /* Creation Date */ + break; + case FOURCC_IENG: /* Engineer */ + break; + case FOURCC_IGNR: /* Genre */ + break; + case FOURCC_IKEY: /* Keywords */ + break; + case FOURCC_IMED: /* Medium */ + break; + case FOURCC_INAM: /* Name */ + data->name = chunk->data; + break; + case FOURCC_IPRD: /* Product */ + break; + case FOURCC_ISBJ: /* Subject */ + break; + case FOURCC_ISFT: /* Software */ + break; + case FOURCC_ISRC: /* Source */ + break; + case FOURCC_ISRF: /* Source Form */ + break; + case FOURCC_ITCH: /* Technician */ + break; + } + } +} + +DLS_Data *LoadDLS(SDL_RWops *src) +{ + RIFF_Chunk *chunk; + DLS_Data *data = (DLS_Data *)malloc(sizeof(*data)); + if ( !data ) { + SDL_Error(SDL_ENOMEM); + return NULL; + } + memset(data, 0, sizeof(*data)); + + data->chunk = LoadRIFF(src); + if ( !data->chunk ) { + FreeDLS(data); + return NULL; + } + + for ( chunk = data->chunk->child; chunk; chunk = chunk->next ) { + Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; + switch(magic) { + case FOURCC_COLH: + Parse_colh(data, chunk); + break; + case FOURCC_LINS: + Parse_lins(data, chunk); + break; + case FOURCC_PTBL: + Parse_ptbl(data, chunk); + break; + case FOURCC_WVPL: + Parse_wvpl(data, chunk); + break; + case FOURCC_INFO: + Parse_INFO_DLS(data, chunk); + break; + } + } + return data; +} + +void FreeDLS(DLS_Data *data) +{ + if ( data->chunk ) { + FreeRIFF(data->chunk); + } + FreeInstruments(data); + FreeWaveList(data); + free(data); +} + +static const char *SourceToString(USHORT usSource) +{ + switch(usSource) { + case CONN_SRC_NONE: + return "NONE"; + case CONN_SRC_LFO: + return "LFO"; + case CONN_SRC_KEYONVELOCITY: + return "KEYONVELOCITY"; + case CONN_SRC_KEYNUMBER: + return "KEYNUMBER"; + case CONN_SRC_EG1: + return "EG1"; + case CONN_SRC_EG2: + return "EG2"; + case CONN_SRC_PITCHWHEEL: + return "PITCHWHEEL"; + case CONN_SRC_CC1: + return "CC1"; + case CONN_SRC_CC7: + return "CC7"; + case CONN_SRC_CC10: + return "CC10"; + case CONN_SRC_CC11: + return "CC11"; + case CONN_SRC_POLYPRESSURE: + return "POLYPRESSURE"; + case CONN_SRC_CHANNELPRESSURE: + return "CHANNELPRESSURE"; + case CONN_SRC_VIBRATO: + return "VIBRATO"; + case CONN_SRC_MONOPRESSURE: + return "MONOPRESSURE"; + case CONN_SRC_CC91: + return "CC91"; + case CONN_SRC_CC93: + return "CC93"; + default: + return "UNKNOWN"; + } +} + +static const char *TransformToString(USHORT usTransform) +{ + switch (usTransform) { + case CONN_TRN_NONE: + return "NONE"; + case CONN_TRN_CONCAVE: + return "CONCAVE"; + case CONN_TRN_CONVEX: + return "CONVEX"; + case CONN_TRN_SWITCH: + return "SWITCH"; + default: + return "UNKNOWN"; + } +} + +static const char *DestinationToString(USHORT usDestination) +{ + switch (usDestination) { + case CONN_DST_NONE: + return "NONE"; + case CONN_DST_ATTENUATION: + return "ATTENUATION"; + case CONN_DST_PITCH: + return "PITCH"; + case CONN_DST_PAN: + return "PAN"; + case CONN_DST_LFO_FREQUENCY: + return "LFO_FREQUENCY"; + case CONN_DST_LFO_STARTDELAY: + return "LFO_STARTDELAY"; + case CONN_DST_EG1_ATTACKTIME: + return "EG1_ATTACKTIME"; + case CONN_DST_EG1_DECAYTIME: + return "EG1_DECAYTIME"; + case CONN_DST_EG1_RELEASETIME: + return "EG1_RELEASETIME"; + case CONN_DST_EG1_SUSTAINLEVEL: + return "EG1_SUSTAINLEVEL"; + case CONN_DST_EG2_ATTACKTIME: + return "EG2_ATTACKTIME"; + case CONN_DST_EG2_DECAYTIME: + return "EG2_DECAYTIME"; + case CONN_DST_EG2_RELEASETIME: + return "EG2_RELEASETIME"; + case CONN_DST_EG2_SUSTAINLEVEL: + return "EG2_SUSTAINLEVEL"; + case CONN_DST_KEYNUMBER: + return "KEYNUMBER"; + case CONN_DST_LEFT: + return "LEFT"; + case CONN_DST_RIGHT: + return "RIGHT"; + case CONN_DST_CENTER: + return "CENTER"; + case CONN_DST_LEFTREAR: + return "LEFTREAR"; + case CONN_DST_RIGHTREAR: + return "RIGHTREAR"; + case CONN_DST_LFE_CHANNEL: + return "LFE_CHANNEL"; + case CONN_DST_CHORUS: + return "CHORUS"; + case CONN_DST_REVERB: + return "REVERB"; + case CONN_DST_VIB_FREQUENCY: + return "VIB_FREQUENCY"; + case CONN_DST_VIB_STARTDELAY: + return "VIB_STARTDELAY"; + case CONN_DST_EG1_DELAYTIME: + return "EG1_DELAYTIME"; + case CONN_DST_EG1_HOLDTIME: + return "EG1_HOLDTIME"; + case CONN_DST_EG1_SHUTDOWNTIME: + return "EG1_SHUTDOWNTIME"; + case CONN_DST_EG2_DELAYTIME: + return "EG2_DELAYTIME"; + case CONN_DST_EG2_HOLDTIME: + return "EG2_HOLDTIME"; + case CONN_DST_FILTER_CUTOFF: + return "FILTER_CUTOFF"; + case CONN_DST_FILTER_Q: + return "FILTER_Q"; + default: + return "UNKOWN"; + } +} + +static void PrintArt(const char *type, CONNECTIONLIST *art, CONNECTION *artList) +{ + Uint32 i; + printf("%s Connections:\n", type); + for ( i = 0; i < art->cConnections; ++i ) { + printf(" Source: %s, Control: %s, Destination: %s, Transform: %s, Scale: %d\n", + SourceToString(artList[i].usSource), + SourceToString(artList[i].usControl), + DestinationToString(artList[i].usDestination), + TransformToString(artList[i].usTransform), + artList[i].lScale); + } +} + +static void PrintWave(DLS_Wave *wave, Uint32 index) +{ + WaveFMT *format = wave->format; + if ( format ) { + printf(" Wave %u: Format: %hu, %hu channels, %u Hz, %hu bits (length = %u)\n", index, format->wFormatTag, format->wChannels, format->dwSamplesPerSec, format->wBitsPerSample, wave->length); + } + if ( wave->wsmp ) { + Uint32 i; + printf(" wsmp->usUnityNote = %hu\n", wave->wsmp->usUnityNote); + printf(" wsmp->sFineTune = %hd\n", wave->wsmp->sFineTune); + printf(" wsmp->lAttenuation = %d\n", wave->wsmp->lAttenuation); + printf(" wsmp->fulOptions = 0x%8.8x\n", wave->wsmp->fulOptions); + printf(" wsmp->cSampleLoops = %u\n", wave->wsmp->cSampleLoops); + for ( i = 0; i < wave->wsmp->cSampleLoops; ++i ) { + WLOOP *loop = &wave->wsmp_loop[i]; + printf(" Loop %u:\n", i); + printf(" ulStart = %u\n", loop->ulStart); + printf(" ulLength = %u\n", loop->ulLength); + } + } +} + +static void PrintRegion(DLS_Region *region, Uint32 index) +{ + printf(" Region %u:\n", index); + if ( region->header ) { + printf(" RangeKey = { %hu - %hu }\n", region->header->RangeKey.usLow, region->header->RangeKey.usHigh); + printf(" RangeVelocity = { %hu - %hu }\n", region->header->RangeVelocity.usLow, region->header->RangeVelocity.usHigh); + printf(" fusOptions = 0x%4.4hx\n", region->header->fusOptions); + printf(" usKeyGroup = %hu\n", region->header->usKeyGroup); + } + if ( region->wlnk ) { + printf(" wlnk->fusOptions = 0x%4.4hx\n", region->wlnk->fusOptions); + printf(" wlnk->usPhaseGroup = %hu\n", region->wlnk->usPhaseGroup); + printf(" wlnk->ulChannel = %u\n", region->wlnk->ulChannel); + printf(" wlnk->ulTableIndex = %u\n", region->wlnk->ulTableIndex); + } + if ( region->wsmp ) { + Uint32 i; + printf(" wsmp->usUnityNote = %hu\n", region->wsmp->usUnityNote); + printf(" wsmp->sFineTune = %hd\n", region->wsmp->sFineTune); + printf(" wsmp->lAttenuation = %d\n", region->wsmp->lAttenuation); + printf(" wsmp->fulOptions = 0x%8.8x\n", region->wsmp->fulOptions); + printf(" wsmp->cSampleLoops = %u\n", region->wsmp->cSampleLoops); + for ( i = 0; i < region->wsmp->cSampleLoops; ++i ) { + WLOOP *loop = ®ion->wsmp_loop[i]; + printf(" Loop %u:\n", i); + printf(" ulStart = %u\n", loop->ulStart); + printf(" ulLength = %u\n", loop->ulLength); + } + } + if ( region->art && region->art->cConnections > 0 ) { + PrintArt("Region", region->art, region->artList); + } +} + +static void PrintInstrument(DLS_Instrument *instrument, Uint32 index) +{ + printf("Instrument %u:\n", index); + if ( instrument->name ) { + printf(" Name: %s\n", instrument->name); + } + if ( instrument->header ) { + Uint32 i; + printf(" ulBank = 0x%8.8x\n", instrument->header->Locale.ulBank); + printf(" ulInstrument = %u\n", instrument->header->Locale.ulInstrument); + printf(" Regions: %u\n", instrument->header->cRegions); + for ( i = 0; i < instrument->header->cRegions; ++i ) { + PrintRegion(&instrument->regions[i], i); + } + } + if ( instrument->art && instrument->art->cConnections > 0 ) { + PrintArt("Instrument", instrument->art, instrument->artList); + } +}; + +void PrintDLS(DLS_Data *data) +{ + printf("DLS Data:\n"); + printf("cInstruments = %u\n", data->cInstruments); + if ( data->instruments ) { + Uint32 i; + for ( i = 0; i < data->cInstruments; ++i ) { + PrintInstrument(&data->instruments[i], i); + } + } + if ( data->ptbl && data->ptbl->cCues > 0 ) { + Uint32 i; + printf("Cues: "); + for ( i = 0; i < data->ptbl->cCues; ++i ) { + if ( i > 0 ) { + printf(", "); + } + printf("%u", data->ptblList[i].ulOffset); + } + printf("\n"); + } + if ( data->waveList ) { + Uint32 i; + printf("Waves:\n"); + for ( i = 0; i < data->ptbl->cCues; ++i ) { + PrintWave(&data->waveList[i], i); + } + } + if ( data->name ) { + printf("Name: %s\n", data->name); + } + if ( data->artist ) { + printf("Artist: %s\n", data->artist); + } + if ( data->copyright ) { + printf("Copyright: %s\n", data->copyright); + } + if ( data->comments ) { + printf("Comments: %s\n", data->comments); + } +} + +#ifdef TEST_MAIN_DLS + +main(int argc, char *argv[]) +{ + int i; + for ( i = 1; i < argc; ++i ) { + DLS_Data *data; + SDL_RWops *src = SDL_RWFromFile(argv[i], "rb"); + if ( !src ) { + fprintf(stderr, "Couldn't open %s: %s", argv[i], SDL_GetError()); + continue; + } + data = LoadDLS(src); + if ( data ) { + PrintRIFF(data->chunk, 0); + PrintDLS(data); + FreeDLS(data); + } else { + fprintf(stderr, "Couldn't load %s: %s\n", argv[i], SDL_GetError()); + } + SDL_RWclose(src); + } +} + +#endif // TEST_MAIN +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*-------------------------------------------------------------------------*/ +/* * * * * * * * * * * * * * * * * instrum_dls.c * * * * * * * * * * * * * */ +/*-------------------------------------------------------------------------*/ + +DLS_Data *Timidity_LoadDLS(SDL_RWops *src) +{ + DLS_Data *patches = LoadDLS(src); + if (!patches) { + SNDDBG(("%s", SDL_GetError())); + } + return patches; +} + +void Timidity_FreeDLS(DLS_Data *patches) +{ + FreeDLS(patches); +} + +/* convert timecents to sec */ +static double to_msec(int timecent) +{ + if (timecent == 0x80000000 || timecent == 0) + return 0.0; + return 1000.0 * pow(2.0, (double)(timecent / 65536) / 1200.0); +} + +/* convert decipercent to {0..1} */ +static double to_normalized_percent(int decipercent) +{ + return ((double)(decipercent / 65536)) / 1000.0; +} + +/* convert from 8bit value to fractional offset (15.15) */ +static Sint32 to_offset(int offset) +{ + return (Sint32)offset << (7+15); +} + +/* calculate ramp rate in fractional unit; + * diff = 8bit, time = msec + */ +static Sint32 calc_rate(MidiSong *song, int diff, int sample_rate, double msec) +{ + double rate; + + if(msec < 6) + msec = 6; + if(diff == 0) + diff = 255; + diff <<= (7+15); + rate = ((double)diff / song->rate) * song->control_ratio * 1000.0 / msec; + return (Sint32)rate; +} + +static int load_connection(ULONG cConnections, CONNECTION *artList, USHORT destination) +{ + ULONG i; + int value = 0; + for (i = 0; i < cConnections; ++i) { + CONNECTION *conn = &artList[i]; + if(conn->usDestination == destination) { + // The formula for the destination is: + // usDestination = usDestination + usTransform(usSource * (usControl * lScale)) + // Since we are only handling source/control of NONE and identity + // transform, this simplifies to: usDestination = usDestination + lScale + if (conn->usSource == CONN_SRC_NONE && + conn->usControl == CONN_SRC_NONE && + conn->usTransform == CONN_TRN_NONE) + value += conn->lScale; + } + } + return value; +} + +static void load_region_dls(MidiSong *song, Sample *sample, DLS_Instrument *ins, Uint32 index) +{ + DLS_Region *rgn = &ins->regions[index]; + DLS_Wave *wave = &song->patches->waveList[rgn->wlnk->ulTableIndex]; + + sample->low_freq = freq_table[rgn->header->RangeKey.usLow]; + sample->high_freq = freq_table[rgn->header->RangeKey.usHigh]; + sample->root_freq = freq_table[rgn->wsmp->usUnityNote]; + sample->low_vel = rgn->header->RangeVelocity.usLow; + sample->high_vel = rgn->header->RangeVelocity.usHigh; + + sample->modes = MODES_16BIT; + sample->sample_rate = wave->format->dwSamplesPerSec; + sample->data_length = wave->length / 2; + sample->data = (sample_t *)safe_malloc(wave->length); + memcpy(sample->data, wave->data, wave->length); + if (rgn->wsmp->cSampleLoops) { + sample->modes |= (MODES_LOOPING|MODES_SUSTAIN); + sample->loop_start = rgn->wsmp_loop->ulStart / 2; + sample->loop_end = sample->loop_start + (rgn->wsmp_loop->ulLength / 2); + } + sample->volume = 1.0f; + + if (sample->modes & MODES_SUSTAIN) { + int value; + double attack, hold, decay, release; int sustain; + CONNECTIONLIST *art = NULL; + CONNECTION *artList = NULL; + + if (ins->art && ins->art->cConnections > 0 && ins->artList) { + art = ins->art; + artList = ins->artList; + } else { + art = rgn->art; + artList = rgn->artList; + } + + value = load_connection(art->cConnections, artList, CONN_DST_EG1_ATTACKTIME); + attack = to_msec(value); + value = load_connection(art->cConnections, artList, CONN_DST_EG1_HOLDTIME); + hold = to_msec(value); + value = load_connection(art->cConnections, artList, CONN_DST_EG1_DECAYTIME); + decay = to_msec(value); + value = load_connection(art->cConnections, artList, CONN_DST_EG1_RELEASETIME); + release = to_msec(value); + value = load_connection(art->cConnections, artList, CONN_DST_EG1_SUSTAINLEVEL); + sustain = (int)((1.0 - to_normalized_percent(value)) * 250.0); + value = load_connection(art->cConnections, artList, CONN_DST_PAN); + sample->panning = (int)((0.5 + to_normalized_percent(value)) * 127.0); + +/* +printf("%d, Rate=%d LV=%d HV=%d Low=%d Hi=%d Root=%d Pan=%d Attack=%f Hold=%f Sustain=%d Decay=%f Release=%f\n", index, sample->sample_rate, rgn->header->RangeVelocity.usLow, rgn->header->RangeVelocity.usHigh, sample->low_freq, sample->high_freq, sample->root_freq, sample->panning, attack, hold, sustain, decay, release); +*/ + + sample->envelope_offset[0] = to_offset(255); + sample->envelope_rate[0] = calc_rate(song, 255, sample->sample_rate, attack); + + sample->envelope_offset[1] = to_offset(250); + sample->envelope_rate[1] = calc_rate(song, 5, sample->sample_rate, hold); + + sample->envelope_offset[2] = to_offset(sustain); + sample->envelope_rate[2] = calc_rate(song, 255 - sustain, sample->sample_rate, decay); + + sample->envelope_offset[3] = to_offset(0); + sample->envelope_rate[3] = calc_rate(song, 5 + sustain, sample->sample_rate, release); + + sample->envelope_offset[4] = to_offset(0); + sample->envelope_rate[4] = to_offset(1); + + sample->envelope_offset[5] = to_offset(0); + sample->envelope_rate[5] = to_offset(1); + + sample->modes |= MODES_ENVELOPE; + } + + sample->data_length <<= FRACTION_BITS; + sample->loop_start <<= FRACTION_BITS; + sample->loop_end <<= FRACTION_BITS; +} + +Instrument *load_instrument_dls(MidiSong *song, int drum, int bank, int instrument) +{ + Instrument *inst; + Uint32 i; + DLS_Instrument *dls_ins; + + if (!song->patches) + return(NULL); + + drum = drum ? 0x80000000 : 0; + for (i = 0; i < song->patches->cInstruments; ++i) { + dls_ins = &song->patches->instruments[i]; + if ((dls_ins->header->Locale.ulBank & 0x80000000) == drum && + ((dls_ins->header->Locale.ulBank >> 8) & 0xFF) == bank && + dls_ins->header->Locale.ulInstrument == instrument) + break; + } + if (i == song->patches->cInstruments && !bank) { + for (i = 0; i < song->patches->cInstruments; ++i) { + dls_ins = &song->patches->instruments[i]; + if ((dls_ins->header->Locale.ulBank & 0x80000000) == drum && + dls_ins->header->Locale.ulInstrument == instrument) + break; + } + } + if (i == song->patches->cInstruments) { + SNDDBG(("Couldn't find %s instrument %d in bank %d\n", drum ? "drum" : "melodic", instrument, bank)); + return(NULL); + } + + inst = (Instrument *)safe_malloc(sizeof(*inst)); + inst->samples = dls_ins->header->cRegions; + inst->sample = (Sample *)safe_malloc(inst->samples * sizeof(*inst->sample)); + memset(inst->sample, 0, inst->samples * sizeof(*inst->sample)); +/* +printf("Found %s instrument %d in bank %d named %s with %d regions\n", drum ? "drum" : "melodic", instrument, bank, dls_ins->name, inst->samples); +*/ + for (i = 0; i < dls_ins->header->cRegions; ++i) { + load_region_dls(song, &inst->sample[i], dls_ins, i); + } + return(inst); +} diff -r 6bd7ca7d218b -r cbc2a4ffeeec decoders/timidity/instrum_dls.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/decoders/timidity/instrum_dls.h Fri Sep 26 20:51:58 2003 +0000 @@ -0,0 +1,24 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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. + + instrum.h + + */ + +extern Instrument *load_instrument_dls(MidiSong *song, int drum, int bank, int instrument); diff -r 6bd7ca7d218b -r cbc2a4ffeeec decoders/timidity/playmidi.c --- a/decoders/timidity/playmidi.c Sat Sep 13 20:46:09 2003 +0000 +++ b/decoders/timidity/playmidi.c Fri Sep 26 20:51:58 2003 +0000 @@ -79,7 +79,7 @@ reset_voices(song); } -static void select_sample(MidiSong *song, int v, Instrument *ip) +static void select_sample(MidiSong *song, int v, Instrument *ip, int vel) { Sint32 f, cdiff, diff; int s,i; @@ -97,7 +97,8 @@ f=song->voice[v].orig_frequency; for (i=0; ilow_freq <= f && sp->high_freq >= f) + if (sp->low_vel <= vel && sp->high_vel >= vel && + sp->low_freq <= f && sp->high_freq >= f) { song->voice[v].sample=sp; return; @@ -282,7 +283,7 @@ song->voice[i].orig_frequency = freq_table[(int)(ip->sample->note_to_use)]; else song->voice[i].orig_frequency = freq_table[e->a & 0x7F]; - select_sample(song, i, ip); + select_sample(song, i, ip, e->b); } song->voice[i].status = VOICE_ON; diff -r 6bd7ca7d218b -r cbc2a4ffeeec decoders/timidity/timidity.c --- a/decoders/timidity/timidity.c Sat Sep 13 20:46:09 2003 +0000 +++ b/decoders/timidity/timidity.c Fri Sep 26 20:51:58 2003 +0000 @@ -398,6 +398,22 @@ return 0; } +int Timidity_Init_NoConfig() +{ + /* Allocate memory for the standard tonebank and drumset */ + master_tonebank[0] = safe_malloc(sizeof(ToneBank)); + memset(master_tonebank[0], 0, sizeof(ToneBank)); + master_tonebank[0]->tone = safe_malloc(128 * sizeof(ToneBankElement)); + memset(master_tonebank[0]->tone, 0, 128 * sizeof(ToneBankElement)); + + master_drumset[0] = safe_malloc(sizeof(ToneBank)); + memset(master_drumset[0], 0, sizeof(ToneBank)); + master_drumset[0]->tone = safe_malloc(128 * sizeof(ToneBankElement)); + memset(master_drumset[0]->tone, 0, 128 * sizeof(ToneBankElement)); + + return 0; +} + int Timidity_Init() { /* !!! FIXME: This may be ugly, but slightly less so than requiring the @@ -414,21 +430,12 @@ add_to_pathlist("/etc"); #endif - /* Allocate memory for the standard tonebank and drumset */ - master_tonebank[0] = safe_malloc(sizeof(ToneBank)); - memset(master_tonebank[0], 0, sizeof(ToneBank)); - master_tonebank[0]->tone = safe_malloc(128 * sizeof(ToneBankElement)); - memset(master_tonebank[0]->tone, 0, 128 * sizeof(ToneBankElement)); - - master_drumset[0] = safe_malloc(sizeof(ToneBank)); - memset(master_drumset[0], 0, sizeof(ToneBank)); - master_drumset[0]->tone = safe_malloc(128 * sizeof(ToneBankElement)); - memset(master_drumset[0]->tone, 0, 128 * sizeof(ToneBankElement)); + Timidity_Init_NoConfig(); return read_config_file(CONFIG_FILE); } -MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio) +MidiSong *Timidity_LoadDLSSong(SDL_RWops *rw, DLS_Patches *patches, SDL_AudioSpec *audio) { MidiSong *song; Sint32 events; @@ -440,6 +447,7 @@ /* Allocate memory for the song */ song = (MidiSong *)safe_malloc(sizeof(*song)); memset(song, 0, sizeof(*song)); + song->patches = patches; for (i = 0; i < 128; i++) { @@ -529,6 +537,11 @@ return(song); } +MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio) +{ + return Timidity_LoadDLSSong(rw, NULL, audio); +} + void Timidity_FreeSong(MidiSong *song) { int i; diff -r 6bd7ca7d218b -r cbc2a4ffeeec decoders/timidity/timidity.h --- a/decoders/timidity/timidity.h Sat Sep 13 20:46:09 2003 +0000 +++ b/decoders/timidity/timidity.h Fri Sep 26 20:51:58 2003 +0000 @@ -19,6 +19,12 @@ */ +#ifndef TIMIDITY_H +#define TIMIDITY_H +#ifdef __cplusplus +extern "C" { +#endif + typedef Sint16 sample_t; typedef Sint32 final_volume_t; @@ -30,7 +36,7 @@ typedef struct { Sint32 loop_start, loop_end, data_length, - sample_rate, low_freq, high_freq, root_freq; + sample_rate, low_vel, high_vel, low_freq, high_freq, root_freq; Sint32 envelope_rate[6], envelope_offset[6]; float @@ -107,6 +113,9 @@ void *next; } MidiEventList; +struct _DLS_Data; +typedef struct _DLS_Data DLS_Patches; + typedef struct { int playing; SDL_RWops *rw; @@ -114,6 +123,7 @@ Sint32 encoding; float master_volume; Sint32 amplification; + DLS_Patches *patches; ToneBank *tonebank[128]; ToneBank *drumset[128]; Instrument *default_instrument; @@ -148,10 +158,19 @@ /* Some of these are not defined in timidity.c but are here for convenience */ extern int Timidity_Init(void); +extern int Timidity_Init_NoConfig(void); extern void Timidity_SetVolume(MidiSong *song, int volume); extern int Timidity_PlaySome(MidiSong *song, void *stream, Sint32 len); +extern DLS_Patches *Timidity_LoadDLS(SDL_RWops *rw); +extern void Timidity_FreeDLS(DLS_Patches *patches); +extern MidiSong *Timidity_LoadDLSSong(SDL_RWops *rw, DLS_Patches *patches, SDL_AudioSpec *audio); extern MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio); extern void Timidity_Start(MidiSong *song); extern void Timidity_Seek(MidiSong *song, Uint32 ms); extern void Timidity_FreeSong(MidiSong *song); extern void Timidity_Exit(void); + +#ifdef __cplusplus +} +#endif +#endif /* TIMIDITY_H */