diff options
author | Viktor Semykin <thesame.ml@gmail.com> | 2010-01-19 00:25:48 +0200 |
---|---|---|
committer | Viktor Semykin <thesame.ml@gmail.com> | 2010-01-19 00:25:48 +0200 |
commit | b07cca605c3686199cadbc797a083b99bce14d5f (patch) | |
tree | de25936c9eb92c49bd3008623fcfd572c57f7a6a /plugins | |
parent | 380065e39d0a8c097569b6705530b68f1abf7ed2 (diff) | |
parent | 583b601c6420b43e0ecbb86faf44ab1e52f95064 (diff) |
Merge branch 'master' of git://deadbeef.git.sourceforge.net/gitroot/deadbeef/deadbeef into notify
Diffstat (limited to 'plugins')
66 files changed, 2578 insertions, 952 deletions
diff --git a/plugins/adplug/Makefile.am b/plugins/adplug/Makefile.am index 52cbb90d..e35d4107 100644 --- a/plugins/adplug/Makefile.am +++ b/plugins/adplug/Makefile.am @@ -1,71 +1,137 @@ +adplugpath=@top_srcdir@/plugins/adplug + adlibdir = $(libdir)/$(PACKAGE) pkglib_LTLIBRARIES = adplug.la + +AM_CFLAGS = $(CFLAGS) -std=c99 -I$(adplugpath)/adplug -I$(adplugpath)/libbinio + +AM_CPPFLAGS = $(CXXFLAGS) -Dstricmp=strcasecmp -DVERSION=\"2.1\" -I$(adplugpath)/adplug -I$(adplugpath)/libbinio + adplug_la_SOURCES = adplug-db.cpp\ plugin.c\ - adplug/adplug.cpp\ - adplug/emuopl.cpp\ - adplug/fmopl.c\ - adplug/diskopl.cpp\ - adplug/debug.c\ - adplug/debug.h\ - adplug/fprovide.cpp\ - adplug/player.cpp\ - adplug/database.cpp\ - adplug/hsc.cpp\ - adplug/sng.cpp\ - adplug/imf.cpp\ - adplug/players.cpp\ - adplug/protrack.cpp\ + libbinio/binfile.h\ + libbinio/binio.h\ + libbinio/binstr.h\ + libbinio/binwrap.h\ + libbinio/binfile.cpp\ + libbinio/binio.cpp\ + libbinio/binstr.cpp\ + libbinio/binwrap.cpp\ adplug/a2m.cpp\ + adplug/a2m.h\ + adplug/adl.cpp\ + adplug/adl.h\ + adplug/adlibemu.c\ + adplug/adlibemu.h\ + adplug/adplug.cpp\ + adplug/adplug.h\ adplug/adtrack.cpp\ + adplug/adtrack.h\ adplug/amd.cpp\ + adplug/amd.h\ + adplug/analopl.cpp\ + adplug/analopl.h\ adplug/bam.cpp\ + adplug/bam.h\ + adplug/bmf.cpp\ + adplug/bmf.h\ + adplug/cff.cpp\ + adplug/cff.h\ adplug/d00.cpp\ + adplug/d00.h\ + adplug/database.cpp\ + adplug/database.h\ + adplug/debug.c\ + adplug/debug.h\ adplug/dfm.cpp\ + adplug/dfm.h\ + adplug/diskopl.cpp\ + adplug/diskopl.h\ + adplug/dmo.cpp\ + adplug/dmo.h\ + adplug/dro2.cpp\ + adplug/dro2.h\ + adplug/dro.cpp\ + adplug/dro.h\ + adplug/dtm.cpp\ + adplug/dtm.h\ + adplug/emuopl.cpp\ + adplug/emuopl.h\ + adplug/flash.cpp\ + adplug/flash.h\ + adplug/fmc.cpp\ + adplug/fmc.h\ + adplug/fmopl.c\ + adplug/fmopl.h\ + adplug/fprovide.cpp\ + adplug/fprovide.h\ + adplug/hsc.cpp\ + adplug/hsc.h\ adplug/hsp.cpp\ + adplug/hsp.h\ + adplug/hybrid.cpp\ + adplug/hybrid.h\ + adplug/hyp.cpp\ + adplug/hyp.h\ + adplug/imf.cpp\ + adplug/imf.h\ + adplug/jbm.cpp\ + adplug/jbm.h\ + adplug/kemuopl.h\ adplug/ksm.cpp\ + adplug/ksm.h\ + adplug/lds.cpp\ + adplug/lds.h\ adplug/mad.cpp\ + adplug/mad.h\ adplug/mid.cpp\ + adplug/mid.h\ + adplug/mididata.h\ adplug/mkj.cpp\ - adplug/cff.cpp\ - adplug/dmo.cpp\ - adplug/s3m.cpp\ - adplug/dtm.cpp\ - adplug/fmc.cpp\ + adplug/mkj.h\ + adplug/msc.cpp\ + adplug/msc.h\ adplug/mtk.cpp\ + adplug/mtk.h\ + adplug/opl.h\ + adplug/player.cpp\ + adplug/player.h\ + adplug/players.cpp\ + adplug/players.h\ + adplug/protrack.cpp\ + adplug/protrack.h\ + adplug/psi.cpp\ + adplug/psi.h\ adplug/rad.cpp\ + adplug/rad.h\ + adplug/rat.cpp\ + adplug/rat.h\ adplug/raw.cpp\ + adplug/raw.h\ + adplug/realopl.cpp\ + adplug/realopl.h\ + adplug/rix.cpp\ + adplug/rix.h\ + adplug/rol.cpp\ + adplug/rol.h\ + adplug/s3m.cpp\ + adplug/s3m.h\ adplug/sa2.cpp\ - adplug/xad.cpp\ - adplug/flash.cpp\ - adplug/bmf.cpp\ - adplug/hybrid.cpp\ - adplug/hyp.cpp\ - adplug/psi.cpp\ - adplug/rat.cpp\ + adplug/sa2.h\ + adplug/silentopl.h\ + adplug/sng.cpp\ + adplug/sng.h\ + adplug/surroundopl.cpp\ + adplug/surroundopl.h\ + adplug/temuopl.cpp\ + adplug/temuopl.h\ adplug/u6m.cpp\ - adplug/rol.cpp\ - adplug/mididata.h\ + adplug/u6m.h\ + adplug/xad.cpp\ + adplug/xad.h\ adplug/xsm.cpp\ - adplug/adlibemu.c\ - adplug/dro.cpp\ - adplug/lds.cpp\ - adplug/realopl.cpp\ - adplug/analopl.cpp\ - adplug/temuopl.cpp\ - adplug/msc.cpp\ - adplug/rix.cpp\ - adplug/adl.cpp\ - libbinio/binfile.h\ - libbinio/binio.h\ - libbinio/binstr.h\ - libbinio/binwrap.h\ - libbinio/binfile.cpp\ - libbinio/binio.cpp\ - libbinio/binstr.cpp\ - libbinio/binwrap.cpp + adplug/xsm.h adplug_la_LDFLAGS = -module -AM_CXXFLAGS = $(CFLAGS) -Dstricmp=strcasecmp -DVERSION=\"2.1\" -I adplug -I libbinio -AM_CFLAGS = $(CFLAGS) -std=c99 + diff --git a/plugins/adplug/adplug-db.cpp b/plugins/adplug/adplug-db.cpp index f5b37ee7..b28da612 100644 --- a/plugins/adplug/adplug-db.cpp +++ b/plugins/adplug/adplug-db.cpp @@ -36,9 +36,9 @@ extern DB_decoder_t adplug_plugin; static DB_functions_t *deadbeef; -const char *adplug_exts[] = { "A2M", "ADL", "AMD", "BAM", "CFF", "CMF", "D00", "DFM", "DMO", "DRO", "DTM", "HSC", "HSP", "IMF", "KSM", "LAA", "LDS", "M", "MAD", "MID", "MKJ", "MSC", "MTK", "RAD", "RAW", "RIX", "ROL", "S3M", "SA2", "SAT", "SCI", "SNG", "SNG", "SNG", "XAD", "XMS", "XSM", NULL }; +const char *adplug_exts[] = { "A2M", "ADL", "AMD", "BAM", "CFF", "CMF", "D00", "DFM", "DMO", "DRO", "DTM", "HSC", "HSP", "IMF", "KSM", "LAA", "LDS", "M", "MAD", "MID", "MKJ", "MSC", "MTK", "RAD", "RAW", "RIX", "ROL", "S3M", "SA2", "SAT", "SCI", "SNG", "SNG", "SNG", "XAD", "XMS", "XSM", "JBM", NULL }; -const char *adplug_filetypes[] = { "A2M", "ADL", "AMD", "BAM", "CFF", "CMF", "D00", "DFM", "DMO", "DRO", "DTM", "HSC", "HSP", "IMF", "KSM", "LAA", "LDS", "M", "MAD", "MID", "MKJ", "MSC", "MTK", "RAD", "RAW", "RIX", "ROL", "S3M", "SA2", "SAT", "SCI", "SNG", "SNG", "SNG", "XAD", "XMS", "XSM", NULL }; +const char *adplug_filetypes[] = { "A2M", "ADL", "AMD", "BAM", "CFF", "CMF", "D00", "DFM", "DMO", "DRO", "DTM", "HSC", "HSP", "IMF", "KSM", "LAA", "LDS", "M", "MAD", "MID", "MKJ", "MSC", "MTK", "RAD", "RAW", "RIX", "ROL", "S3M", "SA2", "SAT", "SCI", "SNG", "SNG", "SNG", "XAD", "XMS", "XSM", "JBM", NULL }; static CEmuopl *opl; static CPlayer *decoder; @@ -54,11 +54,13 @@ adplug_init (DB_playItem_t *it) { int samplerate = deadbeef->get_output ()->samplerate (); int bps = deadbeef->get_output ()->bitspersample (); - opl = new CEmuopl (samplerate, bps, deadbeef->get_output ()->channels () == 2); + int channels = 2; + opl = new CEmuopl (samplerate, true, channels == 2); +// opl->settype (Copl::TYPE_OPL2); decoder = CAdPlug::factory (it->fname, opl, CAdPlug::players); if (!decoder) { trace ("adplug: failed to open %s\n", it->fname); - return NULL; + return -1; } subsong = it->tracknum; @@ -69,11 +71,11 @@ adplug_init (DB_playItem_t *it) { // fill in mandatory plugin fields adplug_plugin.info.bps = bps; - adplug_plugin.info.channels = deadbeef->get_output ()->channels (); + adplug_plugin.info.channels = channels; adplug_plugin.info.samplerate = samplerate; adplug_plugin.info.readpos = 0; -// trace ("adplug_init ok (duration=%f, totalsamples=%d)\n", deadbeef->pl_get_item_duration (it), totalsamples); + trace ("adplug_init ok (duration=%f, totalsamples=%d)\n", deadbeef->pl_get_item_duration (it), totalsamples); return 0; } @@ -98,7 +100,7 @@ adplug_read_int16 (char *bytes, int size) { // return 0 on EOF bool playing = true; int i; - int sampsize = 4; + int sampsize = (adplug_plugin.info.bps >> 3) * adplug_plugin.info.channels; if (currentsample + size/4 >= totalsamples) { // clip diff --git a/plugins/adplug/adplug/COPYING b/plugins/adplug/adplug/COPYING deleted file mode 100644 index aaf2c633..00000000 --- a/plugins/adplug/adplug/COPYING +++ /dev/null @@ -1,509 +0,0 @@ - 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. -^L - 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. -^L - 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. -^L - 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. -^L - 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. -^L - 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. -^L - 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. -^L - 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 -^L - 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. - - - <one line to give the library's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - 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. - - <signature of Ty Coon>, 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/plugins/adplug/adplug/a2m.cpp b/plugins/adplug/adplug/a2m.cpp index 3fd68d98..d9d775e2 100644 --- a/plugins/adplug/adplug/a2m.cpp +++ b/plugins/adplug/adplug/a2m.cpp @@ -29,7 +29,7 @@ * Following commands are ignored: Gxy, Hxy, Kxy - &xy */ -#include <string.h> +#include <cstring> #include "a2m.h" const unsigned int Ca2mLoader::MAXFREQ = 2000, @@ -65,7 +65,7 @@ bool Ca2mLoader::load(const std::string &filename, const CFileProvider &fp) char id[10]; int i,j,k,t; unsigned int l; - unsigned char *org, *orgptr, flags = 0, numpats, version; + unsigned char *org = 0, *orgptr, flags = 0, numpats, version; unsigned long crc, alength; unsigned short len[9], *secdata, *secptr; const unsigned char convfx[16] = {0,1,2,23,24,3,5,4,6,9,17,13,11,19,7,14}; diff --git a/plugins/adplug/adplug/adl.cpp b/plugins/adplug/adplug/adl.cpp index 40896fdb..ae8c4e99 100644 --- a/plugins/adplug/adplug/adl.cpp +++ b/plugins/adplug/adplug/adl.cpp @@ -44,14 +44,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * $URL: https://svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/engines/kyra/sound_adlib.cpp $ - * $Id: adl.cpp,v 1.9 2006/08/16 00:20:45 dynamite Exp $ + * $Id: adl.cpp,v 1.11 2008/02/11 20:18:27 dynamite Exp $ * */ +#include <cstring> #include <inttypes.h> #include <stdarg.h> #include <assert.h> -#include <string.h> #include "adl.h" #include "debug.h" @@ -2378,16 +2378,22 @@ bool CadlPlayer::load(const std::string &filename, const CFileProvider &fp) // _soundFileLoaded = file; - for(int i = 0; i < 200; i++) - if(_trackEntries[i] != 0xff) + // find last subsong + for(int i = 199; i >= 0; i--) + if(_trackEntries[i] != 0xff) { numsubsongs = i + 1; + break; + } fp.close(f); + cursubsong = 2; + rewind(); return true; } void CadlPlayer::rewind(int subsong) { + if(subsong == -1) subsong = cursubsong; opl->init(); opl->write(1,32); playSoundEffect(subsong); diff --git a/plugins/adplug/adplug/adl.h b/plugins/adplug/adplug/adl.h index b0030c43..203692b0 100644 --- a/plugins/adplug/adplug/adl.h +++ b/plugins/adplug/adplug/adl.h @@ -1,6 +1,20 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al. + * Copyright (C) 1999 - 2007 Simon Peter, <dn.tlp@gmx.net>, et al. + * + * 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 * * adl.h - ADL player adaption by Simon Peter <dn.tlp@gmx.net> */ @@ -24,7 +38,7 @@ class CadlPlayer: public CPlayer bool load(const std::string &filename, const CFileProvider &fp); bool update(); - void rewind(int subsong); + void rewind(int subsong = -1); // refresh rate is fixed at 72Hz float getrefresh() @@ -33,6 +47,7 @@ class CadlPlayer: public CPlayer } unsigned int getsubsongs(); + unsigned int getsubsong() { return cursubsong; } std::string gettype() { return std::string("Westwood ADL"); } private: diff --git a/plugins/adplug/adplug/adplug.cpp b/plugins/adplug/adplug/adplug.cpp index 32fea695..f4b8e729 100644 --- a/plugins/adplug/adplug/adplug.cpp +++ b/plugins/adplug/adplug/adplug.cpp @@ -1,6 +1,6 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2006 Simon Peter <dn.tlp@gmx.net>, et al. + * Copyright (C) 1999 - 2008 Simon Peter <dn.tlp@gmx.net>, et al. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,9 +19,9 @@ * adplug.cpp - CAdPlug utility class, by Simon Peter <dn.tlp@gmx.net> */ +#include <cstring> #include <string> #include <binfile.h> -#include <string.h> #include "adplug.h" #include "debug.h" @@ -35,6 +35,7 @@ #include "sng.h" #include "adtrack.h" #include "bam.h" +//#include "cmf.h" #include "d00.h" #include "dfm.h" #include "hsp.h" @@ -62,9 +63,11 @@ #include "rol.h" #include "xsm.h" #include "dro.h" +#include "dro2.h" #include "msc.h" #include "rix.h" #include "adl.h" +#include "jbm.h" /***** CAdPlug *****/ @@ -77,12 +80,13 @@ const CPlayerDesc CAdPlug::allplayers[] = { CPlayerDesc(CadtrackLoader::factory, "Adlib Tracker", ".sng\0"), CPlayerDesc(CamdLoader::factory, "AMUSIC", ".amd\0"), CPlayerDesc(CbamPlayer::factory, "Bob's Adlib Music", ".bam\0"), +// CPlayerDesc(CcmfPlayer::factory, "Creative Music File", ".cmf\0"), CPlayerDesc(Cd00Player::factory, "Packed EdLib", ".d00\0"), CPlayerDesc(CdfmLoader::factory, "Digital-FM", ".dfm\0"), CPlayerDesc(ChspLoader::factory, "HSC Packed", ".hsp\0"), CPlayerDesc(CksmPlayer::factory, "Ken Silverman Music", ".ksm\0"), CPlayerDesc(CmadLoader::factory, "Mlat Adlib Tracker", ".mad\0"), - CPlayerDesc(CmidPlayer::factory, "MIDI", ".mid\0.cmf\0.sci\0.laa\0"), + CPlayerDesc(CmidPlayer::factory, "MIDI", ".mid\0.sci\0.laa\0.cmf\0"), CPlayerDesc(CmkjPlayer::factory, "MKJamz", ".mkj\0"), CPlayerDesc(CcffLoader::factory, "Boomtracker", ".cff\0"), CPlayerDesc(CdmoLoader::factory, "TwinTeam", ".dmo\0"), @@ -103,10 +107,12 @@ const CPlayerDesc CAdPlug::allplayers[] = { CPlayerDesc(Cu6mPlayer::factory, "Ultima 6 Music", ".m\0"), CPlayerDesc(CrolPlayer::factory, "Adlib Visual Composer", ".rol\0"), CPlayerDesc(CxsmPlayer::factory, "eXtra Simple Music", ".xsm\0"), - CPlayerDesc(CdroPlayer::factory, "DOSBox Raw OPL", ".dro\0"), + CPlayerDesc(CdroPlayer::factory, "DOSBox Raw OPL v0.1", ".dro\0"), + CPlayerDesc(Cdro2Player::factory, "DOSBox Raw OPL v2.0", ".dro\0"), CPlayerDesc(CmscPlayer::factory, "Adlib MSC Player", ".msc\0"), CPlayerDesc(CrixPlayer::factory, "Softstar RIX OPL Music", ".rix\0"), CPlayerDesc(CadlPlayer::factory, "Westwood ADL", ".adl\0"), + CPlayerDesc(CjbmPlayer::factory, "JBM Adlib Music", ".jbm\0"), CPlayerDesc() }; @@ -124,39 +130,41 @@ const CPlayers &CAdPlug::init_players(const CPlayerDesc pd[]) const CPlayers CAdPlug::players = CAdPlug::init_players(CAdPlug::allplayers); CAdPlugDatabase *CAdPlug::database = 0; -CPlayer *CAdPlug::factory(const char *fn, Copl *opl, const CPlayers &pl, +CPlayer *CAdPlug::factory(const std::string &fn, Copl *opl, const CPlayers &pl, const CFileProvider &fp) { CPlayer *p; CPlayers::const_iterator i; unsigned int j; - AdPlug_LogWrite("*** CAdPlug::factory(\"%s\",opl,fp) ***\n", fn); + AdPlug_LogWrite("*** CAdPlug::factory(\"%s\",opl,fp) ***\n", fn.c_str()); // Try a direct hit by file extension for(i = pl.begin(); i != pl.end(); i++) for(j = 0; (*i)->get_extension(j); j++) if(fp.extension(fn, (*i)->get_extension(j))) { AdPlug_LogWrite("Trying direct hit: %s\n", (*i)->filetype.c_str()); - if((p = (*i)->factory(opl))) + if((p = (*i)->factory(opl))) { if(p->load(fn, fp)) { AdPlug_LogWrite("got it!\n"); AdPlug_LogWrite("--- CAdPlug::factory ---\n"); return p; } else delete p; + } } // Try all players, one by one for(i = pl.begin(); i != pl.end(); i++) { AdPlug_LogWrite("Trying: %s\n", (*i)->filetype.c_str()); - if((p = (*i)->factory(opl))) + if((p = (*i)->factory(opl))) { if(p->load(fn, fp)) { AdPlug_LogWrite("got it!\n"); AdPlug_LogWrite("--- CAdPlug::factory ---\n"); return p; } else delete p; + } } // Unknown file diff --git a/plugins/adplug/adplug/adplug.h b/plugins/adplug/adplug/adplug.h index 54ee042a..e5aec896 100644 --- a/plugins/adplug/adplug/adplug.h +++ b/plugins/adplug/adplug/adplug.h @@ -37,7 +37,7 @@ class CAdPlug public: static const CPlayers players; - static CPlayer *factory(const char *fn, Copl *opl, + static CPlayer *factory(const std::string &fn, Copl *opl, const CPlayers &pl = players, const CFileProvider &fp = CProvider_Filesystem()); diff --git a/plugins/adplug/adplug/bmf.cpp b/plugins/adplug/adplug/bmf.cpp index df403c86..469fde43 100644 --- a/plugins/adplug/adplug/bmf.cpp +++ b/plugins/adplug/adplug/bmf.cpp @@ -40,7 +40,7 @@ comment : inaccurate replaying, because constant outport; in original player it can be 380 or 382. */ -#include <string.h> +#include <cstring> #include "bmf.h" #include "debug.h" diff --git a/plugins/adplug/adplug/cff.cpp b/plugins/adplug/adplug/cff.cpp index 37197fd9..68a11692 100644 --- a/plugins/adplug/adplug/cff.cpp +++ b/plugins/adplug/adplug/cff.cpp @@ -1,6 +1,6 @@ /* AdPlug - Replayer for many OPL2/OPL3 audio file formats. - Copyright (C) 1999 - 2006 Simon Peter <dn.tlp@gmx.net>, et al. + Copyright (C) 1999 - 2008 Simon Peter <dn.tlp@gmx.net>, et al. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -24,6 +24,7 @@ slides use previous effect data instead of current. */ +#include <cstring> #include <stdlib.h> #include <string.h> diff --git a/plugins/adplug/adplug/cmf.cpp b/plugins/adplug/adplug/cmf.cpp new file mode 100644 index 00000000..580b6df3 --- /dev/null +++ b/plugins/adplug/adplug/cmf.cpp @@ -0,0 +1,780 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2009 Simon Peter, <dn.tlp@gmx.net>, et al. + * + * 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 + * + * cmf.cpp - CMF player by Adam Nielsen <malvineous@shikadi.net> + * Subset of CMF reader in MOPL code (Malvineous' OPL player), no seeking etc. + */ + +#include <stdint.h> // for uintxx_t +#include <cassert> +#include <math.h> // for pow() etc. +#include <string.h> // for memset +#include "debug.h" +#include "cmf.h" + +// ------------------------------ +// OPTIONS +// ------------------------------ + +// The official Creative Labs CMF player seems to ignore the note velocity +// (playing every note at the same volume), but you can uncomment this to +// allow the note velocity to affect the volume (as presumably the composer +// originally intended.) +// +//#define USE_VELOCITY +// +// The Xargon demo song is a good example of a song that uses note velocity. + +// OPL register offsets +#define BASE_CHAR_MULT 0x20 +#define BASE_SCAL_LEVL 0x40 +#define BASE_ATCK_DCAY 0x60 +#define BASE_SUST_RLSE 0x80 +#define BASE_FNUM_L 0xA0 +#define BASE_KEYON_FREQ 0xB0 +#define BASE_RHYTHM 0xBD +#define BASE_WAVE 0xE0 +#define BASE_FEED_CONN 0xC0 + +#define OPLBIT_KEYON 0x20 // Bit in BASE_KEYON_FREQ register for turning a note on + +// Supplied with a channel, return the offset from a base OPL register for the +// Modulator cell (e.g. channel 4's modulator is at offset 0x09. Since 0x60 is +// the attack/decay function, register 0x69 will thus set the attack/decay for +// channel 4's modulator.) (channels go from 0 to 8 inclusive) +#define OPLOFFSET(channel) (((channel) / 3) * 8 + ((channel) % 3)) + +// These 16 instruments are repeated to fill up the 128 available slots. A CMF +// file can override none/some/all of the 128 slots with custom instruments, +// so any that aren't overridden are still available for use with these default +// patches. The Word Rescue CMFs are good examples of songs that rely on these +// default patches. +uint8_t cDefaultPatches[] = +"\x01\x11\x4F\x00\xF1\xD2\x53\x74\x00\x00\x06" +"\x07\x12\x4F\x00\xF2\xF2\x60\x72\x00\x00\x08" +"\x31\xA1\x1C\x80\x51\x54\x03\x67\x00\x00\x0E" +"\x31\xA1\x1C\x80\x41\x92\x0B\x3B\x00\x00\x0E" +"\x31\x16\x87\x80\xA1\x7D\x11\x43\x00\x00\x08" +"\x30\xB1\xC8\x80\xD5\x61\x19\x1B\x00\x00\x0C" +"\xF1\x21\x01\x00\x97\xF1\x17\x18\x00\x00\x08" +"\x32\x16\x87\x80\xA1\x7D\x10\x33\x00\x00\x08" +"\x01\x12\x4F\x00\x71\x52\x53\x7C\x00\x00\x0A" +"\x02\x03\x8D\x00\xD7\xF5\x37\x18\x00\x00\x04" +"\x21\x21\xD1\x00\xA3\xA4\x46\x25\x00\x00\x0A" +"\x22\x22\x0F\x00\xF6\xF6\x95\x36\x00\x00\x0A" +"\xE1\xE1\x00\x00\x44\x54\x24\x34\x02\x02\x07" +"\xA5\xB1\xD2\x80\x81\xF1\x03\x05\x00\x00\x02" +"\x71\x22\xC5\x00\x6E\x8B\x17\x0E\x00\x00\x02" +"\x32\x21\x16\x80\x73\x75\x24\x57\x00\x00\x0E"; + + +CPlayer *CcmfPlayer::factory(Copl *newopl) +{ + return new CcmfPlayer(newopl); +} + +CcmfPlayer::CcmfPlayer(Copl *newopl) : + CPlayer(newopl), + data(NULL), + pInstruments(NULL), + bPercussive(false), + iTranspose(0), + iPrevCommand(0) +{ + assert(OPLOFFSET(1-1) == 0x00); + assert(OPLOFFSET(5-1) == 0x09); + assert(OPLOFFSET(9-1) == 0x12); +} + +CcmfPlayer::~CcmfPlayer() +{ + if (this->data) delete[] data; +} + +bool CcmfPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + + char cSig[4]; + f->readString(cSig, 4); + if ( + (cSig[0] != 'C') || + (cSig[1] != 'T') || + (cSig[2] != 'M') || + (cSig[3] != 'F') + ) { + // Not a CMF file + fp.close(f); + return false; + } + uint16_t iVer = f->readInt(2); + if ((iVer != 0x0101) && (iVer != 0x0100)) { + AdPlug_LogWrite("CMF file is not v1.0 or v1.1 (reports %d.%d)\n", iVer >> 8 , iVer & 0xFF); + fp.close(f); + return false; + } + + this->cmfHeader.iInstrumentBlockOffset = f->readInt(2); + this->cmfHeader.iMusicOffset = f->readInt(2); + this->cmfHeader.iTicksPerQuarterNote = f->readInt(2); + this->cmfHeader.iTicksPerSecond = f->readInt(2); + this->cmfHeader.iTagOffsetTitle = f->readInt(2); + this->cmfHeader.iTagOffsetComposer = f->readInt(2); + this->cmfHeader.iTagOffsetRemarks = f->readInt(2); + f->readString((char *)this->cmfHeader.iChannelsInUse, 16); + this->cmfHeader.iNumInstruments = f->readInt(2); + this->cmfHeader.iTempo = f->readInt(2); + + // Load the instruments + + f->seek(this->cmfHeader.iInstrumentBlockOffset); + this->pInstruments = new SBI[128]; // Always 128 available for use + + for (int i = 0; i < this->cmfHeader.iNumInstruments; i++) { + this->pInstruments[i].op[0].iCharMult = f->readInt(1); + this->pInstruments[i].op[1].iCharMult = f->readInt(1); + this->pInstruments[i].op[0].iScalingOutput = f->readInt(1); + this->pInstruments[i].op[1].iScalingOutput = f->readInt(1); + this->pInstruments[i].op[0].iAttackDecay = f->readInt(1); + this->pInstruments[i].op[1].iAttackDecay = f->readInt(1); + this->pInstruments[i].op[0].iSustainRelease = f->readInt(1); + this->pInstruments[i].op[1].iSustainRelease = f->readInt(1); + this->pInstruments[i].op[0].iWaveSel = f->readInt(1); + this->pInstruments[i].op[1].iWaveSel = f->readInt(1); + this->pInstruments[i].iConnection = f->readInt(1); + f->seek(5, binio::Add); // skip over the padding bytes + } + + // Set the rest of the instruments to the CMF defaults + for (int i = this->cmfHeader.iNumInstruments; i < 128; i++) { + this->pInstruments[i].op[0].iCharMult = cDefaultPatches[(i % 16) * 11 + 0]; + this->pInstruments[i].op[1].iCharMult = cDefaultPatches[(i % 16) * 11 + 1]; + this->pInstruments[i].op[0].iScalingOutput = cDefaultPatches[(i % 16) * 11 + 2]; + this->pInstruments[i].op[1].iScalingOutput = cDefaultPatches[(i % 16) * 11 + 3]; + this->pInstruments[i].op[0].iAttackDecay = cDefaultPatches[(i % 16) * 11 + 4]; + this->pInstruments[i].op[1].iAttackDecay = cDefaultPatches[(i % 16) * 11 + 5]; + this->pInstruments[i].op[0].iSustainRelease = cDefaultPatches[(i % 16) * 11 + 6]; + this->pInstruments[i].op[1].iSustainRelease = cDefaultPatches[(i % 16) * 11 + 7]; + this->pInstruments[i].op[0].iWaveSel = cDefaultPatches[(i % 16) * 11 + 8]; + this->pInstruments[i].op[1].iWaveSel = cDefaultPatches[(i % 16) * 11 + 9]; + this->pInstruments[i].iConnection = cDefaultPatches[(i % 16) * 11 + 10]; + } + + if (this->cmfHeader.iTagOffsetTitle) { + f->seek(this->cmfHeader.iTagOffsetTitle); + this->strTitle = f->readString('\0'); + } + if (this->cmfHeader.iTagOffsetComposer) { + f->seek(this->cmfHeader.iTagOffsetComposer); + this->strComposer = f->readString('\0'); + } + if (this->cmfHeader.iTagOffsetRemarks) { + f->seek(this->cmfHeader.iTagOffsetRemarks); + this->strRemarks = f->readString('\0'); + } + + // Load the MIDI data into memory + f->seek(this->cmfHeader.iMusicOffset); + this->iSongLen = fp.filesize(f) - this->cmfHeader.iMusicOffset; + this->data = new unsigned char[this->iSongLen]; + f->readString((char *)data, this->iSongLen); + + fp.close(f); + rewind(0); + + return true; +} + +bool CcmfPlayer::update() +{ + // This has to be here and not in getrefresh() for some reason. + this->iDelayRemaining = 0; + + // Read in the next event + while (!this->iDelayRemaining) { + uint8_t iCommand = this->data[this->iPlayPointer++]; + if ((iCommand & 0x80) == 0) { + // Running status, use previous command + this->iPlayPointer--; + iCommand = this->iPrevCommand; + } else { + this->iPrevCommand = iCommand; + } + uint8_t iChannel = iCommand & 0x0F; + switch (iCommand & 0xF0) { + case 0x80: { // Note off (two data bytes) + uint8_t iNote = this->data[this->iPlayPointer++]; + uint8_t iVelocity = this->data[this->iPlayPointer++]; // release velocity + this->cmfNoteOff(iChannel, iNote, iVelocity); + break; + } + case 0x90: { // Note on (two data bytes) + uint8_t iNote = this->data[this->iPlayPointer++]; + uint8_t iVelocity = this->data[this->iPlayPointer++]; // attack velocity + if (iVelocity) { + this->cmfNoteOn(iChannel, iNote, iVelocity); + } else { + // This is a note-off instead (velocity == 0) + this->cmfNoteOff(iChannel, iNote, iVelocity); // 64 is the MIDI default note-off velocity + break; + } + break; + } + case 0xA0: { // Polyphonic key pressure (two data bytes) + uint8_t iNote = this->data[this->iPlayPointer++]; + uint8_t iPressure = this->data[this->iPlayPointer++]; + AdPlug_LogWrite("CMF: Key pressure not yet implemented! (wanted ch%d/note %d set to %d)\n", iChannel, iNote, iPressure); + break; + } + case 0xB0: { // Controller (two data bytes) + uint8_t iController = this->data[this->iPlayPointer++]; + uint8_t iValue = this->data[this->iPlayPointer++]; + this->MIDIcontroller(iChannel, iController, iValue); + break; + } + case 0xC0: { // Instrument change (one data byte) + uint8_t iNewInstrument = this->data[this->iPlayPointer++]; + this->chMIDI[iChannel].iPatch = iNewInstrument; + AdPlug_LogWrite("CMF: Remembering MIDI channel %d now uses patch %d\n", iChannel, iNewInstrument); + break; + } + case 0xD0: { // Channel pressure (one data byte) + uint8_t iPressure = this->data[this->iPlayPointer++]; + AdPlug_LogWrite("CMF: Channel pressure not yet implemented! (wanted ch%d set to %d)\n", iChannel, iPressure); + break; + } + case 0xE0: { // Pitch bend (two data bytes) + uint8_t iLSB = this->data[this->iPlayPointer++]; + uint8_t iMSB = this->data[this->iPlayPointer++]; + uint16_t iValue = (iMSB << 7) | iLSB; + // 8192 is middle/off, 0 is -2 semitones, 16384 is +2 semitones + this->chMIDI[iChannel].iPitchbend = iValue; + AdPlug_LogWrite("CMF: Channel %d pitchbent to %d (%+.2f)\n", iChannel + 1, iValue, (float)(iValue - 8192) / 8192); + break; + } + case 0xF0: // System message (arbitrary data bytes) + switch (iCommand) { + case 0xF0: { // Sysex + uint8_t iNextByte; + AdPlug_LogWrite("Sysex message: "); + do { + iNextByte = this->data[this->iPlayPointer++]; + AdPlug_LogWrite("%02X", iNextByte); + } while ((iNextByte & 0x80) == 0); + AdPlug_LogWrite("\n"); + // This will have read in the terminating EOX (0xF7) message too + break; + } + case 0xF1: // MIDI Time Code Quarter Frame + this->iPlayPointer++; + //this->data[this->iPlayPointer++]; // message data (ignored) + break; + case 0xF2: // Song position pointer + this->iPlayPointer++; + this->iPlayPointer++; +// this->data[this->iPlayPointer++]; // message data (ignored) +// this->data[this->iPlayPointer++]; + break; + case 0xF3: // Song select + this->iPlayPointer++; +// this->data[this->iPlayPointer++]; // message data (ignored) + AdPlug_LogWrite("CMF: MIDI Song Select is not implemented.\n"); + break; + case 0xF6: // Tune request + break; + case 0xF7: // End of System Exclusive (EOX) - should never be read, should be absorbed by Sysex handling code + break; + + // These messages are "real time", meaning they can be sent between + // the bytes of other messages - but we're lazy and don't handle these + // here (hopefully they're not necessary in a MIDI file, and even less + // likely to occur in a CMF.) + case 0xF8: // Timing clock (sent 24 times per quarter note, only when playing) + case 0xFA: // Start + case 0xFB: // Continue + case 0xFE: // Active sensing (sent every 300ms or MIDI connection assumed lost) + break; + case 0xFC: // Stop + AdPlug_LogWrite("CMF: Received Real Time Stop message (0xFC)\n"); + this->bSongEnd = true; + this->iPlayPointer = 0; // for repeat in endless-play mode + break; + case 0xFF: { // System reset, used as meta-events in a MIDI file + uint8_t iEvent = this->data[this->iPlayPointer++]; + switch (iEvent) { + case 0x2F: // end of track + AdPlug_LogWrite("CMF: End-of-track, stopping playback\n"); + this->bSongEnd = true; + this->iPlayPointer = 0; // for repeat in endless-play mode + break; + default: + AdPlug_LogWrite("CMF: Unknown MIDI meta-event 0xFF 0x%02X\n", iEvent); + break; + } + break; + } + default: + AdPlug_LogWrite("CMF: Unknown MIDI system command 0x%02X\n", iCommand); + break; + } + break; + default: + AdPlug_LogWrite("CMF: Unknown MIDI command 0x%02X\n", iCommand); + break; + } + + if (this->iPlayPointer >= this->iSongLen) { + this->bSongEnd = true; + this->iPlayPointer = 0; // for repeat in endless-play mode + } + + // Read in the number of ticks until the next event + this->iDelayRemaining = this->readMIDINumber(); + } + + return !this->bSongEnd; +} + +void CcmfPlayer::rewind(int subsong) +{ + this->opl->init(); + + // Initialise + + // Enable use of WaveSel register on OPL3 (even though we're only an OPL2!) + // Apparently this enables nine-channel mode? + this->writeOPL(0x01, 0x20); + + // Really make sure CSM+SEL are off (again, Creative's player...) + this->writeOPL(0x08, 0x00); + + // This freq setting is required for the hihat to sound correct at the start + // of funky.cmf, even though it's for an unrelated channel. + // If it's here however, it makes the hihat in Word Rescue's theme.cmf + // sound really bad. + // TODO: How do we figure out whether we need it or not??? + this->writeOPL(BASE_FNUM_L + 8, 514 & 0xFF); + this->writeOPL(BASE_KEYON_FREQ + 8, (1 << 2) | (514 >> 8)); + + // default freqs? + this->writeOPL(BASE_FNUM_L + 7, 509 & 0xFF); + this->writeOPL(BASE_KEYON_FREQ + 7, (2 << 2) | (509 >> 8)); + this->writeOPL(BASE_FNUM_L + 6, 432 & 0xFF); + this->writeOPL(BASE_KEYON_FREQ + 6, (2 << 2) | (432 >> 8)); + + // Amplify AM + VIB depth. Creative's CMF player does this, and there + // doesn't seem to be any way to stop it from doing so - except for the + // non-standard controller 0x63 I added :-) + this->writeOPL(0xBD, 0xC0); + + this->bSongEnd = false; + this->iPlayPointer = 0; + this->iPrevCommand = 0; // just in case + + // Read in the number of ticks until the first event + this->iDelayRemaining = this->readMIDINumber(); + + // Reset song state. This used to be in the constructor, but the XMMS2 + // plugin sets the song length before starting playback. AdPlug plays the + // song in its entirety (with no synth) to determine the song length, which + // results in the state variables below matching the end of the song. When + // the real OPL synth is activated for playback, it no longer matches the + // state variables and the instruments are not set correctly! + for (int i = 0; i < 9; i++) { + this->chOPL[i].iNoteStart = 0; // no note playing atm + this->chOPL[i].iMIDINote = -1; + this->chOPL[i].iMIDIChannel = -1; + this->chOPL[i].iMIDIPatch = -1; + + this->chMIDI[i].iPatch = -2; + this->chMIDI[i].iPitchbend = 8192; + } + for (int i = 9; i < 16; i++) { + this->chMIDI[i].iPatch = -2; + this->chMIDI[i].iPitchbend = 8192; + } + + memset(this->iCurrentRegs, 0, 256); + + return; +} + +// Return value: 1 == 1 second, 2 == 0.5 seconds +float CcmfPlayer::getrefresh() +{ + if (this->iDelayRemaining) { + return (float)this->cmfHeader.iTicksPerSecond / (float)this->iDelayRemaining; + } else { + // Delay-remaining is zero (e.g. start of song) so use a tiny delay + return this->cmfHeader.iTicksPerSecond; // wait for one tick + } +} + +std::string CcmfPlayer::gettitle() +{ + return this->strTitle; +} +std::string CcmfPlayer::getauthor() +{ + return this->strComposer; +} +std::string CcmfPlayer::getdesc() +{ + return this->strRemarks; +} + + +// +// PROTECTED +// + +// Read a variable-length integer from MIDI data +uint32_t CcmfPlayer::readMIDINumber() +{ + uint32_t iValue = 0; + for (int i = 0; i < 4; i++) { + uint8_t iNext = this->data[this->iPlayPointer++]; + iValue <<= 7; + iValue |= (iNext & 0x7F); // ignore the MSB + if ((iNext & 0x80) == 0) break; // last byte has the MSB unset + } + return iValue; +} + +// iChannel: OPL channel (0-8) +// iOperator: 0 == Modulator, 1 == Carrier +// Source - source operator to read from instrument definition +// Dest - destination operator on OPL chip +// iInstrument: Index into this->pInstruments array of CMF instruments +void CcmfPlayer::writeInstrumentSettings(uint8_t iChannel, uint8_t iOperatorSource, uint8_t iOperatorDest, uint8_t iInstrument) +{ + assert(iChannel <= 8); + + uint8_t iOPLOffset = OPLOFFSET(iChannel); + if (iOperatorDest) iOPLOffset += 3; // Carrier if iOperator == 1 (else Modulator) + + this->writeOPL(BASE_CHAR_MULT + iOPLOffset, this->pInstruments[iInstrument].op[iOperatorSource].iCharMult); + this->writeOPL(BASE_SCAL_LEVL + iOPLOffset, this->pInstruments[iInstrument].op[iOperatorSource].iScalingOutput); + this->writeOPL(BASE_ATCK_DCAY + iOPLOffset, this->pInstruments[iInstrument].op[iOperatorSource].iAttackDecay); + this->writeOPL(BASE_SUST_RLSE + iOPLOffset, this->pInstruments[iInstrument].op[iOperatorSource].iSustainRelease); + this->writeOPL(BASE_WAVE + iOPLOffset, this->pInstruments[iInstrument].op[iOperatorSource].iWaveSel); + + // TODO: Check to see whether we should only be loading this for one or both operators + this->writeOPL(BASE_FEED_CONN + iChannel, this->pInstruments[iInstrument].iConnection); + return; +} + +// Write a byte to the OPL "chip" and update the current record of register states +void CcmfPlayer::writeOPL(uint8_t iRegister, uint8_t iValue) +{ + this->opl->write(iRegister, iValue); + this->iCurrentRegs[iRegister] = iValue; + return; +} + +void CcmfPlayer::cmfNoteOn(uint8_t iChannel, uint8_t iNote, uint8_t iVelocity) +{ + uint8_t iBlock = iNote / 12; + if (iBlock > 1) iBlock--; // keep in the same range as the Creative player + //if (iBlock > 7) iBlock = 7; // don't want to go out of range + + double d = pow(2, ( + (double)iNote + ( + (this->chMIDI[iChannel].iPitchbend - 8192) / 8192.0 + ) + ( + this->iTranspose / 128 + ) - 9) / 12.0 - (iBlock - 20)) + * 440.0 / 32.0 / 50000.0; + uint16_t iOPLFNum = (uint16_t)(d+0.5); + if (iOPLFNum > 1023) AdPlug_LogWrite("CMF: This note is out of range! (send this song to malvineous@shikadi.net!)\n"); + + // See if we're playing a rhythm mode percussive instrument + if ((iChannel > 10) && (this->bPercussive)) { + uint8_t iPercChannel = this->getPercChannel(iChannel); + + // Will have to set every time (easier) than figuring out whether the mod + // or car needs to be changed. + //if (this->chOPL[iPercChannel].iMIDIPatch != this->chMIDI[iChannel].iPatch) { + this->MIDIchangeInstrument(iPercChannel, iChannel, this->chMIDI[iChannel].iPatch); + //} + + /* Velocity calculations - TODO: Work out the proper formula + + iVelocity -> iLevel (values generated by Creative's player) + 7f -> 00 + 7c -> 00 + + 7b -> 09 + 73 -> 0a + 6b -> 0b + 63 -> 0c + 5b -> 0d + 53 -> 0e + 4b -> 0f + 43 -> 10 + 3b -> 11 + 33 -> 13 + 2b -> 15 + 23 -> 19 + 1b -> 1b + 13 -> 1d + 0b -> 1f + 03 -> 21 + + 02 -> 21 + 00 -> N/A (note off) + */ + // Approximate formula, need to figure out more accurate one (my maths isn't so good...) + int iLevel = 0x25 - sqrt(iVelocity * 16/*6*/);//(127 - iVelocity) * 0x20 / 127; + if (iVelocity > 0x7b) iLevel = 0; // full volume + if (iLevel < 0) iLevel = 0; + if (iLevel > 0x3F) iLevel = 0x3F; + //if (iVelocity < 0x40) iLevel = 0x10; + + int iOPLOffset = BASE_SCAL_LEVL + OPLOFFSET(iPercChannel); + //if ((iChannel == 11) || (iChannel == 12) || (iChannel == 14)) { + if (iChannel == 11) iOPLOffset += 3; // only do bassdrum carrier for volume control + //iOPLOffset += 3; // carrier + this->writeOPL(iOPLOffset, (this->iCurrentRegs[iOPLOffset] & ~0x3F) | iLevel);//(iVelocity * 0x3F / 127)); + //} + // Bass drum (ch11) uses both operators + //if (iChannel == 11) this->writeOPL(iOPLOffset + 3, (this->iCurrentRegs[iOPLOffset + 3] & ~0x3F) | iLevel); + +/* #ifdef USE_VELOCITY // Official CMF player seems to ignore velocity levels + uint16_t iLevel = 0x2F - (iVelocity * 0x2F / 127); // 0x2F should be 0x3F but it's too quiet then + AdPlug_LogWrite("%02X + vel %d (lev %02X) == %02X\n", this->iCurrentRegs[iOPLOffset], iVelocity, iLevel, (this->iCurrentRegs[iOPLOffset] & ~0x3F) | iLevel); + //this->writeOPL(iOPLOffset, (this->iCurrentRegs[iOPLOffset] & ~0x3F) | (0x3F - (iVelocity >> 1)));//(iVelocity * 0x3F / 127)); + this->writeOPL(iOPLOffset, (this->iCurrentRegs[iOPLOffset] & ~0x3F) | iLevel);//(iVelocity * 0x3F / 127)); + #endif*/ + + // Apparently you can't set the frequency for the cymbal or hihat? + // Vinyl requires you don't set it, Kiloblaster requires you do! + this->writeOPL(BASE_FNUM_L + iPercChannel, iOPLFNum & 0xFF); + this->writeOPL(BASE_KEYON_FREQ + iPercChannel, (iBlock << 2) | ((iOPLFNum >> 8) & 0x03)); + + uint8_t iBit = 1 << (15 - iChannel); + + // Turn the perc instrument off if it's already playing (OPL can't do + // polyphonic notes w/ percussion) + if (this->iCurrentRegs[BASE_RHYTHM] & iBit) this->writeOPL(BASE_RHYTHM, this->iCurrentRegs[BASE_RHYTHM] & ~iBit); + + // I wonder whether we need to delay or anything here? + + // Turn the note on + //if (iChannel == 15) { + this->writeOPL(BASE_RHYTHM, this->iCurrentRegs[BASE_RHYTHM] | iBit); + //AdPlug_LogWrite("CMF: Note %d on MIDI channel %d (mapped to OPL channel %d-1) - vel %02X, fnum %d/%d\n", iNote, iChannel, iPercChannel+1, iVelocity, iOPLFNum, iBlock); + //} + + this->chOPL[iPercChannel].iNoteStart = ++this->iNoteCount; + this->chOPL[iPercChannel].iMIDIChannel = iChannel; + this->chOPL[iPercChannel].iMIDINote = iNote; + + } else { // Non rhythm-mode or a normal instrument channel + + // Figure out which OPL channel to play this note on + int iOPLChannel = -1; + int iNumChannels = this->bPercussive ? 6 : 9; + for (int i = iNumChannels - 1; i >= 0; i--) { + // If there's no note playing on this OPL channel, use that + if (this->chOPL[i].iNoteStart == 0) { + iOPLChannel = i; + // See if this channel is already set to the instrument we want. + if (this->chOPL[i].iMIDIPatch == this->chMIDI[iChannel].iPatch) { + // It is, so stop searching + break; + } // else keep searching just in case there's a better match + } + } + if (iOPLChannel == -1) { + // All channels were in use, find the one with the longest note + iOPLChannel = 0; + int iEarliest = this->chOPL[0].iNoteStart; + for (int i = 1; i < iNumChannels; i++) { + if (this->chOPL[i].iNoteStart < iEarliest) { + // Found a channel with a note being played for longer + iOPLChannel = i; + iEarliest = this->chOPL[i].iNoteStart; + } + } + AdPlug_LogWrite("CMF: Too many polyphonic notes, cutting note on channel %d\n", iOPLChannel); + } + + // Run through all the channels with negative notestart values - these + // channels have had notes recently stop - and increment the counter + // to slowly move the channel closer to being reused for a future note. + //for (int i = 0; i < iNumChannels; i++) { + // if (this->chOPL[i].iNoteStart < 0) this->chOPL[i].iNoteStart++; + //} + + // Now the new note should be played on iOPLChannel, but see if the instrument + // is right first. + if (this->chOPL[iOPLChannel].iMIDIPatch != this->chMIDI[iChannel].iPatch) { + this->MIDIchangeInstrument(iOPLChannel, iChannel, this->chMIDI[iChannel].iPatch); + } + + this->chOPL[iOPLChannel].iNoteStart = ++this->iNoteCount; + this->chOPL[iOPLChannel].iMIDIChannel = iChannel; + this->chOPL[iOPLChannel].iMIDINote = iNote; + + #ifdef USE_VELOCITY // Official CMF player seems to ignore velocity levels + // Adjust the channel volume to match the note velocity + uint8_t iOPLOffset = BASE_SCAL_LEVL + OPLOFFSET(iChannel) + 3; // +3 == Carrier + uint16_t iLevel = 0x2F - (iVelocity * 0x2F / 127); // 0x2F should be 0x3F but it's too quiet then + this->writeOPL(iOPLOffset, (this->iCurrentRegs[iOPLOffset] & ~0x3F) | iLevel); + #endif + + // Set the frequency and play the note + this->writeOPL(BASE_FNUM_L + iOPLChannel, iOPLFNum & 0xFF); + this->writeOPL(BASE_KEYON_FREQ + iOPLChannel, OPLBIT_KEYON | (iBlock << 2) | ((iOPLFNum & 0x300) >> 8)); + } + return; +} + +void CcmfPlayer::cmfNoteOff(uint8_t iChannel, uint8_t iNote, uint8_t iVelocity) +{ + if ((iChannel > 10) && (this->bPercussive)) { + int iOPLChannel = this->getPercChannel(iChannel); + if (this->chOPL[iOPLChannel].iMIDINote != iNote) return; // there's a different note playing now + this->writeOPL(BASE_RHYTHM, this->iCurrentRegs[BASE_RHYTHM] & ~(1 << (15 - iChannel))); + this->chOPL[iOPLChannel].iNoteStart = 0; // channel free + } else { // Non rhythm-mode or a normal instrument channel + int iOPLChannel = -1; + int iNumChannels = this->bPercussive ? 6 : 9; + for (int i = 0; i < iNumChannels; i++) { + if ( + (this->chOPL[i].iMIDIChannel == iChannel) && + (this->chOPL[i].iMIDINote == iNote) && + (this->chOPL[i].iNoteStart != 0) + ) { + // Found the note, switch it off + this->chOPL[i].iNoteStart = 0; + iOPLChannel = i; + break; + } + } + if (iOPLChannel == -1) return; + + this->writeOPL(BASE_KEYON_FREQ + iOPLChannel, this->iCurrentRegs[BASE_KEYON_FREQ + iOPLChannel] & ~OPLBIT_KEYON); + } + return; +} + +uint8_t CcmfPlayer::getPercChannel(uint8_t iChannel) +{ + switch (iChannel) { + case 11: return 7-1; // Bass drum + case 12: return 8-1; // Snare drum + case 13: return 9-1; // Tom tom + case 14: return 9-1; // Top cymbal + case 15: return 8-1; // Hihat + } + AdPlug_LogWrite("CMF ERR: Tried to get the percussion channel from MIDI channel %d - this shouldn't happen!\n", iChannel); + return 0; +} + + +void CcmfPlayer::MIDIchangeInstrument(uint8_t iOPLChannel, uint8_t iMIDIChannel, uint8_t iNewInstrument) +{ + if ((iMIDIChannel > 10) && (this->bPercussive)) { + switch (iMIDIChannel) { + case 11: // Bass drum (operator 13+16 == channel 7 modulator+carrier) + this->writeInstrumentSettings(7-1, 0, 0, iNewInstrument); + this->writeInstrumentSettings(7-1, 1, 1, iNewInstrument); + break; + case 12: // Snare drum (operator 17 == channel 8 carrier) + //case 15: + this->writeInstrumentSettings(8-1, 0, 1, iNewInstrument); + + // + //this->writeInstrumentSettings(8-1, 0, 0, iNewInstrument); + break; + case 13: // Tom tom (operator 15 == channel 9 modulator) + //case 14: + this->writeInstrumentSettings(9-1, 0, 0, iNewInstrument); + + // + //this->writeInstrumentSettings(9-1, 0, 1, iNewInstrument); + break; + case 14: // Top cymbal (operator 18 == channel 9 carrier) + this->writeInstrumentSettings(9-1, 0, 1, iNewInstrument); + break; + case 15: // Hi-hat (operator 14 == channel 8 modulator) + this->writeInstrumentSettings(8-1, 0, 0, iNewInstrument); + break; + default: + AdPlug_LogWrite("CMF: Invalid MIDI channel %d (not melodic and not percussive!)\n", iMIDIChannel + 1); + break; + } + this->chOPL[iOPLChannel].iMIDIPatch = iNewInstrument; + } else { + // Standard nine OPL channels + this->writeInstrumentSettings(iOPLChannel, 0, 0, iNewInstrument); + this->writeInstrumentSettings(iOPLChannel, 1, 1, iNewInstrument); + this->chOPL[iOPLChannel].iMIDIPatch = iNewInstrument; + } + return; +} + +void CcmfPlayer::MIDIcontroller(uint8_t iChannel, uint8_t iController, uint8_t iValue) +{ + switch (iController) { + case 0x63: + // Custom extension to allow CMF files to switch the AM+VIB depth on and + // off (officially both are on, and there's no way to switch them off.) + // Controller values: + // 0 == AM+VIB off + // 1 == VIB on + // 2 == AM on + // 3 == AM+VIB on + if (iValue) { + this->writeOPL(BASE_RHYTHM, (this->iCurrentRegs[BASE_RHYTHM] & ~0xC0) | (iValue << 6)); // switch AM+VIB extension on + } else { + this->writeOPL(BASE_RHYTHM, this->iCurrentRegs[BASE_RHYTHM] & ~0xC0); // switch AM+VIB extension off + } + AdPlug_LogWrite("CMF: AM+VIB depth change - AM %s, VIB %s\n", + (this->iCurrentRegs[BASE_RHYTHM] & 0x80) ? "on" : "off", + (this->iCurrentRegs[BASE_RHYTHM] & 0x40) ? "on" : "off"); + break; + case 0x66: + AdPlug_LogWrite("CMF: Song set marker to 0x%02X\n", iValue); + break; + case 0x67: + this->bPercussive = (iValue != 0); + if (this->bPercussive) { + this->writeOPL(BASE_RHYTHM, this->iCurrentRegs[BASE_RHYTHM] | 0x20); // switch rhythm-mode on + } else { + this->writeOPL(BASE_RHYTHM, this->iCurrentRegs[BASE_RHYTHM] & ~0x20); // switch rhythm-mode off + } + AdPlug_LogWrite("CMF: Percussive/rhythm mode %s\n", this->bPercussive ? "enabled" : "disabled"); + break; + case 0x68: + // TODO: Shouldn't this just affect the one channel, not the whole song? -- have pitchbends for that + this->iTranspose = iValue; + AdPlug_LogWrite("CMF: Transposing all notes up by %d * 1/128ths of a semitone.\n", iValue); + break; + case 0x69: + this->iTranspose = -iValue; + AdPlug_LogWrite("CMF: Transposing all notes down by %d * 1/128ths of a semitone.\n", iValue); + break; + default: + AdPlug_LogWrite("CMF: Unsupported MIDI controller 0x%02X, ignoring.\n", iController); + break; + } + return; +} diff --git a/plugins/adplug/adplug/cmf.h b/plugins/adplug/adplug/cmf.h new file mode 100644 index 00000000..e4347426 --- /dev/null +++ b/plugins/adplug/adplug/cmf.h @@ -0,0 +1,112 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2009 Simon Peter, <dn.tlp@gmx.net>, et al. + * + * 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 + * + * cmf.h - CMF player by Adam Nielsen <malvineous@shikadi.net> + */ + +#include <stdint.h> // for uintxx_t +#include "player.h" + +typedef struct { + uint16_t iInstrumentBlockOffset; + uint16_t iMusicOffset; + uint16_t iTicksPerQuarterNote; + uint16_t iTicksPerSecond; + uint16_t iTagOffsetTitle; + uint16_t iTagOffsetComposer; + uint16_t iTagOffsetRemarks; + uint8_t iChannelsInUse[16]; + uint16_t iNumInstruments; + uint16_t iTempo; +} CMFHEADER; + +typedef struct { + uint8_t iCharMult; + uint8_t iScalingOutput; + uint8_t iAttackDecay; + uint8_t iSustainRelease; + uint8_t iWaveSel; +} OPERATOR; + +typedef struct { + OPERATOR op[2]; // 0 == modulator, 1 == carrier + uint8_t iConnection; +} SBI; + +typedef struct { + int iPatch; // MIDI patch for this channel + int iPitchbend; // Current pitchbend amount for this channel +} MIDICHANNEL; + +typedef struct { + int iNoteStart; // When the note started playing (longest notes get cut first, 0 == channel free) + int iMIDINote; // MIDI note number currently being played on this OPL channel + int iMIDIChannel; // Source MIDI channel where this note came from + int iMIDIPatch; // Current MIDI patch set on this OPL channel +} OPLCHANNEL; + +class CcmfPlayer: public CPlayer +{ + private: + uint8_t *data; // song data (CMF music block) + int iPlayPointer; // Current location of playback pointer + int iSongLen; // Max value for iPlayPointer + CMFHEADER cmfHeader; + SBI *pInstruments; + bool bPercussive; // are rhythm-mode instruments enabled? + uint8_t iCurrentRegs[256]; // Current values in the OPL chip + int iTranspose; // Transpose amount for entire song (between -128 and +128) + uint8_t iPrevCommand; // Previous command (used for repeated MIDI commands, as the seek and playback code need to share this) + + int iNoteCount; // Used to count how long notes have been playing for + MIDICHANNEL chMIDI[16]; + OPLCHANNEL chOPL[9]; + + // Additions for AdPlug's design + int iDelayRemaining; + bool bSongEnd; + std::string strTitle, strComposer, strRemarks; + + public: + static CPlayer *factory(Copl *newopl); + + CcmfPlayer(Copl *newopl); + ~CcmfPlayer(); + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + float getrefresh(); + + std::string gettype() + { return std::string("Creative Music File (CMF)"); }; + std::string gettitle(); + std::string getauthor(); + std::string getdesc(); + + protected: + uint32_t readMIDINumber(); + void writeInstrumentSettings(uint8_t iChannel, uint8_t iOperatorSource, uint8_t iOperatorDest, uint8_t iInstrument); + void writeOPL(uint8_t iRegister, uint8_t iValue); + void cmfNoteOn(uint8_t iChannel, uint8_t iNote, uint8_t iVelocity); + void cmfNoteOff(uint8_t iChannel, uint8_t iNote, uint8_t iVelocity); + uint8_t getPercChannel(uint8_t iChannel); + void MIDIchangeInstrument(uint8_t iOPLChannel, uint8_t iMIDIChannel, uint8_t iNewInstrument); + void MIDIcontroller(uint8_t iChannel, uint8_t iController, uint8_t iValue); + +}; diff --git a/plugins/adplug/adplug/d00.cpp b/plugins/adplug/adplug/d00.cpp index 7aa042d1..0644b84b 100644 --- a/plugins/adplug/adplug/d00.cpp +++ b/plugins/adplug/adplug/d00.cpp @@ -1,6 +1,6 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2007 Simon Peter, <dn.tlp@gmx.net>, et al. + * Copyright (C) 1999 - 2008 Simon Peter, <dn.tlp@gmx.net>, et al. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -177,7 +177,7 @@ bool Cd00Player::update() setvolume(c); } - if(channel[c].levpuls != 0xff) // Levelpuls + if(channel[c].levpuls != 0xff) { // Levelpuls if(channel[c].frameskip) channel[c].frameskip--; else { @@ -193,6 +193,7 @@ bool Cd00Player::update() channel[c].modvol += levpuls[channel[c].levpuls].voladd; channel[c].modvol &= 63; setvolume(c); } + } } // song handling @@ -413,6 +414,8 @@ void Cd00Player::rewind(int subsong) } *tpoin; int i; + if(subsong == -1) subsong = cursubsong; + if(version > 1) { // do nothing if subsong > number of subsongs if(subsong >= header->subsongs) return; @@ -442,6 +445,7 @@ void Cd00Player::rewind(int subsong) } songend = 0; opl->init(); opl->write(1,32); // reset OPL chip + cursubsong = subsong; } std::string Cd00Player::gettype() diff --git a/plugins/adplug/adplug/d00.h b/plugins/adplug/adplug/d00.h index 50b0de3c..d0bf4b24 100644 --- a/plugins/adplug/adplug/d00.h +++ b/plugins/adplug/adplug/d00.h @@ -91,7 +91,7 @@ class Cd00Player: public CPlayer unsigned char duration,ptr; } *levpuls; - unsigned char songend,version; + unsigned char songend,version,cursubsong; char *datainfo; unsigned short *seqptr; d00header *header; diff --git a/plugins/adplug/adplug/dro.cpp b/plugins/adplug/adplug/dro.cpp index eb97c0f8..8342fe89 100644 --- a/plugins/adplug/adplug/dro.cpp +++ b/plugins/adplug/adplug/dro.cpp @@ -1,6 +1,6 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2005 Simon Peter, <dn.tlp@gmx.net>, et al. + * Copyright (C) 1999 - 2007 Simon Peter, <dn.tlp@gmx.net>, et al. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,8 +23,8 @@ * NOTES: 3-oct-04: the DRO format is not yet finalized. beware. */ +#include <cstring> #include <stdio.h> -#include <string.h> #include "dro.h" @@ -59,9 +59,9 @@ bool CdroPlayer::load(const std::string &filename, const CFileProvider &fp) // load section mstotal = f->readInt(4); // Total milliseconds in file length = f->readInt(4); // Total data bytes in file - f->ignore(1); // Type of opl data this can contain - ignored + f->ignore(4); // Type of opl data this can contain - ignored data = new unsigned char [length]; - for (i=0;i<length;i++) + for (i=0;i<length;i++) data[i]=f->readInt(1); fp.close(f); rewind(0); diff --git a/plugins/adplug/adplug/dro.h b/plugins/adplug/adplug/dro.h index 0f59e7b1..995da6cc 100644 --- a/plugins/adplug/adplug/dro.h +++ b/plugins/adplug/adplug/dro.h @@ -40,7 +40,7 @@ class CdroPlayer: public CPlayer std::string gettype() { - return std::string("DOSBox Raw OPL"); + return std::string("DOSBox Raw OPL v0.1"); } protected: diff --git a/plugins/adplug/adplug/dro2.cpp b/plugins/adplug/adplug/dro2.cpp new file mode 100644 index 00000000..e11196e7 --- /dev/null +++ b/plugins/adplug/adplug/dro2.cpp @@ -0,0 +1,142 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2007 Simon Peter, <dn.tlp@gmx.net>, et al. + * + * 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 + * + * dro2.cpp - DOSBox Raw OPL v2.0 player by Adam Nielsen <malvineous@shikadi.net> + */ + +#include <cstring> +#include <stdio.h> + +#include "dro2.h" + +CPlayer *Cdro2Player::factory(Copl *newopl) +{ + return new Cdro2Player(newopl); +} + +Cdro2Player::Cdro2Player(Copl *newopl) : + CPlayer(newopl), + piConvTable(NULL), + data(0) +{ +} + +Cdro2Player::~Cdro2Player() +{ + if (this->data) delete[] this->data; + if (this->piConvTable) delete[] this->piConvTable; +} + +bool Cdro2Player::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); + if (!f) return false; + + char id[8]; + f->readString(id, 8); + if (strncmp(id, "DBRAWOPL", 8)) { + fp.close(f); + return false; + } + int version = f->readInt(4); + if (version != 0x2) { + fp.close(f); + return false; + } + + this->iLength = f->readInt(4) * 2; // stored in file as number of byte pairs + f->ignore(4); // Length in milliseconds + f->ignore(1); /// OPL type (0 == OPL2, 1 == Dual OPL2, 2 == OPL3) + int iFormat = f->readInt(1); + if (iFormat != 0) { + fp.close(f); + return false; + } + int iCompression = f->readInt(1); + if (iCompression != 0) { + fp.close(f); + return false; + } + this->iCmdDelayS = f->readInt(1); + this->iCmdDelayL = f->readInt(1); + this->iConvTableLen = f->readInt(1); + + this->piConvTable = new uint8_t[this->iConvTableLen]; + f->readString((char *)this->piConvTable, this->iConvTableLen); + + this->data = new uint8_t[this->iLength]; + f->readString((char *)this->data, this->iLength); + + fp.close(f); + rewind(0); + + return true; +} + +bool Cdro2Player::update() +{ + while (this->iPos < this->iLength) { + int iIndex = this->data[this->iPos++]; + int iValue = this->data[this->iPos++]; + + // Short delay + if (iIndex == this->iCmdDelayS) { + this->iDelay = iValue + 1; + return true; + + // Long delay + } else if (iIndex == this->iCmdDelayL) { + this->iDelay = (iValue + 1) << 8; + return true; + + // Normal write + } else { + if (iIndex & 0x80) { + // High bit means use second chip in dual-OPL2 config + this->opl->setchip(1); + iIndex &= 0x7F; + } else { + this->opl->setchip(0); + } + if (iIndex > this->iConvTableLen) { + printf("DRO2: Error - index beyond end of codemap table! Corrupted .dro?\n"); + return false; // EOF + } + int iReg = this->piConvTable[iIndex]; + this->opl->write(iReg, iValue); + } + + } + + // This won't result in endless-play using Adplay, but IMHO that code belongs + // in Adplay itself, not here. + return this->iPos < this->iLength; +} + +void Cdro2Player::rewind(int subsong) +{ + this->iDelay = 0; + this->iPos = 0; + opl->init(); +} + +float Cdro2Player::getrefresh() +{ + if (this->iDelay > 0) return 1000.0 / this->iDelay; + else return 1000.0; +} diff --git a/plugins/adplug/adplug/dro2.h b/plugins/adplug/adplug/dro2.h new file mode 100644 index 00000000..fdd2f06d --- /dev/null +++ b/plugins/adplug/adplug/dro2.h @@ -0,0 +1,60 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2005 Simon Peter, <dn.tlp@gmx.net>, et al. + * + * 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 + * + * dro2.h - DOSBox Raw OPL v2.0 player by Adam Nielsen <malvineous@shikadi.net> + */ + +#include <stdint.h> // for uintxx_t +#include "player.h" + +class Cdro2Player: public CPlayer +{ + protected: + uint8_t iCmdDelayS, iCmdDelayL; + int iConvTableLen; + uint8_t *piConvTable; + + uint8_t *data; + int iLength; + int iPos; + int iDelay; + + + public: + static CPlayer *factory(Copl *newopl); + + Cdro2Player(Copl *newopl); + ~Cdro2Player(); + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + float getrefresh(); + + std::string gettype() + { + return std::string("DOSBox Raw OPL v2.0"); + } + + protected: + //unsigned char *data; + //unsigned long pos,length; + //unsigned long msdone,mstotal; + //unsigned short delay; + //unsigned char index, opl3_mode; +}; diff --git a/plugins/adplug/adplug/dtm.cpp b/plugins/adplug/adplug/dtm.cpp index 3d022ae8..91ea837c 100644 --- a/plugins/adplug/adplug/dtm.cpp +++ b/plugins/adplug/adplug/dtm.cpp @@ -22,7 +22,7 @@ NOTE: Panning (Ex) effect is ignored. */ -#include <string.h> +#include <cstring> #include "dtm.h" /* -------- Public Methods -------------------------------- */ diff --git a/plugins/adplug/adplug/emuopl.cpp b/plugins/adplug/adplug/emuopl.cpp index 0f751e16..43754c61 100644 --- a/plugins/adplug/adplug/emuopl.cpp +++ b/plugins/adplug/adplug/emuopl.cpp @@ -21,11 +21,16 @@ #include "emuopl.h" +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) + CEmuopl::CEmuopl(int rate, bool bit16, bool usestereo) : use16bit(bit16), stereo(usestereo), mixbufSamples(0) { opl[0] = OPLCreate(OPL_TYPE_YM3812, 3579545, rate); opl[1] = OPLCreate(OPL_TYPE_YM3812, 3579545, rate); + mixbuf0 = 0; + mixbuf1 = 0; currType = TYPE_DUAL_OPL2; @@ -36,10 +41,8 @@ CEmuopl::~CEmuopl() { OPLDestroy(opl[0]); OPLDestroy(opl[1]); - if(mixbufSamples) { - delete [] mixbuf0; - delete [] mixbuf1; - } + delete [] mixbuf0; + delete [] mixbuf1; } void CEmuopl::update(short *buf, int samples) @@ -47,15 +50,22 @@ void CEmuopl::update(short *buf, int samples) int i; //ensure that our mix buffers are adequately sized - if(mixbufSamples < samples) { - if(mixbufSamples) { delete[] mixbuf0; delete[] mixbuf1; } - mixbufSamples = samples; + if(unlikely (mixbufSamples < samples)) { + if (mixbuf0) { + delete[] mixbuf0; + mixbuf0 = 0; + } + if (mixbuf1) { + delete[] mixbuf1; + mixbuf1 = 0; + } //*2 = make room for stereo, if we need it mixbuf0 = new short[samples*2]; mixbuf1 = new short[samples*2]; } + mixbufSamples = samples; //data should be rendered to outbuf //tempbuf should be used as a temporary buffer //if we are supposed to generate 16bit output, @@ -65,10 +75,12 @@ void CEmuopl::update(short *buf, int samples) //and so it must point to a mixbuf instead-- //it will be reduced to 8bit and put in "buf" later short *outbuf; - short *tempbuf=mixbuf0; - short *tempbuf2=mixbuf1; - if(use16bit) outbuf = buf; - else outbuf = mixbuf1; + if (likely (use16bit)) { + outbuf = buf; + } + else { + outbuf = mixbuf1; + } //...there is a potentially confusing situation where mixbuf1 can be aliased. //beware. it is a little loony. @@ -82,11 +94,12 @@ void CEmuopl::update(short *buf, int samples) //if we are supposed to output stereo, //then we need to dup the mono channel - if(stereo) - for(i=samples-1;i>=0;i--) { - outbuf[i*2] = outbuf[i]; - outbuf[i*2+1] = outbuf[i]; - } + if(unlikely (stereo)) { + for(i=samples-1;i>=0;i--) { + outbuf[i*2] = outbuf[i]; + outbuf[i*2+1] = outbuf[i]; + } + } break; case TYPE_OPL3: // unsupported @@ -95,40 +108,53 @@ void CEmuopl::update(short *buf, int samples) case TYPE_DUAL_OPL2: //for dual opl2 mode: //render each chip to a different tempbuffer - YM3812UpdateOne(opl[0],tempbuf2,samples); - YM3812UpdateOne(opl[1],tempbuf,samples); + YM3812UpdateOne(opl[0],mixbuf1,samples); + YM3812UpdateOne(opl[1],mixbuf0,samples); //output stereo: //then we need to interleave the two buffers - if(stereo){ - //first, spread tempbuf's samples across left channel - //left channel - for(i=0;i<samples;i++) - outbuf[i*2] = tempbuf2[i]; - //next, insert the samples from tempbuf2 into right channel - for(i=0;i<samples;i++) - outbuf[i*2+1] = tempbuf[i]; - } else - //output mono: - //then we need to mix the two buffers into buf - for(i=0;i<samples;i++) - outbuf[i] = (tempbuf[i]>>1) + (tempbuf2[i]>>1); + if(unlikely (stereo)){ + //first, spread tempbuf's samples across left channel + for(i=0;i<samples;i++) + outbuf[i*2] = mixbuf1[i]; + //next, insert the samples from tempbuf2 into right channel + for(i=0;i<samples;i++) + outbuf[i*2+1] = mixbuf0[i]; + } else { + //output mono: + //then we need to mix the two buffers into buf + for(i=0;i<samples;i++) { + int sample = (int)mixbuf0[i] + (int)mixbuf1[i]; + if (unlikely (sample > 32767)) { + sample = 32767; + } + else if (unlikely (sample < -32768)) { + sample = -32768; + } + outbuf[i] = (short)sample; + } + } break; } //now reduce to 8bit if we need to - if(!use16bit) - for(i=0;i<(stereo ? samples*2 : samples);i++) - ((char *)buf)[i] = (outbuf[i] >> 8) ^ 0x80; + if(unlikely (!use16bit)) { + int smp = stereo ? samples*2 : samples; + for(i=0;i<smp;i++) { + ((char *)buf)[i] = (outbuf[i] >> 8) ^ 0x80; + } + } } void CEmuopl::write(int reg, int val) { switch(currType){ - case TYPE_OPL2: case TYPE_DUAL_OPL2: - OPLWrite(opl[currChip], 0, reg); - OPLWrite(opl[currChip], 1, val); + OPLWrite(opl[1], 0, reg); + OPLWrite(opl[1], 1, val); + case TYPE_OPL2: + OPLWrite(opl[0], 0, reg); + OPLWrite(opl[0], 1, val); break; case TYPE_OPL3: // unsupported break; diff --git a/plugins/adplug/adplug/fmc.cpp b/plugins/adplug/adplug/fmc.cpp index c6839a61..75cd99a7 100644 --- a/plugins/adplug/adplug/fmc.cpp +++ b/plugins/adplug/adplug/fmc.cpp @@ -19,7 +19,7 @@ fmc.cpp - FMC Loader by Riven the Mage <riven@ok.ru> */ -#include <string.h> +#include <cstring> #include "fmc.h" /* -------- Public Methods -------------------------------- */ @@ -115,9 +115,9 @@ bool CfmcLoader::load(const std::string &filename, const CFileProvider &fp) tracks[t][k].param2 = event.byte2 & 0x0F; // fix effects - if (tracks[t][k].command == 0x0E) // 0x0E (14): Retrig + if (tracks[t][k].command == 0x0E) // 0x0E (14): Retrig tracks[t][k].param1 = 3; - if (tracks[t][k].command == 0x1A) // 0x1A (26): Volume Slide + if (tracks[t][k].command == 0x1A) { // 0x1A (26): Volume Slide if (tracks[t][k].param1 > tracks[t][k].param2) { tracks[t][k].param1 -= tracks[t][k].param2; @@ -128,6 +128,7 @@ bool CfmcLoader::load(const std::string &filename, const CFileProvider &fp) tracks[t][k].param2 -= tracks[t][k].param1; tracks[t][k].param1 = 0; } + } } t++; diff --git a/plugins/adplug/adplug/fmopl.c b/plugins/adplug/adplug/fmopl.c index 2b0e82b0..66fc471e 100644 --- a/plugins/adplug/adplug/fmopl.c +++ b/plugins/adplug/adplug/fmopl.c @@ -322,7 +322,7 @@ INLINE void OPL_KEYOFF(OPL_SLOT *SLOT) /* ---------- calcrate Envelope Generator & Phase Generator ---------- */ /* return : envelope output */ -INLINE UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT ) +static INLINE UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT ) { /* calcrate envelope generator */ if( (SLOT->evc+=SLOT->evs) >= SLOT->eve ) @@ -388,7 +388,7 @@ INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) } /* set multi,am,vib,EG-TYP,KSR,mul */ -INLINE void set_mul(FM_OPL *OPL,int slot,int v) +static INLINE void set_mul(FM_OPL *OPL,int slot,int v) { OPL_CH *CH = &OPL->P_CH[slot/2]; OPL_SLOT *SLOT = &CH->SLOT[slot&1]; @@ -418,7 +418,7 @@ INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v) } /* set attack rate & decay rate */ -INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) +static INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) { OPL_CH *CH = &OPL->P_CH[slot/2]; OPL_SLOT *SLOT = &CH->SLOT[slot&1]; @@ -435,7 +435,7 @@ INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) } /* set sustain level & release rate */ -INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v) +static INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v) { OPL_CH *CH = &OPL->P_CH[slot/2]; OPL_SLOT *SLOT = &CH->SLOT[slot&1]; @@ -452,7 +452,7 @@ INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v) /* operator output calcrator */ #define OP_OUT(slot,env,con) slot->wavetable[((slot->Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env] /* ---------- calcrate one of channel ---------- */ -INLINE void OPL_CALC_CH( OPL_CH *CH ) +static INLINE void OPL_CALC_CH( OPL_CH *CH ) { UINT32 env_out; OPL_SLOT *SLOT; @@ -497,7 +497,7 @@ INLINE void OPL_CALC_CH( OPL_CH *CH ) /* ---------- calcrate rythm block ---------- */ #define WHITE_NOISE_db 6.0 -INLINE void OPL_CALC_RH( OPL_CH *CH ) +static INLINE void OPL_CALC_RH( OPL_CH *CH ) { UINT32 env_tam,env_sd,env_top,env_hh; int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP); diff --git a/plugins/adplug/adplug/fprovide.h b/plugins/adplug/adplug/fprovide.h index 2f1a0b62..572f28ac 100644 --- a/plugins/adplug/adplug/fprovide.h +++ b/plugins/adplug/adplug/fprovide.h @@ -32,7 +32,7 @@ public: { } - virtual binistream *open(std::string filename) const = 0; + virtual binistream *open(std::string) const = 0; virtual void close(binistream *) const = 0; static bool extension(const std::string &filename, diff --git a/plugins/adplug/adplug/hsc.h b/plugins/adplug/adplug/hsc.h index d09b8906..4a9e2d27 100644 --- a/plugins/adplug/adplug/hsc.h +++ b/plugins/adplug/adplug/hsc.h @@ -1,6 +1,6 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2002 Simon Peter, <dn.tlp@gmx.net>, et al. + * Copyright (C) 1999 - 2007 Simon Peter, <dn.tlp@gmx.net>, et al. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -31,7 +31,7 @@ class ChscPlayer: public CPlayer ChscPlayer(Copl *newopl): CPlayer(newopl), mtkmode(0) {} - bool load(const std::string &fn, const CFileProvider &fp); + bool load(const std::string &filename, const CFileProvider &fp); bool update(); void rewind(int subsong); float getrefresh() { return 18.2f; }; // refresh rate is fixed at 18.2Hz @@ -48,16 +48,16 @@ class ChscPlayer: public CPlayer protected: struct hscnote { unsigned char note, effect; - }; // note type in HSC pattern + }; // note type in HSC pattern struct hscchan { unsigned char inst; // current instrument signed char slide; // used for manual slide-effects unsigned short freq; // actual replaying frequency - }; // HSC channel data + }; // HSC channel data - hscchan channel[9]; // player channel-info - unsigned char instr[128][12]; // instrument data + hscchan channel[9]; // player channel-info + unsigned char instr[128][12]; // instrument data unsigned char song[0x80]; // song-arrangement (MPU-401 Trakker enhanced) hscnote patterns[50][64*9]; // pattern data unsigned char pattpos,songpos, // various bytes & flags diff --git a/plugins/adplug/adplug/imf.cpp b/plugins/adplug/adplug/imf.cpp index 37af7aca..c525ac8b 100644 --- a/plugins/adplug/adplug/imf.cpp +++ b/plugins/adplug/adplug/imf.cpp @@ -1,6 +1,6 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2006 Simon Peter <dn.tlp@gmx.net>, et al. + * Copyright (C) 1999 - 2008 Simon Peter <dn.tlp@gmx.net>, et al. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -105,7 +105,7 @@ bool CimfPlayer::load(const std::string &filename, const CFileProvider &fp) } // read footer, if any - if(fsize && (fsize < flsize - 2 - mfsize)) + if(fsize && (fsize < flsize - 2 - mfsize)) { if(f->readInt(1) == 0x1a) { // Adam Nielsen's footer format track_name = f->readString(); @@ -119,6 +119,7 @@ bool CimfPlayer::load(const std::string &filename, const CFileProvider &fp) f->readString(footer, footerlen); footer[footerlen] = '\0'; // Make ASCIIZ string } + } rate = getrate(filename, fp, f); fp.close(f); diff --git a/plugins/adplug/adplug/jbm.cpp b/plugins/adplug/adplug/jbm.cpp new file mode 100644 index 00000000..0990001b --- /dev/null +++ b/plugins/adplug/adplug/jbm.cpp @@ -0,0 +1,293 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2007 Simon Peter, <dn.tlp@gmx.net>, et al. + * + * 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 + * + * Johannes Bjerregaard's JBM Adlib Music Format player for AdPlug + * Written by Dennis Lindroos <lindroos@nls.fi>, February-March 2007 + * - Designed and coded from scratch (only frequency-table taken from MUSIC.BIN) + * - The percussion mode is buggy (?) but i'm not good enough to find them + * and honestly i think the melodic-mode tunes are much better ;) + * + * This version doesn't use the binstr.h functions (coded with custom func.) + * This is my first attempt on writing a musicplayer for AdPlug, and i'm not + * coding C++ very often.. + * + * Released under the terms of the GNU General Public License. + */ + +#include "jbm.h" + +static const unsigned short notetable[96] = { + 0x0158, 0x016d, 0x0183, 0x019a, 0x01b2, 0x01cc, 0x01e7, 0x0204, + 0x0223, 0x0244, 0x0266, 0x028b, 0x0558, 0x056d, 0x0583, 0x059a, + 0x05b2, 0x05cc, 0x05e7, 0x0604, 0x0623, 0x0644, 0x0666, 0x068b, + 0x0958, 0x096d, 0x0983, 0x099a, 0x09b2, 0x09cc, 0x09e7, 0x0a04, + 0x0a23, 0x0a44, 0x0a66, 0x0a8b, 0x0d58, 0x0d6d, 0x0d83, 0x0d9a, + 0x0db2, 0x0dcc, 0x0de7, 0x0e04, 0x0e23, 0x0e44, 0x0e66, 0x0e8b, + 0x1158, 0x116d, 0x1183, 0x119a, 0x11b2, 0x11cc, 0x11e7, 0x1204, + 0x1223, 0x1244, 0x1266, 0x128b, 0x1558, 0x156d, 0x1583, 0x159a, + 0x15b2, 0x15cc, 0x15e7, 0x1604, 0x1623, 0x1644, 0x1666, 0x168b, + 0x1958, 0x196d, 0x1983, 0x199a, 0x19b2, 0x19cc, 0x19e7, 0x1a04, + 0x1a23, 0x1a44, 0x1a66, 0x1a8b, 0x1d58, 0x1d6d, 0x1d83, 0x1d9a, + 0x1db2, 0x1dcc, 0x1de7, 0x1e04, 0x1e23, 0x1e44, 0x1e66, 0x1e8b +}; + +static const unsigned char percmx_tab[4] = { 0x14, 0x12, 0x15, 0x11 }; +static const unsigned char perchn_tab[5] = { 6, 7, 8, 8, 7 }; +static unsigned char percmaskoff[5] = { 0xef, 0xf7, 0xfb, 0xfd, 0xfe }; +static unsigned char percmaskon[5] = { 0x10, 0x08, 0x04, 0x02, 0x01 }; + +static inline unsigned short GET_WORD(unsigned char *b, int x) +{ + return ((unsigned short)(b[x+1] << 8) | b[x]); +} + +/*** public methods *************************************/ + +CPlayer *CjbmPlayer::factory(Copl *newopl) +{ + return new CjbmPlayer(newopl); +} + +bool CjbmPlayer::load(const std::string &filename, const CFileProvider &fp) +{ + binistream *f = fp.open(filename); if(!f) return false; + int filelen = fp.filesize(f); + int i; + + if (!filelen || !fp.extension(filename, ".jbm")) goto loaderr; + + // Allocate memory buffer m[] and read entire file into it + + m = new unsigned char[filelen]; + if (f->readString((char *)m, filelen) != filelen) goto loaderr; + + fp.close(f); + + // The known .jbm files always seem to start with the number 0x0002 + + if (GET_WORD(m, 0) != 0x0002) + return false; + + // Song tempo + + i = GET_WORD(m, 2); + timer = 1193810.0 / (i ? i : 0xffff); + + seqtable = GET_WORD(m, 4); + instable = GET_WORD(m, 6); + + // The flags word has atleast 1 bit, the Adlib's rhythm mode, but + // currently we don't support that :( + + flags = GET_WORD(m, 8); + + // Instrument datas are directly addressed with m[] + + inscount = (filelen - instable) >> 4; + + // Voice' and sequence pointers + + seqcount = 0xffff; + for (i = 0; i < 11; i++) { + voice[i].trkpos = voice[i].trkstart = GET_WORD(m, 10 + (i<<1)); + if (voice[i].trkpos && voice[i].trkpos < seqcount) + seqcount = voice[i].trkpos; + } + seqcount = (seqcount - seqtable) >> 1; + sequences = new unsigned short[seqcount]; + for (i = 0; i < seqcount; i++) + sequences[i] = GET_WORD(m, seqtable + (i<<1)); + + rewind(0); + return true; + loaderr: + fp.close(f); + return false; +} + +bool CjbmPlayer::update() +{ + short c, spos, frq; + + for (c = 0; c < 11; c++) { + if (!voice[c].trkpos) // Unused channel + continue; + + if (--voice[c].delay) + continue; + + // Turn current note/percussion off + + if (voice[c].note&0x7f) + opl_noteonoff(c, &voice[c], 0); + + // Process events until we have a note + + spos = voice[c].seqpos; + while(!voice[c].delay) { + switch(m[spos]) { + case 0xFD: // Set Instrument + voice[c].instr = m[spos+1]; + set_opl_instrument(c, &voice[c]); + spos+=2; + break; + case 0xFF: // End of Sequence + voice[c].seqno = m[++voice[c].trkpos]; + if (voice[c].seqno == 0xff) { + voice[c].trkpos = voice[c].trkstart; + voice[c].seqno = m[voice[c].trkpos]; + //voicemask &= 0x7ff-(1<<c); + voicemask &= ~(1<<c); + } + spos = voice[c].seqpos = sequences[voice[c].seqno]; + break; + default: // Note Event + if ((m[spos] & 127) > 95) + return 0; + + voice[c].note = m[spos]; + voice[c].vol = m[spos+1]; + voice[c].delay = + (m[spos+2] + (m[spos+3]<<8)) + 1; + + frq = notetable[voice[c].note&127]; + voice[c].frq[0] = (unsigned char)frq; + voice[c].frq[1] = frq >> 8; + spos+=4; + } + } + voice[c].seqpos = spos; + + // Write new volume to the carrier operator, or percussion + + if (flags&1 && c > 6) + opl->write(0x40 + percmx_tab[c-7], voice[c].vol ^ 0x3f); + else + opl->write(0x43 + op_table[c], voice[c].vol ^ 0x3f); + + // Write new frequencies and Gate bit + + opl_noteonoff(c, &voice[c], !(voice[c].note & 0x80)); + } + return (voicemask); +} + +void CjbmPlayer::rewind(int subsong) +{ + int c; + + voicemask = 0; + + for (c = 0; c < 11; c++) { + voice[c].trkpos = voice[c].trkstart; + + if (!voice[c].trkpos) continue; + + voicemask |= (1<<c); + + voice[c].seqno = m[voice[c].trkpos]; + voice[c].seqpos = sequences[voice[c].seqno]; + + voice[c].note = 0; + voice[c].delay = 1; + } + + opl->init(); + opl->write(0x01, 32); + + // Set rhythm mode if flags bit #0 is set + // AM and Vibrato are full depths (taken from DosBox RAW output) + bdreg = 0xC0 | (flags&1)<<5; + + opl->write(0xbd, bdreg); + +#if 0 + if (flags&1) { + voice[7].frq[0] = 0x58; voice[7].frq[1] = 0x09; // XXX + voice[8].frq[0] = 0x04; voice[8].frq[1] = 0x0a; // XXX + opl_noteonoff(7, &voice[7], 0); + opl_noteonoff(8, &voice[8], 0); + } +#endif + + return; +} + +/*** private methods ************************************/ + +void CjbmPlayer::opl_noteonoff(int channel, JBMVoice *v, bool state) +{ + if (flags&1 && channel > 5) { + // Percussion + opl->write(0xa0 + perchn_tab[channel-6], voice[channel].frq[0]); + opl->write(0xb0 + perchn_tab[channel-6], voice[channel].frq[1]); + opl->write(0xbd, + state ? bdreg | percmaskon[channel-6] : + bdreg & percmaskoff[channel-6]); + } else { + // Melodic mode or Rhythm mode melodic channels + opl->write(0xa0 + channel, voice[channel].frq[0]); + opl->write(0xb0 + channel, + state ? voice[channel].frq[1] | 0x20 : + voice[channel].frq[1] & 0x1f); + } + return; +} + + +void CjbmPlayer::set_opl_instrument(int channel, JBMVoice *v) +{ + short i = instable + (v->instr << 4); + + // Sanity check on instr number - or we'll be reading outside m[] ! + + if (v->instr >= inscount) + return; + + // For rhythm mode, multiplexed drums. I don't care about waveforms! + if ((flags&1) & (channel > 6)) { + opl->write(0x20 + percmx_tab[channel-7], m[i+0]); + opl->write(0x40 + percmx_tab[channel-7], m[i+1] ^ 0x3f); + opl->write(0x60 + percmx_tab[channel-7], m[i+2]); + opl->write(0x80 + percmx_tab[channel-7], m[i+3]); + + opl->write(0xc0 + perchn_tab[channel-6], m[i+8]&15); + return; + } + + // AM/VIB/EG/KSR/FRQMUL, KSL/OUTPUT, ADSR for 1st operator + opl->write(0x20 + op_table[channel], m[i+0]); + opl->write(0x40 + op_table[channel], m[i+1] ^ 0x3f); + opl->write(0x60 + op_table[channel], m[i+2]); + opl->write(0x80 + op_table[channel], m[i+3]); + + // AM/VIB/EG/KSR/FRQMUL, KSL/OUTPUT, ADSR for 2nd operator + opl->write(0x23 + op_table[channel], m[i+4]); + opl->write(0x43 + op_table[channel], m[i+5] ^ 0x3f); + opl->write(0x63 + op_table[channel], m[i+6]); + opl->write(0x83 + op_table[channel], m[i+7]); + + // WAVEFORM for operators + opl->write(0xe0 + op_table[channel], (m[i+8]>>4)&3); + opl->write(0xe3 + op_table[channel], (m[i+8]>>6)&3); + + // FEEDBACK/FM mode + opl->write(0xc0 + channel, m[i+8]&15); + + return; +} diff --git a/plugins/adplug/adplug/jbm.h b/plugins/adplug/adplug/jbm.h new file mode 100644 index 00000000..3f95b03f --- /dev/null +++ b/plugins/adplug/adplug/jbm.h @@ -0,0 +1,80 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2007 Simon Peter <dn.tlp@gmx.net>, et al. + * + * 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 + * + * jbm.h - JBM Player by Dennis Lindroos <lindroos@nls.fi> + */ + +#ifndef H_ADPLUG_JBMPLAYER +#define H_ADPLUG_JBMPLAYER + +#include "player.h" + +class CjbmPlayer: public CPlayer +{ + public: + static CPlayer *factory(Copl *newopl); + + CjbmPlayer(Copl *newopl) : CPlayer(newopl), m(0) + { } + ~CjbmPlayer() + { if(m != NULL) delete [] m; } + + bool load(const std::string &filename, const CFileProvider &fp); + bool update(); + void rewind(int subsong); + + float getrefresh() + { return timer; } + + std::string gettype() + { + return std::string(flags&1 ? "JBM Adlib Music [rhythm mode]" : + "JBM Adlib Music"); + } + std::string getauthor() + { return std::string("Johannes Bjerregaard"); } + + protected: + + unsigned char *m; + float timer; + unsigned short flags, voicemask; + unsigned short seqtable, seqcount; + unsigned short instable, inscount; + unsigned short *sequences; + unsigned char bdreg; + + typedef struct { + unsigned short trkpos, trkstart, seqpos; + unsigned char seqno, note; + short vol; + short delay; + short instr; + unsigned char frq[2]; + unsigned char ivol, dummy; + } JBMVoice; + + JBMVoice voice[11]; + + private: + //void calc_opl_frequency(JBMVoice *); + void set_opl_instrument(int, JBMVoice *); + void opl_noteonoff(int, JBMVoice *, bool); +}; + +#endif diff --git a/plugins/adplug/adplug/lds.h b/plugins/adplug/adplug/lds.h index ec61ad29..95f59606 100644 --- a/plugins/adplug/adplug/lds.h +++ b/plugins/adplug/adplug/lds.h @@ -29,7 +29,7 @@ class CldsPlayer: public CPlayer CldsPlayer(Copl *newopl); virtual ~CldsPlayer(); - bool load(const std::string &fn, const CFileProvider &fp); + bool load(const std::string &filename, const CFileProvider &fp); virtual bool update(); virtual void rewind(int subsong = -1); float getrefresh() { return 70.0f; } diff --git a/plugins/adplug/adplug/mad.cpp b/plugins/adplug/adplug/mad.cpp index d5a60c43..b8cb527d 100644 --- a/plugins/adplug/adplug/mad.cpp +++ b/plugins/adplug/adplug/mad.cpp @@ -19,7 +19,7 @@ mad.cpp - MAD loader by Riven the Mage <riven@ok.ru> */ -#include <string.h> +#include <cstring> #include "mad.h" /* -------- Public Methods -------------------------------- */ diff --git a/plugins/adplug/adplug/mid.cpp b/plugins/adplug/adplug/mid.cpp index e3dd88c5..03a2d84a 100644 --- a/plugins/adplug/adplug/mid.cpp +++ b/plugins/adplug/adplug/mid.cpp @@ -1,6 +1,6 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al. + * Copyright (C) 1999 - 2008 Simon Peter, <dn.tlp@gmx.net>, et al. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -62,6 +62,11 @@ * 10/15/2005: Changes by Simon Peter * Added rhythm mode support for CMF format. * + * 09/13/2008: Changes by Adam Nielsen (malvineous@shikadi.net) + * Fixed a couple of CMF rhythm mode bugs + * Disabled note velocity for CMF files + * Added support for nonstandard CMF AM+VIB controller (for VGFM CMFs) + * * Other acknowledgements: * Allegro - for the midi instruments and the midi volume table * SCUMM Revisited - for getting the .LAA / .MIDs out of those @@ -106,9 +111,6 @@ void CmidPlayer::midiprintf(const char *format, ...) // AdLib standard operator table const unsigned char CmidPlayer::adlib_opadd[] = {0x00 ,0x01 ,0x02 ,0x08 ,0x09 ,0x0A ,0x10 ,0x11 ,0x12}; -// dunno -const int CmidPlayer::ops[] = {0x20,0x20,0x40,0x40,0x60,0x60,0x80,0x80,0xe0,0xe0,0xc0}; - // map CMF drum channels 12 - 15 to corresponding AdLib drum operators // bass drum (channel 11) not mapped, cause it's handled like a normal instrument const int CmidPlayer::map_chan[] = { 0x14, 0x12, 0x15, 0x11 }; @@ -300,12 +302,13 @@ bool CmidPlayer::load(const std::string &filename, const CFileProvider &fp) if (s[1]=='T' && s[2]=='M' && s[3]=='F') good=FILE_CMF; break; case 0x84: - if (s[1]==0x00 && load_sierra_ins(filename, fp)) - if (s[2]==0xf0) - good=FILE_ADVSIERRA; - else - good=FILE_SIERRA; - break; + if (s[1]==0x00 && load_sierra_ins(filename, fp)) { + if (s[2]==0xf0) + good=FILE_ADVSIERRA; + else + good=FILE_SIERRA; + } + break; default: if (s[4]=='A' && s[5]=='D') good=FILE_OLDLUCAS; break; @@ -346,30 +349,24 @@ void CmidPlayer::midi_fm_instrument(int voice, unsigned char *inst) midi_write_adlib(0x20+adlib_opadd[voice],inst[0]); midi_write_adlib(0x23+adlib_opadd[voice],inst[1]); - if ((adlib_style&LUCAS_STYLE)!=0) - { + if (adlib_style & LUCAS_STYLE) { midi_write_adlib(0x43+adlib_opadd[voice],0x3f); if ((inst[10] & 1)==0) midi_write_adlib(0x40+adlib_opadd[voice],inst[2]); - else - midi_write_adlib(0x40+adlib_opadd[voice],0x3f); - } else - { - if ((adlib_style&SIERRA_STYLE)!=0) - { - midi_write_adlib(0x40+adlib_opadd[voice],inst[2]); + midi_write_adlib(0x40+adlib_opadd[voice],0x3f); + + } else if ((adlib_style & SIERRA_STYLE) || (adlib_style & CMF_STYLE)) { + midi_write_adlib(0x40+adlib_opadd[voice],inst[2]); + midi_write_adlib(0x43+adlib_opadd[voice],inst[3]); + + } else { + midi_write_adlib(0x40+adlib_opadd[voice],inst[2]); + if ((inst[10] & 1)==0) midi_write_adlib(0x43+adlib_opadd[voice],inst[3]); - } - else - { - midi_write_adlib(0x40+adlib_opadd[voice],inst[2]); - if ((inst[10] & 1)==0) - midi_write_adlib(0x43+adlib_opadd[voice],inst[3]); - else - midi_write_adlib(0x43+adlib_opadd[voice],0); - } - } + else + midi_write_adlib(0x43+adlib_opadd[voice],0); + } midi_write_adlib(0x60+adlib_opadd[voice],inst[4]); midi_write_adlib(0x63+adlib_opadd[voice],inst[5]); @@ -390,7 +387,8 @@ void CmidPlayer::midi_fm_percussion(int ch, unsigned char *inst) midi_write_adlib(0x60 + opadd, inst[4]); midi_write_adlib(0x80 + opadd, inst[6]); midi_write_adlib(0xe0 + opadd, inst[8]); - midi_write_adlib(0xc0 + opadd, inst[10]); + if (opadd < 0x13) // only output this for the modulator, not the carrier, as it affects the entire channel + midi_write_adlib(0xc0 + percussion_map[ch - 11], inst[10]); } void CmidPlayer::midi_fm_volume(int voice, int volume) @@ -429,7 +427,7 @@ void CmidPlayer::midi_fm_playnote(int voice, int note, int volume) midi_fm_volume(voice,volume); midi_write_adlib(0xa0+voice,(unsigned char)(freq&0xff)); - c=((freq&0x300) >> 8)+(oct<<2) + (adlib_mode == ADLIB_MELODIC || voice < 6 ? (1<<5) : 0); + c=((freq&0x300) >> 8)+((oct&7)<<2) + (adlib_mode == ADLIB_MELODIC || voice < 6 ? (1<<5) : 0); midi_write_adlib(0xb0+voice,(unsigned char)c); } @@ -541,58 +539,62 @@ bool CmidPlayer::update() } else on = percussion_map[c - 11]; - if (vel!=0 && ch[c].inum>=0 && ch[c].inum<128) - { - if (adlib_mode == ADLIB_MELODIC || c < 12) + if (vel!=0 && ch[c].inum>=0 && ch[c].inum<128) { + if (adlib_mode == ADLIB_MELODIC || c < 12) // 11 == bass drum, handled like a normal instrument, on == channel 6 thanks to percussion_map[] above midi_fm_instrument(on,ch[c].ins); else midi_fm_percussion(c, ch[c].ins); - if ((adlib_style&MIDI_STYLE)!=0) - { + if (adlib_style & MIDI_STYLE) { nv=((ch[c].vol*vel)/128); - if ((adlib_style&LUCAS_STYLE)!=0) - nv*=2; + if ((adlib_style&LUCAS_STYLE)!=0) nv*=2; if (nv>127) nv=127; nv=my_midi_fm_vol_table[nv]; if ((adlib_style&LUCAS_STYLE)!=0) nv=(int)((float)sqrt((float)nv)*11); - } - else - { + } else if (adlib_style & CMF_STYLE) { + // CMF doesn't support note velocity (even though some files have them!) + nv = 127; + } else { nv=vel; - } + } - midi_fm_playnote(on,note+ch[c].nshift,nv*2); + midi_fm_playnote(on,note+ch[c].nshift,nv*2); // sets freq in rhythm mode chp[on][0]=c; chp[on][1]=note; chp[on][2]=0; if(adlib_mode == ADLIB_RYTHM && c >= 11) { + // Still need to turn off the perc instrument before playing it again, + // as not all songs send a noteoff. midi_write_adlib(0xbd, adlib_data[0xbd] & ~(0x10 >> (c - 11))); + // Play the perc instrument midi_write_adlib(0xbd, adlib_data[0xbd] | (0x10 >> (c - 11))); } - } - else - { - if (vel==0) //same code as end note - { - for (i=0; i<9; i++) - if (chp[i][0]==c && chp[i][1]==note) - { - // midi_fm_volume(i,0); // really end the note - midi_fm_endnote(i); - chp[i][0]=-1; + } else { + if (vel==0) { //same code as end note + if (adlib_mode == ADLIB_RYTHM && c >= 11) { + // Turn off the percussion instrument + midi_write_adlib(0xbd, adlib_data[0xbd] & ~(0x10 >> (c - 11))); + //midi_fm_endnote(percussion_map[c]); + chp[percussion_map[c - 11]][0]=-1; + } else { + for (i=0; i<9; i++) { + if (chp[i][0]==c && chp[i][1]==note) { + // midi_fm_volume(i,0); // really end the note + midi_fm_endnote(i); + chp[i][0]=-1; } + } } - else - { // i forget what this is for. + } else { + // i forget what this is for. chp[on][0]=-1; chp[on][2]=0; - } } - midiprintf(" [%d:%d:%d:%d]\n",c,ch[c].inum,note,vel); + } + midiprintf(" [%d:%d:%d:%d]\n",c,ch[c].inum,note,vel); } else midiprintf ("off"); @@ -616,8 +618,25 @@ midi_fm_playnote(i,note+cnote[c],my_midi_fm_vol_table[(cvols[c]*vel)/128]*2); ch[c].vol=vel; midiprintf("vol"); break; + case 0x63: + if (adlib_style & CMF_STYLE) { + // Custom extension to allow CMF files to switch the + // AM+VIB depth on and off (officially this is on, + // and there's no way to switch it off.) Controller + // values: + // 0 == AM+VIB off + // 1 == VIB on + // 2 == AM on + // 3 == AM+VIB on + midi_write_adlib(0xbd, (adlib_data[0xbd] & ~0xC0) | (vel << 6)); + midiprintf(" AM+VIB depth change - AM %s, VIB %s\n", + (adlib_data[0xbd] & 0x80) ? "on" : "off", + (adlib_data[0xbd] & 0x40) ? "on" : "off" + ); + } + break; case 0x67: - midiprintf ("\n\nhere:%d\n\n",vel); + midiprintf("Rhythm mode: %d\n", vel); if ((adlib_style&CMF_STYLE)!=0) { adlib_mode=vel; if(adlib_mode == ADLIB_RYTHM) @@ -811,11 +830,12 @@ fwait=1.0f/(((float)iwait/(float)deltas)*((float)msqtr/(float)1000000)); midiprintf ("\n"); for (i=0; i<16; i++) - if (track[i].on) - if (track[i].pos < track[i].tend) - midiprintf ("<%d>",track[i].iwait); - else - midiprintf("stop"); + if (track[i].on) { + if (track[i].pos < track[i].tend) + midiprintf ("<%d>",track[i].iwait); + else + midiprintf("stop"); + } /* if (ret==0 && type==FILE_ADVSIERRA) diff --git a/plugins/adplug/adplug/mid.h b/plugins/adplug/adplug/mid.h index d28f7252..5dfe9e76 100644 --- a/plugins/adplug/adplug/mid.h +++ b/plugins/adplug/adplug/mid.h @@ -1,6 +1,6 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2005 Simon Peter, <dn.tlp@gmx.net>, et al. + * Copyright (C) 1999 - 2008 Simon Peter, <dn.tlp@gmx.net>, et al. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/plugins/adplug/adplug/mkj.cpp b/plugins/adplug/adplug/mkj.cpp index 32d7e27c..38c1c082 100644 --- a/plugins/adplug/adplug/mkj.cpp +++ b/plugins/adplug/adplug/mkj.cpp @@ -19,8 +19,8 @@ * mkj.cpp - MKJamz Player, by Simon Peter <dn.tlp@gmx.net> */ +#include <cstring> #include <assert.h> -#include <string.h> #include "mkj.h" #include "debug.h" diff --git a/plugins/adplug/adplug/msc.cpp b/plugins/adplug/adplug/msc.cpp index 3702adcf..c9eade06 100644 --- a/plugins/adplug/adplug/msc.cpp +++ b/plugins/adplug/adplug/msc.cpp @@ -19,8 +19,8 @@ * msc.c - MSC Player by Lubomir Bulej (pallas@kadan.cz) */ +#include <cstring> #include <stdio.h> -#include <string.h> #include "msc.h" #include "debug.h" @@ -211,7 +211,7 @@ bool CmscPlayer::decode_octet(u8 * output) blk = msc_data [block_num]; while (1) { u8 octet; // decoded octet - u8 len_corr; // length correction + u8 len_corr = 0; // length correction // advance to next block if necessary if (block_pos >= blk.mb_length && dec_len == 0) { diff --git a/plugins/adplug/adplug/mtk.cpp b/plugins/adplug/adplug/mtk.cpp index 410e00e0..6bafc853 100644 --- a/plugins/adplug/adplug/mtk.cpp +++ b/plugins/adplug/adplug/mtk.cpp @@ -19,7 +19,7 @@ * mtk.cpp - MPU-401 Trakker Loader by Simon Peter (dn.tlp@gmx.net) */ -#include <string.h> +#include <cstring> #include "mtk.h" /*** public methods **************************************/ diff --git a/plugins/adplug/adplug/player.h b/plugins/adplug/adplug/player.h index 6b99c34b..8c474daa 100644 --- a/plugins/adplug/adplug/player.h +++ b/plugins/adplug/adplug/player.h @@ -37,7 +37,7 @@ public: /***** Operational methods *****/ void seek(unsigned long ms); - virtual bool load(const std::string &fn, // loads file + virtual bool load(const std::string &filename, // loads file const CFileProvider &fp = CProvider_Filesystem()) = 0; virtual bool update() = 0; // executes replay code for 1 tick virtual void rewind(int subsong = -1) = 0; // rewinds to specified subsong @@ -48,29 +48,31 @@ public: virtual std::string gettype() = 0; // returns file type virtual std::string gettitle() // returns song title - { return std::string(); } + { return std::string(); } virtual std::string getauthor() // returns song author name - { return std::string(); } + { return std::string(); } virtual std::string getdesc() // returns song description - { return std::string(); } + { return std::string(); } virtual unsigned int getpatterns() // returns number of patterns - { return 0; } + { return 0; } virtual unsigned int getpattern() // returns currently playing pattern - { return 0; } + { return 0; } virtual unsigned int getorders() // returns size of orderlist - { return 0; } + { return 0; } virtual unsigned int getorder() // returns currently playing song position - { return 0; } + { return 0; } virtual unsigned int getrow() // returns currently playing row - { return 0; } + { return 0; } virtual unsigned int getspeed() // returns current song speed - { return 0; } + { return 0; } virtual unsigned int getsubsongs() // returns number of subsongs - { return 1; } + { return 1; } + virtual unsigned int getsubsong() // returns current subsong + { return 0; } virtual unsigned int getinstruments() // returns number of instruments - { return 0; } + { return 0; } virtual std::string getinstrument(unsigned int n) // returns n-th instrument name - { return std::string(); } + { return std::string(); } protected: Copl *opl; // our OPL chip diff --git a/plugins/adplug/adplug/protrack.cpp b/plugins/adplug/adplug/protrack.cpp index 86716ef8..ebb1570b 100644 --- a/plugins/adplug/adplug/protrack.cpp +++ b/plugins/adplug/adplug/protrack.cpp @@ -25,7 +25,7 @@ * Protracker-like format, this is most certainly the player you want to use. */ -#include <string.h> +#include <cstring> #include "protrack.h" #include "debug.h" @@ -72,7 +72,7 @@ bool CmodPlayer::update() for(chan = 0; chan < nchans; chan++) { oplchan = set_opl_chip(chan); - if(arplist && arpcmd && inst[channel[chan].inst].arpstart) // special arpeggio + if(arplist && arpcmd && inst[channel[chan].inst].arpstart) { // special arpeggio if(channel[chan].arpspdcnt) channel[chan].arpspdcnt--; else @@ -107,6 +107,7 @@ bool CmodPlayer::update() channel[chan].arppos++; channel[chan].arpspdcnt = inst[channel[chan].inst].arpspeed - 1; } + } info1 = channel[chan].info1; info2 = channel[chan].info2; @@ -631,8 +632,8 @@ void CmodPlayer::setvolume_alt(unsigned char chan) unsigned char ivol2 = inst[channel[chan].inst].data[9] & 63; unsigned char ivol1 = inst[channel[chan].inst].data[10] & 63; - opl->write(0x40 + op_table[oplchan], (((63 - channel[chan].vol2 & 63) + ivol2) >> 1) + (inst[channel[chan].inst].data[9] & 192)); - opl->write(0x43 + op_table[oplchan], (((63 - channel[chan].vol1 & 63) + ivol1) >> 1) + (inst[channel[chan].inst].data[10] & 192)); + opl->write(0x40 + op_table[oplchan], (((63 - (channel[chan].vol2 & 63)) + ivol2) >> 1) + (inst[channel[chan].inst].data[9] & 192)); + opl->write(0x43 + op_table[oplchan], (((63 - (channel[chan].vol1 & 63)) + ivol1) >> 1) + (inst[channel[chan].inst].data[10] & 192)); } void CmodPlayer::setfreq(unsigned char chan) @@ -679,13 +680,14 @@ void CmodPlayer::playnote(unsigned char chan) void CmodPlayer::setnote(unsigned char chan, int note) { - if(note > 96) + if(note > 96) { if(note == 127) { // key off channel[chan].key = 0; setfreq(chan); return; } else note = 96; + } if(note < 13) channel[chan].freq = notetable[note - 1]; @@ -701,23 +703,25 @@ void CmodPlayer::setnote(unsigned char chan, int note) void CmodPlayer::slide_down(unsigned char chan, int amount) { channel[chan].freq -= amount; - if(channel[chan].freq <= 342) + if(channel[chan].freq <= 342) { if(channel[chan].oct) { channel[chan].oct--; channel[chan].freq <<= 1; } else channel[chan].freq = 342; + } } void CmodPlayer::slide_up(unsigned char chan, int amount) { channel[chan].freq += amount; - if(channel[chan].freq >= 686) + if(channel[chan].freq >= 686) { if(channel[chan].oct < 7) { channel[chan].oct++; channel[chan].freq >>= 1; } else channel[chan].freq = 686; + } } void CmodPlayer::tone_portamento(unsigned char chan, unsigned char info) @@ -799,11 +803,12 @@ void CmodPlayer::vol_up_alt(unsigned char chan, int amount) channel[chan].vol1 += amount; else channel[chan].vol1 = 63; - if(inst[channel[chan].inst].data[0] & 1) + if(inst[channel[chan].inst].data[0] & 1) { if(channel[chan].vol2 + amount < 63) channel[chan].vol2 += amount; else channel[chan].vol2 = 63; + } } void CmodPlayer::vol_down_alt(unsigned char chan, int amount) @@ -812,9 +817,10 @@ void CmodPlayer::vol_down_alt(unsigned char chan, int amount) channel[chan].vol1 -= amount; else channel[chan].vol1 = 0; - if(inst[channel[chan].inst].data[0] & 1) + if(inst[channel[chan].inst].data[0] & 1) { if(channel[chan].vol2 - amount > 0) channel[chan].vol2 -= amount; else channel[chan].vol2 = 0; + } } diff --git a/plugins/adplug/adplug/rad.cpp b/plugins/adplug/adplug/rad.cpp index 0178a6c3..7996d9ae 100644 --- a/plugins/adplug/adplug/rad.cpp +++ b/plugins/adplug/adplug/rad.cpp @@ -22,7 +22,7 @@ * some volumes are dropped out */ -#include <string.h> +#include <cstring> #include "rad.h" CPlayer *CradLoader::factory(Copl *newopl) diff --git a/plugins/adplug/adplug/rat.cpp b/plugins/adplug/adplug/rat.cpp index b20af250..34f97cb6 100644 --- a/plugins/adplug/adplug/rat.cpp +++ b/plugins/adplug/adplug/rat.cpp @@ -29,7 +29,7 @@ comment : there are bug in original replayer's adlib_init(): wrong frequency registers. */ -#include <string.h> +#include <cstring> #include "rat.h" #include "debug.h" diff --git a/plugins/adplug/adplug/raw.cpp b/plugins/adplug/adplug/raw.cpp index 1672a1d0..0ca3f36b 100644 --- a/plugins/adplug/adplug/raw.cpp +++ b/plugins/adplug/adplug/raw.cpp @@ -19,7 +19,7 @@ * raw.c - RAW Player by Simon Peter <dn.tlp@gmx.net> */ -#include <string.h> +#include <cstring> #include "raw.h" /*** public methods *************************************/ diff --git a/plugins/adplug/adplug/rix.cpp b/plugins/adplug/adplug/rix.cpp index 02ebc8d5..5cd69bd1 100644 --- a/plugins/adplug/adplug/rix.cpp +++ b/plugins/adplug/adplug/rix.cpp @@ -20,7 +20,7 @@ * BSPAL <BSPAL.ys168.com> */ -#include <string.h> +#include <cstring> #include "rix.h" #include "debug.h" diff --git a/plugins/adplug/adplug/rol.cpp b/plugins/adplug/adplug/rol.cpp index 7507d79b..a2a88fe8 100644 --- a/plugins/adplug/adplug/rol.cpp +++ b/plugins/adplug/adplug/rol.cpp @@ -20,6 +20,7 @@ * * Visit: http://tenacity.hispeed.com/aomit/oplx/ */ +#include <cstring> #include <algorithm> #include "rol.h" @@ -665,7 +666,7 @@ int CrolPlayer::load_rol_instrument( binistream *f, SBnkHeader const &header, st else { // set up default instrument data here - memset( &usedIns.instrument, 0, kSizeofDataRecord ); + memset( &usedIns.instrument, 0, sizeof(SRolInstrument) ); } ins_list.push_back( usedIns ); diff --git a/plugins/adplug/adplug/rol.h b/plugins/adplug/adplug/rol.h index fdb9fabb..82337adf 100644 --- a/plugins/adplug/adplug/rol.h +++ b/plugins/adplug/adplug/rol.h @@ -1,6 +1,6 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2004 Simon Peter, <dn.tlp@gmx.net>, et al. + * Copyright (C) 1999 - 2008 Simon Peter, <dn.tlp@gmx.net>, et al. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,7 +25,7 @@ #include <vector> #include <string> -#include <string.h> +#include <strings.h> #include "player.h" diff --git a/plugins/adplug/adplug/s3m.cpp b/plugins/adplug/adplug/s3m.cpp index ddc2a3b9..ff0baa35 100644 --- a/plugins/adplug/adplug/s3m.cpp +++ b/plugins/adplug/adplug/s3m.cpp @@ -22,7 +22,7 @@ * Extra Fine Slides (EEx, FEx) & Fine Vibrato (Uxy) are inaccurate */ -#include <string.h> +#include <cstring> #include "s3m.h" const char Cs3mPlayer::chnresolv[] = // S3M -> adlib channel conversion @@ -164,16 +164,18 @@ bool Cs3mPlayer::update() vibrato(realchan,channel[realchan].dualinfo); else // dual command: G00 and Dxy tone_portamento(realchan,channel[realchan].dualinfo); - case 4: if(info <= 0x0f) // volume slide down + case 4: if(info <= 0x0f) { // volume slide down if(channel[realchan].vol - info >= 0) channel[realchan].vol -= info; else channel[realchan].vol = 0; - if((info & 0x0f) == 0) // volume slide up + } + if((info & 0x0f) == 0) { // volume slide up if(channel[realchan].vol + (info >> 4) <= 63) channel[realchan].vol += info >> 4; else channel[realchan].vol = 63; + } setvolume(realchan); break; case 5: if(info == 0xf0 || info <= 0xe0) { // slide down @@ -247,7 +249,7 @@ bool Cs3mPlayer::update() if(realchan != -1) { // channel playable? // set channel values donote = 0; - if(pattern[pattnr][row][chan].note < 14) + if(pattern[pattnr][row][chan].note < 14) { // tone portamento if(pattern[pattnr][row][chan].command == 7 || pattern[pattnr][row][chan].command == 12) { channel[realchan].nextfreq = notetable[pattern[pattnr][row][chan].note]; @@ -259,6 +261,7 @@ bool Cs3mPlayer::update() channel[realchan].key = 1; donote = 1; } + } if(pattern[pattnr][row][chan].note == 14) { // key off (is 14 here, cause note is only first 4 bits) channel[realchan].key = 0; setfreq(realchan); @@ -284,11 +287,12 @@ bool Cs3mPlayer::update() if(pattern[pattnr][row][chan].command != 7) donote = 1; } - if(pattern[pattnr][row][chan].volume != 255) + if(pattern[pattnr][row][chan].volume != 255) { if(pattern[pattnr][row][chan].volume < 64) // set volume channel[realchan].vol = pattern[pattnr][row][chan].volume; else channel[realchan].vol = 63; + } channel[realchan].fx = pattern[pattnr][row][chan].command; // set command if(pattern[pattnr][row][chan].info) // set infobyte channel[realchan].info = pattern[pattnr][row][chan].info; @@ -315,16 +319,18 @@ bool Cs3mPlayer::update() case 1: speed = info; break; // set speed case 2: if(info <= ord) songend = 1; ord = info; crow = 0; pattbreak = 1; break; // jump to order case 3: if(!pattbreak) { crow = info; ord++; pattbreak = 1; } break; // pattern break - case 4: if(info > 0xf0) // fine volume down + case 4: if(info > 0xf0) { // fine volume down if(channel[realchan].vol - (info & 0x0f) >= 0) channel[realchan].vol -= info & 0x0f; else channel[realchan].vol = 0; - if((info & 0x0f) == 0x0f && info >= 0x1f) // fine volume up + } + if((info & 0x0f) == 0x0f && info >= 0x1f) { // fine volume up if(channel[realchan].vol + ((info & 0xf0) >> 4) <= 63) channel[realchan].vol += (info & 0xf0) >> 4; else channel[realchan].vol = 63; + } setvolume(realchan); break; case 5: if(info > 0xf0) { // fine slide down @@ -353,7 +359,7 @@ bool Cs3mPlayer::update() case 10: channel[realchan].trigger = 0; break; // arpeggio (set trigger) case 19: if(info == 0xb0) // set loop start loopstart = row; - if(info > 0xb0 && info <= 0xbf) // pattern loop + if(info > 0xb0 && info <= 0xbf) { // pattern loop if(!loopcnt) { loopcnt = info & 0x0f; crow = loopstart; @@ -363,6 +369,7 @@ bool Cs3mPlayer::update() crow = loopstart; pattbreak = 1; } + } if((info & 0xf0) == 0xe0) // patterndelay del = speed * (info & 0x0f) - 1; break; @@ -450,7 +457,7 @@ void Cs3mPlayer::setfreq(unsigned char chan) { opl->write(0xa0 + chan, channel[chan].freq & 255); if(channel[chan].key) - opl->write(0xb0 + chan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2) | 32); + opl->write(0xb0 + chan, (((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2)) | 32); else opl->write(0xb0 + chan, ((channel[chan].freq & 768) >> 8) + (channel[chan].oct << 2)); } diff --git a/plugins/adplug/adplug/sa2.cpp b/plugins/adplug/adplug/sa2.cpp index 2e1248bc..8d81e9c1 100644 --- a/plugins/adplug/adplug/sa2.cpp +++ b/plugins/adplug/adplug/sa2.cpp @@ -1,6 +1,6 @@ /* * Adplug - Replayer for many OPL2/OPL3 audio file formats. - * Copyright (C) 1999 - 2007 Simon Peter, <dn.tlp@gmx.net>, et al. + * Copyright (C) 1999 - 2008 Simon Peter, <dn.tlp@gmx.net>, et al. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,8 +20,9 @@ * SAdT Loader by Mamiya <mamiya@users.sourceforge.net> */ -#include <string.h> +#include <cstring> #include <stdio.h> +#include <string.h> #include "sa2.h" #include "debug.h" diff --git a/plugins/adplug/adplug/sng.cpp b/plugins/adplug/adplug/sng.cpp index bf0fa699..5e8b6af4 100644 --- a/plugins/adplug/adplug/sng.cpp +++ b/plugins/adplug/adplug/sng.cpp @@ -19,7 +19,7 @@ * sng.cpp - SNG Player by Simon Peter <dn.tlp@gmx.net> */ -#include <string.h> +#include <cstring> #include "sng.h" CPlayer *CsngPlayer::factory(Copl *newopl) diff --git a/plugins/adplug/adplug/surroundopl.cpp b/plugins/adplug/adplug/surroundopl.cpp new file mode 100644 index 00000000..14e67e21 --- /dev/null +++ b/plugins/adplug/adplug/surroundopl.cpp @@ -0,0 +1,203 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2010 Simon Peter, <dn.tlp@gmx.net>, et al. + * + * 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 + * + * surroundopl.cpp - Wrapper class to provide a surround/harmonic effect + * for another OPL emulator, by Adam Nielsen <malvineous@shikadi.net> + * + * Stereo harmonic algorithm by Adam Nielsen <malvineous@shikadi.net> + * Please give credit if you use this algorithm elsewhere :-) + */ + +#include <math.h> // for pow() +#include "surroundopl.h" +#include "debug.h" + +CSurroundopl::CSurroundopl(Copl *a, Copl *b, bool use16bit) + : use16bit(use16bit), + bufsize(4096), + a(a), b(b) +{ + currType = TYPE_OPL2; + this->lbuf = new short[this->bufsize]; + this->rbuf = new short[this->bufsize]; +}; + +CSurroundopl::~CSurroundopl() +{ + delete[] this->rbuf; + delete[] this->lbuf; + delete a; + delete b; +} + +void CSurroundopl::update(short *buf, int samples) +{ + if (samples * 2 > this->bufsize) { + // Need to realloc the buffer + delete[] this->rbuf; + delete[] this->lbuf; + this->bufsize = samples * 2; + this->lbuf = new short[this->bufsize]; + this->rbuf = new short[this->bufsize]; + } + + a->update(this->lbuf, samples); + b->update(this->rbuf, samples); + + // Copy the two mono OPL buffers into the stereo buffer + for (int i = 0; i < samples; i++) { + if (this->use16bit) { + buf[i * 2] = this->lbuf[i]; + buf[i * 2 + 1] = this->rbuf[i]; + } else { + ((char *)buf)[i * 2] = ((char *)this->lbuf)[i]; + ((char *)buf)[i * 2 + 1] = ((char *)this->rbuf)[i]; + } + } + +} + +// template methods +void CSurroundopl::write(int reg, int val) +{ + a->write(reg, val); + + // Transpose the other channel to produce the harmonic effect + + int iChannel = -1; + int iRegister = reg; // temp + int iValue = val; // temp + if ((iRegister >> 4 == 0xA) || (iRegister >> 4 == 0xB)) iChannel = iRegister & 0x0F; + + // Remember the FM state, so that the harmonic effect can access + // previously assigned register values. + /*if (((iRegister >> 4 == 0xB) && (iValue & 0x20) && !(this->iFMReg[iRegister] & 0x20)) || + (iRegister == 0xBD) && ( + ((iValue & 0x01) && !(this->iFMReg[0xBD] & 0x01)) + )) { + this->iFMReg[iRegister] = iValue; + }*/ + this->iFMReg[iRegister] = iValue; + + if ((iChannel >= 0)) {// && (i == 1)) { + uint8_t iBlock = (this->iFMReg[0xB0 + iChannel] >> 2) & 0x07; + uint16_t iFNum = ((this->iFMReg[0xB0 + iChannel] & 0x03) << 8) | this->iFMReg[0xA0 + iChannel]; + //double dbOriginalFreq = 50000.0 * (double)iFNum * pow(2, iBlock - 20); + double dbOriginalFreq = 49716.0 * (double)iFNum * pow(2, iBlock - 20); + + uint8_t iNewBlock = iBlock; + uint16_t iNewFNum; + + // Adjust the frequency and calculate the new FNum + //double dbNewFNum = (dbOriginalFreq+(dbOriginalFreq/FREQ_OFFSET)) / (50000.0 * pow(2, iNewBlock - 20)); + //#define calcFNum() ((dbOriginalFreq+(dbOriginalFreq/FREQ_OFFSET)) / (50000.0 * pow(2, iNewBlock - 20))) + #define calcFNum() ((dbOriginalFreq+(dbOriginalFreq/FREQ_OFFSET)) / (49716.0 * pow(2, iNewBlock - 20))) + double dbNewFNum = calcFNum(); + + // Make sure it's in range for the OPL chip + if (dbNewFNum > 1023 - NEWBLOCK_LIMIT) { + // It's too high, so move up one block (octave) and recalculate + + if (iNewBlock > 6) { + // Uh oh, we're already at the highest octave! + AdPlug_LogWrite("OPL WARN: FNum %d/B#%d would need block 8+ after being transposed (new FNum is %d)\n", + iFNum, iBlock, (int)dbNewFNum); + // The best we can do here is to just play the same note out of the second OPL, so at least it shouldn't + // sound *too* bad (hopefully it will just miss out on the nice harmonic.) + iNewBlock = iBlock; + iNewFNum = iFNum; + } else { + iNewBlock++; + iNewFNum = (uint16_t)calcFNum(); + } + } else if (dbNewFNum < 0 + NEWBLOCK_LIMIT) { + // It's too low, so move down one block (octave) and recalculate + + if (iNewBlock == 0) { + // Uh oh, we're already at the lowest octave! + AdPlug_LogWrite("OPL WARN: FNum %d/B#%d would need block -1 after being transposed (new FNum is %d)!\n", + iFNum, iBlock, (int)dbNewFNum); + // The best we can do here is to just play the same note out of the second OPL, so at least it shouldn't + // sound *too* bad (hopefully it will just miss out on the nice harmonic.) + iNewBlock = iBlock; + iNewFNum = iFNum; + } else { + iNewBlock--; + iNewFNum = (uint16_t)calcFNum(); + } + } else { + // Original calculation is within range, use that + iNewFNum = (uint16_t)dbNewFNum; + } + + // Sanity check + if (iNewFNum > 1023) { + // Uh oh, the new FNum is still out of range! (This shouldn't happen) + AdPlug_LogWrite("OPL ERR: Original note (FNum %d/B#%d is still out of range after change to FNum %d/B#%d!\n", + iFNum, iBlock, iNewFNum, iNewBlock); + // The best we can do here is to just play the same note out of the second OPL, so at least it shouldn't + // sound *too* bad (hopefully it will just miss out on the nice harmonic.) + iNewBlock = iBlock; + iNewFNum = iFNum; + } + + if ((iRegister >= 0xB0) && (iRegister <= 0xB8)) { + + // Overwrite the supplied value with the new F-Number and Block. + iValue = (iValue & ~0x1F) | (iNewBlock << 2) | ((iNewFNum >> 8) & 0x03); + + this->iCurrentTweakedBlock[iChannel] = iNewBlock; // save it so we don't have to update register 0xB0 later on + this->iCurrentFNum[iChannel] = iNewFNum; + + if (this->iTweakedFMReg[0xA0 + iChannel] != (iNewFNum & 0xFF)) { + // Need to write out low bits + uint8_t iAdditionalReg = 0xA0 + iChannel; + uint8_t iAdditionalValue = iNewFNum & 0xFF; + b->write(iAdditionalReg, iAdditionalValue); + this->iTweakedFMReg[iAdditionalReg] = iAdditionalValue; + } + } else if ((iRegister >= 0xA0) && (iRegister <= 0xA8)) { + + // Overwrite the supplied value with the new F-Number. + iValue = iNewFNum & 0xFF; + + // See if we need to update the block number, which is stored in a different register + uint8_t iNewB0Value = (this->iFMReg[0xB0 + iChannel] & ~0x1F) | (iNewBlock << 2) | ((iNewFNum >> 8) & 0x03); + if ( + (iNewB0Value & 0x20) && // but only update if there's a note currently playing (otherwise we can just wait + (this->iTweakedFMReg[0xB0 + iChannel] != iNewB0Value) // until the next noteon and update it then) + ) { + AdPlug_LogWrite("OPL INFO: CH%d - FNum %d/B#%d -> FNum %d/B#%d == keyon register update!\n", + iChannel, iFNum, iBlock, iNewFNum, iNewBlock); + // The note is already playing, so we need to adjust the upper bits too + uint8_t iAdditionalReg = 0xB0 + iChannel; + b->write(iAdditionalReg, iNewB0Value); + this->iTweakedFMReg[iAdditionalReg] = iNewB0Value; + } // else the note is not playing, the upper bits will be set when the note is next played + + } // if (register 0xB0 or 0xA0) + + } // if (a register we're interested in) + + // Now write to the original register with a possibly modified value + b->write(iRegister, iValue); + this->iTweakedFMReg[iRegister] = iValue; + +}; + +void CSurroundopl::init() {}; diff --git a/plugins/adplug/adplug/surroundopl.h b/plugins/adplug/adplug/surroundopl.h new file mode 100644 index 00000000..d302a9e8 --- /dev/null +++ b/plugins/adplug/adplug/surroundopl.h @@ -0,0 +1,69 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2010 Simon Peter, <dn.tlp@gmx.net>, et al. + * + * 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 + * + * surroundopl.h - Wrapper class to provide a surround/harmonic effect + * for another OPL emulator, by Adam Nielsen <malvineous@shikadi.net> + * + * Stereo harmonic algorithm by Adam Nielsen <malvineous@shikadi.net> + * Please give credit if you use this algorithm elsewhere :-) + */ + +#ifndef H_ADPLUG_SURROUNDOPL +#define H_ADPLUG_SURROUNDOPL + +#include <stdint.h> // for uintxx_t +#include "opl.h" + +// The right-channel is increased in frequency by itself divided by this amount. +// The right value should not noticeably change the pitch, but it should provide +// a nice stereo harmonic effect. +#define FREQ_OFFSET 128.0//96.0 + +// Number of FNums away from the upper/lower limit before switching to the next +// block (octave.) By rights it should be zero, but for some reason this seems +// to cut it to close and the transposed OPL doesn't hit the right note all the +// time. Setting it higher means it will switch blocks sooner and that seems +// to help. Don't set it too high or it'll get stuck in an infinite loop if +// one block is too high and the adjacent block is too low ;-) +#define NEWBLOCK_LIMIT 32 + +class CSurroundopl: public Copl +{ + private: + bool use16bit; + short bufsize; + short *lbuf, *rbuf; + Copl *a, *b; + uint8_t iFMReg[256]; + uint8_t iTweakedFMReg[256]; + uint8_t iCurrentTweakedBlock[9]; // Current value of the Block in the tweaked OPL chip + uint8_t iCurrentFNum[9]; // Current value of the FNum in the tweaked OPL chip + + public: + + CSurroundopl(Copl *a, Copl *b, bool use16bit); + ~CSurroundopl(); + + void update(short *buf, int samples); + void write(int reg, int val); + + void init(); + +}; + +#endif diff --git a/plugins/adplug/adplug/u6m.cpp b/plugins/adplug/adplug/u6m.cpp index 5c0a2ca2..d34f6fc2 100644 --- a/plugins/adplug/adplug/u6m.cpp +++ b/plugins/adplug/adplug/u6m.cpp @@ -215,7 +215,7 @@ bool Cu6mPlayer::lzw_decompress(Cu6mPlayer::data_block source, Cu6mPlayer::data_ long bytes_written = 0; int cW; - int pW; + int pW = 0; unsigned char C; while (!end_marker_reached) diff --git a/plugins/adplug/adplug/xsm.h b/plugins/adplug/adplug/xsm.h index 15129606..0e844afc 100644 --- a/plugins/adplug/adplug/xsm.h +++ b/plugins/adplug/adplug/xsm.h @@ -29,7 +29,7 @@ public: CxsmPlayer(Copl *newopl); ~CxsmPlayer(); - bool load(const std::string &fn, const CFileProvider &fp); + bool load(const std::string &filename, const CFileProvider &fp); bool update(); void rewind(int subsong); float getrefresh(); diff --git a/plugins/adplug/libbinio/binfile.cpp b/plugins/adplug/libbinio/binfile.cpp index 446f899f..336f1b3b 100644 --- a/plugins/adplug/libbinio/binfile.cpp +++ b/plugins/adplug/libbinio/binfile.cpp @@ -44,7 +44,7 @@ void binfbase::close() void binfbase::seek(long pos, Offset offs) { - int error; + int error = 0; if(f == NULL) { err |= NotOpen; return; } @@ -151,7 +151,7 @@ binofstream::~binofstream() void binofstream::open(const char *filename, const Mode mode) { - char *modestr = "wb"; + const char *modestr = "wb"; // Check if append mode is desired if(mode & Append) modestr = "ab"; @@ -209,16 +209,16 @@ binfstream::~binfstream() void binfstream::open(const char *filename, const Mode mode) { - char *modestr = "w+b"; // Create & at beginning + const char *modestr = "w+b"; // Create & at beginning int ferror = 0; // Apply desired mode if(mode & NoCreate) { if(!(mode & Append)) - modestr[0] = 'r'; // NoCreate & at beginning + modestr = "r+b"; // NoCreate & at beginning } else if(mode & Append) // Create & append - modestr[0] = 'a'; + modestr = "a+b"; f = fopen(filename, modestr); diff --git a/plugins/alsa/alsa.c b/plugins/alsa/alsa.c index 2a5b9b2c..0709fd46 100644 --- a/plugins/alsa/alsa.c +++ b/plugins/alsa/alsa.c @@ -20,7 +20,8 @@ #include <stdint.h> #include <unistd.h> #include <sys/prctl.h> -#include "deadbeef.h" +#include "../../deadbeef.h" +#include "../../config.h" #define trace(...) { fprintf(stderr, __VA_ARGS__); } //#define trace(fmt,...) @@ -177,6 +178,8 @@ error: int palsa_init (void) { int err; + alsa_tid = 0; + mutex = 0; // get and cache conf variables strcpy (conf_alsa_soundcard, deadbeef->conf_get_str ("alsa_soundcard", "default")); @@ -294,11 +297,16 @@ palsa_free (void) { if (audio && !alsa_terminate) { alsa_terminate = 1; printf ("waiting for alsa thread to finish\n"); - deadbeef->thread_join (alsa_tid); - alsa_tid = 0; + if (alsa_tid) { + deadbeef->thread_join (alsa_tid); + alsa_tid = 0; + } snd_pcm_close(audio); audio = NULL; - deadbeef->mutex_free (mutex); + if (mutex) { + deadbeef->mutex_free (mutex); + mutex = 0; + } state = 0; alsa_terminate = 0; } @@ -468,7 +476,7 @@ palsa_thread (void *context) { char buf[frames_to_deliver*4]; palsa_callback (buf, frames_to_deliver*4); if ((err = snd_pcm_writei (audio, buf, frames_to_deliver)) < 0) { - trace ("write %d frames failed (%s)\n", frames_to_deliver, snd_strerror (err)); + trace ("write %d frames failed (%s)\n", (int)frames_to_deliver, snd_strerror (err)); snd_pcm_prepare (audio); snd_pcm_start (audio); } diff --git a/plugins/cdda/cdda.c b/plugins/cdda/cdda.c index 6137e37e..a93fcf26 100644 --- a/plugins/cdda/cdda.c +++ b/plugins/cdda/cdda.c @@ -108,6 +108,7 @@ cda_init (DB_playItem_t *it) { current_sector = first_sector; tail_len = 0; current_sample = 0; + return 0; } int diff --git a/plugins/ffap/ffap.c b/plugins/ffap/ffap.c index 3403ddc3..c0b40ec4 100644 --- a/plugins/ffap/ffap.c +++ b/plugins/ffap/ffap.c @@ -385,7 +385,7 @@ ape_read_header(DB_FILE *fp, APEContext *ape) } if (ape->fileversion < APE_MIN_VERSION || ape->fileversion > APE_MAX_VERSION) { - fprintf (stderr, "Unsupported file version - %d.%02d\n", ape->fileversion / 1000, (ape->fileversion % 1000) / 10); + fprintf (stderr, "ape: Unsupported file version - %d.%02d\n", ape->fileversion / 1000, (ape->fileversion % 1000) / 10); return -1; } @@ -513,7 +513,7 @@ ape_read_header(DB_FILE *fp, APEContext *ape) } if(ape->totalframes > UINT_MAX / sizeof(APEFrame)){ - fprintf (stderr, "Too many frames: %d\n", ape->totalframes); + fprintf (stderr, "ape: Too many frames: %d\n", ape->totalframes); return -1; } ape->frames = malloc(ape->totalframes * sizeof(APEFrame)); @@ -560,7 +560,7 @@ ape_read_header(DB_FILE *fp, APEContext *ape) ape_dumpinfo(ape); #if ENABLE_DEBUG - fprintf (stderr, "Decoding file - v%d.%02d, compression level %d\n", ape->fileversion / 1000, (ape->fileversion % 1000) / 10, ape->compressiontype); + fprintf (stderr, "ape: Decoding file - v%d.%02d, compression level %d\n", ape->fileversion / 1000, (ape->fileversion % 1000) / 10, ape->compressiontype); #endif total_blocks = (ape->totalframes == 0) ? 0 : ((ape->totalframes - 1) * ape->blocksperframe) + ape->finalframeblocks; @@ -672,20 +672,16 @@ ffap_init(DB_playItem_t *it) ape_read_header (fp, &ape_ctx); int i; - if (ape_ctx.bps != 16) { - fprintf (stderr, "Only 16-bit samples are supported\n"); - return -1; - } if (ape_ctx.channels > 2) { - fprintf (stderr, "Only mono and stereo is supported\n"); + fprintf (stderr, "ape: Only mono and stereo is supported\n"); return -1; } #if ENABLE_DEBUG - fprintf (stderr, "Compression Level: %d - Flags: %d\n", ape_ctx.compressiontype, ape_ctx.formatflags); + fprintf (stderr, "ape: Compression Level: %d - Flags: %d\n", ape_ctx.compressiontype, ape_ctx.formatflags); #endif if (ape_ctx.compressiontype % 1000 || ape_ctx.compressiontype > COMPRESSION_LEVEL_INSANE) { - fprintf (stderr, "Incorrect compression level %d\n", ape_ctx.compressiontype); + fprintf (stderr, "ape: Incorrect compression level %d\n", ape_ctx.compressiontype); return -1; } ape_ctx.fset = ape_ctx.compressiontype / 1000 - 1; @@ -716,7 +712,7 @@ ffap_init(DB_playItem_t *it) ape_ctx.packet_data = malloc (PACKET_BUFFER_SIZE); if (!ape_ctx.packet_data) { - fprintf (stderr, "ffap: failed to allocate memory for packet data\n"); + fprintf (stderr, "ape: failed to allocate memory for packet data\n"); return -1; } return 0; @@ -856,8 +852,9 @@ static inline int range_get_symbol(APEContext * ctx, if(cf > 65492){ symbol= cf - 65535 + 63; range_decode_update(ctx, 1, cf); - if(cf > 65535) + if(unlikely (cf > 65535)) { ctx->error=1; + } return symbol; } /* figure out the symbol inefficiently; a binary search would be much better */ @@ -916,15 +913,47 @@ static inline int ape_decode_value(APEContext * ctx, APERice *rice) overflow |= range_decode_bits(ctx, 16); } -// base = range_decode_culfreq(ctx, pivot); - range_dec_normalize(ctx); - ctx->rc.help = ctx->rc.range / pivot; - if (unlikely (ctx->rc.help == 0)) { - ctx->error = 1; - return 0; + if (pivot >= 0x10000) { + /* Codepath for 24-bit streams */ + int nbits, lo_bits, base_hi, base_lo; + + /* Count the number of bits in pivot */ + nbits = 17; /* We know there must be at least 17 bits */ + while ((pivot >> nbits) > 0) { nbits++; } + + /* base_lo is the low (nbits-16) bits of base + base_hi is the high 16 bits of base + */ + lo_bits = (nbits - 16); + + // {{{ unrolled base_hi = range_decode_culfreq(ctx, (pivot >> lo_bits) + 1) + range_dec_normalize(ctx); + ctx->rc.help = ctx->rc.range / ((pivot >> lo_bits) + 1); + if (unlikely (ctx->rc.help == 0)) { + ctx->error = 1; + return 0; + } + base_hi = ctx->rc.low / ctx->rc.help; + // }}} + range_decode_update(ctx, 1, base_hi); + + base_lo = range_decode_culshift(ctx, lo_bits); + range_decode_update(ctx, 1, base_lo); + + base = (base_hi << lo_bits) + base_lo; + } + else { + // {{{ unrolled base = range_decode_culfreq(ctx, pivot) + range_dec_normalize(ctx); + ctx->rc.help = ctx->rc.range / pivot; + if (unlikely (ctx->rc.help == 0)) { + ctx->error = 1; + return 0; + } + base = ctx->rc.low / ctx->rc.help; + // }}} + range_decode_update(ctx, 1, base); } - base = ctx->rc.low / ctx->rc.help; - range_decode_update(ctx, 1, base); x = base + overflow * pivot; } @@ -950,7 +979,7 @@ static void entropy_decode(APEContext * ctx, int blockstodecode, int stereo) memset(decoded0, 0, blockstodecode * sizeof(int32_t)); memset(decoded1, 0, blockstodecode * sizeof(int32_t)); } else { - while (blockstodecode--) { + while (likely (blockstodecode--)) { *decoded0++ = ape_decode_value(ctx, &ctx->riceY); if (stereo) *decoded1++ = ape_decode_value(ctx, &ctx->riceX); @@ -1448,7 +1477,7 @@ static void ape_unpack_mono(APEContext * ctx, int count) if (ctx->frameflags & APE_FRAMECODE_STEREO_SILENCE) { entropy_decode(ctx, count, 0); /* We are pure silence, so we're done. */ - fprintf (stderr, "pure silence mono\n"); + //fprintf (stderr, "pure silence mono\n"); return; } @@ -1475,7 +1504,7 @@ static void ape_unpack_stereo(APEContext * ctx, int count) if (ctx->frameflags & APE_FRAMECODE_STEREO_SILENCE) { /* We are pure silence, so we're done. */ - fprintf (stderr, "pure silence stereo\n"); + //fprintf (stderr, "pure silence stereo\n"); return; } @@ -1503,10 +1532,11 @@ ape_decode_frame(APEContext *s, void *data, int *data_size) int i, n; int blockstodecode; int bytes_used; + int samplesize = plugin.info.bps>>3; /* should not happen but who knows */ - if (BLOCKS_PER_LOOP * 2 * s->channels > *data_size) { - fprintf (stderr, "Packet size is too big! (max is %d where you have %d)\n", *data_size, BLOCKS_PER_LOOP * 2 * s->channels); + if (BLOCKS_PER_LOOP * samplesize * s->channels > *data_size) { + fprintf (stderr, "ape: Packet size is too big! (max is %d where you have %d)\n", *data_size, BLOCKS_PER_LOOP * samplesize * s->channels); return -1; } @@ -1520,7 +1550,7 @@ ape_decode_frame(APEContext *s, void *data, int *data_size) assert (s->samples == 0); // all samples from prev packet must have been read // start new packet if (ape_read_packet (fp, &ape_ctx) < 0) { - fprintf (stderr, "error reading packet\n"); + fprintf (stderr, "ape: error reading packet\n"); return -1; } bswap_buf((uint32_t*)(s->packet_data), (const uint32_t*)(s->packet_data), s->packet_remaining >> 2); @@ -1533,7 +1563,7 @@ ape_decode_frame(APEContext *s, void *data, int *data_size) //fprintf (stderr, "s->samples=%d (1)\n", s->samples); n = bytestream_get_be32(&s->ptr); if(n < 0 || n > 3){ - fprintf (stderr, "Incorrect offset passed\n"); + fprintf (stderr, "ape: Incorrect offset passed\n"); return -1; } s->ptr += n; @@ -1572,7 +1602,7 @@ ape_decode_frame(APEContext *s, void *data, int *data_size) return 0; } if (!s->packet_remaining) { - fprintf (stderr, "packetbuf is empty!!\n"); + fprintf (stderr, "ape: packetbuf is empty!!\n"); *data_size = 0; bytes_used = s->packet_remaining; goto error; @@ -1591,10 +1621,10 @@ ape_decode_frame(APEContext *s, void *data, int *data_size) if(s->error || s->ptr >= s->data_end){ s->samples=0; if (s->error) { - fprintf (stderr, "Error decoding frame, error=%d\n", s->error); + fprintf (stderr, "ape: Error decoding frame, error=%d\n", s->error); } else { - fprintf (stderr, "Error decoding frame, ptr > data_end\n"); + fprintf (stderr, "ape: Error decoding frame, ptr > data_end\n"); } return -1; } @@ -1603,9 +1633,9 @@ ape_decode_frame(APEContext *s, void *data, int *data_size) i = skip; for (; i < blockstodecode; i++) { - *samples++ = s->decoded0[i]; + *samples++ = (int16_t)(s->decoded0[i]>>(plugin.info.bps-16)); if(s->channels == 2) { - *samples++ = s->decoded1[i]; + *samples++ = (int16_t)(s->decoded1[i]>>(plugin.info.bps-16)); } } @@ -1637,13 +1667,13 @@ ffap_insert (DB_playItem_t *after, const char *fname) { return NULL; } if (ape_read_header (fp, &ape_ctx) < 0) { - fprintf (stderr, "failed to read ape header\n"); + fprintf (stderr, "ape: failed to read ape header\n"); deadbeef->fclose (fp); ape_free_ctx (&ape_ctx); return NULL; } if ((ape_ctx.fileversion < APE_MIN_VERSION) || (ape_ctx.fileversion > APE_MAX_VERSION)) { - fprintf(stderr, "unsupported file version - %.2f\n", ape_ctx.fileversion/1000.0); + fprintf(stderr, "ape: unsupported file version - %.2f\n", ape_ctx.fileversion/1000.0); deadbeef->fclose (fp); ape_free_ctx (&ape_ctx); return NULL; diff --git a/plugins/ffmpeg/ffmpeg.c b/plugins/ffmpeg/ffmpeg.c index 59bb66ac..c87f8cf6 100644 --- a/plugins/ffmpeg/ffmpeg.c +++ b/plugins/ffmpeg/ffmpeg.c @@ -16,12 +16,33 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <alloca.h> +#include <errno.h> + #include "../../deadbeef.h" + +#if !FFMPEG_OLD + #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> #include <libavutil/avutil.h> #include <libavutil/avstring.h> +#else + +#include <ffmpeg/avformat.h> +#include <ffmpeg/avcodec.h> +#include <ffmpeg/avutil.h> +#include <ffmpeg/avstring.h> +#define AVERROR_EOF AVERROR(EPIPE) +#define av_register_protocol register_protocol + +#endif + #define trace(...) { fprintf(stderr, __VA_ARGS__); } //#define trace(fmt,...) @@ -87,12 +108,12 @@ ffmpeg_init (DB_playItem_t *it) { } stream_id = -1; + av_find_stream_info(fctx); for (i = 0; i < fctx->nb_streams; i++) { ctx = fctx->streams[i]->codec; if (ctx->codec_type == CODEC_TYPE_AUDIO) { - av_find_stream_info(fctx); codec = avcodec_find_decoder(ctx->codec_id); if (codec != NULL) { stream_id = i; @@ -130,13 +151,12 @@ ffmpeg_init (DB_playItem_t *it) { memset (&pkt, 0, sizeof (pkt)); have_packet = 0; - buffer = malloc (AVCODEC_MAX_AUDIO_FRAME_SIZE); - if (!buffer) { + int err = posix_memalign ((void **)&buffer, 16, AVCODEC_MAX_AUDIO_FRAME_SIZE); + if (err) { fprintf (stderr, "ffmpeg: failed to allocate buffer memory\n"); return -1; } - // fill in mandatory plugin fields plugin.info.readpos = 0; plugin.info.bps = bps; @@ -218,13 +238,13 @@ ffmpeg_read_int16 (char *bytes, int size) { while (left_in_packet > 0 && size > 0) { int out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; int len; - //trace ("in: out_size=%d(%d), size=%d\n", out_size, AVCODEC_MAX_AUDIO_FRAME_SIZE, size); +// trace ("in: out_size=%d(%d), size=%d\n", out_size, AVCODEC_MAX_AUDIO_FRAME_SIZE, size); #if (LIBAVCODEC_VERSION_MAJOR <= 52) && (LIBAVCODEC_VERSION_MINOR <= 25) len = avcodec_decode_audio2(ctx, (int16_t *)buffer, &out_size, pkt.data, pkt.size); #else len = avcodec_decode_audio3(ctx, (int16_t *)buffer, &out_size, &pkt); #endif - //trace ("out: out_size=%d, len=%d\n", out_size, len); +// trace ("out: out_size=%d, len=%d\n", out_size, len); if (len <= 0) { break; } @@ -268,12 +288,12 @@ ffmpeg_read_int16 (char *bytes, int size) { if (ret == -1) { break; } - //trace ("idx:%d, stream:%d\n", pkt.stream_index, stream_id); +// trace ("idx:%d, stream:%d\n", pkt.stream_index, stream_id); if (pkt.stream_index != stream_id) { av_free_packet (&pkt); continue; } - //trace ("got packet: size=%d\n", pkt.size); +// trace ("got packet: size=%d\n", pkt.size); have_packet = 1; left_in_packet = pkt.size; @@ -550,6 +570,7 @@ ffmpeg_start (void) { av_register_protocol (&vfswrapper); return 0; } + static int ffmpeg_stop (void) { // undo everything done in _start here diff --git a/plugins/gtkui/callbacks.c b/plugins/gtkui/callbacks.c index e302169a..818399fe 100644 --- a/plugins/gtkui/callbacks.c +++ b/plugins/gtkui/callbacks.c @@ -35,10 +35,13 @@ #include "gtkplaylist.h" #include "search.h" #include "progress.h" -#include "session.h" +#include "../../session.h" #include "gtkui.h" #include "parser.h" +#define trace(...) { fprintf (stderr, __VA_ARGS__); } +//#define trace(fmt,...) + #define SELECTED(it) (deadbeef->pl_is_selected(it)) #define SELECT(it, sel) (deadbeef->pl_set_selected(it,sel)) #define VSELECT(it, sel) {deadbeef->pl_set_selected(it,sel);gtk_pl_redraw_item_everywhere (it);} @@ -1378,7 +1381,7 @@ void on_help1_activate (GtkMenuItem *menuitem, gpointer user_data) { - show_info_window (PREFIX "/share/doc/deadbeef/help.txt", "Help", &helpwindow); + show_info_window (DOCDIR "/help.txt", "Help", &helpwindow); } static GtkWidget *aboutwindow; @@ -1387,7 +1390,34 @@ void on_about1_activate (GtkMenuItem *menuitem, gpointer user_data) { - show_info_window (PREFIX "/share/doc/deadbeef/about.txt", "About DeaDBeeF " VERSION, &aboutwindow); + show_info_window (DOCDIR "/about.txt", "About DeaDBeeF " VERSION, &aboutwindow); +} + +static GtkWidget *changelogwindow; + +void +on_changelog1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + show_info_window (DOCDIR "/ChangeLog", "DeaDBeeF " VERSION " ChangeLog", &changelogwindow); +} + +static GtkWidget *gplwindow; + +void +on_gpl1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + show_info_window (DOCDIR "/COPYING.GPLv2", "GNU GENERAL PUBLIC LICENSE Version 2", &gplwindow); +} + +static GtkWidget *lgplwindow; + +void +on_lgpl1_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + show_info_window (DOCDIR "/COPYING.LGPLv2.1", "GNU LESSER GENERAL PUBLIC LICENSE Version 2.1", &lgplwindow); } @@ -1843,6 +1873,24 @@ on_remove_column_activate (GtkMenuItem *menuitem, gtkpl_column_rewrite_config (ps); } +void +on_column_id_changed (GtkComboBox *combobox, + gpointer user_data) +{ + GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (combobox)); + if (!toplevel) { + trace ("failed to get toplevel widget for column id combobox\n"); + return; + } + int act = gtk_combo_box_get_active (combobox) + 1; + GtkWidget *fmt = lookup_widget (toplevel, "format"); + if (!fmt) { + trace ("failed to get column format widget\n"); + return; + } + gtk_widget_set_sensitive (fmt, act > DB_COLUMN_ID_MAX ? TRUE : FALSE); +} + void on_pref_alsa_freewhenstopped_clicked (GtkButton *button, @@ -2374,6 +2422,7 @@ on_trackproperties_key_press_event (GtkWidget *widget, gpointer user_data) { if (event->keyval == GDK_Escape) { + trackproperties = NULL; gtk_widget_destroy (widget); } return FALSE; @@ -2401,3 +2450,4 @@ on_trackproperties_delete_event (GtkWidget *widget, return FALSE; } + diff --git a/plugins/gtkui/callbacks.h b/plugins/gtkui/callbacks.h index f4667bde..cee7b241 100644 --- a/plugins/gtkui/callbacks.h +++ b/plugins/gtkui/callbacks.h @@ -787,3 +787,19 @@ gboolean on_trackproperties_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data); + +void +on_column_id_changed (GtkComboBox *combobox, + gpointer user_data); + +void +on_changelog1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_gpl1_activate (GtkMenuItem *menuitem, + gpointer user_data); + +void +on_lgpl1_activate (GtkMenuItem *menuitem, + gpointer user_data); diff --git a/plugins/gtkui/deadbeef.glade b/plugins/gtkui/deadbeef.glade index f54f18bf..cfd07055 100644 --- a/plugins/gtkui/deadbeef.glade +++ b/plugins/gtkui/deadbeef.glade @@ -57,7 +57,7 @@ <accelerator key="O" modifiers="GDK_CONTROL_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image297"> + <widget class="GtkImage" id="image312"> <property name="visible">True</property> <property name="stock">gtk-open</property> <property name="icon_size">1</property> @@ -84,7 +84,7 @@ <signal name="activate" handler="on_add_files_activate" last_modification_time="Sat, 04 Jul 2009 13:04:01 GMT"/> <child internal-child="image"> - <widget class="GtkImage" id="image298"> + <widget class="GtkImage" id="image313"> <property name="visible">True</property> <property name="stock">gtk-add</property> <property name="icon_size">1</property> @@ -105,7 +105,7 @@ <signal name="activate" handler="on_add_folders_activate" last_modification_time="Sun, 06 Sep 2009 17:51:40 GMT"/> <child internal-child="image"> - <widget class="GtkImage" id="image299"> + <widget class="GtkImage" id="image314"> <property name="visible">True</property> <property name="stock">gtk-add</property> <property name="icon_size">1</property> @@ -126,7 +126,7 @@ <signal name="activate" handler="on_add_audio_cd_activate" last_modification_time="Sat, 10 Oct 2009 15:29:22 GMT"/> <child internal-child="image"> - <widget class="GtkImage" id="image300"> + <widget class="GtkImage" id="image315"> <property name="visible">True</property> <property name="stock">gtk-add</property> <property name="icon_size">1</property> @@ -196,7 +196,7 @@ <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image301"> + <widget class="GtkImage" id="image316"> <property name="visible">True</property> <property name="stock">gtk-quit</property> <property name="icon_size">1</property> @@ -230,7 +230,7 @@ <signal name="activate" handler="on_clear1_activate" last_modification_time="Sun, 06 Sep 2009 18:30:03 GMT"/> <child internal-child="image"> - <widget class="GtkImage" id="image302"> + <widget class="GtkImage" id="image317"> <property name="visible">True</property> <property name="stock">gtk-clear</property> <property name="icon_size">1</property> @@ -270,7 +270,7 @@ <signal name="activate" handler="on_remove1_activate" last_modification_time="Sun, 06 Sep 2009 18:30:03 GMT"/> <child internal-child="image"> - <widget class="GtkImage" id="image303"> + <widget class="GtkImage" id="image318"> <property name="visible">True</property> <property name="stock">gtk-remove</property> <property name="icon_size">1</property> @@ -502,25 +502,76 @@ <widget class="GtkMenu" id="menuitem4_menu"> <child> - <widget class="GtkMenuItem" id="about1"> + <widget class="GtkImageMenuItem" id="help1"> <property name="visible">True</property> - <property name="label" translatable="yes">_About</property> + <property name="label" translatable="yes">_Help</property> <property name="use_underline">True</property> - <signal name="activate" handler="on_about1_activate" last_modification_time="Sat, 04 Jul 2009 12:57:58 GMT"/> + <signal name="activate" handler="on_help1_activate" last_modification_time="Tue, 08 Sep 2009 17:32:06 GMT"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image319"> + <property name="visible">True</property> + <property name="stock">gtk-help</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> </widget> </child> <child> - <widget class="GtkImageMenuItem" id="help1"> + <widget class="GtkMenuItem" id="changelog1"> <property name="visible">True</property> - <property name="label" translatable="yes">Help</property> + <property name="label" translatable="yes">_ChangeLog</property> <property name="use_underline">True</property> - <signal name="activate" handler="on_help1_activate" last_modification_time="Tue, 08 Sep 2009 17:32:06 GMT"/> + <signal name="activate" handler="on_changelog1_activate" last_modification_time="Wed, 06 Jan 2010 20:30:20 GMT"/> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator10"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="gpl1"> + <property name="visible">True</property> + <property name="label" translatable="yes">_GPLv2</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_gpl1_activate" last_modification_time="Wed, 06 Jan 2010 20:30:20 GMT"/> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="lgpl1"> + <property name="visible">True</property> + <property name="label" translatable="yes">_LGPLv2.1</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_lgpl1_activate" last_modification_time="Wed, 06 Jan 2010 20:30:20 GMT"/> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator9"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="about1"> + <property name="visible">True</property> + <property name="label" translatable="yes">_About</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_about1_activate" last_modification_time="Sat, 04 Jul 2009 12:57:58 GMT"/> <child internal-child="image"> - <widget class="GtkImage" id="image304"> + <widget class="GtkImage" id="image320"> <property name="visible">True</property> - <property name="stock">gtk-help</property> + <property name="stock">gtk-about</property> <property name="icon_size">1</property> <property name="xalign">0.5</property> <property name="yalign">0.5</property> @@ -3177,6 +3228,7 @@ Track Custom</property> <property name="add_tearoffs">False</property> <property name="focus_on_click">True</property> + <signal name="changed" handler="on_column_id_changed" last_modification_time="Mon, 04 Jan 2010 17:31:44 GMT"/> </widget> <packing> <property name="left_attach">1</property> diff --git a/plugins/gtkui/gtkplaylist.c b/plugins/gtkui/gtkplaylist.c index 6b303c8a..762be03f 100644 --- a/plugins/gtkui/gtkplaylist.c +++ b/plugins/gtkui/gtkplaylist.c @@ -37,8 +37,8 @@ #include "search.h" #include "progress.h" #include "drawing.h" -#include "session.h" -#include "deadbeef.h" +#include "../../session.h" +#include "../../deadbeef.h" #include "parser.h" #define min(x,y) ((x)<(y)?(x):(y)) diff --git a/plugins/gtkui/interface.c b/plugins/gtkui/interface.c index ed1bbb47..0b614e97 100644 --- a/plugins/gtkui/interface.c +++ b/plugins/gtkui/interface.c @@ -35,14 +35,14 @@ create_mainwin (void) GtkWidget *menuitem1; GtkWidget *menuitem1_menu; GtkWidget *open; - GtkWidget *image297; + GtkWidget *image312; GtkWidget *separator2; GtkWidget *add_files; - GtkWidget *image298; + GtkWidget *image313; GtkWidget *add_folders; - GtkWidget *image299; + GtkWidget *image314; GtkWidget *add_audio_cd; - GtkWidget *image300; + GtkWidget *image315; GtkWidget *add_location1; GtkWidget *separatormenuitem1; GtkWidget *playlist_load; @@ -50,16 +50,16 @@ create_mainwin (void) GtkWidget *playlist_save_as; GtkWidget *separator8; GtkWidget *quit; - GtkWidget *image301; + GtkWidget *image316; GtkWidget *edit1; GtkWidget *edit1_menu; GtkWidget *clear1; - GtkWidget *image302; + GtkWidget *image317; GtkWidget *select_all1; GtkWidget *selection1; GtkWidget *selection1_menu; GtkWidget *remove1; - GtkWidget *image303; + GtkWidget *image318; GtkWidget *crop1; GtkWidget *find1; GtkWidget *separator5; @@ -87,9 +87,15 @@ create_mainwin (void) GtkWidget *stop_after_current; GtkWidget *menuitem4; GtkWidget *menuitem4_menu; - GtkWidget *about1; GtkWidget *help1; - GtkWidget *image304; + GtkWidget *image319; + GtkWidget *changelog1; + GtkWidget *separator10; + GtkWidget *gpl1; + GtkWidget *lgpl1; + GtkWidget *separator9; + GtkWidget *about1; + GtkWidget *image320; GtkWidget *hbox2; GtkWidget *hbox3; GtkWidget *stopbtn; @@ -144,9 +150,9 @@ create_mainwin (void) GDK_O, (GdkModifierType) GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); - image297 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_MENU); - gtk_widget_show (image297); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (open), image297); + image312 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_MENU); + gtk_widget_show (image312); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (open), image312); separator2 = gtk_separator_menu_item_new (); gtk_widget_show (separator2); @@ -157,25 +163,25 @@ create_mainwin (void) gtk_widget_show (add_files); gtk_container_add (GTK_CONTAINER (menuitem1_menu), add_files); - image298 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU); - gtk_widget_show (image298); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_files), image298); + image313 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU); + gtk_widget_show (image313); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_files), image313); add_folders = gtk_image_menu_item_new_with_mnemonic ("Add folder(s)"); gtk_widget_show (add_folders); gtk_container_add (GTK_CONTAINER (menuitem1_menu), add_folders); - image299 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU); - gtk_widget_show (image299); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_folders), image299); + image314 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU); + gtk_widget_show (image314); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_folders), image314); add_audio_cd = gtk_image_menu_item_new_with_mnemonic ("Add Audio CD"); gtk_widget_show (add_audio_cd); gtk_container_add (GTK_CONTAINER (menuitem1_menu), add_audio_cd); - image300 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU); - gtk_widget_show (image300); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_audio_cd), image300); + image315 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU); + gtk_widget_show (image315); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_audio_cd), image315); add_location1 = gtk_menu_item_new_with_mnemonic ("Add location"); gtk_widget_show (add_location1); @@ -210,9 +216,9 @@ create_mainwin (void) GDK_Q, (GdkModifierType) GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); - image301 = gtk_image_new_from_stock ("gtk-quit", GTK_ICON_SIZE_MENU); - gtk_widget_show (image301); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (quit), image301); + image316 = gtk_image_new_from_stock ("gtk-quit", GTK_ICON_SIZE_MENU); + gtk_widget_show (image316); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (quit), image316); edit1 = gtk_menu_item_new_with_mnemonic ("_Edit"); gtk_widget_show (edit1); @@ -225,9 +231,9 @@ create_mainwin (void) gtk_widget_show (clear1); gtk_container_add (GTK_CONTAINER (edit1_menu), clear1); - image302 = gtk_image_new_from_stock ("gtk-clear", GTK_ICON_SIZE_MENU); - gtk_widget_show (image302); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (clear1), image302); + image317 = gtk_image_new_from_stock ("gtk-clear", GTK_ICON_SIZE_MENU); + gtk_widget_show (image317); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (clear1), image317); select_all1 = gtk_menu_item_new_with_mnemonic ("Select all"); gtk_widget_show (select_all1); @@ -247,9 +253,9 @@ create_mainwin (void) gtk_widget_show (remove1); gtk_container_add (GTK_CONTAINER (selection1_menu), remove1); - image303 = gtk_image_new_from_stock ("gtk-remove", GTK_ICON_SIZE_MENU); - gtk_widget_show (image303); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (remove1), image303); + image318 = gtk_image_new_from_stock ("gtk-remove", GTK_ICON_SIZE_MENU); + gtk_widget_show (image318); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (remove1), image318); crop1 = gtk_menu_item_new_with_mnemonic ("Crop"); gtk_widget_show (crop1); @@ -366,17 +372,43 @@ create_mainwin (void) menuitem4_menu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem4), menuitem4_menu); - about1 = gtk_menu_item_new_with_mnemonic ("_About"); - gtk_widget_show (about1); - gtk_container_add (GTK_CONTAINER (menuitem4_menu), about1); - - help1 = gtk_image_menu_item_new_with_mnemonic ("Help"); + help1 = gtk_image_menu_item_new_with_mnemonic ("_Help"); gtk_widget_show (help1); gtk_container_add (GTK_CONTAINER (menuitem4_menu), help1); - image304 = gtk_image_new_from_stock ("gtk-help", GTK_ICON_SIZE_MENU); - gtk_widget_show (image304); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (help1), image304); + image319 = gtk_image_new_from_stock ("gtk-help", GTK_ICON_SIZE_MENU); + gtk_widget_show (image319); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (help1), image319); + + changelog1 = gtk_menu_item_new_with_mnemonic ("_ChangeLog"); + gtk_widget_show (changelog1); + gtk_container_add (GTK_CONTAINER (menuitem4_menu), changelog1); + + separator10 = gtk_separator_menu_item_new (); + gtk_widget_show (separator10); + gtk_container_add (GTK_CONTAINER (menuitem4_menu), separator10); + gtk_widget_set_sensitive (separator10, FALSE); + + gpl1 = gtk_menu_item_new_with_mnemonic ("_GPLv2"); + gtk_widget_show (gpl1); + gtk_container_add (GTK_CONTAINER (menuitem4_menu), gpl1); + + lgpl1 = gtk_menu_item_new_with_mnemonic ("_LGPLv2.1"); + gtk_widget_show (lgpl1); + gtk_container_add (GTK_CONTAINER (menuitem4_menu), lgpl1); + + separator9 = gtk_separator_menu_item_new (); + gtk_widget_show (separator9); + gtk_container_add (GTK_CONTAINER (menuitem4_menu), separator9); + gtk_widget_set_sensitive (separator9, FALSE); + + about1 = gtk_image_menu_item_new_with_mnemonic ("_About"); + gtk_widget_show (about1); + gtk_container_add (GTK_CONTAINER (menuitem4_menu), about1); + + image320 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_MENU); + gtk_widget_show (image320); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (about1), image320); hbox2 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox2); @@ -605,12 +637,21 @@ create_mainwin (void) g_signal_connect ((gpointer) stop_after_current, "activate", G_CALLBACK (on_stop_after_current_activate), NULL); - g_signal_connect ((gpointer) about1, "activate", - G_CALLBACK (on_about1_activate), - NULL); g_signal_connect ((gpointer) help1, "activate", G_CALLBACK (on_help1_activate), NULL); + g_signal_connect ((gpointer) changelog1, "activate", + G_CALLBACK (on_changelog1_activate), + NULL); + g_signal_connect ((gpointer) gpl1, "activate", + G_CALLBACK (on_gpl1_activate), + NULL); + g_signal_connect ((gpointer) lgpl1, "activate", + G_CALLBACK (on_lgpl1_activate), + NULL); + g_signal_connect ((gpointer) about1, "activate", + G_CALLBACK (on_about1_activate), + NULL); g_signal_connect ((gpointer) stopbtn, "clicked", G_CALLBACK (on_stopbtn_clicked), NULL); @@ -739,14 +780,14 @@ create_mainwin (void) GLADE_HOOKUP_OBJECT (mainwin, menuitem1, "menuitem1"); GLADE_HOOKUP_OBJECT (mainwin, menuitem1_menu, "menuitem1_menu"); GLADE_HOOKUP_OBJECT (mainwin, open, "open"); - GLADE_HOOKUP_OBJECT (mainwin, image297, "image297"); + GLADE_HOOKUP_OBJECT (mainwin, image312, "image312"); GLADE_HOOKUP_OBJECT (mainwin, separator2, "separator2"); GLADE_HOOKUP_OBJECT (mainwin, add_files, "add_files"); - GLADE_HOOKUP_OBJECT (mainwin, image298, "image298"); + GLADE_HOOKUP_OBJECT (mainwin, image313, "image313"); GLADE_HOOKUP_OBJECT (mainwin, add_folders, "add_folders"); - GLADE_HOOKUP_OBJECT (mainwin, image299, "image299"); + GLADE_HOOKUP_OBJECT (mainwin, image314, "image314"); GLADE_HOOKUP_OBJECT (mainwin, add_audio_cd, "add_audio_cd"); - GLADE_HOOKUP_OBJECT (mainwin, image300, "image300"); + GLADE_HOOKUP_OBJECT (mainwin, image315, "image315"); GLADE_HOOKUP_OBJECT (mainwin, add_location1, "add_location1"); GLADE_HOOKUP_OBJECT (mainwin, separatormenuitem1, "separatormenuitem1"); GLADE_HOOKUP_OBJECT (mainwin, playlist_load, "playlist_load"); @@ -754,16 +795,16 @@ create_mainwin (void) GLADE_HOOKUP_OBJECT (mainwin, playlist_save_as, "playlist_save_as"); GLADE_HOOKUP_OBJECT (mainwin, separator8, "separator8"); GLADE_HOOKUP_OBJECT (mainwin, quit, "quit"); - GLADE_HOOKUP_OBJECT (mainwin, image301, "image301"); + GLADE_HOOKUP_OBJECT (mainwin, image316, "image316"); GLADE_HOOKUP_OBJECT (mainwin, edit1, "edit1"); GLADE_HOOKUP_OBJECT (mainwin, edit1_menu, "edit1_menu"); GLADE_HOOKUP_OBJECT (mainwin, clear1, "clear1"); - GLADE_HOOKUP_OBJECT (mainwin, image302, "image302"); + GLADE_HOOKUP_OBJECT (mainwin, image317, "image317"); GLADE_HOOKUP_OBJECT (mainwin, select_all1, "select_all1"); GLADE_HOOKUP_OBJECT (mainwin, selection1, "selection1"); GLADE_HOOKUP_OBJECT (mainwin, selection1_menu, "selection1_menu"); GLADE_HOOKUP_OBJECT (mainwin, remove1, "remove1"); - GLADE_HOOKUP_OBJECT (mainwin, image303, "image303"); + GLADE_HOOKUP_OBJECT (mainwin, image318, "image318"); GLADE_HOOKUP_OBJECT (mainwin, crop1, "crop1"); GLADE_HOOKUP_OBJECT (mainwin, find1, "find1"); GLADE_HOOKUP_OBJECT (mainwin, separator5, "separator5"); @@ -789,9 +830,15 @@ create_mainwin (void) GLADE_HOOKUP_OBJECT (mainwin, stop_after_current, "stop_after_current"); GLADE_HOOKUP_OBJECT (mainwin, menuitem4, "menuitem4"); GLADE_HOOKUP_OBJECT (mainwin, menuitem4_menu, "menuitem4_menu"); - GLADE_HOOKUP_OBJECT (mainwin, about1, "about1"); GLADE_HOOKUP_OBJECT (mainwin, help1, "help1"); - GLADE_HOOKUP_OBJECT (mainwin, image304, "image304"); + GLADE_HOOKUP_OBJECT (mainwin, image319, "image319"); + GLADE_HOOKUP_OBJECT (mainwin, changelog1, "changelog1"); + GLADE_HOOKUP_OBJECT (mainwin, separator10, "separator10"); + GLADE_HOOKUP_OBJECT (mainwin, gpl1, "gpl1"); + GLADE_HOOKUP_OBJECT (mainwin, lgpl1, "lgpl1"); + GLADE_HOOKUP_OBJECT (mainwin, separator9, "separator9"); + GLADE_HOOKUP_OBJECT (mainwin, about1, "about1"); + GLADE_HOOKUP_OBJECT (mainwin, image320, "image320"); GLADE_HOOKUP_OBJECT (mainwin, hbox2, "hbox2"); GLADE_HOOKUP_OBJECT (mainwin, hbox3, "hbox3"); GLADE_HOOKUP_OBJECT (mainwin, stopbtn, "stopbtn"); @@ -2099,6 +2146,10 @@ create_editcolumndlg (void) gtk_dialog_add_action_widget (GTK_DIALOG (editcolumndlg), okbutton1, GTK_RESPONSE_OK); GTK_WIDGET_SET_FLAGS (okbutton1, GTK_CAN_DEFAULT); + g_signal_connect ((gpointer) id, "changed", + G_CALLBACK (on_column_id_changed), + NULL); + /* Store pointers to all widgets, for use by lookup_widget(). */ GLADE_HOOKUP_OBJECT_NO_REF (editcolumndlg, editcolumndlg, "editcolumndlg"); GLADE_HOOKUP_OBJECT_NO_REF (editcolumndlg, dialog_vbox1, "dialog_vbox1"); diff --git a/plugins/gtkui/search.c b/plugins/gtkui/search.c index ae53caf5..8c2055d1 100644 --- a/plugins/gtkui/search.c +++ b/plugins/gtkui/search.c @@ -31,7 +31,7 @@ #include "search.h" #include "gtkplaylist.h" -#include "deadbeef.h" +#include "../../deadbeef.h" #define min(x,y) ((x)<(y)?(x):(y)) #define max(x,y) ((x)>(y)?(x):(y)) diff --git a/plugins/hotkeys/hotkeys.c b/plugins/hotkeys/hotkeys.c index 7d292f10..ae186254 100644 --- a/plugins/hotkeys/hotkeys.c +++ b/plugins/hotkeys/hotkeys.c @@ -220,7 +220,7 @@ read_config (Display *disp) cmd_entry->modifier |= ShiftMask; else if (0 == strcasecmp (p, "Super")) { - cmd_entry->modifier |= Mod2Mask; + cmd_entry->modifier |= Mod4Mask; } else { diff --git a/plugins/mpgmad/mpgmad.c b/plugins/mpgmad/mpgmad.c index 9bef2bc8..55bced8f 100644 --- a/plugins/mpgmad/mpgmad.c +++ b/plugins/mpgmad/mpgmad.c @@ -28,6 +28,9 @@ #define min(x,y) ((x)<(y)?(x):(y)) #define max(x,y) ((x)>(y)?(x):(y)) +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) + static DB_decoder_t plugin; static DB_functions_t *deadbeef; @@ -516,7 +519,7 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { static int cmp3_init (DB_playItem_t *it) { memset (&buffer, 0, sizeof (buffer)); - buffer.file = plugin.info.file = deadbeef->fopen (it->fname); + buffer.file = deadbeef->fopen (it->fname); if (!buffer.file) { return -1; } @@ -659,6 +662,10 @@ MadFixedToFloat (mad_fixed_t Fixed) { static int cmp3_decode_cut (int framesize) { if (buffer.duration >= 0) { + if (unlikely (!buffer.channels || buffer.channels > 2)) { + trace ("mpgmad: got frame with invalid number of channels (%d)\n", buffer.channels); + return 1; + } if (buffer.currentsample + buffer.readsize / (framesize * buffer.channels) > buffer.endsample) { int sz = (buffer.endsample - buffer.currentsample + 1) * framesize * buffer.channels; trace ("size truncated to %d bytes, cursample=%d, endsample=%d, totalsamples=%d\n", buffer.readsize, buffer.currentsample, buffer.endsample, buffer.totalsamples); @@ -840,7 +847,6 @@ cmp3_decode_float32 (void) { static void cmp3_free (void) { - plugin.info.file = NULL; if (buffer.file) { deadbeef->fclose (buffer.file); buffer.file = NULL; diff --git a/plugins/nullout/nullout.c b/plugins/nullout/nullout.c index 4a3b3c59..e8da5255 100644 --- a/plugins/nullout/nullout.c +++ b/plugins/nullout/nullout.c @@ -20,7 +20,7 @@ #include <sys/prctl.h> #include <stdio.h> #include <string.h> -#include "deadbeef.h" +#include "../../deadbeef.h" //#define trace(...) { fprintf(stderr, __VA_ARGS__); } #define trace(fmt,...) diff --git a/plugins/sndfile/sndfile.c b/plugins/sndfile/sndfile.c index 99f717cc..e6dfb7ce 100644 --- a/plugins/sndfile/sndfile.c +++ b/plugins/sndfile/sndfile.c @@ -62,7 +62,11 @@ sf_vfs_write (const void *ptr, sf_count_t count, void *user_data) { static sf_count_t sf_vfs_seek (sf_count_t offset, int whence, void *user_data) { sndfilectx_t *ctx = user_data; - return deadbeef->fseek (ctx->file, offset, whence); + int ret = deadbeef->fseek (ctx->file, offset, whence); + if (!ret) { + return offset; + } + return -1; } static sf_count_t @@ -174,7 +178,11 @@ sndfile_read_float32 (char *bytes, int size) { static int sndfile_seek_sample (int sample) { - sfctx.currentsample = sf_seek (sfctx.ctx, sample + sfctx.startsample, SEEK_SET); + int ret = sf_seek (sfctx.ctx, sample + sfctx.startsample, SEEK_SET); + if (ret < 0) { + return -1; + } + sfctx.currentsample = ret; plugin.info.readpos = (float)(sfctx.currentsample - sfctx.startsample) / plugin.info.samplerate; return 0; } diff --git a/plugins/vfs_curl/vfs_curl.c b/plugins/vfs_curl/vfs_curl.c index 3185df67..127a5a4e 100644 --- a/plugins/vfs_curl/vfs_curl.c +++ b/plugins/vfs_curl/vfs_curl.c @@ -70,6 +70,9 @@ static DB_vfs_t plugin; static char http_err[CURL_ERROR_SIZE]; +static int vfs_curl_abort; +static int vfs_curl_count; + static size_t http_content_header_handler (void *ptr, size_t size, size_t nmemb, void *stream); @@ -128,6 +131,9 @@ http_curl_write (void *ptr, size_t size, size_t nmemb, void *stream) { } deadbeef->mutex_unlock (fp->mutex); while (avail > 0) { + if (vfs_curl_abort) { + break; + } deadbeef->mutex_lock (fp->mutex); if (fp->status == STATUS_SEEK) { trace ("vfs_curl seek request, aborting current request\n"); @@ -190,26 +196,6 @@ http_curl_write (void *ptr, size_t size, size_t nmemb, void *stream) { return nmemb * size - avail; } -#if 0 -static size_t -http_size_header_handler (void *ptr, size_t size, size_t nmemb, void *stream) { - assert (stream); - HTTP_FILE *fp = (HTTP_FILE *)stream; - // don't copy/allocate mem, just grep for "Content-Length: " - const char *cl = strcasestr (ptr, "Content-Length:"); - if (cl) { - cl += 15; - while (*cl <= 0x20) { - cl++; - } - fp->length = atoi (cl); - trace ("vfs_curl: file size is %d bytes\n", fp->length); - return 0; - } - return size * nmemb; -} -#endif - static const uint8_t * parse_header (const uint8_t *p, const uint8_t *e, uint8_t *key, int keysize, uint8_t *value, int valuesize) { int sz; // will hold lenght of extracted string @@ -313,20 +299,19 @@ http_content_header_handler (void *ptr, size_t size, size_t nmemb, void *stream) return size * nmemb; } -//static size_t -//http_curl_write_abort (void *ptr, size_t size, size_t nmemb, void *stream) { -// return 0; -//} - static int http_curl_control (void *stream, double dltotal, double dlnow, double ultotal, double ulnow) { -// trace ("http_curl_control\n"); - assert (stream); HTTP_FILE *fp = (HTTP_FILE *)stream; + trace ("http_curl_control, status = %d\n", fp ? fp->status : -1); + assert (stream); if (fp->status == STATUS_ABORTED) { trace ("vfs_curl STATUS_ABORTED in progress callback\n"); return -1; } + if (vfs_curl_abort) { + trace ("vfs_curl: aborting stream %p due to external request\n"); + return -1; + } return 0; } @@ -339,26 +324,6 @@ http_thread_func (void *ctx) { fp->status = STATUS_INITIAL; int status; -#if 0 - // get filesize (once) - curl_easy_setopt (curl, CURLOPT_URL, fp->url); - curl_easy_setopt (curl, CURLOPT_NOBODY, 0); - curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1); - curl_easy_setopt (curl, CURLOPT_MAXREDIRS, 10); - curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, http_size_header_handler); - curl_easy_setopt (curl, CURLOPT_HEADERDATA, ctx); - curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, http_curl_write_abort); - curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, http_curl_control); - curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1); - curl_easy_setopt (curl, CURLOPT_MAXREDIRS, 10); - status = curl_easy_perform(curl); -#if 0 - if (status != 0) { - trace ("vfs_curl: curl_easy_perform failed while getting filesize, status %d\n", status); - } -#endif -#endif -// fp->status = STATUS_STARTING; trace ("vfs_curl: started loading data\n"); for (;;) { @@ -415,7 +380,9 @@ http_thread_func (void *ctx) { #endif curl_easy_setopt (curl, CURLOPT_PROXYTYPE, curlproxytype); } + vfs_curl_count++; status = curl_easy_perform (curl); + vfs_curl_count--; trace ("vfs_curl: curl_easy_perform status=%d\n", status); if (status != 0) { trace ("curl error:\n%s\n", http_err); @@ -497,7 +464,8 @@ http_read (void *ptr, size_t size, size_t nmemb, DB_FILE *stream) { while (fp->status != STATUS_FINISHED && sz > 0) { // wait until data is available - while ((fp->remaining == 0 || fp->skipbytes > 0) && fp->status != STATUS_FINISHED) { + while ((fp->remaining == 0 || fp->skipbytes > 0) && fp->status != STATUS_FINISHED && !vfs_curl_abort) { + trace ("vfs_curl: readwait..\n"); deadbeef->mutex_lock (fp->mutex); int skip = min (fp->remaining, fp->skipbytes); if (skip > 0) { @@ -651,7 +619,7 @@ http_get_content_type (DB_FILE *stream) { http_start_streamer (fp); } trace ("http_get_content_type waiting for response...\n"); - while (fp->status != STATUS_FINISHED && fp->status != STATUS_ABORTED && !fp->gotheader) { + while (fp->status != STATUS_FINISHED && fp->status != STATUS_ABORTED && !fp->gotheader && !vfs_curl_abort) { usleep (3000); } return fp->content_type; @@ -672,13 +640,12 @@ http_get_content_name (DB_FILE *stream) { http_start_streamer (fp); } trace ("http_get_content_name waiting for response...\n"); - while (fp->status != STATUS_FINISHED && fp->status != STATUS_ABORTED && !fp->gotheader) { + while (fp->status != STATUS_FINISHED && fp->status != STATUS_ABORTED && !fp->gotheader && !vfs_curl_abort) { usleep (3000); } return fp->content_name; } -#if 0 static const char * http_get_content_genre (DB_FILE *stream) { trace ("http_get_content_genre\n"); @@ -694,19 +661,38 @@ http_get_content_genre (DB_FILE *stream) { http_start_streamer (fp); } trace ("http_get_content_genre waiting for response...\n"); - while (fp->status != STATUS_FINISHED && fp->status != STATUS_ABORTED && !fp->gotheader) { + while (fp->status != STATUS_FINISHED && fp->status != STATUS_ABORTED && !fp->gotheader && !vfs_curl_abort) { usleep (3000); } return fp->content_genre; } -#endif -static void -http_stop (DB_FILE *stream) { - trace ("http_stop\n"); - assert (stream); - HTTP_FILE *fp = (HTTP_FILE *)stream; - fp->status = STATUS_ABORTED; +static int +vfs_curl_on_abort (DB_event_t *ev, uintptr_t data) { + trace ("vfs_curl: got abort signal (vfs_curl_count=%d)!\n", vfs_curl_count); + if (vfs_curl_count > 0) { + vfs_curl_abort = 1; + while (vfs_curl_count > 0) { + trace ("vfs_curl: (vfs_curl_count=%d)!\n", vfs_curl_count); + usleep (20000); + } + vfs_curl_abort = 0; + } + trace ("vfs_curl: abort handler done!\n"); + return 0; +} + +static int +vfs_curl_start (void) { + deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_ABORTREAD, DB_CALLBACK (vfs_curl_on_abort), 0); + return 0; +} + +static int +vfs_curl_stop (void) { + deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_ABORTREAD, DB_CALLBACK (vfs_curl_on_abort), 0); + vfs_curl_on_abort (NULL, 0); + return 0; } static const char *scheme_names[] = { "http://", "ftp://", NULL }; @@ -722,6 +708,8 @@ static DB_vfs_t plugin = { .plugin.author = "Alexey Yakovenko", .plugin.email = "waker@users.sourceforge.net", .plugin.website = "http://deadbeef.sf.net", + .plugin.start = vfs_curl_start, + .plugin.stop = vfs_curl_stop, .open = http_open, .close = http_close, .read = http_read, @@ -731,8 +719,7 @@ static DB_vfs_t plugin = { .getlength = http_getlength, .get_content_type = http_get_content_type, .get_content_name = http_get_content_name, - .get_content_genre = http_get_content_type, - .stop = http_stop, + .get_content_genre = http_get_content_genre, .scheme_names = scheme_names, .streaming = 1 }; diff --git a/plugins/vorbis/vorbis.c b/plugins/vorbis/vorbis.c index 1eb3f002..9a631a73 100644 --- a/plugins/vorbis/vorbis.c +++ b/plugins/vorbis/vorbis.c @@ -128,7 +128,7 @@ cvorbis_init (DB_playItem_t *it) { cur_bit_stream = -1; ptrack = it; - file = plugin.info.file = deadbeef->fopen (it->fname); + file = deadbeef->fopen (it->fname); if (!file) { return -1; } @@ -209,7 +209,6 @@ cvorbis_init (DB_playItem_t *it) { static void cvorbis_free (void) { - plugin.info.file = NULL; if (file) { ptrack = NULL; ov_clear (&vorbis_file); |