summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorGravatar Viktor Semykin <thesame.ml@gmail.com>2010-01-19 00:25:48 +0200
committerGravatar Viktor Semykin <thesame.ml@gmail.com>2010-01-19 00:25:48 +0200
commitb07cca605c3686199cadbc797a083b99bce14d5f (patch)
treede25936c9eb92c49bd3008623fcfd572c57f7a6a /plugins
parent380065e39d0a8c097569b6705530b68f1abf7ed2 (diff)
parent583b601c6420b43e0ecbb86faf44ab1e52f95064 (diff)
Merge branch 'master' of git://deadbeef.git.sourceforge.net/gitroot/deadbeef/deadbeef into notify
Diffstat (limited to 'plugins')
-rw-r--r--plugins/adplug/Makefile.am160
-rw-r--r--plugins/adplug/adplug-db.cpp16
-rw-r--r--plugins/adplug/adplug/COPYING509
-rw-r--r--plugins/adplug/adplug/a2m.cpp4
-rw-r--r--plugins/adplug/adplug/adl.cpp14
-rw-r--r--plugins/adplug/adplug/adl.h19
-rw-r--r--plugins/adplug/adplug/adplug.cpp24
-rw-r--r--plugins/adplug/adplug/adplug.h2
-rw-r--r--plugins/adplug/adplug/bmf.cpp2
-rw-r--r--plugins/adplug/adplug/cff.cpp3
-rw-r--r--plugins/adplug/adplug/cmf.cpp780
-rw-r--r--plugins/adplug/adplug/cmf.h112
-rw-r--r--plugins/adplug/adplug/d00.cpp8
-rw-r--r--plugins/adplug/adplug/d00.h2
-rw-r--r--plugins/adplug/adplug/dro.cpp8
-rw-r--r--plugins/adplug/adplug/dro.h2
-rw-r--r--plugins/adplug/adplug/dro2.cpp142
-rw-r--r--plugins/adplug/adplug/dro2.h60
-rw-r--r--plugins/adplug/adplug/dtm.cpp2
-rw-r--r--plugins/adplug/adplug/emuopl.cpp100
-rw-r--r--plugins/adplug/adplug/fmc.cpp7
-rw-r--r--plugins/adplug/adplug/fmopl.c12
-rw-r--r--plugins/adplug/adplug/fprovide.h2
-rw-r--r--plugins/adplug/adplug/hsc.h12
-rw-r--r--plugins/adplug/adplug/imf.cpp5
-rw-r--r--plugins/adplug/adplug/jbm.cpp293
-rw-r--r--plugins/adplug/adplug/jbm.h80
-rw-r--r--plugins/adplug/adplug/lds.h2
-rw-r--r--plugins/adplug/adplug/mad.cpp2
-rw-r--r--plugins/adplug/adplug/mid.cpp148
-rw-r--r--plugins/adplug/adplug/mid.h2
-rw-r--r--plugins/adplug/adplug/mkj.cpp2
-rw-r--r--plugins/adplug/adplug/msc.cpp4
-rw-r--r--plugins/adplug/adplug/mtk.cpp2
-rw-r--r--plugins/adplug/adplug/player.h28
-rw-r--r--plugins/adplug/adplug/protrack.cpp24
-rw-r--r--plugins/adplug/adplug/rad.cpp2
-rw-r--r--plugins/adplug/adplug/rat.cpp2
-rw-r--r--plugins/adplug/adplug/raw.cpp2
-rw-r--r--plugins/adplug/adplug/rix.cpp2
-rw-r--r--plugins/adplug/adplug/rol.cpp3
-rw-r--r--plugins/adplug/adplug/rol.h4
-rw-r--r--plugins/adplug/adplug/s3m.cpp25
-rw-r--r--plugins/adplug/adplug/sa2.cpp5
-rw-r--r--plugins/adplug/adplug/sng.cpp2
-rw-r--r--plugins/adplug/adplug/surroundopl.cpp203
-rw-r--r--plugins/adplug/adplug/surroundopl.h69
-rw-r--r--plugins/adplug/adplug/u6m.cpp2
-rw-r--r--plugins/adplug/adplug/xsm.h2
-rw-r--r--plugins/adplug/libbinio/binfile.cpp10
-rw-r--r--plugins/alsa/alsa.c18
-rw-r--r--plugins/cdda/cdda.c1
-rw-r--r--plugins/ffap/ffap.c98
-rw-r--r--plugins/ffmpeg/ffmpeg.c37
-rw-r--r--plugins/gtkui/callbacks.c56
-rw-r--r--plugins/gtkui/callbacks.h16
-rw-r--r--plugins/gtkui/deadbeef.glade82
-rw-r--r--plugins/gtkui/gtkplaylist.c4
-rw-r--r--plugins/gtkui/interface.c151
-rw-r--r--plugins/gtkui/search.c2
-rw-r--r--plugins/hotkeys/hotkeys.c2
-rw-r--r--plugins/mpgmad/mpgmad.c10
-rw-r--r--plugins/nullout/nullout.c2
-rw-r--r--plugins/sndfile/sndfile.c12
-rw-r--r--plugins/vfs_curl/vfs_curl.c109
-rw-r--r--plugins/vorbis/vorbis.c3
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);